From a58bf235d8d90ca4ec185c296b2b95f5b11507ea Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 13 Feb 2022 16:38:53 -0600 Subject: [PATCH 1/2] raspberry: StateMachine: Add support for wrap=, wrap_target= --- .../bindings/rp2pio/StateMachine.c | 22 ++++++++++++-- .../bindings/rp2pio/StateMachine.h | 3 +- .../common-hal/audiobusio/I2SOut.c | 3 +- .../raspberrypi/common-hal/audiobusio/PDMIn.c | 5 ++-- .../imagecapture/ParallelImageCapture.c | 4 +-- .../common-hal/neopixel_write/__init__.c | 3 +- .../common-hal/paralleldisplay/ParallelBus.c | 5 ++-- .../raspberrypi/common-hal/pulseio/PulseIn.c | 3 +- .../common-hal/rotaryio/IncrementalEncoder.c | 4 ++- .../common-hal/rp2pio/StateMachine.c | 29 ++++++++++++------- .../common-hal/rp2pio/StateMachine.h | 4 +-- 11 files changed, 58 insertions(+), 27 deletions(-) diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index fb13821e35..557b15617d 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -87,7 +87,10 @@ //| auto_push: bool = False, //| push_threshold: int = 32, //| in_shift_right: bool = True, -//| user_interruptible: bool = True) -> None: +//| user_interruptible: bool = True, +//| wrap_target: int = 0, +//| wrap: int = -1, +//| ) -> None: //| //| """Construct a StateMachine object on the given pins with the given program. //| @@ -136,6 +139,10 @@ //| 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 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. //| """ //| ... //| @@ -155,7 +162,9 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n ARG_auto_pull, ARG_pull_threshold, ARG_out_shift_right, ARG_wait_for_txstall, ARG_auto_push, ARG_push_threshold, ARG_in_shift_right, - ARG_user_interruptible,}; + ARG_user_interruptible, + ARG_wrap_target, + ARG_wrap,}; 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 }, @@ -194,6 +203,9 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n { MP_QSTR_push_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_in_shift_right, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_user_interruptible, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + + { 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_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); @@ -254,6 +266,9 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n mp_raise_ValueError(translate("Init program size invalid")); } + int wrap = args[ARG_wrap].u_int; + int wrap_target = args[ARG_wrap_target].u_int; + common_hal_rp2pio_statemachine_construct(self, bufinfo.buf, bufinfo.len / 2, args[ARG_frequency].u_int, @@ -269,7 +284,8 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n args[ARG_auto_pull].u_bool, pull_threshold, args[ARG_out_shift_right].u_bool, 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); + args[ARG_user_interruptible].u_bool, + wrap_target, wrap); return MP_OBJ_FROM_PTR(self); } diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.h b/ports/raspberrypi/bindings/rp2pio/StateMachine.h index 3f3b8cf7d8..eb3f4addc5 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.h +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -51,7 +51,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, bool auto_pull, uint8_t pull_threshold, bool out_shift_right, bool wait_for_txstall, bool auto_push, uint8_t push_threshold, bool in_shift_right, - bool user_interruptible); + bool user_interruptible, + int wrap_taget, int wrap); void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self); bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self); diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c index 8432e47a52..a7cce01640 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c @@ -134,7 +134,8 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, false, 32, false, // shift out left to start with MSB false, // Wait for txstall false, 32, false, // in settings - false); // Not user-interruptible. + false, // Not user-interruptible. + 0, -1); // wrap settings 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 4b5694706f..de1b8a4b5e 100644 --- a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c +++ b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -63,7 +63,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, // Use the state machine to manage pins. common_hal_rp2pio_statemachine_construct(&self->state_machine, - pdmin, sizeof(pdmin) / sizeof(pdmin[0]), + pdmin, MP_ARRAY_SIZE(pdmin), sample_rate * 32 * 2, // Frequency based on sample rate NULL, 0, NULL, 1, 0, 0xffffffff, // out pin @@ -78,7 +78,8 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, false, 32, false, // out settings false, // Wait for txstall false, 32, true, // in settings - false); // Not user-interruptible. + false, // Not user-interruptible. + 0, -1); // wrap settings uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); if (actual_frequency < MIN_MIC_CLOCK) { diff --git a/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c b/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c index 45a3766897..045441aedd 100644 --- a/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +++ b/ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c @@ -118,13 +118,13 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle false, 32, false, // out settings false, // wait for txstall true, 32, true, // in settings - false); // Not user-interruptible. + false, // Not user-interruptible. + 2, 5); // wrap settings PIO pio = self->state_machine.pio; uint8_t pio_index = pio_get_index(pio); uint sm = self->state_machine.state_machine; - rp2pio_statemachine_set_wrap(&self->state_machine, 2, 5); } 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 09388af481..1acfed055c 100644 --- a/ports/raspberrypi/common-hal/neopixel_write/__init__.c +++ b/ports/raspberrypi/common-hal/neopixel_write/__init__.c @@ -78,7 +78,8 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, false, 32, true, // RX setting we don't use false, // claim pins false, // Not user-interruptible. - false); // No sideset enable + false, // No sideset enable + 0, -1); // wrap if (!ok) { // Do nothing. Maybe bitbang? return; diff --git a/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c b/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c index 2e0ae4def2..4243eddab3 100644 --- a/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c +++ b/ports/raspberrypi/common-hal/paralleldisplay/ParallelBus.c @@ -92,7 +92,7 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu } common_hal_rp2pio_statemachine_construct(&self->state_machine, - parallel_program, sizeof(parallel_program) / sizeof(parallel_program[0]), + parallel_program, MP_ARRAY_SIZE(parallel_program), frequency * 2, // frequency multiplied by 2 as 2 PIO instructions NULL, 0, // init data0, 8, 0, 255, // first out pin, # out pins @@ -106,7 +106,8 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu true, 8, true, // TX, auto pull every 8 bits. shift left to output msb first false, // wait for TX stall false, 32, true, // RX setting we don't use - false); // Not user-interruptible. + false, // Not user-interruptible. + 0, -1); // wrap settings 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 e507cd16e8..83edde25ad 100644 --- a/ports/raspberrypi/common-hal/pulseio/PulseIn.c +++ b/ports/raspberrypi/common-hal/pulseio/PulseIn.c @@ -74,7 +74,8 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, true, 32, true, // RX auto-push every 32 bits false, // claim pins false, // Not user-interruptible. - false); // No sideset enable + false, // No sideset enable + 0, -1); // wrap settings if (!ok) { mp_raise_RuntimeError(translate("All state machines in use")); diff --git a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c index 1f15b010f7..97749c8f14 100644 --- a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c @@ -92,7 +92,9 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode false, 32, false, // out settings false, // Wait for txstall false, 32, false, // in settings - false); // Not user-interruptible. + false, // Not user-interruptible. + 0, MP_ARRAY_SIZE(encoder) - 1 // wrap settings + ); // 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 ac5a41652a..cd1d383008 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -165,7 +165,8 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, bool auto_push, uint8_t push_threshold, bool in_shift_right, bool claim_pins, bool user_interruptible, - bool sideset_enable + bool sideset_enable, + int wrap_target, int wrap ) { // 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); @@ -289,7 +290,18 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, if (jmp_pin != NULL) { sm_config_set_jmp_pin(&c, jmp_pin->number); } - sm_config_set_wrap(&c, program_offset, program_offset + program_len - 1); + + mp_arg_validate_int_range(wrap, -1, program_len - 1, MP_QSTR_wrap); + if (wrap == -1) { + wrap = program_len - 1; + } + + mp_arg_validate_int_range(wrap_target, 0, program_len - 1, MP_QSTR_wrap_target); + + wrap += program_offset; + wrap_target += program_offset; + + sm_config_set_wrap(&c, wrap_target, wrap); sm_config_set_in_shift(&c, in_shift_right, auto_push, push_threshold); sm_config_set_out_shift(&c, out_shift_right, auto_pull, pull_threshold); @@ -348,7 +360,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, bool auto_pull, uint8_t pull_threshold, bool out_shift_right, bool wait_for_txstall, bool auto_push, uint8_t push_threshold, bool in_shift_right, - bool user_interruptible) { + bool user_interruptible, + int wrap_target, int wrap) { // 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; @@ -510,7 +523,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, auto_push, push_threshold, in_shift_right, true /* claim pins */, user_interruptible, - sideset_enable); + sideset_enable, + wrap_target, wrap); if (!ok) { mp_raise_RuntimeError(translate("All state machines in use")); } @@ -834,10 +848,3 @@ uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self) { uint8_t sm = self->state_machine; return _current_program_offset[pio_index][sm]; } - -void rp2pio_statemachine_set_wrap(rp2pio_statemachine_obj_t *self, uint wrap_target, uint wrap) { - uint8_t sm = self->state_machine; - uint8_t offset = rp2pio_statemachine_program_offset(self); - - pio_sm_set_wrap(self->pio, sm, offset + wrap_target, offset + wrap); -} diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h index 125e0fa68b..0e8e7a3806 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -76,10 +76,10 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, bool auto_push, uint8_t push_threshold, bool in_shift_right, bool claim_pins, bool interruptible, - bool sideset_enable); + bool sideset_enable, + int wrap_target, int wrap); uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self); -void rp2pio_statemachine_set_wrap(rp2pio_statemachine_obj_t *self, uint wrap_target, uint wrap); void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins); From 729fcf749ea3981349b949746e38365e156fdf79 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 15 Feb 2022 16:03:52 -0600 Subject: [PATCH 2/2] Fix doc markup --- ports/raspberrypi/bindings/rp2pio/StateMachine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index 557b15617d..98213be265 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -139,8 +139,8 @@ //| 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 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`` +//| :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. //| """