Merge branch 'feature/pcnt_add_isr_manage_apis' into 'master'
Driver(pcnt) : Add new feature that each unit can has it's own interrupt handler. See merge request idf/esp-idf!2086
This commit is contained in:
commit
234723c061
2 changed files with 136 additions and 6 deletions
|
@ -330,6 +330,61 @@ esp_err_t pcnt_set_mode(pcnt_unit_t unit, pcnt_channel_t channel,
|
||||||
pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode,
|
pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode,
|
||||||
pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode);
|
pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add ISR handler for specified unit.
|
||||||
|
*
|
||||||
|
* Call this function after using pcnt_isr_service_install() to
|
||||||
|
* install the PCNT driver's ISR handler service.
|
||||||
|
*
|
||||||
|
* The ISR handlers do not need to be declared with IRAM_ATTR,
|
||||||
|
* unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the
|
||||||
|
* ISR in pcnt_isr_service_install().
|
||||||
|
*
|
||||||
|
* This ISR handler will be called from an ISR. So there is a stack
|
||||||
|
* size limit (configurable as "ISR stack size" in menuconfig). This
|
||||||
|
* limit is smaller compared to a global PCNT interrupt handler due
|
||||||
|
* to the additional level of indirection.
|
||||||
|
*
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param isr_handler Interrupt handler function.
|
||||||
|
* @param args Parameter for handler function
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK Success
|
||||||
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
|
*/
|
||||||
|
esp_err_t pcnt_isr_handler_add(pcnt_unit_t unit, void(*isr_handler)(void *), void *args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Install PCNT ISR service.
|
||||||
|
* @note We can manage different interrupt service for each unit.
|
||||||
|
* Please do not use pcnt_isr_register if this function was called.
|
||||||
|
*
|
||||||
|
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
|
||||||
|
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK Success
|
||||||
|
* - ESP_ERR_NO_MEM No memory to install this service
|
||||||
|
* - ESP_ERR_INVALID_STATE ISR service already installed
|
||||||
|
*/
|
||||||
|
esp_err_t pcnt_isr_service_install(int intr_alloc_flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Uninstall PCNT ISR service, freeing related resources.
|
||||||
|
*/
|
||||||
|
void pcnt_isr_service_uninstall(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete ISR handler for specified unit.
|
||||||
|
*
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK Success
|
||||||
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
|
*/
|
||||||
|
esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup pcnt-examples
|
* @addtogroup pcnt-examples
|
||||||
|
|
|
@ -25,19 +25,24 @@
|
||||||
#define PCNT_CTRL_MODE_ERR_STR "PCNT CTRL MODE ERROR"
|
#define PCNT_CTRL_MODE_ERR_STR "PCNT CTRL MODE ERROR"
|
||||||
#define PCNT_EVT_TYPE_ERR_STR "PCNT value type error"
|
#define PCNT_EVT_TYPE_ERR_STR "PCNT value type error"
|
||||||
|
|
||||||
static const char* PCNT_TAG = "pcnt";
|
#define PCNT_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
|
||||||
|
#define PCNT_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
|
||||||
|
|
||||||
#define PCNT_CHECK(a, str, ret_val) \
|
#define PCNT_CHECK(a, str, ret_val) \
|
||||||
if (!(a)) { \
|
if (!(a)) { \
|
||||||
ESP_LOGE(PCNT_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
|
ESP_LOGE(PCNT_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
|
||||||
return (ret_val); \
|
return (ret_val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
static portMUX_TYPE pcnt_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
typedef struct{
|
||||||
|
void(*fn)(void *args); /*!< isr function */
|
||||||
|
void* args; /*!< isr function args */
|
||||||
|
} pcnt_isr_func_t;
|
||||||
|
|
||||||
#define PCNT_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
|
static pcnt_isr_func_t *pcnt_isr_func = NULL;
|
||||||
#define PCNT_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
|
static pcnt_isr_handle_t pcnt_isr_service = NULL;
|
||||||
#define PCNT_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
|
static portMUX_TYPE pcnt_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
#define PCNT_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
|
static const char* PCNT_TAG = "pcnt";
|
||||||
|
|
||||||
esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config)
|
esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config)
|
||||||
{
|
{
|
||||||
|
@ -285,3 +290,73 @@ esp_err_t pcnt_isr_register(void (*fun)(void*), void * arg, int intr_alloc_flags
|
||||||
return esp_intr_alloc(ETS_PCNT_INTR_SOURCE, intr_alloc_flags, fun, arg, handle);
|
return esp_intr_alloc(ETS_PCNT_INTR_SOURCE, intr_alloc_flags, fun, arg, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pcnt interrupt service
|
||||||
|
static void IRAM_ATTR pcnt_intr_service(void* arg)
|
||||||
|
{
|
||||||
|
uint32_t intr_status = PCNT.int_st.val;
|
||||||
|
for (int unit = 0; unit < PCNT_UNIT_MAX; unit++) {
|
||||||
|
if (intr_status & (BIT(unit))) {
|
||||||
|
if (pcnt_isr_func[unit].fn != NULL) {
|
||||||
|
(pcnt_isr_func[unit].fn)(pcnt_isr_func[unit].args);
|
||||||
|
}
|
||||||
|
PCNT.int_clr.val = BIT(unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t pcnt_isr_handler_add(pcnt_unit_t unit, void(*isr_handler)(void *), void *args)
|
||||||
|
{
|
||||||
|
PCNT_CHECK(pcnt_isr_func != NULL, "ISR service is not installed, call pcnt_install_isr_service() first", ESP_ERR_INVALID_STATE);
|
||||||
|
PCNT_CHECK(unit < PCNT_UNIT_MAX, "PCNT unit error", ESP_ERR_INVALID_ARG);
|
||||||
|
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||||
|
pcnt_intr_disable(unit);
|
||||||
|
if (pcnt_isr_func) {
|
||||||
|
pcnt_isr_func[unit].fn = isr_handler;
|
||||||
|
pcnt_isr_func[unit].args = args;
|
||||||
|
}
|
||||||
|
pcnt_intr_enable(unit);
|
||||||
|
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit)
|
||||||
|
{
|
||||||
|
PCNT_CHECK(pcnt_isr_func != NULL, "ISR service is not installed", ESP_ERR_INVALID_STATE);
|
||||||
|
PCNT_CHECK(unit < PCNT_UNIT_MAX, "PCNT unit error", ESP_ERR_INVALID_ARG);
|
||||||
|
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||||
|
pcnt_intr_disable(unit);
|
||||||
|
if (pcnt_isr_func) {
|
||||||
|
pcnt_isr_func[unit].fn = NULL;
|
||||||
|
pcnt_isr_func[unit].args = NULL;
|
||||||
|
}
|
||||||
|
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t pcnt_isr_service_install(int intr_alloc_flags)
|
||||||
|
{
|
||||||
|
PCNT_CHECK(pcnt_isr_func == NULL, "ISR service already installed", ESP_ERR_INVALID_STATE);
|
||||||
|
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||||
|
esp_err_t ret = ESP_FAIL;
|
||||||
|
pcnt_isr_func = (pcnt_isr_func_t*) calloc(PCNT_UNIT_MAX, sizeof(pcnt_isr_func_t));
|
||||||
|
if (pcnt_isr_func == NULL) {
|
||||||
|
ret = ESP_ERR_NO_MEM;
|
||||||
|
} else {
|
||||||
|
ret = pcnt_isr_register(pcnt_intr_service, NULL, intr_alloc_flags, &pcnt_isr_service);
|
||||||
|
}
|
||||||
|
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcnt_isr_service_uninstall(void)
|
||||||
|
{
|
||||||
|
if (pcnt_isr_func == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||||
|
esp_intr_free(pcnt_isr_service);
|
||||||
|
free(pcnt_isr_func);
|
||||||
|
pcnt_isr_func = NULL;
|
||||||
|
pcnt_isr_service = NULL;
|
||||||
|
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue