mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 02:37:19 +02:00
remove(legacy_pcnt): remove legacy pcnt driver in IDF v6.0
This commit is contained in:
@ -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")
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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)
|
@ -1,2 +0,0 @@
|
||||
| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
|
@ -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)
|
@ -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();
|
||||
}
|
@ -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
|
@ -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)
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
@ -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
|
||||
|
||||
|
@ -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``.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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``。
|
||||
|
@ -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']
|
||||
|
Reference in New Issue
Block a user