Skip to content

Commit 0ae56c7

Browse files
jonathanhoggjimmo
authored andcommitted
docs/library/machine: Add docs for Counter and Encoder.
Add documentation for `machine.Counter` and `machine.Encoder` as currently implemented by the esp32 port, but intended to be implemented by other ports. Originally authored by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com> and Jonathan Hogg <me@jonathanhogg.com>. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
1 parent 8ba37ce commit 0ae56c7

File tree

6 files changed

+194
-0
lines changed

6 files changed

+194
-0
lines changed

docs/esp32/quickref.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,26 @@ Use the :ref:`esp32.PCNT <esp32.PCNT>` class::
445445
counter.value(0) # reset counter
446446
count = counter.value(0) # read and reset
447447

448+
The PCNT hardware supports monitoring multiple pins in a single unit to
449+
implement quadrature decoding or up/down signal counters.
450+
451+
See the :ref:`machine.Counter <machine.Counter>` and
452+
:ref:`machine.Encoder <machine.Encoder>` classes for simpler abstractions of
453+
common pulse counting applications. These classes are implemented as thin Python
454+
shims around the ``PCNT()`` class::
455+
456+
from machine import Pin, Counter
457+
458+
counter = Counter(0, Pin(2)) # create a counter as above and start it
459+
count = counter.value() # read the count as an arbitrary precision signed integer
460+
461+
encoder = Encoder(0, Pin(12), Pin(14)) # create an encoder and begin counting
462+
count = encoder.value() # read the count as an arbitrary precision signed integer
463+
464+
Note that the id of these ``Counter()`` and ``Encoder()`` objects is an
465+
arbitrary number, each uniquely identified object will be allocated a free PCNT
466+
unit.
467+
448468

449469
Software SPI bus
450470
----------------

docs/library/esp32.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ abstractions of common pulse counting applications.
275275
value. Thus the ``IRQ_ZERO`` event will also trigger when either of these
276276
events occurs.
277277

278+
See the :ref:`machine.Counter <machine.Counter>` and
279+
:ref:`machine.Encoder <machine.Encoder>` classes for simpler abstractions of
280+
common pulse counting applications.
281+
278282

279283
.. _esp32.RMT:
280284

docs/library/machine.Counter.rst

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
.. currentmodule:: machine
2+
.. _machine.Counter:
3+
4+
class Counter -- pulse counter
5+
==============================
6+
7+
Counter implements pulse counting by monitoring an input signal and counting
8+
rising or falling edges.
9+
10+
Minimal example usage::
11+
12+
from machine import Pin, Counter
13+
14+
counter = Counter(0, Pin(0, Pin.IN)) # create Counter for pin 0 and begin counting
15+
value = counter.value() # retrieve current pulse count
16+
17+
Availability: **ESP32**
18+
19+
Constructors
20+
------------
21+
22+
.. class:: Counter(id, ...)
23+
24+
Construct a Counter object with the given id. Values of *id* depend on a
25+
particular port and its hardware. Values 0, 1, etc. are commonly used to
26+
select hardware block #0, #1, etc. Additional arguments are passed to the
27+
``init()`` method described below.
28+
29+
On ESP32, the *id* corresponds to a :ref:`PCNT unit <esp32.PCNT>`.
30+
31+
Methods
32+
-------
33+
34+
.. method:: Counter.init(src, *, ...)
35+
36+
Initialise and reset the Counter with the given parameters:
37+
38+
- *src* specifies the input pin as a :ref:`machine.Pin <machine.Pin>` object.
39+
May be omitted on ports that have a predefined pin for a given hardware
40+
block.
41+
42+
Additional keyword-only parameters that may be supported by a port are:
43+
44+
- *edge* specifies the edge to count. Either ``Counter.RISING`` (the default)
45+
or ``Counter.FALLING``. *(Supported on ESP32)*
46+
47+
- *direction* specifies the direction to count. Either ``Counter.UP`` (the
48+
default) or ``Counter.DOWN``. *(Supported on ESP32)*
49+
50+
- *filter_ns* specifies a minimum period of time in nanoseconds that the
51+
source signal needs to be stable for a pulse to be counted. Implementations
52+
should use the longest filter supported by the hardware that is less than
53+
or equal to this value. The default is 0 (no filter). *(Supported on ESP32)*
54+
55+
.. method:: Counter.deinit()
56+
57+
Stops the Counter, disabling any interrupts and releasing hardware resources.
58+
A Soft Reset should deinitialize all Counter objects.
59+
60+
.. method:: Counter.value([value])
61+
62+
Get, and optionally set, the counter value as a signed integer.
63+
Implementations must aim to do the get and set atomically (i.e. without
64+
leading to skipped counts).
65+
66+
This counter value could exceed the range of a :term:`small integer`, which
67+
means that calling :meth:`Counter.value` could cause a heap allocation, but
68+
implementations should aim to ensure that internal state only uses small
69+
integers and therefore will not allocate until the user calls
70+
:meth:`Counter.value`.
71+
72+
For example, on ESP32, the internal state counts overflows of the hardware
73+
counter (every 32000 counts), which means that it will not exceed the small
74+
integer range until ``2**30 * 32000`` counts (slightly over 1 year at 1MHz).
75+
76+
In general, it is recommended that you should use ``Counter.value(0)`` to reset
77+
the counter (i.e. to measure the counts since the last call), and this will
78+
avoid this problem.
79+
80+
Constants
81+
---------
82+
83+
.. data:: Counter.RISING
84+
Counter.FALLING
85+
86+
Select the pulse edge.
87+
88+
.. data:: Counter.UP
89+
Counter.DOWN
90+
91+
Select the counting direction.

docs/library/machine.Encoder.rst

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
.. currentmodule:: machine
2+
.. _machine.Encoder:
3+
4+
class Encoder -- quadrature decoding
5+
====================================
6+
7+
Encoder implements decoding of quadrature signals as commonly output from
8+
rotary encoders, by counting either up or down depending on the order of two
9+
input pulses.
10+
11+
Minimal example usage::
12+
13+
from machine import Pin, Encoder
14+
15+
counter = Counter(0, Pin(0, Pin.IN), Pin(1, Pin.IN)) # create Encoder for pins 0, 1 and begin counting
16+
value = counter.value() # retrieve current count
17+
18+
Availability: **ESP32**
19+
20+
Constructors
21+
------------
22+
23+
.. class:: Encoder(id, ...)
24+
25+
Construct an Encoder object with the given id. Values of *id* depend on a
26+
particular port and its hardware. Values 0, 1, etc. are commonly used to
27+
select hardware block #0, #1, etc. Additional arguments are passed to the
28+
``init()`` method described below.
29+
30+
On ESP32, the *id* corresponds to a :ref:`PCNT unit <esp32.PCNT>`.
31+
32+
Methods
33+
-------
34+
35+
.. method:: Encoder.init(phase_a, phase_b, *, ...)
36+
37+
Initialise and reset the Encoder with the given parameters:
38+
39+
- *phase_a* specifies the first input pin as a
40+
:ref:`machine.Pin <machine.Pin>` object.
41+
42+
- *phase_a* specifies the second input pin as a
43+
:ref:`machine.Pin <machine.Pin>` object.
44+
45+
These pins may be omitted on ports that have predefined pins for a given
46+
hardware block.
47+
48+
Additional keyword-only parameters that may be supported by a port are:
49+
50+
- *filter_ns* specifies a minimum period of time in nanoseconds that the
51+
source signal needs to be stable for a pulse to be counted. Implementations
52+
should use the longest filter supported by the hardware that is less than
53+
or equal to this value. The default is 0 (no filter). *(Supported on ESP32)*
54+
55+
- *phases* specifies the number of signal edges to count and thus the
56+
granularity of the decoding. e.g. 4 phases corresponds to "4x quadrature
57+
decoding", and will result in four counts per pulse. Ports may support
58+
either 1, 2, or 4 phases and the default is 1 phase. *(Supported on ESP32)*
59+
60+
.. method:: Encoder.deinit()
61+
62+
Stops the Encoder, disabling any interrupts and releasing hardware resources.
63+
A Soft Reset should deinitialize all Encoder objects.
64+
65+
.. method:: Encoder.value([value])
66+
67+
Get, and optionally set, the encoder value as a signed integer.
68+
Implementations should aim to do the get and set atomically.
69+
70+
See :meth:`machine.Counter.value` for details about overflow of this value.

docs/library/machine.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ Classes
262262
machine.I2S.rst
263263
machine.RTC.rst
264264
machine.Timer.rst
265+
machine.Counter.rst
266+
machine.Encoder.rst
265267
machine.WDT.rst
266268
machine.SD.rst
267269
machine.SDCard.rst

docs/reference/glossary.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ Glossary
188188
Most MicroPython boards make a REPL available over a UART, and this is
189189
typically accessible on a host PC via USB.
190190

191+
small integer
192+
MicroPython optimises the internal representation of integers such that
193+
"small" values do not take up space on the heap, and calculations with
194+
them do not require heap allocation. On most 32-bit ports, this
195+
corresponds to values in the interval ``-2**30 <= x < 2**30``, but this
196+
should be considered an implementation detail and not relied upon.
197+
191198
stream
192199
Also known as a "file-like object". A Python object which provides
193200
sequential read-write access to the underlying data. A stream object

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy