Skip to content

Commit e54553c

Browse files
jonathanhoggdpgeorge
authored andcommitted
docs/esp32: Add documentation for esp32.PCNT.
Document the new `esp32.PCNT` class for hardware pulse counting. Originally authored by: Jonathan Hogg <[email protected]> Signed-off-by: Jim Mussared <[email protected]>
1 parent c3f3339 commit e54553c

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

docs/esp32/quickref.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,27 @@ ESP32 S2:
566566

567567
Provided to deinit the adc driver.
568568

569+
Pulse Counter (pin pulse/edge counting)
570+
---------------------------------------
571+
572+
The ESP32 provides up to 8 pulse counter peripherals depending on the hardware,
573+
with id 0..7. These can be configured to count rising and/or falling edges on
574+
any input pin.
575+
576+
Use the :ref:`esp32.PCNT <esp32.PCNT>` class::
577+
578+
from machine import Pin
579+
from esp32 import PCNT
580+
581+
counter = PCNT(0, pin=Pin(2), rising=PCNT.INCREMENT) # create counter
582+
counter.start() # start counter
583+
count = counter.value() # read count, -32768..32767
584+
counter.value(0) # reset counter
585+
count = counter.value(0) # read and reset
586+
587+
The PCNT hardware supports monitoring multiple pins in a single unit to
588+
implement quadrature decoding or up/down signal counters.
589+
569590
Software SPI bus
570591
----------------
571592

docs/library/esp32.rst

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,148 @@ Constants
195195

196196
Used in `idf_heap_info`.
197197

198+
199+
.. _esp32.PCNT:
200+
201+
PCNT
202+
----
203+
204+
This class provides access to the ESP32 hardware support for pulse counting.
205+
There are 8 pulse counter units, with id 0..7.
206+
207+
See the :ref:`machine.Counter <machine.Counter>` and
208+
:ref:`machine.Encoder <machine.Encoder>` classes for simpler and portable
209+
abstractions of common pulse counting applications. These classes are
210+
implemented as thin Python shims around :class:`PCNT`.
211+
212+
.. class:: PCNT(id, *, ...)
213+
214+
Returns the singleton PCNT instance for the given unit ``id``.
215+
216+
Keyword arguments are passed to the ``init()`` method as described
217+
below.
218+
219+
.. method:: PCNT.init(*, ...)
220+
221+
(Re-)initialise a pulse counter unit. Supported keyword arguments are:
222+
223+
- ``channel``: see description below
224+
- ``pin``: the input Pin to monitor for pulses
225+
- ``rising``: an action to take on a rising edge - one of
226+
``PCNT.INCREMENT``, ``PCNT.DECREMENT`` or ``PCNT.IGNORE`` (the default)
227+
- ``falling``: an action to take on a falling edge (takes the save values
228+
as the ``rising`` argument).
229+
- ``mode_pin``: ESP32 pulse counters support monitoring a second pin and
230+
altering the behaviour of the counter based on its level - set this
231+
keyword to any input Pin
232+
- ``mode_low``: set to either ``PCNT.HOLD`` or ``PCNT.REVERSE`` to
233+
either suspend counting or reverse the direction of the counter (i.e.,
234+
``PCNT.INCREMENT`` behaves as ``PCNT.DECREMENT`` and vice versa)
235+
when ``mode_pin`` is low
236+
- ``mode_high``: as ``mode_low`` but for the behaviour when ``mode_pin``
237+
is high
238+
- ``filter``: set to a value 1..1023, in ticks of the 80MHz clock, to
239+
enable the pulse width filter
240+
- ``min``: set to the minimum level of the counter value when
241+
decrementing (-32768..-1) or 0 to disable
242+
- ``max``: set to the maximum level of the counter value when
243+
incrementing (1..32767) or 0 to disable
244+
- ``threshold0``: sets the counter value for the
245+
``PCNT.IRQ_THRESHOLD0`` event (see ``irq`` method)
246+
- ``threshold1``: sets the counter value for the
247+
``PCNT.IRQ_THRESHOLD1`` event (see ``irq`` method)
248+
- ``value``: can be set to ``0`` to reset the counter value
249+
250+
The hardware initialisation is done in stages and so some of the keyword
251+
arguments can be used in groups or in isolation to partially reconfigure a
252+
unit:
253+
254+
- the ``pin`` keyword (optionally combined with ``mode_pin``) can be used
255+
to change just the bound pin(s)
256+
- ``rising``, ``falling``, ``mode_low`` and ``mode_high`` can be used
257+
(singly or together) to change the counting logic - omitted keywords
258+
use their default (``PCNT.IGNORE`` or ``PCNT.NORMAL``)
259+
- ``filter`` can be used to change only the pulse width filter (with 0
260+
disabling it)
261+
- each of ``min``, ``max``, ``threshold0`` and ``threshold1`` can
262+
be used to change these limit/event values individually; however,
263+
setting any will reset the counter to zero (i.e., they imply
264+
``value=0``)
265+
266+
Each pulse counter unit supports two channels, 0 and 1, each able to
267+
monitor different pins with different counting logic but updating the same
268+
counter value. Use ``channel=1`` with the ``pin``, ``rising``, ``falling``,
269+
``mode_pin``, ``mode_low`` and ``mode_high`` keywords to configure the
270+
second channel.
271+
272+
The second channel can be used to configure 4X quadrature decoding with a
273+
single counter unit::
274+
275+
pin_a = Pin(2, Pin.INPUT, pull=Pin.PULL_UP)
276+
pin_b = Pin(3, Pin.INPUT, pull=Pin.PULL_UP)
277+
rotary = PCNT(0, min=-32000, max=32000)
278+
rotary.init(channel=0, pin=pin_a, falling=PCNT.INCREMENT, rising=PCNT.DECREMENT, mode_pin=pin_b, mode_low=PCNT.REVERSE)
279+
rotary.init(channel=1, pin=pin_b, falling=PCNT.DECREMENT, rising=PCNT.INCREMENT, mode_pin=pin_a, mode_low=PCNT.REVERSE)
280+
rotary.start()
281+
282+
.. method:: PCNT.value([value])
283+
284+
Call this method with no arguments to return the current counter value.
285+
286+
If the optional *value* argument is set to ``0`` then the counter is
287+
reset (but the previous value is returned). Read and reset is not atomic and
288+
so it is possible for a pulse to be missed. Any value other than ``0`` will
289+
raise an error.
290+
291+
.. method:: PCNT.irq(handler=None, trigger=PCNT.IRQ_ZERO)
292+
293+
ESP32 pulse counters support interrupts on these counter events:
294+
295+
- ``PCNT.IRQ_ZERO``: the counter has reset to zero
296+
- ``PCNT.IRQ_MIN``: the counter has hit the ``min`` value
297+
- ``PCNT.IRQ_MAX``: the counter has hit the ``max`` value
298+
- ``PCNT.IRQ_THRESHOLD0``: the counter has hit the ``threshold0`` value
299+
- ``PCNT.IRQ_THRESHOLD1``: the counter has hit the ``threshold1`` value
300+
301+
``trigger`` should be a bit-mask of the desired events OR'ed together. The
302+
``handler`` function should take a single argument which is the
303+
:class:`PCNT` instance that raised the event.
304+
305+
This method returns a callback object. The callback object can be used to
306+
access the bit-mask of events that are outstanding on the PCNT unit.::
307+
308+
def pcnt_irq(pcnt):
309+
flags = pcnt.irq().flags()
310+
if flags & PCNT.IRQ_ZERO:
311+
# reset
312+
if flags & PCNT.IRQ_MAX:
313+
# overflow...
314+
... etc
315+
316+
pcnt.irq(handler=pcnt_irq, trigger=PCNT.IRQ_ZERO | PCNT.IRQ_MAX | ...)
317+
318+
**Note:** Accessing ``irq.flags()`` will clear the flags, so only call it
319+
once per invocation of the handler.
320+
321+
The handler is called with the MicroPython scheduler and so will run at a
322+
point after the interrupt. If another interrupt occurs before the handler
323+
has been called then the events will be coalesced together into a single
324+
call and the bit mask will indicate all events that have occurred.
325+
326+
To avoid race conditions between a handler being called and retrieving the
327+
current counter value, the ``value()`` method will force execution of any
328+
pending events before returning the current counter value (and potentially
329+
resetting the value).
330+
331+
Only one handler can be in place per-unit. Set ``handler`` to ``None`` to
332+
disable the event interrupt.
333+
334+
.. Note::
335+
ESP32 pulse counters reset to *zero* when reaching the minimum or maximum
336+
value. Thus the ``IRQ_ZERO`` event will also trigger when either of these
337+
events occurs.
338+
339+
198340
.. _esp32.RMT:
199341

200342
RMT

0 commit comments

Comments
 (0)