From a9d929627a0550f83cacc02aa97dbdcdb0e9737e Mon Sep 17 00:00:00 2001 From: Jeff Epler <jepler@gmail.com> Date: Thu, 5 May 2022 14:40:49 -0500 Subject: [PATCH 1/7] minor comment update --- ports/raspberrypi/common-hal/neopixel_write/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/common-hal/neopixel_write/__init__.c b/ports/raspberrypi/common-hal/neopixel_write/__init__.c index 034c5de002b00..5c66d33feb248 100644 --- a/ports/raspberrypi/common-hal/neopixel_write/__init__.c +++ b/ports/raspberrypi/common-hal/neopixel_write/__init__.c @@ -63,7 +63,7 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, uint32_t pins_we_use = 1 << digitalinout->pin->number; bool ok = rp2pio_statemachine_construct(&state_machine, neopixel_program, sizeof(neopixel_program) / sizeof(neopixel_program[0]), - 12800000, // MHz, to get about appropriate sub-bit times in PIO program. + 12800000, // 12.8MHz, to get appropriate sub-bit times in PIO program. NULL, 0, // init program NULL, 1, // out NULL, 1, // in From 1a9034ff7c3aa2b17822a61e35ea277ec401d2ac Mon Sep 17 00:00:00 2001 From: Jeff Epler <jepler@gmail.com> Date: Fri, 6 May 2022 14:21:09 -0500 Subject: [PATCH 2/7] rp2pio: Allow background_write(None) to terminate after complete loop --- ports/raspberrypi/common-hal/rp2pio/StateMachine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index c38e1ec0107ac..b830a82be89bf 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -917,7 +917,7 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t * self->loop = *loop; self->pending_buffers = pending_buffers; - if (self->dma_completed) { + if (self->dma_completed && self->once.info.len) { rp2pio_statemachine_dma_complete(self, SM_DMA_GET_CHANNEL(pio_index, sm)); self->dma_completed = false; } From f776749ca3f5cc69beeff2f7b1005c3527dec27d Mon Sep 17 00:00:00 2001 From: Jeff Epler <jepler@gmail.com> Date: Fri, 6 May 2022 14:22:07 -0500 Subject: [PATCH 3/7] Key off len, not buf, to decide if anything to DMA --- ports/raspberrypi/common-hal/rp2pio/StateMachine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index b830a82be89bf..00e715be6bed4 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -894,8 +894,8 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t * uint8_t pio_index = pio_get_index(self->pio); uint8_t sm = self->state_machine; - int pending_buffers = (once->info.buf != NULL) + (loop->info.buf != NULL); - if (!once->info.buf) { + int pending_buffers = (once->info.len != 0) + (loop->info.len != 0); + if (!once->info.len) { once = loop; } From 23c0fc83549536905b1562a3fd4b5ed0a6fde871 Mon Sep 17 00:00:00 2001 From: Jeff Epler <jepler@gmail.com> Date: Fri, 6 May 2022 14:42:24 -0500 Subject: [PATCH 4/7] add ability to get, clear txstall flag This can be used to make sure a PIO has actually finished all data it was schedule to receive via a 'once' background_write --- .../bindings/rp2pio/StateMachine.c | 34 +++++++++++++++++++ .../bindings/rp2pio/StateMachine.h | 2 ++ .../common-hal/rp2pio/StateMachine.c | 12 +++++++ 3 files changed, 48 insertions(+) diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index 28668355b186b..d234a50a9a067 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -708,6 +708,18 @@ STATIC mp_obj_t rp2pio_statemachine_obj_clear_rxfifo(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_clear_rxfifo_obj, rp2pio_statemachine_obj_clear_rxfifo); +//| def clear_txstall(self) -> None: +//| """Clears the txstall flag.""" +//| ... +//| +STATIC mp_obj_t rp2pio_statemachine_obj_clear_txstall(mp_obj_t self_in) { + rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_rp2pio_statemachine_clear_txstall(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_clear_txstall_obj, rp2pio_statemachine_obj_clear_txstall); + + //| frequency: int //| """The actual state machine frequency. This may not match the frequency requested //| due to internal limitations.""" @@ -736,6 +748,26 @@ const mp_obj_property_t rp2pio_statemachine_frequency_obj = { MP_ROM_NONE}, }; +//| txstall: bool +//| """True when the state machine has stalled due to a full TX FIFO since the last +//| `clear_txstall` call.""" +//| + +STATIC mp_obj_t rp2pio_statemachine_obj_get_txstall(mp_obj_t self_in) { + rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_rp2pio_statemachine_get_txstall(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_txstall_obj, rp2pio_statemachine_obj_get_txstall); + +const mp_obj_property_t rp2pio_statemachine_txstall_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&rp2pio_statemachine_get_txstall_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + + //| rxstall: bool //| """True when the state machine has stalled due to a full RX FIFO since the last //| `clear_rxfifo` call.""" @@ -782,6 +814,7 @@ STATIC const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&rp2pio_statemachine_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&rp2pio_statemachine_run_obj) }, { MP_ROM_QSTR(MP_QSTR_clear_rxfifo), MP_ROM_PTR(&rp2pio_statemachine_clear_rxfifo_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_txstall), MP_ROM_PTR(&rp2pio_statemachine_clear_txstall_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&rp2pio_statemachine_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&rp2pio_statemachine_write_obj) }, @@ -793,6 +826,7 @@ STATIC const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&rp2pio_statemachine_frequency_obj) }, { MP_ROM_QSTR(MP_QSTR_rxstall), MP_ROM_PTR(&rp2pio_statemachine_rxstall_obj) }, + { MP_ROM_QSTR(MP_QSTR_txstall), MP_ROM_PTR(&rp2pio_statemachine_txstall_obj) }, { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&rp2pio_statemachine_in_waiting_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 087283ced21b8..36e406032df40 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.h +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -81,6 +81,8 @@ void common_hal_rp2pio_statemachine_set_frequency(rp2pio_statemachine_obj_t *sel bool common_hal_rp2pio_statemachine_get_rxstall(rp2pio_statemachine_obj_t *self); void common_hal_rp2pio_statemachine_clear_rxfifo(rp2pio_statemachine_obj_t *self); +bool common_hal_rp2pio_statemachine_get_txstall(rp2pio_statemachine_obj_t *self); +void common_hal_rp2pio_statemachine_clear_txstall(rp2pio_statemachine_obj_t *self); size_t common_hal_rp2pio_statemachine_get_in_waiting(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); diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 00e715be6bed4..8017722e6288c 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -848,6 +848,18 @@ void common_hal_rp2pio_statemachine_clear_rxfifo(rp2pio_statemachine_obj_t *self self->pio->fdebug = stall_mask; } +bool common_hal_rp2pio_statemachine_get_txstall(rp2pio_statemachine_obj_t *self) { + uint32_t stall_mask = 1 << (PIO_FDEBUG_TXSTALL_LSB + self->state_machine); + return (self->pio->fdebug & stall_mask) != 0; +} + +void common_hal_rp2pio_statemachine_clear_txstall(rp2pio_statemachine_obj_t *self) { + uint8_t level = pio_sm_get_rx_fifo_level(self->pio, self->state_machine); + uint32_t stall_mask = 1 << (PIO_FDEBUG_TXSTALL_LSB + self->state_machine); + self->pio->fdebug = stall_mask; +} + + size_t common_hal_rp2pio_statemachine_get_in_waiting(rp2pio_statemachine_obj_t *self) { uint8_t level = pio_sm_get_rx_fifo_level(self->pio, self->state_machine); return level; From b482a732c6ab2293d3a9efdcd39dda92848238d5 Mon Sep 17 00:00:00 2001 From: Jeff Epler <jepler@gmail.com> Date: Fri, 6 May 2022 15:18:59 -0500 Subject: [PATCH 5/7] StateMachine: add swap flag Always use DMA if swap flag is enabled. Improve docs a bit --- locale/circuitpython.pot | 6 ++- .../bindings/rp2pio/StateMachine.c | 42 +++++++++++++------ .../bindings/rp2pio/StateMachine.h | 8 ++-- .../raspberrypi/common-hal/audiobusio/PDMIn.c | 4 +- .../imagecapture/ParallelImageCapture.c | 2 +- .../common-hal/neopixel_write/__init__.c | 2 +- .../common-hal/paralleldisplay/ParallelBus.c | 2 +- .../common-hal/rotaryio/IncrementalEncoder.c | 2 +- .../common-hal/rp2pio/StateMachine.c | 40 +++++++++++++----- .../common-hal/rp2pio/StateMachine.h | 2 +- 10 files changed, 74 insertions(+), 36 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index db06147fe0382..3f8322c8ddb98 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1540,6 +1540,10 @@ msgstr "" msgid "Mismatched data size" msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "" + #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/stm/common-hal/busio/SPI.c msgid "Missing MISO or MOSI Pin" msgstr "" @@ -2033,7 +2037,7 @@ msgstr "" msgid "RNG Init Error" msgstr "" -#: ports/nrf/common-hal/busio/UART.c ports/raspberrypi/common-hal/busio/UART.c +#: ports/nrf/common-hal/busio/UART.c msgid "RS485 Not yet supported on this device" msgstr "" diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index d234a50a9a067..c690a0da5db0d 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -378,7 +378,7 @@ STATIC mp_obj_t rp2pio_statemachine_stop(mp_obj_t self_obj) { } MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_stop_obj, rp2pio_statemachine_stop); -//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: Optional[int] = None) -> None: +//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: Optional[int] = None, swap bool = False) -> None: //| """Write the data contained in ``buffer`` to the state machine. If the buffer is empty, nothing happens. //| //| Writes to the FIFO will match the input buffer's element size. For example, bytearray elements @@ -391,14 +391,16 @@ MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_stop_obj, rp2pio_statemachine_stop //| :param ~circuitpython_typing.ReadableBuffer buffer: Write out the data in this buffer //| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]`` //| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)``""" +//| :param bool swap: For 2- and 4-byte elements, swap the byte order""" //| ... //| STATIC mp_obj_t rp2pio_statemachine_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_buffer, ARG_start, ARG_end }; + enum { ARG_buffer, ARG_start, ARG_end, ARG_swap }; static const mp_arg_t allowed_args[] = { { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); @@ -420,7 +422,7 @@ STATIC mp_obj_t rp2pio_statemachine_write(size_t n_args, const mp_obj_t *pos_arg mp_raise_ValueError(translate("Buffer elements must be 4 bytes long or less")); } - bool ok = common_hal_rp2pio_statemachine_write(self, ((uint8_t *)bufinfo.buf) + start, length, stride_in_bytes); + bool ok = common_hal_rp2pio_statemachine_write(self, ((uint8_t *)bufinfo.buf) + start, length, stride_in_bytes, args[ARG_swap].u_bool); if (mp_hal_is_interrupted()) { return mp_const_none; } @@ -431,7 +433,7 @@ STATIC mp_obj_t rp2pio_statemachine_write(size_t n_args, const mp_obj_t *pos_arg } MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_write_obj, 2, rp2pio_statemachine_write); -//| def background_write(self, once: Optional[ReadableBuffer]=None, *, loop: Optional[ReadableBuffer]=None) -> None: +//| def background_write(self, once: Optional[ReadableBuffer]=None, *, loop: Optional[ReadableBuffer]=None, swap: bool=False) -> None: //| """Write data to the TX fifo in the background, with optional looping. //| //| First, if any previous ``once`` or ``loop`` buffer has not been started, this function blocks until they have. @@ -459,8 +461,13 @@ MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_write_obj, 2, rp2pio_statemachine //| where a change in duty cycle requires a special transitional buffer to be used exactly once. Most //| use cases will probably only use one of ``once`` or ``loop``. //| +//| Having neither ``once`` nor ``loop`` terminates an existing +//| background looping write after exactly a whole loop. This is in contrast to +//| `stop_background_write, which interrupts an ongoing DMA operation. +//| //| :param ~Optional[circuitpython_typing.ReadableBuffer] once: Data to be written once //| :param ~Optional[circuitpython_typing.ReadableBuffer] loop: Data to be written repeatedly +//| :param bool swap: For 2- and 4-byte elements, swap the byte order""" //| """ //| ... //| @@ -483,10 +490,11 @@ STATIC void fill_buf_info(sm_buf_info *info, mp_obj_t obj, size_t *stride_in_byt } STATIC mp_obj_t rp2pio_statemachine_background_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_once, ARG_loop }; + enum { ARG_once, ARG_loop, ARG_swap }; static const mp_arg_t allowed_args[] = { { MP_QSTR_once, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_loop, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); @@ -502,7 +510,7 @@ STATIC mp_obj_t rp2pio_statemachine_background_write(size_t n_args, const mp_obj return mp_const_none; } - bool ok = common_hal_rp2pio_statemachine_background_write(self, &once_info, &loop_info, stride_in_bytes); + bool ok = common_hal_rp2pio_statemachine_background_write(self, &once_info, &loop_info, stride_in_bytes, args[ARG_swap].u_bool); if (mp_hal_is_interrupted()) { return mp_const_none; @@ -515,7 +523,9 @@ STATIC mp_obj_t rp2pio_statemachine_background_write(size_t n_args, const mp_obj MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_background_write_obj, 1, rp2pio_statemachine_background_write); //| def stop_background_write(self) -> None: -//| """Immediately stop a background write, if one is in progress. Items already in the TX FIFO are not affected.""" +//| """Immediately stop a background write, if one is in progress. Any +//| DMA in progress is halted, but items already in the TX FIFO are not +//| affected.""" //| STATIC mp_obj_t rp2pio_statemachine_obj_stop_background_write(mp_obj_t self_in) { rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -567,7 +577,7 @@ const mp_obj_property_t rp2pio_statemachine_pending_obj = { MP_ROM_NONE}, }; -//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: Optional[int] = None) -> None: +//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: Optional[int] = None, bool swap) -> None: //| """Read into ``buffer``. If the number of bytes to read is 0, nothing happens. The buffer //| includes any data added to the fifo even if it was added before this was called. //| @@ -581,16 +591,18 @@ const mp_obj_property_t rp2pio_statemachine_pending_obj = { //| //| :param ~circuitpython_typing.WriteableBuffer buffer: Read data into this buffer //| :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]`` -//| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)``""" +//| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)`` +//| :param bool swap: For 2- and 4-byte elements, swap the byte order""" //| ... //| STATIC mp_obj_t rp2pio_statemachine_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_buffer, ARG_start, ARG_end }; + enum { ARG_buffer, ARG_start, ARG_end, ARG_swap }; static const mp_arg_t allowed_args[] = { { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); @@ -613,7 +625,7 @@ STATIC mp_obj_t rp2pio_statemachine_readinto(size_t n_args, const mp_obj_t *pos_ mp_raise_ValueError(translate("Buffer elements must be 4 bytes long or less")); } - bool ok = common_hal_rp2pio_statemachine_readinto(self, ((uint8_t *)bufinfo.buf) + start, length, stride_in_bytes); + bool ok = common_hal_rp2pio_statemachine_readinto(self, ((uint8_t *)bufinfo.buf) + start, length, stride_in_bytes, args[ARG_swap].u_bool); if (!ok) { mp_raise_OSError(MP_EIO); } @@ -639,11 +651,13 @@ MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_readinto_obj, 2, rp2pio_statemach //| :param int out_end: End of the slice; this index is not included. Defaults to ``len(buffer_out)`` //| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]`` //| :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)``""" +//| :param bool swap_out: For 2- and 4-byte elements, swap the byte order for the buffer being transmitted (written)""" +//| :param bool swap_in: For 2- and 4-rx elements, swap the byte order for the buffer being received (read)""" //| ... //| STATIC mp_obj_t rp2pio_statemachine_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end, ARG_swap_out, ARG_swap_in }; static const mp_arg_t allowed_args[] = { { MP_QSTR_buffer_out, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_buffer_in, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, @@ -651,6 +665,8 @@ STATIC mp_obj_t rp2pio_statemachine_write_readinto(size_t n_args, const mp_obj_t { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_swap_out, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_swap_in, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); @@ -689,7 +705,7 @@ STATIC mp_obj_t rp2pio_statemachine_write_readinto(size_t n_args, const mp_obj_t out_stride_in_bytes, ((uint8_t *)buf_in_info.buf) + in_start, in_length, - in_stride_in_bytes); + in_stride_in_bytes, args[ARG_swap_out].u_bool, args[ARG_swap_in].u_bool); if (!ok) { mp_raise_OSError(MP_EIO); } diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.h b/ports/raspberrypi/bindings/rp2pio/StateMachine.h index 36e406032df40..3ec70a8703263 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.h +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -65,15 +65,15 @@ void common_hal_rp2pio_statemachine_stop(rp2pio_statemachine_obj_t *self); void common_hal_rp2pio_statemachine_run(rp2pio_statemachine_obj_t *self, const uint16_t *instructions, size_t len); // Writes out the given data. -bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes); -bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self, const sm_buf_info *once_obj, const sm_buf_info *loop_obj, uint8_t stride_in_bytes); +bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes, bool swap); +bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self, const sm_buf_info *once_obj, const sm_buf_info *loop_obj, uint8_t stride_in_bytes, bool swap); bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_obj_t *self); mp_int_t common_hal_rp2pio_statemachine_get_pending(rp2pio_statemachine_obj_t *self); bool common_hal_rp2pio_statemachine_get_writing(rp2pio_statemachine_obj_t *self); -bool common_hal_rp2pio_statemachine_readinto(rp2pio_statemachine_obj_t *self, uint8_t *data, size_t len, uint8_t stride_in_bytes); +bool common_hal_rp2pio_statemachine_readinto(rp2pio_statemachine_obj_t *self, uint8_t *data, size_t len, uint8_t stride_in_bytes, bool swap); bool common_hal_rp2pio_statemachine_write_readinto(rp2pio_statemachine_obj_t *self, const uint8_t *data_out, size_t out_len, uint8_t out_stride_in_bytes, - uint8_t *data_in, size_t in_len, uint8_t in_stride_in_bytes); + uint8_t *data_in, size_t in_len, uint8_t in_stride_in_bytes, bool swap_out, bool swap_in); // Return actual state machine frequency. uint32_t common_hal_rp2pio_statemachine_get_frequency(rp2pio_statemachine_obj_t *self); diff --git a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c index 1a120a45f790f..8301f9fde4026 100644 --- a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c +++ b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -157,9 +157,9 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *se size_t output_count = 0; common_hal_rp2pio_statemachine_clear_rxfifo(&self->state_machine); // Do one read to get the mic going and throw it away. - common_hal_rp2pio_statemachine_readinto(&self->state_machine, (uint8_t *)samples, 2 * sizeof(uint32_t), sizeof(uint32_t)); + common_hal_rp2pio_statemachine_readinto(&self->state_machine, (uint8_t *)samples, 2 * sizeof(uint32_t), sizeof(uint32_t), false); while (output_count < output_buffer_length && !common_hal_rp2pio_statemachine_get_rxstall(&self->state_machine)) { - common_hal_rp2pio_statemachine_readinto(&self->state_machine, (uint8_t *)samples, 2 * sizeof(uint32_t), sizeof(uint32_t)); + common_hal_rp2pio_statemachine_readinto(&self->state_machine, (uint8_t *)samples, 2 * sizeof(uint32_t), sizeof(uint32_t), false); // Call filter_sample just one place so it can be inlined. uint16_t value = filter_sample(samples); if (self->bit_depth == 8) { diff --git a/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c b/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c index c578c3216f630..3c5c57eea5ad3 100644 --- a/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +++ b/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c @@ -153,7 +153,7 @@ void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecaptur pio_sm_exec(pio, sm, pio_encode_jmp(offset)); pio_sm_set_enabled(pio, sm, true); - common_hal_rp2pio_statemachine_readinto(&self->state_machine, bufinfo.buf, bufinfo.len, 4); + common_hal_rp2pio_statemachine_readinto(&self->state_machine, bufinfo.buf, bufinfo.len, 4, false); pio_sm_set_enabled(pio, sm, false); } diff --git a/ports/raspberrypi/common-hal/neopixel_write/__init__.c b/ports/raspberrypi/common-hal/neopixel_write/__init__.c index 5c66d33feb248..d473285b02826 100644 --- a/ports/raspberrypi/common-hal/neopixel_write/__init__.c +++ b/ports/raspberrypi/common-hal/neopixel_write/__init__.c @@ -90,7 +90,7 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, while (port_get_raw_ticks(NULL) < next_start_raw_ticks) { } - common_hal_rp2pio_statemachine_write(&state_machine, pixels, num_bytes, 1 /* stride in bytes */); + common_hal_rp2pio_statemachine_write(&state_machine, pixels, num_bytes, 1 /* stride in bytes */, false); // Use a private deinit of the state machine that doesn't reset the pin. rp2pio_statemachine_deinit(&state_machine, true); diff --git a/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c b/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c index 4f30d121ad209..96c89ade95e86 100644 --- a/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c +++ b/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c @@ -161,7 +161,7 @@ void common_hal_paralleldisplay_parallelbus_send(mp_obj_t obj, display_byte_type paralleldisplay_parallelbus_obj_t *self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->command, byte_type == DISPLAY_DATA); - common_hal_rp2pio_statemachine_write(&self->state_machine, data, data_length, 1); + common_hal_rp2pio_statemachine_write(&self->state_machine, data, data_length, 1, false); } void common_hal_paralleldisplay_parallelbus_end_transaction(mp_obj_t obj) { diff --git a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c index bbeeb5a1b9d6a..0da12e5923ca2 100644 --- a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c @@ -98,7 +98,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode // We're guaranteed by the init code that some output will be available promptly uint8_t quiescent_state; - common_hal_rp2pio_statemachine_readinto(&self->state_machine, &quiescent_state, 1, 1); + common_hal_rp2pio_statemachine_readinto(&self->state_machine, &quiescent_state, 1, 1, false); shared_module_softencoder_state_init(self, quiescent_state & 3); common_hal_rp2pio_statemachine_set_interrupt_handler(&self->state_machine, incrementalencoder_interrupt_handler, self, PIO_IRQ0_INTF_SM0_RXNEMPTY_BITS); diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 8017722e6288c..bee77238b50d2 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -663,7 +663,7 @@ STATIC enum dma_channel_transfer_size _stride_to_dma_size(uint8_t stride) { static bool _transfer(rp2pio_statemachine_obj_t *self, const uint8_t *data_out, size_t out_len, uint8_t out_stride_in_bytes, - uint8_t *data_in, size_t in_len, uint8_t in_stride_in_bytes) { + uint8_t *data_in, size_t in_len, uint8_t in_stride_in_bytes, bool swap_out, bool swap_in) { // This implementation is based on SPI but varies because the tx and rx buffers // may be different lengths and occur at different times or speeds. @@ -674,13 +674,26 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, size_t len = MAX(out_len, in_len); bool tx = data_out != NULL; bool rx = data_in != NULL; - if (len >= dma_min_size_threshold) { + bool use_dma = len >= dma_min_size_threshold || swap_out || swap_in; + if (use_dma) { // Use DMA channels to service the two FIFOs if (tx) { chan_tx = dma_claim_unused_channel(false); + // DMA allocation failed... + if (chan_tx < 0) { + return false; + } } if (rx) { chan_rx = dma_claim_unused_channel(false); + // DMA allocation failed... + if (chan_rx < 0) { + // may need to free tx channel + if (chan_tx >= 0) { + dma_channel_unclaim(chan_tx); + } + return false; + } } } volatile uint8_t *tx_destination = NULL; @@ -698,7 +711,6 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, } } uint32_t stall_mask = 1 << (PIO_FDEBUG_TXSTALL_LSB + self->state_machine); - bool use_dma = (!rx || chan_rx >= 0) && (!tx || chan_tx >= 0); if (use_dma) { dma_channel_config c; uint32_t channel_mask = 0; @@ -708,6 +720,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, channel_config_set_dreq(&c, self->tx_dreq); channel_config_set_read_increment(&c, true); channel_config_set_write_increment(&c, false); + channel_config_set_bswap(&c, swap_out); dma_channel_configure(chan_tx, &c, tx_destination, data_out, @@ -721,6 +734,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, channel_config_set_dreq(&c, self->rx_dreq); channel_config_set_read_increment(&c, false); channel_config_set_write_increment(&c, true); + channel_config_set_bswap(&c, swap_in); dma_channel_configure(chan_rx, &c, data_in, rx_source, @@ -811,27 +825,27 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, // TODO: Provide a way around these checks in case someone wants to use the FIFO // with manually run code. -bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes) { +bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes, bool swap) { if (!self->out) { mp_raise_RuntimeError(translate("No out in program")); } - return _transfer(self, data, len, stride_in_bytes, NULL, 0, 0); + return _transfer(self, data, len, stride_in_bytes, NULL, 0, 0, swap, false); } -bool common_hal_rp2pio_statemachine_readinto(rp2pio_statemachine_obj_t *self, uint8_t *data, size_t len, uint8_t stride_in_bytes) { +bool common_hal_rp2pio_statemachine_readinto(rp2pio_statemachine_obj_t *self, uint8_t *data, size_t len, uint8_t stride_in_bytes, bool swap) { if (!self->in) { mp_raise_RuntimeError(translate("No in in program")); } - return _transfer(self, NULL, 0, 0, data, len, stride_in_bytes); + return _transfer(self, NULL, 0, 0, data, len, stride_in_bytes, false, swap); } bool common_hal_rp2pio_statemachine_write_readinto(rp2pio_statemachine_obj_t *self, const uint8_t *data_out, size_t out_len, uint8_t out_stride_in_bytes, - uint8_t *data_in, size_t in_len, uint8_t in_stride_in_bytes) { + uint8_t *data_in, size_t in_len, uint8_t in_stride_in_bytes, bool swap_out, bool swap_in) { if (!self->in || !self->out) { mp_raise_RuntimeError(translate("No in or out in program")); } - return _transfer(self, data_out, out_len, out_stride_in_bytes, data_in, in_len, in_stride_in_bytes); + return _transfer(self, data_out, out_len, out_stride_in_bytes, data_in, in_len, in_stride_in_bytes, swap_out, swap_in); } bool common_hal_rp2pio_statemachine_get_rxstall(rp2pio_statemachine_obj_t *self) { @@ -902,7 +916,7 @@ uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self) { return _current_program_offset[pio_index][sm]; } -bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self, const sm_buf_info *once, const sm_buf_info *loop, uint8_t stride_in_bytes) { +bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self, const sm_buf_info *once, const sm_buf_info *loop, uint8_t stride_in_bytes, bool swap) { uint8_t pio_index = pio_get_index(self->pio); uint8_t sm = self->state_machine; @@ -911,11 +925,13 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t * once = loop; } - if (SM_DMA_ALLOCATED(pio_index, sm)) { if (stride_in_bytes != self->background_stride_in_bytes) { mp_raise_ValueError(translate("Mismatched data size")); } + if (swap != self->byteswap) { + mp_raise_ValueError(translate("Mismatched swap flag")); + } while (self->pending_buffers) { RUN_BACKGROUND_TASKS; @@ -958,12 +974,14 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t * self->pending_buffers = pending_buffers; self->dma_completed = false; self->background_stride_in_bytes = stride_in_bytes; + self->byteswap = swap; c = dma_channel_get_default_config(channel); channel_config_set_transfer_data_size(&c, _stride_to_dma_size(stride_in_bytes)); channel_config_set_dreq(&c, self->tx_dreq); channel_config_set_read_increment(&c, true); channel_config_set_write_increment(&c, false); + channel_config_set_bswap(&c, swap); dma_channel_configure(channel, &c, tx_destination, once->info.buf, diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h index 470f0ed8b15d6..03dadc53b3c31 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -64,7 +64,7 @@ typedef struct { volatile int pending_buffers; sm_buf_info current, once, loop; int background_stride_in_bytes; - bool dma_completed; + bool dma_completed, byteswap; } rp2pio_statemachine_obj_t; void reset_rp2pio_statemachine(void); From 34427bd6ba02d0a3a3a6c8bfad85cd38dddaa1d8 Mon Sep 17 00:00:00 2001 From: Dan Halbert <halbert@adafruit.com> Date: Fri, 6 May 2022 22:36:24 -0400 Subject: [PATCH 6/7] Update StateMachine.c --- ports/raspberrypi/bindings/rp2pio/StateMachine.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index c690a0da5db0d..eee6e6b018d1b 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -391,7 +391,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_stop_obj, rp2pio_statemachine_stop //| :param ~circuitpython_typing.ReadableBuffer buffer: Write out the data in this buffer //| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]`` //| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)``""" -//| :param bool swap: For 2- and 4-byte elements, swap the byte order""" +//| :param bool swap: For 2- and 4-byte elements, swap (reverse) the byte order""" //| ... //| STATIC mp_obj_t rp2pio_statemachine_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -467,7 +467,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_write_obj, 2, rp2pio_statemachine //| //| :param ~Optional[circuitpython_typing.ReadableBuffer] once: Data to be written once //| :param ~Optional[circuitpython_typing.ReadableBuffer] loop: Data to be written repeatedly -//| :param bool swap: For 2- and 4-byte elements, swap the byte order""" +//| :param bool swap: For 2- and 4-byte elements, swap (reverse) the byte order //| """ //| ... //| @@ -592,7 +592,7 @@ const mp_obj_property_t rp2pio_statemachine_pending_obj = { //| :param ~circuitpython_typing.WriteableBuffer buffer: Read data into this buffer //| :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]`` //| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)`` -//| :param bool swap: For 2- and 4-byte elements, swap the byte order""" +//| :param bool swap: For 2- and 4-byte elements, swap (reverse) the byte order""" //| ... //| @@ -651,8 +651,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_readinto_obj, 2, rp2pio_statemach //| :param int out_end: End of the slice; this index is not included. Defaults to ``len(buffer_out)`` //| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]`` //| :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)``""" -//| :param bool swap_out: For 2- and 4-byte elements, swap the byte order for the buffer being transmitted (written)""" -//| :param bool swap_in: For 2- and 4-rx elements, swap the byte order for the buffer being received (read)""" +//| :param bool swap_out: For 2- and 4-byte elements, swap (reverse) the byte order for the buffer being transmitted (written)""" +//| :param bool swap_in: For 2- and 4-rx elements, swap (reverse) the byte order for the buffer being received (read)""" //| ... //| From 561ed3739a4b61e24999021f97879da1a7b8fca7 Mon Sep 17 00:00:00 2001 From: Jeff Epler <jepler@gmail.com> Date: Sat, 7 May 2022 07:49:16 -0500 Subject: [PATCH 7/7] fix the docstrings --- ports/raspberrypi/bindings/rp2pio/StateMachine.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index eee6e6b018d1b..5b903fb2ad21f 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -378,7 +378,7 @@ STATIC mp_obj_t rp2pio_statemachine_stop(mp_obj_t self_obj) { } MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_stop_obj, rp2pio_statemachine_stop); -//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: Optional[int] = None, swap bool = False) -> None: +//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: Optional[int] = None, swap: bool = False) -> None: //| """Write the data contained in ``buffer`` to the state machine. If the buffer is empty, nothing happens. //| //| Writes to the FIFO will match the input buffer's element size. For example, bytearray elements @@ -390,7 +390,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_stop_obj, rp2pio_statemachine_stop //| //| :param ~circuitpython_typing.ReadableBuffer buffer: Write out the data in this buffer //| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]`` -//| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)``""" +//| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)`` //| :param bool swap: For 2- and 4-byte elements, swap (reverse) the byte order""" //| ... //| @@ -463,7 +463,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_write_obj, 2, rp2pio_statemachine //| //| Having neither ``once`` nor ``loop`` terminates an existing //| background looping write after exactly a whole loop. This is in contrast to -//| `stop_background_write, which interrupts an ongoing DMA operation. +//| `stop_background_write`, which interrupts an ongoing DMA operation. //| //| :param ~Optional[circuitpython_typing.ReadableBuffer] once: Data to be written once //| :param ~Optional[circuitpython_typing.ReadableBuffer] loop: Data to be written repeatedly @@ -577,7 +577,7 @@ const mp_obj_property_t rp2pio_statemachine_pending_obj = { MP_ROM_NONE}, }; -//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: Optional[int] = None, bool swap) -> None: +//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: Optional[int] = None, swap: bool=False) -> None: //| """Read into ``buffer``. If the number of bytes to read is 0, nothing happens. The buffer //| includes any data added to the fifo even if it was added before this was called. //| @@ -650,8 +650,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_readinto_obj, 2, rp2pio_statemach //| :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]`` //| :param int out_end: End of the slice; this index is not included. Defaults to ``len(buffer_out)`` //| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]`` -//| :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)``""" -//| :param bool swap_out: For 2- and 4-byte elements, swap (reverse) the byte order for the buffer being transmitted (written)""" +//| :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)`` +//| :param bool swap_out: For 2- and 4-byte elements, swap (reverse) the byte order for the buffer being transmitted (written) //| :param bool swap_in: For 2- and 4-rx elements, swap (reverse) the byte order for the buffer being received (read)""" //| ... //|