Merge pull request #8223 from jepler/sm-mayeexec
rp2: Add StateMachine(may_exec=, offset=)
This commit is contained in:
commit
472e6bca4d
|
@ -251,6 +251,22 @@ msgstr ""
|
|||
msgid "%q=%q"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
msgid "%q[%u] shifts in more bits than pin count"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
msgid "%q[%u] shifts out more bits than pin count"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
msgid "%q[%u] uses extra pin"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
msgid "%q[%u] waits on input outside of count"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/espidf/__init__.c
|
||||
#, c-format
|
||||
msgid "%s error 0x%x"
|
||||
|
@ -1161,26 +1177,6 @@ msgstr ""
|
|||
msgid "Input/output error"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Instruction %d shifts in more bits than pin count"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Instruction %d shifts out more bits than pin count"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Instruction %d uses extra pin"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Instruction %d waits on input outside of count"
|
||||
msgstr ""
|
||||
|
||||
#: ports/nrf/common-hal/_bleio/__init__.c
|
||||
msgid "Insufficient authentication"
|
||||
msgstr ""
|
||||
|
@ -1352,38 +1348,31 @@ msgid "Mismatched swap flag"
|
|||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing first_in_pin. Instruction %d reads pin(s)"
|
||||
msgid "Missing first_in_pin. %q[%u] reads pin(s)"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing first_in_pin. Instruction %d shifts in from pin(s)"
|
||||
msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing first_in_pin. Instruction %d waits based on pin"
|
||||
msgid "Missing first_in_pin. %q[%u] waits based on pin"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing first_out_pin. Instruction %d shifts out to pin(s)"
|
||||
msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing first_out_pin. Instruction %d writes pin(s)"
|
||||
msgid "Missing first_out_pin. %q[%u] writes pin(s)"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing first_set_pin. Instruction %d sets pin(s)"
|
||||
msgid "Missing first_set_pin. %q[%u] sets pin(s)"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#, c-format
|
||||
msgid "Missing jmp_pin. Instruction %d jumps on pin"
|
||||
msgid "Missing jmp_pin. %q[%u] jumps on pin"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
//| program: ReadableBuffer,
|
||||
//| frequency: int,
|
||||
//| *,
|
||||
//| may_exec: Optional[ReadableBuffer] = None,
|
||||
//| init: Optional[ReadableBuffer] = None,
|
||||
//| first_out_pin: Optional[microcontroller.Pin] = None,
|
||||
//| out_pin_count: int = 1,
|
||||
|
@ -93,6 +94,7 @@
|
|||
//| user_interruptible: bool = True,
|
||||
//| wrap_target: int = 0,
|
||||
//| wrap: int = -1,
|
||||
//| offset: int = -1,
|
||||
//| ) -> None:
|
||||
//| """Construct a StateMachine object on the given pins with the given program.
|
||||
//|
|
||||
|
@ -100,6 +102,10 @@
|
|||
//| :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
|
||||
//| is started so instructions may be intermingled
|
||||
//| :param ReadableBuffer may_exec: Instructions that may be executed via `StateMachine.run` calls.
|
||||
//| Some elements of the `StateMachine`'s configuration are inferred from the instructions used;
|
||||
//| 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
|
||||
|
@ -146,13 +152,16 @@
|
|||
//| :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.
|
||||
//| """
|
||||
//| ...
|
||||
|
||||
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 = m_new_obj(rp2pio_statemachine_obj_t);
|
||||
self->base.type = &rp2pio_statemachine_type;
|
||||
enum { ARG_program, ARG_frequency, ARG_init,
|
||||
enum { ARG_program, ARG_frequency, ARG_init, 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,
|
||||
|
@ -166,11 +175,13 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
|
|||
ARG_auto_push, ARG_push_threshold, ARG_in_shift_right,
|
||||
ARG_user_interruptible,
|
||||
ARG_wrap_target,
|
||||
ARG_wrap,};
|
||||
ARG_wrap,
|
||||
ARG_offset,};
|
||||
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_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} },
|
||||
{ MP_QSTR_out_pin_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
|
@ -209,6 +220,7 @@ 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_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);
|
||||
|
@ -220,6 +232,10 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
|
|||
init_bufinfo.len = 0;
|
||||
mp_get_buffer(args[ARG_init].u_obj, &init_bufinfo, MP_BUFFER_READ);
|
||||
|
||||
mp_buffer_info_t may_exec_bufinfo;
|
||||
may_exec_bufinfo.len = 0;
|
||||
mp_get_buffer(args[ARG_may_exec].u_obj, &may_exec_bufinfo, MP_BUFFER_READ);
|
||||
|
||||
// We don't validate pin in use here because we may be ok sharing them within a PIO.
|
||||
const mcu_pin_obj_t *first_out_pin =
|
||||
validate_obj_is_pin_or_none(args[ARG_first_out_pin].u_obj, MP_QSTR_first_out_pin);
|
||||
|
@ -264,6 +280,7 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
|
|||
bufinfo.buf, bufinfo.len / 2,
|
||||
args[ARG_frequency].u_int,
|
||||
init_bufinfo.buf, init_bufinfo.len / 2,
|
||||
may_exec_bufinfo.buf, may_exec_bufinfo.len / 2,
|
||||
first_out_pin, out_pin_count, args[ARG_initial_out_pin_state].u_int, args[ARG_initial_out_pin_direction].u_int,
|
||||
first_in_pin, in_pin_count, args[ARG_pull_in_pin_up].u_int, args[ARG_pull_in_pin_down].u_int,
|
||||
first_set_pin, set_pin_count, args[ARG_initial_set_pin_state].u_int, args[ARG_initial_set_pin_direction].u_int,
|
||||
|
@ -276,7 +293,7 @@ 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);
|
||||
wrap_target, wrap, args[ARG_offset].u_int);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
const uint16_t *program, size_t program_len,
|
||||
size_t frequency,
|
||||
const uint16_t *init, size_t init_len,
|
||||
const uint16_t *may_exec, size_t may_exec_len,
|
||||
const mcu_pin_obj_t *first_out_pin, uint8_t out_pin_count, uint32_t initial_out_pin_state, uint32_t initial_out_pin_direction,
|
||||
const mcu_pin_obj_t *first_in_pin, uint8_t in_pin_count, uint32_t pull_pin_up, uint32_t pull_pin_down,
|
||||
const mcu_pin_obj_t *first_set_pin, uint8_t set_pin_count, uint32_t initial_set_pin_state, uint32_t initial_set_pin_direction,
|
||||
|
@ -53,7 +54,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
bool wait_for_txstall,
|
||||
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
||||
bool user_interruptible,
|
||||
int wrap_taget, int wrap);
|
||||
int wrap_taget, int wrap,
|
||||
int offset);
|
||||
|
||||
void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self);
|
||||
bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self);
|
||||
|
|
|
@ -121,7 +121,8 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
|
|||
&self->state_machine,
|
||||
program, program_len,
|
||||
44100 * 32 * 6, // Clock at 44.1 khz to warm the DAC up.
|
||||
NULL, 0,
|
||||
NULL, 0, // init
|
||||
NULL, 0, // may_exec
|
||||
data, 1, 0, 0xffffffff, // out pin
|
||||
NULL, 0, // in pins
|
||||
0, 0, // in pulls
|
||||
|
@ -135,7 +136,8 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
|
|||
false, // Wait for txstall
|
||||
false, 32, false, // in settings
|
||||
false, // Not user-interruptible.
|
||||
0, -1); // wrap settings
|
||||
0, -1, // wrap settings
|
||||
PIO_ANY_OFFSET);
|
||||
|
||||
self->playing = false;
|
||||
audio_dma_init(&self->dma);
|
||||
|
|
|
@ -66,6 +66,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self,
|
|||
pdmin, MP_ARRAY_SIZE(pdmin),
|
||||
sample_rate * 32 * 2, // Frequency based on sample rate
|
||||
NULL, 0,
|
||||
NULL, 0, // may_exec
|
||||
NULL, 1, 0, 0xffffffff, // out pin
|
||||
data_pin, 1, // in pins
|
||||
0, 0, // in pulls
|
||||
|
@ -79,8 +80,8 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self,
|
|||
false, // Wait for txstall
|
||||
false, 32, true, // in settings
|
||||
false, // Not user-interruptible.
|
||||
0, -1); // wrap settings
|
||||
|
||||
0, -1, // wrap settings
|
||||
PIO_ANY_OFFSET);
|
||||
uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine);
|
||||
if (actual_frequency < MIN_MIC_CLOCK) {
|
||||
mp_raise_ValueError(translate("sampling rate out of range"));
|
||||
|
|
|
@ -102,6 +102,7 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle
|
|||
imagecapture_code, MP_ARRAY_SIZE(imagecapture_code),
|
||||
common_hal_mcu_processor_get_frequency(), // full speed (4 instructions per loop -> max pclk 30MHz @ 120MHz)
|
||||
0, 0, // init
|
||||
NULL, 0, // may_exec
|
||||
NULL, 0, 0, 0, // out pins
|
||||
pin_from_number(data_pins[0]), data_count, // in pins
|
||||
0, 0, // in pulls
|
||||
|
@ -119,7 +120,8 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle
|
|||
false, // wait for txstall
|
||||
true, 32, true, // in settings
|
||||
false, // Not user-interruptible.
|
||||
2, 5); // wrap settings
|
||||
2, 5, // wrap settings
|
||||
PIO_ANY_OFFSET);
|
||||
}
|
||||
|
||||
void common_hal_imagecapture_parallelimagecapture_deinit(imagecapture_parallelimagecapture_obj_t *self) {
|
||||
|
|
|
@ -79,7 +79,9 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
|
|||
false, // claim pins
|
||||
false, // Not user-interruptible.
|
||||
false, // No sideset enable
|
||||
0, -1); // wrap
|
||||
0, -1, // wrap
|
||||
PIO_ANY_OFFSET // offset
|
||||
);
|
||||
if (!ok) {
|
||||
// Do nothing. Maybe bitbang?
|
||||
return;
|
||||
|
|
|
@ -98,6 +98,7 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu
|
|||
parallel_program, MP_ARRAY_SIZE(parallel_program),
|
||||
frequency * 2, // frequency multiplied by 2 as 2 PIO instructions
|
||||
NULL, 0, // init
|
||||
NULL, 0, // may_exec
|
||||
data0, 8, 0, 255, // first out pin, # out pins
|
||||
NULL, 0, 0, 0, // first in pin, # in pins
|
||||
NULL, 0, 0, 0, // first set pin
|
||||
|
@ -110,7 +111,8 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu
|
|||
false, // wait for TX stall
|
||||
false, 32, true, // RX setting we don't use
|
||||
false, // Not user-interruptible.
|
||||
0, -1); // wrap settings
|
||||
0, -1, // wrap settings
|
||||
PIO_ANY_OFFSET);
|
||||
|
||||
common_hal_rp2pio_statemachine_never_reset(&self->state_machine);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self,
|
|||
pulsein_program, MP_ARRAY_SIZE(pulsein_program),
|
||||
1000000, // frequency
|
||||
NULL, 0, // init, init_len
|
||||
NULL, 0, // may_exec
|
||||
NULL, 0, 0, 0, // first out pin, # out pins, initial_out_pin_state
|
||||
pin, 1, 0, 0, // first in pin, # in pins
|
||||
NULL, 0, 0, 0, // first set pin
|
||||
|
@ -73,7 +74,8 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self,
|
|||
false, // wait for TX stall
|
||||
true, 32, true, // RX auto pull every 32 bits. shift left to output msb first
|
||||
false, // Not user-interruptible.
|
||||
0, -1); // wrap settings
|
||||
0, -1, // wrap settings
|
||||
PIO_ANY_OFFSET);
|
||||
|
||||
common_hal_pulseio_pulsein_pause(self);
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
|
|||
encoder, MP_ARRAY_SIZE(encoder),
|
||||
1000000,
|
||||
encoder_init, MP_ARRAY_SIZE(encoder_init), // init
|
||||
NULL, 0, // may_exec
|
||||
NULL, 0, 0, 0, // out pin
|
||||
pins[0], 2, // in pins
|
||||
3, 0, // in pulls
|
||||
|
@ -94,7 +95,8 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
|
|||
false, // Wait for txstall
|
||||
false, 32, false, // in settings
|
||||
false, // Not user-interruptible.
|
||||
0, MP_ARRAY_SIZE(encoder) - 1 // wrap settings
|
||||
0, MP_ARRAY_SIZE(encoder) - 1, // wrap settings
|
||||
PIO_ANY_OFFSET
|
||||
);
|
||||
|
||||
// We're guaranteed by the init code that some output will be available promptly
|
||||
|
|
|
@ -178,6 +178,21 @@ STATIC uint32_t _check_pins_free(const mcu_pin_obj_t *first_pin, uint8_t pin_cou
|
|||
return pins_we_use;
|
||||
}
|
||||
|
||||
static bool can_add_program(PIO pio, const pio_program_t *program, int offset) {
|
||||
if (offset == -1) {
|
||||
return pio_can_add_program(pio, program);
|
||||
}
|
||||
return pio_can_add_program_at_offset(pio, program, offset);
|
||||
}
|
||||
|
||||
static uint add_program(PIO pio, const pio_program_t *program, int offset) {
|
||||
if (offset == -1) {
|
||||
return pio_add_program(pio, program);
|
||||
} else {
|
||||
pio_add_program_at_offset(pio, program, offset);
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||
const uint16_t *program, size_t program_len,
|
||||
|
@ -197,7 +212,8 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
bool claim_pins,
|
||||
bool user_interruptible,
|
||||
bool sideset_enable,
|
||||
int wrap_target, int wrap
|
||||
int wrap_target, int wrap,
|
||||
int offset
|
||||
) {
|
||||
// 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);
|
||||
|
@ -215,14 +231,15 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
uint8_t free_count = 0;
|
||||
for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) {
|
||||
if (_current_program_id[i][j] == program_id &&
|
||||
_current_program_len[i][j] == program_len) {
|
||||
_current_program_len[i][j] == program_len &&
|
||||
(offset == -1 || offset == _current_program_offset[i][j])) {
|
||||
program_offset = _current_program_offset[i][j];
|
||||
}
|
||||
if (!pio_sm_is_claimed(pio, j)) {
|
||||
free_count++;
|
||||
}
|
||||
}
|
||||
if (free_count > 0 && (program_offset < 32 || pio_can_add_program(pio, &program_struct))) {
|
||||
if (free_count > 0 && (program_offset < 32 || can_add_program(pio, &program_struct, offset))) {
|
||||
pio_index = i;
|
||||
if (program_offset < 32) {
|
||||
break;
|
||||
|
@ -254,7 +271,7 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
self->pio = pio_instances[pio_index];
|
||||
self->state_machine = state_machine;
|
||||
if (program_offset == 32) {
|
||||
program_offset = pio_add_program(self->pio, &program_struct);
|
||||
program_offset = add_program(self->pio, &program_struct, offset);
|
||||
}
|
||||
self->offset = program_offset;
|
||||
_current_program_id[pio_index][state_machine] = program_id;
|
||||
|
@ -387,10 +404,119 @@ static uint32_t mask_and_rotate(const mcu_pin_obj_t *first_pin, uint32_t bit_cou
|
|||
return value << shift | value >> (32 - shift);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
uint32_t pins_we_use, in_pin_count, out_pin_count;
|
||||
bool has_jmp_pin, auto_push, auto_pull, has_in_pin, has_out_pin, has_set_pin;
|
||||
} inputs;
|
||||
struct {
|
||||
bool tx_fifo, rx_fifo, in_loaded, out_loaded, in_used, out_used;
|
||||
} outputs;
|
||||
} introspect_t;
|
||||
|
||||
static void consider_instruction(introspect_t *state, uint16_t full_instruction, qstr what_program, size_t i) {
|
||||
uint16_t instruction = full_instruction & 0xe000;
|
||||
if (instruction == 0x8000) {
|
||||
if ((full_instruction & 0xe080) == pio_instr_bits_push) {
|
||||
state->outputs.rx_fifo = true;
|
||||
state->outputs.in_loaded = true;
|
||||
} else { // pull otherwise.
|
||||
state->outputs.tx_fifo = true;
|
||||
state->outputs.out_loaded = true;
|
||||
}
|
||||
}
|
||||
if (instruction == pio_instr_bits_jmp) {
|
||||
uint16_t condition = (full_instruction & 0x00e0) >> 5;
|
||||
if ((condition == 0x6) && !state->inputs.has_jmp_pin) {
|
||||
mp_raise_ValueError_varg(translate("Missing jmp_pin. %q[%u] jumps on pin"), what_program, i);
|
||||
}
|
||||
}
|
||||
if (instruction == pio_instr_bits_wait) {
|
||||
uint16_t wait_source = (full_instruction & 0x0060) >> 5;
|
||||
uint16_t wait_index = full_instruction & 0x001f;
|
||||
if (wait_source == 0 && (state->inputs.pins_we_use & (1 << wait_index)) == 0) { // GPIO
|
||||
mp_raise_ValueError_varg(translate("%q[%u] uses extra pin"), what_program, i);
|
||||
}
|
||||
if (wait_source == 1) { // Input pin
|
||||
if (!state->inputs.has_in_pin) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_in_pin. %q[%u] waits based on pin"), what_program, i);
|
||||
}
|
||||
if (wait_index >= state->inputs.in_pin_count) {
|
||||
mp_raise_ValueError_varg(translate("%q[%u] waits on input outside of count"), what_program, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (instruction == pio_instr_bits_in) {
|
||||
uint16_t source = (full_instruction & 0x00e0) >> 5;
|
||||
uint16_t bit_count = full_instruction & 0x001f;
|
||||
if (source == 0) {
|
||||
if (!state->inputs.has_in_pin) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_in_pin. %q[%u] shifts in from pin(s)"), what_program, i);
|
||||
}
|
||||
if (bit_count > state->inputs.in_pin_count) {
|
||||
mp_raise_ValueError_varg(translate("%q[%u] shifts in more bits than pin count"), what_program, i);
|
||||
}
|
||||
}
|
||||
if (state->inputs.auto_push) {
|
||||
state->outputs.in_loaded = true;
|
||||
state->outputs.rx_fifo = true;
|
||||
}
|
||||
state->outputs.in_used = true;
|
||||
}
|
||||
if (instruction == pio_instr_bits_out) {
|
||||
uint16_t bit_count = full_instruction & 0x001f;
|
||||
uint16_t destination = (full_instruction & 0x00e0) >> 5;
|
||||
// Check for pins or pindirs destination.
|
||||
if (destination == 0x0 || destination == 0x4) {
|
||||
if (!state->inputs.has_out_pin) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_out_pin. %q[%u] shifts out to pin(s)"), what_program, i);
|
||||
}
|
||||
if (bit_count > state->inputs.out_pin_count) {
|
||||
mp_raise_ValueError_varg(translate("%q[%u] shifts out more bits than pin count"), what_program, i);
|
||||
}
|
||||
}
|
||||
if (state->inputs.auto_pull) {
|
||||
state->outputs.out_loaded = true;
|
||||
state->outputs.tx_fifo = true;
|
||||
}
|
||||
state->outputs.out_used = true;
|
||||
}
|
||||
if (instruction == pio_instr_bits_set) {
|
||||
uint16_t destination = (full_instruction & 0x00e0) >> 5;
|
||||
// Check for pins or pindirs destination.
|
||||
if ((destination == 0x00 || destination == 0x4) && !state->inputs.has_set_pin) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_set_pin. %q[%u] sets pin(s)"), what_program, i);
|
||||
}
|
||||
}
|
||||
if (instruction == pio_instr_bits_mov) {
|
||||
uint16_t source = full_instruction & 0x0007;
|
||||
uint16_t destination = (full_instruction & 0x00e0) >> 5;
|
||||
// Check for pins or pindirs destination.
|
||||
if (destination == 0x0 && !state->inputs.has_out_pin) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_out_pin. %q[%u] writes pin(s)"), what_program, i);
|
||||
}
|
||||
if (source == 0x0 && !state->inputs.has_in_pin) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_in_pin. %q[%u] reads pin(s)"), what_program, i);
|
||||
}
|
||||
if (destination == 0x6) {
|
||||
state->outputs.in_loaded = true;
|
||||
} else if (destination == 0x7) {
|
||||
state->outputs.out_loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void consider_program(introspect_t *state, const uint16_t *program, size_t program_len, qstr what_program) {
|
||||
for (size_t i = 0; i < program_len; i++) {
|
||||
consider_instruction(state, program[i], what_program, i);
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||
const uint16_t *program, size_t program_len,
|
||||
size_t frequency,
|
||||
const uint16_t *init, size_t init_len,
|
||||
const uint16_t *may_exec, size_t may_exec_len,
|
||||
const mcu_pin_obj_t *first_out_pin, uint8_t out_pin_count, uint32_t initial_out_pin_state, uint32_t initial_out_pin_direction,
|
||||
const mcu_pin_obj_t *first_in_pin, uint8_t in_pin_count,
|
||||
uint32_t pull_pin_up, uint32_t pull_pin_down,
|
||||
|
@ -404,7 +530,8 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
bool wait_for_txstall,
|
||||
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
||||
bool user_interruptible,
|
||||
int wrap_target, int wrap) {
|
||||
int wrap_target, int wrap,
|
||||
int offset) {
|
||||
|
||||
// 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;
|
||||
|
@ -415,109 +542,27 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
pins_we_use |= _check_pins_free(jmp_pin, 1, exclusive_pin_use);
|
||||
|
||||
// Look through the program to see what we reference and make sure it was provided.
|
||||
bool tx_fifo = false;
|
||||
bool rx_fifo = false;
|
||||
bool in_loaded = false; // can be loaded in other ways besides the fifo
|
||||
bool out_loaded = false;
|
||||
bool in_used = false;
|
||||
bool out_used = false;
|
||||
for (size_t i = 0; i < program_len; i++) {
|
||||
uint16_t full_instruction = program[i];
|
||||
uint16_t instruction = full_instruction & 0xe000;
|
||||
if (instruction == 0x8000) {
|
||||
if ((full_instruction & 0xe080) == pio_instr_bits_push) {
|
||||
rx_fifo = true;
|
||||
in_loaded = true;
|
||||
} else { // pull otherwise.
|
||||
tx_fifo = true;
|
||||
out_loaded = true;
|
||||
}
|
||||
introspect_t state = {
|
||||
.inputs = {
|
||||
.pins_we_use = pins_we_use,
|
||||
.has_jmp_pin = jmp_pin != NULL,
|
||||
.has_in_pin = first_in_pin != NULL,
|
||||
.has_out_pin = first_out_pin != NULL,
|
||||
.has_set_pin = first_set_pin != NULL,
|
||||
.in_pin_count = in_pin_count,
|
||||
.out_pin_count = out_pin_count,
|
||||
.auto_pull = auto_pull,
|
||||
.auto_push = auto_push,
|
||||
}
|
||||
if (instruction == pio_instr_bits_jmp) {
|
||||
uint16_t condition = (full_instruction & 0x00e0) >> 5;
|
||||
if ((condition == 0x6) && (jmp_pin == NULL)) {
|
||||
mp_raise_ValueError_varg(translate("Missing jmp_pin. Instruction %d jumps on pin"), i);
|
||||
}
|
||||
}
|
||||
if (instruction == pio_instr_bits_wait) {
|
||||
uint16_t wait_source = (full_instruction & 0x0060) >> 5;
|
||||
uint16_t wait_index = full_instruction & 0x001f;
|
||||
if (wait_source == 0 && (pins_we_use & (1 << wait_index)) == 0) { // GPIO
|
||||
mp_raise_ValueError_varg(translate("Instruction %d uses extra pin"), i);
|
||||
}
|
||||
if (wait_source == 1) { // Input pin
|
||||
if (first_in_pin == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d waits based on pin"), i);
|
||||
}
|
||||
if (wait_index >= in_pin_count) {
|
||||
mp_raise_ValueError_varg(translate("Instruction %d waits on input outside of count"), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (instruction == pio_instr_bits_in) {
|
||||
uint16_t source = (full_instruction & 0x00e0) >> 5;
|
||||
uint16_t bit_count = full_instruction & 0x001f;
|
||||
if (source == 0) {
|
||||
if (first_in_pin == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d shifts in from pin(s)"), i);
|
||||
}
|
||||
if (bit_count > in_pin_count) {
|
||||
mp_raise_ValueError_varg(translate("Instruction %d shifts in more bits than pin count"), i);
|
||||
}
|
||||
}
|
||||
if (auto_push) {
|
||||
in_loaded = true;
|
||||
rx_fifo = true;
|
||||
}
|
||||
in_used = true;
|
||||
}
|
||||
if (instruction == pio_instr_bits_out) {
|
||||
uint16_t bit_count = full_instruction & 0x001f;
|
||||
uint16_t destination = (full_instruction & 0x00e0) >> 5;
|
||||
// Check for pins or pindirs destination.
|
||||
if (destination == 0x0 || destination == 0x4) {
|
||||
if (first_out_pin == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_out_pin. Instruction %d shifts out to pin(s)"), i);
|
||||
}
|
||||
if (bit_count > out_pin_count) {
|
||||
mp_raise_ValueError_varg(translate("Instruction %d shifts out more bits than pin count"), i);
|
||||
}
|
||||
}
|
||||
if (auto_pull) {
|
||||
out_loaded = true;
|
||||
tx_fifo = true;
|
||||
}
|
||||
out_used = true;
|
||||
}
|
||||
if (instruction == pio_instr_bits_set) {
|
||||
uint16_t destination = (full_instruction & 0x00e0) >> 5;
|
||||
// Check for pins or pindirs destination.
|
||||
if ((destination == 0x00 || destination == 0x4) && first_set_pin == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_set_pin. Instruction %d sets pin(s)"), i);
|
||||
}
|
||||
}
|
||||
if (instruction == pio_instr_bits_mov) {
|
||||
uint16_t source = full_instruction & 0x0007;
|
||||
uint16_t destination = (full_instruction & 0x00e0) >> 5;
|
||||
// Check for pins or pindirs destination.
|
||||
if (destination == 0x0 && first_out_pin == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_out_pin. Instruction %d writes pin(s)"), i);
|
||||
}
|
||||
if (source == 0x0 && first_in_pin == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d reads pin(s)"), i);
|
||||
}
|
||||
if (destination == 0x6) {
|
||||
in_loaded = true;
|
||||
} else if (destination == 0x7) {
|
||||
out_loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
consider_program(&state, program, program_len, MP_QSTR_program);
|
||||
consider_program(&state, init, init_len, MP_QSTR_init);
|
||||
consider_program(&state, may_exec, may_exec_len, MP_QSTR_may_exec);
|
||||
|
||||
if (!in_loaded && in_used) {
|
||||
if (!state.outputs.in_loaded && state.outputs.in_used) {
|
||||
mp_raise_ValueError_varg(translate("Program does IN without loading ISR"));
|
||||
}
|
||||
if (!out_loaded && out_used) {
|
||||
if (!state.outputs.out_loaded && state.outputs.out_used) {
|
||||
mp_raise_ValueError_varg(translate("Program does OUT without loading OSR"));
|
||||
}
|
||||
|
||||
|
@ -570,14 +615,14 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
first_sideset_pin, sideset_pin_count,
|
||||
initial_pin_state, initial_pin_direction,
|
||||
jmp_pin,
|
||||
pins_we_use, tx_fifo, rx_fifo,
|
||||
pins_we_use, state.outputs.tx_fifo, state.outputs.rx_fifo,
|
||||
auto_pull, pull_threshold, out_shift_right,
|
||||
wait_for_txstall,
|
||||
auto_push, push_threshold, in_shift_right,
|
||||
true /* claim pins */,
|
||||
user_interruptible,
|
||||
sideset_enable,
|
||||
wrap_target, wrap);
|
||||
wrap_target, wrap, offset);
|
||||
if (!ok) {
|
||||
mp_raise_RuntimeError(translate("All state machines in use"));
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include "common-hal/microcontroller/Pin.h"
|
||||
#include "src/rp2_common/hardware_pio/include/hardware/pio.h"
|
||||
|
||||
enum { PIO_ANY_OFFSET = -1 };
|
||||
|
||||
typedef struct sm_buf_info {
|
||||
mp_obj_t obj;
|
||||
mp_buffer_info_t info;
|
||||
|
@ -88,7 +90,7 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
|||
bool claim_pins,
|
||||
bool interruptible,
|
||||
bool sideset_enable,
|
||||
int wrap_target, int wrap);
|
||||
int wrap_target, int wrap, int offset);
|
||||
|
||||
uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self);
|
||||
|
||||
|
|
Loading…
Reference in New Issue