summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Hogg <me@jonathanhogg.com>2022-09-12 18:37:22 +0100
committerDamien George <damien@micropython.org>2025-08-02 00:00:03 +1000
commit641ca2eb0624fc0df2b358f1a4652525af123fd7 (patch)
tree42d2585a96a49aeeece189b3d10824414dfcd632
parent327655905e9f523070301f2f35459197d46db4fb (diff)
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>
-rw-r--r--docs/esp32/quickref.rst15
-rw-r--r--docs/library/esp32.rst3
-rw-r--r--docs/library/machine.Counter.rst93
-rw-r--r--docs/library/machine.Encoder.rst72
-rw-r--r--docs/library/machine.rst2
-rw-r--r--docs/reference/glossary.rst7
6 files changed, 192 insertions, 0 deletions
diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 7127cc402..2c667a0f0 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -587,6 +587,21 @@ Use the :ref:`esp32.PCNT <esp32.PCNT>` class::
The PCNT hardware supports monitoring multiple pins in a single unit to
implement quadrature decoding or up/down signal counters.
+See the :ref:`machine.Counter <machine.Counter>` and
+:ref:`machine.Encoder <machine.Encoder>` classes for simpler abstractions of
+common pulse counting applications::
+
+ from machine import Pin, Counter
+
+ counter = Counter(0, Pin(2)) # create a counter as above and start it
+ count = counter.value() # read the count as an arbitrary precision signed integer
+
+ encoder = Encoder(0, Pin(12), Pin(14)) # create an encoder and begin counting
+ count = encoder.value() # read the count as an arbitrary precision signed integer
+
+Note that the id passed to these ``Counter()`` and ``Encoder()`` objects must be
+a PCNT id.
+
Software SPI bus
----------------
diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst
index 0cf0ebc62..e5f39c7f5 100644
--- a/docs/library/esp32.rst
+++ b/docs/library/esp32.rst
@@ -336,6 +336,9 @@ implemented as thin Python shims around :class:`PCNT`.
value. Thus the ``IRQ_ZERO`` event will also trigger when either of these
events occurs.
+See the :ref:`machine.Counter <machine.Counter>` and
+:ref:`machine.Encoder <machine.Encoder>` classes for simpler abstractions of
+common pulse counting applications.
.. _esp32.RMT:
diff --git a/docs/library/machine.Counter.rst b/docs/library/machine.Counter.rst
new file mode 100644
index 000000000..f89a6d5b4
--- /dev/null
+++ b/docs/library/machine.Counter.rst
@@ -0,0 +1,93 @@
+.. currentmodule:: machine
+.. _machine.Counter:
+
+class Counter -- pulse counter
+==============================
+
+Counter implements pulse counting by monitoring an input signal and counting
+rising or falling edges.
+
+Minimal example usage::
+
+ from machine import Pin, Counter
+
+ counter = Counter(0, Pin(0, Pin.IN)) # create Counter for pin 0 and begin counting
+ value = counter.value() # retrieve current pulse count
+
+Availability: **ESP32**
+
+Constructors
+------------
+
+.. class:: Counter(id, ...)
+
+ Returns the singleton Counter object for the the given *id*. Values of *id*
+ depend on a particular port and its hardware. Values 0, 1, etc. are commonly
+ used to select hardware block #0, #1, etc.
+
+ Additional arguments are passed to the :meth:`init` method described below,
+ and will cause the Counter instance to be re-initialised and reset.
+
+ On ESP32, the *id* corresponds to a :ref:`PCNT unit <esp32.PCNT>`.
+
+Methods
+-------
+
+.. method:: Counter.init(src, *, ...)
+
+ Initialise and reset the Counter with the given parameters:
+
+ - *src* specifies the input pin as a :ref:`machine.Pin <machine.Pin>` object.
+ May be omitted on ports that have a predefined pin for a given hardware
+ block.
+
+ Additional keyword-only parameters that may be supported by a port are:
+
+ - *edge* specifies the edge to count. Either ``Counter.RISING`` (the default)
+ or ``Counter.FALLING``. *(Supported on ESP32)*
+
+ - *direction* specifies the direction to count. Either ``Counter.UP`` (the
+ default) or ``Counter.DOWN``. *(Supported on ESP32)*
+
+ - *filter_ns* specifies a minimum period of time in nanoseconds that the
+ source signal needs to be stable for a pulse to be counted. Implementations
+ should use the longest filter supported by the hardware that is less than
+ or equal to this value. The default is 0 (no filter). *(Supported on ESP32)*
+
+.. method:: Counter.deinit()
+
+ Stops the Counter, disabling any interrupts and releasing hardware resources.
+ A Soft Reset should deinitialize all Counter objects.
+
+.. method:: Counter.value([value])
+
+ Get, and optionally set, the counter value as a signed integer.
+ Implementations must aim to do the get and set atomically (i.e. without
+ leading to skipped counts).
+
+ This counter value could exceed the range of a :term:`small integer`, which
+ means that calling :meth:`Counter.value` could cause a heap allocation, but
+ implementations should aim to ensure that internal state only uses small
+ integers and therefore will not allocate until the user calls
+ :meth:`Counter.value`.
+
+ For example, on ESP32, the internal state counts overflows of the hardware
+ counter (every 32000 counts), which means that it will not exceed the small
+ integer range until ``2**30 * 32000`` counts (slightly over 1 year at 1MHz).
+
+ In general, it is recommended that you should use ``Counter.value(0)`` to reset
+ the counter (i.e. to measure the counts since the last call), and this will
+ avoid this problem.
+
+Constants
+---------
+
+.. data:: Counter.RISING
+ Counter.FALLING
+
+ Select the pulse edge.
+
+.. data:: Counter.UP
+ Counter.DOWN
+
+ Select the counting direction.
diff --git a/docs/library/machine.Encoder.rst b/docs/library/machine.Encoder.rst
new file mode 100644
index 000000000..fc2de3208
--- /dev/null
+++ b/docs/library/machine.Encoder.rst
@@ -0,0 +1,72 @@
+.. currentmodule:: machine
+.. _machine.Encoder:
+
+class Encoder -- quadrature decoding
+====================================
+
+Encoder implements decoding of quadrature signals as commonly output from
+rotary encoders, by counting either up or down depending on the order of two
+input pulses.
+
+Minimal example usage::
+
+ from machine import Pin, Encoder
+
+ counter = Counter(0, Pin(0, Pin.IN), Pin(1, Pin.IN)) # create Encoder for pins 0, 1 and begin counting
+ value = counter.value() # retrieve current count
+
+Availability: **ESP32**
+
+Constructors
+------------
+
+.. class:: Encoder(id, ...)
+
+ Returns the singleton Encoder object for the the given *id*. Values of *id*
+ depend on a particular port and its hardware. Values 0, 1, etc. are commonly
+ used to select hardware block #0, #1, etc.
+
+ Additional arguments are passed to the :meth:`init` method described below,
+ and will cause the Encoder instance to be re-initialised and reset.
+
+ On ESP32, the *id* corresponds to a :ref:`PCNT unit <esp32.PCNT>`.
+
+Methods
+-------
+
+.. method:: Encoder.init(phase_a, phase_b, *, ...)
+
+ Initialise and reset the Encoder with the given parameters:
+
+ - *phase_a* specifies the first input pin as a
+ :ref:`machine.Pin <machine.Pin>` object.
+
+ - *phase_b* specifies the second input pin as a
+ :ref:`machine.Pin <machine.Pin>` object.
+
+ These pins may be omitted on ports that have predefined pins for a given
+ hardware block.
+
+ Additional keyword-only parameters that may be supported by a port are:
+
+ - *filter_ns* specifies a minimum period of time in nanoseconds that the
+ source signal needs to be stable for a pulse to be counted. Implementations
+ should use the longest filter supported by the hardware that is less than
+ or equal to this value. The default is 0 (no filter). *(Supported on ESP32)*
+
+ - *phases* specifies the number of signal edges to count and thus the
+ granularity of the decoding. e.g. 4 phases corresponds to "4x quadrature
+ decoding", and will result in four counts per pulse. Ports may support
+ either 1, 2, or 4 phases and the default is 1 phase. *(Supported on ESP32)*
+
+.. method:: Encoder.deinit()
+
+ Stops the Encoder, disabling any interrupts and releasing hardware resources.
+ A Soft Reset should deinitialize all Encoder objects.
+
+.. method:: Encoder.value([value])
+
+ Get, and optionally set, the encoder value as a signed integer.
+ Implementations should aim to do the get and set atomically.
+
+ See :meth:`machine.Counter.value` for details about overflow of this value.
diff --git a/docs/library/machine.rst b/docs/library/machine.rst
index 3c22aa9af..7acaddde8 100644
--- a/docs/library/machine.rst
+++ b/docs/library/machine.rst
@@ -268,6 +268,8 @@ Classes
machine.I2S.rst
machine.RTC.rst
machine.Timer.rst
+ machine.Counter.rst
+ machine.Encoder.rst
machine.WDT.rst
machine.SD.rst
machine.SDCard.rst
diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst
index efaa8f607..ab0b22049 100644
--- a/docs/reference/glossary.rst
+++ b/docs/reference/glossary.rst
@@ -188,6 +188,13 @@ Glossary
Most MicroPython boards make a REPL available over a UART, and this is
typically accessible on a host PC via USB.
+ small integer
+ MicroPython optimises the internal representation of integers such that
+ "small" values do not take up space on the heap, and calculations with
+ them do not require heap allocation. On most 32-bit ports, this
+ corresponds to values in the interval ``-2**30 <= x < 2**30``, but this
+ should be considered an implementation detail and not relied upon.
+
stream
Also known as a "file-like object". A Python object which provides
sequential read-write access to the underlying data. A stream object