Pulse Counter¶
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 8 independent counting “units” numbered from 0 to 7. 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.
Note
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.
- Note
This function will disable three events: PCNT_EVT_L_LIM, PCNT_EVT_H_LIM, PCNT_EVT_ZERO.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver already initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
pcnt_config
: Pointer of Pulse Counter unit configure parameter
-
esp_err_t
pcnt_get_counter_value
(pcnt_unit_t pcnt_unit, int16_t *count)¶ Get pulse counter value.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
pcnt_unit
: Pulse Counter unit numbercount
: Pointer to accept counter value
-
esp_err_t
pcnt_counter_pause
(pcnt_unit_t pcnt_unit)¶ Pause PCNT counter of PCNT unit.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
pcnt_unit
: PCNT unit number
-
esp_err_t
pcnt_counter_resume
(pcnt_unit_t pcnt_unit)¶ Resume counting for PCNT counter.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
pcnt_unit
: PCNT unit number, select from pcnt_unit_t
-
esp_err_t
pcnt_counter_clear
(pcnt_unit_t pcnt_unit)¶ Clear and reset PCNT counter value to zero.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
pcnt_unit
: PCNT unit number, select from pcnt_unit_t
-
esp_err_t
pcnt_intr_enable
(pcnt_unit_t pcnt_unit)¶ 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()
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
pcnt_unit
: PCNT unit number
-
esp_err_t
pcnt_intr_disable
(pcnt_unit_t pcnt_unit)¶ Disable PCNT interrupt for PCNT unit.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
pcnt_unit
: PCNT unit number
-
esp_err_t
pcnt_event_enable
(pcnt_unit_t unit, pcnt_evt_type_t evt_type)¶ Enable PCNT event of PCNT unit.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit numberevt_type
: Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).
-
esp_err_t
pcnt_event_disable
(pcnt_unit_t unit, pcnt_evt_type_t evt_type)¶ Disable PCNT event of PCNT unit.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit numberevt_type
: Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).
-
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.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit numberevt_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_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.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit numberevt_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_err_t
pcnt_get_event_status
(pcnt_unit_t unit, uint32_t *status)¶ Get PCNT event status of PCNT unit.
- Return
- ESP_OK Success - ESP_ERR_INVALID_STATE pcnt driver has not been initialized - ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit numberstatus
: Pointer to accept event status word
-
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.
- Return
ESP_OK Success
ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
ESP_ERR_INVALID_ARG Function pointer error.
- Parameters
handle
: handle to unregister the ISR service.
-
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.
- Return
ESP_OK Success
ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
ESP_ERR_INVALID_ARG Function pointer error.
- Parameters
fn
: Interrupt handler function.arg
: Parameter for handler functionintr_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_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.
- 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
- Parameters
unit
: PCNT unit numberchannel
: PCNT channel numberpulse_io
: Pulse signal input GPIOctrl_io
: Control signal input GPIO
-
esp_err_t
pcnt_filter_enable
(pcnt_unit_t unit)¶ Enable PCNT input filter.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit number
-
esp_err_t
pcnt_filter_disable
(pcnt_unit_t unit)¶ Disable PCNT input filter.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit number
-
esp_err_t
pcnt_set_filter_value
(pcnt_unit_t unit, uint16_t filter_val)¶ Set PCNT filter value.
- 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
- Parameters
unit
: PCNT unit numberfilter_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_err_t
pcnt_get_filter_value
(pcnt_unit_t unit, uint16_t *filter_val)¶ Get PCNT filter value.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit numberfilter_val
: Pointer to accept PCNT filter value.
-
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.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit numberchannel
: PCNT channel numberpos_mode
: Counter mode when detecting positive edgeneg_mode
: Counter mode when detecting negative edgehctrl_mode
: Counter mode when control signal is high levellctrl_mode
: Counter mode when control signal is low level
-
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.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit numberisr_handler
: Interrupt handler function.args
: Parameter for handler function
-
esp_err_t
pcnt_isr_service_install
(int intr_alloc_flags)¶ 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.
- 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
- Parameters
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.
-
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.
- Return
ESP_OK Success
ESP_ERR_INVALID_STATE pcnt driver has not been initialized
ESP_ERR_INVALID_ARG Parameter error
- Parameters
unit
: PCNT unit number
Type Definitions¶
-
typedef intr_handle_t
pcnt_isr_handle_t
¶
Header File¶
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
Enumerations¶
-
enum
pcnt_port_t
¶ PCNT port number, the max port number is (PCNT_PORT_MAX - 1).
Values:
-
PCNT_PORT_0
= 0¶ PCNT port 0
-
PCNT_PORT_MAX
¶ PCNT port max
-
-
enum
pcnt_unit_t
¶ Selection of all available PCNT units.
Values:
-
PCNT_UNIT_0
= 0¶ PCNT unit 0
-
PCNT_UNIT_1
= 1¶ PCNT unit 1
-
PCNT_UNIT_2
= 2¶ PCNT unit 2
-
PCNT_UNIT_3
= 3¶ PCNT unit 3
-
PCNT_UNIT_4
= 4¶ PCNT unit 4
-
PCNT_UNIT_5
= 5¶ PCNT unit 5
-
PCNT_UNIT_6
= 6¶ PCNT unit 6
-
PCNT_UNIT_7
= 7¶ PCNT unit 7
-
PCNT_UNIT_MAX
¶
-
-
enum
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.
- Note
Configuration covers two actions, one for high, and one for low level on the control input
Values:
-
PCNT_MODE_KEEP
= 0¶ Control mode: won’t change counter mode
-
PCNT_MODE_REVERSE
= 1¶ Control mode: invert counter mode(increase -> decrease, decrease -> increase)
-
PCNT_MODE_DISABLE
= 2¶ Control mode: Inhibit counter(counter value will not change in this condition)
-
PCNT_MODE_MAX
¶
-
enum
pcnt_count_mode_t
¶ 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
Values:
-
PCNT_COUNT_DIS
= 0¶ Counter mode: Inhibit counter(counter value will not change in this condition)
-
PCNT_COUNT_INC
= 1¶ Counter mode: Increase counter value
-
PCNT_COUNT_DEC
= 2¶ Counter mode: Decrease counter value
-
PCNT_COUNT_MAX
¶
-
enum
pcnt_channel_t
¶ Selection of channels available for a single PCNT unit.
Values:
-
PCNT_CHANNEL_0
= 0x00¶ PCNT channel 0
-
PCNT_CHANNEL_1
= 0x01¶ PCNT channel 1
-
PCNT_CHANNEL_MAX
¶
-
-
enum
pcnt_evt_type_t
¶ Selection of counter’s events the may trigger an interrupt.
Values:
-
PCNT_EVT_THRES_1
= BIT(2)¶ PCNT watch point event: threshold1 value event
-
PCNT_EVT_THRES_0
= BIT(3)¶ PCNT watch point event: threshold0 value event
-
PCNT_EVT_L_LIM
= BIT(4)¶ PCNT watch point event: Minimum counter value
-
PCNT_EVT_H_LIM
= BIT(5)¶ PCNT watch point event: Maximum counter value
-
PCNT_EVT_ZERO
= BIT(6)¶ PCNT watch point event: counter value zero event
-
PCNT_EVT_MAX
¶
-