Pulse Counter (PCNT)
Introduction
The PCNT (Pulse Counter) module is designed to count the number of rising and/or falling edges of an input signal. Each pulse counter unit has a 16-bit signed counter register and two channels that can be configured to either increment or decrement the counter. Each channel has a signal input that accepts signal edges to be detected, as well as a control input that can be used to enable or disable the signal input. The inputs have optional filters that can be used to discard unwanted glitches in the signal.
Functionality Overview
Description of functionality of this API has been broken down into four sections:
Configuration - describes counter’s configuration parameters and how to setup the counter.
Operating the Counter - provides information on control functions to pause, measure and clear the counter.
Filtering Pulses - describes options to filtering pulses and the counter control signals.
Using Interrupts - presents how to trigger interrupts on specific states of the counter.
Configuration
The PCNT module has 4 independent counting “units” numbered from 0 to 3. In the API they are referred to using pcnt_unit_t
. Each unit has two independent channels numbered as 0 and 1 and specified with pcnt_channel_t
.
The configuration is provided separately per unit’s channel using pcnt_config_t
and covers:
The unit and the channel number this configuration refers to.
GPIO numbers of the pulse input and the pulse gate input.
Two pairs of parameters:
pcnt_ctrl_mode_t
andpcnt_count_mode_t
to define how the counter reacts depending on the the status of control signal and how counting is done positive / negative edge of the pulses.Two limit values (minimum / maximum) that are used to establish watchpoints and trigger interrupts when the pulse count is meeting particular limit.
Setting up of particular channel is then done by calling a function pcnt_unit_config()
with above pcnt_config_t
as the input parameter.
To disable the pulse or the control input pin in configuration, provide PCNT_PIN_NOT_USED
instead of the GPIO number.
Operating the Counter
After doing setup with pcnt_unit_config()
, the counter immediately starts to operate. The accumulated pulse count can be checked by calling pcnt_get_counter_value()
.
There are couple of functions that allow to control the counter’s operation: pcnt_counter_pause()
, pcnt_counter_resume()
and pcnt_counter_clear()
It is also possible to dynamically change the previously set up counter modes with pcnt_unit_config()
by calling pcnt_set_mode()
.
If desired, the pulse input pin and the control input pin may be changed “on the fly” using pcnt_set_pin()
. To disable particular input provide as a function parameter PCNT_PIN_NOT_USED
instead of the GPIO number.
备注
For the counter not to miss any pulses, the pulse duration should be longer than one APB_CLK cycle (12.5 ns). The pulses are sampled on the edges of the APB_CLK clock and may be missed, if fall between the edges. This applies to counter operation with or without a filer.
Filtering Pulses
The PCNT unit features filters on each of the pulse and control inputs, adding the option to ignore short glitches in the signals.
The length of ignored pulses is provided in APB_CLK clock cycles by calling pcnt_set_filter_value()
. The current filter setting may be checked with pcnt_get_filter_value()
. The APB_CLK clock is running at 80 MHz.
The filter is put into operation / suspended by calling pcnt_filter_enable()
/ pcnt_filter_disable()
.
Using Interrupts
There are five counter state watch events, defined in pcnt_evt_type_t
, that are able to trigger an interrupt. The event happens on the pulse counter reaching specific values:
Minimum or maximum count values:
counter_l_lim
orcounter_h_lim
provided inpcnt_config_t
as discussed in ConfigurationThreshold 0 or Threshold 1 values set using function
pcnt_set_event_value()
.Pulse count = 0
To register, enable or disable an interrupt to service the above events, call pcnt_isr_register()
, pcnt_intr_enable()
. and pcnt_intr_disable()
. To enable or disable events on reaching threshold values, you will also need to call functions pcnt_event_enable()
and pcnt_event_disable()
.
In order to check what are the threshold values currently set, use function pcnt_get_event_value()
.
Application Example
Pulse counter with control signal and event interrupt example: peripherals/pcnt/pulse_count_event.
Parse the signal generated from rotary encoder: peripherals/pcnt/rotary_encoder.
API Reference
Header File
Functions
-
esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config)
Configure Pulse Counter unit.
备注
This function will disable three events: PCNT_EVT_L_LIM, PCNT_EVT_H_LIM, PCNT_EVT_ZERO.
- 参数
pcnt_config – Pointer of Pulse Counter unit configure parameter
- 返回
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver already initialized
ESP_ERR_INVALID_ARG Parameter error
-
esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t *count)
Get pulse counter value.
- 参数
pcnt_unit – Pulse Counter unit number
count – Pointer to accept counter value
- 返回
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)
Pause PCNT counter of PCNT unit.
- 参数
pcnt_unit – PCNT unit number
- 返回
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)
Resume counting for PCNT counter.
- 参数
pcnt_unit – PCNT unit number, select from pcnt_unit_t
- 返回
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)
Clear and reset PCNT counter value to zero.
- 参数
pcnt_unit – PCNT unit number, select from pcnt_unit_t
- 返回
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)
Enable PCNT interrupt for PCNT unit.
备注
Each Pulse counter unit has five watch point events that share the same interrupt. Configure events with pcnt_event_enable() and pcnt_event_disable()
- 参数
pcnt_unit – PCNT unit number
- 返回
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)
Disable PCNT interrupt for PCNT unit.
- 参数
pcnt_unit – PCNT unit number
- 返回
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)
Enable PCNT event of PCNT unit.
- 参数
unit – PCNT unit number
evt_type – Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).
- 返回
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)
Disable PCNT event of PCNT unit.
- 参数
unit – PCNT unit number
evt_type – Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).
- 返回
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)
Set PCNT event value of PCNT unit.
- 参数
unit – PCNT unit number
evt_type – Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).
value – Counter value for PCNT event
- 返回
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)
Get PCNT event value of PCNT unit.
- 参数
unit – PCNT unit number
evt_type – Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).
value – Pointer to accept counter value for PCNT event
- 返回
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)
Get PCNT event status of PCNT unit.
- 参数
unit – PCNT unit number
status – Pointer to accept event status word
- 返回
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
-
esp_err_t pcnt_isr_unregister(pcnt_isr_handle_t handle)
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.
- 参数
handle – handle to unregister the ISR service.
- 返回
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)
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.
- 参数
fn – Interrupt handler function.
arg – Parameter for handler function
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.
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.
- 返回
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_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io)
Configure PCNT pulse signal input pin and control input pin.
备注
Set the signal input to PCNT_PIN_NOT_USED if unused.
- 参数
unit – PCNT unit number
channel – PCNT channel number
pulse_io – Pulse signal input GPIO
ctrl_io – Control signal input GPIO
- 返回
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)
Enable PCNT input filter.
- 参数
unit – PCNT unit number
- 返回
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)
Disable PCNT input filter.
- 参数
unit – PCNT unit number
- 返回
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)
Set PCNT filter value.
备注
filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
- 参数
unit – PCNT unit number
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.
- 返回
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)
Get PCNT filter value.
- 参数
unit – PCNT unit number
filter_val – Pointer to accept PCNT filter value.
- 返回
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)
Set PCNT counter mode.
- 参数
unit – PCNT unit number
channel – PCNT channel number
pos_mode – Counter mode when detecting positive edge
neg_mode – Counter mode when detecting negative edge
hctrl_mode – Counter mode when control signal is high level
lctrl_mode – Counter mode when control signal is low level
- 返回
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)
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.
- 参数
unit – PCNT unit number
isr_handler – Interrupt handler function.
args – Parameter for handler function
- 返回
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
-
esp_err_t pcnt_isr_service_install(int intr_alloc_flags)
Install PCNT ISR service.
备注
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.
- 参数
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.
- 返回
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
-
void pcnt_isr_service_uninstall(void)
Uninstall PCNT ISR service, freeing related resources.
-
esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit)
Delete ISR handler for specified unit.
- 参数
unit – PCNT unit number
- 返回
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
Structures
-
struct pcnt_config_t
Pulse Counter configuration for a single channel.
Public Members
-
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
-
int pulse_gpio_num
Macros
-
PCNT_PIN_NOT_USED
When selected for a pin, this pin will not be used
-
PCNT_MODE_KEEP
Control mode: won’t change counter mode
-
PCNT_MODE_REVERSE
Control mode: invert counter mode(increase -> decrease, decrease -> increase)
-
PCNT_MODE_DISABLE
Control mode: Inhibit counter(counter value will not change in this condition)
-
PCNT_MODE_MAX
-
PCNT_COUNT_DIS
Counter mode: Inhibit counter(counter value will not change in this condition)
-
PCNT_COUNT_INC
Counter mode: Increase counter value
-
PCNT_COUNT_DEC
Counter mode: Decrease counter value
-
PCNT_COUNT_MAX
Type Definitions
-
typedef intr_handle_t pcnt_isr_handle_t
-
typedef pcnt_channel_level_action_t pcnt_ctrl_mode_t
Selection of available modes that determine the counter’s action depending on the state of the control signal’s input GPIO.
备注
Configuration covers two actions, one for high, and one for low level on the control input
-
typedef pcnt_channel_edge_action_t pcnt_count_mode_t
Selection of available modes that determine the counter’s action on the edge of the pulse signal’s input GPIO.
备注
Configuration covers two actions, one for positive, and one for negative edge on the pulse input
Enumerations
-
enum pcnt_port_t
PCNT port number, the max port number is (PCNT_PORT_MAX - 1).
Values:
-
enumerator PCNT_PORT_0
PCNT port 0
-
enumerator PCNT_PORT_MAX
PCNT port max
-
enumerator PCNT_PORT_0
-
enum pcnt_unit_t
Selection of all available PCNT units.
Values:
-
enumerator PCNT_UNIT_0
PCNT unit 0
-
enumerator PCNT_UNIT_1
PCNT unit 1
-
enumerator PCNT_UNIT_2
PCNT unit 2
-
enumerator PCNT_UNIT_3
PCNT unit 3
-
enumerator PCNT_UNIT_MAX
-
enumerator PCNT_UNIT_0
-
enum pcnt_channel_t
Selection of channels available for a single PCNT unit.
Values:
-
enumerator PCNT_CHANNEL_0
PCNT channel 0
-
enumerator PCNT_CHANNEL_1
PCNT channel 1
-
enumerator PCNT_CHANNEL_MAX
-
enumerator PCNT_CHANNEL_0
-
enum pcnt_evt_type_t
Selection of counter’s events the may trigger an interrupt.
Values:
-
enumerator PCNT_EVT_THRES_1
PCNT watch point event: threshold1 value event
-
enumerator PCNT_EVT_THRES_0
PCNT watch point event: threshold0 value event
-
enumerator PCNT_EVT_L_LIM
PCNT watch point event: Minimum counter value
-
enumerator PCNT_EVT_H_LIM
PCNT watch point event: Maximum counter value
-
enumerator PCNT_EVT_ZERO
PCNT watch point event: counter value zero event
-
enumerator PCNT_EVT_MAX
-
enumerator PCNT_EVT_THRES_1
Header File
Enumerations
-
enum pcnt_channel_level_action_t
PCNT channel action on control level.
Values:
-
enumerator PCNT_CHANNEL_LEVEL_ACTION_KEEP
Keep current count mode
-
enumerator PCNT_CHANNEL_LEVEL_ACTION_INVERSE
Invert current count mode (increase -> decrease, decrease -> increase)
-
enumerator PCNT_CHANNEL_LEVEL_ACTION_HOLD
Hold current count value
-
enumerator PCNT_CHANNEL_LEVEL_ACTION_KEEP
-
enum pcnt_channel_edge_action_t
PCNT channel action on signal edge.
Values:
-
enumerator PCNT_CHANNEL_EDGE_ACTION_HOLD
Hold current count value
-
enumerator PCNT_CHANNEL_EDGE_ACTION_INCREASE
Increase count value
-
enumerator PCNT_CHANNEL_EDGE_ACTION_DECREASE
Decrease count value
-
enumerator PCNT_CHANNEL_EDGE_ACTION_HOLD
-
enum pcnt_unit_count_sign_t
PCNT unit counter value’s sign.
Values:
-
enumerator PCNT_UNIT_COUNT_SIGN_ZERO_POS
positive value to zero
-
enumerator PCNT_UNIT_COUNT_SIGN_ZERO_NEG
negative value to zero
-
enumerator PCNT_UNIT_COUNT_SIGN_NEG
counter value negative
-
enumerator PCNT_UNIT_COUNT_SIGN_POS
counter value positive
-
enumerator PCNT_UNIT_COUNT_SIGN_ZERO_POS