diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index 33d69a95ae8a6..806674ee4c3dd 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -21,7 +21,13 @@ #include "py/objproperty.h" #include "py/runtime.h" - +//| import memorymap +//| +//| FifoType = Literal["auto", "txrx", "tx", "rx", "txput", "txget", "putget"] +//| FifoType_piov0 = Literal["auto", "txrx", "tx", "rx"] +//| MovStatusType = Literal["txfifo", "rxfifo", "irq"] +//| MovStatusType_piov0 = Literal["txfifo"] +//| //| class StateMachine: //| """A single PIO StateMachine //| @@ -41,6 +47,7 @@ //| program: ReadableBuffer, //| frequency: int, //| *, +//| pio_version: int = 0, //| may_exec: Optional[ReadableBuffer] = None, //| init: Optional[ReadableBuffer] = None, //| first_out_pin: Optional[microcontroller.Pin] = None, @@ -74,9 +81,14 @@ //| wrap_target: int = 0, //| wrap: int = -1, //| offset: int = -1, +//| fifo_type: FifoType = "auto", +//| mov_status_type: MovStatusType = "txfifo", +//| mov_status_n: int = 0, //| ) -> None: //| """Construct a StateMachine object on the given pins with the given program. //| +//| The following parameters are usually supplied directly: +//| //| :param ReadableBuffer program: the program to run with the state machine //| :param int frequency: the target clock frequency of the state machine. Actual may be less. Use 0 for system clock speed. //| :param ReadableBuffer init: a program to run once at start up. This is run after program @@ -86,60 +98,77 @@ //| for instance, if there is no ``in`` or ``push`` instruction, then the `StateMachine` is configured without a receive FIFO. //| In this case, passing a ``may_exec`` program containing an ``in`` instruction such as ``in x``, a receive FIFO will be configured. //| :param ~microcontroller.Pin first_out_pin: the first pin to use with the OUT instruction -//| :param int out_pin_count: the count of consecutive pins to use with OUT starting at first_out_pin //| :param int initial_out_pin_state: the initial output value for out pins starting at first_out_pin //| :param int initial_out_pin_direction: the initial output direction for out pins starting at first_out_pin //| :param ~microcontroller.Pin first_in_pin: the first pin to use with the IN instruction -//| :param int in_pin_count: the count of consecutive pins to use with IN starting at first_in_pin //| :param int pull_in_pin_up: a 1-bit in this mask sets pull up on the corresponding in pin //| :param int pull_in_pin_down: a 1-bit in this mask sets pull down on the corresponding in pin. Setting both pulls enables a "bus keep" function, i.e. a weak pull to whatever is current high/low state of GPIO. //| :param ~microcontroller.Pin first_set_pin: the first pin to use with the SET instruction -//| :param int set_pin_count: the count of consecutive pins to use with SET starting at first_set_pin //| :param int initial_set_pin_state: the initial output value for set pins starting at first_set_pin //| :param int initial_set_pin_direction: the initial output direction for set pins starting at first_set_pin //| :param ~microcontroller.Pin first_sideset_pin: the first pin to use with a side set -//| :param int sideset_pin_count: the count of consecutive pins to use with a side set starting at first_sideset_pin. Does not include sideset enable //| :param int initial_sideset_pin_state: the initial output value for sideset pins starting at first_sideset_pin //| :param int initial_sideset_pin_direction: the initial output direction for sideset pins starting at first_sideset_pin //| :param bool sideset_enable: True when the top sideset bit is to enable. This should be used with the ".side_set # opt" directive //| :param ~microcontroller.Pin jmp_pin: the pin which determines the branch taken by JMP PIN instructions //| :param ~digitalio.Pull jmp_pin_pull: The pull value for the jmp pin, default is no pull. //| :param bool exclusive_pin_use: When True, do not share any pins with other state machines. Pins are never shared with other peripherals -//| :param bool auto_pull: When True, automatically load data from the tx FIFO into the -//| output shift register (OSR) when an OUT instruction shifts more than pull_threshold bits -//| :param int pull_threshold: Number of bits to shift before loading a new value into the OSR from the tx FIFO -//| :param bool out_shift_right: When True, data is shifted out the right side (LSB) of the -//| OSR. It is shifted out the left (MSB) otherwise. NOTE! This impacts data alignment -//| when the number of bytes is not a power of two (1, 2 or 4 bytes). //| :param bool wait_for_txstall: When True, writing data out will block until the TX FIFO and OSR are empty //| and an instruction is stalled waiting for more data. When False, data writes won't //| wait for the OSR to empty (only the TX FIFO) so make sure you give enough time before //| deiniting or stopping the state machine. -//| :param bool auto_push: When True, automatically save data from input shift register -//| (ISR) into the rx FIFO when an IN instruction shifts more than push_threshold bits -//| :param int push_threshold: Number of bits to shift before saving the ISR value to the RX FIFO -//| :param bool in_shift_right: When True, data is shifted into the right side (LSB) of the -//| ISR. It is shifted into the left (MSB) otherwise. NOTE! This impacts data alignment -//| when the number of bytes is not a power of two (1, 2 or 4 bytes). //| :param bool user_interruptible: When True (the default), //| `write()`, `readinto()`, and `write_readinto()` can be interrupted by a ctrl-C. //| This is useful when developing a PIO program: if there is an error in the program //| that causes an infinite loop, you will be able to interrupt the loop. //| However, if you are writing to a device that can get into a bad state if a read or write //| is interrupted, you may want to set this to False after your program has been vetted. +//| :param int offset: A specific offset in the state machine's program memory where the program must be loaded. +//| The default value, -1, allows the program to be loaded at any offset. +//| This is appropriate for most programs. +//| +//| The following parameters are usually set via assembler directives and passed using a ``**program.pio_kwargs`` argument but may also be specified directly: +//| +//| :param int out_pin_count: the count of consecutive pins to use with OUT starting at first_out_pin +//| :param int in_pin_count: the count of consecutive pins to use with IN starting at first_in_pin +//| :param int set_pin_count: the count of consecutive pins to use with SET starting at first_set_pin +//| :param int sideset_pin_count: the count of consecutive pins to use with a side set starting at first_sideset_pin. Does not include sideset enable +//| :param int pio_version: The version of the PIO peripheral required by the program. The constructor will raise an error if the actual hardware is not compatible with this program version. +//| :param bool auto_push: When True, automatically save data from input shift register +//| (ISR) into the rx FIFO when an IN instruction shifts more than push_threshold bits +//| :param int push_threshold: Number of bits to shift before saving the ISR value to the RX FIFO +//| :param bool in_shift_right: When True, data is shifted into the right side (LSB) of the +//| ISR. It is shifted into the left (MSB) otherwise. NOTE! This impacts data alignment +//| when the number of bytes is not a power of two (1, 2 or 4 bytes). +//| :param bool auto_pull: When True, automatically load data from the tx FIFO into the +//| output shift register (OSR) when an OUT instruction shifts more than pull_threshold bits +//| :param int pull_threshold: Number of bits to shift before loading a new value into the OSR from the tx FIFO +//| :param bool out_shift_right: When True, data is shifted out the right side (LSB) of the +//| OSR. It is shifted out the left (MSB) otherwise. NOTE! This impacts data alignment +//| when the number of bytes is not a power of two (1, 2 or 4 bytes). //| :param int wrap_target: The target instruction number of automatic wrap. Defaults to the first instruction of the program. //| :param int wrap: The instruction after which to wrap to the ``wrap`` //| instruction. As a special case, -1 (the default) indicates the //| last instruction of the program. -//| :param int offset: A specific offset in the state machine's program memory where the program must be loaded. -//| The default value, -1, allows the program to be loaded at any offset. -//| This is appropriate for most programs. +//| :param FifoType fifo_type: How the program accessess the FIFOs. PIO version 0 only supports a subset of values. +//| :param MovStatusType mov_status_type: What condition the ``mov status`` instruction checks. PIO version 0 only supports a subset of values. +//| :param MovStatusType mov_status_n: The FIFO depth or IRQ the ``mov status`` instruction checks for. For ``mov_status irq`` this includes the encoding of the ``next``/``prev`` selection bits. //| """ //| ... +static int one_of(qstr_short_t what, mp_obj_t arg, size_t n_options, const qstr_short_t options[], const int values[]) { + for (size_t i = 0; i < n_options; i++) { + mp_obj_t option_str = MP_OBJ_NEW_QSTR(options[i]); + if (mp_obj_equal(arg, option_str)) { + return values[i]; + } + } + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), what); +} + static mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { rp2pio_statemachine_obj_t *self = mp_obj_malloc(rp2pio_statemachine_obj_t, &rp2pio_statemachine_type); - enum { ARG_program, ARG_frequency, ARG_init, ARG_may_exec, + enum { ARG_program, ARG_frequency, ARG_init, ARG_pio_version, ARG_may_exec, ARG_first_out_pin, ARG_out_pin_count, ARG_initial_out_pin_state, ARG_initial_out_pin_direction, ARG_first_in_pin, ARG_in_pin_count, ARG_pull_in_pin_up, ARG_pull_in_pin_down, @@ -154,11 +183,15 @@ static mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n ARG_user_interruptible, ARG_wrap_target, ARG_wrap, - ARG_offset, }; + ARG_offset, + ARG_fifo_type, + ARG_mov_status_type, + ARG_mov_status_n, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_init, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_pio_version, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_may_exec, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_first_out_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, @@ -198,11 +231,18 @@ static mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n { MP_QSTR_wrap_target, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_wrap, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_offset, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + + { MP_QSTR_offset, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PIO_ANY_OFFSET} }, + + { MP_QSTR_fifo_type, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_ROM_QSTR(MP_QSTR_auto) } }, + { MP_QSTR_mov_status_type, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_ROM_QSTR(MP_QSTR_txfifo) } }, + { MP_QSTR_mov_status_n, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + (void)mp_arg_validate_int_max(args[ARG_pio_version].u_int, PICO_PIO_VERSION, MP_QSTR_out_pin_count); + mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_program].u_obj, &bufinfo, MP_BUFFER_READ); @@ -254,6 +294,33 @@ static mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n int wrap = args[ARG_wrap].u_int; int wrap_target = args[ARG_wrap_target].u_int; + const qstr_short_t fifo_alternatives[] = { MP_QSTR_auto, MP_QSTR_txrx, MP_QSTR_tx, MP_QSTR_rx, + #if PICO_PIO_VERSION > 0 + MP_QSTR_txput, MP_QSTR_txget, MP_QSTR_putget + #endif + }; + const int fifo_values[] = { PIO_FIFO_JOIN_AUTO, PIO_FIFO_JOIN_NONE, PIO_FIFO_JOIN_TX, PIO_FIFO_JOIN_RX, + #if PICO_PIO_VERSION > 0 + PIO_FIFO_JOIN_TXPUT, PIO_FIFO_JOIN_TXGET, PIO_FIFO_JOIN_PUTGET + #endif + }; + MP_STATIC_ASSERT(MP_ARRAY_SIZE(fifo_alternatives) == MP_ARRAY_SIZE(fifo_values)); + + int fifo_type = one_of(MP_QSTR_fifo_type, args[ARG_fifo_type].u_obj, MP_ARRAY_SIZE(fifo_alternatives), fifo_alternatives, fifo_values); + + const qstr_short_t mov_status_alternatives[] = { MP_QSTR_txfifo, MP_QSTR_rxfifo, + #if PICO_PIO_VERSION > 0 + MP_QSTR_IRQ + #endif + }; + const int mov_status_values[] = { STATUS_TX_LESSTHAN, STATUS_RX_LESSTHAN, + #if PICO_PIO_VERSION > 0 + STATUS_IRQ_SET + #endif + }; + MP_STATIC_ASSERT(MP_ARRAY_SIZE(mov_status_alternatives) == MP_ARRAY_SIZE(mov_status_values)); + int mov_status_type = one_of(MP_QSTR_mov_status_type, args[ARG_mov_status_type].u_obj, MP_ARRAY_SIZE(mov_status_alternatives), mov_status_alternatives, mov_status_values); + common_hal_rp2pio_statemachine_construct(self, bufinfo.buf, bufinfo.len / 2, args[ARG_frequency].u_int, @@ -271,7 +338,10 @@ static mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n args[ARG_wait_for_txstall].u_bool, args[ARG_auto_push].u_bool, push_threshold, args[ARG_in_shift_right].u_bool, args[ARG_user_interruptible].u_bool, - wrap_target, wrap, args[ARG_offset].u_int); + wrap_target, wrap, args[ARG_offset].u_int, + fifo_type, + mov_status_type, args[ARG_mov_status_n].u_int + ); return MP_OBJ_FROM_PTR(self); } @@ -841,6 +911,32 @@ MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_pc_obj, rp2pio_statemachine_ob MP_PROPERTY_GETTER(rp2pio_statemachine_pc_obj, (mp_obj_t)&rp2pio_statemachine_get_pc_obj); +//| rxfifo: memorymap.AddressRange +//| """Access the state machine's rxfifo directly +//| +//| If the state machine's fifo mode is ``txput`` then accessing this object +//| reads values stored by the ``mov rxfifo[], isr`` PIO instruction, and the +//| result of modifying it is undefined. +//| +//| If the state machine's fifo mode is ``txget`` then modifying this object +//| writes values accessed by the ``mov osr, rxfifo[]`` PIO instruction, and +//| the result of accessing it is undefined. +//| +//| If this state machine's mode is something else, then the property's value is `None`. +//| +//| Note: Since the ``txput`` and ``txget`` fifo mode does not exist on RP2040, this property will always be `None`.""" +//| + +static mp_obj_t rp2pio_statemachine_obj_get_rxfifo(mp_obj_t self_in) { + rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_rp2pio_statemachine_get_rxfifo(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_rxfifo_obj, rp2pio_statemachine_obj_get_rxfifo); + +MP_PROPERTY_GETTER(rp2pio_statemachine_rxfifo_obj, + (mp_obj_t)&rp2pio_statemachine_get_rxfifo_obj); + static const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rp2pio_statemachine_deinit_obj) }, @@ -868,6 +964,8 @@ static const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_offset), MP_ROM_PTR(&rp2pio_statemachine_offset_obj) }, { MP_ROM_QSTR(MP_QSTR_pc), MP_ROM_PTR(&rp2pio_statemachine_pc_obj) }, + + { MP_ROM_QSTR(MP_QSTR_rxfifo), MP_ROM_PTR(&rp2pio_statemachine_rxfifo_obj) }, }; static MP_DEFINE_CONST_DICT(rp2pio_statemachine_locals_dict, rp2pio_statemachine_locals_dict_table); diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.h b/ports/raspberrypi/bindings/rp2pio/StateMachine.h index 69234b62fc60f..41cceb3063574 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.h +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -34,7 +34,10 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, bool auto_push, uint8_t push_threshold, bool in_shift_right, bool user_interruptible, int wrap_taget, int wrap, - int offset); + int offset, + int fifo_type, + int mov_status_type, + int mov_status_n); void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self); bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self); @@ -70,3 +73,5 @@ int common_hal_rp2pio_statemachine_get_offset(rp2pio_statemachine_obj_t *self); int common_hal_rp2pio_statemachine_get_pc(rp2pio_statemachine_obj_t *self); void common_hal_rp2pio_statemachine_set_interrupt_handler(rp2pio_statemachine_obj_t *self, void (*handler)(void *), void *arg, int mask); + +mp_obj_t common_hal_rp2pio_statemachine_get_rxfifo(rp2pio_statemachine_obj_t *self); diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c index f3c23400db28e..60200e5c1214e 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c @@ -198,7 +198,11 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, false, 32, false, // in settings false, // Not user-interruptible. 0, -1, // wrap settings - PIO_ANY_OFFSET); + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, + PIO_MOV_N_DEFAULT + ); self->playing = false; audio_dma_init(&self->dma); diff --git a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c index 11f239e4009ae..b6e9d767d4bb1 100644 --- a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c +++ b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -60,7 +60,9 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, false, 32, true, // in settings false, // Not user-interruptible. 0, -1, // wrap settings - PIO_ANY_OFFSET); + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); if (actual_frequency < MIN_MIC_CLOCK) { mp_raise_ValueError(MP_ERROR_TEXT("sampling rate out of range")); diff --git a/ports/raspberrypi/common-hal/floppyio/__init__.c b/ports/raspberrypi/common-hal/floppyio/__init__.c index 570e5c7a98c1e..a8a31c63d21d0 100644 --- a/ports/raspberrypi/common-hal/floppyio/__init__.c +++ b/ports/raspberrypi/common-hal/floppyio/__init__.c @@ -99,7 +99,9 @@ int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalin false, // Not user-interruptible. false, // No sideset enable 0, -1, // wrap - PIO_ANY_OFFSET // offset + PIO_ANY_OFFSET, // offset + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT ); if (!ok) { mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); diff --git a/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c b/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c index a05307313b6d0..ac378d5877042 100644 --- a/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +++ b/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c @@ -101,7 +101,9 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle true, 32, true, // in settings false, // Not user-interruptible. 2, 5, // wrap settings - PIO_ANY_OFFSET); + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); } void common_hal_imagecapture_parallelimagecapture_deinit(imagecapture_parallelimagecapture_obj_t *self) { diff --git a/ports/raspberrypi/common-hal/neopixel_write/__init__.c b/ports/raspberrypi/common-hal/neopixel_write/__init__.c index 4753c17e5fe6c..c30022204683e 100644 --- a/ports/raspberrypi/common-hal/neopixel_write/__init__.c +++ b/ports/raspberrypi/common-hal/neopixel_write/__init__.c @@ -60,8 +60,9 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, false, // Not user-interruptible. false, // No sideset enable 0, -1, // wrap - PIO_ANY_OFFSET // offset - ); + PIO_ANY_OFFSET, // offset + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); if (!ok) { // Do nothing. Maybe bitbang? return; diff --git a/ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c b/ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c index 7efa2740a0cfb..bb0d3c1fd426c 100644 --- a/ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +++ b/ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c @@ -92,7 +92,9 @@ void common_hal_paralleldisplaybus_parallelbus_construct(paralleldisplaybus_para false, 32, true, // RX setting we don't use false, // Not user-interruptible. 0, -1, // wrap settings - PIO_ANY_OFFSET); + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); common_hal_rp2pio_statemachine_never_reset(&self->state_machine); } diff --git a/ports/raspberrypi/common-hal/pulseio/PulseIn.c b/ports/raspberrypi/common-hal/pulseio/PulseIn.c index ee4aa79af0ce3..a3b8a06f4ab29 100644 --- a/ports/raspberrypi/common-hal/pulseio/PulseIn.c +++ b/ports/raspberrypi/common-hal/pulseio/PulseIn.c @@ -54,7 +54,9 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, true, 32, true, // RX auto pull every 32 bits. shift left to output msb first false, // Not user-interruptible. 0, -1, // wrap settings - PIO_ANY_OFFSET); + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); common_hal_pulseio_pulsein_pause(self); diff --git a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c index a31312b6436b7..b5af0474be759 100644 --- a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c @@ -76,8 +76,9 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode false, 32, false, // in settings false, // Not user-interruptible. 0, MP_ARRAY_SIZE(encoder) - 1, // wrap settings - PIO_ANY_OFFSET - ); + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); // We're guaranteed by the init code that some output will be available promptly uint8_t quiescent_state; diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 642c47b933da8..bffc9400b34c9 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -12,6 +12,7 @@ #include "shared-bindings/digitalio/Pull.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/memorymap/AddressRange.h" #include "src/rp2040/hardware_regs/include/hardware/platform_defs.h" #include "src/rp2_common/hardware_clocks/include/hardware/clocks.h" @@ -180,6 +181,33 @@ static uint add_program(PIO pio, const pio_program_t *program, int offset) { } } +static enum pio_fifo_join compute_fifo_type(int fifo_type_in, bool rx_fifo, bool tx_fifo) { + if (fifo_type_in != PIO_FIFO_JOIN_AUTO) { + return fifo_type_in; + } + if (!rx_fifo) { + return PIO_FIFO_JOIN_TX; + } + if (!tx_fifo) { + return PIO_FIFO_JOIN_RX; + } + return PIO_FIFO_JOIN_NONE; +} + +static int compute_fifo_depth(enum pio_fifo_join join) { + if (join == PIO_FIFO_JOIN_TX || join == PIO_FIFO_JOIN_RX) { + return 8; + } + + #if PICO_PIO_VERSION > 0 + if (join == PIO_FIFO_JOIN_PUTGET) { + return 0; + } + #endif + + return 4; +} + bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, const uint16_t *program, size_t program_len, size_t frequency, @@ -199,7 +227,9 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, bool user_interruptible, bool sideset_enable, int wrap_target, int wrap, - int offset + int offset, + int fifo_type, + int mov_status_type, int mov_status_n ) { // Create a program id that isn't the pointer so we can store it without storing the original object. uint32_t program_id = ~((uint32_t)program); @@ -343,15 +373,27 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, sm_config_set_wrap(&c, wrap_target, wrap); sm_config_set_in_shift(&c, in_shift_right, auto_push, push_threshold); + #if PICO_PIO_VERSION > 0 + sm_config_set_in_pin_count(&c, in_pin_count); + #endif + sm_config_set_out_shift(&c, out_shift_right, auto_pull, pull_threshold); + sm_config_set_out_pin_count(&c, out_pin_count); - enum pio_fifo_join join = PIO_FIFO_JOIN_NONE; - if (!rx_fifo) { - join = PIO_FIFO_JOIN_TX; - } else if (!tx_fifo) { - join = PIO_FIFO_JOIN_RX; + sm_config_set_set_pin_count(&c, set_pin_count); + + enum pio_fifo_join join = compute_fifo_type(fifo_type, rx_fifo, tx_fifo); + + self->fifo_depth = compute_fifo_depth(join); + + #if PICO_PIO_VERSION > 0 + if (fifo_type == PIO_FIFO_JOIN_TXPUT || fifo_type == PIO_FIFO_JOIN_TXGET) { + self->rxfifo_obj.base.type = &memorymap_addressrange_type; + common_hal_memorymap_addressrange_construct(&self->rxfifo_obj, (uint8_t *)self->pio->rxf_putget[self->state_machine], 4 * sizeof(uint32_t)); + } else { + self->rxfifo_obj.base.type = NULL; } - self->fifo_depth = (join == PIO_FIFO_JOIN_NONE) ? 4 : 8; + #endif if (rx_fifo) { self->rx_dreq = pio_get_dreq(self->pio, self->state_machine, false); @@ -370,6 +412,11 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, self->init_len = init_len; sm_config_set_fifo_join(&c, join); + + // TODO: these arguments + // int mov_status_type, int mov_status_n, + // int set_count, int out_count + self->sm_config = c; // no DMA allocated @@ -519,7 +566,10 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, bool auto_push, uint8_t push_threshold, bool in_shift_right, bool user_interruptible, int wrap_target, int wrap, - int offset) { + int offset, + int fifo_type, + int mov_status_type, + int mov_status_n) { // First, check that all pins are free OR already in use by any PIO if exclusive_pin_use is false. uint32_t pins_we_use = wait_gpio_mask; @@ -585,7 +635,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, pull_up |= jmp_mask; } if (jmp_pull == PULL_DOWN) { - pull_up |= jmp_mask; + pull_down |= jmp_mask; } } if (initial_pin_direction & (pull_up | pull_down)) { @@ -610,7 +660,9 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, true /* claim pins */, user_interruptible, sideset_enable, - wrap_target, wrap, offset); + wrap_target, wrap, offset, + fifo_type, + mov_status_type, mov_status_n); if (!ok) { mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); } @@ -1102,6 +1154,16 @@ int common_hal_rp2pio_statemachine_get_pc(rp2pio_statemachine_obj_t *self) { return pio_sm_get_pc(pio, sm); } +mp_obj_t common_hal_rp2pio_statemachine_get_rxfifo(rp2pio_statemachine_obj_t *self) { + #if PICO_PIO_VERSION > 0 + if (self->rxfifo_obj.base.type) { + return MP_OBJ_FROM_PTR(&self->rxfifo_obj); + } + #endif + return mp_const_none; +} + + // Use a compile-time constant for MP_REGISTER_POINTER so the preprocessor will // not split the expansion across multiple lines. MP_REGISTER_ROOT_POINTER(mp_obj_t background_pio[enum_NUM_DMA_CHANNELS]); diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h index fcb86f783ac12..16946e4f7281a 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -9,9 +9,13 @@ #include "py/obj.h" #include "common-hal/microcontroller/Pin.h" +#include "common-hal/memorymap/AddressRange.h" #include "src/rp2_common/hardware_pio/include/hardware/pio.h" enum { PIO_ANY_OFFSET = -1 }; +enum { PIO_FIFO_JOIN_AUTO = -1, PIO_FIFO_TYPE_DEFAULT = PIO_FIFO_JOIN_AUTO }; +enum { PIO_MOV_STATUS_DEFAULT = STATUS_TX_LESSTHAN }; +enum { PIO_MOV_N_DEFAULT = 0 }; typedef struct sm_buf_info { mp_obj_t obj; @@ -47,6 +51,9 @@ typedef struct { sm_buf_info current, once, loop; int background_stride_in_bytes; bool dma_completed, byteswap; + #if PICO_PIO_VERSION > 0 + memorymap_addressrange_obj_t rxfifo_obj; + #endif } rp2pio_statemachine_obj_t; void reset_rp2pio_statemachine(void); @@ -70,7 +77,10 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, bool claim_pins, bool interruptible, bool sideset_enable, - int wrap_target, int wrap, int offset); + int wrap_target, int wrap, int offset, + int fifo_type, + int mov_status_type, int mov_status_n + ); uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self);