Skip to content

Commit f1d25af

Browse files
committed
Allow PIO to be user-interruptible
1 parent 41168c8 commit f1d25af

File tree

11 files changed

+69
-26
lines changed

11 files changed

+69
-26
lines changed

ports/raspberrypi/bindings/rp2pio/StateMachine.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,13 @@
8080
//| initial_sideset_pin_direction: int = 0x1f,
8181
//| exclusive_pin_use: bool = True,
8282
//| auto_pull: bool = False,
83-
//| pull_threshold : int = 32,
84-
//| out_shift_right : bool = True,
83+
//| pull_threshold: int = 32,
84+
//| out_shift_right: bool = True,
8585
//| wait_for_txstall: bool = True,
8686
//| auto_push: bool = False,
87-
//| push_threshold : int = 32,
88-
//| in_shift_right : bool = True) -> None:
87+
//| push_threshold: int = 32,
88+
//| in_shift_right: bool = True,
89+
//| user_interruptible: bool = True) -> None:
8990
//|
9091
//| """Construct a StateMachine object on the given pins with the given program.
9192
//|
@@ -126,7 +127,14 @@
126127
//| :param int push_threshold: Number of bits to shift before saving the ISR value to the RX FIFO
127128
//| :param bool in_shift_right: When True, data is shifted into the right side (LSB) of the
128129
//| ISR. It is shifted into the left (MSB) otherwise. NOTE! This impacts data alignment
129-
//| when the number of bytes is not a power of two (1, 2 or 4 bytes)."""
130+
//| when the number of bytes is not a power of two (1, 2 or 4 bytes).
131+
//| :param bool user_interruptible: When True (the default),
132+
//| `write()`, `readinto()`, and `write_readinto()` can be interrupted by a ctrl-C.
133+
//| This is useful when developing a PIO program: if there is an error in the program
134+
//| that causes an infinite loop, you will be able to interrupt the loop.
135+
//| However, if you are writing to a device that can get into a bad state if a read or write
136+
//| is interrupted, you may want to set this to False after your program has been vetted.
137+
//| """
130138
//| ...
131139
//|
132140

@@ -143,7 +151,8 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
143151
ARG_exclusive_pin_use,
144152
ARG_auto_pull, ARG_pull_threshold, ARG_out_shift_right,
145153
ARG_wait_for_txstall,
146-
ARG_auto_push, ARG_push_threshold, ARG_in_shift_right};
154+
ARG_auto_push, ARG_push_threshold, ARG_in_shift_right,
155+
ARG_user_interruptible,};
147156
static const mp_arg_t allowed_args[] = {
148157
{ MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ },
149158
{ MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT },
@@ -179,6 +188,7 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
179188
{ MP_QSTR_auto_push, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
180189
{ MP_QSTR_push_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
181190
{ MP_QSTR_in_shift_right, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
191+
{ MP_QSTR_user_interruptible, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
182192
};
183193
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
184194
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -252,7 +262,8 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
252262
args[ARG_exclusive_pin_use].u_bool,
253263
args[ARG_auto_pull].u_bool, pull_threshold, args[ARG_out_shift_right].u_bool,
254264
args[ARG_wait_for_txstall].u_bool,
255-
args[ARG_auto_push].u_bool, push_threshold, args[ARG_in_shift_right].u_bool);
265+
args[ARG_auto_push].u_bool, push_threshold, args[ARG_in_shift_right].u_bool,
266+
args[ARG_user_interruptible].u_bool);
256267
return MP_OBJ_FROM_PTR(self);
257268
}
258269

ports/raspberrypi/bindings/rp2pio/StateMachine.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
4949
bool exclusive_pin_use,
5050
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
5151
bool wait_for_txstall,
52-
bool auto_push, uint8_t push_threshold, bool in_shift_right);
52+
bool auto_push, uint8_t push_threshold, bool in_shift_right,
53+
bool user_interruptible);
5354

5455
void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self);
5556
bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self);

ports/raspberrypi/common-hal/audiobusio/I2SOut.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
132132
true, // exclusive pin use
133133
false, 32, false, // shift out left to start with MSB
134134
false, // Wait for txstall
135-
false, 32, false); // in settings
135+
false, 32, false, // in settings
136+
false); // Not user-interruptible.
136137

137138
self->playing = false;
138139
audio_dma_init(&self->dma);

ports/raspberrypi/common-hal/audiobusio/PDMIn.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self,
7676
true, // exclusive pin use
7777
false, 32, false, // out settings
7878
false, // Wait for txstall
79-
false, 32, true); // in settings
79+
false, 32, true, // in settings
80+
false); // Not user-interruptible
8081

8182
uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine);
8283
if (actual_frequency < MIN_MIC_CLOCK) {

ports/raspberrypi/common-hal/displayio/ParallelBus.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t *sel
104104
true, // exclusive pin usage
105105
true, 8, true, // TX, auto pull every 8 bits. shift left to output msb first
106106
false, // wait for TX stall
107-
false, 32, true // RX setting we don't use
108-
);
107+
false, 32, true, // RX setting we don't use
108+
false); // Not user-interruptible.
109109

110110
common_hal_rp2pio_statemachine_never_reset(&self->state_machine);
111111
}

ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle
116116
true, // exclusive pin use
117117
false, 32, false, // out settings
118118
false, // wait for txstall
119-
true, 32, true); // in settings
119+
true, 32, true, // in settings
120+
false); // Not user-interruptible.
121+
120122

121123
PIO pio = self->state_machine.pio;
122124
uint8_t pio_index = pio_get_index(pio);

ports/raspberrypi/common-hal/neopixel_write/__init__.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
7676
true, 8, false, // TX, auto pull every 8 bits. shift left to output msb first
7777
true, // Wait for txstall. If we don't, then we'll deinit too quickly.
7878
false, 32, true, // RX setting we don't use
79-
false); // claim pins
79+
false, // claim pins
80+
false); // Not user-interruptible.
8081
if (!ok) {
8182
// Do nothing. Maybe bitbang?
8283
return;

ports/raspberrypi/common-hal/pulseio/PulseIn.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self,
7272
false, 8, false, // TX, unused
7373
false,
7474
true, 32, true, // RX auto-push every 32 bits
75-
false); // claim pins
75+
false, // claim pins
76+
false); // Not user-interruptible.
7677

7778
if (!ok) {
7879
mp_raise_RuntimeError(translate("All state machines in use"));

ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
8989
true, // exclusive pin use
9090
false, 32, false, // out settings
9191
false, // Wait for txstall
92-
false, 32, false); // in settings
92+
false, 32, false, // in settings
93+
false); // Not user-interruptible.
9394

9495
common_hal_rp2pio_statemachine_run(&self->state_machine, encoder_init, MP_ARRAY_SIZE(encoder_init));
9596

ports/raspberrypi/common-hal/rp2pio/StateMachine.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
163163
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
164164
bool wait_for_txstall,
165165
bool auto_push, uint8_t push_threshold, bool in_shift_right,
166-
bool claim_pins) {
166+
bool claim_pins,
167+
bool user_interruptible
168+
) {
167169
// Create a program id that isn't the pointer so we can store it without storing the original object.
168170
uint32_t program_id = ~((uint32_t)program);
169171

@@ -303,6 +305,7 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
303305
self->out_shift_right = out_shift_right;
304306
self->in_shift_right = in_shift_right;
305307
self->wait_for_txstall = wait_for_txstall;
308+
self->user_interruptible = user_interruptible;
306309

307310
self->init = init;
308311
self->init_len = init_len;
@@ -338,7 +341,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
338341
bool exclusive_pin_use,
339342
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
340343
bool wait_for_txstall,
341-
bool auto_push, uint8_t push_threshold, bool in_shift_right) {
344+
bool auto_push, uint8_t push_threshold, bool in_shift_right,
345+
bool user_interruptible) {
342346

343347
// First, check that all pins are free OR already in use by any PIO if exclusive_pin_use is false.
344348
uint32_t pins_we_use = wait_gpio_mask;
@@ -482,7 +486,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
482486
if (initial_pin_direction & (pull_up | pull_down)) {
483487
mp_raise_ValueError(translate("pull masks conflict with direction masks"));
484488
}
485-
bool ok = rp2pio_statemachine_construct(self,
489+
bool ok = rp2pio_statemachine_construct(
490+
self,
486491
program, program_len,
487492
frequency,
488493
init, init_len,
@@ -497,7 +502,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
497502
auto_pull, pull_threshold, out_shift_right,
498503
wait_for_txstall,
499504
auto_push, push_threshold, in_shift_right,
500-
true /* claim pins */);
505+
true /* claim pins */,
506+
user_interruptible);
501507
if (!ok) {
502508
mp_raise_RuntimeError(translate("All state machines in use"));
503509
}
@@ -664,6 +670,16 @@ static bool _transfer(rp2pio_statemachine_obj_t *self,
664670
(tx && dma_channel_is_busy(chan_tx))) {
665671
// TODO: We should idle here until we get a DMA interrupt or something else.
666672
RUN_BACKGROUND_TASKS;
673+
if (self->user_interruptible && mp_hal_is_interrupted()) {
674+
if (rx && dma_channel_is_busy(chan_rx)) {
675+
dma_channel_abort(chan_rx);
676+
}
677+
if (tx && dma_channel_is_busy(chan_tx)) {
678+
dma_channel_abort(chan_tx);
679+
}
680+
break;
681+
}
682+
667683
}
668684
// Clear the stall bit so we can detect when the state machine is done transmitting.
669685
self->pio->fdebug = stall_mask;
@@ -678,7 +694,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self,
678694
dma_channel_unclaim(chan_tx);
679695
}
680696

681-
if (!use_dma) {
697+
if (!use_dma && !(self->user_interruptible && mp_hal_is_interrupted())) {
682698
// Use software for small transfers, or if couldn't claim two DMA channels
683699
size_t rx_remaining = in_len / in_stride_in_bytes;
684700
size_t tx_remaining = out_len / out_stride_in_bytes;
@@ -707,6 +723,9 @@ static bool _transfer(rp2pio_statemachine_obj_t *self,
707723
--rx_remaining;
708724
}
709725
RUN_BACKGROUND_TASKS;
726+
if (self->user_interruptible && mp_hal_is_interrupted()) {
727+
break;
728+
}
710729
}
711730
// Clear the stall bit so we can detect when the state machine is done transmitting.
712731
self->pio->fdebug = stall_mask;
@@ -717,6 +736,9 @@ static bool _transfer(rp2pio_statemachine_obj_t *self,
717736
while (!pio_sm_is_tx_fifo_empty(self->pio, self->state_machine) ||
718737
(self->wait_for_txstall && (self->pio->fdebug & stall_mask) == 0)) {
719738
RUN_BACKGROUND_TASKS;
739+
if (self->user_interruptible && mp_hal_is_interrupted()) {
740+
break;
741+
}
720742
}
721743
}
722744
return true;

ports/raspberrypi/common-hal/rp2pio/StateMachine.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,16 @@ typedef struct {
4343
uint32_t initial_pin_direction;
4444
uint32_t pull_pin_up;
4545
uint32_t pull_pin_down;
46+
uint tx_dreq;
47+
uint rx_dreq;
48+
uint32_t actual_frequency;
49+
pio_sm_config sm_config;
4650
bool in;
4751
bool out;
4852
bool wait_for_txstall;
49-
uint tx_dreq;
50-
uint rx_dreq;
5153
bool out_shift_right;
5254
bool in_shift_right;
53-
uint32_t actual_frequency;
54-
pio_sm_config sm_config;
55+
bool user_interruptible;
5556
uint8_t offset;
5657
} rp2pio_statemachine_obj_t;
5758

@@ -73,7 +74,8 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
7374
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
7475
bool wait_for_txstall,
7576
bool auto_push, uint8_t push_threshold, bool in_shift_right,
76-
bool claim_pins);
77+
bool claim_pins,
78+
bool interruptible);
7779

7880
uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self);
7981
void rp2pio_statemachine_set_wrap(rp2pio_statemachine_obj_t *self, uint wrap_target, uint wrap);

0 commit comments

Comments
 (0)