mirror of
https://github.com/espressif/esp-idf.git
synced 2026-06-04 20:26:38 +03:00
feat(pcnt): add support for step notify
PCNT can add watch of value increment that we call step notify. This commit add a step notify driver and a test for the driver. Closes https://github.com/espressif/esp-idf/issues/9604 Closes https://github.com/espressif/esp-idf/issues/12136
This commit is contained in:
@@ -25,6 +25,7 @@ Description of the PCNT functionality is divided into the following sections:
|
||||
- :ref:`pcnt-resource-allocation` - covers how to allocate PCNT units and channels with properly set of configurations. It also covers how to recycle the resources when they finished working.
|
||||
- :ref:`pcnt-setup-channel-actions` - covers how to configure the PCNT channel to behave on different signal edges and levels.
|
||||
- :ref:`pcnt-watch-points` - describes how to configure PCNT watch points (i.e., tell PCNT unit to trigger an event when the count reaches a certain value).
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - :ref:`pcnt-step-notify` - describes how to configure PCNT watch step (i.e., tell PCNT unit to trigger an event when the count increment reaches a certain value).
|
||||
- :ref:`pcnt-register-event-callbacks` - describes how to hook your specific code to the watch point event callback function.
|
||||
- :ref:`pcnt-set-glitch-filter` - describes how to enable and set the timing parameters for the internal glitch filter.
|
||||
:SOC_PCNT_SUPPORT_CLEAR_SIGNAL: - :ref:`pcnt-set-clear-signal` - describes how to set the parameters for the external clear signal.
|
||||
@@ -47,9 +48,13 @@ Install PCNT Unit
|
||||
|
||||
To install a PCNT unit, there is a configuration structure that needs to be given in advance: :cpp:type:`pcnt_unit_config_t`:
|
||||
|
||||
- :cpp:member:`pcnt_unit_config_t::low_limit` and :cpp:member:`pcnt_unit_config_t::high_limit` specify the range for the internal hardware counter. The counter will reset to zero automatically when it crosses either the high or low limit.
|
||||
- :cpp:member:`pcnt_unit_config_t::accum_count` sets whether to create an internal accumulator for the counter. This is helpful when you want to extend the counter's width, which by default is 16 bit at most, defined in the hardware. See also :ref:`pcnt-compensate-overflow-loss` for how to use this feature to compensate the overflow loss.
|
||||
- :cpp:member:`pcnt_unit_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority.
|
||||
.. list::
|
||||
|
||||
- :cpp:member:`pcnt_unit_config_t::low_limit` and :cpp:member:`pcnt_unit_config_t::high_limit` specify the range for the internal hardware counter. The counter will reset to zero automatically when it crosses either the high or low limit.
|
||||
- :cpp:member:`pcnt_unit_config_t::accum_count` sets whether to create an internal accumulator for the counter. This is helpful when you want to extend the counter's width, which by default is 16 bit at most, defined in the hardware. See also :ref:`pcnt-compensate-overflow-loss` for how to use this feature to compensate the overflow loss.
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - :cpp:member:`pcnt_unit_config_t::en_step_notify_up` Configure whether to enable watch step to count in the positive direction.
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - :cpp:member:`pcnt_unit_config_t::en_step_notify_down` Configure whether to enable watch step to count in the negative direction.
|
||||
- :cpp:member:`pcnt_unit_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -141,7 +146,36 @@ It is recommended to remove the unused watch point by :cpp:func:`pcnt_unit_remov
|
||||
|
||||
Due to the hardware limitation, after adding a watch point, you should call :cpp:func:`pcnt_unit_clear_count` to make it take effect.
|
||||
|
||||
.. _pcnt-register-event-callbacks:
|
||||
.. only:: SOC_PCNT_SUPPORT_STEP_NOTIFY
|
||||
|
||||
.. _pcnt-step-notify:
|
||||
|
||||
Watch Step
|
||||
^^^^^^^^^^^
|
||||
|
||||
PCNT unit can be configured to watch a specific value increment(can be positive or negative) that you are interested in. The function of watching value increment is also called **Watch Step**. To install watch step requires enabling :cpp:member:`pcnt_unit_config_t::en_step_notify_up` or :cpp:member:`pcnt_unit_config_t::en_step_notify_down`. The step interval itself can not exceed the range set in :cpp:type:`pcnt_unit_config_t` by :cpp:member:`pcnt_unit_config_t::low_limit` and :cpp:member:`pcnt_unit_config_t::high_limit`.When the counter increment reaches step interval, a watch event will be triggered and notify you by interrupt if any watch event callback has ever registered in :cpp:func:`pcnt_unit_register_event_callbacks`. See :ref:`pcnt-register-event-callbacks` for how to register event callbacks.
|
||||
|
||||
The watch step can be added and removed by :cpp:func:`pcnt_unit_add_watch_step` and :cpp:func:`pcnt_unit_remove_watch_step`. You can not add multiple watch step, otherwise it will return error :c:macro:`ESP_ERR_INVALID_STATE`。
|
||||
|
||||
It is recommended to remove the unused watch step by :cpp:func:`pcnt_unit_remove_watch_step` to recycle the watch step resources.
|
||||
|
||||
.. note::
|
||||
|
||||
When a watch step and a watch point are triggered at the same time, only one interrupt event will be generated.
|
||||
The step interval must be a divisor of :cpp:member:`pcnt_unit_config_t::low_limit` or :cpp:member:`pcnt_unit_config_t::high_limit`.
|
||||
|
||||
.. code:: c
|
||||
|
||||
// add positive direction watch step with 100 step intervals
|
||||
ESP_ERROR_CHECK(pcnt_unit_add_watch_step(pcnt_unit, 100));
|
||||
|
||||
.. _pcnt-register-event-callbacks:
|
||||
|
||||
.. only:: not SOC_PCNT_SUPPORT_STEP_NOTIFY
|
||||
|
||||
.. _pcnt-register-event-callbacks:
|
||||
|
||||
|
||||
|
||||
Register Event Callbacks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -152,10 +186,18 @@ When PCNT unit reaches any enabled watch point, specific event will be generated
|
||||
|
||||
You can save their own context to :cpp:func:`pcnt_unit_register_event_callbacks` as well, via the parameter ``user_ctx``. This user data will be directly passed to the callback functions.
|
||||
|
||||
In the callback function, the driver will fill in the event data of specific event. For example, the watch point event data is declared as :cpp:type:`pcnt_watch_event_data_t`:
|
||||
.. only:: SOC_PCNT_SUPPORT_STEP_NOTIFY
|
||||
|
||||
- :cpp:member:`pcnt_watch_event_data_t::watch_point_value` saves the watch point value that triggers the event.
|
||||
- :cpp:member:`pcnt_watch_event_data_t::zero_cross_mode` saves how the PCNT unit crosses the zero point in the latest time. The possible zero cross modes are listed in the :cpp:type:`pcnt_unit_zero_cross_mode_t`. Usually different zero cross mode means different **counting direction** and **counting step size**.
|
||||
In the callback function, the driver will fill in the event data of specific event. For example, the watch point event or watch step event data is declared as :cpp:type:`pcnt_watch_event_data_t`:
|
||||
|
||||
.. only:: not SOC_PCNT_SUPPORT_STEP_NOTIFY
|
||||
|
||||
In the callback function, the driver will fill in the event data of specific event. For example, the watch point event data is declared as :cpp:type:`pcnt_watch_event_data_t`:
|
||||
|
||||
.. list::
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - :cpp:member:`pcnt_watch_event_data_t::watch_point_value` saves the watch point value or watch step value that triggers the event.
|
||||
:not SOC_PCNT_SUPPORT_STEP_NOTIFY: - :cpp:member:`pcnt_watch_event_data_t::watch_point_value` saves the watch point value that triggers the event.
|
||||
- :cpp:member:`pcnt_watch_event_data_t::zero_cross_mode` saves how the PCNT unit crosses the zero point in the latest time. The possible zero cross modes are listed in the :cpp:type:`pcnt_unit_zero_cross_mode_t`. Usually different zero cross mode means different **counting direction** and **counting step size**.
|
||||
|
||||
Registering callback function results in lazy installation of interrupt service, thus this function should only be called before the unit is enabled by :cpp:func:`pcnt_unit_enable`. Otherwise, it can return :c:macro:`ESP_ERR_INVALID_STATE` error.
|
||||
|
||||
@@ -284,7 +326,10 @@ The internal hardware counter will be cleared to zero automatically when it reac
|
||||
|
||||
.. note::
|
||||
|
||||
:cpp:func:`pcnt_unit_clear_count` resets the accumulated count value as well.
|
||||
.. list::
|
||||
|
||||
- :cpp:func:`pcnt_unit_clear_count` resets the accumulated count value as well.
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - setting the watch step will also enable the accumulator.
|
||||
|
||||
.. _pcnt-power-management:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user