Add disabling/enabling of shared interrupt, add testcase for interrupts

This commit is contained in:
Jeroen Domburg 2016-12-07 21:30:21 +08:00
parent 32fa94935d
commit ae8c37e0b6
16 changed files with 348 additions and 102 deletions

View file

@ -321,10 +321,10 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
return ESP_OK; return ESP_OK;
} }
esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags) 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); GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG);
return esp_intr_alloc(ETS_GPIO_INTR_SOURCE, intr_alloc_flags, fn, arg, NULL); return esp_intr_alloc(ETS_GPIO_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
} }
/*only level interrupt can be used for wake-up function*/ /*only level interrupt can be used for wake-up function*/

View file

@ -23,6 +23,7 @@
#include "soc/gpio_sig_map.h" #include "soc/gpio_sig_map.h"
#include "rom/gpio.h" #include "rom/gpio.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_intr_alloc.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -203,6 +204,9 @@ typedef enum {
GPIO_FLOATING, /*!< Pad floating */ GPIO_FLOATING, /*!< Pad floating */
} gpio_pull_mode_t; } gpio_pull_mode_t;
typedef intr_handle_t gpio_isr_handle_t;
typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num); typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num);
/** /**
@ -352,7 +356,7 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
* - ESP_OK Success ; * - ESP_OK Success ;
* - ESP_ERR_INVALID_ARG GPIO error * - ESP_ERR_INVALID_ARG GPIO error
*/ */
esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags); esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, gpio_isr_handle_t *handle);

View file

@ -21,6 +21,7 @@
#include "soc/ledc_struct.h" #include "soc/ledc_struct.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/periph_ctrl.h" #include "driver/periph_ctrl.h"
#include "esp_intr_alloc.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -100,6 +101,7 @@ typedef struct {
uint32_t freq_hz; /*!< LEDC timer frequency(Hz)*/ uint32_t freq_hz; /*!< LEDC timer frequency(Hz)*/
} ledc_timer_config_t; } ledc_timer_config_t;
typedef intr_handle_t ledc_isr_handle_t;
/** /**
* @brief LEDC channel configuration * @brief LEDC channel configuration
@ -268,7 +270,7 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty,
* - ESP_OK Success * - ESP_OK Success
* - ESP_ERR_INVALID_ARG Function pointer error. * - ESP_ERR_INVALID_ARG Function pointer error.
*/ */
esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags); esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, ledc_isr_handle_t *handle);
/** /**
* @brief configure LEDC settings * @brief configure LEDC settings

View file

@ -12,6 +12,7 @@
#include "soc/pcnt_struct.h" #include "soc/pcnt_struct.h"
#include "soc/gpio_sig_map.h" #include "soc/gpio_sig_map.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esp_intr_alloc.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -76,6 +77,8 @@ typedef struct {
pcnt_channel_t channel; /*!< the PCNT channel */ pcnt_channel_t channel; /*!< the PCNT channel */
} pcnt_config_t; } pcnt_config_t;
typedef intr_handle_t pcnt_isr_handle_t;
/** /**
* @brief Configure Pulse Counter unit * @brief Configure Pulse Counter unit
* *
@ -223,7 +226,7 @@ esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16
* - ESP_OK Success * - ESP_OK Success
* - ESP_ERR_INVALID_ARG Function pointer error. * - ESP_ERR_INVALID_ARG Function pointer error.
*/ */
esp_err_t pcnt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags); 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 * @brief Configure PCNT pulse signal input pin and control input pin

View file

@ -117,6 +117,8 @@ typedef struct {
}; };
} rmt_config_t; } rmt_config_t;
typedef intr_handle_t rmt_isr_handle_t;
/** /**
* @brief Set RMT clock divider, channel clock is divided from source clock. * @brief Set RMT clock divider, channel clock is divided from source clock.
* *
@ -574,13 +576,25 @@ esp_err_t rmt_config(rmt_config_t* rmt_param);
* @param arg Parameter for handler function * @param arg Parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * @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. * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param If non-zero, a handle to later clean up the ISR gets stored here.
* *
* @return * @return
* - ESP_OK Success * - ESP_OK Success
* - ESP_ERR_INVALID_ARG Function pointer error. * - ESP_ERR_INVALID_ARG Function pointer error.
* - ESP_FAIL System driver installed, can not register ISR handler for RMT * - ESP_FAIL System driver installed, can not register ISR handler for RMT
*/ */
esp_err_t rmt_isr_register(void (* fn)(void* ), void * arg, int intr_alloc_flags); 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. * @brief Fill memory data of channel with given RMT items.

View file

@ -19,6 +19,7 @@
#include "soc/soc.h" #include "soc/soc.h"
#include "soc/timer_group_reg.h" #include "soc/timer_group_reg.h"
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "esp_intr_alloc.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -100,6 +101,13 @@ typedef struct {
uint16_t divider; /*!< Counter clock divider*/ uint16_t divider; /*!< Counter clock divider*/
} timer_config_t; } 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. * @brief Read the counter value of hardware timer.
* *
@ -264,7 +272,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
* - ESP_OK Success * - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_ARG Parameter error
*/ */
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); 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. /** @brief Initializes and configure the timer.
* *

View file

@ -371,8 +371,7 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
* @param fn Interrupt handler function. * @param fn Interrupt handler function.
* @param arg parameter for handler function * @param arg parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. Note that the UART * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* driver at the moment does not work with a shared interrupt.
* *
* @return * @return
* - ESP_OK Success * - ESP_OK Success

View file

@ -114,12 +114,12 @@ static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel,
return ESP_OK; return ESP_OK;
} }
esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags) esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, ledc_isr_handle_t *handle)
{ {
esp_err_t ret; esp_err_t ret;
LEDC_CHECK(fn, "ledc isr null", ESP_ERR_INVALID_ARG); LEDC_CHECK(fn, "ledc isr null", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&ledc_spinlock); portENTER_CRITICAL(&ledc_spinlock);
ret=esp_intr_alloc(ETS_LEDC_INTR_SOURCE, intr_alloc_flags, fn, arg, NULL); ret=esp_intr_alloc(ETS_LEDC_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
portEXIT_CRITICAL(&ledc_spinlock); portEXIT_CRITICAL(&ledc_spinlock);
return ret; return ret;
} }

View file

@ -267,9 +267,9 @@ esp_err_t pcnt_filter_disable(pcnt_unit_t unit)
return ESP_OK; return ESP_OK;
} }
esp_err_t pcnt_isr_register(void (*fun)(void*), void * arg, int intr_alloc_flags) 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); PCNT_CHECK(fun != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
return esp_intr_alloc(ETS_PCNT_INTR_SOURCE, intr_alloc_flags, fun, arg, NULL); return esp_intr_alloc(ETS_PCNT_INTR_SOURCE, intr_alloc_flags, fun, arg, handle);
} }

View file

@ -46,6 +46,7 @@
static const char* RMT_TAG = "RMT"; static const char* RMT_TAG = "RMT";
static bool s_rmt_driver_installed = false; 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)) { \ #define RMT_CHECK(a, str, ret) if (!(a)) { \
ESP_LOGE(RMT_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ ESP_LOGE(RMT_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
@ -473,17 +474,23 @@ esp_err_t rmt_fill_tx_items(rmt_channel_t channel, rmt_item32_t* item, uint16_t
return ESP_OK; return ESP_OK;
} }
esp_err_t rmt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags) esp_err_t rmt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, rmt_isr_handle_t *handle)
{ {
esp_err_t ret; esp_err_t ret;
RMT_CHECK((fn != NULL), RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); 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); RMT_CHECK(s_rmt_driver_installed == false, "RMT DRIVER INSTALLED, CAN NOT REG ISR HANDLER", ESP_FAIL);
portENTER_CRITICAL(&rmt_spinlock); portENTER_CRITICAL(&rmt_spinlock);
ret=esp_intr_alloc(ETS_RMT_INTR_SOURCE, intr_alloc_flags, fn, arg, NULL); ret=esp_intr_alloc(ETS_RMT_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
portEXIT_CRITICAL(&rmt_spinlock); portEXIT_CRITICAL(&rmt_spinlock);
return ret; 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) static int IRAM_ATTR rmt_get_mem_len(rmt_channel_t channel)
{ {
int block_num = RMT.conf_ch[channel].conf0.mem_size; int block_num = RMT.conf_ch[channel].conf0.mem_size;
@ -615,7 +622,7 @@ esp_err_t rmt_driver_uninstall(rmt_channel_t channel)
free(p_rmt_obj[channel]); free(p_rmt_obj[channel]);
p_rmt_obj[channel] = NULL; p_rmt_obj[channel] = NULL;
s_rmt_driver_installed = false; 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 intr_alloc_flags) esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr_alloc_flags)
@ -650,7 +657,7 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr
rmt_set_err_intr_en(channel, 1); rmt_set_err_intr_en(channel, 1);
} }
if(s_rmt_driver_installed == false) { if(s_rmt_driver_installed == false) {
rmt_isr_register(rmt_driver_isr_default, NULL, intr_alloc_flags); rmt_isr_register(rmt_driver_isr_default, NULL, intr_alloc_flags, &s_rmt_driver_intr_handle);
s_rmt_driver_installed = true; s_rmt_driver_installed = true;
} }
rmt_set_tx_intr_en(channel, 1); rmt_set_tx_intr_en(channel, 1);

View file

@ -169,13 +169,15 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
} }
esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, 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) 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(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(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
int intr_source = 0; int intr_source = 0;
uint32_t status_reg = 0;
int mask = 0;
switch(group_num) { switch(group_num) {
case TIMER_GROUP_0: case TIMER_GROUP_0:
default: default:
@ -184,6 +186,8 @@ esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num,
} else { } else {
intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num; intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;
} }
status_reg = TIMG_INT_ST_TIMERS_REG(0);
mask = 1<<timer_num;
break; break;
case TIMER_GROUP_1: case TIMER_GROUP_1:
if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) { if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
@ -191,9 +195,11 @@ esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num,
} else { } else {
intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num; intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;
} }
status_reg = TIMG_INT_ST_TIMERS_REG(1);
mask = 1<<timer_num;
break; break;
} }
return esp_intr_alloc(intr_source, intr_alloc_flags, fn, arg, NULL); 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) esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)

View file

@ -55,7 +55,7 @@ typedef struct {
uart_port_t uart_num; /*!< UART port number*/ uart_port_t uart_num; /*!< UART port number*/
int queue_size; /*!< UART event queue size*/ int queue_size; /*!< UART event queue size*/
QueueHandle_t xQueueUart; /*!< UART queue handler*/ QueueHandle_t xQueueUart; /*!< UART queue handler*/
int_handle_t intr_handle; /*!< UART interrupt handle*/ intr_handle_t intr_handle; /*!< UART interrupt handle*/
//rx parameters //rx parameters
SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/ SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/
int rx_buf_size; /*!< RX ring buffer size */ int rx_buf_size; /*!< RX ring buffer size */
@ -292,7 +292,6 @@ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg,
{ {
int ret; int ret;
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK(((intr_alloc_flags & ESP_INTR_FLAG_SHARED)==0), "UART doesn't support shared interrupts", ESP_FAIL);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
switch(uart_num) { switch(uart_num) {
case UART_NUM_1: case UART_NUM_1:

View file

@ -47,6 +47,7 @@ extern "C" {
#define ESP_INTR_FLAG_SHARED (1<<8) ///< Interrupt can be shared between ISRs #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_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_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_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_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.
@ -79,8 +80,8 @@ extern "C" {
typedef void (*intr_handler_t)(void *arg); typedef void (*intr_handler_t)(void *arg);
typedef struct int_handle_data_t int_handle_data_t; typedef struct intr_handle_data_t intr_handle_data_t;
typedef int_handle_data_t* int_handle_t ; typedef intr_handle_data_t* intr_handle_t ;
/** /**
* @brief Mark an interrupt as a shared interrupt * @brief Mark an interrupt as a shared interrupt
@ -134,7 +135,7 @@ esp_err_t esp_intr_reserve(int intno, int cpu);
* @param handler The interrupt handler. Must be NULL when an interrupt of level >3 * @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. * is requested, because these types of interrupts aren't C-callable.
* @param arg Optional argument for passed to the interrupt handler * @param arg Optional argument for passed to the interrupt handler
* @param ret_handle Pointer to an int_handle_t to store a handle that can later be * @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 * used to request details or free the interrupt. Can be NULL if no handle
* is required. * is required.
* *
@ -142,7 +143,7 @@ esp_err_t esp_intr_reserve(int intno, int cpu);
* ESP_ERR_NOT_FOUND No free interrupt found with the specified flags * ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
* ESP_OK otherwise * ESP_OK otherwise
*/ */
esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, int_handle_t *ret_handle); esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, intr_handle_t *ret_handle);
/** /**
@ -171,7 +172,7 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *ar
* @param handler The interrupt handler. Must be NULL when an interrupt of level >3 * @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. * is requested, because these types of interrupts aren't C-callable.
* @param arg Optional argument for passed to the interrupt handler * @param arg Optional argument for passed to the interrupt handler
* @param ret_handle Pointer to an int_handle_t to store a handle that can later be * @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 * used to request details or free the interrupt. Can be NULL if no handle
* is required. * is required.
* *
@ -179,7 +180,7 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *ar
* ESP_ERR_NOT_FOUND No free interrupt found with the specified flags * ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
* ESP_OK otherwise * ESP_OK otherwise
*/ */
esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusreg, uint32_t intrstatusmask, intr_handler_t handler, void *arg, int_handle_t *ret_handle); 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);
/** /**
@ -194,7 +195,7 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
* where the interrupt is allocated on. * where the interrupt is allocated on.
* ESP_OK otherwise * ESP_OK otherwise
*/ */
esp_err_t esp_intr_free(int_handle_t handle); esp_err_t esp_intr_free(intr_handle_t handle);
/** /**
@ -204,7 +205,7 @@ esp_err_t esp_intr_free(int_handle_t handle);
* *
* @return The core number where the interrupt is allocated * @return The core number where the interrupt is allocated
*/ */
int esp_intr_get_cpu(int_handle_t handle); int esp_intr_get_cpu(intr_handle_t handle);
/** /**
* @brief Get the allocated interrupt for a certain handle * @brief Get the allocated interrupt for a certain handle
@ -213,32 +214,36 @@ int esp_intr_get_cpu(int_handle_t handle);
* *
* @return The interrupt number * @return The interrupt number
*/ */
int esp_intr_get_intno(int_handle_t handle); int esp_intr_get_intno(intr_handle_t handle);
/** /**
* @brief Disable the interrupt associated with the handle * @brief Disable the interrupt associated with the handle
* *
* @note This function can only disable non-shared inteerupts allocated on the CPU that runs this function. * @note This function can only disable non-shared inteerupts allocated on the CPU that runs this function.
* @warning Do not call this in a critical section; when the critical section ends the interrupt status
* on critical section enter may be restored.
* *
* @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus * @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. * @return ESP_ERR_INVALID_ARG if the combination of arguments is invalid.
* ESP_OK otherwise * ESP_OK otherwise
*/ */
esp_err_t esp_intr_disable(int_handle_t handle); esp_err_t esp_intr_disable(intr_handle_t handle);
/** /**
* @brief Ensable the interrupt associated with the handle * @brief Ensable the interrupt associated with the handle
* *
* @note This function can only enable non-shared inteerupts allocated on the CPU that runs this function. * @note This function can only enable non-shared inteerupts allocated on the CPU that runs this function.
* @warning Do not call this in a critical section; when the critical section ends the interrupt status
* on critical section enter may be restored.
* *
* @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus * @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. * @return ESP_ERR_INVALID_ARG if the combination of arguments is invalid.
* ESP_OK otherwise * ESP_OK otherwise
*/ */
esp_err_t esp_intr_enable(int_handle_t handle); esp_err_t esp_intr_enable(intr_handle_t handle);
/** /**

View file

@ -131,28 +131,12 @@ const static int_desc_t int_desc[32]={
{ 5, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //31 { 5, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //31
}; };
//For memory usage and to get an unique ID for every int on every CPU core, the
//intrs and cpus are stored in in one int. These functions handle that.
inline static int to_intno_cpu(int intno, int cpu)
{
return intno+cpu*32;
}
inline static int to_intno(int intno_cpu)
{
return (intno_cpu)&31;
}
inline static int to_cpu(int intno_cpu)
{
return (intno_cpu)/32;
}
typedef struct shared_vector_desc_t shared_vector_desc_t; typedef struct shared_vector_desc_t shared_vector_desc_t;
typedef struct vector_desc_t vector_desc_t; typedef struct vector_desc_t vector_desc_t;
struct shared_vector_desc_t { struct shared_vector_desc_t {
int disabled: 1;
int source: 8;
volatile uint32_t *statusreg; volatile uint32_t *statusreg;
uint32_t statusmask; uint32_t statusmask;
intr_handler_t isr; intr_handler_t isr;
@ -166,20 +150,23 @@ struct shared_vector_desc_t {
#define VECDESC_FL_SHARED (1<<2) #define VECDESC_FL_SHARED (1<<2)
#define VECDESC_FL_NONSHARED (1<<3) #define VECDESC_FL_NONSHARED (1<<3)
//Pack using bitfields for better memory use
struct vector_desc_t { struct vector_desc_t {
int intno_cpu; //intno+cpu*32 int flags: 16; //OR of VECDESC_FLAG_* defines
int flags; //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 shared_vector_desc_t *shared_vec_info; //used when VECDESC_FL_SHARED
vector_desc_t *next; vector_desc_t *next;
}; };
struct int_handle_data_t { struct intr_handle_data_t {
vector_desc_t *vector_desc; vector_desc_t *vector_desc;
shared_vector_desc_t *shared_vector_desc; shared_vector_desc_t *shared_vector_desc;
}; };
//Linked list of vector descriptions, sorted by intno_cpu value //Linked list of vector descriptions, sorted by cpu.intno value
static vector_desc_t *vector_desc_head; static vector_desc_t *vector_desc_head;
//This bitmask has an 1 if the int should be disabled when the flash is disabled. //This bitmask has an 1 if the int should be disabled when the flash is disabled.
@ -192,13 +179,14 @@ static bool non_iram_int_disabled_flag[portNUM_PROCESSORS];
static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
//Inserts an item into vector_desc list so that the list is sorted //Inserts an item into vector_desc list so that the list is sorted
//with an incrementing intno_cpu value. //with an incrementing cpu.intno value.
static void insert_vector_desc(vector_desc_t *to_insert) static void insert_vector_desc(vector_desc_t *to_insert)
{ {
vector_desc_t *vd=vector_desc_head; vector_desc_t *vd=vector_desc_head;
vector_desc_t *prev=NULL; vector_desc_t *prev=NULL;
while(vd!=NULL) { while(vd!=NULL) {
if (vd->intno_cpu >= to_insert->intno_cpu) break; if (vd->cpu > to_insert->cpu) break;
if (vd->cpu == to_insert->cpu && vd->intno >= to_insert->intno) break;
prev=vd; prev=vd;
vd=vd->next; vd=vd->next;
} }
@ -217,7 +205,7 @@ static vector_desc_t *find_desc_for_int(int intno, int cpu)
{ {
vector_desc_t *vd=vector_desc_head; vector_desc_t *vd=vector_desc_head;
while(vd!=NULL) { while(vd!=NULL) {
if (vd->intno_cpu==to_intno_cpu(intno, cpu)) break; if (vd->cpu==cpu && vd->intno==intno) break;
vd=vd->next; vd=vd->next;
} }
return vd; return vd;
@ -233,7 +221,8 @@ static vector_desc_t *get_desc_for_int(int intno, int cpu)
vector_desc_t *newvd=malloc(sizeof(vector_desc_t)); vector_desc_t *newvd=malloc(sizeof(vector_desc_t));
if (newvd==NULL) return NULL; if (newvd==NULL) return NULL;
memset(newvd, 0, sizeof(vector_desc_t)); memset(newvd, 0, sizeof(vector_desc_t));
newvd->intno_cpu=to_intno_cpu(intno, cpu); newvd->intno=intno;
newvd->cpu=cpu;
insert_vector_desc(newvd); insert_vector_desc(newvd);
return newvd; return newvd;
} else { } else {
@ -296,6 +285,7 @@ static bool int_has_handler(int intr, int cpu)
//Locate a free interrupt compatible with the flags given. //Locate a free interrupt compatible with the flags given.
//The 'force' argument can be -1, or 0-31 to force checking a certain interrupt. //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) static int get_free_int(int flags, int cpu, int force)
{ {
int x; int x;
@ -323,10 +313,14 @@ static int get_free_int(int flags, int cpu, int force)
x, int_desc[x].cpuflags[cpu]==INTDESC_RESVD, int_desc[x].level, 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)); int_desc[x].type==INTTP_LEVEL?"LEVEL":"EDGE", int_has_handler(x, cpu));
//Check if interrupt is not reserved by design //Check if interrupt is not reserved by design
if (int_desc[x].cpuflags[cpu]==INTDESC_RESVD) { //ToDo: Check for SPECIAL and force!=-1 if (int_desc[x].cpuflags[cpu]==INTDESC_RESVD) {
ALCHLOG(TAG, "....Unusable: reserved"); ALCHLOG(TAG, "....Unusable: reserved");
continue; 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 //Check if the interrupt level is acceptable
if (!(flags&(1<<int_desc[x].level))) { if (!(flags&(1<<int_desc[x].level))) {
ALCHLOG(TAG, "....Unusable: incompatible level"); ALCHLOG(TAG, "....Unusable: incompatible level");
@ -426,10 +420,12 @@ static void IRAM_ATTR shared_intr_isr(void *arg)
shared_vector_desc_t *sh_vec=vd->shared_vec_info; shared_vector_desc_t *sh_vec=vd->shared_vec_info;
portENTER_CRITICAL(&spinlock); portENTER_CRITICAL(&spinlock);
while(sh_vec) { while(sh_vec) {
if ((sh_vec->statusreg == NULL) || (*sh_vec->statusreg & sh_vec->statusmask)) { if (!sh_vec->disabled) {
sh_vec->isr(sh_vec->arg); if ((sh_vec->statusreg == NULL) || (*sh_vec->statusreg & sh_vec->statusmask)) {
sh_vec=sh_vec->next; sh_vec->isr(sh_vec->arg);
}
} }
sh_vec=sh_vec->next;
} }
portEXIT_CRITICAL(&spinlock); portEXIT_CRITICAL(&spinlock);
} }
@ -437,19 +433,18 @@ static void IRAM_ATTR shared_intr_isr(void *arg)
//We use ESP_EARLY_LOG* here because this can be called before the scheduler is running. //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, esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusreg, uint32_t intrstatusmask, intr_handler_t handler,
void *arg, int_handle_t *ret_handle) void *arg, intr_handle_t *ret_handle)
{ {
int_handle_data_t *ret=NULL; intr_handle_data_t *ret=NULL;
int force=-1; int force=-1;
printf("Src %d reg/mask %x/%x\n", source, intrstatusreg, intrstatusmask);
ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): checking args", xPortGetCoreID()); ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): checking args", xPortGetCoreID());
//Shared interrupts should be level-triggered. //Shared interrupts should be level-triggered.
if ((flags&ESP_INTR_FLAG_SHARED) && (flags&ESP_INTR_FLAG_EDGE)) return ESP_ERR_INVALID_ARG; 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. //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; if ((flags&ESP_INTR_FLAG_HIGH) && (handler)) return ESP_ERR_INVALID_ARG;
//Shared ints should have handler //Shared ints should have handler and non-processor-local source
if ((flags&ESP_INTR_FLAG_SHARED) && (!handler)) return ESP_ERR_INVALID_ARG; if ((flags&ESP_INTR_FLAG_SHARED) && (!handler || source<0)) return ESP_ERR_INVALID_ARG;
//Only shared interrupts can have status reg / mask
if (intrstatusreg && (!(flags&ESP_INTR_FLAG_SHARED))) return ESP_ERR_INVALID_ARG;
//Statusreg should have a mask //Statusreg should have a mask
if (intrstatusreg && !intrstatusmask) return ESP_ERR_INVALID_ARG; if (intrstatusreg && !intrstatusmask) return ESP_ERR_INVALID_ARG;
@ -472,11 +467,9 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
if (source==ETS_INTERNAL_SW1_INTR_SOURCE) force=ETS_INTERNAL_SW1_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; if (source==ETS_INTERNAL_PROFILING_INTR_SOURCE) force=ETS_INTERNAL_PROFILING_INTR_NO;
//If we should return a handle, allocate it here. //Allocate a return handle. If we end up not needing it, we'll free it later on.
if (ret_handle!=NULL) { ret=malloc(sizeof(intr_handle_data_t));
ret=malloc(sizeof(int_handle_data_t)); if (ret==NULL) return ESP_ERR_NO_MEM;
if (ret==NULL) return ESP_ERR_NO_MEM;
}
portENTER_CRITICAL(&spinlock); portENTER_CRITICAL(&spinlock);
int cpu=xPortGetCoreID(); int cpu=xPortGetCoreID();
@ -511,6 +504,8 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
sh_vec->isr=handler; sh_vec->isr=handler;
sh_vec->arg=arg; sh_vec->arg=arg;
sh_vec->next=vd->shared_vec_info; sh_vec->next=vd->shared_vec_info;
sh_vec->source=source;
sh_vec->disabled=0;
vd->shared_vec_info=sh_vec; vd->shared_vec_info=sh_vec;
vd->flags|=VECDESC_FL_SHARED; vd->flags|=VECDESC_FL_SHARED;
//(Re-)set shared isr handler to new value. //(Re-)set shared isr handler to new value.
@ -522,6 +517,7 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
xt_set_interrupt_handler(intr, handler, arg); xt_set_interrupt_handler(intr, handler, arg);
} }
if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr); if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr);
vd->source=source;
} }
if (flags&ESP_INTR_FLAG_IRAM) { if (flags&ESP_INTR_FLAG_IRAM) {
vd->flags|=VECDESC_FL_INIRAM; vd->flags|=VECDESC_FL_INIRAM;
@ -533,22 +529,34 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
if (source>=0) { if (source>=0) {
intr_matrix_set(cpu, source, intr); intr_matrix_set(cpu, source, intr);
} }
//Fill return handle if needed
if (ret_handle!=NULL) { //Fill return handle data.
ret->vector_desc=vd; ret->vector_desc=vd;
ret->shared_vector_desc=vd->shared_vec_info; ret->shared_vector_desc=vd->shared_vec_info;
*ret_handle=ret;
//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);
} }
//We enable the interrupt in any case. For shared interrupts, the interrupts are enabled as soon as we exit
//the critical region anyway, so this is consistent.
portEXIT_CRITICAL(&spinlock); 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); ESP_EARLY_LOGD(TAG, "Connected src %d to int %d (cpu %d)", source, intr, cpu);
ESP_INTR_ENABLE(intr);
return ESP_OK; return ESP_OK;
} }
esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, int_handle_t *ret_handle) 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 As an optimization, we can create a table with the possible interrupt status registers and masks for every single
@ -559,13 +567,14 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *ar
} }
esp_err_t esp_intr_free(int_handle_t handle) esp_err_t esp_intr_free(intr_handle_t handle)
{ {
bool free_shared_vector=false; bool free_shared_vector=false;
if (!handle) return ESP_ERR_INVALID_ARG; if (!handle) return ESP_ERR_INVALID_ARG;
//This routine should be called from the interrupt the task is scheduled on. //This routine should be called from the interrupt the task is scheduled on.
if (to_cpu(handle->vector_desc->intno_cpu)!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; if (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG;
esp_intr_disable(handle);
portENTER_CRITICAL(&spinlock); portENTER_CRITICAL(&spinlock);
if (handle->vector_desc->flags&VECDESC_FL_SHARED) { if (handle->vector_desc->flags&VECDESC_FL_SHARED) {
//Find and kill the shared int //Find and kill the shared int
@ -593,46 +602,87 @@ esp_err_t esp_intr_free(int_handle_t handle)
if ((handle->vector_desc->flags&VECDESC_FL_NONSHARED) || free_shared_vector) { if ((handle->vector_desc->flags&VECDESC_FL_NONSHARED) || free_shared_vector) {
ESP_LOGV(TAG, "esp_intr_free: Disabling int, killing handler"); ESP_LOGV(TAG, "esp_intr_free: Disabling int, killing handler");
//Interrupt is not shared. Just disable it and revert to the default interrupt handler. //Reset to normal handler
ESP_INTR_DISABLE(to_intno(handle->vector_desc->intno_cpu)); xt_set_interrupt_handler(handle->vector_desc->intno, xt_unhandled_interrupt, (void*)handle->vector_desc->intno);
xt_set_interrupt_handler(to_intno(handle->vector_desc->intno_cpu), xt_unhandled_interrupt, NULL);
//Theoretically, we could free the vector_desc... not sure if that's worth the few bytes of memory //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 //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. //the desc.) For now, just mark it as free.
handle->vector_desc->flags&=!(VECDESC_FL_NONSHARED|VECDESC_FL_RESERVED); handle->vector_desc->flags&=!(VECDESC_FL_NONSHARED|VECDESC_FL_RESERVED);
//Also kill non_iram mask bit. //Also kill non_iram mask bit.
non_iram_int_mask[to_cpu(handle->vector_desc->intno_cpu)]&=~(1<<(to_intno(handle->vector_desc->intno_cpu))); non_iram_int_mask[handle->vector_desc->cpu]&=~(1<<(handle->vector_desc->intno));
} }
portEXIT_CRITICAL(&spinlock); portEXIT_CRITICAL(&spinlock);
free(handle); free(handle);
return ESP_OK; return ESP_OK;
} }
int esp_intr_get_intno(int_handle_t handle) int esp_intr_get_intno(intr_handle_t handle)
{ {
return to_intno(handle->vector_desc->intno_cpu); return handle->vector_desc->intno;
} }
int esp_intr_get_cpu(int_handle_t handle) int esp_intr_get_cpu(intr_handle_t handle)
{ {
return to_cpu(handle->vector_desc->intno_cpu); return handle->vector_desc->cpu;
} }
esp_err_t esp_intr_enable(int_handle_t handle) /*
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; if (!handle) return ESP_ERR_INVALID_ARG;
if (handle->shared_vector_desc) return ESP_ERR_INVALID_ARG; //Shared ints can't be enabled using this function. portENTER_CRITICAL(&spinlock);
if (to_cpu(handle->vector_desc->intno_cpu)!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; //Can only enable ints on this cpu int source;
ESP_INTR_ENABLE(to_intno(handle->vector_desc->intno_cpu)); 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; return ESP_OK;
} }
esp_err_t esp_intr_disable(int_handle_t handle) esp_err_t esp_intr_disable(intr_handle_t handle)
{ {
if (!handle) return ESP_ERR_INVALID_ARG; if (!handle) return ESP_ERR_INVALID_ARG;
if (handle->shared_vector_desc) return ESP_ERR_INVALID_ARG; //Shared ints can't be disabled using this function. portENTER_CRITICAL(&spinlock);
if (to_cpu(handle->vector_desc->intno_cpu)!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; //Can only disable ints on this cpu int source;
ESP_INTR_DISABLE(to_intno(handle->vector_desc->intno_cpu)); 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; return ESP_OK;
} }

View file

@ -0,0 +1,150 @@
/*
Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc.
*/
#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 */
/*
* @brief timer group0 hardware timer1 init
*/
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]);
}
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);
}

View file

@ -74,6 +74,7 @@ CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
# #
# Component config # Component config
# #
CONFIG_BTC_TASK_STACK_SIZE=2048
CONFIG_BT_RESERVE_DRAM=0 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_DEFAULT_CPU_FREQ_MHZ=240
# CONFIG_ESP32_ENABLE_STACK_WIFI is not set # CONFIG_ESP32_ENABLE_STACK_WIFI is not set
# CONFIG_ESP32_ENABLE_STACK_BT is not set # CONFIG_ESP32_ENABLE_STACK_BT is not set
CONFIG_ESP32_ENABLE_STACK_NONE=y
CONFIG_MEMMAP_SMP=y CONFIG_MEMMAP_SMP=y
# CONFIG_MEMMAP_TRACEMEM is not set # CONFIG_MEMMAP_TRACEMEM is not set
CONFIG_TRACEMEM_RESERVE_DRAM=0x0 CONFIG_TRACEMEM_RESERVE_DRAM=0x0
@ -165,7 +165,6 @@ CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384
CONFIG_MBEDTLS_HARDWARE_AES=y CONFIG_MBEDTLS_HARDWARE_AES=y
CONFIG_MBEDTLS_HARDWARE_MPI=y CONFIG_MBEDTLS_HARDWARE_MPI=y
CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y
CONFIG_MBEDTLS_MPI_INTERRUPT_NUM=18
CONFIG_MBEDTLS_HARDWARE_SHA=y CONFIG_MBEDTLS_HARDWARE_SHA=y
# #