docs/esp32: Add documentation for esp32.PCNT.
Document the new `esp32.PCNT` class for hardware pulse counting. Originally authored by: Jonathan Hogg <me@jonathanhogg.com> Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This commit is contained in:
committed by
Damien George
parent
c3f3339c87
commit
e54553c496
@@ -566,6 +566,27 @@ ESP32 S2:
|
|||||||
|
|
||||||
Provided to deinit the adc driver.
|
Provided to deinit the adc driver.
|
||||||
|
|
||||||
|
Pulse Counter (pin pulse/edge counting)
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
The ESP32 provides up to 8 pulse counter peripherals depending on the hardware,
|
||||||
|
with id 0..7. These can be configured to count rising and/or falling edges on
|
||||||
|
any input pin.
|
||||||
|
|
||||||
|
Use the :ref:`esp32.PCNT <esp32.PCNT>` class::
|
||||||
|
|
||||||
|
from machine import Pin
|
||||||
|
from esp32 import PCNT
|
||||||
|
|
||||||
|
counter = PCNT(0, pin=Pin(2), rising=PCNT.INCREMENT) # create counter
|
||||||
|
counter.start() # start counter
|
||||||
|
count = counter.value() # read count, -32768..32767
|
||||||
|
counter.value(0) # reset counter
|
||||||
|
count = counter.value(0) # read and reset
|
||||||
|
|
||||||
|
The PCNT hardware supports monitoring multiple pins in a single unit to
|
||||||
|
implement quadrature decoding or up/down signal counters.
|
||||||
|
|
||||||
Software SPI bus
|
Software SPI bus
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,148 @@ Constants
|
|||||||
|
|
||||||
Used in `idf_heap_info`.
|
Used in `idf_heap_info`.
|
||||||
|
|
||||||
|
|
||||||
|
.. _esp32.PCNT:
|
||||||
|
|
||||||
|
PCNT
|
||||||
|
----
|
||||||
|
|
||||||
|
This class provides access to the ESP32 hardware support for pulse counting.
|
||||||
|
There are 8 pulse counter units, with id 0..7.
|
||||||
|
|
||||||
|
See the :ref:`machine.Counter <machine.Counter>` and
|
||||||
|
:ref:`machine.Encoder <machine.Encoder>` classes for simpler and portable
|
||||||
|
abstractions of common pulse counting applications. These classes are
|
||||||
|
implemented as thin Python shims around :class:`PCNT`.
|
||||||
|
|
||||||
|
.. class:: PCNT(id, *, ...)
|
||||||
|
|
||||||
|
Returns the singleton PCNT instance for the given unit ``id``.
|
||||||
|
|
||||||
|
Keyword arguments are passed to the ``init()`` method as described
|
||||||
|
below.
|
||||||
|
|
||||||
|
.. method:: PCNT.init(*, ...)
|
||||||
|
|
||||||
|
(Re-)initialise a pulse counter unit. Supported keyword arguments are:
|
||||||
|
|
||||||
|
- ``channel``: see description below
|
||||||
|
- ``pin``: the input Pin to monitor for pulses
|
||||||
|
- ``rising``: an action to take on a rising edge - one of
|
||||||
|
``PCNT.INCREMENT``, ``PCNT.DECREMENT`` or ``PCNT.IGNORE`` (the default)
|
||||||
|
- ``falling``: an action to take on a falling edge (takes the save values
|
||||||
|
as the ``rising`` argument).
|
||||||
|
- ``mode_pin``: ESP32 pulse counters support monitoring a second pin and
|
||||||
|
altering the behaviour of the counter based on its level - set this
|
||||||
|
keyword to any input Pin
|
||||||
|
- ``mode_low``: set to either ``PCNT.HOLD`` or ``PCNT.REVERSE`` to
|
||||||
|
either suspend counting or reverse the direction of the counter (i.e.,
|
||||||
|
``PCNT.INCREMENT`` behaves as ``PCNT.DECREMENT`` and vice versa)
|
||||||
|
when ``mode_pin`` is low
|
||||||
|
- ``mode_high``: as ``mode_low`` but for the behaviour when ``mode_pin``
|
||||||
|
is high
|
||||||
|
- ``filter``: set to a value 1..1023, in ticks of the 80MHz clock, to
|
||||||
|
enable the pulse width filter
|
||||||
|
- ``min``: set to the minimum level of the counter value when
|
||||||
|
decrementing (-32768..-1) or 0 to disable
|
||||||
|
- ``max``: set to the maximum level of the counter value when
|
||||||
|
incrementing (1..32767) or 0 to disable
|
||||||
|
- ``threshold0``: sets the counter value for the
|
||||||
|
``PCNT.IRQ_THRESHOLD0`` event (see ``irq`` method)
|
||||||
|
- ``threshold1``: sets the counter value for the
|
||||||
|
``PCNT.IRQ_THRESHOLD1`` event (see ``irq`` method)
|
||||||
|
- ``value``: can be set to ``0`` to reset the counter value
|
||||||
|
|
||||||
|
The hardware initialisation is done in stages and so some of the keyword
|
||||||
|
arguments can be used in groups or in isolation to partially reconfigure a
|
||||||
|
unit:
|
||||||
|
|
||||||
|
- the ``pin`` keyword (optionally combined with ``mode_pin``) can be used
|
||||||
|
to change just the bound pin(s)
|
||||||
|
- ``rising``, ``falling``, ``mode_low`` and ``mode_high`` can be used
|
||||||
|
(singly or together) to change the counting logic - omitted keywords
|
||||||
|
use their default (``PCNT.IGNORE`` or ``PCNT.NORMAL``)
|
||||||
|
- ``filter`` can be used to change only the pulse width filter (with 0
|
||||||
|
disabling it)
|
||||||
|
- each of ``min``, ``max``, ``threshold0`` and ``threshold1`` can
|
||||||
|
be used to change these limit/event values individually; however,
|
||||||
|
setting any will reset the counter to zero (i.e., they imply
|
||||||
|
``value=0``)
|
||||||
|
|
||||||
|
Each pulse counter unit supports two channels, 0 and 1, each able to
|
||||||
|
monitor different pins with different counting logic but updating the same
|
||||||
|
counter value. Use ``channel=1`` with the ``pin``, ``rising``, ``falling``,
|
||||||
|
``mode_pin``, ``mode_low`` and ``mode_high`` keywords to configure the
|
||||||
|
second channel.
|
||||||
|
|
||||||
|
The second channel can be used to configure 4X quadrature decoding with a
|
||||||
|
single counter unit::
|
||||||
|
|
||||||
|
pin_a = Pin(2, Pin.INPUT, pull=Pin.PULL_UP)
|
||||||
|
pin_b = Pin(3, Pin.INPUT, pull=Pin.PULL_UP)
|
||||||
|
rotary = PCNT(0, min=-32000, max=32000)
|
||||||
|
rotary.init(channel=0, pin=pin_a, falling=PCNT.INCREMENT, rising=PCNT.DECREMENT, mode_pin=pin_b, mode_low=PCNT.REVERSE)
|
||||||
|
rotary.init(channel=1, pin=pin_b, falling=PCNT.DECREMENT, rising=PCNT.INCREMENT, mode_pin=pin_a, mode_low=PCNT.REVERSE)
|
||||||
|
rotary.start()
|
||||||
|
|
||||||
|
.. method:: PCNT.value([value])
|
||||||
|
|
||||||
|
Call this method with no arguments to return the current counter value.
|
||||||
|
|
||||||
|
If the optional *value* argument is set to ``0`` then the counter is
|
||||||
|
reset (but the previous value is returned). Read and reset is not atomic and
|
||||||
|
so it is possible for a pulse to be missed. Any value other than ``0`` will
|
||||||
|
raise an error.
|
||||||
|
|
||||||
|
.. method:: PCNT.irq(handler=None, trigger=PCNT.IRQ_ZERO)
|
||||||
|
|
||||||
|
ESP32 pulse counters support interrupts on these counter events:
|
||||||
|
|
||||||
|
- ``PCNT.IRQ_ZERO``: the counter has reset to zero
|
||||||
|
- ``PCNT.IRQ_MIN``: the counter has hit the ``min`` value
|
||||||
|
- ``PCNT.IRQ_MAX``: the counter has hit the ``max`` value
|
||||||
|
- ``PCNT.IRQ_THRESHOLD0``: the counter has hit the ``threshold0`` value
|
||||||
|
- ``PCNT.IRQ_THRESHOLD1``: the counter has hit the ``threshold1`` value
|
||||||
|
|
||||||
|
``trigger`` should be a bit-mask of the desired events OR'ed together. The
|
||||||
|
``handler`` function should take a single argument which is the
|
||||||
|
:class:`PCNT` instance that raised the event.
|
||||||
|
|
||||||
|
This method returns a callback object. The callback object can be used to
|
||||||
|
access the bit-mask of events that are outstanding on the PCNT unit.::
|
||||||
|
|
||||||
|
def pcnt_irq(pcnt):
|
||||||
|
flags = pcnt.irq().flags()
|
||||||
|
if flags & PCNT.IRQ_ZERO:
|
||||||
|
# reset
|
||||||
|
if flags & PCNT.IRQ_MAX:
|
||||||
|
# overflow...
|
||||||
|
... etc
|
||||||
|
|
||||||
|
pcnt.irq(handler=pcnt_irq, trigger=PCNT.IRQ_ZERO | PCNT.IRQ_MAX | ...)
|
||||||
|
|
||||||
|
**Note:** Accessing ``irq.flags()`` will clear the flags, so only call it
|
||||||
|
once per invocation of the handler.
|
||||||
|
|
||||||
|
The handler is called with the MicroPython scheduler and so will run at a
|
||||||
|
point after the interrupt. If another interrupt occurs before the handler
|
||||||
|
has been called then the events will be coalesced together into a single
|
||||||
|
call and the bit mask will indicate all events that have occurred.
|
||||||
|
|
||||||
|
To avoid race conditions between a handler being called and retrieving the
|
||||||
|
current counter value, the ``value()`` method will force execution of any
|
||||||
|
pending events before returning the current counter value (and potentially
|
||||||
|
resetting the value).
|
||||||
|
|
||||||
|
Only one handler can be in place per-unit. Set ``handler`` to ``None`` to
|
||||||
|
disable the event interrupt.
|
||||||
|
|
||||||
|
.. Note::
|
||||||
|
ESP32 pulse counters reset to *zero* when reaching the minimum or maximum
|
||||||
|
value. Thus the ``IRQ_ZERO`` event will also trigger when either of these
|
||||||
|
events occurs.
|
||||||
|
|
||||||
|
|
||||||
.. _esp32.RMT:
|
.. _esp32.RMT:
|
||||||
|
|
||||||
RMT
|
RMT
|
||||||
|
|||||||
Reference in New Issue
Block a user