From 2c34ab3374c9ad58152f17cc18d8e2d7f24f84f0 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Thu, 8 Dec 2016 12:38:22 +0800 Subject: [PATCH] Mark some interrupts that are now allocated dynamically as free, add int handle param documentation, add local ints test --- components/driver/include/driver/gpio.h | 2 + components/driver/include/driver/ledc.h | 2 + components/driver/include/driver/pcnt.h | 2 + components/driver/include/driver/timer.h | 7 +- components/driver/include/driver/uart.h | 12 ++ components/driver/uart.c | 13 ++ components/esp32/include/soc/soc.h | 9 +- components/esp32/intr_alloc.c | 6 +- components/esp32/test/test_intr_alloc.c | 217 ++++++++++----------- examples/13_timer_group/main/timer_group.c | 8 +- 10 files changed, 154 insertions(+), 124 deletions(-) diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index 7f178677b..fba013fe8 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -351,6 +351,8 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num); * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. * @param arg Parameter for handler function + * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will + * be returned here. * * @return * - ESP_OK Success ; diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index 643052325..fb97c6c01 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -265,6 +265,8 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. * @param arg Parameter for handler function + * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will + * be returned here. * * @return * - ESP_OK Success diff --git a/components/driver/include/driver/pcnt.h b/components/driver/include/driver/pcnt.h index d852f8fe7..f5a10581c 100644 --- a/components/driver/include/driver/pcnt.h +++ b/components/driver/include/driver/pcnt.h @@ -221,6 +221,8 @@ esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16 * @param arg Parameter for handler function * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will + * be returned here. * * @return * - ESP_OK Success diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index f46e70873..134fd504f 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -258,12 +258,15 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ * @param timer_num Timer index of timer group * @param fn Interrupt handler function. * @note - * Code inside the handler function can only call functions in IRAM, so cannot call other timer APIs. - * Use direct register access to access timers from inside the ISR. + * In case the this is called with the INIRAM flag, code inside the handler function can + * only call functions in IRAM, so it cannot call other timer APIs. + * Use direct register access to access timers from inside the ISR in this case. * * @param arg Parameter for handler function * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will + * be returned here. * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Function pointer error. diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index be3a6c8fc..dd69dce27 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -379,6 +379,18 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh); */ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags); + +/** + * @brief Free UART interrupt handler registered by uart_isr_register. + * + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_isr_free(uart_port_t uart_num); + /** * @brief Set UART pin number * diff --git a/components/driver/uart.c b/components/driver/uart.c index 7ce560f62..baf2d1f5a 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -309,6 +309,19 @@ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, return ret; } + +esp_err_t uart_isr_free(uart_port_t uart_num) +{ + esp_err_t ret; + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + if (p_uart_obj[uart_num]->intr_handle==NULL) return ESP_ERR_INVALID_ARG; + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + ret=esp_intr_free(p_uart_obj[uart_num]->intr_handle); + p_uart_obj[uart_num]->intr_handle=NULL; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ret; +} + //internal signal can be output to multiple GPIO pads //only one GPIO pad can connect with input signal esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num) diff --git a/components/esp32/include/soc/soc.h b/components/esp32/include/soc/soc.h index 3991152f2..511456a10 100755 --- a/components/esp32/include/soc/soc.h +++ b/components/esp32/include/soc/soc.h @@ -264,14 +264,14 @@ * Intr num Level Type PRO CPU usage APP CPU uasge * 0 1 extern level WMAC Reserved * 1 1 extern level BT/BLE Host VHCI Reserved - * 2 1 extern level FROM_CPU FROM_CPU - * 3 1 extern level TG0_WDT Reserved + * 2 1 extern level + * 3 1 extern level * 4 1 extern level WBB * 5 1 extern level BT Controller * 6 1 timer FreeRTOS Tick(L1) FreeRTOS Tick(L1) * 7 1 software Reserved Reserved * 8 1 extern level BLE Controller - * 9 1 extern level EMAC + * 9 1 extern level * 10 1 extern edge Internal Timer * 11 3 profiling * 12 1 extern level @@ -300,10 +300,7 @@ //CPU0 Interrupt number reserved, not touch this. #define ETS_WMAC_INUM 0 #define ETS_BT_HOST_INUM 1 -#define ETS_FROM_CPU_INUM 2 -#define ETS_T0_WDT_INUM 3 #define ETS_WBB_INUM 4 -#define ETS_EMAC_INUM 9 #define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/ #define ETS_FRC1_INUM 22 #define ETS_T1_WDT_INUM 24 diff --git a/components/esp32/intr_alloc.c b/components/esp32/intr_alloc.c index f17c56bc2..77572b1a5 100644 --- a/components/esp32/intr_alloc.c +++ b/components/esp32/intr_alloc.c @@ -99,8 +99,8 @@ typedef struct { const static int_desc_t int_desc[32]={ { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //0 { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //1 - { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //2 - { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //3 + { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //2 + { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //3 { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_NORMAL} }, //4 { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_NORMAL} }, //5 { 1, INTTP_NA, {INT6RES, INT6RES } }, //6 @@ -602,7 +602,7 @@ esp_err_t esp_intr_free(intr_handle_t handle) if ((handle->vector_desc->flags&VECDESC_FL_NONSHARED) || free_shared_vector) { ESP_LOGV(TAG, "esp_intr_free: Disabling int, killing handler"); //Reset to normal handler - xt_set_interrupt_handler(handle->vector_desc->intno, xt_unhandled_interrupt, (void*)handle->vector_desc->intno); + xt_set_interrupt_handler(handle->vector_desc->intno, xt_unhandled_interrupt, (void*)((int)handle->vector_desc->intno)); //Theoretically, we could free the vector_desc... not sure if that's worth the few bytes of memory //we save.(We can also not use the same exit path for empty shared ints anymore if we delete //the desc.) For now, just mark it as free. diff --git a/components/esp32/test/test_intr_alloc.c b/components/esp32/test/test_intr_alloc.c index 390079aa4..31991b4e4 100644 --- a/components/esp32/test/test_intr_alloc.c +++ b/components/esp32/test/test_intr_alloc.c @@ -1,5 +1,5 @@ /* - Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc. + Tests for the interrupt allocator. */ #include @@ -25,9 +25,6 @@ #define TIMER_INTERVAL1_SEC (5.78) /*!< test interval for timer 1 */ -/* - * @brief timer group0 hardware timer1 init - */ static void my_timer_init(int timer_group, int timer_idx, int ival) { timer_config_t config; @@ -55,38 +52,38 @@ static volatile int count[4]={0,0,0,0}; static void timer_isr(void *arg) { int timer_idx = (int)arg; - count[timer_idx]++; + count[timer_idx]++; if (timer_idx==0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update=1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } + TIMERG0.int_clr_timers.t0 = 1; + TIMERG0.hw_timer[0].update=1; + TIMERG0.hw_timer[0].config.alarm_en = 1; + } if (timer_idx==1) { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update=1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } + TIMERG0.int_clr_timers.t1 = 1; + TIMERG0.hw_timer[1].update=1; + TIMERG0.hw_timer[1].config.alarm_en = 1; + } if (timer_idx==2) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update=1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } + TIMERG1.int_clr_timers.t0 = 1; + TIMERG1.hw_timer[0].update=1; + TIMERG1.hw_timer[0].config.alarm_en = 1; + } if (timer_idx==3) { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update=1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } -// ets_printf("int %d\n", timer_idx); + TIMERG1.int_clr_timers.t1 = 1; + TIMERG1.hw_timer[1].update=1; + TIMERG1.hw_timer[1].config.alarm_en = 1; + } +// ets_printf("int %d\n", timer_idx); } static void timer_test(int flags) { - int x; - timer_isr_handle_t inth[4]; - my_timer_init(TIMER_GROUP_0, TIMER_0, 110000); - my_timer_init(TIMER_GROUP_0, TIMER_1, 120000); - my_timer_init(TIMER_GROUP_1, TIMER_0, 130000); - my_timer_init(TIMER_GROUP_1, TIMER_1, 140000); + int x; + timer_isr_handle_t inth[4]; + my_timer_init(TIMER_GROUP_0, TIMER_0, 110000); + my_timer_init(TIMER_GROUP_0, TIMER_1, 120000); + my_timer_init(TIMER_GROUP_1, TIMER_0, 130000); + my_timer_init(TIMER_GROUP_1, TIMER_1, 140000); timer_isr_register(TIMER_GROUP_0, TIMER_0, timer_isr, (void*)0, flags|ESP_INTR_FLAG_INTRDISABLED, &inth[0]); timer_isr_register(TIMER_GROUP_0, TIMER_1, timer_isr, (void*)1, flags, &inth[1]); timer_isr_register(TIMER_GROUP_1, TIMER_0, timer_isr, (void*)2, flags, &inth[2]); @@ -96,111 +93,111 @@ static void timer_test(int flags) { timer_start(TIMER_GROUP_1, TIMER_0); timer_start(TIMER_GROUP_1, TIMER_1); - for (x=0; x<4; x++) count[x]=0; - printf("Interrupts allocated: %d (dis) %d %d %d\n", - esp_intr_get_intno(inth[0]), esp_intr_get_intno(inth[1]), - esp_intr_get_intno(inth[2]), esp_intr_get_intno(inth[3])); - printf("Timer values on start: %d %d %d %d\n", count[0], count[1], count[2], count[3]); - vTaskDelay(1000 / portTICK_RATE_MS); - printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); - TEST_ASSERT(count[0]==0); - TEST_ASSERT(count[1]!=0); - TEST_ASSERT(count[2]!=0); - TEST_ASSERT(count[3]!=0); + for (x=0; x<4; x++) count[x]=0; + printf("Interrupts allocated: %d (dis) %d %d %d\n", + esp_intr_get_intno(inth[0]), esp_intr_get_intno(inth[1]), + esp_intr_get_intno(inth[2]), esp_intr_get_intno(inth[3])); + printf("Timer values on start: %d %d %d %d\n", count[0], count[1], count[2], count[3]); + vTaskDelay(1000 / portTICK_RATE_MS); + printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); + TEST_ASSERT(count[0]==0); + TEST_ASSERT(count[1]!=0); + TEST_ASSERT(count[2]!=0); + TEST_ASSERT(count[3]!=0); - printf("Disabling timers 1 and 2...\n"); - esp_intr_enable(inth[0]); - esp_intr_disable(inth[1]); - esp_intr_disable(inth[2]); - for (x=0; x<4; x++) count[x]=0; - vTaskDelay(1000 / portTICK_RATE_MS); - printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); - TEST_ASSERT(count[0]!=0); - TEST_ASSERT(count[1]==0); - TEST_ASSERT(count[2]==0); - TEST_ASSERT(count[3]!=0); - printf("Disabling other half...\n"); - esp_intr_enable(inth[1]); - esp_intr_enable(inth[2]); - esp_intr_disable(inth[0]); - esp_intr_disable(inth[3]); - for (x=0; x<4; x++) count[x]=0; - vTaskDelay(1000 / portTICK_RATE_MS); - printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); - TEST_ASSERT(count[0]==0); - TEST_ASSERT(count[1]!=0); - TEST_ASSERT(count[2]!=0); - TEST_ASSERT(count[3]==0); - printf("Done.\n"); - esp_intr_free(inth[0]); - esp_intr_free(inth[1]); - esp_intr_free(inth[2]); - esp_intr_free(inth[3]); + printf("Disabling timers 1 and 2...\n"); + esp_intr_enable(inth[0]); + esp_intr_disable(inth[1]); + esp_intr_disable(inth[2]); + for (x=0; x<4; x++) count[x]=0; + vTaskDelay(1000 / portTICK_RATE_MS); + printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); + TEST_ASSERT(count[0]!=0); + TEST_ASSERT(count[1]==0); + TEST_ASSERT(count[2]==0); + TEST_ASSERT(count[3]!=0); + printf("Disabling other half...\n"); + esp_intr_enable(inth[1]); + esp_intr_enable(inth[2]); + esp_intr_disable(inth[0]); + esp_intr_disable(inth[3]); + for (x=0; x<4; x++) count[x]=0; + vTaskDelay(1000 / portTICK_RATE_MS); + printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); + TEST_ASSERT(count[0]==0); + TEST_ASSERT(count[1]!=0); + TEST_ASSERT(count[2]!=0); + TEST_ASSERT(count[3]==0); + printf("Done.\n"); + esp_intr_free(inth[0]); + esp_intr_free(inth[1]); + esp_intr_free(inth[2]); + esp_intr_free(inth[3]); } static volatile int int_timer_ctr; void int_timer_handler(void *arg) { - xthal_set_ccompare(1, xthal_get_ccount()+8000000); - int_timer_ctr++; + xthal_set_ccompare(1, xthal_get_ccount()+8000000); + int_timer_ctr++; } void local_timer_test() { - intr_handle_t ih; - esp_err_t r; - r=esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, 0, int_timer_handler, NULL, &ih); - TEST_ASSERT(r==ESP_OK); - printf("Int timer 1 intno %d\n", esp_intr_get_intno(ih)); - xthal_set_ccompare(1, xthal_get_ccount()+8000000); - int_timer_ctr=0; - vTaskDelay(1000 / portTICK_RATE_MS); - printf("Timer val after 1 sec: %d\n", int_timer_ctr); - TEST_ASSERT(int_timer_ctr!=0); - printf("Disabling int\n"); - esp_intr_disable(ih); - int_timer_ctr=0; - vTaskDelay(1000 / portTICK_RATE_MS); - printf("Timer val after 1 sec: %d\n", int_timer_ctr); - TEST_ASSERT(int_timer_ctr==0); - printf("Re-enabling\n"); - esp_intr_enable(ih); - vTaskDelay(1000 / portTICK_RATE_MS); - printf("Timer val after 1 sec: %d\n", int_timer_ctr); - TEST_ASSERT(int_timer_ctr!=0); + intr_handle_t ih; + esp_err_t r; + r=esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, 0, int_timer_handler, NULL, &ih); + TEST_ASSERT(r==ESP_OK); + printf("Int timer 1 intno %d\n", esp_intr_get_intno(ih)); + xthal_set_ccompare(1, xthal_get_ccount()+8000000); + int_timer_ctr=0; + vTaskDelay(1000 / portTICK_RATE_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr!=0); + printf("Disabling int\n"); + esp_intr_disable(ih); + int_timer_ctr=0; + vTaskDelay(1000 / portTICK_RATE_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr==0); + printf("Re-enabling\n"); + esp_intr_enable(ih); + vTaskDelay(1000 / portTICK_RATE_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr!=0); - printf("Free int, re-alloc disabled\n"); - r=esp_intr_free(ih); - TEST_ASSERT(r==ESP_OK); - r=esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, ESP_INTR_FLAG_INTRDISABLED, int_timer_handler, NULL, &ih); - TEST_ASSERT(r==ESP_OK); - int_timer_ctr=0; - vTaskDelay(1000 / portTICK_RATE_MS); - printf("Timer val after 1 sec: %d\n", int_timer_ctr); - TEST_ASSERT(int_timer_ctr==0); - printf("Re-enabling\n"); - esp_intr_enable(ih); - vTaskDelay(1000 / portTICK_RATE_MS); - printf("Timer val after 1 sec: %d\n", int_timer_ctr); - TEST_ASSERT(int_timer_ctr!=0); - r=esp_intr_free(ih); - TEST_ASSERT(r==ESP_OK); - printf("Done.\n"); + printf("Free int, re-alloc disabled\n"); + r=esp_intr_free(ih); + TEST_ASSERT(r==ESP_OK); + r=esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, ESP_INTR_FLAG_INTRDISABLED, int_timer_handler, NULL, &ih); + TEST_ASSERT(r==ESP_OK); + int_timer_ctr=0; + vTaskDelay(1000 / portTICK_RATE_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr==0); + printf("Re-enabling\n"); + esp_intr_enable(ih); + vTaskDelay(1000 / portTICK_RATE_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr!=0); + r=esp_intr_free(ih); + TEST_ASSERT(r==ESP_OK); + printf("Done.\n"); } TEST_CASE("Intr_alloc test, CPU-local int source", "[esp32]") { - local_timer_test(); + local_timer_test(); } TEST_CASE("Intr_alloc test, private ints", "[esp32]") { - timer_test(0); + timer_test(0); } TEST_CASE("Intr_alloc test, shared ints", "[esp32]") { - timer_test(ESP_INTR_FLAG_SHARED); + timer_test(ESP_INTR_FLAG_SHARED); } diff --git a/examples/13_timer_group/main/timer_group.c b/examples/13_timer_group/main/timer_group.c index e91efe767..f61f39b2c 100644 --- a/examples/13_timer_group/main/timer_group.c +++ b/examples/13_timer_group/main/timer_group.c @@ -86,7 +86,9 @@ void IRAM_ATTR timer_group0_isr(void *para) /*Timer0 is an example that don't reload counter value*/ TIMERG0.hw_timer[timer_idx].update = 1; - /*We don't call a API here because they are not declared with IRAM_ATTR*/ + /* We don't call a API here because they are not declared with IRAM_ATTR. + If we're okay with the timer irq not being serviced while SPI flash cache is disabled, + we can alloc this interrupt without the ESP_INTR_FLAG_IRAM flag and use the normal API. */ TIMERG0.int_clr_timers.t0 = 1; uint64_t timer_val = ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32 | TIMERG0.hw_timer[timer_idx].cnt_low; @@ -155,7 +157,7 @@ void tg0_timer0_init() /*Enable timer interrupt*/ timer_enable_intr(timer_group, timer_idx); /*Set ISR handler*/ - timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, 0); + timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM); /*Start timer counter*/ timer_start(timer_group, timer_idx); } @@ -185,7 +187,7 @@ void tg0_timer1_init() /*Enable timer interrupt*/ timer_enable_intr(timer_group, timer_idx); /*Set ISR handler*/ - timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, 0); + timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM); /*Start timer counter*/ timer_start(timer_group, timer_idx); }