remove(legacy_pcnt): remove legacy pcnt driver in IDF v6.0

This commit is contained in:
Chen Jichang
2025-06-09 19:01:30 +08:00
parent ae3f20fa9f
commit d345ac1a50
18 changed files with 26 additions and 1837 deletions

View File

@ -41,11 +41,6 @@ if(CONFIG_SOC_MCPWM_SUPPORTED)
list(APPEND srcs "deprecated/mcpwm_legacy.c")
endif()
# PCNT legacy driver
if(CONFIG_SOC_PCNT_SUPPORTED)
list(APPEND srcs "deprecated/pcnt_legacy.c")
endif()
# RMT legacy driver
if(CONFIG_SOC_RMT_SUPPORTED)
list(APPEND srcs "deprecated/rmt_legacy.c")

View File

@ -1,366 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "driver/pcnt_types_legacy.h"
#if !CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN
#warning "legacy pcnt driver is deprecated, please migrate to use driver/pulse_cnt.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Configure Pulse Counter unit
* @note
* This function will disable three events: PCNT_EVT_L_LIM, PCNT_EVT_H_LIM, PCNT_EVT_ZERO.
*
* @param pcnt_config Pointer of Pulse Counter unit configure parameter
*
* @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);
/**
* @brief Get pulse counter value
*
* @param pcnt_unit Pulse Counter unit number
* @param count Pointer to accept counter value
*
* @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);
/**
* @brief Pause PCNT counter of PCNT unit
*
* @param pcnt_unit PCNT unit number
*
* @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);
/**
* @brief Resume counting for PCNT counter
*
* @param pcnt_unit PCNT unit number, select from pcnt_unit_t
*
* @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);
/**
* @brief Clear and reset PCNT counter value to zero
*
* @param pcnt_unit PCNT unit number, select from pcnt_unit_t
*
* @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);
/**
* @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 pcnt_unit PCNT unit number
*
* @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);
/**
* @brief Disable PCNT interrupt for PCNT unit
*
* @param pcnt_unit PCNT unit number
*
* @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);
/**
* @brief Enable PCNT event of PCNT unit
*
* @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).
* @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);
/**
* @brief Disable PCNT event of PCNT unit
*
* @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).
* @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);
/**
* @brief Set PCNT event value of PCNT unit
*
* @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
*
* @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);
/**
* @brief Get PCNT event value of PCNT unit
*
* @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
*
* @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);
/**
* @brief Get PCNT event status of PCNT unit
*
* @param unit PCNT unit number
* @param status Pointer to accept event status word
* @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_status(pcnt_unit_t unit, uint32_t *status);
/**
* @brief Unregister PCNT interrupt handler (registered by pcnt_isr_register), the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
* If the interrupt service is registered by pcnt_isr_service_install, please call pcnt_isr_service_uninstall instead
*
* @param handle handle to unregister the ISR service.
*
* @return
* - ESP_OK Success
* - 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_unregister(pcnt_isr_handle_t handle);
/**
* @brief Register PCNT interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
* Please do not use pcnt_isr_service_install if this function was called.
*
* @param fn Interrupt handler function.
* @param arg Parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here. Calling pcnt_isr_unregister to unregister this ISR service if needed,
* but only if the handle is not NULL.
*
* @return
* - ESP_OK Success
* - 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);
/**
* @brief Configure PCNT pulse signal input pin and control input pin
*
* @param unit PCNT unit number
* @param channel PCNT channel number
* @param pulse_io Pulse signal input GPIO
* @param ctrl_io Control signal input GPIO
*
* @note Set the signal input to PCNT_PIN_NOT_USED if unused.
*
* @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);
/**
* @brief Enable PCNT input filter
*
* @param unit PCNT unit number
*
* @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);
/**
* @brief Disable PCNT input filter
*
* @param unit PCNT unit number
*
* @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);
/**
* @brief Set PCNT filter value
*
* @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.
*
* @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);
/**
* @brief Get PCNT filter value
*
* @param unit PCNT unit number
* @param filter_val Pointer to accept PCNT filter value.
*
* @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);
/**
* @brief Set PCNT counter mode
*
* @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
*
* @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,
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_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);
/**
* @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.
*
* @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
*/
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_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit);
#ifdef __cplusplus
}
#endif

View File

@ -1,108 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_intr_alloc.h"
#include "soc/soc_caps.h"
#include "hal/pcnt_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */
/**
* @brief PCNT interrupt handle
*/
typedef intr_handle_t pcnt_isr_handle_t;
/**
* @brief PCNT port number, the max port number is (PCNT_PORT_MAX - 1).
*/
typedef enum {
PCNT_PORT_0, /*!< PCNT port 0 */
PCNT_PORT_MAX, /*!< PCNT port max */
} pcnt_port_t;
/**
* @brief Selection of all available PCNT units
*/
typedef enum {
PCNT_UNIT_0, /*!< PCNT unit 0 */
PCNT_UNIT_1, /*!< PCNT unit 1 */
PCNT_UNIT_2, /*!< PCNT unit 2 */
PCNT_UNIT_3, /*!< PCNT unit 3 */
#if SOC_PCNT_UNITS_PER_GROUP > 4
PCNT_UNIT_4, /*!< PCNT unit 4 */
PCNT_UNIT_5, /*!< PCNT unit 5 */
PCNT_UNIT_6, /*!< PCNT unit 6 */
PCNT_UNIT_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, /*!< PCNT channel 0 */
PCNT_CHANNEL_1, /*!< 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 = 1 << 2, /*!< PCNT watch point event: threshold1 value event */
PCNT_EVT_THRES_0 = 1 << 3, /*!< PCNT watch point event: threshold0 value event */
PCNT_EVT_L_LIM = 1 << 4, /*!< PCNT watch point event: Minimum counter value */
PCNT_EVT_H_LIM = 1 << 5, /*!< PCNT watch point event: Maximum counter value */
PCNT_EVT_ZERO = 1 << 6, /*!< PCNT watch point event: counter value zero event */
PCNT_EVT_MAX
} pcnt_evt_type_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 pcnt_channel_level_action_t pcnt_ctrl_mode_t;
#define PCNT_MODE_KEEP PCNT_CHANNEL_LEVEL_ACTION_KEEP /*!< Control mode: won't change counter mode*/
#define PCNT_MODE_REVERSE PCNT_CHANNEL_LEVEL_ACTION_INVERSE /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase) */
#define PCNT_MODE_DISABLE PCNT_CHANNEL_LEVEL_ACTION_HOLD /*!< Control mode: Inhibit counter(counter value will not change in this condition) */
#define PCNT_MODE_MAX 3
/**
* @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 pcnt_channel_edge_action_t pcnt_count_mode_t;
#define PCNT_COUNT_DIS PCNT_CHANNEL_EDGE_ACTION_HOLD /*!< Counter mode: Inhibit counter(counter value will not change in this condition) */
#define PCNT_COUNT_INC PCNT_CHANNEL_EDGE_ACTION_INCREASE /*!< Counter mode: Increase counter value */
#define PCNT_COUNT_DEC PCNT_CHANNEL_EDGE_ACTION_DECREASE /*!< Counter mode: Decrease counter value */
#define PCNT_COUNT_MAX 3
/**
* @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

View File

@ -1,574 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "freertos/FreeRTOS.h"
#include "esp_log.h"
#include "esp_check.h"
#include "soc/soc_caps.h"
#include "esp_private/periph_ctrl.h"
#include "driver/pcnt_types_legacy.h"
#include "driver/gpio.h"
#include "hal/pcnt_hal.h"
#include "hal/pcnt_ll.h"
#include "hal/gpio_hal.h"
#include "soc/pcnt_periph.h"
#include "esp_rom_gpio.h"
#include "esp_private/gpio.h"
#define PCNT_CHANNEL_ERR_STR "PCNT CHANNEL ERROR"
#define PCNT_UNIT_ERR_STR "PCNT UNIT ERROR"
#define PCNT_GPIO_ERR_STR "PCNT GPIO NUM ERROR"
#define PCNT_ADDRESS_ERR_STR "PCNT ADDRESS ERROR"
#define PCNT_PARAM_ERR_STR "PCNT PARAM ERROR"
#define PCNT_COUNT_MODE_ERR_STR "PCNT COUNTER MODE ERROR"
#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)
#if !SOC_RCC_IS_INDEPENDENT
#define PCNT_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define PCNT_RCC_ATOMIC()
#endif
static const char *TAG = "pcnt(legacy)";
#define PCNT_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE(a, ret_val, TAG, "%s", str)
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 */
} 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;
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_unregister(pcnt_isr_handle_t handle);
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 < SOC_PCNT_UNITS_PER_GROUP, 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_ll_set_edge_action(p_pcnt_obj[pcnt_port]->hal.dev, unit, channel, pos_mode, neg_mode);
pcnt_ll_set_level_action(p_pcnt_obj[pcnt_port]->hal.dev, unit, channel, 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 < SOC_PCNT_UNITS_PER_GROUP, 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);
if (pulse_io >= 0) {
gpio_func_sel(pulse_io, PIN_FUNC_GPIO);
gpio_set_direction(pulse_io, GPIO_MODE_INPUT);
gpio_set_pull_mode(pulse_io, GPIO_PULLUP_ONLY);
esp_rom_gpio_connect_in_signal(pulse_io, pcnt_periph_signals.groups[pcnt_port].units[unit].channels[channel].pulse_sig, 0);
}
if (ctrl_io >= 0) {
gpio_func_sel(ctrl_io, PIN_FUNC_GPIO);
gpio_set_direction(ctrl_io, GPIO_MODE_INPUT);
gpio_set_pull_mode(ctrl_io, GPIO_PULLUP_ONLY);
esp_rom_gpio_connect_in_signal(ctrl_io, pcnt_periph_signals.groups[pcnt_port].units[unit].channels[channel].control_sig, 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 < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(count != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
*count = pcnt_ll_get_count(p_pcnt_obj[pcnt_port]->hal.dev, pcnt_unit);
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 < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
pcnt_ll_stop_count(p_pcnt_obj[pcnt_port]->hal.dev, 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 < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
pcnt_ll_start_count(p_pcnt_obj[pcnt_port]->hal.dev, 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 < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
pcnt_ll_clear_count(p_pcnt_obj[pcnt_port]->hal.dev, 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, bool enable)
{
PCNT_OBJ_CHECK(pcnt_port);
PCNT_CHECK(pcnt_unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
pcnt_ll_enable_intr(p_pcnt_obj[pcnt_port]->hal.dev, 1 << pcnt_unit, enable);
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, bool enable)
{
PCNT_OBJ_CHECK(pcnt_port);
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
switch (evt_type) {
case PCNT_EVT_THRES_1:
pcnt_ll_enable_thres_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, 1, enable);
break;
case PCNT_EVT_THRES_0:
pcnt_ll_enable_thres_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, 0, enable);
break;
case PCNT_EVT_L_LIM:
pcnt_ll_enable_low_limit_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, enable);
break;
case PCNT_EVT_H_LIM:
pcnt_ll_enable_high_limit_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, enable);
break;
case PCNT_EVT_ZERO:
pcnt_ll_enable_zero_cross_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, enable);
break;
default:
PCNT_CHECK(false, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
break;
}
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 < SOC_PCNT_UNITS_PER_GROUP, 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);
switch (evt_type) {
case PCNT_EVT_THRES_1:
pcnt_ll_set_thres_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, 1, value);
break;
case PCNT_EVT_THRES_0:
pcnt_ll_set_thres_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, 0, value);
break;
case PCNT_EVT_L_LIM:
pcnt_ll_set_low_limit_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, value);
break;
case PCNT_EVT_H_LIM:
pcnt_ll_set_high_limit_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, value);
break;
default:
break;
}
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 < SOC_PCNT_UNITS_PER_GROUP, 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);
switch (evt_type) {
case PCNT_EVT_THRES_1:
*value = pcnt_ll_get_thres_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, 1);
break;
case PCNT_EVT_THRES_0:
*value = pcnt_ll_get_thres_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, 0);
break;
case PCNT_EVT_L_LIM:
*value = pcnt_ll_get_low_limit_value(p_pcnt_obj[pcnt_port]->hal.dev, unit);
break;
case PCNT_EVT_H_LIM:
*value = pcnt_ll_get_high_limit_value(p_pcnt_obj[pcnt_port]->hal.dev, unit);
break;
default:
break;
}
return ESP_OK;
}
static inline esp_err_t _pcnt_get_event_status(pcnt_port_t pcnt_port, pcnt_unit_t unit, uint32_t *status)
{
PCNT_OBJ_CHECK(pcnt_port);
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(status != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
*status = pcnt_ll_get_unit_status(p_pcnt_obj[pcnt_port]->hal.dev, unit);
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 < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(filter_val < 1024, PCNT_PARAM_ERR_STR, ESP_ERR_INVALID_ARG);
pcnt_ll_set_glitch_filter_thres(p_pcnt_obj[pcnt_port]->hal.dev, 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 < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(filter_val != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
*filter_val = (uint16_t)pcnt_ll_get_glitch_filter_thres(p_pcnt_obj[pcnt_port]->hal.dev, unit);
return ESP_OK;
}
static inline esp_err_t _pcnt_filter_enable(pcnt_port_t pcnt_port, pcnt_unit_t unit, bool enable)
{
PCNT_OBJ_CHECK(pcnt_port);
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
pcnt_ll_enable_glitch_filter(p_pcnt_obj[pcnt_port]->hal.dev, unit, enable);
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 < SOC_PCNT_UNITS_PER_GROUP, "PCNT unit error", ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
_pcnt_intr_enable(PCNT_PORT_0, unit, false);
if (pcnt_isr_func) {
pcnt_isr_func[unit].fn = isr_handler;
pcnt_isr_func[unit].args = args;
}
_pcnt_intr_enable(PCNT_PORT_0, unit, true);
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 < SOC_PCNT_UNITS_PER_GROUP, "PCNT unit error", ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
_pcnt_intr_enable(PCNT_PORT_0, unit, false);
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 = 0;
pcnt_port_t pcnt_port = (pcnt_port_t)arg;
status = pcnt_ll_get_intr_status(p_pcnt_obj[pcnt_port]->hal.dev);
pcnt_ll_clear_intr_status(p_pcnt_obj[pcnt_port]->hal.dev, 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);
}
}
}
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);
esp_err_t ret = ESP_FAIL;
pcnt_isr_func = (pcnt_isr_func_t *) calloc(SOC_PCNT_UNITS_PER_GROUP, 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);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "pcnt isr registration failed, maybe you need `pcnt_isr_unregister` to unregister your isr");
free(pcnt_isr_func);
pcnt_isr_func = NULL;
}
}
return ret;
}
static inline esp_err_t _pcnt_isr_service_uninstall(pcnt_port_t pcnt_port)
{
PCNT_OBJ_CHECK(pcnt_port);
PCNT_CHECK(pcnt_isr_func != NULL, "ISR Service not installed yet.", ESP_ERR_INVALID_STATE);
esp_err_t ret = ESP_FAIL;
ret = pcnt_isr_unregister(pcnt_isr_service);
free(pcnt_isr_func);
pcnt_isr_func = NULL;
pcnt_isr_service = NULL;
return ret;
}
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;
int ctrl_io = pcnt_config->ctrl_gpio_num;
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(input_io < 0 || (GPIO_IS_VALID_GPIO(input_io) && (input_io != ctrl_io)), "PCNT pulse input io error", ESP_ERR_INVALID_ARG);
PCNT_CHECK(ctrl_io < 0 || GPIO_IS_VALID_GPIO(ctrl_io), "PCNT ctrl io error", ESP_ERR_INVALID_ARG);
PCNT_CHECK((pcnt_config->pos_mode < PCNT_COUNT_MAX) && (pcnt_config->neg_mode < PCNT_COUNT_MAX), PCNT_COUNT_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK((pcnt_config->hctrl_mode < PCNT_MODE_MAX) && (pcnt_config->lctrl_mode < PCNT_MODE_MAX), PCNT_CTRL_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
/*Enable hardware module*/
static bool pcnt_enable = false;
if (pcnt_enable == false) {
PCNT_RCC_ATOMIC() {
pcnt_ll_reset_register(pcnt_port);
pcnt_ll_enable_bus_clock(pcnt_port, true);
}
pcnt_enable = true;
}
/*Set counter range*/
_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_enable(pcnt_port, unit, PCNT_EVT_H_LIM, false);
_pcnt_event_enable(pcnt_port, unit, PCNT_EVT_L_LIM, false);
_pcnt_event_enable(pcnt_port, unit, PCNT_EVT_ZERO, false);
_pcnt_filter_enable(pcnt_port, unit, false);
/*set pulse input and control 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(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;
}
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)
{
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)
{
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)
{
return _pcnt_get_counter_value(PCNT_PORT_0, pcnt_unit, count);
}
esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit)
{
return _pcnt_counter_pause(PCNT_PORT_0, pcnt_unit);
}
esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit)
{
return _pcnt_counter_resume(PCNT_PORT_0, pcnt_unit);
}
esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit)
{
return _pcnt_counter_clear(PCNT_PORT_0, pcnt_unit);
}
esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit)
{
return _pcnt_intr_enable(PCNT_PORT_0, pcnt_unit, true);
}
esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit)
{
return _pcnt_intr_enable(PCNT_PORT_0, pcnt_unit, false);
}
esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)
{
return _pcnt_event_enable(PCNT_PORT_0, unit, evt_type, true);
}
esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)
{
return _pcnt_event_enable(PCNT_PORT_0, unit, evt_type, false);
}
esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value)
{
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)
{
return _pcnt_get_event_value(PCNT_PORT_0, unit, evt_type, value);
}
esp_err_t pcnt_get_event_status(pcnt_unit_t unit, uint32_t *status)
{
return _pcnt_get_event_status(PCNT_PORT_0, unit, status);
}
esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val)
{
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)
{
return _pcnt_get_filter_value(PCNT_PORT_0, unit, filter_val);
}
esp_err_t pcnt_filter_enable(pcnt_unit_t unit)
{
return _pcnt_filter_enable(PCNT_PORT_0, unit, true);
}
esp_err_t pcnt_filter_disable(pcnt_unit_t unit)
{
return _pcnt_filter_enable(PCNT_PORT_0, unit, false);
}
esp_err_t pcnt_isr_unregister(pcnt_isr_handle_t handle)
{
esp_err_t ret = ESP_FAIL;
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
ret = esp_intr_free(handle);
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
return ret;
}
esp_err_t pcnt_isr_register(void (*fun)(void *), void *arg, int intr_alloc_flags, pcnt_isr_handle_t *handle)
{
esp_err_t ret = ESP_FAIL;
PCNT_CHECK(fun != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
ret = esp_intr_alloc(pcnt_periph_signals.groups[0].irq, intr_alloc_flags, fun, arg, handle);
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
return ret;
}
esp_err_t pcnt_isr_handler_add(pcnt_unit_t unit, void(*isr_handler)(void *), void *args)
{
return _pcnt_isr_handler_add(PCNT_PORT_0, unit, isr_handler, args);
}
esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit)
{
return _pcnt_isr_handler_remove(PCNT_PORT_0, unit);
}
esp_err_t pcnt_isr_service_install(int intr_alloc_flags)
{
return _pcnt_isr_service_install(PCNT_PORT_0, intr_alloc_flags);
}
void pcnt_isr_service_uninstall(void)
{
_pcnt_isr_service_uninstall(PCNT_PORT_0);
}
#if !CONFIG_PCNT_SKIP_LEGACY_CONFLICT_CHECK
/**
* @brief This function will be called during start up, to check that pulse_cnt driver is not running along with the legacy pcnt driver
*/
__attribute__((constructor))
static void check_pcnt_driver_conflict(void)
{
// This function was declared as weak here. pulse_cnt driver has one implementation.
// So if pulse_cnt driver is not linked in, then `pcnt_new_unit` should be NULL at runtime.
extern __attribute__((weak)) esp_err_t pcnt_new_unit(const void *config, void **ret_unit);
if ((void *)pcnt_new_unit != NULL) {
ESP_EARLY_LOGE(TAG, "CONFLICT! driver_ng is not allowed to be used with the legacy driver");
abort();
}
ESP_EARLY_LOGW(TAG, "legacy driver is deprecated, please migrate to `driver/pulse_cnt.h`");
}
#endif //CONFIG_PCNT_SKIP_LEGACY_CONFLICT_CHECK

View File

@ -34,12 +34,6 @@ components/driver/test_apps/legacy_mcpwm_driver:
depends_filepatterns:
- components/driver/deprecated/**/*mcpwm*
components/driver/test_apps/legacy_pcnt_driver:
disable:
- if: SOC_PCNT_SUPPORTED != 1
depends_filepatterns:
- components/driver/deprecated/**/*pcnt*
components/driver/test_apps/legacy_rmt_driver:
disable:
- if: SOC_RMT_SUPPORTED != 1

View File

@ -1,8 +0,0 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(legacy_pcnt_driver_test)

View File

@ -1,2 +0,0 @@
| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |

View File

@ -1,8 +0,0 @@
set(srcs "test_app_main.c"
"test_legacy_pcnt.c")
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES unity driver
WHOLE_ARCHIVE)

View File

@ -1,45 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
#ifndef CONFIG_FREERTOS_SMP
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
#else
// TODO: IDF-5290
#define TEST_MEMORY_LEAK_THRESHOLD (-400)
#endif // CONFIG_FREERTOS_SMP
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
unity_run_menu();
}

View File

@ -1,682 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "driver/gpio.h"
#include "driver/pcnt.h"
#if SOC_LEDC_SUPPORTED
#include "driver/ledc.h"
#include "soc/ledc_periph.h"
#endif
#include "esp_attr.h"
#include "esp_log.h"
#include "soc/gpio_periph.h"
#include "soc/pcnt_struct.h"
#include "soc/pcnt_periph.h"
#include "unity.h"
#include "esp_rom_gpio.h"
#if CONFIG_IDF_TARGET_ESP32P4
#define PULSE_IO 20
#define PCNT_INPUT_IO 21
#define PCNT_CTRL_VCC_IO 1
#define PCNT_CTRL_GND_IO 0
#else
#define PULSE_IO 0
#define PCNT_INPUT_IO 4
#define PCNT_CTRL_VCC_IO 5
#define PCNT_CTRL_GND_IO 2
#endif
#define PCNT_CTRL_HIGH_LEVEL 1
#define PCNT_CTRL_LOW_LEVEL 0
// test PCNT basic configuration
TEST_CASE("PCNT_test_config", "[pcnt]")
{
pcnt_config_t pcnt_config = {
.pulse_gpio_num = PCNT_INPUT_IO,
.ctrl_gpio_num = PCNT_CTRL_VCC_IO,
.channel = PCNT_CHANNEL_0,
.unit = PCNT_UNIT_0,
.pos_mode = PCNT_COUNT_INC,
.neg_mode = PCNT_COUNT_DIS,
.lctrl_mode = PCNT_MODE_REVERSE,
.hctrl_mode = PCNT_MODE_KEEP,
.counter_h_lim = 100,
.counter_l_lim = 0,
};
// basic configuration
pcnt_config_t temp_pcnt_config = pcnt_config;
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
// test SOC_PCNT_UNITS_PER_GROUP units, from 0-(SOC_PCNT_UNITS_PER_GROUP-1)
pcnt_config = temp_pcnt_config;
pcnt_config.unit = SOC_PCNT_UNITS_PER_GROUP;
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
pcnt_config.unit = i;
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
}
// test channels
pcnt_config = temp_pcnt_config;
pcnt_config.channel = PCNT_CHANNEL_MAX;
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
pcnt_config = temp_pcnt_config;
pcnt_config.pulse_gpio_num = -1;
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
pcnt_config = temp_pcnt_config;
pcnt_config.pulse_gpio_num = GPIO_NUM_MAX + 1;
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
// test pulse_gpio_num and ctrl_gpio_num is the same
pcnt_config = temp_pcnt_config;
pcnt_config.pulse_gpio_num = PCNT_INPUT_IO;
pcnt_config.ctrl_gpio_num = PCNT_INPUT_IO;
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
pcnt_config = temp_pcnt_config;
pcnt_config.pos_mode = PCNT_COUNT_MAX;
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
pcnt_config = temp_pcnt_config;
pcnt_config.hctrl_mode = PCNT_MODE_MAX;
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
pcnt_config = temp_pcnt_config;
pcnt_config.lctrl_mode = PCNT_MODE_MAX;
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
}
// The following test cases rely on the support of LEDC
#if SOC_LEDC_SUPPORTED
// The following items only used in the cases that involve LEDC
static QueueHandle_t pcnt_evt_queue = NULL;
typedef struct {
int zero_times;
int h_limit;
int l_limit;
int h_threshold;
int l_threshold;
int filter_time;
} event_times;
static void pcnt_test_io_config(int ctrl_level)
{
// Connect internal signals using IO matrix.
gpio_set_direction(PULSE_IO, GPIO_MODE_INPUT_OUTPUT);
esp_rom_gpio_connect_out_signal(PULSE_IO, ledc_periph_signal[LEDC_LOW_SPEED_MODE].sig_out0_idx + 1, 0, 0); // LEDC_CHANNEL_1, LEDC_LOW_SPEED_MODE
esp_rom_gpio_connect_in_signal(PULSE_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0); // PCNT_UNIT_0, PCNT_CHANNEL_0
esp_rom_gpio_connect_in_signal(ctrl_level ? GPIO_MATRIX_CONST_ONE_INPUT : GPIO_MATRIX_CONST_ZERO_INPUT, pcnt_periph_signals.groups[0].units[0].channels[0].control_sig, 0); // PCNT_UNIT_0, PCNT_CHANNEL_0
}
/* use LEDC to produce pulse for PCNT
* the frequency of LEDC is 1000, so every second will get 1000 count values
* the PCNT count the LEDC pulse
* */
static void produce_pulse(void)
{
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.timer_num = LEDC_TIMER_1,
.duty_resolution = LEDC_TIMER_14_BIT,
.freq_hz = 2,
.clk_cfg = LEDC_AUTO_CLK,
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_1,
.timer_sel = LEDC_TIMER_1,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = PULSE_IO,
.duty = 100,
.hpoint = 0,
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
}
static void IRAM_ATTR pcnt_intr_handler(void *arg)
{
uint32_t intr_status = PCNT.int_st.val;
int i;
uint32_t status;
BaseType_t port_status = pdFALSE;
for (i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
if (intr_status & (BIT(i))) {
status = PCNT.status_unit[i].val;
PCNT.int_clr.val = BIT(i);
xQueueSendFromISR(pcnt_evt_queue, &status, &port_status);
if (port_status == pdTRUE) {
portYIELD_FROM_ISR();
}
}
}
}
static void event_calculate(event_times *event)
{
int16_t test_counter = 0;
int times = 0;
BaseType_t port_status;
uint32_t status = 0;
while (times < 10) {
port_status = xQueueReceive(pcnt_evt_queue, &status, 1001 / portTICK_PERIOD_MS);
if (port_status == pdTRUE) {
event->filter_time++;
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("Current counter value :%d\n", test_counter);
if (status & PCNT_EVT_THRES_1) {
printf("THRES1 EVT\n");
event->h_threshold++;
}
if (status & PCNT_EVT_THRES_0) {
printf("THRES0 EVT\n");
event->l_threshold++;
}
if (status & PCNT_EVT_L_LIM) {
printf("L_LIM EVT\n");
event->l_limit++;
}
if (status & PCNT_EVT_H_LIM) {
printf("H_LIM EVT\n");
event->h_limit++;
}
if (status & PCNT_EVT_ZERO) {
printf("ZERO EVT\n");
event->zero_times++;
}
} else {
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("Current counter value :%d\n", test_counter);
}
times++;
}
printf("%d, %d, %d, %d, %d, %d\n", event->h_threshold, event->l_threshold,
event->l_limit, event->h_limit, event->zero_times, event->filter_time);
}
/*
* There exist 2 kind of counting methods: positive and negative counting method
* 1. when control IO is high level, PCNT is positive counting mode
* 2. when control IO is low level, PCNT is positive negative mode
* the positive method standard is as below:
* ----------------------------------------------------------------------------------
* POS_ MODE | LCTRL_ MODE | HCTRL_ MODE | sig l→h when ctrl=0 | sig l→h when ctrl=1
* NEG_ MODE | | | |
* ===================================================================================
* 1 (inc) | 0 (-) | 0 (-) | Inc ctr | Inc ctr
* 2 (dec) | 0 (-) | 0 (-) | Dec ctr | Dec ctr
* 0 (-) | x | x | No action | No action
* 1 (inc) | 0 (-) | 1 (inv) | Inc ctr | Dec ctr
* 1 (inc) | 1 (inv) | 0 (-) | Dec ctr | Inc ctr
* 2 (dec) | 0 (-) | 1 (inv) | Dec ctr | Inc ctr
* 1 (inc) | 0 (-) | 2 (dis) | Inc ctr | No action
* 1 (inc) | 2 (dis) | 0 (-) | No action | Inc ctr
* -----------------------------------------------------------------------------------
* */
static void count_mode_test(gpio_num_t ctl_io)
{
int16_t test_counter;
//produce pulse, 100HZ
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.timer_num = LEDC_TIMER_1,
.duty_resolution = LEDC_TIMER_10_BIT,
.freq_hz = 100,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config(&ledc_timer);
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_1,
.timer_sel = LEDC_TIMER_1,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = PULSE_IO,
.duty = 100,
.hpoint = 0,
};
ledc_channel_config(&ledc_channel);
pcnt_config_t pcnt_config = {
.pulse_gpio_num = PCNT_INPUT_IO,
.ctrl_gpio_num = ctl_io,
.channel = PCNT_CHANNEL_0,
.unit = PCNT_UNIT_0,
.pos_mode = PCNT_COUNT_INC,
.neg_mode = PCNT_COUNT_DIS,
.lctrl_mode = PCNT_MODE_REVERSE,
.hctrl_mode = PCNT_MODE_KEEP,
.counter_h_lim = 101,
.counter_l_lim = -101,
};
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
pcnt_test_io_config((ctl_io == PCNT_CTRL_VCC_IO) ? PCNT_CTRL_HIGH_LEVEL : PCNT_CTRL_LOW_LEVEL);
int16_t result1[8] = {100, -100, 0, -100, 100, 100, 0, 100};
int16_t result2[8] = {100, -100, 0, 100, -100, -100, 100, 0};
int16_t *result;
if (ctl_io == PCNT_CTRL_VCC_IO) {
result = result1;
} else {
result = result2;
}
// Wait for ledc and pcnt settling down
vTaskDelay(500 / portTICK_PERIOD_MS);
// 1, 0, 0, 0
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
PCNT_COUNT_INC, PCNT_COUNT_DIS,
PCNT_MODE_KEEP, PCNT_MODE_KEEP));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("value: %d\n", test_counter);
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[0]);
//2, 0, 0, 0
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
PCNT_COUNT_DEC, PCNT_COUNT_DIS,
PCNT_MODE_KEEP, PCNT_MODE_KEEP));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("value: %d\n", test_counter);
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[1]);
//0,0,0,0
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
PCNT_COUNT_DIS, PCNT_COUNT_DIS,
PCNT_MODE_KEEP, PCNT_MODE_KEEP));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("value: %d\n", test_counter);
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[2]);
//1,0,1,0
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
PCNT_COUNT_INC, PCNT_COUNT_DIS,
PCNT_MODE_REVERSE, PCNT_MODE_KEEP));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("value: %d\n", test_counter);
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[3]);
//1,0,0,1
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
PCNT_COUNT_INC, PCNT_COUNT_DIS,
PCNT_MODE_KEEP, PCNT_MODE_REVERSE));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("value: %d\n", test_counter);
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[4]);
//2,0,0,1
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
PCNT_COUNT_DEC, PCNT_COUNT_DIS,
PCNT_MODE_REVERSE, PCNT_MODE_KEEP));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("value: %d\n", test_counter);
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[5]);
//1,0,2,0
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
PCNT_COUNT_INC, PCNT_COUNT_DIS,
PCNT_MODE_DISABLE, PCNT_MODE_KEEP));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("value: %d\n", test_counter);
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[6]);
//1,0,0,2
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
PCNT_COUNT_INC, PCNT_COUNT_DIS,
PCNT_MODE_KEEP, PCNT_MODE_DISABLE));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("value: %d\n", test_counter);
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[7]);
}
/* PCNT basic property:
* 1. pause counter
* 2. resume counter
* 3. clear counter
* 4. check the counter value*/
TEST_CASE("PCNT_basic_function_test", "[pcnt]")
{
int16_t test_counter;
int16_t time = 0;
int clear_count = 0;
int resume_count = 0;
int temp_value = 0;
pcnt_config_t pcnt_config = {
.pulse_gpio_num = PCNT_INPUT_IO,
.ctrl_gpio_num = PCNT_CTRL_VCC_IO,
.channel = PCNT_CHANNEL_0,
.unit = PCNT_UNIT_0,
.pos_mode = PCNT_COUNT_INC,
.neg_mode = PCNT_COUNT_DIS,
.lctrl_mode = PCNT_MODE_REVERSE,
.hctrl_mode = PCNT_MODE_KEEP,
.counter_h_lim = 10,
.counter_l_lim = -10,
};
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
// use LEDC to produce the pulse, then the PCNT to count it
produce_pulse();
vTaskDelay(10 / portTICK_PERIOD_MS); // ensure LEDC is working
pcnt_test_io_config(PCNT_CTRL_HIGH_LEVEL);
// initialize first, the initial value should be 0
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
TEST_ASSERT_EQUAL_INT16(test_counter, 0);
// resume the PCNT
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
TEST_ASSERT_EQUAL_INT16(test_counter, 0);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
TEST_ASSERT_EQUAL_INT16(test_counter, 0);
//count now
while (time != 10) {
vTaskDelay(501 / portTICK_PERIOD_MS); // in case of can't wait to get counter(edge effect)
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("COUNT: %d\n", test_counter);
TEST_ASSERT_NOT_EQUAL(test_counter, temp_value);
temp_value = test_counter;
if (test_counter == 5 || test_counter == -5) {
//test clear
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
TEST_ASSERT_EQUAL_INT16(test_counter, 0);
clear_count++;
}
if (test_counter == 0) {
//test pause
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
vTaskDelay(500 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("PAUSE: %d\n", test_counter);
TEST_ASSERT_EQUAL_INT16(test_counter, 0);
// test resume
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
vTaskDelay(500 / portTICK_PERIOD_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("RESUME: %d\n", test_counter);
TEST_ASSERT_EQUAL_INT16(test_counter, 1);
resume_count++;
}
time++;
}
TEST_ASSERT_EQUAL_INT16(clear_count, 2);
TEST_ASSERT_EQUAL_INT16(resume_count, 2);
}
/**
* there are 4 situations will be tested:
* 1. set event to interrupt triggered
* 2. disable interrupt to stop triggering interrupt
* 3. enable interrupt to interrupt triggered again
* 4. disable event to stop triggering interrupt
*
* PCNT interrupt type:
* 1. PCNT_EVT_THRES_1
* 2. PCNT_EVT_THRES_0
* 3. PCNT_EVT_ZERO
* 4. PCNT_EVT_H_LIM
* 5. PCNT_EVT_L_LIM
* */
TEST_CASE("PCNT_interrupt_method_test_control_IO_high", "[pcnt][timeout=120]")
{
pcnt_config_t config = {
.pulse_gpio_num = PCNT_INPUT_IO,
.ctrl_gpio_num = PCNT_CTRL_VCC_IO,
.channel = PCNT_CHANNEL_0,
.unit = PCNT_UNIT_0,
.pos_mode = PCNT_COUNT_INC,
.neg_mode = PCNT_COUNT_DIS,
.lctrl_mode = PCNT_MODE_REVERSE,
.hctrl_mode = PCNT_MODE_KEEP,
.counter_h_lim = 10,
.counter_l_lim = 0,
};
TEST_ESP_OK(pcnt_unit_config(&config));
produce_pulse();
pcnt_test_io_config(PCNT_CTRL_HIGH_LEVEL);
event_times event = {
.zero_times = 0,
.h_limit = 0,
.l_limit = 0,
.h_threshold = 0,
.l_threshold = 0,
.filter_time = 0,
};
//interrupt set
TEST_ESP_OK(pcnt_set_filter_value(PCNT_UNIT_0, 2));
TEST_ESP_OK(pcnt_filter_enable(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, 8)); // when arrive to max threshold trigger
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, 2)); // when arrive to minimum threshold trigger
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM)); // when arrive to max limit trigger
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM)); // when arrive to minimum limit trigger
// initialize first, the initial value should be 0
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
pcnt_evt_queue = xQueueCreate(10, sizeof(uint32_t));
pcnt_isr_handle_t pcnt_isr_service;
TEST_ESP_OK(pcnt_isr_register(pcnt_intr_handler, NULL, 0, &pcnt_isr_service));
TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
// test event
event_calculate(&event);
TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 2);
TEST_ASSERT(event.l_limit == 0);
TEST_ASSERT_INT_WITHIN(2, event.h_limit, 2);
TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
TEST_ASSERT_INT_WITHIN(3, event.filter_time, 4);
// test interrupt disable
TEST_ESP_OK(pcnt_intr_disable(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
// for the original control io disable interrupt status
event_calculate(&event);
TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 2);
TEST_ASSERT(event.l_limit == 0);
TEST_ASSERT_INT_WITHIN(2, event.h_limit, 2);
TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
TEST_ASSERT_INT_WITHIN(3, event.filter_time, 4);
// enable the intr
TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
event_calculate(&event);
TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 4);
TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 4);
TEST_ASSERT(event.l_limit == 0);
TEST_ASSERT_INT_WITHIN(2, event.h_limit, 4);
TEST_ASSERT_INT_WITHIN(2, event.zero_times, 4);
TEST_ASSERT_INT_WITHIN(3, event.filter_time, 10);
// disable part of events
TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_ZERO));
TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_L_LIM));
TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
event_calculate(&event);
TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 5);
TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 4);
TEST_ASSERT(event.l_limit == 0);
TEST_ASSERT_INT_WITHIN(3, event.h_limit, 6);
TEST_ASSERT_INT_WITHIN(2, event.zero_times, 4);
TEST_ASSERT_INT_WITHIN(3, event.filter_time, 14);
// Because this test uses its own ISR, we need to release it with `pcnt_isr_unregister` instead of `pcnt_isr_service_uninstall`
TEST_ESP_OK(pcnt_isr_unregister(pcnt_isr_service));
vQueueDelete(pcnt_evt_queue);
}
TEST_CASE("PCNT_interrupt_method_test_control_IO_low", "[pcnt][timeout=120]")
{
pcnt_config_t config = {
.pulse_gpio_num = PCNT_INPUT_IO,
.ctrl_gpio_num = PCNT_CTRL_GND_IO,
.channel = PCNT_CHANNEL_0,
.unit = PCNT_UNIT_0,
.pos_mode = PCNT_COUNT_INC,
.neg_mode = PCNT_COUNT_DIS,
.lctrl_mode = PCNT_MODE_REVERSE,
.hctrl_mode = PCNT_MODE_KEEP,
.counter_h_lim = 0,
.counter_l_lim = -10,
};
TEST_ESP_OK(pcnt_unit_config(&config));
produce_pulse();
pcnt_test_io_config(PCNT_CTRL_LOW_LEVEL);
event_times event = {
.zero_times = 0,
.h_limit = 0,
.l_limit = 0,
.h_threshold = 0,
.l_threshold = 0,
.filter_time = 0,
};
//interrupt set
TEST_ESP_OK(pcnt_set_filter_value(PCNT_UNIT_0, 2));
TEST_ESP_OK(pcnt_filter_enable(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, -8)); // when arrive to max threshold trigger
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, 0)); // when arrive to minimum threshold trigger
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM)); // when arrive to max limit trigger
TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM)); // when arrive to minimum limit trigger
// to initialize for PCNT
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
pcnt_evt_queue = xQueueCreate(10, sizeof(uint32_t));
pcnt_isr_handle_t pcnt_isr_service;
TEST_ESP_OK(pcnt_isr_register(pcnt_intr_handler, NULL, 0, &pcnt_isr_service));
TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
// test event
event_calculate(&event);
TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 1);
TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 1);
TEST_ASSERT_INT_WITHIN(2, event.l_limit, 1);
TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
TEST_ASSERT_INT_WITHIN(2, event.zero_times, 1);
TEST_ASSERT_INT_WITHIN(2, event.filter_time, 2);
// test interrupt disable
TEST_ESP_OK(pcnt_intr_disable(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
// for the original control io disable interrupt status
event_calculate(&event);
TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 1);
TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 1);
TEST_ASSERT_INT_WITHIN(2, event.l_limit, 1);
TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
TEST_ASSERT_INT_WITHIN(2, event.zero_times, 1);
TEST_ASSERT_INT_WITHIN(2, event.filter_time, 2);
// enable the intr
pcnt_unit_config(&config);
pcnt_test_io_config(PCNT_CTRL_LOW_LEVEL);
TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
event_calculate(&event);
TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 3);
TEST_ASSERT_INT_WITHIN(2, event.l_limit, 2);
TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
TEST_ASSERT_INT_WITHIN(2, event.filter_time, 6);
// disable part of events
TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_ZERO));
TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_L_LIM));
TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
event_calculate(&event);
TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 4);
TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 3);
TEST_ASSERT_INT_WITHIN(2, event.l_limit, 2);
TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
TEST_ASSERT_INT_WITHIN(2, event.filter_time, 8);
// Because this test uses its own ISR, we need to release it with `pcnt_isr_unregister` instead of `pcnt_isr_service_uninstall`
TEST_ESP_OK(pcnt_isr_unregister(pcnt_isr_service));
vQueueDelete(pcnt_evt_queue);
}
TEST_CASE("PCNT_counting_mode_test", "[pcnt]")
{
printf("PCNT mode test for positive count\n");
count_mode_test(PCNT_CTRL_VCC_IO);
printf("PCNT mode test for negative count\n");
count_mode_test(PCNT_CTRL_GND_IO);
}
#endif // SOC_LEDC_SUPPORTED

View File

@ -1,20 +0,0 @@
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
@idf_parametrize(
'target', ['esp32', 'esp32s2', 'esp32s3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4'], indirect=['target']
)
def test_legacy_pcnt(dut: Dut) -> None:
dut.run_all_single_board_cases(timeout=240)

View File

@ -1,5 +0,0 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -1,3 +0,0 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y

View File

@ -248,12 +248,14 @@ LEDC
.. only:: SOC_PCNT_SUPPORTED
Pulse Counter Driver
--------------------
.. _deprecate_pcnt_legacy_driver:
Legacy PCNT Driver is Deprecated
--------------------------------
Pulse counter driver has been redesigned (see :doc:`PCNT <../../../api-reference/peripherals/pcnt>`), which aims to unify and simplify the usage of PCNT peripheral.
Although it is recommended to use the new driver APIs, the legacy driver is still available in the previous include path ``driver/pcnt.h``. However, including ``driver/pcnt.h`` triggers the build warning below by default. The warning can be suppressed by the Kconfig option :ref:`CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN`.
Although it is recommended to use the new driver APIs, the legacy driver is still available in the previous include path ``driver/pcnt.h``. However, including ``driver/pcnt.h`` triggers the build warning below by default. The warning can be suppressed by the Kconfig option ``CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN``.
.. code-block:: text

View File

@ -61,3 +61,10 @@ The legacy timer group driver ``driver/timer.h`` is deprecated since version 5.0
------------------------------------
The legacy i2s driver ``driver/i2s.h`` is deprecated since version 5.0 (see :ref:`deprecate_i2s_legacy_driver`). Starting from version 6.0, the legacy driver is completely removed. The new driver is placed in the :component:`esp_driver_i2s`, and the header file path is ``driver/i2s_std.h``, ``driver/i2s_pdm.h`` and ``driver/i2s_tdm.h``.
.. only:: SOC_PCNT_SUPPORTED
Legacy PCNT Driver is Removed
------------------------------------
The legacy PCNT driver ``driver/pcnt.h`` is deprecated since version 5.0 (see :ref:`deprecate_pcnt_legacy_driver`). Starting from version 6.0, the legacy driver is completely removed. The new driver is placed in the :component:`esp_driver_pcnt`, and the header file path is ``driver/pulse_cnt.h``.

View File

@ -248,12 +248,14 @@ LEDC
.. only:: SOC_PCNT_SUPPORTED
脉冲计数器 (PCNT) 驱动
.. _deprecate_pcnt_legacy_driver:
旧版 PCNT 驱动被弃用
----------------------------------
为统一和简化 PCNT 外设PCNT 驱动已更新,详见 :doc:`PCNT <../../../api-reference/peripherals/pcnt>`
尽管我们推荐使用新的驱动 API旧版驱动仍然可用保留在头文件引用路径 ``driver/pcnt.h`` 中。但是,引用路径 ``driver/pcnt.h`` 会默认触发如下编译警告,可通过配置 Kconfig 选项 :ref:`CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN` 来关闭该警告。
尽管我们推荐使用新的驱动 API旧版驱动仍然可用保留在头文件引用路径 ``driver/pcnt.h`` 中。但是,引用路径 ``driver/pcnt.h`` 会默认触发如下编译警告,可通过配置 Kconfig 选项 ``CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN`` 来关闭该警告。
.. code-block:: text

View File

@ -61,3 +61,10 @@ I2C 从机在 v5.4 上已经被重新设计。在当前版本上,老的 I2C
----------------------
旧版的 I2S 驱动 ``driver/i2s.h`` 在 5.0 的版本中就已经被弃用(请参考 :ref:`deprecate_i2s_legacy_driver`)。从 6.0 版本开始,旧版驱动被完全移除。新驱动位于 :component:`esp_driver_i2s` 组件中,头文件引用路径为 ``driver/i2s_std.h``, ``driver/i2s_pdm.h`` and ``driver/i2s_tdm.h``
.. only:: SOC_PCNT_SUPPORTED
旧版 PCNT 驱动被移除
----------------------
旧版的 PCNT 驱动 ``driver/pcnt.h`` 在 5.0 的版本中就已经被弃用 (参考 :ref:`deprecate_pcnt_legacy_driver`)。从 6.0 版本开始,旧版驱动被完全移除。新驱动位于 :component:`esp_driver_pcnt` 组件中,头文件引用路径为 ``driver/pulse_cnt.h``

View File

@ -499,3 +499,6 @@
-
re_variables: ['driver/i2s.h']
hint_variables: ['legacy I2S', 'driver/i2s_std.h, driver/i2s_pdm.h, driver/i2s_tdm.h', 'esp_driver_i2s']
-
re_variables: ['driver/pcnt.h']
hint_variables: ['legacy pcnt', 'driver/pulse_cnt.h', 'esp_driver_pcnt']