diff --git a/docs/library/rp2.PIO.rst b/docs/library/rp2.PIO.rst index f922456c8c483..51e6d1d9396b1 100644 --- a/docs/library/rp2.PIO.rst +++ b/docs/library/rp2.PIO.rst @@ -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 @@ -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. @@ -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`. @@ -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 --------- @@ -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 diff --git a/docs/library/rp2.StateMachine.rst b/docs/library/rp2.StateMachine.rst index 4984be0b2183c..d0dba1f593673 100644 --- a/docs/library/rp2.StateMachine.rst +++ b/docs/library/rp2.StateMachine.rst @@ -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`. @@ -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`. @@ -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*. @@ -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 @@ -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 --------------- diff --git a/docs/library/rp2.rst b/docs/library/rp2.rst index a215e98b51e55..53fa6a010728c 100644 --- a/docs/library/rp2.rst +++ b/docs/library/rp2.rst @@ -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. @@ -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) @@ -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 ---------------------------------- @@ -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. @@ -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. @@ -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) @@ -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*. diff --git a/docs/rp2/tutorial/pio.rst b/docs/rp2/tutorial/pio.rst index 4e519650eea6d..8193c4ee9b4ef 100644 --- a/docs/rp2/tutorial/pio.rst +++ b/docs/rp2/tutorial/pio.rst @@ -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 `). +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:: diff --git a/ports/rp2/modrp2.c b/ports/rp2/modrp2.c index 5a43c11e71928..2fb885396406d 100644 --- a/ports/rp2/modrp2.c +++ b/ports/rp2/modrp2.c @@ -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" @@ -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) }, diff --git a/ports/rp2/modules/rp2.py b/ports/rp2/modules/rp2.py index 831f3416b2150..5cfdf401fa0c2 100644 --- a/ports/rp2/modules/rp2.py +++ b/ports/rp2/modules/rp2.py @@ -35,6 +35,7 @@ def __init__( push_thresh=32, pull_thresh=32, fifo_join=PIO.JOIN_NONE, + in_count=0, ): # array is a built-in module so importing it here won't require # scanning the filesystem. @@ -42,14 +43,19 @@ def __init__( self.labels = {} execctrl = side_pindir << 29 + # fifo_join encodes the legacy JOIN_NONE/TX/RX modes in bits [31:30] (values 0-2), + # and the RP2350 FJOIN_RX_GET/PUT modes in bits [15:14] (values 4/8/12). + # in_count (RP2350): SHIFTCTRL bits [4:0], masks unneeded IN-mapped pins to zero. shiftctrl = ( - fifo_join << 30 + (fifo_join & 3) << 30 + | (fifo_join >> 2) << 14 | (pull_thresh & 0x1F) << 25 | (push_thresh & 0x1F) << 20 | out_shiftdir << 19 | in_shiftdir << 18 | autopull << 17 | autopush << 16 + | (in_count & 0x1F) ) self.prog = [array("H"), -1, -1, -1, execctrl, shiftctrl, out_init, set_init, sideset_init] @@ -135,7 +141,9 @@ def jmp(self, cond, label=None): def wait(self, polarity, src, index): if src == 6: - src = 1 # "pin" + src = 1 # "pin" (IN-mapped pins) + elif src == 3: + pass # "jmp_pin" (RP2350: PINCTRL_JMP_PIN with 2-bit offset in index) elif src != 0: src = 2 # "irq" return self.word(0x2000 | polarity << 7 | src << 5 | index) @@ -184,6 +192,7 @@ def set(self, dest, data): "gpio": 0, # "pin": see below, translated to 1 # "irq": see below function, translated to 2 + "jmp_pin": 3, # RP2350: PINCTRL_JMP_PIN source for wait, index is 2-bit offset (0-3) # source/dest constants for in_, out, mov, set "pins": 0, "x": 1, @@ -216,6 +225,9 @@ def set(self, dest, data): # "block": see above "clear": 0x40, "rel": lambda x: x | 0x10, + # RP2350: cross-PIO irq modifiers; applied to the irq index, e.g. irq(next_pio(2)) + "next_pio": lambda x: x | 0x08, + "prev_pio": lambda x: x | 0x18, } diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 81351431cb937..230a23af248a6 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -230,7 +230,7 @@ typedef struct _asm_pio_config_t { static void asm_pio_override_shiftctrl(mp_obj_t arg, uint32_t bits, uint32_t lsb, pio_sm_config *config) { if (arg != mp_const_none) { - config->shiftctrl = (config->shiftctrl & ~bits) | (mp_obj_get_int(arg) << lsb); + config->shiftctrl = (config->shiftctrl & ~bits) | ((mp_obj_get_int(arg) << lsb) & bits); } } @@ -487,6 +487,46 @@ static mp_obj_t rp2_pio_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k } static MP_DEFINE_CONST_FUN_OBJ_KW(rp2_pio_irq_obj, 1, rp2_pio_irq); +// PIO.version() +static mp_obj_t rp2_pio_version(mp_obj_t self_in) { + #if PICO_RP2350 + rp2_pio_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((self->pio->dbg_cfginfo >> PIO_DBG_CFGINFO_VERSION_LSB) & 0xf); + #else + (void)self_in; + return MP_OBJ_NEW_SMALL_INT(0); + #endif +} +static MP_DEFINE_CONST_FUN_OBJ_1(rp2_pio_version_obj, rp2_pio_version); + +#if PICO_RP2350 +// PIO.sm_mask_enable(sm_mask, next_mask=0, prev_mask=0) +// Atomically enable SMs on this PIO and neighbouring PIOs via CTRL NEXT/PREV_PIO_MASK bits. +static mp_obj_t rp2_pio_sm_mask_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sm_mask, ARG_next_mask, ARG_prev_mask }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sm_mask, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_next_mask, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_prev_mask, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + rp2_pio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint32_t ctrl = args[ARG_sm_mask].u_int & 0xf; + uint32_t next_mask = args[ARG_next_mask].u_int & 0xf; + uint32_t prev_mask = args[ARG_prev_mask].u_int & 0xf; + if (next_mask || prev_mask) { + ctrl |= (next_mask << PIO_CTRL_NEXT_PIO_MASK_LSB) + | (prev_mask << PIO_CTRL_PREV_PIO_MASK_LSB) + | PIO_CTRL_NEXTPREV_SM_ENABLE_BITS; + } + self->pio->ctrl = ctrl; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(rp2_pio_sm_mask_enable_obj, 1, rp2_pio_sm_mask_enable); +#endif + static const mp_rom_map_elem_t rp2_pio_locals_dict_table[] = { #if PICO_PIO_USE_GPIO_BASE { MP_ROM_QSTR(MP_QSTR_gpio_base), MP_ROM_PTR(&rp2_pio_gpio_base_obj) }, @@ -495,6 +535,10 @@ static const mp_rom_map_elem_t rp2_pio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_remove_program), MP_ROM_PTR(&rp2_pio_remove_program_obj) }, { MP_ROM_QSTR(MP_QSTR_state_machine), MP_ROM_PTR(&rp2_pio_state_machine_obj) }, { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&rp2_pio_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&rp2_pio_version_obj) }, + #if PICO_RP2350 + { MP_ROM_QSTR(MP_QSTR_sm_mask_enable), MP_ROM_PTR(&rp2_pio_sm_mask_enable_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_IN_LOW), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_IN_HIGH), MP_ROM_INT(1) }, @@ -507,6 +551,10 @@ static const mp_rom_map_elem_t rp2_pio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_JOIN_NONE), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_JOIN_TX), MP_ROM_INT(1) }, { MP_ROM_QSTR(MP_QSTR_JOIN_RX), MP_ROM_INT(2) }, + #if PICO_RP2350 + { MP_ROM_QSTR(MP_QSTR_JOIN_RX_GET), MP_ROM_INT(4) }, + { MP_ROM_QSTR(MP_QSTR_JOIN_RX_PUT), MP_ROM_INT(8) }, + #endif { MP_ROM_QSTR(MP_QSTR_IRQ_SM0), MP_ROM_INT(0x100) }, { MP_ROM_QSTR(MP_QSTR_IRQ_SM1), MP_ROM_INT(0x200) }, @@ -618,7 +666,10 @@ static mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel enum { ARG_prog, ARG_freq, ARG_in_base, ARG_out_base, ARG_set_base, ARG_jmp_pin, ARG_sideset_base, - ARG_in_shiftdir, ARG_out_shiftdir, ARG_push_thresh, ARG_pull_thresh + ARG_in_shiftdir, ARG_out_shiftdir, ARG_push_thresh, ARG_pull_thresh, + #if PICO_RP2350 + ARG_in_count, + #endif }; static const mp_arg_t allowed_args[] = { { MP_QSTR_prog, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -632,6 +683,9 @@ static mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel { MP_QSTR_out_shiftdir, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_push_thresh, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_pull_thresh, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + #if PICO_RP2350 + { MP_QSTR_in_count, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + #endif }; // Parse the arguments. @@ -728,6 +782,9 @@ static mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel asm_pio_override_shiftctrl(args[ARG_out_shiftdir].u_obj, PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_BITS, PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_LSB, &config); asm_pio_override_shiftctrl(args[ARG_push_thresh].u_obj, PIO_SM0_SHIFTCTRL_PUSH_THRESH_BITS, PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB, &config); asm_pio_override_shiftctrl(args[ARG_pull_thresh].u_obj, PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS, PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB, &config); + #if PICO_RP2350 + asm_pio_override_shiftctrl(args[ARG_in_count].u_obj, PIO_SM0_SHIFTCTRL_IN_COUNT_BITS, PIO_SM0_SHIFTCTRL_IN_COUNT_LSB, &config); + #endif // Configure the state machine. pio_sm_set_config(self->pio, self->sm, &config); @@ -1003,6 +1060,23 @@ static mp_obj_t rp2_state_machine_irq(size_t n_args, const mp_obj_t *pos_args, m } static MP_DEFINE_CONST_FUN_OBJ_KW(rp2_state_machine_irq_obj, 1, rp2_state_machine_irq); +#if PICO_RP2350 +// StateMachine.putget(index[, value]) -- read or write RXF_PUTGET register slot (FJOIN_RX_PUT/GET mode) +static mp_obj_t rp2_state_machine_putget(size_t n_args, const mp_obj_t *args) { + rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t index = mp_obj_get_int(args[1]); + if (index < 0 || index > 3) { + mp_raise_ValueError(MP_ERROR_TEXT("index out of range")); + } + if (n_args > 2) { + self->pio->rxf_putget[self->sm][index] = mp_obj_get_int_truncated(args[2]); + return mp_const_none; + } + return mp_obj_new_int_from_uint(self->pio->rxf_putget[self->sm][index]); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_state_machine_putget_obj, 2, 3, rp2_state_machine_putget); +#endif + static const mp_rom_map_elem_t rp2_state_machine_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&rp2_state_machine_init_obj) }, { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&rp2_state_machine_active_obj) }, @@ -1013,6 +1087,9 @@ static const mp_rom_map_elem_t rp2_state_machine_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_rx_fifo), MP_ROM_PTR(&rp2_state_machine_rx_fifo_obj) }, { MP_ROM_QSTR(MP_QSTR_tx_fifo), MP_ROM_PTR(&rp2_state_machine_tx_fifo_obj) }, { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&rp2_state_machine_irq_obj) }, + #if PICO_RP2350 + { MP_ROM_QSTR(MP_QSTR_putget), MP_ROM_PTR(&rp2_state_machine_putget_obj) }, + #endif }; static MP_DEFINE_CONST_DICT(rp2_state_machine_locals_dict, rp2_state_machine_locals_dict_table);