esp32/esp32_rmt: Update RMT module to use the new RMT API.
Some checks failed
JavaScript code lint and formatting with Biome / eslint (push) Has been cancelled
Check code formatting / code-formatting (push) Has been cancelled
Check spelling with codespell / codespell (push) Has been cancelled
Build docs / build (push) Has been cancelled
Check examples / embedding (push) Has been cancelled
Package mpremote / build (push) Has been cancelled
.mpy file format and tools / test (push) Has been cancelled
Build ports metadata / build (push) Has been cancelled
alif port / build_alif (alif_ae3_build) (push) Has been cancelled
cc3200 port / build (push) Has been cancelled
esp32 port / build_idf (esp32_build_c2_c6) (push) Has been cancelled
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Has been cancelled
esp32 port / build_idf (esp32_build_s3_c3) (push) Has been cancelled
esp8266 port / build (push) Has been cancelled
mimxrt port / build (push) Has been cancelled
nrf port / build (push) Has been cancelled
powerpc port / build (push) Has been cancelled
qemu port / build_and_test_arm (bigendian) (push) Has been cancelled
qemu port / build_and_test_arm (sabrelite) (push) Has been cancelled
qemu port / build_and_test_arm (thumb_hardfp) (push) Has been cancelled
qemu port / build_and_test_arm (thumb_softfp) (push) Has been cancelled
qemu port / build_and_test_rv32 (push) Has been cancelled
qemu port / build_and_test_rv64 (push) Has been cancelled
renesas-ra port / build_renesas_ra_board (push) Has been cancelled
rp2 port / build (push) Has been cancelled
samd port / build (push) Has been cancelled
stm32 port / build_stm32 (stm32_misc_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_nucleo_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_pyb_build) (push) Has been cancelled
unix port / minimal (push) Has been cancelled
unix port / reproducible (push) Has been cancelled
unix port / standard (push) Has been cancelled
unix port / standard_v2 (push) Has been cancelled
unix port / coverage (push) Has been cancelled
unix port / coverage_32bit (push) Has been cancelled
unix port / nanbox (push) Has been cancelled
unix port / longlong (push) Has been cancelled
unix port / float (push) Has been cancelled
unix port / gil_enabled (push) Has been cancelled
unix port / stackless_clang (push) Has been cancelled
unix port / float_clang (push) Has been cancelled
unix port / settrace_stackless (push) Has been cancelled
unix port / repr_b (push) Has been cancelled
unix port / macos (push) Has been cancelled
unix port / qemu_mips (push) Has been cancelled
unix port / qemu_arm (push) Has been cancelled
unix port / qemu_riscv64 (push) Has been cancelled
unix port / sanitize_address (push) Has been cancelled
unix port / sanitize_undefined (push) Has been cancelled
webassembly port / build (push) Has been cancelled
windows port / build-vs (Debug, true, x64, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, true, x86, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, x64, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x86, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, true, x64, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, true, x64, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, true, x64, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, true, x64, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, true, x86, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, true, x86, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, true, x86, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, true, x86, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (push) Has been cancelled
windows port / cross-build-on-linux (push) Has been cancelled
zephyr port / build (push) Has been cancelled
Python code lint and formatting with ruff / ruff (push) Has been cancelled

The current `esp32.RMT` class uses a legacy API from ESP-IDF 4.x.  The
ESP-IDF 5.x offers a new API, which is overall better, and easier to
implement the RX side in the future.  This commit updates the module and
the documentation, preserving the current MicroPython RMT API as much as
possible.

The bitstream RMT implementation was updated as well, since ESP-IDF does
not allow firmware to reference legacy and new APIs at the same time (it
resets right after boot with an error message, even if neither module is
imported).

The documentation is updated accordingly.

Signed-off-by: Elvis Pfutzenreuter <elvis.pfutzenreuter@gmail.com>
This commit is contained in:
Elvis Pfutzenreuter
2024-11-22 20:38:58 -03:00
committed by Damien George
parent 27544a2d81
commit 2a3b9b0b4b
7 changed files with 392 additions and 241 deletions

View File

@@ -837,9 +837,9 @@ The RMT is ESP32-specific and allows generation of accurate digital pulses with
import esp32
from machine import Pin
r = esp32.RMT(0, pin=Pin(18), clock_div=8)
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
# The channel resolution is 100ns (1/(source_freq/clock_div)).
r = esp32.RMT(pin=Pin(18), resolution_hz=10000000)
r # RMT(pin=18, source_freq=80000000, resolution_hz=10000000)
# The channel resolution is based on resolution_hz, i.e. 100ns for 10000000
r.write_pulses((1, 20, 2, 40), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
The ESP32-C2 family does not include any RMT peripheral, so this class is
@@ -903,8 +903,7 @@ The APA106 driver extends NeoPixel, but internally uses a different colour order
``NeoPixel`` object.
For low-level driving of a NeoPixel see `machine.bitstream`.
This low-level driver uses an RMT channel by default. To configure this see
`RMT.bitstream_channel`.
This low-level driver uses an RMT channel by default.
APA102 (DotStar) uses a different driver as it has an additional clock pin.

View File

@@ -362,29 +362,24 @@ used to transmit or receive many other types of digital signals::
import esp32
from machine import Pin
r = esp32.RMT(0, pin=Pin(18), clock_div=8)
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8, idle_level=0)
r = esp32.RMT(pin=Pin(18), resolution_hz=10000000)
r # RMT(pin=18, source_freq=80000000, resolution_hz=10000000, idle_level=0)
# To apply a carrier frequency to the high output
r = esp32.RMT(0, pin=Pin(18), clock_div=8, tx_carrier=(38000, 50, 1))
r = esp32.RMT(pin=Pin(18), resolution_hz=10000000, tx_carrier=(38000, 50, 1))
# The channel resolution is 100ns (1/(source_freq/clock_div)).
# The channel resolution is 100ns (1/resolution_hz)
r.write_pulses((1, 20, 2, 40), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
The input to the RMT module is an 80MHz clock (in the future it may be able to
configure the input clock but, for now, it's fixed). ``clock_div`` *divides*
the clock input which determines the resolution of the RMT channel. The
numbers specified in ``write_pulses`` are multiplied by the resolution to
configure the input clock but, for now, it's fixed). ``resolution_hz`` determines
the resolution of the RMT channel. The numbers specified in ``write_pulses`` are
multiplied by the resolution to
define the pulses.
``clock_div`` is an 8-bit divider (0-255) and each pulse can be defined by
multiplying the resolution by a 15-bit (1-``PULSE_MAX``) number. There are eight
channels (0-7) and each can have a different clock divider.
So, in the example above, the 80MHz clock is divided by 8. Thus the
resolution is (1/(80Mhz/8)) 100ns. Since the ``start`` level is 0 and toggles
with each number, the bitstream is ``0101`` with durations of [100ns, 2000ns,
100ns, 4000ns].
So, in the example above, the resolution is resolution is (1/10Mhz) = 100ns.
Since the ``start`` level is 0 and toggles with each number, the bitstream is
``0101`` with durations of [100ns, 2000ns, 100ns, 4000ns].
For more details see Espressif's `ESP-IDF RMT documentation.
<https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html>`_.
@@ -395,13 +390,24 @@ For more details see Espressif's `ESP-IDF RMT documentation.
*beta feature* and the interface may change in the future.
.. class:: RMT(channel, *, pin=None, clock_div=8, idle_level=False, tx_carrier=None)
.. class:: RMT(channel, *, pin=None, resolution_hz=10000000, clock_div=None, idle_level=False, num_symbols=48|64, tx_carrier=None)
This class provides access to one of the eight RMT channels. *channel* is
required and identifies which RMT channel (0-7) will be configured. *pin*,
also required, configures which Pin is bound to the RMT channel. *clock_div*
is an 8-bit clock divider that divides the source clock (80MHz) to the RMT
channel allowing the resolution to be specified. *idle_level* specifies
optional and a dummy parameter for backward compatibility. *pin* is required
and configures which Pin is bound to the RMT channel.
*resolution_hz* defines the resolution/unit of the samples.
For example, 1,000,000 means the unit is microsecond. The pulse widths can
assume values up to *RMT.PULSE_MAX*, so the resolution should be selected
accordingly to the signal to be transmitted.
*clock_div* (deprecated) is equivalent to *resolution_hz*, but expressed as
a clock divider that divides the source clock (80MHz) to the RMT
channel allowing the resolution to be specified. Either *clock_div* and
*resolution_hz* may be supplied, but not both.
*num_symbols* specifies the
RMT buffer allocated for this channel (minimum 48 or 64, depending on chip), from a small pool of
symbols (192 to 512, depending on chip) that are shared by all channels. This buffer does not limit the
size of the pulse train that you can send, but bigger buffers reduce the
CPU load and the potential of glitches/imprecise pulse lengths. *idle_level* specifies
what level the output will be when no transmission is in progress and can
be any value that converts to a boolean, with ``True`` representing high
voltage and ``False`` representing low.
@@ -419,21 +425,52 @@ For more details see Espressif's `ESP-IDF RMT documentation.
.. method:: RMT.clock_div()
Return the clock divider. Note that the channel resolution is
``1 / (source_freq / clock_div)``.
``1 / (source_freq / clock_div)``. (Method deprecated. The value may
not be faithful if resolution was supplied as *resolution_hz*.)
.. method:: RMT.wait_done(*, timeout=0)
Returns ``True`` if the channel is idle or ``False`` if a sequence of
pulses started with `RMT.write_pulses` is being transmitted. If the
*timeout* keyword argument is given then block for up to this many
milliseconds for transmission to complete.
milliseconds for transmission to complete. Timeout of -1 blocks until
transmission is complete (and blocks forever if loop is enabled).
.. method:: RMT.loop(enable_loop)
Configure looping on the channel. *enable_loop* is bool, set to ``True`` to
enable looping on the *next* call to `RMT.write_pulses`. If called with
``False`` while a looping sequence is currently being transmitted then the
current loop iteration will be completed and then transmission will stop.
transmission will stop. (Method deprecated by `RMT.loop_count`.)
.. method:: RMT.loop_count(n)
Configure looping on the channel. *n* is int. Affects the *next* call to
`RMT.write_pulses`. Set to ``0`` to disable looping, ``-1`` to enable
infinite looping, or a positive number to loop for a given number of times.
If *n* is changed, the current transmission is stopped.
Note: looping for a finite number of times is not supported by all flavors
of ESP32.
.. method:: RMT.active([boolean])
If called without parameters, returns *True* if there is an ongoing transmission.
If called with parameter *False*, stops the ongoing transmission.
This is useful to stop an infinite transmission loop.
The current loop is finished and transmission stops.
The object is not invalidated, and the RMT channel is again enabled when a new
transmission is started.
Calling with parameter *True* does not restart transmission. A new transmission
should always be initiated by *write_pulses()*.
.. method:: RMT.deinit()
Release all RMT resources and invalidate the object. All subsequent method
calls will raise OSError. Useful to free RMT resources without having to wait
for the object to be garbage-collected.
.. method:: RMT.write_pulses(duration, data=True)
@@ -463,17 +500,28 @@ For more details see Espressif's `ESP-IDF RMT documentation.
new sequence of pulses. Looping sequences longer than 126 pulses is not
supported by the hardware.
.. staticmethod:: RMT.bitstream_rmt([value])
Configure RMT usage in the `machine.bitstream` implementation.
If *value* is ``True``, bitstream tries to use RMT if possible. If *value*
is ``False``, bitstream sticks to the bit-banging implementation.
If no parameter is supplied, it returns the current state. The default state
is ``True``.
.. staticmethod:: RMT.bitstream_channel([value])
Select which RMT channel is used by the `machine.bitstream` implementation.
*value* can be ``None`` or a valid RMT channel number. The default RMT
channel is the highest numbered one.
*This function is deprecated and will be replaced by `RMT.bitstream_rmt()`.*
Passing in ``None`` disables the use of RMT and instead selects a bit-banging
implementation for `machine.bitstream`.
Passing in no argument will return ``1`` if RMT was enabled for the `machine.bitstream`
feature, and ``None`` otherwise.
Passing in no argument will not change the channel. This function returns
the current channel number.
Passing any non-negative integer argument is equivalent to calling ``RMT.bitstream_rmt(True)``.
.. note:: In previous versions of MicroPython it was necessary to use this function to assign
a specific RMT channel number for the bitstream, but the channel number is now assigned
dynamically.
Constants
---------