]> granicus.if.org Git - esp-idf/commitdiff
Add interrupt allocation scheme / interrupt sharing. Also modifies drivers and exampl...
authorJeroen Domburg <git@j0h.nl>
Fri, 25 Nov 2016 09:33:51 +0000 (17:33 +0800)
committerJeroen Domburg <git@j0h.nl>
Thu, 8 Dec 2016 04:39:33 +0000 (12:39 +0800)
to be marked specifically as having a handler that's all in IRAM.

29 files changed:
components/driver/gpio.c
components/driver/include/driver/gpio.h
components/driver/include/driver/ledc.h
components/driver/include/driver/pcnt.h
components/driver/include/driver/rmt.h
components/driver/include/driver/timer.h
components/driver/include/driver/uart.h
components/driver/ledc.c
components/driver/pcnt.c
components/driver/rmt.c
components/driver/timer.c
components/driver/uart.c
components/esp32/cpu_start.c
components/esp32/crosscore_int.c
components/esp32/include/esp_intr_alloc.h [new file with mode: 0644]
components/esp32/intr_alloc.c [new file with mode: 0644]
components/esp32/task_wdt.c
components/ethernet/emac_main.c
components/freertos/xtensa_intr.c
components/freertos/xtensa_intr_asm.S
components/mbedtls/port/esp_bignum.c
components/newlib/time.c
components/spi_flash/cache_utils.c
docs/Doxyfile
docs/api/intr_alloc.rst [new file with mode: 0644]
docs/index.rst
examples/11_rmt_nec_tx_rx/main/infrared_nec.c
examples/13_timer_group/main/timer_group.c
examples/16_pcnt/main/pcnt_test.c

index f8694597a816c69dbc4b49f61bcd203e002dae23..2cba63ca6f4111636ed89f930d51fb94b5e47d65 100644 (file)
@@ -14,6 +14,7 @@
 #include <esp_types.h>
 #include "esp_err.h"
 #include "esp_intr.h"
+#include "esp_intr_alloc.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/xtensa_api.h"
 #include "driver/gpio.h"
@@ -320,14 +321,10 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
     return ESP_OK;
 }
 
-esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg)
+esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags)
 {
     GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG);
-    ESP_INTR_DISABLE(gpio_intr_num);
-    intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num);
-    xt_set_interrupt_handler(gpio_intr_num, fn, arg);
-    ESP_INTR_ENABLE(gpio_intr_num);
-    return ESP_OK;
+    return esp_intr_alloc(ETS_GPIO_INTR_SOURCE, intr_alloc_flags, fn, arg, NULL);
 }
 
 /*only level interrupt can be used for wake-up function*/
index de7525bd5f19124403b7d8f928fa5d91e3a2b0aa..59dd5685782ac2857a41755179c5e1c7679935b7 100644 (file)
@@ -343,8 +343,9 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
  *          Users should know that which CPU is running and then pick a INUM that is not used by system.
  *          We can find the information of INUM and interrupt level in soc.h.
  *
- * @param  gpio_intr_num  GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details
  * @param  fn  Interrupt 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.
  *
  *         @note
  *         Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
@@ -355,7 +356,7 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
  *     - ESP_OK Success ;
  *     - ESP_ERR_INVALID_ARG GPIO error
  */
-esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg);
+esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags);
 
 
 
@@ -415,7 +416,7 @@ esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
  */
 
 /**
- *----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ *
+ *----------EXAMPLE TO CONFIGURE GPIO AS OUTPUT ------------ *
  * @code{c}
  *     gpio_config_t io_conf;
  *     io_conf.intr_type = GPIO_INTR_DISABLE;             //disable interrupt
@@ -428,7 +429,7 @@ esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
  **/
 
 /**
- *----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ *
+ *----------EXAMPLE TO CONFIGURE GPIO AS OUTPUT ------------ *
  * @code{c}
  *     io_conf.intr_type = GPIO_INTR_POSEDGE;             //set posedge interrupt
  *     io_conf.mode = GPIO_MODE_INPUT;                        //set as input
@@ -441,8 +442,7 @@ esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
 /**
  *----------EXAMPLE TO SET ISR HANDLER ----------------------
  * @code{c}
- * //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
- * gpio_isr_register(18,gpio_intr_test,NULL);    //hook the isr handler for GPIO interrupt
+ * gpio_isr_register(gpio_intr_test,NULL, 0);    //hook the isr handler for GPIO interrupt
  * @endcode
  * @note
  *     1. user should arrange the INUMs that used, better not to use a same INUM for different interrupt.
index e07787b2b177b00cf6d92c035ab239ea6dd4714b..a581f604ecb56a6b4e4663441aea6572b34b8014 100644 (file)
@@ -257,11 +257,11 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty,
 /**
  * @brief   register LEDC interrupt handler, the handler is an ISR.
  *          The handler will be attached to the same CPU core that this function is running on.
- * @note
- *     Users should know that which CPU is running and then pick a INUM that is not used by system.
- *     We can find the information of INUM and interrupt level in soc.h.
- * @param   ledc_intr_num  LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details
+ *
  * @param   fn Interrupt handler function.
+ * @param  arg User-supplied argument passed to the 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.
  * @note
  *     Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
  * @param   arg Parameter for handler function
@@ -270,7 +270,7 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty,
  *     - ESP_OK Success
  *     - ESP_ERR_INVALID_ARG Function pointer error.
  */
-esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg);
+esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags);
 
 /**
  * @brief      configure LEDC settings
@@ -398,13 +398,8 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint
  * ----------------EXAMPLE OF LEDC INTERRUPT ------------------
  * @code{c}
  * //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here.
- * ledc_isr_register(18, ledc_isr_handler, NULL);           //hook the isr handler for LEDC interrupt
+ * ledc_isr_register(ledc_isr_handler, NULL, 0);           //hook the isr handler for LEDC interrupt
  * @endcode
- * @note
- *     1. the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
- *     2. user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
- *     3. do not pick the INUM that already occupied by the system.
- *     4. refer to soc.h to check which INUMs that can be used.
  *
  * ----------------EXAMPLE OF INTERRUPT HANDLER ---------------
  * @code{c}
index d2620cf15ee65d403ac4a16f882e596a07328027..1ab2abae74ca8458e686d106fe416b66e1825120 100644 (file)
@@ -213,21 +213,19 @@ esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16
 /**
  * @brief Register PCNT interrupt handler, the handler is an ISR.
  *        The handler will be attached to the same CPU core that this function is running on.
- *        @note
- *        Users should know that which CPU is running and then pick a INUM that is not used by system.
- *        We can find the information of INUM and interrupt level in soc.h.
  *
- * @param pcnt_intr_num PCNT interrupt number, check the info in soc.h, and please see the core-isa.h for more details
  * @param fn Interrupt handler function.
  *        @note
  *        Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
  * @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.
  *
  * @return
  *     - ESP_OK Success
  *     - ESP_ERR_INVALID_ARG Function pointer error.
  */
-esp_err_t pcnt_isr_register(uint32_t pcnt_intr_num, void (*fn)(void*), void * arg);
+esp_err_t pcnt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags);
 
 /**
  * @brief Configure PCNT pulse signal input pin and control input pin
index 50a5c743dd3902a078621b94d725320ec655b62f..4c28406d80a2dcfe794f055b57bbe5c33ac50f8f 100644 (file)
@@ -566,27 +566,21 @@ esp_err_t rmt_config(rmt_config_t* rmt_param);
  * @brief   register RMT interrupt handler, the handler is an ISR.
  *
  *          The handler will be attached to the same CPU core that this function is running on.
- *          Users should know that which CPU is running and then pick a INUM that is not used by system.
- *          We can find the information of INUM and interrupt level in soc.h.
  *          @note
  *          If you already called rmt_driver_install to use system RMT driver,
  *          please do not register ISR handler again.
  *
- * @param rmt_intr_num RMT interrupt number, check the info in soc.h, and please see the core-isa.h for more details
- *
  * @param fn Interrupt handler function.
- *
- *          @note
- *          the handler function MUST be defined with attribution of "IRAM_ATTR".
- *
  * @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.
  *
  * @return
  *     - ESP_OK Success
  *     - ESP_ERR_INVALID_ARG Function pointer error.
  *     - ESP_FAIL System driver installed, can not register ISR handler for RMT
  */
-esp_err_t rmt_isr_register(uint8_t rmt_intr_num, void (* fn)(void* ), void * arg);
+esp_err_t rmt_isr_register(void (* fn)(void* ), void * arg, int intr_alloc_flags);
 
 /**
  * @brief Fill memory data of channel with given RMT items.
@@ -727,7 +721,7 @@ esp_err_t rmt_get_ringbuf_handler(rmt_channel_t channel, RingbufHandle_t* buf_ha
  *     rmt_config(&rmt_tx);
  *
  *     //install system RMT driver, disable rx ringbuffer for transmitter.
- *     rmt_driver_install(rmt_tx.channel, 0, RMT_INTR_NUM);
+ *     rmt_driver_install(rmt_tx.channel, 0, 0);
  * }
  *
  * @endcode
@@ -747,20 +741,16 @@ esp_err_t rmt_get_ringbuf_handler(rmt_channel_t channel, RingbufHandle_t* buf_ha
  *     rmt_config(&rmt_rx);
  *
  *     //install system RMT driver.
- *     rmt_driver_install(rmt_rx.channel, 1000, RMT_INTR_NUM);
+ *     rmt_driver_install(rmt_rx.channel, 1000, 0);
  * }
  *
  * ----------------EXAMPLE OF RMT INTERRUPT ------------------
  * @code{c}
  *
- * rmt_isr_register(RMT_INTR_NUM, rmt_isr, NULL);           //hook the ISR handler for RMT interrupt
+ * rmt_isr_register(rmt_isr, NULL, 0);           //hook the ISR handler for RMT interrupt
  * @endcode
  * @note
  *     0. If you have called rmt_driver_install, you don't need to set ISR handler any more.
- *     1. the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
- *     2. user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
- *     3. do not pick the INUM that already occupied by the system.
- *     4. refer to soc.h to check which INUMs that can be used.
  *
  * ----------------EXAMPLE OF INTERRUPT HANDLER ---------------
  * @code{c}
index c0ad7116e400e6b1a1923d783aecb3b57441bb8d..e6cbbd3787083c458b7259c780a7a7cf7a5861a6 100644 (file)
@@ -94,8 +94,8 @@ typedef enum {
 typedef struct {
     bool alarm_en; /*!< Timer alarm enable */
     bool counter_en; /*!< Counter enable */
-    timer_count_dir_t counter_dir; /*!< Counter direction  */
     timer_intr_mode_t intr_type; /*!< Interrupt mode */
+    timer_count_dir_t counter_dir; /*!< Counter direction  */
     bool auto_reload; /*!< Timer auto-reload */
     uint16_t divider; /*!< Counter clock divider*/
 } timer_config_t;
@@ -245,21 +245,17 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
 /**
  * @brief   register Timer interrupt handler, the handler is an ISR.
  *          The handler will be attached to the same CPU core that this function is running on.
- *          @note
- *          Users should know that which CPU is running and then pick a INUM that is not used by system.
- *          We can find the information of INUM and interrupt level in soc.h.
  *
  * @param group_num Timer group number
  * @param timer_num Timer index of timer group
- * @param timer_intr_num  TIMER interrupt number, check the info in soc.h, and please see the core-isa.h for more details
- * @param intr_type Timer interrupt type
  * @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.
  *
  * @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.
  * @return
  *     - ESP_OK Success
  *     - ESP_ERR_INVALID_ARG Function pointer error.
@@ -268,7 +264,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
  *     - ESP_OK Success
  *     - ESP_ERR_INVALID_ARG Parameter error
  */
-esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, int timer_intr_num, timer_intr_mode_t intr_type, void (*fn)(void*), void * arg);
+esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void*), void * arg, int intr_alloc_flags);
 
 /** @brief Initializes and configure the timer.
  * 
index 1ddfcad9fae390c608c22e86678c5f587445b425..0e7a4b515b53a7ffa23e52507390a8047a0bc7b8 100644 (file)
@@ -366,21 +366,19 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
  * @brief register UART interrupt handler(ISR).\r
  *\r
  * @note UART ISR handler will be attached to the same CPU core that this function is running on.\r
- * Users should know that which CPU is running and then pick a INUM that is not used by system.\r
- * We can find the information of INUM and interrupt level in soc.h.\r
- *\r
- * @attention The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now.\r
  *\r
  * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2\r
- * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details\r
  * @param fn  Interrupt handler function.\r
  * @param arg parameter for handler function\r
+ * @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. Note that the UART
+ *            driver at the moment does not work with a shared interrupt.\r
  *\r
  * @return\r
  *     - ESP_OK   Success\r
  *     - ESP_FAIL Parameter error\r
  */\r
-esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg);\r
+esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags);\r
 \r
 /**\r
  * @brief Set UART pin number\r
@@ -461,14 +459,15 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
  * @param tx_buffer_size UART TX ring buffer size.\r
  *        If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..\r
  * @param queue_size UART event queue size/depth.\r
- * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details\r
  * @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue.\r
+ * @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.
  *\r
  * @return\r
  *     - ESP_OK   Success\r
  *     - ESP_FAIL Parameter error\r
  */\r
-esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, int uart_intr_num, void* uart_queue);\r
+esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, void* uart_queue, int intr_alloc_flags);\r
 \r
 /**\r
  * @brief Uninstall UART driver.\r
@@ -733,7 +732,7 @@ esp_err_t uart_flush(uart_port_t uart_num);
  *     //Set UART log level\r
  *     esp_log_level_set(TAG, ESP_LOG_INFO);\r
  *     //Install UART driver, and get the queue.\r
- *     uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, &uart0_queue);\r
+ *     uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, &uart0_queue, 0);\r
  *     //Create a task to handler UART event from ISR\r
  *     xTaskCreate(uart_task, "uTask", 1024, (void*)uart_num, 10, NULL);\r
  * }\r
index 893c78a6bebd8b8a280c775ab634af5e2c0a25a5..66c31da9b95128245dddd91b9e7543a1cff4522d 100644 (file)
@@ -13,6 +13,7 @@
 // limitations under the License.
 #include <esp_types.h>
 #include "esp_intr.h"
+#include "esp_intr_alloc.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/semphr.h"
 #include "freertos/xtensa_api.h"
@@ -113,16 +114,14 @@ static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel,
     return ESP_OK;
 }
 
-esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg)
+esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags)
 {
+    esp_err_t ret;
     LEDC_CHECK(fn, "ledc isr null", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
-    ESP_INTR_DISABLE(ledc_intr_num);
-    intr_matrix_set(xPortGetCoreID(), ETS_LEDC_INTR_SOURCE, ledc_intr_num);
-    xt_set_interrupt_handler(ledc_intr_num, fn, arg);
-    ESP_INTR_ENABLE(ledc_intr_num);
+    ret=esp_intr_alloc(ETS_LEDC_INTR_SOURCE, intr_alloc_flags, fn, arg, NULL);
     portEXIT_CRITICAL(&ledc_spinlock);
-    return ESP_OK;
+    return ret;
 }
 
 esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
index e65d733c01c27ccc52c63deb5663f4387d658c61..aedd22104a5ceae51adb99f7de1b7f1e38bdd56f 100644 (file)
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 #include "esp_log.h"
+#include "esp_intr_alloc.h"
 #include "driver/pcnt.h"
 #include "driver/periph_ctrl.h"
 
@@ -266,13 +267,9 @@ esp_err_t pcnt_filter_disable(pcnt_unit_t unit)
     return ESP_OK;
 }
 
-esp_err_t pcnt_isr_register(uint32_t pcnt_intr_num, void (*fun)(void*), void * arg)
+esp_err_t pcnt_isr_register(void (*fun)(void*), void * arg, int intr_alloc_flags)
 {
     PCNT_CHECK(fun != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
-    ESP_INTR_DISABLE(pcnt_intr_num);
-    intr_matrix_set(xPortGetCoreID(), ETS_PCNT_INTR_SOURCE, pcnt_intr_num);
-    xt_set_interrupt_handler(pcnt_intr_num, fun, arg);
-    ESP_INTR_ENABLE(pcnt_intr_num);
-    return ESP_OK;
+    return esp_intr_alloc(ETS_PCNT_INTR_SOURCE, intr_alloc_flags, fun, arg, NULL);
 }
 
index f23fa257d023b00a4560e2d845cdb65365c1bdc5..ba70ffea607cb00c13c07dbea44702124546fe8d 100644 (file)
@@ -21,6 +21,7 @@
 #include "esp_intr.h"
 #include "esp_log.h"
 #include "esp_err.h"
+#include "esp_intr_alloc.h"
 #include "soc/gpio_sig_map.h"
 #include "soc/rmt_struct.h"
 #include "driver/periph_ctrl.h"
@@ -472,17 +473,15 @@ esp_err_t rmt_fill_tx_items(rmt_channel_t channel, rmt_item32_t* item, uint16_t
     return ESP_OK;
 }
 
-esp_err_t rmt_isr_register(uint8_t rmt_intr_num, void (*fn)(void*), void * arg)
+esp_err_t rmt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags)
 {
+    esp_err_t ret;
     RMT_CHECK((fn != NULL), RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
     RMT_CHECK(s_rmt_driver_installed == false, "RMT DRIVER INSTALLED, CAN NOT REG ISR HANDLER", ESP_FAIL);
     portENTER_CRITICAL(&rmt_spinlock);
-    ESP_INTR_DISABLE(rmt_intr_num);
-    intr_matrix_set(xPortGetCoreID(), ETS_RMT_INTR_SOURCE, rmt_intr_num);
-    xt_set_interrupt_handler(rmt_intr_num, fn, arg);
-    ESP_INTR_ENABLE(rmt_intr_num);
+    ret=esp_intr_alloc(ETS_RMT_INTR_SOURCE, intr_alloc_flags, fn, arg, NULL);
     portEXIT_CRITICAL(&rmt_spinlock);
-    return ESP_OK;
+    return ret;
 }
 
 static int IRAM_ATTR rmt_get_mem_len(rmt_channel_t channel)
@@ -619,7 +618,7 @@ esp_err_t rmt_driver_uninstall(rmt_channel_t channel)
     return ESP_OK;
 }
 
-esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
+esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr_alloc_flags)
 {
     RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
     if(p_rmt_obj[channel] != NULL) {
@@ -627,7 +626,6 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_
         return ESP_FAIL;
     }
 
-    ESP_INTR_DISABLE(rmt_intr_num);
     p_rmt_obj[channel] = (rmt_obj_t*) malloc(sizeof(rmt_obj_t));
 
     if(p_rmt_obj[channel] == NULL) {
@@ -652,11 +650,10 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_
         rmt_set_err_intr_en(channel, 1);
     }
     if(s_rmt_driver_installed == false) {
-        rmt_isr_register(rmt_intr_num, rmt_driver_isr_default, NULL);
+        rmt_isr_register(rmt_driver_isr_default, NULL, intr_alloc_flags);
         s_rmt_driver_installed = true;
     }
     rmt_set_tx_intr_en(channel, 1);
-    ESP_INTR_ENABLE(rmt_intr_num);
     return ESP_OK;
 }
 
index b305a414686a87e694a68d67a03f3a65b783e807..023f731cc36af3be1b9c5ab146ab541b2f677159 100644 (file)
@@ -15,6 +15,7 @@
 #include "esp_log.h"\r
 #include "esp_err.h"\r
 #include "esp_intr.h"\r
+#include "esp_intr_alloc.h"\r
 #include "freertos/FreeRTOS.h"\r
 #include "freertos/xtensa_api.h"\r
 #include "driver/timer.h"\r
@@ -167,36 +168,32 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
     return ESP_OK;\r
 }\r
 \r
-esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, int timer_intr_num,\r
-    timer_intr_mode_t intr_type, void (*fn)(void*), void * arg)\r
+esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, \r
+    void (*fn)(void*), void * arg, int intr_alloc_flags)\r
 {\r
     TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
     TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
     TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
 \r
-    ESP_INTR_DISABLE(timer_intr_num);\r
     int intr_source = 0;\r
     switch(group_num) {\r
         case TIMER_GROUP_0:\r
         default:\r
-            if(intr_type == TIMER_INTR_LEVEL) {\r
+            if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {\r
                 intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;\r
             } else {\r
                 intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;\r
             }\r
             break;\r
         case TIMER_GROUP_1:\r
-            if(intr_type == TIMER_INTR_LEVEL) {\r
+            if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {\r
                 intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;\r
             } else {\r
                 intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;\r
             }\r
             break;\r
     }\r
-    intr_matrix_set(xPortGetCoreID(), intr_source, timer_intr_num);\r
-    xt_set_interrupt_handler(timer_intr_num, fn, arg);\r
-    ESP_INTR_ENABLE(timer_intr_num);\r
-    return ESP_OK;\r
+    return esp_intr_alloc(intr_source, intr_alloc_flags, fn, arg, NULL);\r
 }\r
 \r
 esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)\r
index 59b4904dcd7ece413a1ecb4dbb6815afd81f288f..62979dd5a3122d8456e203da65c779dabcf842a9 100644 (file)
@@ -15,7 +15,9 @@
 #include "esp_types.h"\r
 #include "esp_attr.h"\r
 #include "esp_intr.h"\r
+#include "esp_intr_alloc.h"\r
 #include "esp_log.h"\r
+#include "esp_err.h"\r
 #include "malloc.h"\r
 #include "freertos/FreeRTOS.h"\r
 #include "freertos/semphr.h"\r
@@ -53,7 +55,7 @@ typedef struct {
     uart_port_t uart_num;               /*!< UART port number*/\r
     int queue_size;                     /*!< UART event queue size*/\r
     QueueHandle_t xQueueUart;           /*!< UART queue handler*/\r
-    int intr_num;                       /*!< UART interrupt number*/\r
+    int_handle_t intr_handle;           /*!< UART interrupt handle*/\r
     //rx parameters\r
     SemaphoreHandle_t rx_mux;           /*!< UART RX data mutex*/\r
     int rx_buf_size;                    /*!< RX ring buffer size */\r
@@ -283,31 +285,29 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)
     UART[uart_num]->conf1.txfifo_empty_thrhd = thresh & UART_TXFIFO_EMPTY_THRHD_V;\r
     UART[uart_num]->int_ena.txfifo_empty = enable & 0x1;\r
     UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
-    ESP_INTR_ENABLE(p_uart_obj[uart_num]->intr_num);\r
     return ESP_OK;\r
 }\r
 \r
-esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg)\r
+esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags)\r
 {\r
+    int ret;
     UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
+    UART_CHECK(((intr_alloc_flags & ESP_INTR_FLAG_SHARED)==0), "UART doesn't support shared interrupts", ESP_FAIL);\r
     UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
-    ESP_INTR_DISABLE(uart_intr_num);\r
     switch(uart_num) {\r
         case UART_NUM_1:\r
-            intr_matrix_set(xPortGetCoreID(), ETS_UART1_INTR_SOURCE, uart_intr_num);\r
+            ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);\r
             break;\r
         case UART_NUM_2:\r
-            intr_matrix_set(xPortGetCoreID(), ETS_UART2_INTR_SOURCE, uart_intr_num);\r
+            ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);\r
             break;\r
         case UART_NUM_0:\r
             default:\r
-            intr_matrix_set(xPortGetCoreID(), ETS_UART0_INTR_SOURCE, uart_intr_num);\r
+            ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);\r
             break;\r
     }\r
-    xt_set_interrupt_handler(uart_intr_num, fn, arg);\r
-    ESP_INTR_ENABLE(uart_intr_num);\r
     UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);\r
-    return ESP_OK;\r
+    return ret;\r
 }\r
 \r
 //internal signal can be output to multiple GPIO pads\r
@@ -859,7 +859,7 @@ esp_err_t uart_flush(uart_port_t uart_num)
 \r
     //rx sem protect the ring buffer read related functions\r
     xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY);\r
-    ESP_INTR_DISABLE(p_uart->intr_num);\r
+    esp_intr_disable(p_uart->intr_handle);\r
     while(true) {\r
         if(p_uart->rx_head_ptr) {\r
             vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr);\r
@@ -876,12 +876,12 @@ esp_err_t uart_flush(uart_port_t uart_num)
     p_uart->rx_ptr = NULL;\r
     p_uart->rx_cur_remain = 0;\r
     p_uart->rx_head_ptr = NULL;\r
-    ESP_INTR_ENABLE(p_uart->intr_num);\r
+    esp_intr_enable(p_uart->intr_handle);\r
     xSemaphoreGive(p_uart->rx_mux);\r
 \r
     if(p_uart->tx_buf_size > 0) {\r
         xSemaphoreTake(p_uart->tx_mux, (portTickType)portMAX_DELAY);\r
-        ESP_INTR_DISABLE(p_uart->intr_num);\r
+        esp_intr_disable(p_uart->intr_handle);\r
         UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);\r
         UART[uart_num]->int_ena.txfifo_empty = 0;\r
         UART[uart_num]->int_clr.txfifo_empty = 1;\r
@@ -901,19 +901,18 @@ esp_err_t uart_flush(uart_port_t uart_num)
         p_uart->tx_ptr = NULL;\r
         p_uart->tx_waiting_brk = 0;\r
         p_uart->tx_waiting_fifo = false;\r
-        ESP_INTR_ENABLE(p_uart->intr_num);\r
+        esp_intr_enable(p_uart->intr_handle);\r
         xSemaphoreGive(p_uart->tx_mux);\r
     }\r
     uart_reset_fifo(uart_num);\r
     return ESP_OK;\r
 }\r
 \r
-esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, int uart_intr_num, void* uart_queue)\r
+esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, void* uart_queue, int intr_alloc_flags)\r
 {\r
     UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);\r
     UART_CHECK((rx_buffer_size > 0), "uart rx buffer length error", ESP_FAIL);\r
     if(p_uart_obj[uart_num] == NULL) {\r
-        ESP_INTR_DISABLE(uart_intr_num);\r
         p_uart_obj[uart_num] = (uart_obj_t*) malloc(sizeof(uart_obj_t));\r
         if(p_uart_obj[uart_num] == NULL) {\r
             ESP_LOGE(UART_TAG, "UART driver malloc error");\r
@@ -926,7 +925,6 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
         p_uart_obj[uart_num]->tx_brk_sem = xSemaphoreCreateBinary();\r
         p_uart_obj[uart_num]->tx_mux = xSemaphoreCreateMutex();\r
         p_uart_obj[uart_num]->rx_mux = xSemaphoreCreateMutex();\r
-        p_uart_obj[uart_num]->intr_num = uart_intr_num;\r
         p_uart_obj[uart_num]->queue_size = queue_size;\r
         p_uart_obj[uart_num]->tx_ptr = NULL;\r
         p_uart_obj[uart_num]->tx_head = NULL;\r
@@ -959,7 +957,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
         ESP_LOGE(UART_TAG, "UART driver already installed");\r
         return ESP_FAIL;\r
     }\r
-    uart_isr_register(uart_num, uart_intr_num, uart_rx_intr_handler_default, p_uart_obj[uart_num]);\r
+    uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags);\r
     uart_intr_config_t uart_intr = {\r
         .intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M\r
                             | UART_RXFIFO_TOUT_INT_ENA_M\r
@@ -972,7 +970,6 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
         .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT\r
     };\r
     uart_intr_config(uart_num, &uart_intr);\r
-    ESP_INTR_ENABLE(uart_intr_num);\r
     return ESP_OK;\r
 }\r
 \r
@@ -984,10 +981,9 @@ esp_err_t uart_driver_delete(uart_port_t uart_num)
         ESP_LOGI(UART_TAG, "ALREADY NULL");\r
         return ESP_OK;\r
     }\r
-    ESP_INTR_DISABLE(p_uart_obj[uart_num]->intr_num);\r
+    esp_intr_free(p_uart_obj[uart_num]->intr_handle);
     uart_disable_rx_intr(uart_num);\r
     uart_disable_tx_intr(uart_num);\r
-    uart_isr_register(uart_num, p_uart_obj[uart_num]->intr_num, NULL, NULL);\r
 \r
     if(p_uart_obj[uart_num]->tx_fifo_sem) {\r
         vSemaphoreDelete(p_uart_obj[uart_num]->tx_fifo_sem);\r
index 8802b7dcd78766d0d019c4e064f287d7304d3247..d6088b04017c7d7d0ef3a43bee9f3ebbc55bbb80 100644 (file)
@@ -173,12 +173,6 @@ void start_cpu0_default(void)
     uart_div_modify(CONFIG_CONSOLE_UART_NUM, (APB_CLK_FREQ << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
 #if CONFIG_BROWNOUT_DET
     esp_brownout_init();
-#endif
-#if CONFIG_INT_WDT
-    esp_int_wdt_init();
-#endif
-#if CONFIG_TASK_WDT
-    esp_task_wdt_init();
 #endif
     esp_setup_time_syscalls();
     esp_vfs_dev_uart_register();
@@ -194,6 +188,12 @@ void start_cpu0_default(void)
     _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr;
 #endif
     do_global_ctors();
+#if CONFIG_INT_WDT
+    esp_int_wdt_init();
+#endif
+#if CONFIG_TASK_WDT
+    esp_task_wdt_init();
+#endif
 #if !CONFIG_FREERTOS_UNICORE
     esp_crosscore_int_init();
 #endif
index 60f972a2a21db5c0b068e289bdf39abd98b66047..f7ea4f6a7456fdac819de1d21cd6b93344f8c0c8 100644 (file)
@@ -17,6 +17,7 @@
 #include "esp_attr.h"
 #include "esp_err.h"
 #include "esp_intr.h"
+#include "esp_intr_alloc.h"
 
 #include "rom/ets_sys.h"
 #include "rom/uart.h"
@@ -72,14 +73,11 @@ void esp_crosscore_int_init() {
     portENTER_CRITICAL(&reasonSpinlock);
     reason[xPortGetCoreID()]=0;
     portEXIT_CRITICAL(&reasonSpinlock);
-    ESP_INTR_DISABLE(ETS_FROM_CPU_INUM);
     if (xPortGetCoreID()==0) {
-        intr_matrix_set(xPortGetCoreID(), ETS_FROM_CPU_INTR0_SOURCE, ETS_FROM_CPU_INUM);
+        esp_intr_alloc(ETS_FROM_CPU_INTR0_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()], NULL);
     } else {
-        intr_matrix_set(xPortGetCoreID(), ETS_FROM_CPU_INTR1_SOURCE, ETS_FROM_CPU_INUM);
+        esp_intr_alloc(ETS_FROM_CPU_INTR1_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()], NULL);
     }
-    xt_set_interrupt_handler(ETS_FROM_CPU_INUM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()]);
-    ESP_INTR_ENABLE(ETS_FROM_CPU_INUM);
 }
 
 void esp_crosscore_int_send_yield(int coreId) {
diff --git a/components/esp32/include/esp_intr_alloc.h b/components/esp32/include/esp_intr_alloc.h
new file mode 100644 (file)
index 0000000..ea7d597
--- /dev/null
@@ -0,0 +1,262 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __ESP_INTR_ALLOC_H__
+#define __ESP_INTR_ALLOC_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** @addtogroup Intr_Alloc
+  * @{
+  */
+
+
+/** @brief Interrupt allocation flags
+ *
+ * These flags can be used to specify which interrupt qualities the
+ * code calling esp_intr_alloc* needs.
+ *
+ */
+
+//Keep the LEVELx values as they are here; they match up with (1<<level)
+#define ESP_INTR_FLAG_LEVEL1           (1<<1)  ///< Accept a Level 1 interrupt vector
+#define ESP_INTR_FLAG_LEVEL2           (1<<2)  ///< Accept a Level 2 interrupt vector
+#define ESP_INTR_FLAG_LEVEL3           (1<<3)  ///< Accept a Level 3 interrupt vector
+#define ESP_INTR_FLAG_LEVEL4           (1<<4)  ///< Accept a Level 4 interrupt vector
+#define ESP_INTR_FLAG_LEVEL5           (1<<5)  ///< Accept a Level 5 interrupt vector
+#define ESP_INTR_FLAG_LEVEL6           (1<<6)  ///< Accept a Level 6 interrupt vector
+#define ESP_INTR_FLAG_NMI                      (1<<7)  ///< Accept a Level 7 interrupt vector
+#define ESP_INTR_FLAG_SHARED           (1<<8)  ///< Interrupt can be shared between ISRs
+#define ESP_INTR_FLAG_EDGE                     (1<<9)  ///< Edge-triggered interrupt
+#define ESP_INTR_FLAG_IRAM                     (1<<10) ///< ISR can be called if cache is disabled
+
+#define ESP_INTR_FLAG_LOWMED   (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) ///< Low and medium prio interrupts. These can be handled in C.
+#define ESP_INTR_FLAG_HIGH             (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) ///< High level interrupts. Need to be handled in assembly.
+
+#define ESP_INTR_FLAG_LEVELMASK        (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3| \
+                                                                ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \
+                                                                ESP_INTR_FLAG_NMI) ///< Mask for all level flags
+/**@}*/
+
+
+/** @addtogroup Intr_Alloc_Pseudo_Src
+  * @{
+  */
+
+/**
+ * The esp_intr_alloc* functions can allocate an int for all ETS_*_INTR_SOURCE interrupt sources that
+ * are routed through the interrupt mux. Apart from these sources, each core also has some internal
+ * sources that do not pass through the interrupt mux. To allocate an interrupt for these sources,
+ * pass these pseudo-sources to the functions.
+ */
+#define ETS_INTERNAL_TIMER0_INTR_SOURCE                -1 ///< Xtensa timer 0 interrupt source
+#define ETS_INTERNAL_TIMER1_INTR_SOURCE                -2 ///< Xtensa timer 1 interrupt source
+#define ETS_INTERNAL_TIMER2_INTR_SOURCE                -3 ///< Xtensa timer 2 interrupt source
+#define ETS_INTERNAL_SW0_INTR_SOURCE           -4 ///< Software int source 1
+#define ETS_INTERNAL_SW1_INTR_SOURCE           -5 ///< Software int source 2
+#define ETS_INTERNAL_PROFILING_INTR_SOURCE     -6 ///< Int source for profiling
+
+/**@}*/
+
+typedef void (*intr_handler_t)(void *arg); 
+
+
+typedef struct int_handle_data_t int_handle_data_t;
+typedef int_handle_data_t* int_handle_t ;
+
+/**
+ * @brief Mark an interrupt as a shared interrupt
+ * 
+ * This will mark a certain interrupt on the specified CPU as
+ * an interrupt that can be used to hook shared interrupt handlers
+ * to.
+ *
+ * @param intno The number of the interrupt (0-31)
+ * @param cpu CPU on which the interrupt should be marked as shared (0 or 1)
+ * @param is_in_iram Shared interrupt is for handlers that reside in IRAM and
+ *                   the int can be left enabled while the flash cache is out.
+ *
+ * @return ESP_ERR_INVALID_ARG if cpu or intno is invalid
+ *         ESP_OK otherwise
+ */
+esp_err_t esp_intr_mark_shared(int intno, int cpu, bool is_in_iram);
+
+/**
+ * @brief Reserve an interrupt to be used outside of this framewoek
+ * 
+ * This will mark a certain interrupt on the specified CPU as
+ * reserved, not to be allocated for any reason.
+ *
+ * @param intno The number of the interrupt (0-31)
+ * @param cpu CPU on which the interrupt should be marked as shared (0 or 1)
+ *
+ * @return ESP_ERR_INVALID_ARG if cpu or intno is invalid
+ *         ESP_OK otherwise
+ */
+esp_err_t esp_intr_reserve(int intno, int cpu);
+
+/**
+ * @brief Allocate an interrupt with the given parameters.
+ *
+ * This finds an interrupt that matches the restrictions as given in the flags
+ * parameter, maps the given interrupt source to it and hooks up the given
+ * interrupt handler (with optional argument) as well. If needed, it can return
+ * a handle for the interrupt as well.
+ *
+ * The interrupt will always be allocated on the core that runs this function.
+ *
+ * @param source The interrupt source. One of the ETS_*_INTR_SOURCE interrupt mux
+ *               sources, as defined in soc/soc.h, or one of the internal
+ *               ETS_INTERNAL_*_INTR_SOURCE sources as defined in this header.
+ * @param flags An ORred mask of the ESP_INTR_FLAG_* defines. These restrict the
+ *               choice of interrupts that this routine can choose from. If this value
+ *               is 0, it will default to allocating a non-shared interrupt of level
+ *               1, 2 or 3. If this is ESP_INTR_FLAG_SHARED, it will allocate a shared
+ *               interrupt of level 1.
+ * @param handler The interrupt handler. Must be NULL when an interrupt of level >3
+ *               is requested, because these types of interrupts aren't C-callable.
+ * @param arg    Optional argument for passed to the interrupt handler
+ * @param ret_handle Pointer to an int_handle_t to store a handle that can later be
+ *               used to request details or free the interrupt. Can be NULL if no handle
+ *               is required.
+ *
+ * @return ESP_ERR_INVALID_ARG if the combination of arguments is invalid.
+ *         ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
+ *         ESP_OK otherwise
+ */
+esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, int_handle_t *ret_handle);
+
+
+/**
+ * @brief Allocate an interrupt with the given parameters.
+ *
+ *
+ * This essentially does the same as esp_intr_alloc, but allows specifying a register and mask
+ * combo. For shared interrupts, the handler is only called if a read from the specified 
+ * register, ANDed with the mask, returns non-zero. By passing an interrupt status register
+ * address and a fitting mask, this can be used to accelerate interrupt handling in the case
+ * a shared interrupt is triggered; by checking the interrupt statuses first, the code can
+ * decide which ISRs can be skipped
+ *
+ * @param source The interrupt source. One of the ETS_*_INTR_SOURCE interrupt mux
+ *               sources, as defined in soc/soc.h, or one of the internal
+ *               ETS_INTERNAL_*_INTR_SOURCE sources as defined in this header.
+ * @param flags An ORred mask of the ESP_INTR_FLAG_* defines. These restrict the
+ *               choice of interrupts that this routine can choose from. If this value
+ *               is 0, it will default to allocating a non-shared interrupt of level
+ *               1, 2 or 3. If this is ESP_INTR_FLAG_SHARED, it will allocate a shared
+ *               interrupt of level 1.
+ * @param intrstatusreg The address of an interrupt status register
+ * @param intrstatusmask A mask. If a read of address intrstatusreg has any of the bits
+ *               that are 1 in the mask set, the ISR will be called. If not, it will be
+ *               skipped.
+ * @param handler The interrupt handler. Must be NULL when an interrupt of level >3
+ *               is requested, because these types of interrupts aren't C-callable.
+ * @param arg    Optional argument for passed to the interrupt handler
+ * @param ret_handle Pointer to an int_handle_t to store a handle that can later be
+ *               used to request details or free the interrupt. Can be NULL if no handle
+ *               is required.
+ *
+ * @return ESP_ERR_INVALID_ARG if the combination of arguments is invalid.
+ *         ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
+ *         ESP_OK otherwise
+ */
+esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusreg, uint32_t intrstatusmask, intr_handler_t handler, void *arg, int_handle_t *ret_handle);
+
+
+/**
+ * @brief Disable and free an interrupt.
+ *
+ * Use an interrupt handle to disable the interrupt (if non-shared) and release the resources
+ * associated with it.
+ *
+ * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus
+ *
+ * @return ESP_ERR_INVALID_ARG if handle is invalid, or esp_intr_free runs on another core than
+ *                             where the interrupt is allocated on.
+ *         ESP_OK otherwise
+ */
+esp_err_t esp_intr_free(int_handle_t handle);
+
+
+/**
+ * @brief Get CPU number an interrupt is tied to
+ * 
+ * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus
+ *
+ * @return The core number where the interrupt is allocated
+ */
+int esp_intr_get_cpu(int_handle_t handle);
+
+/**
+ * @brief Get the allocated interrupt for a certain handle
+ * 
+ * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus
+ *
+ * @return The interrupt number
+ */
+int esp_intr_get_intno(int_handle_t handle);
+
+
+/**
+ * @brief Disable the interrupt associated with the handle
+ * 
+ * @note This function can only disable non-shared inteerupts allocated on the CPU that runs this function.
+ *
+ * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus
+ *
+ * @return ESP_ERR_INVALID_ARG if the combination of arguments is invalid.
+ *         ESP_OK otherwise
+ */
+esp_err_t esp_intr_disable(int_handle_t handle);
+
+/**
+ * @brief Ensable the interrupt associated with the handle
+ * 
+ * @note This function can only enable non-shared inteerupts allocated on the CPU that runs this function.
+ *
+ * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus
+ *
+ * @return ESP_ERR_INVALID_ARG if the combination of arguments is invalid.
+ *         ESP_OK otherwise
+ */
+esp_err_t esp_intr_enable(int_handle_t handle);
+
+
+/**
+ * @brief Disable interrupts that aren't specifically marked as running from IRAM
+ */
+void esp_intr_noniram_disable();
+
+
+/**
+ * @brief Re-enable interrupts disabled by esp_intr_noniram_disable
+ */
+void esp_intr_noniram_enable();
+
+/**@}*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/components/esp32/intr_alloc.c b/components/esp32/intr_alloc.c
new file mode 100644 (file)
index 0000000..bd7a7e2
--- /dev/null
@@ -0,0 +1,654 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+
+#include "sdkconfig.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include <esp_types.h>
+#include "esp_err.h"
+#include "esp_log.h"
+#include "esp_intr.h"
+#include "esp_attr.h"
+#include "esp_intr_alloc.h"
+#include <limits.h>
+#include <assert.h>
+
+static const char* TAG = "intr_alloc";
+
+
+#define ETS_INTERNAL_TIMER0_INTR_NO 6
+#define ETS_INTERNAL_TIMER1_INTR_NO 15
+#define ETS_INTERNAL_TIMER2_INTR_NO 16
+#define ETS_INTERNAL_SW0_INTR_NO 7
+#define ETS_INTERNAL_SW1_INTR_NO 29
+#define ETS_INTERNAL_PROFILING_INTR_NO 11
+
+
+/*
+Define this to debug the choices made when allocating the interrupt. This leads to much debugging
+output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
+being triggered, that is why it is separate from the normal LOG* scheme.
+*/
+//define DEBUG_INT_ALLOC_DECISIONS
+#ifdef DEBUG_INT_ALLOC_DECISIONS
+# define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__)
+#else
+# define ALCHLOG(...) do {} while (0)
+#endif
+
+
+typedef enum {
+    INTDESC_NORMAL=0,
+    INTDESC_RESVD,
+    INTDESC_SPECIAL //for xtensa timers / software ints
+} int_desc_flag_t;
+
+typedef enum {
+    INTTP_LEVEL=0,
+    INTTP_EDGE,
+    INTTP_NA
+} int_type_t;
+
+typedef struct {
+    int level;
+    int_type_t type;
+    int_desc_flag_t cpuflags[2];
+} int_desc_t;
+
+
+//We should mark the interrupt for the timer used by FreeRTOS as reserved. The specific timer 
+//is selectable using menuconfig; we use these cpp bits to convert that into something we can use in
+//the table below.
+#if CONFIG_FREERTOS_CORETIMER_0
+#define INT6RES INTDESC_RESVD
+#else
+#define INT6RES INTDESC_SPECIAL
+#endif
+
+#if CONFIG_FREERTOS_CORETIMER_1
+#define INT15RES INTDESC_RESVD
+#else
+#define INT15RES INTDESC_SPECIAL
+#endif
+
+#if CONFIG_FREERTOS_CORETIMER_2
+#define INT16RES INTDESC_RESVD
+#else
+#define INT16RES INTDESC_SPECIAL
+#endif
+
+//This is basically a software-readable version of the interrupt usage table in include/soc/soc.h
+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_RESVD,  INTDESC_NORMAL} }, //4
+    { 1, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_NORMAL} }, //5
+    { 1, INTTP_NA,    {INT6RES,        INT6RES       } }, //6
+    { 1, INTTP_NA,    {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //7
+    { 1, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //8
+    { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //9
+    { 1, INTTP_EDGE , {INTDESC_RESVD,  INTDESC_NORMAL} }, //10
+    { 3, INTTP_NA,    {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //11
+    { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //12
+    { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //13
+    { 7, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //14, NMI
+    { 3, INTTP_NA,    {INT15RES,       INT15RES      } }, //15
+    { 5, INTTP_NA,    {INT16RES,       INT16RES      } }, //16
+    { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //17
+    { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //18
+    { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //19
+    { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //20
+    { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //21
+    { 3, INTTP_EDGE,  {INTDESC_RESVD,  INTDESC_NORMAL} }, //22
+    { 3, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //23
+    { 4, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_NORMAL} }, //24
+    { 4, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //25
+    { 5, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //26
+    { 3, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //27
+    { 4, INTTP_EDGE,  {INTDESC_NORMAL, INTDESC_NORMAL} }, //28
+    { 3, INTTP_NA,    {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //29
+    { 4, INTTP_EDGE,  {INTDESC_RESVD,  INTDESC_RESVD } }, //30
+    { 5, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //31
+};
+
+
+//For memory usage and to get an unique ID for every int on every CPU core, the
+//intrs and cpus are stored in in one int. These functions handle that.
+inline static int to_intno_cpu(int intno, int cpu) 
+{
+    return intno+cpu*32;
+}
+
+inline static int to_intno(int intno_cpu) 
+{
+    return (intno_cpu)&31;
+}
+
+inline static int to_cpu(int intno_cpu) 
+{
+    return (intno_cpu)/32;
+}
+
+typedef struct shared_vector_desc_t shared_vector_desc_t;
+typedef struct vector_desc_t vector_desc_t;
+
+struct shared_vector_desc_t {
+    volatile uint32_t *statusreg;
+    uint32_t statusmask;
+    intr_handler_t isr;
+    void *arg;
+    shared_vector_desc_t *next;
+};
+
+
+#define VECDESC_FL_RESERVED     (1<<0)
+#define VECDESC_FL_INIRAM       (1<<1)
+#define VECDESC_FL_SHARED       (1<<2)
+#define VECDESC_FL_NONSHARED    (1<<3)
+
+struct vector_desc_t {
+    int intno_cpu;                          //intno+cpu*32
+    int flags;                              //OR of VECDESC_FLAG_* defines
+    shared_vector_desc_t *shared_vec_info;  //used when VECDESC_FL_SHARED
+    vector_desc_t *next;
+};
+
+struct int_handle_data_t {
+    vector_desc_t *vector_desc;
+    shared_vector_desc_t *shared_vector_desc;
+};
+
+
+//Linked list of vector descriptions, sorted by intno_cpu value
+static vector_desc_t *vector_desc_head;
+
+//This bitmask has an 1 if the int should be disabled when the flash is disabled.
+static uint32_t non_iram_int_mask[portNUM_PROCESSORS];
+//This bitmask has 1 in it if the int was disabled using esp_intr_noniram_disable.
+static uint32_t non_iram_int_disabled[portNUM_PROCESSORS];
+static bool non_iram_int_disabled_flag[portNUM_PROCESSORS];
+
+
+static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
+
+//Inserts an item into vector_desc list so that the list is sorted
+//with an incrementing intno_cpu value.
+static void insert_vector_desc(vector_desc_t *to_insert) 
+{
+    vector_desc_t *vd=vector_desc_head;
+    vector_desc_t *prev=NULL;
+    while(vd!=NULL) {
+        if (vd->intno_cpu >= to_insert->intno_cpu) break;
+        prev=vd;
+        vd=vd->next;
+    }
+    if (vd==NULL && prev==NULL) {
+        //First item
+        vector_desc_head=to_insert;
+        vector_desc_head->next=NULL;
+    } else {
+        prev->next=to_insert;
+        to_insert->next=vd;
+    }
+}
+
+//Returns a vector_desc entry for an intno/cpu, or NULL if none exists.
+static vector_desc_t *find_desc_for_int(int intno, int cpu) 
+{
+    vector_desc_t *vd=vector_desc_head;
+    while(vd!=NULL) {
+        if (vd->intno_cpu==to_intno_cpu(intno, cpu)) break;
+        vd=vd->next;
+    }
+    return vd;
+}
+
+//Returns a vector_desc entry for an intno/cpu.
+//Either returns a preexisting one or allocates a new one and inserts
+//it into the list.
+static vector_desc_t *get_desc_for_int(int intno, int cpu) 
+{
+    vector_desc_t *vd=find_desc_for_int(intno, cpu);
+    if (vd==NULL) {
+        vector_desc_t *newvd=malloc(sizeof(vector_desc_t));
+        memset(newvd, 0, sizeof(vector_desc_t));
+        newvd->intno_cpu=to_intno_cpu(intno, cpu);
+        insert_vector_desc(newvd);
+        return newvd;
+    } else {
+        return vd;
+    }
+}
+
+esp_err_t esp_intr_mark_shared(int intno, int cpu, bool is_int_ram)
+{
+    if (intno>31) return ESP_ERR_INVALID_ARG;
+    if (cpu>=portNUM_PROCESSORS) return ESP_ERR_INVALID_ARG;
+
+    portENTER_CRITICAL(&spinlock);
+    vector_desc_t *vd=get_desc_for_int(intno, cpu);
+    vd->flags=VECDESC_FL_SHARED;
+    if (is_int_ram) vd->flags|=VECDESC_FL_INIRAM;
+    portEXIT_CRITICAL(&spinlock);
+
+    return ESP_OK;
+}
+
+esp_err_t esp_intr_reserve(int intno, int cpu)
+{
+    if (intno>31) return ESP_ERR_INVALID_ARG;
+    if (cpu>=portNUM_PROCESSORS) return ESP_ERR_INVALID_ARG;
+
+    portENTER_CRITICAL(&spinlock);
+    vector_desc_t *vd=get_desc_for_int(intno, cpu);
+    vd->flags=VECDESC_FL_RESERVED;
+    portEXIT_CRITICAL(&spinlock);
+
+    return ESP_OK;
+}
+
+//Interrupt handler table and unhandled uinterrupt routine. Duplicated 
+//from xtensa_intr.c... it's supposed to be private, but we need to look 
+//into it in order to see if someone allocated an int using 
+//xt_set_interrupt_handler.
+typedef struct xt_handler_table_entry {
+    void * handler;
+    void * arg;
+} xt_handler_table_entry;
+extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS];
+extern void xt_unhandled_interrupt(void * arg);
+
+//Returns true if handler for interrupt is not the default unhandled interrupt handler
+static bool int_has_handler(int intr, int cpu) 
+{
+    return (_xt_interrupt_table[intr*portNUM_PROCESSORS+cpu].handler != xt_unhandled_interrupt);
+}
+
+
+//Locate a free interrupt compatible with the flags given.
+//The 'force' argument can be -1, or 0-31 to force checking a certain interrupt.
+static int get_free_int(int flags, int cpu, int force)
+{
+    int x;
+    int best=-1;
+    int bestLevel=9;
+    int bestSharedCt=INT_MAX;
+    //Default vector desc, for vectors not in the linked list
+    vector_desc_t empty_vect_desc;
+    memset(&empty_vect_desc, 0, sizeof(vector_desc_t));
+    //Level defaults to any low/med interrupt
+    if (!(flags&ESP_INTR_FLAG_LEVELMASK)) flags|=ESP_INTR_FLAG_LOWMED;
+
+    ALCHLOG(TAG, "get_free_int: start looking. Current cpu: %d", cpu);
+    //Iterate over the 32 possible interrupts
+    for (x=0; x!=31; x++) {
+        //Grab the vector_desc for this vector.
+        vector_desc_t *vd=find_desc_for_int(x, cpu);
+        if (vd==NULL) vd=&empty_vect_desc;
+        //See if we have a forced interrupt; if so, bail out if this is not it.
+        if (force!=-1 && force!=x) {
+            ALCHLOG(TAG, "Ignoring int %d: forced to %d", x, force);
+            continue;
+        }
+        ALCHLOG(TAG, "Int %d reserved %d level %d %s hasIsr %d", 
+            x, int_desc[x].cpuflags[cpu]==INTDESC_RESVD, int_desc[x].level, 
+            int_desc[x].type==INTTP_LEVEL?"LEVEL":"EDGE", int_has_handler(x, cpu));
+        //Check if interrupt is not reserved by design
+        if (int_desc[x].cpuflags[cpu]==INTDESC_RESVD) { //ToDo: Check for SPECIAL and force!=-1
+            ALCHLOG(TAG, "....Unusable: reserved");
+            continue;
+        }
+        //Check if the interrupt level is acceptable
+        if (!(flags&(1<<int_desc[x].level))) {
+            ALCHLOG(TAG, "....Unusable: incompatible level");
+            continue;
+        }
+        //check if edge/level type matches what we want
+        if (((flags&ESP_INTR_FLAG_EDGE) && (int_desc[x].type==INTTP_LEVEL)) || 
+                (((!(flags&ESP_INTR_FLAG_EDGE)) && (int_desc[x].type==INTTP_EDGE)))) {
+            ALCHLOG(TAG, "....Unusable: incompatible trigger type");
+            continue;
+        }
+        //Check if interrupt already is allocated by xt_set_interrupt_handler
+        if (int_has_handler(x, cpu) && !(vd->flags&VECDESC_FL_SHARED))  {
+            ALCHLOG(TAG, "....Unusable: already allocated");
+            continue;
+        }
+        //Ints can't be both shared and non-shared.
+        assert(!((vd->flags&VECDESC_FL_SHARED)&&(vd->flags&VECDESC_FL_NONSHARED)));
+        //check if interrupt is reserved at runtime
+        if (vd->flags&VECDESC_FL_RESERVED)  {
+            ALCHLOG(TAG, "....Unusable: reserved at runtime.");
+            continue;
+        }
+        //check if interrupt already is in use by a non-shared interrupt
+        if (vd->flags&VECDESC_FL_NONSHARED) {
+            ALCHLOG(TAG, "....Unusable: already in (non-shared) use.");
+            continue;
+        }
+        if (flags&ESP_INTR_FLAG_SHARED) {
+            //We're allocating a shared int.
+            bool in_iram_flag=((flags&ESP_INTR_FLAG_IRAM)!=0);
+            bool desc_in_iram_flag=((vd->flags&VECDESC_FL_INIRAM)!=0);
+            //Bail out if int is shared, but iram property doesn't match what we want.
+            if ((vd->flags&VECDESC_FL_SHARED) && (desc_in_iram_flag!=in_iram_flag))  {
+                ALCHLOG(TAG, "....Unusable: shared but iram prop doesn't match");
+                continue;
+            }
+            //See if int already is used as a shared interrupt.
+            if (vd->flags&VECDESC_FL_SHARED) {
+                //We can use this already-marked-as-shared interrupt. Count the already attached isrs in order to see
+                //how useful it is.
+                int no=0;
+                shared_vector_desc_t *svdesc=vd->shared_vec_info;
+                while (svdesc!=NULL) {
+                    no++;
+                    svdesc=svdesc->next;
+                }
+                if (no<bestSharedCt || bestLevel>int_desc[x].level) {
+                    //Seems like this shared vector is both okay and has the least amount of ISRs already attached to it.
+                    best=x;
+                    bestSharedCt=no;
+                    bestLevel=int_desc[x].level;
+                    ALCHLOG(TAG, "...int %d more usable as a shared int: has %d existing vectors", x, no);
+                } else {
+                    ALCHLOG(TAG, "...worse than int %d", best);
+                }
+            } else {
+                if (best==-1) {
+                    //We haven't found a feasible shared interrupt yet. This one is still free and usable, even if 
+                    //not marked as shared.
+                    //Remember it in case we don't find any other shared interrupt that qualifies.
+                    if (bestLevel>int_desc[x].level) {
+                        best=x;
+                        bestLevel=int_desc[x].level;
+                        ALCHLOG(TAG, "...int %d usable as a new shared int", x);
+                    }
+                } else {
+                    ALCHLOG(TAG, "...already have a shared int");
+                }
+            }
+        } else {
+            //We need an unshared IRQ; can't use shared ones; bail out if this is shared.
+            if (vd->flags&VECDESC_FL_SHARED) {
+                ALCHLOG(TAG, "...Unusable: int is shared, we need non-shared.");
+                continue;
+            }
+            //Seems this interrupt is feasible. Select it and break out of the loop; no need to search further.
+            if (bestLevel>int_desc[x].level) {
+                best=x;
+                bestLevel=int_desc[x].level;
+            } else {
+                ALCHLOG(TAG, "...worse than int %d", best);
+            }
+        }
+    }
+    ALCHLOG(TAG, "get_free_int: using int %d", best);
+
+    //Okay, by now we have looked at all potential interrupts and hopefully have selected the best one in best.
+    return best;
+}
+
+
+//Common shared isr handler. Chain-call all ISRs.
+static void IRAM_ATTR shared_intr_isr(void *arg) 
+{
+    vector_desc_t *vd=(vector_desc_t*)arg;
+    shared_vector_desc_t *sh_vec=vd->shared_vec_info;
+    portENTER_CRITICAL(&spinlock);
+    while(sh_vec) {
+        if ((sh_vec->statusreg == NULL) || (*sh_vec->statusreg & sh_vec->statusmask)) {
+            sh_vec->isr(sh_vec->arg);
+            sh_vec=sh_vec->next;
+        }
+    }
+    portEXIT_CRITICAL(&spinlock);
+}
+
+
+//We use ESP_EARLY_LOG* here because this can be called before the scheduler is running.
+esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusreg, uint32_t intrstatusmask, intr_handler_t handler, 
+                                        void *arg, int_handle_t *ret_handle) 
+{
+    int force=-1;
+    ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): checking args", xPortGetCoreID());
+    //Shared interrupts should be level-triggered.
+    if ((flags&ESP_INTR_FLAG_SHARED) && (flags&ESP_INTR_FLAG_EDGE)) return ESP_ERR_INVALID_ARG;
+    //You can't set an handler / arg for a non-C-callable interrupt.
+    if ((flags&ESP_INTR_FLAG_HIGH) && (handler)) return ESP_ERR_INVALID_ARG;
+    //Shared ints should have handler
+    if ((flags&ESP_INTR_FLAG_SHARED) && (!handler)) return ESP_ERR_INVALID_ARG;
+    //Only shared interrupts can have status reg / mask
+    if (intrstatusreg && (!(flags&ESP_INTR_FLAG_SHARED))) return ESP_ERR_INVALID_ARG;
+    //Statusreg should have a mask
+    if (intrstatusreg && !intrstatusmask) return ESP_ERR_INVALID_ARG;
+
+    //Default to prio 1 for shared interrupts. Default to prio 1, 2 or 3 for non-shared interrupts.
+    if ((flags&ESP_INTR_FLAG_LEVELMASK)==0) {
+        if (flags&ESP_INTR_FLAG_SHARED) {
+            flags|=ESP_INTR_FLAG_LEVEL1;
+        } else {
+            flags|=ESP_INTR_FLAG_LOWMED;
+        }
+    }
+    ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): Args okay. Resulting flags 0x%X", xPortGetCoreID(), flags);
+    
+    //Check 'special' interrupt sources. These are tied to one specific interrupt, so we
+    //have to force get_free_int to only look at that.
+    if (source==ETS_INTERNAL_TIMER0_INTR_SOURCE) force=ETS_INTERNAL_TIMER0_INTR_NO;
+    if (source==ETS_INTERNAL_TIMER1_INTR_SOURCE) force=ETS_INTERNAL_TIMER1_INTR_NO;
+    if (source==ETS_INTERNAL_TIMER2_INTR_SOURCE) force=ETS_INTERNAL_TIMER2_INTR_NO;
+    if (source==ETS_INTERNAL_SW0_INTR_SOURCE) force=ETS_INTERNAL_SW0_INTR_NO;
+    if (source==ETS_INTERNAL_SW1_INTR_SOURCE) force=ETS_INTERNAL_SW1_INTR_NO;
+    if (source==ETS_INTERNAL_PROFILING_INTR_SOURCE) force=ETS_INTERNAL_PROFILING_INTR_NO;
+
+    portENTER_CRITICAL(&spinlock);
+    int cpu=xPortGetCoreID();
+    //See if we can find an interrupt that matches the flags.
+    int intr=get_free_int(flags, cpu, force);
+    if (intr==-1) {
+        //None found. Bail out.
+        portEXIT_CRITICAL(&spinlock);
+        return ESP_ERR_NOT_FOUND;
+    }
+    //Get an int vector desc for int.
+    vector_desc_t *vd=get_desc_for_int(intr, cpu);
+
+    //Allocate that int!
+    if (flags&ESP_INTR_FLAG_SHARED) {
+        //Populate vector entry and add to linked list.
+        shared_vector_desc_t *sh_vec=malloc(sizeof(shared_vector_desc_t));
+        memset(sh_vec, 0, sizeof(shared_vector_desc_t));
+        sh_vec->statusreg=(uint32_t*)intrstatusreg;
+        sh_vec->statusmask=intrstatusmask;
+        sh_vec->isr=handler;
+        sh_vec->arg=arg;
+        sh_vec->next=vd->shared_vec_info;
+        vd->shared_vec_info=sh_vec;
+        vd->flags|=VECDESC_FL_SHARED;
+        //(Re-)set shared isr handler to new value.
+        xt_set_interrupt_handler(intr, shared_intr_isr, vd);
+    } else {
+        //Mark as unusable for other interrupt sources. This is ours now!
+        vd->flags=VECDESC_FL_NONSHARED;
+        if (handler) {
+            xt_set_interrupt_handler(intr, handler, arg);
+        }
+        if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr);
+    }
+    if (flags&ESP_INTR_FLAG_IRAM) {
+        vd->flags|=VECDESC_FL_INIRAM;
+        non_iram_int_mask[cpu]&=~(1<<intr);
+    } else {
+        vd->flags&=~VECDESC_FL_INIRAM;
+        non_iram_int_mask[cpu]|=(1<<intr);
+    }
+    if (source>=0) {
+        intr_matrix_set(cpu, source, intr);
+    }
+    //If we should return a handle, allocate it here.
+    if (ret_handle!=NULL) {
+        int_handle_data_t *ret;
+        ret=malloc(sizeof(int_handle_data_t));
+        ret->vector_desc=vd;
+        ret->shared_vector_desc=vd->shared_vec_info;
+        *ret_handle=ret;
+    }
+
+    //We enable the interrupt in any case. For shared interrupts, the interrupts are enabled as soon as we exit 
+    //the critical region anyway, so this is consistent.
+    portEXIT_CRITICAL(&spinlock);
+    ESP_EARLY_LOGD(TAG, "Connected src %d to int %d (cpu %d)", source, intr, cpu);
+    ESP_INTR_ENABLE(intr);
+    return ESP_OK;
+}
+
+esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, int_handle_t *ret_handle) 
+{
+    /*
+      As an optimization, we can create a table with the possible interrupt status registers and masks for every single
+      source there is. We can then add code here to look up an applicable value and pass that to the 
+      esp_intr_alloc_intrstatus function.
+    */
+    return esp_intr_alloc_intrstatus(source, flags, 0, 0, handler, arg, ret_handle);
+}
+
+
+esp_err_t esp_intr_free(int_handle_t handle) 
+{
+    bool free_shared_vector=false;
+    if (!handle) return ESP_ERR_INVALID_ARG;
+    //This routine should be called from the interrupt the task is scheduled on.
+    if (to_cpu(handle->vector_desc->intno_cpu)!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG;
+
+    portENTER_CRITICAL(&spinlock);
+    if (handle->vector_desc->flags&VECDESC_FL_SHARED) {
+        //Find and kill the shared int 
+        shared_vector_desc_t *svd=handle->vector_desc->shared_vec_info;
+        shared_vector_desc_t *prevsvd=NULL;
+        assert(svd); //should be something in there for a shared int
+        while (svd!=NULL) {
+            if (svd==handle->shared_vector_desc) {
+                //Found it. Now kill it.
+                if (prevsvd) {
+                    prevsvd->next=svd->next;
+                } else {
+                    handle->vector_desc->shared_vec_info=svd->next;
+                }
+                free(svd);
+                break;
+            }
+            prevsvd=svd;
+            svd=svd->next;
+        }
+        //If nothing left, disable interrupt.
+        if (handle->vector_desc->shared_vec_info==NULL) free_shared_vector=true;
+        ESP_LOGV(TAG, "esp_intr_free: Deleting shared int: %s. Shared int is %s", svd?"not found or last one":"deleted", free_shared_vector?"empty now.":"still in use");
+    }
+
+    if ((handle->vector_desc->flags&VECDESC_FL_NONSHARED) || free_shared_vector) {
+        ESP_LOGV(TAG, "esp_intr_free: Disabling int, killing handler");
+        //Interrupt is not shared. Just disable it and revert to the default interrupt handler.
+        ESP_INTR_DISABLE(to_intno(handle->vector_desc->intno_cpu));
+        xt_set_interrupt_handler(to_intno(handle->vector_desc->intno_cpu), xt_unhandled_interrupt, NULL);
+        //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. 
+        handle->vector_desc->flags&=!(VECDESC_FL_NONSHARED|VECDESC_FL_RESERVED);
+        //Also kill non_iram mask bit.
+        non_iram_int_mask[to_cpu(handle->vector_desc->intno_cpu)]&=~(1<<(to_intno(handle->vector_desc->intno_cpu)));
+    }
+    portEXIT_CRITICAL(&spinlock);
+    free(handle);
+    return ESP_OK;
+}
+
+int esp_intr_get_intno(int_handle_t handle)
+{
+    return to_intno(handle->vector_desc->intno_cpu);
+}
+
+int esp_intr_get_cpu(int_handle_t handle)
+{
+    return to_cpu(handle->vector_desc->intno_cpu);
+}
+
+esp_err_t esp_intr_enable(int_handle_t handle)
+{
+    if (!handle) return ESP_ERR_INVALID_ARG;
+    if (handle->shared_vector_desc) return ESP_ERR_INVALID_ARG; //Shared ints can't be enabled using this function.
+    if (to_cpu(handle->vector_desc->intno_cpu)!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; //Can only enable ints on this cpu
+    ESP_INTR_ENABLE(to_intno(handle->vector_desc->intno_cpu));
+    return ESP_OK;
+}
+
+esp_err_t esp_intr_disable(int_handle_t handle)
+{
+    if (!handle) return ESP_ERR_INVALID_ARG;
+    if (handle->shared_vector_desc) return ESP_ERR_INVALID_ARG; //Shared ints can't be disabled using this function.
+    if (to_cpu(handle->vector_desc->intno_cpu)!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; //Can only disable ints on this cpu
+    ESP_INTR_DISABLE(to_intno(handle->vector_desc->intno_cpu));
+    return ESP_OK;
+}
+
+
+void esp_intr_noniram_disable() 
+{
+    int oldint;
+    int cpu=xPortGetCoreID();
+    int intmask=~non_iram_int_mask[cpu];
+    assert(non_iram_int_disabled_flag[cpu]==false);
+    non_iram_int_disabled_flag[cpu]=true;
+    asm volatile (
+        "movi %0,0\n"
+        "xsr %0,INTENABLE\n"    //disable all ints first
+        "rsync\n"
+        "and a3,%0,%1\n"        //mask ints that need disabling
+        "wsr a3,INTENABLE\n"    //write back
+        "rsync\n"
+        :"=r"(oldint):"r"(intmask):"a3");
+    //Save which ints we did disable
+    non_iram_int_disabled[cpu]=oldint&non_iram_int_mask[cpu];
+}
+
+void esp_intr_noniram_enable() 
+{
+    int cpu=xPortGetCoreID();
+    int intmask=non_iram_int_disabled[cpu];
+    assert(non_iram_int_disabled_flag[cpu]==true);
+    non_iram_int_disabled_flag[cpu]=false;
+    asm volatile (
+        "movi a3,0\n"
+        "xsr a3,INTENABLE\n"
+        "rsync\n"
+        "or a3,a3,%0\n"
+        "wsr a3,INTENABLE\n"
+        "rsync\n"
+        ::"r"(intmask):"a3");
+}
+
+
+
+
+
+
index 860556b8c5034599f41545d8ead1d91575a34f73..8585260e2faf3f17cba34af89b2a8bef04b88720 100644 (file)
@@ -27,6 +27,7 @@
 #include <esp_types.h>
 #include "esp_err.h"
 #include "esp_intr.h"
+#include "esp_intr_alloc.h"
 #include "esp_attr.h"
 #include "esp_freertos_hooks.h"
 #include "soc/timer_group_struct.h"
@@ -51,7 +52,7 @@ static wdt_task_t *wdt_task_list=NULL;
 static portMUX_TYPE taskwdt_spinlock = portMUX_INITIALIZER_UNLOCKED;
 
 
-static void IRAM_ATTR task_wdt_isr(void *arg) {
+static void task_wdt_isr(void *arg) {
     wdt_task_t *wdttask;
     const char *cpu;
     //Feed the watchdog so we do not reset
@@ -71,21 +72,21 @@ static void IRAM_ATTR task_wdt_isr(void *arg) {
         return;
     }
     //Watchdog got triggered because at least one task did not report in.
-    ets_printf(DRAM_STR("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n"));
+    ets_printf("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n");
     for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
         if (!wdttask->fed_watchdog) {
             cpu=xTaskGetAffinity(wdttask->task_handle)==0?DRAM_STR("CPU 0"):DRAM_STR("CPU 1");
             if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu=DRAM_STR("CPU 0/1");
-            ets_printf(DRAM_STR(" - %s (%s)\n"), pcTaskGetTaskName(wdttask->task_handle), cpu);
+            ets_printf(" - %s (%s)\n", pcTaskGetTaskName(wdttask->task_handle), cpu);
         }
     }
     ets_printf(DRAM_STR("Tasks currently running:\n"));
     for (int x=0; x<portNUM_PROCESSORS; x++) {
-        ets_printf(DRAM_STR("CPU %d: %s\n"), x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
+        ets_printf("CPU %d: %s\n", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
     }
 
 #if CONFIG_TASK_WDT_PANIC
-    ets_printf(DRAM_STR("Aborting.\n"));
+    ets_printf("Aborting.\n");
     abort();
 #endif
     portEXIT_CRITICAL(&taskwdt_spinlock);
@@ -201,12 +202,7 @@ void esp_task_wdt_init() {
 #if CONFIG_TASK_WDT_CHECK_IDLE_TASK
     esp_register_freertos_idle_hook(idle_hook);
 #endif
-    ESP_INTR_DISABLE(ETS_T0_WDT_INUM);
-    intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM);
-    xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL);
-    TIMERG0.int_clr_timers.wdt=1;
-    timer_group_intr_enable(TIMER_GROUP_0, TIMG_WDT_INT_ENA_M);
-    ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
+    esp_intr_alloc(ETS_TG0_WDT_LEVEL_INTR_SOURCE, 0, task_wdt_isr, NULL, NULL);
 }
 
 
index cbbab5149edbf957f781ab7baff18a6c8d111650..3dc61d809cce328d162e616d154f4199a6dfeb32 100644 (file)
@@ -35,6 +35,7 @@
 #include "esp_err.h"
 #include "esp_log.h"
 #include "esp_eth.h"
+#include "esp_intr_alloc.h"
 
 #include "emac_common.h"
 #include "emac_desc.h"
@@ -305,19 +306,16 @@ static void IRAM_ATTR emac_process_intr(void *arg)
     }
 }
 
+//ToDo: this should only be called once because this allocates the interrupt as well.
 static void emac_enable_intr()
 {
     //init emac intr
-    REG_SET_FIELD(DPORT_PRO_EMAC_INT_MAP_REG, DPORT_PRO_EMAC_INT_MAP, ETS_EMAC_INUM);
-    xt_set_interrupt_handler(ETS_EMAC_INUM, emac_process_intr, NULL);
-    xt_ints_on(1 << ETS_EMAC_INUM);
-
+    esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL);
     REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, EMAC_INTR_ENABLE_BIT);
 }
 
 static void emac_disable_intr()
 {
-    xt_ints_off(1 << ETS_EMAC_INUM);
     REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, 0);
 }
 
index 2f5dc3542e41e3ed3bfe25c28c566e94aea22baf..476703227756fbf5b237ebcbf6cad7e4b2a084fa 100644 (file)
@@ -39,7 +39,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #if XCHAL_HAVE_EXCEPTIONS
 
 /* Handler table is in xtensa_intr_asm.S */
-// Todo: Make multicore - JD
 
 extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM*portNUM_PROCESSORS];
 
index 8c7ae63fdb6823c1cae21a4d316c4e30f3edb0ed..aff4e3cbc2985d566f80f8fef341f11c874cbd09 100644 (file)
@@ -40,6 +40,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 -------------------------------------------------------------------------------
 */
 
+
+#if XT_USE_SWPRI
+/* Warning - this is not multicore-compatible. */
     .data
     .global _xt_intdata
     .align  8
@@ -53,7 +56,7 @@ _xt_intdata:
 
 _xt_intenable:     .word   0             /* Virtual INTENABLE     */
 _xt_vpri_mask:     .word   0xFFFFFFFF    /* Virtual priority mask */
-
+#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -124,7 +127,8 @@ _xt_exception_table:
   unsigned int xt_ints_on ( unsigned int mask )
 
   Enables a set of interrupts. Does not simply set INTENABLE directly, but
-  computes it as a function of the current virtual priority.
+  computes it as a function of the current virtual priority if XT_USE_SWPRI is
+  enabled.
   Can be called from interrupt handlers.
 -------------------------------------------------------------------------------
 */
@@ -137,7 +141,9 @@ _xt_exception_table:
 xt_ints_on:
 
     ENTRY0
+
 #if XCHAL_HAVE_INTERRUPTS
+#if XT_USE_SWPRI
     movi    a3, 0
     movi    a4, _xt_intdata
     xsr     a3, INTENABLE        /* Disables all interrupts   */
@@ -149,6 +155,13 @@ xt_ints_on:
     and     a5, a5, a6           /* a5 = _xt_intenable & _xt_vpri_mask */
     wsr     a5, INTENABLE        /* Reenable interrupts       */
     mov     a2, a3               /* Previous mask             */
+#else
+    movi    a3, 0
+    xsr     a3, INTENABLE        /* Disables all interrupts   */
+    or      a2, a3, a2           /* set bits in mask */
+    wsr     a2, INTENABLE        /* Re-enable ints */
+    mov     a2, a3               /* return prev mask */
+#endif
 #else
     movi    a2, 0                /* Return zero */
 #endif
@@ -162,7 +175,8 @@ xt_ints_on:
   unsigned int xt_ints_off ( unsigned int mask )
 
   Disables a set of interrupts. Does not simply set INTENABLE directly,
-  but computes it as a function of the current virtual priority.
+  but computes it as a function of the current virtual priority if XT_USE_SWPRI is
+  enabled.
   Can be called from interrupt handlers.
 -------------------------------------------------------------------------------
 */
@@ -176,6 +190,7 @@ xt_ints_off:
 
     ENTRY0
 #if XCHAL_HAVE_INTERRUPTS
+#if XT_USE_SWPRI
     movi    a3, 0
     movi    a4, _xt_intdata
     xsr     a3, INTENABLE        /* Disables all interrupts    */
@@ -188,6 +203,14 @@ xt_ints_off:
     and     a5, a5, a6           /* a5 = _xt_intenable & _xt_vpri_mask */
     wsr     a5, INTENABLE        /* Reenable interrupts        */
     mov     a2, a3               /* Previous mask              */
+#else
+    movi    a3, 0
+    xsr     a3, INTENABLE        /* Disables all interrupts   */
+    or      a2, a3, a2           /* set bits in mask */
+    xor     a2, a3, a2           /* invert bits in mask set in mask, essentially clearing them */
+    wsr     a2, INTENABLE        /* Re-enable ints */
+    mov     a2, a3               /* return prev mask */
+#endif
 #else
     movi    a2, 0                /* return zero */
 #endif
index 2fe4d920c3a2dbe75f56495b0e5c4509ea3e9541..5cce103ea3496b96f8901a1fab02a127cac39222 100644 (file)
@@ -32,6 +32,7 @@
 #include "esp_system.h"
 #include "esp_log.h"
 #include "esp_intr.h"
+#include "esp_intr_alloc.h"
 #include "esp_attr.h"
 
 #include "soc/dport_reg.h"
@@ -59,10 +60,7 @@ static void rsa_isr_initialise()
 {
     if (op_complete_sem == NULL) {
         op_complete_sem = xSemaphoreCreateBinary();
-        intr_matrix_set(xPortGetCoreID(), ETS_RSA_INTR_SOURCE, CONFIG_MBEDTLS_MPI_INTERRUPT_NUM);
-        xt_set_interrupt_handler(CONFIG_MBEDTLS_MPI_INTERRUPT_NUM, &rsa_complete_isr, NULL);
-        xthal_set_intclear(1 << CONFIG_MBEDTLS_MPI_INTERRUPT_NUM);
-        xt_ints_on(1 << CONFIG_MBEDTLS_MPI_INTERRUPT_NUM);
+        esp_intr_alloc(ETS_RSA_INTR_SOURCE, 0, rsa_complete_isr, NULL, NULL);
     }
 }
 
index 1baa955759456848767a7b66afbd23bd5f1588cf..363e17b3eb810731d606d74c3370e35e98574d6e 100644 (file)
@@ -22,6 +22,7 @@
 #include <sys/times.h>
 #include <sys/lock.h>
 #include "esp_attr.h"
+#include "esp_intr_alloc.h"
 #include "soc/soc.h"
 #include "soc/rtc_cntl_reg.h"
 #include "soc/frc_timer_reg.h"
@@ -105,9 +106,7 @@ void esp_setup_time_syscalls()
     SET_PERI_REG_MASK(FRC_TIMER_CTRL_REG(0),
             FRC_TIMER_ENABLE | \
             FRC_TIMER_INT_ENABLE);
-    intr_matrix_set(xPortGetCoreID(), ETS_TIMER1_INTR_SOURCE, ETS_FRC1_INUM);
-    xt_set_interrupt_handler(ETS_FRC1_INUM, &frc_timer_isr, NULL);
-    xt_ints_on(1 << ETS_FRC1_INUM);
+    esp_intr_alloc(ETS_TIMER1_INTR_SOURCE, 0, &frc_timer_isr, NULL, NULL);
 #endif // WITH_FRC1
 }
 
index 904007b3160f6d20ec3892e4b538b48b091d5a76..f30db80cd8d23a52f03206318df767692da3562e 100644 (file)
@@ -27,6 +27,7 @@
 #include "sdkconfig.h"
 #include "esp_ipc.h"
 #include "esp_attr.h"
+#include "esp_intr_alloc.h"
 #include "esp_spi_flash.h"
 #include "esp_log.h"
 
@@ -60,6 +61,8 @@ void IRAM_ATTR spi_flash_op_block_func(void* arg)
 {
     // Disable scheduler on this CPU
     vTaskSuspendAll();
+    // Restore interrupts that aren't located in IRAM
+    esp_intr_noniram_disable();
     uint32_t cpuid = (uint32_t) arg;
     // Disable cache so that flash operation can start
     spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
@@ -70,6 +73,8 @@ void IRAM_ATTR spi_flash_op_block_func(void* arg)
     }
     // Flash operation is complete, re-enable cache
     spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
+    // Restore interrupts that aren't located in IRAM
+    esp_intr_noniram_enable();
     // Re-enable scheduler
     xTaskResumeAll();
 }
@@ -104,6 +109,8 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
         // occupied by highest priority task
         assert(xPortGetCoreID() == cpuid);
     }
+    // Kill interrupts that aren't located in IRAM
+    esp_intr_noniram_disable();
     // Disable cache on this CPU as well
     spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
 }
@@ -130,6 +137,8 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
     }
     // Release API lock
     spi_flash_op_unlock();
+    // Re-enable non-iram interrupts
+    esp_intr_noniram_enable();
 }
 
 #else // CONFIG_FREERTOS_UNICORE
@@ -151,6 +160,7 @@ void spi_flash_op_unlock()
 
 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
 {
+    esp_intr_noniram_disable();
     spi_flash_op_lock();
     spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
 }
@@ -159,6 +169,7 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
 {
     spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
     spi_flash_op_unlock();
+    esp_intr_noniram_enable();
 }
 
 #endif // CONFIG_FREERTOS_UNICORE
index c1aebcd308588294a0b1fc12547dcc979e8c9f49..bdb91a4dcef9a3e317fbe87c8f88afcdadd7bfb6 100755 (executable)
@@ -27,7 +27,8 @@ INPUT = ../components/esp32/include/esp_wifi.h \
        ../components/esp32/include/esp_task_wdt.h \
        ../components/app_update/include/esp_ota_ops.h \
        ../components/ethernet/include/esp_eth.h \
-       ../components/ulp/include/esp32/ulp.h
+       ../components/ulp/include/esp32/ulp.h \
+       ../components/esp32/include/esp_intr_alloc.h
 
 ## Get warnings for functions that have no documentation for their parameters or return value 
 ##
diff --git a/docs/api/intr_alloc.rst b/docs/api/intr_alloc.rst
new file mode 100644 (file)
index 0000000..e4e9bdb
--- /dev/null
@@ -0,0 +1,84 @@
+Interrupt allocation
+====================
+
+Overview
+--------
+
+The ESP32 has two cores, with 32 interrupts each. Each interrupt has a certain priority level, most (but not all) interrupts are connected
+to the interrupt mux. Because there are more interrupt sources than interrupts, sometimes it makes sense to share an interrupt in
+multiple drivers. The esp_intr_alloc abstraction exists to hide all these implementation details.
+
+A driver can allocate an interrupt for a certain peripheral by calling esp_intr_alloc (or esp_intr_alloc_sintrstatus). It can use
+the flags passed to this function to set the type of interrupt allocated, specifying a specific level or trigger method. The
+interrupt allocation code will then find an applicable interrupt, use the interrupt mux to hook it up to the peripheral, and
+install the given interrupt handler and ISR to it.
+
+This code has two different types of interrupts it handles differently: Shared interrupts and non-shared interrupts. The simplest
+of the two are non-shared interrupts: a separate interrupt is allocated per esp_intr_alloc call and this interrupt is solely used for
+the peripheral attached to it, with only one ISR that will get called. Non-shared interrupts can have multiple peripherals triggering 
+it, with multiple ISRs being called when one of the peripherals attached signals an interrupt. Thus, ISRs that are intended for shared
+interrupts should check the interrupt status of the peripheral they service in order to see if any action is required.
+
+Non-shared interrupts can be either level- or edge-triggered. Shared interrupts can
+only be level interrupts (because of the chance of missed interrupts when edge interrupts are
+used.)
+(The logic behind this: DevA and DevB share an int. DevB signals an int. Int line goes high. ISR handler
+calls code for DevA -> does nothing. ISR handler calls code for DevB, but while doing that,
+DevA signals an int. ISR DevB is done, clears int for DevB, exits interrupt code. Now an 
+interrupt for DevA is still pending, but because the int line never went low (DevA kept it high
+even when the int for DevB was cleared) the interrupt is never serviced.)
+
+
+
+
+Application Example
+-------------------
+
+API Reference
+-------------
+
+Header Files
+^^^^^^^^^^^^
+
+  * `esp_intr_alloc.h <https://github.com/espressif/esp-idf/blob/master/components/esp32/include/esp_intr_alloc.h>`_
+
+
+Macros
+^^^^^^
+
+.. doxygendefine:: ESP_INTR_FLAG_LEVEL1
+.. doxygendefine:: ESP_INTR_FLAG_LEVEL2
+.. doxygendefine:: ESP_INTR_FLAG_LEVEL3
+.. doxygendefine:: ESP_INTR_FLAG_LEVEL4
+.. doxygendefine:: ESP_INTR_FLAG_LEVEL5
+.. doxygendefine:: ESP_INTR_FLAG_LEVEL6
+.. doxygendefine:: ESP_INTR_FLAG_NMI
+.. doxygendefine:: ESP_INTR_FLAG_LOWMED
+.. doxygendefine:: ESP_INTR_FLAG_HIGH
+.. doxygendefine:: ESP_INTR_FLAG_SHARED
+.. doxygendefine:: ESP_INTR_FLAG_EDGE
+.. doxygendefine:: ESP_INTR_FLAG_IRAM
+
+Type Definitions
+^^^^^^^^^^^^^^^^
+
+Enumerations
+^^^^^^^^^^^^
+
+Structures
+^^^^^^^^^^
+
+Functions
+^^^^^^^^^
+
+.. doxygenfunction:: esp_intr_mark_shared
+.. doxygenfunction:: esp_intr_reserve
+.. doxygenfunction:: esp_intr_alloc
+.. doxygenfunction:: esp_intr_alloc_intrstatus
+.. doxygenfunction:: esp_intr_free
+.. doxygenfunction:: esp_intr_get_cpu
+.. doxygenfunction:: esp_intr_get_intno
+.. doxygenfunction:: esp_intr_disable
+.. doxygenfunction:: esp_intr_enable
+.. doxygenfunction:: esp_intr_noniram_disable
+.. doxygenfunction:: esp_intr_noniram_enable
index 4c48255ae2bcf7e8f1d91828ca5181322f54e8dd..4e58cfe02f2900415e5fcaa112f4022dcc03398e 100755 (executable)
@@ -110,6 +110,7 @@ Contents:
    Non-Volatile Storage <api/nvs_flash>
    Virtual Filesystem <api/vfs>
    Ethernet <api/esp_eth>
+   Interrupt Allocation <api/intr_alloc>
    deep-sleep-stub
 
    Template <api/template>
index dbd11fbae513c80813d6ff9a57e991ca47dc8d87..d2f7b091fa36dce9e05a8d9bad043421d9aa113e 100644 (file)
@@ -43,7 +43,6 @@ static const char* NEC_TAG = "NEC";
 #define RMT_TX_GPIO_NUM  16     /*!< GPIO number for transmitter signal */
 #define RMT_RX_CHANNEL    0     /*!< RMT channel for receiver */
 #define RMT_RX_GPIO_NUM  19     /*!< GPIO number for receiver */
-#define RMT_INTR_NUM     19     /*!< RMT interrupt number, select from soc.h */
 #define RMT_CLK_DIV      100    /*!< RMT counter clock divider */
 #define RMT_TICK_10_US    (80000000/RMT_CLK_DIV/100000)   /*!< RMT counter value for 10 us.(Source clock is APB clock) */
 
@@ -254,7 +253,7 @@ static void rmt_tx_init()
     rmt_tx.tx_config.idle_output_en = true;
     rmt_tx.rmt_mode = 0;
     rmt_config(&rmt_tx);
-    rmt_driver_install(rmt_tx.channel, 0, RMT_INTR_NUM);
+    rmt_driver_install(rmt_tx.channel, 0, 0);
 }
 
 /*
@@ -272,7 +271,7 @@ void rmt_rx_init()
     rmt_rx.rx_config.filter_ticks_thresh = 100;
     rmt_rx.rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US);
     rmt_config(&rmt_rx);
-    rmt_driver_install(rmt_rx.channel, 1000, RMT_INTR_NUM);
+    rmt_driver_install(rmt_rx.channel, 1000, 0);
 }
 
 /**
index 15d1ca2c05b4daab67d4734065b6caf452a96e7e..e91efe767def095abdf460bb5644cbd2f9cc34b6 100644 (file)
@@ -16,8 +16,6 @@
 #include "driver/periph_ctrl.h"
 #include "driver/timer.h"
 
-#define TIMER_INTR_NUM_0 17              /*!< Interrupt number for hardware timer 0 */
-#define TIMER_INTR_NUM_1 18              /*!< Interrupt number for hardware timer 1*/
 #define TIMER_INTR_SEL TIMER_INTR_LEVEL  /*!< Timer level interrupt */
 #define TIMER_GROUP    TIMER_GROUP_0     /*!< Test on timer group 0 */
 #define TIMER_DIVIDER   16               /*!< Hardware timer clock divider */
@@ -157,7 +155,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_INTR_NUM_0, TIMER_INTR_SEL, timer_group0_isr, (void*) timer_idx);
+    timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, 0);
     /*Start timer counter*/
     timer_start(timer_group, timer_idx);
 }
@@ -187,7 +185,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_INTR_NUM_1, TIMER_INTR_SEL, timer_group0_isr, (void*) timer_idx);
+    timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, 0);
     /*Start timer counter*/
     timer_start(timer_group, timer_idx);
 }
index 1da4cca56eaf60e9da68f60e659ad9aa343b0751..31d8f288705d9b80334cf9bc2a0837ed9a399192 100644 (file)
@@ -42,7 +42,6 @@ static const char* TAG = "PCNT_TEST";
 #define PCNT_L_LIM_VAL    (-10)
 #define PCNT_THRESH1_VAL  (5)
 #define PCNT_THRESH0_VAL  (-5)
-#define PCNT_INTR_NUM     (18)
 #define PCNT_INPUT_SIG_IO   (4)
 #define PCNT_INPUT_CTRL_IO  (5)
 #define LEDC_OUPUT_IO      (18)
@@ -177,7 +176,7 @@ static void pcnt_init(void)
     /*Reset counter value*/
     pcnt_counter_clear(PCNT_TEST_UNIT);
     /*Register ISR handler*/
-    pcnt_isr_register(PCNT_INTR_NUM, pcnt_intr_handler, NULL);
+    pcnt_isr_register(pcnt_intr_handler, NULL, 0);
     /*Enable interrupt for PCNT unit*/
     pcnt_intr_enable(PCNT_TEST_UNIT);
     /*Resume counting*/