Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 51 additions & 5 deletions docs/library/rp2.PIO.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class PIO -- advanced PIO usage
===============================

The :class:`PIO` class gives access to an instance of the RP2040's PIO
The :class:`PIO` class gives access to an instance of the RP2040/RP2350's PIO
(programmable I/O) interface.

The preferred way to interact with PIO is using :class:`rp2.StateMachine`, the
Expand All @@ -18,8 +18,8 @@ Constructors

.. class:: PIO(id)

Gets the PIO instance numbered *id*. The RP2040 has two PIO instances,
numbered 0 and 1.
Gets the PIO instance numbered *id*. The RP2040 has two PIO instances
(0 and 1); the RP2350 has three (0, 1 and 2).

Raises a ``ValueError`` if any other argument is provided.

Expand Down Expand Up @@ -56,8 +56,8 @@ Methods

.. method:: PIO.state_machine(id, [program, ...])

Gets the state machine numbered *id*. On the RP2040, each PIO instance has
four state machines, numbered 0 to 3.
Gets the state machine numbered *id*. Each PIO instance has four state
machines, numbered 0 to 3.

Optionally initialize it with a *program*: see `StateMachine.init`.

Expand All @@ -72,6 +72,34 @@ Methods

Optionally configure it.

.. method:: PIO.version()

Returns the hardware version of this PIO instance as an integer:
0 for PIO v0 (RP2040), 1 for PIO v1 (RP2350).

This can be used to detect at runtime which PIO features are available.

.. method:: PIO.sm_mask_enable(sm_mask, *, next_mask=0, prev_mask=0)

Atomically enable state machines across PIO blocks in a single write to
the ``CTRL`` register.

*sm_mask* is a 4-bit mask of state machines (bits 0–3) to enable on
this PIO instance.

*next_mask* and *prev_mask* are 4-bit masks of state machines to enable
simultaneously on the neighbouring (next/previous) PIO instance.
Setting either causes the ``NEXTPREV_SM_ENABLE`` bit to be asserted in
the same write, making the enable across all specified PIO blocks
simultaneous.

Only available on RP2350 (PIO v1).

Example — start SM0 on PIO0 and SM0 on PIO1 at exactly the same time::

p0 = rp2.PIO(0)
p0.sm_mask_enable(0b0001, next_mask=0b0001)


Constants
---------
Expand All @@ -96,6 +124,24 @@ Constants

These constants are used for the *fifo_join* argument to `asm_pio`.

.. data:: PIO.JOIN_RX_PUT
PIO.JOIN_RX_GET

RP2350 (PIO v1) FIFO join modes, used for the *fifo_join* argument to
`asm_pio`.

``JOIN_RX_PUT``: the state machine writes to its RX FIFO entries with
``MOV rxfifo[n], ISR``, and the host reads them with
`StateMachine.putget`. The entries act as status registers: the state
machine updates them and the host reads them at any time.

``JOIN_RX_GET``: the host writes to the RX FIFO entries with
`StateMachine.putget`, and the state machine reads them with
``MOV OSR, rxfifo[n]``. The entries act as configuration registers:
the host updates them and the state machine reads them at any time.

Only available on RP2350.

.. data:: PIO.IRQ_SM0
PIO.IRQ_SM1
PIO.IRQ_SM2
Expand Down
52 changes: 44 additions & 8 deletions docs/library/rp2.StateMachine.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
.. currentmodule:: rp2
.. _rp2.StateMachine:

class StateMachine -- access to the RP2040's programmable I/O interface
=======================================================================
class StateMachine -- access to the RP2040/RP2350's programmable I/O interface
===============================================================================

The :class:`StateMachine` class gives access to the RP2040's PIO (programmable
I/O) interface.
The :class:`StateMachine` class gives access to the RP2040/RP2350's PIO
(programmable I/O) interface.

For assembling PIO programs, see :func:`rp2.asm_pio`.

Expand All @@ -15,9 +15,8 @@ Constructors

.. class:: StateMachine(id, [program, ...])

Get the state machine numbered *id*. The RP2040 has two identical PIO
instances, each with 4 state machines: so there are 8 state machines in
total, numbered 0 to 7.
Get the state machine numbered *id*. The RP2040 has 8 state machines in
total (numbered 0 to 7); the RP2350 has 12 (numbered 0 to 11).

Optionally initialize it with the given program *program*: see
`StateMachine.init`.
Expand All @@ -26,7 +25,7 @@ Constructors
Methods
-------

.. method:: StateMachine.init(program, freq=-1, *, in_base=None, out_base=None, set_base=None, jmp_pin=None, sideset_base=None, in_shiftdir=None, out_shiftdir=None, push_thresh=None, pull_thresh=None)
.. method:: StateMachine.init(program, freq=-1, *, in_base=None, out_base=None, set_base=None, jmp_pin=None, sideset_base=None, in_shiftdir=None, out_shiftdir=None, push_thresh=None, pull_thresh=None, in_count=None)

Configure the state machine instance to run the given *program*.

Expand Down Expand Up @@ -57,6 +56,9 @@ Methods
re-pushing is triggered.
- *pull_thresh* is the threshold in bits before auto-pull or conditional
re-pulling is triggered.
- *in_count* overrides the ``IN_COUNT`` field in ``SHIFTCTRL`` (bits 4:0),
masking unneeded IN-mapped pins to zero. Only effective on RP2350.
Usually set via the `asm_pio` decorator instead.

Note: pins used for *in_base* need to be configured manually for input (or
otherwise) so that the PIO can see the desired signal (they could be input
Expand Down Expand Up @@ -145,6 +147,40 @@ Methods

Optionally configure it.

.. method:: StateMachine.putget(index, [value])

Read or write a single RX FIFO storage register by index (0–3). This is
only meaningful when the state machine's FIFO join mode is
`PIO.JOIN_RX_PUT` or `PIO.JOIN_RX_GET`.

The direction of access depends on the FIFO join mode:

- `PIO.JOIN_RX_GET` (host writes, SM reads): call ``putget(index, value)``
to write a configuration word that the state machine can read with
``MOV OSR, rxfifo[n]``.
- `PIO.JOIN_RX_PUT` (SM writes, host reads): call ``putget(index)`` to
read a status word that the state machine wrote with
``MOV rxfifo[n], ISR``.

*index* must be in the range 0–3; a ``ValueError`` is raised otherwise.

If *value* is given, writes it to the selected FIFO register and returns
``None``. If *value* is omitted, returns the current value of the
selected FIFO register as an integer.

Only available on RP2350 (PIO v1).

Example — host writes configuration registers for a UART TX program::

@rp2.asm_pio(fifo_join=rp2.PIO.JOIN_RX_GET)
def uart_tx():
...

sm = rp2.StateMachine(0, uart_tx)
sm.putget(0, 8) # configure: 8 data bits
sm.putget(1, 1) # configure: 1 stop bit
sm.active(1)

Buffer protocol
---------------

Expand Down
43 changes: 33 additions & 10 deletions docs/library/rp2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The ``rp2`` module includes functions for assembling PIO programs.

For running PIO programs, see :class:`rp2.StateMachine`.

.. function:: asm_pio(*, out_init=None, set_init=None, sideset_init=None, side_pindir=False, in_shiftdir=PIO.SHIFT_LEFT, out_shiftdir=PIO.SHIFT_LEFT, autopush=False, autopull=False, push_thresh=32, pull_thresh=32, fifo_join=PIO.JOIN_NONE)
.. function:: asm_pio(*, out_init=None, set_init=None, sideset_init=None, side_pindir=False, in_shiftdir=PIO.SHIFT_LEFT, out_shiftdir=PIO.SHIFT_LEFT, autopush=False, autopull=False, push_thresh=32, pull_thresh=32, fifo_join=PIO.JOIN_NONE, in_count=0)

Assemble a PIO program.

Expand Down Expand Up @@ -56,9 +56,15 @@ For running PIO programs, see :class:`rp2.StateMachine`.

- *autopush* configures whether auto-push is enabled.
- *autopull* configures whether auto-pull is enabled.
- *fifo_join* configures whether the 4-word TX and RX FIFOs should be
combined into a single 8-word FIFO for one direction only. The options
are `PIO.JOIN_NONE`, `PIO.JOIN_RX` and `PIO.JOIN_TX`.
- *fifo_join* configures the FIFO mode. The options are `PIO.JOIN_NONE`,
`PIO.JOIN_RX` and `PIO.JOIN_TX`. On RP2350 the additional modes
``PIO.JOIN_TXGET`` (4), ``PIO.JOIN_TXPUT`` (8) and ``PIO.JOIN_PUTGET``
(12) enable random read/write access to the RX FIFO storage registers
via ``StateMachine.putget()``.
- *in_count* (RP2350 only) is the number of IN-mapped pins that are not
masked to zero when read by ``in_(pins, ...)``, ``wait(pin, ...)``, or
``mov(x, pins)``. Pins beyond this count read as zero. Default is 0,
which means all 32 pins are visible (no masking).

.. function:: asm_pio_encode(instr, sideset_count, sideset_opt=False)

Expand All @@ -85,6 +91,8 @@ For running PIO programs, see :class:`rp2.StateMachine`.
an error assembling a PIO program.


.. _pio_assembly_instructions:

PIO assembly language instructions
----------------------------------

Expand All @@ -93,7 +101,9 @@ PIO-machine instructions. In MicroPython, PIO assembly routines are written as
a Python function with the decorator ``@rp2.asm_pio()``, and they use Python
syntax. Such routines support standard Python variables and arithmetic, as well
as the following custom functions that encode PIO instructions and direct the
assembler. See sec 3.4 of the RP2040 datasheet for further details.
assembler. See sec 3.4 of the RP2040 datasheet or sec 3.5 of the RP2350
datasheet for further details. Instructions marked *RP2350 only* encode
correctly on RP2040 but produce undefined behaviour at runtime.

wrap_target()
Specify the location where execution continues after program wrapping.
Expand Down Expand Up @@ -138,9 +148,15 @@ wait(polarity, src, index)
Block, waiting for high/low on a pin or IRQ line.

- *polarity*: 0 or 1, whether to wait for a low or high value
- *src*: one of: ``gpio`` (absolute pin), ``pin`` (pin relative to
StateMachine's ``in_base`` argument), ``irq``
- *index*: 0-31, the index for *src*
- *src*: one of:

- ``gpio``: absolute GPIO pin number
- ``pin``: pin index relative to the StateMachine's ``in_base``
- ``irq``: IRQ flag number
- ``jmp_pin``: *(RP2350 only)* PINCTRL_JMP_PIN, with *index* as a
2-bit offset (0-3) added to the configured JMP pin

- *index*: 0-31 for ``gpio``/``pin``/``irq``; 0-3 for ``jmp_pin``

in_(src, bit_count)
Shift data in from *src* to ISR.
Expand Down Expand Up @@ -188,7 +204,9 @@ pull(...)
mov(dest, src)
Move into *dest* the value from *src*.

- *dest*: one of: ``pins``, ``x``, ``y``, ``exec``, ``pc``, ``isr``, ``osr``
- *dest*: one of: ``pins``, ``x``, ``y``, ``exec``, ``pc``, ``isr``,
``osr``, ``pindirs`` *(RP2350 only — sets direction of all OUT-mapped
pins; use* ``null`` *or* ``invert(null)`` *as src)*
- *src*: one of: ``pins``, ``x``, ``y``, ``null``, ``status``, ``isr``,
``osr``; this argument can be optionally modified by wrapping it in
``invert()`` or ``reverse()`` (but not both together)
Expand All @@ -207,9 +225,14 @@ irq(...)
If ``block`` is used then the instruction stalls until the flag is cleared
by another entity. If ``clear`` is used then the flag is cleared instead of
being set. Relative IRQ indices add the state machine ID to the IRQ index
with modulo-4 addition. IRQs 0-3 are visible from to the processor, 4-7 are
with modulo-4 addition. IRQs 0-3 are visible from the processor, 4-7 are
internal to the state machines.

On RP2350, the index argument can be wrapped in ``next_pio()`` or
``prev_pio()`` to target IRQ flags in a neighbouring PIO block instead of
the current one, e.g. ``irq(next_pio(2))`` or ``irq(clear, prev_pio(0))``.
Cross-PIO IRQ flags are observed on the next cycle with no delay penalty.

set(dest, data)
Set *dest* with the value *data*.

Expand Down
35 changes: 20 additions & 15 deletions docs/rp2/tutorial/pio.rst
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
Programmable IO
===============

The RP2040 has hardware support for standard communication protocols like I2C,
SPI and UART. For protocols where there is no hardware support, or where there
is a requirement of custom I/O behaviour, Programmable Input Output (PIO) comes
into play. Also, some MicroPython applications make use of a technique called
bit banging in which pins are rapidly turned on and off to transmit data. This
can make the entire process slow as the processor concentrates on bit banging
rather than executing other logic. However, PIO allows bit banging to happen
in the background while the CPU is executing the main work.

Along with the two central Cortex-M0+ processing cores, the RP2040 has two PIO
blocks each of which has four independent state machines. These state machines
can transfer data to/from other entities using First-In-First-Out (FIFO) buffers,
which allow the state machine and main processor to work independently yet also
synchronise their data. Each FIFO has four words (each of 32 bits) which can be
linked to the DMA to transfer larger amounts of data.
The RP2040 and RP2350 have hardware support for standard communication
protocols like I2C, SPI and UART. For protocols where there is no hardware
support, or where there is a requirement of custom I/O behaviour, Programmable
Input Output
(PIO) comes into play. Also, some MicroPython applications make use of a
technique called bit banging in which pins are rapidly turned on and off to
transmit data. This can make the entire process slow as the processor
concentrates on bit banging rather than executing other logic. However, PIO
allows bit banging to happen in the background while the CPU is executing the
main work.

The RP2040 has two PIO blocks each with four independent state machines (8
total). The RP2350 adds a third PIO block for 12 state machines in total, and
introduces PIO version 1 with additional instruction capabilities (see
:ref:`PIO assembly language instructions <pio_assembly_instructions>`).
These state machines can transfer
data to/from other entities using First-In-First-Out (FIFO) buffers, which
allow the state machine and main processor to work independently yet also
synchronise their data. Each FIFO has four words (each of 32 bits) which can
be linked to the DMA to transfer larger amounts of data.

All PIO instructions follow a common pattern::

Expand Down
31 changes: 31 additions & 0 deletions ports/rp2/modrp2.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "modrp2.h"
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/pio.h"
#include "hardware/sync.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/sio.h"
Expand Down Expand Up @@ -97,6 +98,36 @@ static const mp_rom_map_elem_t rp2_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_DMA), MP_ROM_PTR(&rp2_dma_type) },
{ MP_ROM_QSTR(MP_QSTR_bootsel_button), MP_ROM_PTR(&rp2_bootsel_button_obj) },

// DREQ constants for PIO0 and PIO1 (available on RP2040 and RP2350).
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO0_TX0), MP_ROM_INT(DREQ_PIO0_TX0) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO0_TX1), MP_ROM_INT(DREQ_PIO0_TX1) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO0_TX2), MP_ROM_INT(DREQ_PIO0_TX2) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO0_TX3), MP_ROM_INT(DREQ_PIO0_TX3) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO0_RX0), MP_ROM_INT(DREQ_PIO0_RX0) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO0_RX1), MP_ROM_INT(DREQ_PIO0_RX1) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO0_RX2), MP_ROM_INT(DREQ_PIO0_RX2) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO0_RX3), MP_ROM_INT(DREQ_PIO0_RX3) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO1_TX0), MP_ROM_INT(DREQ_PIO1_TX0) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO1_TX1), MP_ROM_INT(DREQ_PIO1_TX1) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO1_TX2), MP_ROM_INT(DREQ_PIO1_TX2) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO1_TX3), MP_ROM_INT(DREQ_PIO1_TX3) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO1_RX0), MP_ROM_INT(DREQ_PIO1_RX0) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO1_RX1), MP_ROM_INT(DREQ_PIO1_RX1) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO1_RX2), MP_ROM_INT(DREQ_PIO1_RX2) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO1_RX3), MP_ROM_INT(DREQ_PIO1_RX3) },

#if NUM_PIOS >= 3
// DREQ constants for PIO2 (RP2350 only).
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO2_TX0), MP_ROM_INT(DREQ_PIO2_TX0) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO2_TX1), MP_ROM_INT(DREQ_PIO2_TX1) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO2_TX2), MP_ROM_INT(DREQ_PIO2_TX2) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO2_TX3), MP_ROM_INT(DREQ_PIO2_TX3) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO2_RX0), MP_ROM_INT(DREQ_PIO2_RX0) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO2_RX1), MP_ROM_INT(DREQ_PIO2_RX1) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO2_RX2), MP_ROM_INT(DREQ_PIO2_RX2) },
{ MP_ROM_QSTR(MP_QSTR_DREQ_PIO2_RX3), MP_ROM_INT(DREQ_PIO2_RX3) },
#endif

#if MICROPY_PY_NETWORK_CYW43
// Deprecated (use network.country instead).
{ MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&mod_network_country_obj) },
Expand Down
Loading
Loading