mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/intr_alloc' into 'master'
Add dynamic interrupt allocation mechanism This adds: - Dynamic allocation of interrupts. Pass it the features of the interrupt you want, it'll set you up with an int. - Shared interrupts. Enables multiple peripheral drivers to use the same interrupt. - Marking what interrupts are fully executable from IRAM; if an int isn't marked like that it will get disabled once flash cache gets disabled. Also: - Modifies driver to be in line with these changes See merge request !254
This commit is contained in:
commit
bf57594ebe
@ -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_isr_handle_t *handle)
|
||||
{
|
||||
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, handle);
|
||||
}
|
||||
|
||||
/*only level interrupt can be used for wake-up function*/
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -203,6 +204,9 @@ typedef enum {
|
||||
GPIO_FLOATING, /*!< Pad floating */
|
||||
} gpio_pull_mode_t;
|
||||
|
||||
|
||||
|
||||
typedef intr_handle_t gpio_isr_handle_t;
|
||||
typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num);
|
||||
|
||||
/**
|
||||
@ -343,19 +347,18 @@ 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.
|
||||
*
|
||||
* @note
|
||||
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
*
|
||||
* @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 ;
|
||||
* - 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, gpio_isr_handle_t *handle);
|
||||
|
||||
|
||||
|
||||
@ -415,7 +418,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 +431,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 +444,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.
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "soc/ledc_struct.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -100,6 +101,7 @@ typedef struct {
|
||||
uint32_t freq_hz; /*!< LEDC timer frequency(Hz)*/
|
||||
} ledc_timer_config_t;
|
||||
|
||||
typedef intr_handle_t ledc_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief LEDC channel configuration
|
||||
@ -257,20 +259,20 @@ 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.
|
||||
* @note
|
||||
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
* @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.
|
||||
* @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
|
||||
* - 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, ledc_isr_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief configure LEDC settings
|
||||
@ -398,13 +400,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}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "soc/pcnt_struct.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -76,6 +77,8 @@ typedef struct {
|
||||
pcnt_channel_t channel; /*!< the PCNT channel */
|
||||
} pcnt_config_t;
|
||||
|
||||
typedef intr_handle_t pcnt_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Configure Pulse Counter unit
|
||||
*
|
||||
@ -213,21 +216,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.
|
||||
* @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.
|
||||
*/
|
||||
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, pcnt_isr_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief Configure PCNT pulse signal input pin and control input pin
|
||||
|
@ -117,6 +117,8 @@ typedef struct {
|
||||
};
|
||||
} rmt_config_t;
|
||||
|
||||
typedef intr_handle_t rmt_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Set RMT clock divider, channel clock is divided from source clock.
|
||||
*
|
||||
@ -566,27 +568,32 @@ 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,
|
||||
* @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.
|
||||
* @param handle If non-zero, a handle to later clean up the ISR gets stored here.
|
||||
*
|
||||
* @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, rmt_isr_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief Deregister previously registered RMT interrupt handler
|
||||
*
|
||||
* @param handle Handle obtained from rmt_isr_register
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Handle invalid
|
||||
*/
|
||||
esp_err_t rmt_isr_deregister(rmt_isr_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Fill memory data of channel with given RMT items.
|
||||
@ -727,7 +734,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,25 +754,20 @@ 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}
|
||||
* #include "esp_attr.h"
|
||||
* //we should add 'IRAM_ATTR' attribution when we declare the isr function
|
||||
* void IRAM_ATTR rmt_isr_handler(void* arg)
|
||||
* {
|
||||
* //read RMT interrupt status.
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "soc/soc.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -94,12 +95,19 @@ 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;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Interrupt handle, used in order to free the isr after use.
|
||||
* Aliases to an int handle for now.
|
||||
*/
|
||||
typedef intr_handle_t timer_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Read the counter value of hardware timer.
|
||||
*
|
||||
@ -245,21 +253,20 @@ 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.
|
||||
* 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.
|
||||
@ -268,7 +275,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, timer_isr_handle_t *handle);
|
||||
|
||||
/** @brief Initializes and configure the timer.
|
||||
*
|
||||
|
@ -19,6 +19,7 @@ extern "C" {
|
||||
#endif
|
||||
#include "esp_intr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#define TOUCH_PAD_SLEEP_CYCLE_CONFIG (0x1000)//The Time is 150Khz,the Max value is 0xffff
|
||||
#define TOUCH_PAD_MEASURE_CYCLE_CONFIG (0xffff)//The Time is 8Mhz,the Max value is 0xffff
|
||||
typedef enum {
|
||||
@ -34,6 +35,9 @@ typedef enum {
|
||||
TOUCH_PAD_NUM9, /*!< Touch pad channel 0 is GPIO32*/
|
||||
TOUCH_PAD_MAX,
|
||||
} touch_pad_t;
|
||||
|
||||
typedef intr_handle_t touch_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize touch module.
|
||||
*
|
||||
@ -79,44 +83,40 @@ esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t * touch_value);
|
||||
/**
|
||||
* @brief register TouchPad 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 touch_intr_num Touch 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.
|
||||
* @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 GPIO error
|
||||
*/
|
||||
esp_err_t touch_pad_isr_handler_register(uint32_t touch_intr_num, void(*fn)(void*), void *arg);
|
||||
esp_err_t touch_pad_isr_handler_register(void(*fn)(void *), void *arg, int intr_alloc_flags, touch_isr_handle_t *handle);
|
||||
|
||||
|
||||
/**
|
||||
* *************** ATTENTION ********************/
|
||||
/**
|
||||
*@attention
|
||||
*Touch button is through the body's capacitive characteristics,
|
||||
*there is a charge discharge circuit inside the. When the hands touch,
|
||||
*the charge and discharge time will be slow.
|
||||
*Because of the different hardware, each pad needs to be calibrated at the factory.
|
||||
*We use touch_pad_read to determine factory parament.
|
||||
*/
|
||||
*Touch button is through the body's capacitive characteristics,
|
||||
*there is a charge discharge circuit inside the. When the hands touch,
|
||||
*the charge and discharge time will be slow.
|
||||
*Because of the different hardware, each pad needs to be calibrated at the factory.
|
||||
*We use touch_pad_read to determine factory parameters.
|
||||
*/
|
||||
/**
|
||||
*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ *
|
||||
*----------EXAMPLE TO CONFIGURE GPIO AS OUTPUT ------------ *
|
||||
* @code{c}
|
||||
* touch_pad_init();
|
||||
* void taskA(void* arg)
|
||||
* {
|
||||
* for(;;){
|
||||
* vtaskDelay(20/portTICK_PERIOD_MS);
|
||||
* ets_printf("tocuch pad value %u\n",touch_pad_read(0));//Take the touched status and untouched status value
|
||||
* ets_printf("touch pad value %u\n",touch_pad_read(0));//Take the touched status and untouched status value
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
@ -124,22 +124,17 @@ esp_err_t touch_pad_isr_handler_register(uint32_t touch_intr_num, void(*fn)(void
|
||||
/**
|
||||
*----------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.
|
||||
* touch_pad_isr_handler_register(19,rtc_intr,NULL); //hook the isr handler for TouchPad interrupt
|
||||
* touch_pad_isr_handler_register(rtc_intr,NULL, 0, NULL) //hook the isr handler for TouchPad interrupt
|
||||
* @endcode
|
||||
* @note
|
||||
* 1. user should arrange the INUMs that used, better not to use a same INUM for different interrupt.
|
||||
* 2. do not pick the INUM that already occupied by the system.
|
||||
* 3. refer to soc.h to check which INUMs that can be used.
|
||||
*/
|
||||
/**
|
||||
*----------EXAMPLE TO USE TOUCH_PAD------------ *
|
||||
* @code{c}
|
||||
* touch_pad_init();//only init one time
|
||||
* touch_pad_config(0,300);//set the intr threshold,use touch_pad_read to determine this threshold
|
||||
* touch_pad_isr_handler_register(19,rtc_intr,NULL)
|
||||
* touch_pad_isr_handler_register(rtc_intr,NULL, 0, NULL)
|
||||
* #include "esp_attr.h"
|
||||
* void IRAM_ATTR rtc_intr(void * arg)
|
||||
* void rtc_intr(void * arg)
|
||||
* {
|
||||
* uint32_t pad_intr = READ_PERI_REG(SARADC_SAR_TOUCH_CTRL2_REG) & 0x3ff;
|
||||
* uint8_t i = 0;
|
||||
|
@ -366,21 +366,31 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
|
||||
* @brief register UART interrupt handler(ISR).
|
||||
*
|
||||
* @note UART ISR 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.
|
||||
*
|
||||
* @attention The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details
|
||||
* @param fn Interrupt handler function.
|
||||
* @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_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg);
|
||||
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. Must be called on the same core as
|
||||
* uart_isr_register was called.
|
||||
*
|
||||
* @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
|
||||
@ -461,14 +471,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.
|
||||
* If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..
|
||||
* @param queue_size UART event queue size/depth.
|
||||
* @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details
|
||||
* @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue.
|
||||
* @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_FAIL Parameter error
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Uninstall UART driver.
|
||||
@ -733,7 +744,7 @@ esp_err_t uart_flush(uart_port_t uart_num);
|
||||
* //Set UART log level
|
||||
* esp_log_level_set(TAG, ESP_LOG_INFO);
|
||||
* //Install UART driver, and get the queue.
|
||||
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, &uart0_queue);
|
||||
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, &uart0_queue, 0);
|
||||
* //Create a task to handler UART event from ISR
|
||||
* xTaskCreate(uart_task, "uTask", 1024, (void*)uart_num, 10, NULL);
|
||||
* }
|
||||
|
@ -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, ledc_isr_handle_t *handle)
|
||||
{
|
||||
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, handle);
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
return ESP_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
|
||||
|
@ -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_isr_handle_t *handle)
|
||||
{
|
||||
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, handle);
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
@ -45,6 +46,7 @@
|
||||
|
||||
static const char* RMT_TAG = "RMT";
|
||||
static bool s_rmt_driver_installed = false;
|
||||
static rmt_isr_handle_t s_rmt_driver_intr_handle;
|
||||
|
||||
#define RMT_CHECK(a, str, ret) if (!(a)) { \
|
||||
ESP_LOGE(RMT_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
@ -472,17 +474,21 @@ 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, rmt_isr_handle_t *handle)
|
||||
{
|
||||
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, handle);
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t rmt_isr_deregister(rmt_isr_handle_t handle)
|
||||
{
|
||||
return esp_intr_free(handle);
|
||||
}
|
||||
|
||||
static int IRAM_ATTR rmt_get_mem_len(rmt_channel_t channel)
|
||||
@ -616,10 +622,10 @@ esp_err_t rmt_driver_uninstall(rmt_channel_t channel)
|
||||
free(p_rmt_obj[channel]);
|
||||
p_rmt_obj[channel] = NULL;
|
||||
s_rmt_driver_installed = false;
|
||||
return ESP_OK;
|
||||
return rmt_isr_deregister(s_rmt_driver_intr_handle);
|
||||
}
|
||||
|
||||
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 +633,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 +657,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_intr_handle);
|
||||
s_rmt_driver_installed = true;
|
||||
}
|
||||
rmt_set_tx_intr_en(channel, 1);
|
||||
ESP_INTR_ENABLE(rmt_intr_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -264,15 +264,10 @@ esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num)
|
||||
/*---------------------------------------------------------------
|
||||
Touch Pad
|
||||
---------------------------------------------------------------*/
|
||||
esp_err_t touch_pad_isr_handler_register(uint32_t touch_intr_num, void(*fn)(void *), void *arg)
|
||||
esp_err_t touch_pad_isr_handler_register(void(*fn)(void *), void *arg, int intr_alloc_flags, touch_isr_handle_t *handle)
|
||||
{
|
||||
RTC_MODULE_CHECK(fn, "Touch_Pad ISR null", ESP_ERR_INVALID_ARG);
|
||||
ESP_INTR_DISABLE(touch_intr_num);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_RTC_CORE_INTR_SOURCE, touch_intr_num);
|
||||
xt_set_interrupt_handler(touch_intr_num, fn, arg);
|
||||
ESP_INTR_ENABLE(touch_intr_num);
|
||||
|
||||
return ESP_OK;
|
||||
return esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
|
||||
}
|
||||
|
||||
static esp_err_t touch_pad_get_io_num(touch_pad_t touch_num, gpio_num_t *gpio_num)
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "esp_log.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/timer.h"
|
||||
@ -167,36 +168,38 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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, timer_isr_handle_t *handle)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
ESP_INTR_DISABLE(timer_intr_num);
|
||||
int intr_source = 0;
|
||||
uint32_t status_reg = 0;
|
||||
int mask = 0;
|
||||
switch(group_num) {
|
||||
case TIMER_GROUP_0:
|
||||
default:
|
||||
if(intr_type == TIMER_INTR_LEVEL) {
|
||||
if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
|
||||
intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;
|
||||
} else {
|
||||
intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;
|
||||
}
|
||||
status_reg = TIMG_INT_ST_TIMERS_REG(0);
|
||||
mask = 1<<timer_num;
|
||||
break;
|
||||
case TIMER_GROUP_1:
|
||||
if(intr_type == TIMER_INTR_LEVEL) {
|
||||
if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
|
||||
intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;
|
||||
} else {
|
||||
intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;
|
||||
}
|
||||
status_reg = TIMG_INT_ST_TIMERS_REG(1);
|
||||
mask = 1<<timer_num;
|
||||
break;
|
||||
}
|
||||
intr_matrix_set(xPortGetCoreID(), intr_source, timer_intr_num);
|
||||
xt_set_interrupt_handler(timer_intr_num, fn, arg);
|
||||
ESP_INTR_ENABLE(timer_intr_num);
|
||||
return ESP_OK;
|
||||
return esp_intr_alloc_intrstatus(intr_source, intr_alloc_flags, status_reg, mask, fn, arg, handle);
|
||||
}
|
||||
|
||||
esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)
|
||||
|
@ -15,7 +15,9 @@
|
||||
#include "esp_types.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "malloc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
@ -53,7 +55,7 @@ typedef struct {
|
||||
uart_port_t uart_num; /*!< UART port number*/
|
||||
int queue_size; /*!< UART event queue size*/
|
||||
QueueHandle_t xQueueUart; /*!< UART queue handler*/
|
||||
int intr_num; /*!< UART interrupt number*/
|
||||
intr_handle_t intr_handle; /*!< UART interrupt handle*/
|
||||
//rx parameters
|
||||
SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/
|
||||
int rx_buf_size; /*!< RX ring buffer size */
|
||||
@ -283,31 +285,41 @@ 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;
|
||||
UART[uart_num]->int_ena.txfifo_empty = enable & 0x1;
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
ESP_INTR_ENABLE(p_uart_obj[uart_num]->intr_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg)
|
||||
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags)
|
||||
{
|
||||
int ret;
|
||||
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
ESP_INTR_DISABLE(uart_intr_num);
|
||||
switch(uart_num) {
|
||||
case UART_NUM_1:
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_UART1_INTR_SOURCE, uart_intr_num);
|
||||
ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
|
||||
break;
|
||||
case UART_NUM_2:
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_UART2_INTR_SOURCE, uart_intr_num);
|
||||
ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
|
||||
break;
|
||||
case UART_NUM_0:
|
||||
default:
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_UART0_INTR_SOURCE, uart_intr_num);
|
||||
ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
|
||||
break;
|
||||
}
|
||||
xt_set_interrupt_handler(uart_intr_num, fn, arg);
|
||||
ESP_INTR_ENABLE(uart_intr_num);
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
return ESP_OK;
|
||||
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
|
||||
@ -859,7 +871,7 @@ esp_err_t uart_flush(uart_port_t uart_num)
|
||||
|
||||
//rx sem protect the ring buffer read related functions
|
||||
xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY);
|
||||
ESP_INTR_DISABLE(p_uart->intr_num);
|
||||
esp_intr_disable(p_uart->intr_handle);
|
||||
while(true) {
|
||||
if(p_uart->rx_head_ptr) {
|
||||
vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr);
|
||||
@ -876,12 +888,12 @@ esp_err_t uart_flush(uart_port_t uart_num)
|
||||
p_uart->rx_ptr = NULL;
|
||||
p_uart->rx_cur_remain = 0;
|
||||
p_uart->rx_head_ptr = NULL;
|
||||
ESP_INTR_ENABLE(p_uart->intr_num);
|
||||
esp_intr_enable(p_uart->intr_handle);
|
||||
xSemaphoreGive(p_uart->rx_mux);
|
||||
|
||||
if(p_uart->tx_buf_size > 0) {
|
||||
xSemaphoreTake(p_uart->tx_mux, (portTickType)portMAX_DELAY);
|
||||
ESP_INTR_DISABLE(p_uart->intr_num);
|
||||
esp_intr_disable(p_uart->intr_handle);
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
UART[uart_num]->int_ena.txfifo_empty = 0;
|
||||
UART[uart_num]->int_clr.txfifo_empty = 1;
|
||||
@ -901,19 +913,18 @@ esp_err_t uart_flush(uart_port_t uart_num)
|
||||
p_uart->tx_ptr = NULL;
|
||||
p_uart->tx_waiting_brk = 0;
|
||||
p_uart->tx_waiting_fifo = false;
|
||||
ESP_INTR_ENABLE(p_uart->intr_num);
|
||||
esp_intr_enable(p_uart->intr_handle);
|
||||
xSemaphoreGive(p_uart->tx_mux);
|
||||
}
|
||||
uart_reset_fifo(uart_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
|
||||
UART_CHECK((rx_buffer_size > 0), "uart rx buffer length error", ESP_FAIL);
|
||||
if(p_uart_obj[uart_num] == NULL) {
|
||||
ESP_INTR_DISABLE(uart_intr_num);
|
||||
p_uart_obj[uart_num] = (uart_obj_t*) malloc(sizeof(uart_obj_t));
|
||||
if(p_uart_obj[uart_num] == NULL) {
|
||||
ESP_LOGE(UART_TAG, "UART driver malloc error");
|
||||
@ -926,7 +937,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();
|
||||
p_uart_obj[uart_num]->tx_mux = xSemaphoreCreateMutex();
|
||||
p_uart_obj[uart_num]->rx_mux = xSemaphoreCreateMutex();
|
||||
p_uart_obj[uart_num]->intr_num = uart_intr_num;
|
||||
p_uart_obj[uart_num]->queue_size = queue_size;
|
||||
p_uart_obj[uart_num]->tx_ptr = NULL;
|
||||
p_uart_obj[uart_num]->tx_head = NULL;
|
||||
@ -959,7 +969,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");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uart_isr_register(uart_num, uart_intr_num, uart_rx_intr_handler_default, p_uart_obj[uart_num]);
|
||||
uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags);
|
||||
uart_intr_config_t uart_intr = {
|
||||
.intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M
|
||||
| UART_RXFIFO_TOUT_INT_ENA_M
|
||||
@ -972,7 +982,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
|
||||
};
|
||||
uart_intr_config(uart_num, &uart_intr);
|
||||
ESP_INTR_ENABLE(uart_intr_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -984,10 +993,9 @@ esp_err_t uart_driver_delete(uart_port_t uart_num)
|
||||
ESP_LOGI(UART_TAG, "ALREADY NULL");
|
||||
return ESP_OK;
|
||||
}
|
||||
ESP_INTR_DISABLE(p_uart_obj[uart_num]->intr_num);
|
||||
esp_intr_free(p_uart_obj[uart_num]->intr_handle);
|
||||
uart_disable_rx_intr(uart_num);
|
||||
uart_disable_tx_intr(uart_num);
|
||||
uart_isr_register(uart_num, p_uart_obj[uart_num]->intr_num, NULL, NULL);
|
||||
|
||||
if(p_uart_obj[uart_num]->tx_fifo_sem) {
|
||||
vSemaphoreDelete(p_uart_obj[uart_num]->tx_fifo_sem);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
267
components/esp32/include/esp_intr_alloc.h
Normal file
267
components/esp32/include/esp_intr_alloc.h
Normal file
@ -0,0 +1,267 @@
|
||||
// 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_INTRDISABLED (1<<11) ///< Return with this interrupt 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 intr_handle_data_t intr_handle_data_t;
|
||||
typedef intr_handle_data_t* intr_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 disabled.
|
||||
*
|
||||
* @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. Setting ESP_INTR_FLAG_INTRDISABLED will return
|
||||
* from this function with the interrupt disabled.
|
||||
* @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 intr_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, intr_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. Setting ESP_INTR_FLAG_INTRDISABLED will return
|
||||
* from this function with the interrupt disabled.
|
||||
* @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 intr_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, intr_handle_t *ret_handle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Disable and free an interrupt.
|
||||
*
|
||||
* Use an interrupt handle to disable the interrupt 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(intr_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(intr_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(intr_handle_t handle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Disable the interrupt associated with the handle
|
||||
*
|
||||
* @note For local interrupts (ESP_INTERNAL_* sources), this function has to be called on the
|
||||
* CPU the interrupt is allocated on. Other interrupts have no such restriction.
|
||||
*
|
||||
* @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(intr_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Ensable the interrupt associated with the handle
|
||||
*
|
||||
* @note For local interrupts (ESP_INTERNAL_* sources), this function has to be called on the
|
||||
* CPU the interrupt is allocated on. Other interrupts have no such restriction.
|
||||
*
|
||||
* @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(intr_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
|
@ -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
|
||||
|
728
components/esp32/intr_alloc.c
Normal file
728
components/esp32/intr_alloc.c
Normal file
@ -0,0 +1,728 @@
|
||||
// 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_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
|
||||
{ 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
|
||||
};
|
||||
|
||||
typedef struct shared_vector_desc_t shared_vector_desc_t;
|
||||
typedef struct vector_desc_t vector_desc_t;
|
||||
|
||||
struct shared_vector_desc_t {
|
||||
int disabled: 1;
|
||||
int source: 8;
|
||||
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)
|
||||
|
||||
//Pack using bitfields for better memory use
|
||||
struct vector_desc_t {
|
||||
int flags: 16; //OR of VECDESC_FLAG_* defines
|
||||
unsigned int cpu: 1;
|
||||
unsigned int intno: 5;
|
||||
int source: 8; //Interrupt mux flags, used when not shared
|
||||
shared_vector_desc_t *shared_vec_info; //used when VECDESC_FL_SHARED
|
||||
vector_desc_t *next;
|
||||
};
|
||||
|
||||
struct intr_handle_data_t {
|
||||
vector_desc_t *vector_desc;
|
||||
shared_vector_desc_t *shared_vector_desc;
|
||||
};
|
||||
|
||||
|
||||
//Linked list of vector descriptions, sorted by cpu.intno 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 cpu.intno 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->cpu > to_insert->cpu) break;
|
||||
if (vd->cpu == to_insert->cpu && vd->intno >= to_insert->intno) 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->cpu==cpu && vd->intno==intno) 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. Returns NULL on malloc fail.
|
||||
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));
|
||||
if (newvd==NULL) return NULL;
|
||||
memset(newvd, 0, sizeof(vector_desc_t));
|
||||
newvd->intno=intno;
|
||||
newvd->cpu=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);
|
||||
if (vd==NULL) {
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
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);
|
||||
if (vd==NULL) {
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
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.
|
||||
//When a CPU is forced, the INTDESC_SPECIAL marked interrupts are also accepted.
|
||||
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<32; 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) {
|
||||
ALCHLOG(TAG, "....Unusable: reserved");
|
||||
continue;
|
||||
}
|
||||
if (int_desc[x].cpuflags[cpu]==INTDESC_SPECIAL && force==-1) {
|
||||
ALCHLOG(TAG, "....Unusable: special-purpose int");
|
||||
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->disabled) {
|
||||
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, intr_handle_t *ret_handle)
|
||||
{
|
||||
intr_handle_data_t *ret=NULL;
|
||||
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 and non-processor-local source
|
||||
if ((flags&ESP_INTR_FLAG_SHARED) && (!handler || source<0)) 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;
|
||||
|
||||
//Allocate a return handle. If we end up not needing it, we'll free it later on.
|
||||
ret=malloc(sizeof(intr_handle_data_t));
|
||||
if (ret==NULL) return ESP_ERR_NO_MEM;
|
||||
|
||||
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);
|
||||
free(ret);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
//Get an int vector desc for int.
|
||||
vector_desc_t *vd=get_desc_for_int(intr, cpu);
|
||||
if (vd==NULL) {
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
free(ret);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
//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));
|
||||
if (sh_vec==NULL) {
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
free(ret);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
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;
|
||||
sh_vec->source=source;
|
||||
sh_vec->disabled=0;
|
||||
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);
|
||||
vd->source=source;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
//Fill return handle data.
|
||||
ret->vector_desc=vd;
|
||||
ret->shared_vector_desc=vd->shared_vec_info;
|
||||
|
||||
//Enable int at CPU-level;
|
||||
ESP_INTR_ENABLE(intr);
|
||||
|
||||
//If interrupt has to be started disabled, do that now; ints won't be enabled for real until the end
|
||||
//of the critical section.
|
||||
if (flags&ESP_INTR_FLAG_INTRDISABLED) {
|
||||
esp_intr_disable(ret);
|
||||
}
|
||||
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
|
||||
//Fill return handle if needed, otherwise free handle.
|
||||
if (ret_handle!=NULL) {
|
||||
*ret_handle=ret;
|
||||
} else {
|
||||
free(ret);
|
||||
}
|
||||
|
||||
ESP_EARLY_LOGD(TAG, "Connected src %d to int %d (cpu %d)", source, intr, cpu);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, intr_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(intr_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 (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
portENTER_CRITICAL(&spinlock);
|
||||
esp_intr_disable(handle);
|
||||
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");
|
||||
//Reset to normal handler
|
||||
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.
|
||||
handle->vector_desc->flags&=!(VECDESC_FL_NONSHARED|VECDESC_FL_RESERVED);
|
||||
//Also kill non_iram mask bit.
|
||||
non_iram_int_mask[handle->vector_desc->cpu]&=~(1<<(handle->vector_desc->intno));
|
||||
}
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
free(handle);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int esp_intr_get_intno(intr_handle_t handle)
|
||||
{
|
||||
return handle->vector_desc->intno;
|
||||
}
|
||||
|
||||
int esp_intr_get_cpu(intr_handle_t handle)
|
||||
{
|
||||
return handle->vector_desc->cpu;
|
||||
}
|
||||
|
||||
/*
|
||||
Interrupt disabling strategy:
|
||||
If the source is >=0 (meaning a muxed interrupt), we disable it by muxing the interrupt to a non-connected
|
||||
interrupt. If the source is <0 (meaning an internal, per-cpu interrupt), we disable it using ESP_INTR_DISABLE.
|
||||
This allows us to, for the muxed CPUs, disable an int from the other core. It also allows disabling shared
|
||||
interrupts.
|
||||
*/
|
||||
|
||||
//Muxing an interrupt source to interrupt 6, 7, 11, 15, 16 or 29 cause the interrupt to effectively be disabled.
|
||||
#define INT_MUX_DISABLED_INTNO 6
|
||||
|
||||
esp_err_t esp_intr_enable(intr_handle_t handle)
|
||||
{
|
||||
if (!handle) return ESP_ERR_INVALID_ARG;
|
||||
portENTER_CRITICAL(&spinlock);
|
||||
int source;
|
||||
if (handle->shared_vector_desc) {
|
||||
handle->shared_vector_desc->disabled=0;
|
||||
source=handle->shared_vector_desc->source;
|
||||
} else {
|
||||
source=handle->vector_desc->source;
|
||||
}
|
||||
if (source >= 0) {
|
||||
//Disabled using int matrix; re-connect to enable
|
||||
intr_matrix_set(handle->vector_desc->cpu, source, handle->vector_desc->intno);
|
||||
} else {
|
||||
//Re-enable using cpu int ena reg
|
||||
if (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; //Can only enable these ints on this cpu
|
||||
ESP_INTR_ENABLE(handle->vector_desc->intno);
|
||||
}
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_intr_disable(intr_handle_t handle)
|
||||
{
|
||||
if (!handle) return ESP_ERR_INVALID_ARG;
|
||||
portENTER_CRITICAL(&spinlock);
|
||||
int source;
|
||||
if (handle->shared_vector_desc) {
|
||||
handle->shared_vector_desc->disabled=1;
|
||||
source=handle->shared_vector_desc->source;
|
||||
} else {
|
||||
source=handle->vector_desc->source;
|
||||
}
|
||||
if (source >= 0) {
|
||||
//Disable using int matrix
|
||||
intr_matrix_set(handle->vector_desc->cpu, source, INT_MUX_DISABLED_INTNO);
|
||||
} else {
|
||||
//Disable using per-cpu regs
|
||||
if (handle->vector_desc->cpu!=xPortGetCoreID()) {
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
return ESP_ERR_INVALID_ARG; //Can only enable these ints on this cpu
|
||||
}
|
||||
ESP_INTR_DISABLE(handle->vector_desc->intno);
|
||||
}
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 5902a2229e5371aeea45c09e63ea5e233b58750f
|
||||
Subproject commit 3a412c08af1ace47a58d1f8722a8fed5b8d3b944
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
203
components/esp32/test/test_intr_alloc.c
Normal file
203
components/esp32/test/test_intr_alloc.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
Tests for the interrupt allocator.
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/timer.h"
|
||||
|
||||
|
||||
#define TIMER_DIVIDER 16 /*!< Hardware timer clock divider */
|
||||
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) /*!< used to calculate counter value */
|
||||
#define TIMER_INTERVAL0_SEC (3.4179) /*!< test interval for timer 0 */
|
||||
#define TIMER_INTERVAL1_SEC (5.78) /*!< test interval for timer 1 */
|
||||
|
||||
|
||||
static void my_timer_init(int timer_group, int timer_idx, int ival)
|
||||
{
|
||||
timer_config_t config;
|
||||
config.alarm_en = 1;
|
||||
config.auto_reload = 1;
|
||||
config.counter_dir = TIMER_COUNT_UP;
|
||||
config.divider = TIMER_DIVIDER;
|
||||
config.intr_type = TIMER_INTR_LEVEL;
|
||||
config.counter_en = TIMER_PAUSE;
|
||||
/*Configure timer*/
|
||||
timer_init(timer_group, timer_idx, &config);
|
||||
/*Stop timer counter*/
|
||||
timer_pause(timer_group, timer_idx);
|
||||
/*Load counter value */
|
||||
timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
|
||||
/*Set alarm value*/
|
||||
timer_set_alarm_value(timer_group, timer_idx, ival);
|
||||
/*Enable timer interrupt*/
|
||||
timer_enable_intr(timer_group, timer_idx);
|
||||
}
|
||||
|
||||
static volatile int count[4]={0,0,0,0};
|
||||
|
||||
|
||||
static void timer_isr(void *arg)
|
||||
{
|
||||
int timer_idx = (int)arg;
|
||||
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;
|
||||
}
|
||||
if (timer_idx==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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
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]);
|
||||
timer_isr_register(TIMER_GROUP_1, TIMER_1, timer_isr, (void*)3, flags, &inth[3]);
|
||||
timer_start(TIMER_GROUP_0, TIMER_0);
|
||||
timer_start(TIMER_GROUP_0, TIMER_1);
|
||||
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);
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
TEST_CASE("Intr_alloc test, private ints", "[esp32]")
|
||||
{
|
||||
timer_test(0);
|
||||
}
|
||||
|
||||
TEST_CASE("Intr_alloc test, shared ints", "[esp32]")
|
||||
{
|
||||
timer_test(ESP_INTR_FLAG_SHARED);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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 a4, 0
|
||||
xsr a4, INTENABLE /* Disables all interrupts */
|
||||
or a3, a4, a2 /* set bits in mask */
|
||||
xor a3, a3, a2 /* invert bits in mask set in mask, essentially clearing them */
|
||||
wsr a3, INTENABLE /* Re-enable ints */
|
||||
mov a2, a4 /* return prev mask */
|
||||
#endif
|
||||
#else
|
||||
movi a2, 0 /* return zero */
|
||||
#endif
|
||||
|
@ -61,14 +61,6 @@ config MBEDTLS_MPI_USE_INTERRUPT
|
||||
This allows other code to run on the CPU while an MPI operation is pending.
|
||||
Otherwise the CPU busy-waits.
|
||||
|
||||
config MBEDTLS_MPI_INTERRUPT_NUM
|
||||
int "MPI Interrupt number"
|
||||
depends on MBEDTLS_MPI_USE_INTERRUPT
|
||||
default 18
|
||||
help
|
||||
CPU interrupt number for MPI interrupt to connect to. Must be otherwise unused.
|
||||
Eventually this assignment will be handled automatically at runtime.
|
||||
|
||||
config MBEDTLS_HARDWARE_SHA
|
||||
bool "Enable hardware SHA acceleration"
|
||||
default y
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
##
|
||||
|
111
docs/api/intr_alloc.rst
Normal file
111
docs/api/intr_alloc.rst
Normal file
@ -0,0 +1,111 @@
|
||||
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.)
|
||||
|
||||
|
||||
Multicore issues
|
||||
----------------
|
||||
|
||||
Peripherals that can generate interrupts can be divided in two types: external peripherals, outside the Xtensa
|
||||
cores in the ESP32, and internal peripherals, inside the ESP32. Interrupt handling differs slightly between
|
||||
these two types of peripherals.
|
||||
|
||||
Each Xtensa core has its own set of internal peripherals: three timer comparators, a performance monitor and two
|
||||
software interrupts. These peripherals can only be configured from the core they are associated with. When
|
||||
generating an interrupt, the interrupt they generate is hard-wired to their associated core; it's not possible
|
||||
to have e.g. an internal timer comparator of one core generate an interrupt on another core. That is why these
|
||||
sources can only be managed using a task running on that specific core. Internal interrupt sources are still
|
||||
allocatable using esp_intr_alloc as normal, but they cannot be shared and will always have a fixed interrupt
|
||||
level (namely, the one associated in hardware with the peripheral). Internal interrupt sources are defined
|
||||
in esp_intr_alloc.h as ETS_INTERNAL_*_INTR_SOURCE.
|
||||
|
||||
The remaining interrupt slots in both cores are wired to an interrupt multiplexer, which can be used to
|
||||
route any external interrupt source to any of these interrupt slots. Allocating an external interrupt will always
|
||||
allocate it on the core that does the allocation, and freeing the interrupt should always happen on the same
|
||||
core. Disabling and enabling the interrupt from another core is allowed, however. External interrupts can
|
||||
share an interrupt slot bu passing ESP_INTR_FLAG_SHARED as a flag to esp_intr_alloc. External interrupt sources
|
||||
are defined in soc/soc.h as ETS_*_INTR_SOURCE.
|
||||
|
||||
Care should be taken when allocating an interrupt using a task not pinned to a certain core; while running
|
||||
code not in a critical secion, these tasks can migrate between cores at any moment, possibly making an
|
||||
interrupt operation fail because of the reasons mentioned above. It is advised to always use
|
||||
xTaskCreatePinnedToCore with a specific CoreID argument to create tasks that will handle interrupts.
|
||||
|
||||
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
|
||||
.. doxygendefine:: ESP_INTR_FLAG_INTRDISABLED
|
||||
|
||||
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
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 */
|
||||
@ -88,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;
|
||||
@ -157,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_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, ESP_INTR_FLAG_IRAM, NULL);
|
||||
/*Start timer counter*/
|
||||
timer_start(timer_group, timer_idx);
|
||||
}
|
||||
@ -187,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_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, ESP_INTR_FLAG_IRAM, NULL);
|
||||
/*Start timer counter*/
|
||||
timer_start(timer_group, timer_idx);
|
||||
}
|
||||
|
@ -41,7 +41,6 @@
|
||||
#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)
|
||||
@ -176,7 +175,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, NULL);
|
||||
/*Enable interrupt for PCNT unit*/
|
||||
pcnt_intr_enable(PCNT_TEST_UNIT);
|
||||
/*Resume counting*/
|
||||
|
@ -74,6 +74,7 @@ CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
|
||||
#
|
||||
# Component config
|
||||
#
|
||||
CONFIG_BTC_TASK_STACK_SIZE=2048
|
||||
CONFIG_BT_RESERVE_DRAM=0
|
||||
|
||||
#
|
||||
@ -85,7 +86,6 @@ CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
|
||||
# CONFIG_ESP32_ENABLE_STACK_WIFI is not set
|
||||
# CONFIG_ESP32_ENABLE_STACK_BT is not set
|
||||
CONFIG_ESP32_ENABLE_STACK_NONE=y
|
||||
CONFIG_MEMMAP_SMP=y
|
||||
# CONFIG_MEMMAP_TRACEMEM is not set
|
||||
CONFIG_TRACEMEM_RESERVE_DRAM=0x0
|
||||
@ -93,6 +93,11 @@ CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
|
||||
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048
|
||||
CONFIG_MAIN_TASK_STACK_SIZE=4096
|
||||
CONFIG_NEWLIB_STDOUT_ADDCR=y
|
||||
CONFIG_CONSOLE_UART_DEFAULT=y
|
||||
# CONFIG_CONSOLE_UART_CUSTOM is not set
|
||||
# CONFIG_CONSOLE_UART_NONE is not set
|
||||
CONFIG_CONSOLE_UART_NUM=0
|
||||
CONFIG_CONSOLE_UART_BAUDRATE=115200
|
||||
CONFIG_ULP_COPROC_ENABLED=y
|
||||
CONFIG_ULP_COPROC_RESERVE_MEM=512
|
||||
# CONFIG_ESP32_PANIC_PRINT_HALT is not set
|
||||
@ -165,7 +170,6 @@ CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384
|
||||
CONFIG_MBEDTLS_HARDWARE_AES=y
|
||||
CONFIG_MBEDTLS_HARDWARE_MPI=y
|
||||
CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y
|
||||
CONFIG_MBEDTLS_MPI_INTERRUPT_NUM=18
|
||||
CONFIG_MBEDTLS_HARDWARE_SHA=y
|
||||
|
||||
#
|
||||
|
Loading…
x
Reference in New Issue
Block a user