pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_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
#define PCNT_CTRL_MODE_ERR_STR "PCNT CTRL MODE 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) \
if (!(a)) { \
ESP_LOGE(PCNT_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
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)
-#define PCNT_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
-#define PCNT_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
-#define PCNT_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
+static pcnt_isr_func_t *pcnt_isr_func = NULL;
+static pcnt_isr_handle_t pcnt_isr_service = NULL;
+static portMUX_TYPE pcnt_spinlock = portMUX_INITIALIZER_UNLOCKED;
+static const char* PCNT_TAG = "pcnt";
esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config)
{
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);
+}