summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/rp2/rp2_pio.c102
1 files changed, 85 insertions, 17 deletions
diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c
index 87deaf7e5..3ece26bd4 100644
--- a/ports/rp2/rp2_pio.c
+++ b/ports/rp2/rp2_pio.c
@@ -68,6 +68,11 @@ typedef struct _rp2_state_machine_irq_obj_t {
STATIC const rp2_state_machine_obj_t rp2_state_machine_obj[8];
STATIC uint8_t rp2_state_machine_initial_pc[8];
+// These masks keep track of PIO instruction memory used by this module.
+STATIC uint32_t rp2_pio_instruction_memory_usage_mask[2];
+
+STATIC const rp2_state_machine_obj_t *rp2_state_machine_get_object(mp_int_t sm_id);
+STATIC void rp2_state_machine_reset_all(void);
STATIC mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
STATIC void pio_irq0(PIO pio) {
@@ -101,16 +106,42 @@ STATIC void pio1_irq0(void) {
pio_irq0(pio1);
}
-void rp2_pio_init(void) {
- // Reset all PIO instruction memory.
- #if MICROPY_PY_NETWORK_CYW43
- // TODO: cannot reset PIO memory when CYW43 driver is enabled and active
- // because it uses a PIO for the bus interface.
- #else
- pio_clear_instruction_memory(pio0);
- pio_clear_instruction_memory(pio1);
- #endif
+// Calls pio_add_program() and keeps track of used instruction memory.
+STATIC uint rp2_pio_add_managed_program(PIO pio, struct pio_program *pio_program) {
+ uint offset = pio_add_program(pio, pio_program);
+ uint32_t mask = ((1 << pio_program->length) - 1) << offset;
+ rp2_pio_instruction_memory_usage_mask[pio_get_index(pio)] |= mask;
+ return offset;
+}
+
+// Calls pio_remove_program() and keeps track of used instruction memory.
+STATIC void rp2_pio_remove_managed_program(PIO pio, struct pio_program *pio_program, uint offset) {
+ pio_remove_program(pio, pio_program, offset);
+ uint32_t mask = ((1 << pio_program->length) - 1) << offset;
+ rp2_pio_instruction_memory_usage_mask[pio_get_index(pio)] &= ~mask;
+}
+
+// Calls pio_remove_program() for all programs registered with rp2_pio_add_managed_program(),
+// that weren't already removed via rp2_pio_remove_managed_program().
+STATIC void rp2_pio_remove_all_managed_programs(PIO pio) {
+ uint32_t mask = rp2_pio_instruction_memory_usage_mask[pio_get_index(pio)];
+ for (size_t i = 0; i < 32; ++i) {
+ if (mask & (1 << i)) {
+ size_t j;
+ for (j = i + 1; j < 32; ++j) {
+ if (!(mask & (1 << j))) {
+ break;
+ }
+ }
+ struct pio_program pio_program = { NULL, j - i, -1 };
+ pio_remove_program(pio, &pio_program, i);
+ i = j; // i indexes an unused bit, or is 32
+ }
+ }
+ rp2_pio_instruction_memory_usage_mask[pio_get_index(pio)] = 0;
+}
+void rp2_pio_init(void) {
// Set up interrupts.
memset(MP_STATE_PORT(rp2_pio_irq_obj), 0, sizeof(MP_STATE_PORT(rp2_pio_irq_obj)));
memset(MP_STATE_PORT(rp2_state_machine_irq_obj), 0, sizeof(MP_STATE_PORT(rp2_state_machine_irq_obj)));
@@ -123,6 +154,14 @@ void rp2_pio_deinit(void) {
irq_set_mask_enabled((1u << PIO0_IRQ_0) | (1u << PIO0_IRQ_1), false);
irq_remove_handler(PIO0_IRQ_0, pio0_irq0);
irq_remove_handler(PIO1_IRQ_0, pio1_irq0);
+
+ rp2_state_machine_reset_all();
+
+ // Reset all PIO instruction memory allocated by this module.
+ // Note: other subsystems (eg the CYW43 driver) may use the PIO,
+ // and their PIO programs should remain intact.
+ rp2_pio_remove_all_managed_programs(pio0);
+ rp2_pio_remove_all_managed_programs(pio1);
}
/******************************************************************************/
@@ -238,7 +277,7 @@ STATIC mp_obj_t rp2_pio_add_program(mp_obj_t self_in, mp_obj_t prog_in) {
if (!pio_can_add_program(self->pio, &pio_program)) {
mp_raise_OSError(MP_ENOMEM);
}
- uint offset = pio_add_program(self->pio, &pio_program);
+ uint offset = rp2_pio_add_managed_program(self->pio, &pio_program);
// Store the program offset in the program object.
prog[PROG_OFFSET_PIO0 + PIO_NUM(self->pio)] = MP_OBJ_NEW_SMALL_INT(offset);
@@ -272,7 +311,7 @@ STATIC mp_obj_t rp2_pio_remove_program(size_t n_args, const mp_obj_t *args) {
// Remove the program from the instruction memory.
struct pio_program pio_program = { NULL, length, -1 };
- pio_remove_program(self->pio, &pio_program, offset);
+ rp2_pio_remove_managed_program(self->pio, &pio_program, offset);
return mp_const_none;
}
@@ -285,11 +324,11 @@ STATIC mp_obj_t rp2_pio_state_machine(size_t n_args, const mp_obj_t *pos_args, m
// Get and verify the state machine id.
mp_int_t sm_id = mp_obj_get_int(pos_args[1]);
if (!(0 <= sm_id && sm_id < 4)) {
- mp_raise_ValueError("invalide state machine");
+ mp_raise_ValueError("invalid StateMachine");
}
// Return the correct StateMachine object.
- const rp2_state_machine_obj_t *sm = &rp2_state_machine_obj[(self->pio == pio0 ? 0 : 4) + sm_id];
+ const rp2_state_machine_obj_t *sm = rp2_state_machine_get_object((self->pio == pio0 ? 0 : 4) + sm_id);
if (n_args > 2 || kw_args->used > 0) {
// Configuration arguments given so init this StateMachine.
@@ -414,6 +453,9 @@ STATIC const mp_irq_methods_t rp2_pio_irq_methods = {
/******************************************************************************/
// StateMachine object
+// This mask keeps track of state machines claimed by this module.
+STATIC uint32_t rp2_state_machine_claimed_mask;
+
STATIC const mp_irq_methods_t rp2_state_machine_irq_methods;
STATIC const rp2_state_machine_obj_t rp2_state_machine_obj[] = {
@@ -427,6 +469,35 @@ STATIC const rp2_state_machine_obj_t rp2_state_machine_obj[] = {
{ { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 3, 7 },
};
+STATIC const rp2_state_machine_obj_t *rp2_state_machine_get_object(mp_int_t sm_id) {
+ if (!(0 <= sm_id && sm_id < MP_ARRAY_SIZE(rp2_state_machine_obj))) {
+ mp_raise_ValueError("invalid StateMachine");
+ }
+
+ const rp2_state_machine_obj_t *sm_obj = &rp2_state_machine_obj[sm_id];
+
+ if (!(rp2_state_machine_claimed_mask & (1 << sm_id))) {
+ if (pio_sm_is_claimed(sm_obj->pio, sm_obj->sm)) {
+ mp_raise_ValueError("StateMachine claimed by external resource");
+ }
+ pio_sm_claim(sm_obj->pio, sm_obj->sm);
+ rp2_state_machine_claimed_mask |= 1 << sm_id;
+ }
+
+ return sm_obj;
+}
+
+STATIC void rp2_state_machine_reset_all(void) {
+ for (size_t i = 0; i < MP_ARRAY_SIZE(rp2_state_machine_obj); ++i) {
+ if (rp2_state_machine_claimed_mask & (1 << i)) {
+ const rp2_state_machine_obj_t *sm_obj = &rp2_state_machine_obj[i];
+ pio_sm_unclaim(sm_obj->pio, sm_obj->sm);
+ pio_sm_set_enabled(sm_obj->pio, sm_obj->sm, false);
+ }
+ }
+ rp2_state_machine_claimed_mask = 0;
+}
+
STATIC void rp2_state_machine_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "StateMachine(%u)", self->id);
@@ -573,10 +644,7 @@ STATIC mp_obj_t rp2_state_machine_make_new(const mp_obj_type_t *type, size_t n_a
// Get the StateMachine object.
mp_int_t sm_id = mp_obj_get_int(args[0]);
- if (!(0 <= sm_id && sm_id < MP_ARRAY_SIZE(rp2_state_machine_obj))) {
- mp_raise_ValueError("invalid StateMachine");
- }
- const rp2_state_machine_obj_t *self = &rp2_state_machine_obj[sm_id];
+ const rp2_state_machine_obj_t *self = rp2_state_machine_get_object(sm_id);
if (n_args > 1 || n_kw > 0) {
// Configuration arguments given so init this StateMachine.