From b1a72866cab620ec872e0a87e844087d9c86adc4 Mon Sep 17 00:00:00 2001 From: xiongyu Date: Mon, 15 Jul 2019 14:44:15 +0800 Subject: [PATCH] refactor(pcnt): add hal pcnt driver --- components/driver/include/driver/pcnt.h | 133 ++-- components/driver/pcnt.c | 591 +++++++++++------- components/soc/CMakeLists.txt | 1 + components/soc/esp32/include/hal/pcnt_ll.h | 301 +++++++++ components/soc/esp32/include/soc/pcnt_caps.h | 40 ++ .../soc/esp32s2beta/include/hal/pcnt_ll.h | 301 +++++++++ .../soc/esp32s2beta/include/soc/pcnt_caps.h | 37 ++ components/soc/include/hal/pcnt_hal.h | 214 +++++++ components/soc/include/hal/pcnt_types.h | 92 +++ components/soc/src/hal/pcnt_hal.c | 23 + docs/Doxyfile | 1 + 11 files changed, 1418 insertions(+), 316 deletions(-) create mode 100644 components/soc/esp32/include/hal/pcnt_ll.h create mode 100644 components/soc/esp32/include/soc/pcnt_caps.h create mode 100644 components/soc/esp32s2beta/include/hal/pcnt_ll.h create mode 100644 components/soc/esp32s2beta/include/soc/pcnt_caps.h create mode 100644 components/soc/include/hal/pcnt_hal.h create mode 100644 components/soc/include/hal/pcnt_types.h create mode 100644 components/soc/src/hal/pcnt_hal.c diff --git a/components/driver/include/driver/pcnt.h b/components/driver/include/driver/pcnt.h index f984dc68d..292f389a2 100644 --- a/components/driver/include/driver/pcnt.h +++ b/components/driver/include/driver/pcnt.h @@ -1,5 +1,18 @@ -#ifndef __PCNT_H__ -#define __PCNT_H__ +// Copyright 2015-2019 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. + +#pragma once #include #include "esp_intr_alloc.h" @@ -8,92 +21,15 @@ #include "freertos/semphr.h" #include "freertos/xtensa_api.h" #include "soc/soc.h" -#include "soc/pcnt_periph.h" +#include "soc/pcnt_caps.h" #include "driver/gpio.h" +#include "hal/pcnt_types.h" +#include "hal/pcnt_hal.h" #ifdef __cplusplus extern "C" { #endif -#define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */ - -/** - * @brief Selection of available modes that determine the counter's action depending on the state of the control signal's input GPIO - * @note Configuration covers two actions, one for high, and one for low level on the control input - */ -typedef enum { - PCNT_MODE_KEEP = 0, /*!< Control mode: won't change counter mode*/ - PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase) */ - PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition) */ - PCNT_MODE_MAX -} pcnt_ctrl_mode_t; - -/** - * @brief Selection of available modes that determine the counter's action on the edge of the pulse signal's input GPIO - * @note Configuration covers two actions, one for positive, and one for negative edge on the pulse input - */ -typedef enum { - PCNT_COUNT_DIS = 0, /*!< Counter mode: Inhibit counter(counter value will not change in this condition) */ - PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value */ - PCNT_COUNT_DEC = 2, /*!< Counter mode: Decrease counter value */ - PCNT_COUNT_MAX -} pcnt_count_mode_t; - -/** - * @brief Selection of all available PCNT units - */ -typedef enum { - PCNT_UNIT_0 = 0, /*!< PCNT unit 0 */ - PCNT_UNIT_1 = 1, /*!< PCNT unit 1 */ - PCNT_UNIT_2 = 2, /*!< PCNT unit 2 */ - PCNT_UNIT_3 = 3, /*!< PCNT unit 3 */ -//ESP32-S2 only have 4 unit -#ifdef CONFIG_IDF_TARGET_ESP32 - PCNT_UNIT_4 = 4, /*!< PCNT unit 4 */ - PCNT_UNIT_5 = 5, /*!< PCNT unit 5 */ - PCNT_UNIT_6 = 6, /*!< PCNT unit 6 */ - PCNT_UNIT_7 = 7, /*!< PCNT unit 7 */ -#endif - PCNT_UNIT_MAX, -} pcnt_unit_t; - -/** - * @brief Selection of channels available for a single PCNT unit - */ -typedef enum { - PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel 0 */ - PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel 1 */ - PCNT_CHANNEL_MAX, -} pcnt_channel_t; - -/** - * @brief Selection of counter's events the may trigger an interrupt - */ -typedef enum { - PCNT_EVT_THRES_1 = BIT(2), /*!< PCNT watch point event: threshold1 value event */ - PCNT_EVT_THRES_0 = BIT(3), /*!< PCNT watch point event: threshold0 value event */ - PCNT_EVT_L_LIM = BIT(4), /*!< PCNT watch point event: Minimum counter value */ - PCNT_EVT_H_LIM = BIT(5), /*!< PCNT watch point event: Maximum counter value */ - PCNT_EVT_ZERO = BIT(6), /*!< PCNT watch point event: counter value zero event */ - PCNT_EVT_MAX -} pcnt_evt_type_t; - -/** - * @brief Pulse Counter configuration for a single channel - */ -typedef struct { - int pulse_gpio_num; /*!< Pulse input GPIO number, if you want to use GPIO16, enter pulse_gpio_num = 16, a negative value will be ignored */ - int ctrl_gpio_num; /*!< Control signal input GPIO number, a negative value will be ignored */ - pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode */ - pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode */ - pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode */ - pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode */ - int16_t counter_h_lim; /*!< Maximum counter value */ - int16_t counter_l_lim; /*!< Minimum counter value */ - pcnt_unit_t unit; /*!< PCNT unit number */ - pcnt_channel_t channel; /*!< the PCNT channel */ -} pcnt_config_t; - typedef intr_handle_t pcnt_isr_handle_t; /** @@ -105,6 +41,7 @@ typedef intr_handle_t pcnt_isr_handle_t; * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver already initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config); @@ -115,11 +52,12 @@ esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config); * @param pcnt_unit Pulse Counter unit number * @param count Pointer to accept counter value * - * @return + * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t* count); +esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t *count); /** * @brief Pause PCNT counter of PCNT unit @@ -128,6 +66,7 @@ esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t* count); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit); @@ -139,6 +78,7 @@ esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit); @@ -150,6 +90,7 @@ esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit); @@ -164,6 +105,7 @@ esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit); @@ -175,6 +117,7 @@ esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit); @@ -187,6 +130,7 @@ esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit); * All enabled events share the same interrupt (one interrupt per pulse counter unit). * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type); @@ -199,6 +143,7 @@ esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type); * All enabled events share the same interrupt (one interrupt per pulse counter unit). * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type); @@ -214,6 +159,7 @@ esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value); @@ -228,6 +174,7 @@ esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16 * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value); @@ -250,7 +197,7 @@ esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16 * - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags. * - ESP_ERR_INVALID_ARG Function pointer error. */ -esp_err_t pcnt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, pcnt_isr_handle_t *handle); +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 @@ -264,6 +211,7 @@ esp_err_t pcnt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io); @@ -275,6 +223,7 @@ esp_err_t pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, i * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_filter_enable(pcnt_unit_t unit); @@ -286,6 +235,7 @@ esp_err_t pcnt_filter_enable(pcnt_unit_t unit); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_filter_disable(pcnt_unit_t unit); @@ -301,6 +251,7 @@ esp_err_t pcnt_filter_disable(pcnt_unit_t unit); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val); @@ -313,6 +264,7 @@ esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val); @@ -329,6 +281,7 @@ esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_set_mode(pcnt_unit_t unit, pcnt_channel_t channel, @@ -356,6 +309,7 @@ esp_err_t pcnt_set_mode(pcnt_unit_t unit, pcnt_channel_t channel, * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_isr_handler_add(pcnt_unit_t unit, void(*isr_handler)(void *), void *args); @@ -364,13 +318,14 @@ esp_err_t pcnt_isr_handler_add(pcnt_unit_t unit, void(*isr_handler)(void *), voi * @brief Install PCNT ISR service. * @note We can manage different interrupt service for each unit. * This function will use the default ISR handle service, Calling pcnt_isr_service_uninstall to - * uninstall the default service if needed. Please do not use pcnt_isr_register if this function was called. + * uninstall the default service if needed. 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_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_NO_MEM No memory to install this service * - ESP_ERR_INVALID_STATE ISR service already installed */ @@ -388,6 +343,7 @@ void pcnt_isr_service_uninstall(void); * * @return * - ESP_OK Success + * - ESP_ERR_INVALID_STATE pcnt driver has not been initialized * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit); @@ -428,9 +384,6 @@ esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit); * @} */ -#ifdef __cplusplus +#ifdef __cplusplus } #endif - - -#endif diff --git a/components/driver/pcnt.c b/components/driver/pcnt.c index e9500f643..094ee0034 100644 --- a/components/driver/pcnt.c +++ b/components/driver/pcnt.c @@ -3,7 +3,7 @@ // 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 @@ -11,6 +11,7 @@ // 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 "esp_log.h" #include "driver/pcnt.h" #include "driver/periph_ctrl.h" @@ -24,28 +25,313 @@ #define PCNT_CTRL_MODE_ERR_STR "PCNT CTRL MODE ERROR" #define PCNT_EVT_TYPE_ERR_STR "PCNT value type error" #define PCNT_LIMT_VAL_ERR_STR "PCNT limit value error" +#define PCNT_NUM_ERR_STR "PCNT num error" +#define PCNT_DRIVER_ERR_STR "PCNT driver error" #define PCNT_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux) #define PCNT_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux) +static const char *TAG = "pcnt"; + #define PCNT_CHECK(a, str, ret_val) \ if (!(a)) { \ - ESP_LOGE(PCNT_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ + ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ return (ret_val); \ } -typedef struct{ +typedef struct { + pcnt_hal_context_t hal; /*!< PCNT hal context*/ +} pcnt_obj_t; + +static pcnt_obj_t *p_pcnt_obj[PCNT_PORT_MAX] = {0}; + +#define PCNT_OBJ_CHECK(pcnt_port) { \ + PCNT_CHECK((pcnt_port < PCNT_PORT_MAX), PCNT_NUM_ERR_STR, ESP_ERR_INVALID_ARG); \ + PCNT_CHECK((p_pcnt_obj[pcnt_port]), PCNT_DRIVER_ERR_STR, ESP_ERR_INVALID_STATE); \ +} + +typedef struct { void(*fn)(void *args); /*!< isr function */ - void* args; /*!< isr function args */ + void *args; /*!< isr function args */ } pcnt_isr_func_t; 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) +static inline esp_err_t _pcnt_set_mode(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_channel_t channel, 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_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK((pos_mode < PCNT_COUNT_MAX) && (neg_mode < PCNT_COUNT_MAX), PCNT_COUNT_MODE_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK((hctrl_mode < PCNT_MODE_MAX) && (lctrl_mode < PCNT_MODE_MAX), PCNT_CTRL_MODE_ERR_STR, ESP_ERR_INVALID_ARG); + + pcnt_hal_set_mode(&(p_pcnt_obj[pcnt_port]->hal), unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode); + return ESP_OK; +} + +static inline esp_err_t _pcnt_set_pin(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(GPIO_IS_VALID_GPIO(pulse_io) || pulse_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(GPIO_IS_VALID_GPIO(ctrl_io) || ctrl_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG); + + int sig_base = (channel == 0) ? PCNT_SIG_CH0_IN0_IDX : PCNT_SIG_CH1_IN0_IDX; + int ctrl_base = (channel == 0) ? PCNT_CTRL_CH0_IN0_IDX : PCNT_CTRL_CH1_IN0_IDX; + if (unit > 4) { + sig_base += 12; // GPIO matrix assignments have a gap between units 4 & 5 + ctrl_base += 12; + } + + int input_sig_index = sig_base + (4 * unit); + int ctrl_sig_index = ctrl_base + (4 * unit); + + if (pulse_io >= 0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pulse_io], PIN_FUNC_GPIO); + gpio_set_direction(pulse_io, GPIO_MODE_INPUT); + gpio_set_pull_mode(pulse_io, GPIO_PULLUP_ONLY); + gpio_matrix_in(pulse_io, input_sig_index, 0); + } + + if (ctrl_io >= 0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[ctrl_io], PIN_FUNC_GPIO); + gpio_set_direction(ctrl_io, GPIO_MODE_INPUT); + gpio_set_pull_mode(ctrl_io, GPIO_PULLUP_ONLY); + gpio_matrix_in(ctrl_io, ctrl_sig_index, 0); + } + + return ESP_OK; +} + +static inline esp_err_t _pcnt_get_counter_value(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit, int16_t *count) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(count != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG); + pcnt_hal_get_counter_value(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit, count); + return ESP_OK; +} + +static inline esp_err_t _pcnt_counter_pause(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_ENTER_CRITICAL(&pcnt_spinlock); + pcnt_hal_counter_pause(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit); + PCNT_EXIT_CRITICAL(&pcnt_spinlock); + return ESP_OK; +} + +static inline esp_err_t _pcnt_counter_resume(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_ENTER_CRITICAL(&pcnt_spinlock); + pcnt_hal_counter_resume(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit); + PCNT_EXIT_CRITICAL(&pcnt_spinlock); + return ESP_OK; +} + +static inline esp_err_t _pcnt_counter_clear(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_ENTER_CRITICAL(&pcnt_spinlock); + pcnt_hal_counter_clear(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit); + PCNT_EXIT_CRITICAL(&pcnt_spinlock); + return ESP_OK; +} + +static inline esp_err_t _pcnt_intr_enable(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_ENTER_CRITICAL(&pcnt_spinlock); + pcnt_hal_intr_enable(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit); + PCNT_EXIT_CRITICAL(&pcnt_spinlock); + return ESP_OK; +} + +static inline esp_err_t _pcnt_intr_disable(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_ENTER_CRITICAL(&pcnt_spinlock); + pcnt_hal_intr_disable(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit); + PCNT_EXIT_CRITICAL(&pcnt_spinlock); + return ESP_OK; +} + +static inline esp_err_t _pcnt_event_enable(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); + pcnt_hal_event_enable(&(p_pcnt_obj[pcnt_port]->hal), unit, evt_type); + return ESP_OK; +} + +static inline esp_err_t _pcnt_event_disable(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); + pcnt_hal_event_disable(&(p_pcnt_obj[pcnt_port]->hal), unit, evt_type); + return ESP_OK; +} + +static inline esp_err_t _pcnt_set_event_value(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(!(evt_type == PCNT_EVT_L_LIM && value > 0), PCNT_LIMT_VAL_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(!(evt_type == PCNT_EVT_H_LIM && value < 0), PCNT_LIMT_VAL_ERR_STR, ESP_ERR_INVALID_ARG); + pcnt_hal_set_event_value(&(p_pcnt_obj[pcnt_port]->hal), unit, evt_type, value); + return ESP_OK; +} + +static inline esp_err_t _pcnt_get_event_value(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(value != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG); + + pcnt_hal_get_event_value(&(p_pcnt_obj[pcnt_port]->hal), unit, evt_type, value); + return ESP_OK; +} + +static inline esp_err_t _pcnt_set_filter_value(pcnt_port_t pcnt_port, pcnt_unit_t unit, uint16_t filter_val) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(filter_val < 1024, PCNT_PARAM_ERR_STR, ESP_ERR_INVALID_ARG); + pcnt_hal_set_filter_value(&(p_pcnt_obj[pcnt_port]->hal), unit, filter_val); + return ESP_OK; +} + +static inline esp_err_t _pcnt_get_filter_value(pcnt_port_t pcnt_port, pcnt_unit_t unit, uint16_t *filter_val) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK(filter_val != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG); + + pcnt_hal_get_filter_value(&(p_pcnt_obj[pcnt_port]->hal), unit, filter_val); + return ESP_OK; +} + +static inline esp_err_t _pcnt_filter_enable(pcnt_port_t pcnt_port, pcnt_unit_t unit) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + pcnt_hal_filter_enable(&(p_pcnt_obj[pcnt_port]->hal), unit); + return ESP_OK; +} + +static inline esp_err_t _pcnt_filter_disable(pcnt_port_t pcnt_port, pcnt_unit_t unit) +{ + PCNT_OBJ_CHECK(pcnt_port); + PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); + pcnt_hal_filter_disable(&(p_pcnt_obj[pcnt_port]->hal), unit); + return ESP_OK; +} + +static inline esp_err_t _pcnt_isr_handler_add(pcnt_port_t pcnt_port, pcnt_unit_t unit, void(*isr_handler)(void *), void *args) +{ + PCNT_OBJ_CHECK(pcnt_port); + 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(PCNT_PORT_0, unit); + + if (pcnt_isr_func) { + pcnt_isr_func[unit].fn = isr_handler; + pcnt_isr_func[unit].args = args; + } + + _pcnt_intr_enable(PCNT_PORT_0, unit); + PCNT_EXIT_CRITICAL(&pcnt_spinlock); + return ESP_OK; +} + +static inline esp_err_t _pcnt_isr_handler_remove(pcnt_port_t pcnt_port, pcnt_unit_t unit) +{ + PCNT_OBJ_CHECK(pcnt_port); + 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(PCNT_PORT_0, 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; +} + +// pcnt interrupt service +static void IRAM_ATTR pcnt_intr_service(void *arg) +{ + uint32_t status; + pcnt_port_t pcnt_port = (pcnt_port_t)arg; + pcnt_hal_get_intr_status(&(p_pcnt_obj[pcnt_port]->hal), &status); + + while (status) { + int unit = __builtin_ffs(status) - 1; + status &= ~(1 << unit); + + if (pcnt_isr_func[unit].fn != NULL) { + (pcnt_isr_func[unit].fn)(pcnt_isr_func[unit].args); + } + } + pcnt_hal_clear_intr_status(&(p_pcnt_obj[pcnt_port]->hal), status); +} + +static inline esp_err_t _pcnt_isr_service_install(pcnt_port_t pcnt_port, int intr_alloc_flags) +{ + PCNT_OBJ_CHECK(pcnt_port); + 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, (void *)pcnt_port, intr_alloc_flags, &pcnt_isr_service); + } + + PCNT_EXIT_CRITICAL(&pcnt_spinlock); + return ret; +} + +static inline esp_err_t _pcnt_isr_service_uninstall(pcnt_port_t pcnt_port) +{ + PCNT_OBJ_CHECK(pcnt_port); + + if (pcnt_isr_func == NULL) { + return ESP_FAIL; + } + + 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); + + return ESP_OK; +} + +static inline esp_err_t _pcnt_unit_config(pcnt_port_t pcnt_port, const pcnt_config_t *pcnt_config) +{ + PCNT_OBJ_CHECK(pcnt_port); uint8_t unit = pcnt_config->unit; uint8_t channel = pcnt_config->channel; int input_io = pcnt_config->pulse_gpio_num; @@ -65,310 +351,163 @@ esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config) } periph_module_enable(PERIPH_PCNT_MODULE); /*Set counter range*/ - pcnt_set_event_value(unit, PCNT_EVT_H_LIM, pcnt_config->counter_h_lim); - pcnt_set_event_value(unit, PCNT_EVT_L_LIM, pcnt_config->counter_l_lim); + _pcnt_set_event_value(pcnt_port, unit, PCNT_EVT_H_LIM, pcnt_config->counter_h_lim); + _pcnt_set_event_value(pcnt_port, unit, PCNT_EVT_L_LIM, pcnt_config->counter_l_lim); /*Default value after reboot is positive, we disable these events like others*/ - pcnt_event_disable(unit, PCNT_EVT_H_LIM); - pcnt_event_disable(unit, PCNT_EVT_L_LIM); - pcnt_event_disable(unit, PCNT_EVT_ZERO); - pcnt_filter_disable(unit); + _pcnt_event_disable(pcnt_port, unit, PCNT_EVT_H_LIM); + _pcnt_event_disable(pcnt_port, unit, PCNT_EVT_L_LIM); + _pcnt_event_disable(pcnt_port, unit, PCNT_EVT_ZERO); + _pcnt_filter_disable(pcnt_port, unit); /*set pulse input and control mode*/ - pcnt_set_mode(unit, channel, pcnt_config->pos_mode, pcnt_config->neg_mode, pcnt_config->hctrl_mode, pcnt_config->lctrl_mode); + _pcnt_set_mode(pcnt_port, unit, channel, pcnt_config->pos_mode, pcnt_config->neg_mode, pcnt_config->hctrl_mode, pcnt_config->lctrl_mode); /*Set pulse input and control pins*/ - pcnt_set_pin(unit, channel, input_io, ctrl_io); + _pcnt_set_pin(pcnt_port, unit, channel, input_io, ctrl_io); return ESP_OK; } +esp_err_t pcnt_deinit(pcnt_port_t pcnt_port) +{ + PCNT_OBJ_CHECK(pcnt_port); + + heap_caps_free(p_pcnt_obj[pcnt_port]); + p_pcnt_obj[pcnt_port] = NULL; + return ESP_OK; +} + +esp_err_t pcnt_init(pcnt_port_t pcnt_port) +{ + PCNT_CHECK((pcnt_port < PCNT_PORT_MAX), PCNT_NUM_ERR_STR, ESP_ERR_INVALID_ARG); + PCNT_CHECK((p_pcnt_obj[pcnt_port]) == NULL, "pcnt driver already initted", ESP_ERR_INVALID_STATE); + + p_pcnt_obj[pcnt_port] = (pcnt_obj_t *)heap_caps_calloc(1, sizeof(pcnt_obj_t), MALLOC_CAP_DEFAULT); + + if (p_pcnt_obj[pcnt_port] == NULL) { + ESP_LOGE(TAG, "PCNT driver malloc error"); + return ESP_FAIL; + } + + pcnt_hal_init(&(p_pcnt_obj[pcnt_port]->hal), pcnt_port); + return ESP_OK; +} + +// TODO: The following functions are wrappers, for compatibility with current API. + +esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config) +{ + esp_err_t ret; + + if ((p_pcnt_obj[PCNT_PORT_0]) == NULL) { + ret = pcnt_init(PCNT_PORT_0); + if (ret != ESP_OK) { + return ret; + } + } + return _pcnt_unit_config(PCNT_PORT_0, pcnt_config); +} + 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_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK((pos_mode < PCNT_COUNT_MAX) && (neg_mode < PCNT_COUNT_MAX), PCNT_COUNT_MODE_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK((hctrl_mode < PCNT_MODE_MAX) && (lctrl_mode < PCNT_MODE_MAX), PCNT_CTRL_MODE_ERR_STR, ESP_ERR_INVALID_ARG); - - if(channel == 0) { - PCNT.conf_unit[unit].conf0.ch0_pos_mode = pos_mode; - PCNT.conf_unit[unit].conf0.ch0_neg_mode = neg_mode; - PCNT.conf_unit[unit].conf0.ch0_hctrl_mode = hctrl_mode; - PCNT.conf_unit[unit].conf0.ch0_lctrl_mode = lctrl_mode; - } else { - PCNT.conf_unit[unit].conf0.ch1_pos_mode = pos_mode; - PCNT.conf_unit[unit].conf0.ch1_neg_mode = neg_mode; - PCNT.conf_unit[unit].conf0.ch1_hctrl_mode = hctrl_mode; - PCNT.conf_unit[unit].conf0.ch1_lctrl_mode = lctrl_mode; - } - return ESP_OK; + return _pcnt_set_mode(PCNT_PORT_0, unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode); } esp_err_t pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(GPIO_IS_VALID_GPIO(pulse_io) || pulse_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(GPIO_IS_VALID_GPIO(ctrl_io) || ctrl_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG); - - int sig_base = (channel == 0) ? PCNT_SIG_CH0_IN0_IDX : PCNT_SIG_CH1_IN0_IDX; - int ctrl_base = (channel == 0) ? PCNT_CTRL_CH0_IN0_IDX : PCNT_CTRL_CH1_IN0_IDX; - if (unit > 4) { - sig_base += 12; // GPIO matrix assignments have a gap between units 4 & 5 - ctrl_base += 12; - } - int input_sig_index = sig_base + (4 * unit); - int ctrl_sig_index = ctrl_base + (4 * unit); - - if(pulse_io >= 0) { - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pulse_io], PIN_FUNC_GPIO); - gpio_set_direction(pulse_io, GPIO_MODE_INPUT); - gpio_set_pull_mode(pulse_io, GPIO_PULLUP_ONLY); - gpio_matrix_in(pulse_io, input_sig_index, 0); - } - if(ctrl_io >= 0) { - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[ctrl_io], PIN_FUNC_GPIO); - gpio_set_direction(ctrl_io, GPIO_MODE_INPUT); - gpio_set_pull_mode(ctrl_io, GPIO_PULLUP_ONLY); - gpio_matrix_in(ctrl_io, ctrl_sig_index, 0); - } - return ESP_OK; + return _pcnt_set_pin(PCNT_PORT_0, unit, channel, pulse_io, ctrl_io); } -esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t* count) +esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t *count) { - PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(count != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG); - *count = (int16_t) PCNT.cnt_unit[pcnt_unit].cnt_val; - return ESP_OK; + return _pcnt_get_counter_value(PCNT_PORT_0, pcnt_unit, count); } esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit) { - PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_ENTER_CRITICAL(&pcnt_spinlock); - PCNT.ctrl.val |= BIT(PCNT_CNT_PAUSE_U0_S + (pcnt_unit * 2)); - PCNT_EXIT_CRITICAL(&pcnt_spinlock); - return ESP_OK; + return _pcnt_counter_pause(PCNT_PORT_0, pcnt_unit); } esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit) { - PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_ENTER_CRITICAL(&pcnt_spinlock); - PCNT.ctrl.val &= (~(BIT(PCNT_CNT_PAUSE_U0_S + (pcnt_unit * 2)))); - PCNT_EXIT_CRITICAL(&pcnt_spinlock); - return ESP_OK; + return _pcnt_counter_resume(PCNT_PORT_0, pcnt_unit); } esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit) { - PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_ENTER_CRITICAL(&pcnt_spinlock); -#ifdef CONFIG_IDF_TARGET_ESP32 - uint32_t reset_bit = BIT(PCNT_PLUS_CNT_RST_U0_S + (pcnt_unit * 2)); -#elif defined CONFIG_IDF_TARGET_ESP32S2BETA - uint32_t reset_bit = BIT(PCNT_PULSE_CNT_RST_U0_S + (pcnt_unit * 2)); -#endif - PCNT.ctrl.val |= reset_bit; - PCNT.ctrl.val &= ~reset_bit; - PCNT_EXIT_CRITICAL(&pcnt_spinlock); - return ESP_OK; + return _pcnt_counter_clear(PCNT_PORT_0, pcnt_unit); } esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit) { - PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_ENTER_CRITICAL(&pcnt_spinlock); - PCNT.int_ena.val |= BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + pcnt_unit); - PCNT_EXIT_CRITICAL(&pcnt_spinlock); - return ESP_OK; + return _pcnt_intr_enable(PCNT_PORT_0, pcnt_unit); } esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit) { - PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_ENTER_CRITICAL(&pcnt_spinlock); - PCNT.int_ena.val &= (~(BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + pcnt_unit))); - PCNT_EXIT_CRITICAL(&pcnt_spinlock); - return ESP_OK; + return _pcnt_intr_disable(PCNT_PORT_0, pcnt_unit); } esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); - if(evt_type == PCNT_EVT_L_LIM) { - PCNT.conf_unit[unit].conf0.thr_l_lim_en = 1; - } else if(evt_type == PCNT_EVT_H_LIM) { - PCNT.conf_unit[unit].conf0.thr_h_lim_en = 1; - } else if(evt_type == PCNT_EVT_THRES_0) { - PCNT.conf_unit[unit].conf0.thr_thres0_en = 1; - } else if(evt_type == PCNT_EVT_THRES_1) { - PCNT.conf_unit[unit].conf0.thr_thres1_en = 1; - } else if(evt_type == PCNT_EVT_ZERO) { - PCNT.conf_unit[unit].conf0.thr_zero_en = 1; - } - return ESP_OK; + return _pcnt_event_enable(PCNT_PORT_0, unit, evt_type); } esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); - if(evt_type == PCNT_EVT_L_LIM) { - PCNT.conf_unit[unit].conf0.thr_l_lim_en = 0; - } else if(evt_type == PCNT_EVT_H_LIM) { - PCNT.conf_unit[unit].conf0.thr_h_lim_en = 0; - } else if(evt_type == PCNT_EVT_THRES_0) { - PCNT.conf_unit[unit].conf0.thr_thres0_en = 0; - } else if(evt_type == PCNT_EVT_THRES_1) { - PCNT.conf_unit[unit].conf0.thr_thres1_en = 0; - } else if(evt_type == PCNT_EVT_ZERO) { - PCNT.conf_unit[unit].conf0.thr_zero_en = 0; - } - return ESP_OK; + return _pcnt_event_disable(PCNT_PORT_0, unit, evt_type); } esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(!(evt_type == PCNT_EVT_L_LIM && value > 0), PCNT_LIMT_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(!(evt_type == PCNT_EVT_H_LIM && value < 0), PCNT_LIMT_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - if(evt_type == PCNT_EVT_L_LIM) { - PCNT.conf_unit[unit].conf2.cnt_l_lim = value; - } else if(evt_type == PCNT_EVT_H_LIM) { - PCNT.conf_unit[unit].conf2.cnt_h_lim = value; - } else if(evt_type == PCNT_EVT_THRES_0) { - PCNT.conf_unit[unit].conf1.cnt_thres0 = value; - } else if(evt_type == PCNT_EVT_THRES_1) { - PCNT.conf_unit[unit].conf1.cnt_thres1 = value; - } - return ESP_OK; + return _pcnt_set_event_value(PCNT_PORT_0, unit, evt_type, value); } esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(value != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG); - - if(evt_type == PCNT_EVT_L_LIM) { - *value = (int16_t) PCNT.conf_unit[unit].conf2.cnt_l_lim; - } else if(evt_type == PCNT_EVT_H_LIM) { - *value = (int16_t) PCNT.conf_unit[unit].conf2.cnt_h_lim; - } else if(evt_type == PCNT_EVT_THRES_0) { - *value = (int16_t) PCNT.conf_unit[unit].conf1.cnt_thres0; - } else if(evt_type == PCNT_EVT_THRES_1) { - *value = (int16_t) PCNT.conf_unit[unit].conf1.cnt_thres1; - } else { - *value = 0; - } - return ESP_OK; + return _pcnt_get_event_value(PCNT_PORT_0, unit, evt_type, value); } esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(filter_val < 1024, PCNT_PARAM_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT.conf_unit[unit].conf0.filter_thres = filter_val; - return ESP_OK; + return _pcnt_set_filter_value(PCNT_PORT_0, unit, filter_val); } esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT_CHECK(filter_val != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG); - - *filter_val = PCNT.conf_unit[unit].conf0.filter_thres; - return ESP_OK; + return _pcnt_get_filter_value(PCNT_PORT_0, unit, filter_val); } esp_err_t pcnt_filter_enable(pcnt_unit_t unit) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT.conf_unit[unit].conf0.filter_en = 1; - return ESP_OK; + return _pcnt_filter_enable(PCNT_PORT_0, unit); } esp_err_t pcnt_filter_disable(pcnt_unit_t unit) { - PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG); - PCNT.conf_unit[unit].conf0.filter_en = 0; - return ESP_OK; + return _pcnt_filter_disable(PCNT_PORT_0, unit); } -esp_err_t pcnt_isr_register(void (*fun)(void*), void * arg, int intr_alloc_flags, pcnt_isr_handle_t *handle) +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); 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) -{ - const uint32_t intr_status = PCNT.int_st.val; - uint32_t status = intr_status; - while (status) { - int unit = __builtin_ffs(status) - 1; - status &= ~(1 << unit); - if (pcnt_isr_func[unit].fn != NULL) { - (pcnt_isr_func[unit].fn)(pcnt_isr_func[unit].args); - } - } - PCNT.int_clr.val = intr_status; -} - 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; + return _pcnt_isr_handler_add(PCNT_PORT_0, unit, isr_handler, args); } 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; + return _pcnt_isr_handler_remove(PCNT_PORT_0, unit); } + 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; + return _pcnt_isr_service_install(PCNT_PORT_0, intr_alloc_flags); } -void pcnt_isr_service_uninstall(void) +void pcnt_isr_service_uninstall() { - 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); -} + _pcnt_isr_service_uninstall(PCNT_PORT_0); +} \ No newline at end of file diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 83c0dbb93..933954d65 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -17,6 +17,7 @@ list(APPEND srcs "src/hal/spi_slave_hal.c" "src/hal/spi_slave_hal_iram.c" "src/soc_include_legacy_warn.c" + "src/hal/pcnt_hal.c" ) # TODO: SPI Flash HAL for ESP32S2Beta also diff --git a/components/soc/esp32/include/hal/pcnt_ll.h b/components/soc/esp32/include/hal/pcnt_ll.h new file mode 100644 index 000000000..c1a2e55cb --- /dev/null +++ b/components/soc/esp32/include/hal/pcnt_ll.h @@ -0,0 +1,301 @@ +// Copyright 2015-2019 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. + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The LL layer for ESP32 PCNT register operations + +#pragma once + +#include "soc/pcnt_periph.h" +#include "hal/pcnt_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Get PCNT hardware instance with giving pcnt num +#define PCNT_LL_GET_HW(num) (((num) == 0) ? (&PCNT) : NULL) + +/** + * @brief Set PCNT counter mode + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param channel PCNT channel number + * @param pos_mode Counter mode when detecting positive edge + * @param neg_mode Counter mode when detecting negative edge + * @param hctrl_mode Counter mode when control signal is high level + * @param lctrl_mode Counter mode when control signal is low level + */ +static inline void pcnt_ll_set_mode(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_channel_t channel, pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode, pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode) +{ + typeof(hw->conf_unit[unit].conf0) conf0_reg = hw->conf_unit[unit].conf0; + if (channel == 0) { + conf0_reg.ch0_pos_mode = pos_mode; + conf0_reg.ch0_neg_mode = neg_mode; + conf0_reg.ch0_hctrl_mode = hctrl_mode; + conf0_reg.ch0_lctrl_mode = lctrl_mode; + } else { + conf0_reg.ch1_pos_mode = pos_mode; + conf0_reg.ch1_neg_mode = neg_mode; + conf0_reg.ch1_hctrl_mode = hctrl_mode; + conf0_reg.ch1_lctrl_mode = lctrl_mode; + } + hw->conf_unit[unit].conf0 = conf0_reg; +} + +/** + * @brief Get pulse counter value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit Pulse Counter unit number + * @param count Pointer to accept counter value + */ +static inline void pcnt_ll_get_counter_value(pcnt_dev_t *hw, pcnt_unit_t unit, int16_t *count) +{ + *count = (int16_t) hw->cnt_unit[unit].cnt_val; +} + +/** + * @brief Pause PCNT counter of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_counter_pause(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->ctrl.val |= BIT(PCNT_CNT_PAUSE_U0_S + (unit * 2)); +} + +/** + * @brief Resume counting for PCNT counter + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number, select from pcnt_unit_t + */ +static inline void pcnt_ll_counter_resume(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->ctrl.val &= (~(BIT(PCNT_CNT_PAUSE_U0_S + (unit * 2)))); +} + +/** + * @brief Clear and reset PCNT counter value to zero + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number, select from pcnt_unit_t + */ +static inline void pcnt_ll_counter_clear(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + uint32_t reset_bit = BIT(PCNT_PLUS_CNT_RST_U0_S + (unit * 2)); + hw->ctrl.val |= reset_bit; + hw->ctrl.val &= ~reset_bit; +} + +/** + * @brief Enable PCNT interrupt for PCNT unit + * @note + * Each Pulse counter unit has five watch point events that share the same interrupt. + * Configure events with pcnt_event_enable() and pcnt_event_disable() + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_intr_enable(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->int_ena.val |= BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + unit); +} + +/** + * @brief Disable PCNT interrupt for PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_intr_disable(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->int_ena.val &= (~(BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + unit))); +} + +/** + * @brief Get PCNT interrupt status + * + * @param hw Peripheral PCNT hardware instance address. + * @param status Pointer to accept value + */ +static inline void pcnt_ll_get_intr_status(pcnt_dev_t *hw, uint32_t *status) +{ + *status = hw->int_st.val; +} + +/** + * @brief Clear PCNT interrupt status + * + * @param hw Peripheral PCNT hardware instance address. + * @param status value to clear interrupt status + */ +static inline void pcnt_ll_clear_intr_status(pcnt_dev_t *hw, uint32_t status) +{ + hw->int_clr.val = status; +} + +/** + * @brief Enable PCNT event of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + */ +static inline void pcnt_ll_event_enable(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type) +{ + if (evt_type == PCNT_EVT_L_LIM) { + hw->conf_unit[unit].conf0.thr_l_lim_en = 1; + } else if (evt_type == PCNT_EVT_H_LIM) { + hw->conf_unit[unit].conf0.thr_h_lim_en = 1; + } else if (evt_type == PCNT_EVT_THRES_0) { + hw->conf_unit[unit].conf0.thr_thres0_en = 1; + } else if (evt_type == PCNT_EVT_THRES_1) { + hw->conf_unit[unit].conf0.thr_thres1_en = 1; + } else if (evt_type == PCNT_EVT_ZERO) { + hw->conf_unit[unit].conf0.thr_zero_en = 1; + } +} + +/** + * @brief Disable PCNT event of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + */ +static inline void pcnt_ll_event_disable(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type) +{ + if (evt_type == PCNT_EVT_L_LIM) { + hw->conf_unit[unit].conf0.thr_l_lim_en = 0; + } else if (evt_type == PCNT_EVT_H_LIM) { + hw->conf_unit[unit].conf0.thr_h_lim_en = 0; + } else if (evt_type == PCNT_EVT_THRES_0) { + hw->conf_unit[unit].conf0.thr_thres0_en = 0; + } else if (evt_type == PCNT_EVT_THRES_1) { + hw->conf_unit[unit].conf0.thr_thres1_en = 0; + } else if (evt_type == PCNT_EVT_ZERO) { + hw->conf_unit[unit].conf0.thr_zero_en = 0; + } +} + +/** + * @brief Set PCNT event value of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + * + * @param value Counter value for PCNT event + */ +static inline void pcnt_ll_set_event_value(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value) +{ + if (evt_type == PCNT_EVT_L_LIM) { + hw->conf_unit[unit].conf2.cnt_l_lim = value; + } else if (evt_type == PCNT_EVT_H_LIM) { + hw->conf_unit[unit].conf2.cnt_h_lim = value; + } else if (evt_type == PCNT_EVT_THRES_0) { + hw->conf_unit[unit].conf1.cnt_thres0 = value; + } else if (evt_type == PCNT_EVT_THRES_1) { + hw->conf_unit[unit].conf1.cnt_thres1 = value; + } +} + +/** + * @brief Get PCNT event value of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + * @param value Pointer to accept counter value for PCNT event + */ +static inline void pcnt_ll_get_event_value(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value) +{ + if (evt_type == PCNT_EVT_L_LIM) { + *value = (int16_t) hw->conf_unit[unit].conf2.cnt_l_lim; + } else if (evt_type == PCNT_EVT_H_LIM) { + *value = (int16_t) hw->conf_unit[unit].conf2.cnt_h_lim; + } else if (evt_type == PCNT_EVT_THRES_0) { + *value = (int16_t) hw->conf_unit[unit].conf1.cnt_thres0; + } else if (evt_type == PCNT_EVT_THRES_1) { + *value = (int16_t) hw->conf_unit[unit].conf1.cnt_thres1; + } else { + *value = 0; + } +} + +/** + * @brief Set PCNT filter value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param filter_val PCNT signal filter value, counter in APB_CLK cycles. + * Any pulses lasting shorter than this will be ignored when the filter is enabled. + * @note + * filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023. + */ +static inline void pcnt_ll_set_filter_value(pcnt_dev_t *hw, pcnt_unit_t unit, uint16_t filter_val) +{ + hw->conf_unit[unit].conf0.filter_thres = filter_val; +} + +/** + * @brief Get PCNT filter value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param filter_val Pointer to accept PCNT filter value. + */ +static inline void pcnt_ll_get_filter_value(pcnt_dev_t *hw, pcnt_unit_t unit, uint16_t *filter_val) +{ + *filter_val = hw->conf_unit[unit].conf0.filter_thres; +} + +/** + * @brief Enable PCNT input filter + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_filter_enable(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->conf_unit[unit].conf0.filter_en = 1; +} + +/** + * @brief Disable PCNT input filter + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_filter_disable(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->conf_unit[unit].conf0.filter_en = 0; +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/soc/esp32/include/soc/pcnt_caps.h b/components/soc/esp32/include/soc/pcnt_caps.h new file mode 100644 index 000000000..b66dccf51 --- /dev/null +++ b/components/soc/esp32/include/soc/pcnt_caps.h @@ -0,0 +1,40 @@ +// Copyright 2015-2019 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// ESP32 have 1 PCNT peripheral +#define PCNT_PORT_0 (0) /*!< PCNT port 0 */ +#define PCNT_PORT_MAX (1) /*!< PCNT port max */ +#define SOC_PCNT_NUM (PCNT_PORT_MAX) + +#define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */ + +#define PCNT_UNIT_0 (0) /*!< PCNT unit 0 */ +#define PCNT_UNIT_1 (1) /*!< PCNT unit 1 */ +#define PCNT_UNIT_2 (2) /*!< PCNT unit 2 */ +#define PCNT_UNIT_3 (3) /*!< PCNT unit 3 */ +#define PCNT_UNIT_4 (4) /*!< PCNT unit 4 */ +#define PCNT_UNIT_5 (5) /*!< PCNT unit 5 */ +#define PCNT_UNIT_6 (6) /*!< PCNT unit 6 */ +#define PCNT_UNIT_7 (7) /*!< PCNT unit 7 */ +#define PCNT_UNIT_MAX (8) + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32s2beta/include/hal/pcnt_ll.h b/components/soc/esp32s2beta/include/hal/pcnt_ll.h new file mode 100644 index 000000000..41fad9bec --- /dev/null +++ b/components/soc/esp32s2beta/include/hal/pcnt_ll.h @@ -0,0 +1,301 @@ +// Copyright 2015-2019 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. + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The LL layer for ESP32-S2 PCNT register operations + +#pragma once + +#include "soc/pcnt_periph.h" +#include "hal/pcnt_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Get PCNT hardware instance with giving pcnt num +#define PCNT_LL_GET_HW(num) (((num) == 0) ? (&PCNT) : NULL) + +/** + * @brief Set PCNT counter mode + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param channel PCNT channel number + * @param pos_mode Counter mode when detecting positive edge + * @param neg_mode Counter mode when detecting negative edge + * @param hctrl_mode Counter mode when control signal is high level + * @param lctrl_mode Counter mode when control signal is low level + */ +static inline void pcnt_ll_set_mode(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_channel_t channel, pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode, pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode) +{ + typeof(hw->conf_unit[unit].conf0) conf0_reg = hw->conf_unit[unit].conf0; + if (channel == 0) { + conf0_reg.ch0_pos_mode = pos_mode; + conf0_reg.ch0_neg_mode = neg_mode; + conf0_reg.ch0_hctrl_mode = hctrl_mode; + conf0_reg.ch0_lctrl_mode = lctrl_mode; + } else { + conf0_reg.ch1_pos_mode = pos_mode; + conf0_reg.ch1_neg_mode = neg_mode; + conf0_reg.ch1_hctrl_mode = hctrl_mode; + conf0_reg.ch1_lctrl_mode = lctrl_mode; + } + hw->conf_unit[unit].conf0 = conf0_reg; +} + +/** + * @brief Get pulse counter value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit Pulse Counter unit number + * @param count Pointer to accept counter value + */ +static inline void pcnt_ll_get_counter_value(pcnt_dev_t *hw, pcnt_unit_t unit, int16_t *count) +{ + *count = (int16_t) hw->cnt_unit[unit].cnt_val; +} + +/** + * @brief Pause PCNT counter of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_counter_pause(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->ctrl.val |= BIT(PCNT_CNT_PAUSE_U0_S + (unit * 2)); +} + +/** + * @brief Resume counting for PCNT counter + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number, select from pcnt_unit_t + */ +static inline void pcnt_ll_counter_resume(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->ctrl.val &= (~(BIT(PCNT_CNT_PAUSE_U0_S + (unit * 2)))); +} + +/** + * @brief Clear and reset PCNT counter value to zero + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number, select from pcnt_unit_t + */ +static inline void pcnt_ll_counter_clear(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + uint32_t reset_bit = BIT(PCNT_PULSE_CNT_RST_U0_S + (unit * 2)); + hw->ctrl.val |= reset_bit; + hw->ctrl.val &= ~reset_bit; +} + +/** + * @brief Enable PCNT interrupt for PCNT unit + * @note + * Each Pulse counter unit has five watch point events that share the same interrupt. + * Configure events with pcnt_event_enable() and pcnt_event_disable() + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_intr_enable(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->int_ena.val |= BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + unit); +} + +/** + * @brief Disable PCNT interrupt for PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_intr_disable(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->int_ena.val &= (~(BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + unit))); +} + +/** + * @brief Get PCNT interrupt status + * + * @param hw Peripheral PCNT hardware instance address. + * @param status Pointer to accept value + */ +static inline void pcnt_ll_get_intr_status(pcnt_dev_t *hw, uint32_t *status) +{ + *status = hw->int_st.val; +} + +/** + * @brief Clear PCNT interrupt status + * + * @param hw Peripheral PCNT hardware instance address. + * @param status value to clear interrupt status + */ +static inline void pcnt_ll_clear_intr_status(pcnt_dev_t *hw, uint32_t status) +{ + hw->int_clr.val = status; +} + +/** + * @brief Enable PCNT event of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + */ +static inline void pcnt_ll_event_enable(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type) +{ + if (evt_type == PCNT_EVT_L_LIM) { + hw->conf_unit[unit].conf0.thr_l_lim_en = 1; + } else if (evt_type == PCNT_EVT_H_LIM) { + hw->conf_unit[unit].conf0.thr_h_lim_en = 1; + } else if (evt_type == PCNT_EVT_THRES_0) { + hw->conf_unit[unit].conf0.thr_thres0_en = 1; + } else if (evt_type == PCNT_EVT_THRES_1) { + hw->conf_unit[unit].conf0.thr_thres1_en = 1; + } else if (evt_type == PCNT_EVT_ZERO) { + hw->conf_unit[unit].conf0.thr_zero_en = 1; + } +} + +/** + * @brief Disable PCNT event of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + */ +static inline void pcnt_ll_event_disable(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type) +{ + if (evt_type == PCNT_EVT_L_LIM) { + hw->conf_unit[unit].conf0.thr_l_lim_en = 0; + } else if (evt_type == PCNT_EVT_H_LIM) { + hw->conf_unit[unit].conf0.thr_h_lim_en = 0; + } else if (evt_type == PCNT_EVT_THRES_0) { + hw->conf_unit[unit].conf0.thr_thres0_en = 0; + } else if (evt_type == PCNT_EVT_THRES_1) { + hw->conf_unit[unit].conf0.thr_thres1_en = 0; + } else if (evt_type == PCNT_EVT_ZERO) { + hw->conf_unit[unit].conf0.thr_zero_en = 0; + } +} + +/** + * @brief Set PCNT event value of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + * + * @param value Counter value for PCNT event + */ +static inline void pcnt_ll_set_event_value(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value) +{ + if (evt_type == PCNT_EVT_L_LIM) { + hw->conf_unit[unit].conf2.cnt_l_lim = value; + } else if (evt_type == PCNT_EVT_H_LIM) { + hw->conf_unit[unit].conf2.cnt_h_lim = value; + } else if (evt_type == PCNT_EVT_THRES_0) { + hw->conf_unit[unit].conf1.cnt_thres0 = value; + } else if (evt_type == PCNT_EVT_THRES_1) { + hw->conf_unit[unit].conf1.cnt_thres1 = value; + } +} + +/** + * @brief Get PCNT event value of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + * @param value Pointer to accept counter value for PCNT event + */ +static inline void pcnt_ll_get_event_value(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value) +{ + if (evt_type == PCNT_EVT_L_LIM) { + *value = (int16_t) hw->conf_unit[unit].conf2.cnt_l_lim; + } else if (evt_type == PCNT_EVT_H_LIM) { + *value = (int16_t) hw->conf_unit[unit].conf2.cnt_h_lim; + } else if (evt_type == PCNT_EVT_THRES_0) { + *value = (int16_t) hw->conf_unit[unit].conf1.cnt_thres0; + } else if (evt_type == PCNT_EVT_THRES_1) { + *value = (int16_t) hw->conf_unit[unit].conf1.cnt_thres1; + } else { + *value = 0; + } +} + +/** + * @brief Set PCNT filter value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param filter_val PCNT signal filter value, counter in APB_CLK cycles. + * Any pulses lasting shorter than this will be ignored when the filter is enabled. + * @note + * filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023. + */ +static inline void pcnt_ll_set_filter_value(pcnt_dev_t *hw, pcnt_unit_t unit, uint16_t filter_val) +{ + hw->conf_unit[unit].conf0.filter_thres = filter_val; +} + +/** + * @brief Get PCNT filter value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param filter_val Pointer to accept PCNT filter value. + */ +static inline void pcnt_ll_get_filter_value(pcnt_dev_t *hw, pcnt_unit_t unit, uint16_t *filter_val) +{ + *filter_val = hw->conf_unit[unit].conf0.filter_thres; +} + +/** + * @brief Enable PCNT input filter + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_filter_enable(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->conf_unit[unit].conf0.filter_en = 1; +} + +/** + * @brief Disable PCNT input filter + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +static inline void pcnt_ll_filter_disable(pcnt_dev_t *hw, pcnt_unit_t unit) +{ + hw->conf_unit[unit].conf0.filter_en = 0; +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/soc/esp32s2beta/include/soc/pcnt_caps.h b/components/soc/esp32s2beta/include/soc/pcnt_caps.h new file mode 100644 index 000000000..6659a61ae --- /dev/null +++ b/components/soc/esp32s2beta/include/soc/pcnt_caps.h @@ -0,0 +1,37 @@ +// Copyright 2015-2019 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// ESP32-S2 have 1 PCNT peripheral +#define PCNT_PORT_0 (0) /*!< PCNT port 0 */ +#define PCNT_PORT_MAX (1) /*!< PCNT port max */ +#define SOC_PCNT_NUM (PCNT_PORT_MAX) + +#define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */ + +// ESP32-S2 only have 4 unit +#define PCNT_UNIT_0 (0) /*!< PCNT unit 0 */ +#define PCNT_UNIT_1 (1) /*!< PCNT unit 1 */ +#define PCNT_UNIT_2 (2) /*!< PCNT unit 2 */ +#define PCNT_UNIT_3 (3) /*!< PCNT unit 3 */ +#define PCNT_UNIT_MAX (4) + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/include/hal/pcnt_hal.h b/components/soc/include/hal/pcnt_hal.h new file mode 100644 index 000000000..2a14a0ae7 --- /dev/null +++ b/components/soc/include/hal/pcnt_hal.h @@ -0,0 +1,214 @@ +// Copyright 2015-2019 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. + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The HAL layer for PCNT. +// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters. + +#pragma once + +#include +#include "soc/pcnt_periph.h" +#include "hal/pcnt_types.h" +#include "hal/pcnt_ll.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Context that should be maintained by both the driver and the HAL + */ + +typedef struct { + pcnt_dev_t *dev; +} pcnt_hal_context_t; + +/** + * @brief Set PCNT counter mode + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + * @param channel PCNT channel number + * @param pos_mode Counter mode when detecting positive edge + * @param neg_mode Counter mode when detecting negative edge + * @param hctrl_mode Counter mode when control signal is high level + * @param lctrl_mode Counter mode when control signal is low level + */ +#define pcnt_hal_set_mode(hal, unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode) pcnt_ll_set_mode((hal)->dev, unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode) + +/** + * @brief Get pulse counter value + * + * @param hal Context of the HAL layer + * @param unit Pulse Counter unit number + * @param count Pointer to accept counter value + */ +#define pcnt_hal_get_counter_value(hal, unit, count) pcnt_ll_get_counter_value((hal)->dev, unit, count) + +/** + * @brief Pause PCNT counter of PCNT unit + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + */ +#define pcnt_hal_counter_pause(hal, unit) pcnt_ll_counter_pause((hal)->dev, unit) + +/** + * @brief Resume counting for PCNT counter + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number, select from unit_t + */ +#define pcnt_hal_counter_resume(hal, unit) pcnt_ll_counter_resume((hal)->dev, unit) + +/** + * @brief Clear and reset PCNT counter value to zero + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number, select from unit_t + */ +#define pcnt_hal_counter_clear(hal, unit) pcnt_ll_counter_clear((hal)->dev, unit) + +/** + * @brief Enable PCNT interrupt for PCNT unit + * @note + * Each Pulse counter unit has five watch point events that share the same interrupt. + * Configure events with pcnt_event_enable() and pcnt_event_disable() + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + */ +#define pcnt_hal_intr_enable(hal, unit) pcnt_ll_intr_enable((hal)->dev, unit) + +/** + * @brief Disable PCNT interrupt for PCNT unit + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + */ +#define pcnt_hal_intr_disable(hal, unit) pcnt_ll_intr_disable((hal)->dev, unit) + +/** + * @brief Get PCNT interrupt status + * + * @param hal Context of the HAL layer + * @param mask The interrupt status mask to be cleared. Pointer to accept value interrupt status mask. + */ +#define pcnt_hal_get_intr_status(hal, mask) pcnt_ll_get_intr_status((hal)->dev, mask) + +/** + * @brief Clear PCNT interrupt status + * + * @param hal Context of the HAL layer + * @param mask The interrupt status mask to be cleared. + */ +#define pcnt_hal_clear_intr_status(hal, mask) pcnt_ll_clear_intr_status((hal)->dev, mask) + +/** + * @brief Enable PCNT event of PCNT unit + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + */ +#define pcnt_hal_event_enable(hal, unit, evt_type) pcnt_ll_event_enable((hal)->dev, unit, evt_type) + +/** + * @brief Disable PCNT event of PCNT unit + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + */ +#define pcnt_hal_event_disable(hal, unit, evt_type) pcnt_ll_event_disable((hal)->dev, unit, evt_type) + +/** + * @brief Set PCNT event value of PCNT unit + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + * + * @param value Counter value for PCNT event + */ +#define pcnt_hal_set_event_value(hal, unit, evt_type, value) pcnt_ll_set_event_value((hal)->dev, unit, evt_type, value) + +/** + * @brief Get PCNT event value of PCNT unit + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + * @param evt_type Watch point event type. + * All enabled events share the same interrupt (one interrupt per pulse counter unit). + * @param value Pointer to accept counter value for PCNT event + */ +#define pcnt_hal_get_event_value(hal, unit, evt_type, value) pcnt_ll_get_event_value((hal)->dev, unit, evt_type, value) + +/** + * @brief Set PCNT filter value + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + * @param filter_val PCNT signal filter value, counter in APB_CLK cycles. + * Any pulses lasting shorter than this will be ignored when the filter is enabled. + * @note + * filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023. + */ +#define pcnt_hal_set_filter_value(hal, unit, filter_val) pcnt_ll_set_filter_value((hal)->dev, unit, filter_val) + +/** + * @brief Get PCNT filter value + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + * @param filter_val Pointer to accept PCNT filter value. + */ +#define pcnt_hal_get_filter_value(hal, unit, filter_val) pcnt_ll_get_filter_value((hal)->dev, unit, filter_val) + +/** + * @brief Enable PCNT input filter + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + */ +#define pcnt_hal_filter_enable(hal, unit) pcnt_ll_filter_enable((hal)->dev, unit) + +/** + * @brief Disable PCNT input filter + * + * @param hal Context of the HAL layer + * @param unit PCNT unit number + */ +#define pcnt_hal_filter_disable(hal, unit) pcnt_ll_filter_disable((hal)->dev, unit) + +/** + * @brief Init the PCNT hal and set the PCNT to the default configuration. This function should be called first before other hal layer function is called + * + * @param hal Context of the HAL layer + * @param pcnt_num The uart port number, the max port number is (PCNT_NUM_MAX -1) + */ +void pcnt_hal_init(pcnt_hal_context_t *hal, int pcnt_num); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/soc/include/hal/pcnt_types.h b/components/soc/include/hal/pcnt_types.h new file mode 100644 index 000000000..3d065d6ff --- /dev/null +++ b/components/soc/include/hal/pcnt_types.h @@ -0,0 +1,92 @@ +// Copyright 2015-2019 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief PCNT port number, the max port number is (PCNT_PORT_MAX - 1). + */ +typedef int pcnt_port_t; + +/** + * @brief Selection of all available PCNT units + */ +typedef int pcnt_unit_t; + +/** + * @brief Selection of available modes that determine the counter's action depending on the state of the control signal's input GPIO + * @note Configuration covers two actions, one for high, and one for low level on the control input + */ +typedef enum { + PCNT_MODE_KEEP = 0, /*!< Control mode: won't change counter mode*/ + PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase) */ + PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition) */ + PCNT_MODE_MAX +} pcnt_ctrl_mode_t; + +/** + * @brief Selection of available modes that determine the counter's action on the edge of the pulse signal's input GPIO + * @note Configuration covers two actions, one for positive, and one for negative edge on the pulse input + */ +typedef enum { + PCNT_COUNT_DIS = 0, /*!< Counter mode: Inhibit counter(counter value will not change in this condition) */ + PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value */ + PCNT_COUNT_DEC = 2, /*!< Counter mode: Decrease counter value */ + PCNT_COUNT_MAX +} pcnt_count_mode_t; + +/** + * @brief Selection of channels available for a single PCNT unit + */ +typedef enum { + PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel 0 */ + PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel 1 */ + PCNT_CHANNEL_MAX, +} pcnt_channel_t; + +/** + * @brief Selection of counter's events the may trigger an interrupt + */ +typedef enum { + PCNT_EVT_THRES_1 = BIT(2), /*!< PCNT watch point event: threshold1 value event */ + PCNT_EVT_THRES_0 = BIT(3), /*!< PCNT watch point event: threshold0 value event */ + PCNT_EVT_L_LIM = BIT(4), /*!< PCNT watch point event: Minimum counter value */ + PCNT_EVT_H_LIM = BIT(5), /*!< PCNT watch point event: Maximum counter value */ + PCNT_EVT_ZERO = BIT(6), /*!< PCNT watch point event: counter value zero event */ + PCNT_EVT_MAX +} pcnt_evt_type_t; + +/** + * @brief Pulse Counter configuration for a single channel + */ +typedef struct { + int pulse_gpio_num; /*!< Pulse input GPIO number, if you want to use GPIO16, enter pulse_gpio_num = 16, a negative value will be ignored */ + int ctrl_gpio_num; /*!< Control signal input GPIO number, a negative value will be ignored */ + pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode */ + pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode */ + pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode */ + pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode */ + int16_t counter_h_lim; /*!< Maximum counter value */ + int16_t counter_l_lim; /*!< Minimum counter value */ + pcnt_unit_t unit; /*!< PCNT unit number */ + pcnt_channel_t channel; /*!< the PCNT channel */ +} pcnt_config_t; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/soc/src/hal/pcnt_hal.c b/components/soc/src/hal/pcnt_hal.c new file mode 100644 index 000000000..f703f70af --- /dev/null +++ b/components/soc/src/hal/pcnt_hal.c @@ -0,0 +1,23 @@ +// Copyright 2015-2019 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. + +// The HAL layer for PCNT (common part) + +#include "hal/pcnt_hal.h" + +void pcnt_hal_init(pcnt_hal_context_t *hal, int pcnt_num) +{ + //Get hardware instance. + hal->dev = PCNT_LL_GET_HW(pcnt_num); +} diff --git a/docs/Doxyfile b/docs/Doxyfile index af1a5b342..523c03c9d 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -104,6 +104,7 @@ INPUT = \ ../../components/driver/include/driver/uart.h \ ../../components/esp_adc_cal/include/esp_adc_cal.h \ ../../components/soc/include/hal/spi_types.h \ + ../../components/soc/include/hal/pcnt_types.h \ ../../components/soc/esp32/include/soc/adc_channel.h \ ../../components/soc/esp32/include/soc/dac_channel.h \ ../../components/soc/esp32/include/soc/touch_channel.h \