Allow PIO to be user-interruptible
This commit is contained in:
parent
41168c8008
commit
f1d25af7ba
|
@ -85,7 +85,8 @@
|
||||||
//| wait_for_txstall: bool = True,
|
//| wait_for_txstall: bool = True,
|
||||||
//| auto_push: bool = False,
|
//| auto_push: bool = False,
|
||||||
//| push_threshold: int = 32,
|
//| push_threshold: int = 32,
|
||||||
//| in_shift_right : bool = True) -> None:
|
//| in_shift_right: bool = True,
|
||||||
|
//| user_interruptible: bool = True) -> None:
|
||||||
//|
|
//|
|
||||||
//| """Construct a StateMachine object on the given pins with the given program.
|
//| """Construct a StateMachine object on the given pins with the given program.
|
||||||
//|
|
//|
|
||||||
|
@ -126,7 +127,14 @@
|
||||||
//| :param int push_threshold: Number of bits to shift before saving the ISR value to the RX FIFO
|
//| :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
|
//| :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
|
//| 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)."""
|
//| 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.
|
||||||
|
//| """
|
||||||
//| ...
|
//| ...
|
||||||
//|
|
//|
|
||||||
|
|
||||||
|
@ -143,7 +151,8 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
|
||||||
ARG_exclusive_pin_use,
|
ARG_exclusive_pin_use,
|
||||||
ARG_auto_pull, ARG_pull_threshold, ARG_out_shift_right,
|
ARG_auto_pull, ARG_pull_threshold, ARG_out_shift_right,
|
||||||
ARG_wait_for_txstall,
|
ARG_wait_for_txstall,
|
||||||
ARG_auto_push, ARG_push_threshold, ARG_in_shift_right};
|
ARG_auto_push, ARG_push_threshold, ARG_in_shift_right,
|
||||||
|
ARG_user_interruptible,};
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
{ MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||||
{ MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT },
|
{ 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
|
||||||
{ MP_QSTR_auto_push, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
{ MP_QSTR_auto_push, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||||
{ MP_QSTR_push_threshold, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
|
{ 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_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_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
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
|
||||||
args[ARG_exclusive_pin_use].u_bool,
|
args[ARG_exclusive_pin_use].u_bool,
|
||||||
args[ARG_auto_pull].u_bool, pull_threshold, args[ARG_out_shift_right].u_bool,
|
args[ARG_auto_pull].u_bool, pull_threshold, args[ARG_out_shift_right].u_bool,
|
||||||
args[ARG_wait_for_txstall].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_auto_push].u_bool, push_threshold, args[ARG_in_shift_right].u_bool,
|
||||||
|
args[ARG_user_interruptible].u_bool);
|
||||||
return MP_OBJ_FROM_PTR(self);
|
return MP_OBJ_FROM_PTR(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
bool exclusive_pin_use,
|
bool exclusive_pin_use,
|
||||||
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
|
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
|
||||||
bool wait_for_txstall,
|
bool wait_for_txstall,
|
||||||
bool auto_push, uint8_t push_threshold, bool in_shift_right);
|
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
||||||
|
bool user_interruptible);
|
||||||
|
|
||||||
void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self);
|
void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self);
|
||||||
bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self);
|
bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
|
@ -132,7 +132,8 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
|
||||||
true, // exclusive pin use
|
true, // exclusive pin use
|
||||||
false, 32, false, // shift out left to start with MSB
|
false, 32, false, // shift out left to start with MSB
|
||||||
false, // Wait for txstall
|
false, // Wait for txstall
|
||||||
false, 32, false); // in settings
|
false, 32, false, // in settings
|
||||||
|
false); // Not user-interruptible.
|
||||||
|
|
||||||
self->playing = false;
|
self->playing = false;
|
||||||
audio_dma_init(&self->dma);
|
audio_dma_init(&self->dma);
|
||||||
|
|
|
@ -76,7 +76,8 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self,
|
||||||
true, // exclusive pin use
|
true, // exclusive pin use
|
||||||
false, 32, false, // out settings
|
false, 32, false, // out settings
|
||||||
false, // Wait for txstall
|
false, // Wait for txstall
|
||||||
false, 32, true); // in settings
|
false, 32, true, // in settings
|
||||||
|
false); // Not user-interruptible
|
||||||
|
|
||||||
uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine);
|
uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine);
|
||||||
if (actual_frequency < MIN_MIC_CLOCK) {
|
if (actual_frequency < MIN_MIC_CLOCK) {
|
||||||
|
|
|
@ -104,8 +104,8 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t *sel
|
||||||
true, // exclusive pin usage
|
true, // exclusive pin usage
|
||||||
true, 8, true, // TX, auto pull every 8 bits. shift left to output msb first
|
true, 8, true, // TX, auto pull every 8 bits. shift left to output msb first
|
||||||
false, // wait for TX stall
|
false, // wait for TX stall
|
||||||
false, 32, true // RX setting we don't use
|
false, 32, true, // RX setting we don't use
|
||||||
);
|
false); // Not user-interruptible.
|
||||||
|
|
||||||
common_hal_rp2pio_statemachine_never_reset(&self->state_machine);
|
common_hal_rp2pio_statemachine_never_reset(&self->state_machine);
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,9 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle
|
||||||
true, // exclusive pin use
|
true, // exclusive pin use
|
||||||
false, 32, false, // out settings
|
false, 32, false, // out settings
|
||||||
false, // wait for txstall
|
false, // wait for txstall
|
||||||
true, 32, true); // in settings
|
true, 32, true, // in settings
|
||||||
|
false); // Not user-interruptible.
|
||||||
|
|
||||||
|
|
||||||
PIO pio = self->state_machine.pio;
|
PIO pio = self->state_machine.pio;
|
||||||
uint8_t pio_index = pio_get_index(pio);
|
uint8_t pio_index = pio_get_index(pio);
|
||||||
|
|
|
@ -76,7 +76,8 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
|
||||||
true, 8, false, // TX, auto pull every 8 bits. shift left to output msb first
|
true, 8, false, // TX, auto pull every 8 bits. shift left to output msb first
|
||||||
true, // Wait for txstall. If we don't, then we'll deinit too quickly.
|
true, // Wait for txstall. If we don't, then we'll deinit too quickly.
|
||||||
false, 32, true, // RX setting we don't use
|
false, 32, true, // RX setting we don't use
|
||||||
false); // claim pins
|
false, // claim pins
|
||||||
|
false); // Not user-interruptible.
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
// Do nothing. Maybe bitbang?
|
// Do nothing. Maybe bitbang?
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -72,7 +72,8 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self,
|
||||||
false, 8, false, // TX, unused
|
false, 8, false, // TX, unused
|
||||||
false,
|
false,
|
||||||
true, 32, true, // RX auto-push every 32 bits
|
true, 32, true, // RX auto-push every 32 bits
|
||||||
false); // claim pins
|
false, // claim pins
|
||||||
|
false); // Not user-interruptible.
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
mp_raise_RuntimeError(translate("All state machines in use"));
|
mp_raise_RuntimeError(translate("All state machines in use"));
|
||||||
|
|
|
@ -89,7 +89,8 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
|
||||||
true, // exclusive pin use
|
true, // exclusive pin use
|
||||||
false, 32, false, // out settings
|
false, 32, false, // out settings
|
||||||
false, // Wait for txstall
|
false, // Wait for txstall
|
||||||
false, 32, false); // in settings
|
false, 32, false, // in settings
|
||||||
|
false); // Not user-interruptible.
|
||||||
|
|
||||||
common_hal_rp2pio_statemachine_run(&self->state_machine, encoder_init, MP_ARRAY_SIZE(encoder_init));
|
common_hal_rp2pio_statemachine_run(&self->state_machine, encoder_init, MP_ARRAY_SIZE(encoder_init));
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,9 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
|
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
|
||||||
bool wait_for_txstall,
|
bool wait_for_txstall,
|
||||||
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
||||||
bool claim_pins) {
|
bool claim_pins,
|
||||||
|
bool user_interruptible
|
||||||
|
) {
|
||||||
// Create a program id that isn't the pointer so we can store it without storing the original object.
|
// 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);
|
uint32_t program_id = ~((uint32_t)program);
|
||||||
|
|
||||||
|
@ -303,6 +305,7 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
self->out_shift_right = out_shift_right;
|
self->out_shift_right = out_shift_right;
|
||||||
self->in_shift_right = in_shift_right;
|
self->in_shift_right = in_shift_right;
|
||||||
self->wait_for_txstall = wait_for_txstall;
|
self->wait_for_txstall = wait_for_txstall;
|
||||||
|
self->user_interruptible = user_interruptible;
|
||||||
|
|
||||||
self->init = init;
|
self->init = init;
|
||||||
self->init_len = init_len;
|
self->init_len = init_len;
|
||||||
|
@ -338,7 +341,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
bool exclusive_pin_use,
|
bool exclusive_pin_use,
|
||||||
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
|
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
|
||||||
bool wait_for_txstall,
|
bool wait_for_txstall,
|
||||||
bool auto_push, uint8_t push_threshold, bool in_shift_right) {
|
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
||||||
|
bool user_interruptible) {
|
||||||
|
|
||||||
// First, check that all pins are free OR already in use by any PIO if exclusive_pin_use is false.
|
// 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;
|
uint32_t pins_we_use = wait_gpio_mask;
|
||||||
|
@ -482,7 +486,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
if (initial_pin_direction & (pull_up | pull_down)) {
|
if (initial_pin_direction & (pull_up | pull_down)) {
|
||||||
mp_raise_ValueError(translate("pull masks conflict with direction masks"));
|
mp_raise_ValueError(translate("pull masks conflict with direction masks"));
|
||||||
}
|
}
|
||||||
bool ok = rp2pio_statemachine_construct(self,
|
bool ok = rp2pio_statemachine_construct(
|
||||||
|
self,
|
||||||
program, program_len,
|
program, program_len,
|
||||||
frequency,
|
frequency,
|
||||||
init, init_len,
|
init, init_len,
|
||||||
|
@ -497,7 +502,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
auto_pull, pull_threshold, out_shift_right,
|
auto_pull, pull_threshold, out_shift_right,
|
||||||
wait_for_txstall,
|
wait_for_txstall,
|
||||||
auto_push, push_threshold, in_shift_right,
|
auto_push, push_threshold, in_shift_right,
|
||||||
true /* claim pins */);
|
true /* claim pins */,
|
||||||
|
user_interruptible);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
mp_raise_RuntimeError(translate("All state machines in use"));
|
mp_raise_RuntimeError(translate("All state machines in use"));
|
||||||
}
|
}
|
||||||
|
@ -664,6 +670,16 @@ static bool _transfer(rp2pio_statemachine_obj_t *self,
|
||||||
(tx && dma_channel_is_busy(chan_tx))) {
|
(tx && dma_channel_is_busy(chan_tx))) {
|
||||||
// TODO: We should idle here until we get a DMA interrupt or something else.
|
// TODO: We should idle here until we get a DMA interrupt or something else.
|
||||||
RUN_BACKGROUND_TASKS;
|
RUN_BACKGROUND_TASKS;
|
||||||
|
if (self->user_interruptible && mp_hal_is_interrupted()) {
|
||||||
|
if (rx && dma_channel_is_busy(chan_rx)) {
|
||||||
|
dma_channel_abort(chan_rx);
|
||||||
|
}
|
||||||
|
if (tx && dma_channel_is_busy(chan_tx)) {
|
||||||
|
dma_channel_abort(chan_tx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Clear the stall bit so we can detect when the state machine is done transmitting.
|
// Clear the stall bit so we can detect when the state machine is done transmitting.
|
||||||
self->pio->fdebug = stall_mask;
|
self->pio->fdebug = stall_mask;
|
||||||
|
@ -678,7 +694,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self,
|
||||||
dma_channel_unclaim(chan_tx);
|
dma_channel_unclaim(chan_tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!use_dma) {
|
if (!use_dma && !(self->user_interruptible && mp_hal_is_interrupted())) {
|
||||||
// Use software for small transfers, or if couldn't claim two DMA channels
|
// Use software for small transfers, or if couldn't claim two DMA channels
|
||||||
size_t rx_remaining = in_len / in_stride_in_bytes;
|
size_t rx_remaining = in_len / in_stride_in_bytes;
|
||||||
size_t tx_remaining = out_len / out_stride_in_bytes;
|
size_t tx_remaining = out_len / out_stride_in_bytes;
|
||||||
|
@ -707,6 +723,9 @@ static bool _transfer(rp2pio_statemachine_obj_t *self,
|
||||||
--rx_remaining;
|
--rx_remaining;
|
||||||
}
|
}
|
||||||
RUN_BACKGROUND_TASKS;
|
RUN_BACKGROUND_TASKS;
|
||||||
|
if (self->user_interruptible && mp_hal_is_interrupted()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Clear the stall bit so we can detect when the state machine is done transmitting.
|
// Clear the stall bit so we can detect when the state machine is done transmitting.
|
||||||
self->pio->fdebug = stall_mask;
|
self->pio->fdebug = stall_mask;
|
||||||
|
@ -717,6 +736,9 @@ static bool _transfer(rp2pio_statemachine_obj_t *self,
|
||||||
while (!pio_sm_is_tx_fifo_empty(self->pio, self->state_machine) ||
|
while (!pio_sm_is_tx_fifo_empty(self->pio, self->state_machine) ||
|
||||||
(self->wait_for_txstall && (self->pio->fdebug & stall_mask) == 0)) {
|
(self->wait_for_txstall && (self->pio->fdebug & stall_mask) == 0)) {
|
||||||
RUN_BACKGROUND_TASKS;
|
RUN_BACKGROUND_TASKS;
|
||||||
|
if (self->user_interruptible && mp_hal_is_interrupted()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -43,15 +43,16 @@ typedef struct {
|
||||||
uint32_t initial_pin_direction;
|
uint32_t initial_pin_direction;
|
||||||
uint32_t pull_pin_up;
|
uint32_t pull_pin_up;
|
||||||
uint32_t pull_pin_down;
|
uint32_t pull_pin_down;
|
||||||
|
uint tx_dreq;
|
||||||
|
uint rx_dreq;
|
||||||
|
uint32_t actual_frequency;
|
||||||
|
pio_sm_config sm_config;
|
||||||
bool in;
|
bool in;
|
||||||
bool out;
|
bool out;
|
||||||
bool wait_for_txstall;
|
bool wait_for_txstall;
|
||||||
uint tx_dreq;
|
|
||||||
uint rx_dreq;
|
|
||||||
bool out_shift_right;
|
bool out_shift_right;
|
||||||
bool in_shift_right;
|
bool in_shift_right;
|
||||||
uint32_t actual_frequency;
|
bool user_interruptible;
|
||||||
pio_sm_config sm_config;
|
|
||||||
uint8_t offset;
|
uint8_t offset;
|
||||||
} rp2pio_statemachine_obj_t;
|
} rp2pio_statemachine_obj_t;
|
||||||
|
|
||||||
|
@ -73,7 +74,8 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
|
bool auto_pull, uint8_t pull_threshold, bool out_shift_right,
|
||||||
bool wait_for_txstall,
|
bool wait_for_txstall,
|
||||||
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
||||||
bool claim_pins);
|
bool claim_pins,
|
||||||
|
bool interruptible);
|
||||||
|
|
||||||
uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self);
|
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_set_wrap(rp2pio_statemachine_obj_t *self, uint wrap_target, uint wrap);
|
||||||
|
|
Loading…
Reference in New Issue