From 5583543f14f8f164f58928dc138f297a4f567e32 Mon Sep 17 00:00:00 2001 From: Our Air Quality Date: Sat, 22 Jul 2017 22:09:09 +1000 Subject: [PATCH] Add an argument to ISRs. Disable interrupts while masking them. --- FreeRTOS/Source/portable/esp8266/port.c | 6 +- core/esp_gpio.c | 10 ++-- core/esp_interrupts.c | 23 +++++--- core/include/esp/gpio.h | 2 +- core/include/esp/interrupts.h | 56 ++++++++++++------- examples/blink_timers/blink_timers.c | 8 +-- examples/experiments/timers/timers.c | 8 +-- .../unaligned_load/unaligned_load.c | 4 +- examples/i2s_audio/i2s_audio_example.c | 4 +- extras/i2s_dma/i2s_dma.c | 4 +- extras/i2s_dma/i2s_dma.h | 5 +- extras/pwm/pwm.c | 4 +- .../stdin_uart_interrupt.c | 4 +- extras/ws2812_i2s/ws2812_i2s.c | 4 +- open_esplibs/libmain/os_cpu_a.c | 2 +- tests/cases/03_byte_load_flash.c | 2 +- 16 files changed, 87 insertions(+), 59 deletions(-) diff --git a/FreeRTOS/Source/portable/esp8266/port.c b/FreeRTOS/Source/portable/esp8266/port.c index 87d846f..087f778 100644 --- a/FreeRTOS/Source/portable/esp8266/port.c +++ b/FreeRTOS/Source/portable/esp8266/port.c @@ -153,7 +153,7 @@ void IRAM PendSV(enum SVC_ReqType req) */ extern portBASE_TYPE sdk_MacIsrSigPostDefHdl(void); -void IRAM SV_ISR(void) +void IRAM SV_ISR(void *arg) { portBASE_TYPE xHigherPriorityTaskWoken=pdFALSE ; if(pending_maclayer_sv) @@ -185,11 +185,11 @@ void xPortSysTickHandle (void) */ portBASE_TYPE xPortStartScheduler( void ) { - _xt_isr_attach(INUM_SOFT, SV_ISR); + _xt_isr_attach(INUM_SOFT, SV_ISR, NULL); _xt_isr_unmask(BIT(INUM_SOFT)); /* Initialize system tick timer interrupt and schedule the first tick. */ - _xt_isr_attach(INUM_TICK, sdk__xt_timer_int); + _xt_isr_attach(INUM_TICK, sdk__xt_timer_int, NULL); _xt_isr_unmask(BIT(INUM_TICK)); sdk__xt_tick_timer_init(); diff --git a/core/esp_gpio.c b/core/esp_gpio.c index a3011e1..359f828 100644 --- a/core/esp_gpio.c +++ b/core/esp_gpio.c @@ -58,17 +58,17 @@ void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep) static gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { 0 }; -void __attribute__((weak)) IRAM gpio_interrupt_handler(void) +void __attribute__((weak)) IRAM gpio_interrupt_handler(void *arg) { uint32_t status_reg = GPIO.STATUS; GPIO.STATUS_CLEAR = status_reg; uint8_t gpio_idx; - while((gpio_idx = __builtin_ffs(status_reg))) + while ((gpio_idx = __builtin_ffs(status_reg))) { gpio_idx--; status_reg &= ~BIT(gpio_idx); - if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) { + if (FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) { gpio_interrupt_handler_t handler = gpio_interrupt_handlers[gpio_idx]; if (handler) { handler(gpio_idx); @@ -82,8 +82,8 @@ void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, g gpio_interrupt_handlers[gpio_num] = handler; GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type); - if(int_type != GPIO_INTTYPE_NONE) { - _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler); + if (int_type != GPIO_INTTYPE_NONE) { + _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler, NULL); _xt_isr_unmask(1< -_xt_isr isr[16]; +typedef struct _xt_isr_entry_ { + _xt_isr handler; + void *arg; +} _xt_isr_entry; + +_xt_isr_entry isr[16]; bool esp_in_isr; -void IRAM _xt_isr_attach(uint8_t i, _xt_isr func) +void IRAM _xt_isr_attach(uint8_t i, _xt_isr func, void *arg) { - isr[i] = func; + isr[i].handler = func; + isr[i].arg = arg; } /* Generic ISR handler. @@ -25,17 +31,20 @@ uint16_t IRAM _xt_isr_handler(uint16_t intset) esp_in_isr = true; /* WDT has highest priority (occasional WDT resets otherwise) */ - if(intset & BIT(INUM_WDT)) { + if (intset & BIT(INUM_WDT)) { _xt_clear_ints(BIT(INUM_WDT)); - isr[INUM_WDT](); + isr[INUM_WDT].handler(NULL); intset -= BIT(INUM_WDT); } - while(intset) { + while (intset) { uint8_t index = __builtin_ffs(intset) - 1; uint16_t mask = BIT(index); _xt_clear_ints(mask); - isr[index](); + _xt_isr handler = isr[index].handler; + if (handler) { + handler(isr[index].arg); + } intset -= mask; } diff --git a/core/include/esp/gpio.h b/core/include/esp/gpio.h index 9187087..85842aa 100644 --- a/core/include/esp/gpio.h +++ b/core/include/esp/gpio.h @@ -150,7 +150,7 @@ typedef void (* gpio_interrupt_handler_t)(uint8_t gpio_num); * * Example: * - * void IRAM gpio_interrupt_handler(void) { + * void IRAM gpio_interrupt_handler(void *arg) { * // check GPIO.STATUS * // write GPIO.STATUS_CLEAR * // Do something when GPIO changes diff --git a/core/include/esp/interrupts.h b/core/include/esp/interrupts.h index 47594a2..5bdd833 100644 --- a/core/include/esp/interrupts.h +++ b/core/include/esp/interrupts.h @@ -35,19 +35,37 @@ typedef enum { INUM_TIMER_FRC2 = 10, } xt_isr_num_t; -void sdk__xt_int_exit (void); -void _xt_user_exit (void); -void sdk__xt_tick_timer_init (void); -void sdk__xt_timer_int(void); +void sdk__xt_int_exit(void); +void _xt_user_exit(void); +void sdk__xt_tick_timer_init(void); +void sdk__xt_timer_int(void *); void sdk__xt_timer_int1(void); +/* The normal running level is 0. + * The system tick isr, timer frc2_isr, sv_isr etc run at level 1. + * Debug exceptions run at level 2? + * The wdev nmi runs at level 3. + */ static inline uint32_t _xt_get_intlevel(void) { uint32_t level; - __asm__ volatile("rsr %0, intlevel" : "=a"(level)); - return level; + __asm__ volatile("rsr %0, ps" : "=a"(level)); + return level & 0xf; } +/* + * There are conflicting definitions for XCHAL_EXCM_LEVEL. Newlib + * defines it to be 1 and xtensa_rtos.h defines it to be 3. Don't want + * 3 as that is for the NMI and might want to check that the OS apis + * are not entered in level 3. Setting the interrupt level to 3 does + * not disable the NMI anyway. So set the level to 2. + */ + +#ifdef XCHAL_EXCM_LEVEL +#undef XCHAL_EXCM_LEVEL +#define XCHAL_EXCM_LEVEL 2 +#endif + /* Disable interrupts and return the old ps value, to pass into _xt_restore_interrupts later. @@ -68,25 +86,27 @@ static inline void _xt_restore_interrupts(uint32_t new_ps) __asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps)); } -/* ESPTODO: the mask/unmask functions aren't thread safe */ - -static inline void _xt_isr_unmask(uint32_t unmask) +static inline uint32_t _xt_isr_unmask(uint32_t unmask) { + uint32_t old_level = _xt_disable_interrupts(); uint32_t intenable; asm volatile ("rsr %0, intenable" : "=a" (intenable)); - intenable |= unmask; - asm volatile ("wsr %0, intenable; esync" :: "a" (intenable)); + asm volatile ("wsr %0, intenable;" :: "a" (intenable | unmask)); + _xt_restore_interrupts(old_level); + return intenable; } -static inline void _xt_isr_mask (uint32_t mask) +static inline uint32_t _xt_isr_mask(uint32_t mask) { + uint32_t old_level = _xt_disable_interrupts(); uint32_t intenable; asm volatile ("rsr %0, intenable" : "=a" (intenable)); - intenable &= ~mask; - asm volatile ("wsr %0, intenable; esync" :: "a" (intenable)); + asm volatile ("wsr %0, intenable;" :: "a" (intenable & ~mask)); + _xt_restore_interrupts(old_level); + return intenable; } -static inline uint32_t _xt_read_ints (void) +static inline uint32_t _xt_read_ints(void) { uint32_t interrupt; asm volatile ("rsr %0, interrupt" : "=a" (interrupt)); @@ -98,9 +118,7 @@ static inline void _xt_clear_ints(uint32_t mask) asm volatile ("wsr %0, intclear; esync" :: "a" (mask)); } -typedef void (* _xt_isr)(void); -/* This function is implemeneted in FreeRTOS port.c at the moment, - should be moved or converted to an inline */ -void _xt_isr_attach (uint8_t i, _xt_isr func); +typedef void (* _xt_isr)(void *arg); +void _xt_isr_attach (uint8_t i, _xt_isr func, void *arg); #endif diff --git a/examples/blink_timers/blink_timers.c b/examples/blink_timers/blink_timers.c index 177cff3..bef887d 100644 --- a/examples/blink_timers/blink_timers.c +++ b/examples/blink_timers/blink_timers.c @@ -17,13 +17,13 @@ const int freq_frc2 = 10; static volatile uint32_t frc1_count; static volatile uint32_t frc2_count; -void frc1_interrupt_handler(void) +void frc1_interrupt_handler(void *arg) { frc1_count++; gpio_toggle(gpio_frc1); } -void frc2_interrupt_handler(void) +void frc2_interrupt_handler(void *arg) { /* FRC2 needs the match register updated on each timer interrupt */ timer_set_frequency(FRC2, freq_frc2); @@ -47,8 +47,8 @@ void user_init(void) timer_set_run(FRC2, false); /* set up ISRs */ - _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler); - _xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler); + _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL); + _xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler, NULL); /* configure timer frequencies */ timer_set_frequency(FRC1, freq_frc1); diff --git a/examples/experiments/timers/timers.c b/examples/experiments/timers/timers.c index a2e5e66..c889643 100644 --- a/examples/experiments/timers/timers.c +++ b/examples/experiments/timers/timers.c @@ -97,7 +97,7 @@ void timerRegTask(void *pvParameters) } } -IRAM void frc1_handler(void) +IRAM void frc1_handler(void *arg) { frc1_handler_call_count++; frc1_last_count_val = TIMER(0).COUNT; @@ -106,7 +106,7 @@ IRAM void frc1_handler(void) //TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000; } -void frc2_handler(void) +void frc2_handler(void *arg) { frc2_handler_call_count++; frc2_last_count_val = TIMER(1).COUNT; @@ -127,9 +127,9 @@ void user_init(void) TIMER(1).LOAD = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256); DPORT.INT_ENABLE |= DPORT_INT_ENABLE_TIMER0 | DPORT_INT_ENABLE_TIMER1; - _xt_isr_attach(INUM_TIMER_FRC1, frc1_handler); + _xt_isr_attach(INUM_TIMER_FRC1, frc1_handler, NULL); _xt_isr_unmask(1<