summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/library/rp2.PIO.rst11
-rw-r--r--ports/rp2/rp2_pio.c92
2 files changed, 90 insertions, 13 deletions
diff --git a/docs/library/rp2.PIO.rst b/docs/library/rp2.PIO.rst
index e0675af1e..f922456c8 100644
--- a/docs/library/rp2.PIO.rst
+++ b/docs/library/rp2.PIO.rst
@@ -27,6 +27,17 @@ Constructors
Methods
-------
+.. method:: PIO.gpio_base([base])
+
+ Query and optionally set the current GPIO base for this PIO instance.
+
+ If an argument is given then it must be a pin (or integer corresponding to a pin
+ number), restricted to either GPIO0 or GPIO16. The GPIO base will then be set to
+ that pin. Setting the GPIO base must be done before any programs are added or state
+ machines created.
+
+ Returns the current GPIO base pin.
+
.. method:: PIO.add_program(program)
Add the *program* to the instruction memory of this PIO instance.
diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c
index 0ca91656f..56c576581 100644
--- a/ports/rp2/rp2_pio.c
+++ b/ports/rp2/rp2_pio.c
@@ -31,6 +31,7 @@
#include "py/mperrno.h"
#include "py/mphal.h"
#include "shared/runtime/mpirq.h"
+#include "machine_pin.h"
#include "modrp2.h"
#include "hardware/clocks.h"
@@ -54,7 +55,7 @@ typedef struct _rp2_state_machine_obj_t {
PIO pio;
uint8_t irq;
uint8_t sm; // 0-3
- uint8_t id; // 0-7
+ uint8_t id; // 0-7 on RP2040, or 0-11 on RP2350
} rp2_state_machine_obj_t;
typedef struct _rp2_state_machine_irq_obj_t {
@@ -63,11 +64,11 @@ typedef struct _rp2_state_machine_irq_obj_t {
uint8_t trigger;
} 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];
+static const rp2_state_machine_obj_t rp2_state_machine_obj[NUM_PIOS * 4];
+static uint8_t rp2_state_machine_initial_pc[NUM_PIOS * 4];
// These masks keep track of PIO instruction memory used by this module.
-static uint32_t rp2_pio_instruction_memory_usage_mask[2];
+static uint32_t rp2_pio_instruction_memory_usage_mask[NUM_PIOS];
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);
@@ -104,8 +105,19 @@ static void pio1_irq0(void) {
pio_irq0(pio1);
}
+#if NUM_PIOS >= 3
+static void pio2_irq0(void) {
+ pio_irq0(pio2);
+}
+#endif
+
// Returns the correct irq0 handler wrapper for a given pio
static inline irq_handler_t rp2_pio_get_irq_handler(PIO pio) {
+ #if NUM_PIOS >= 3
+ if (pio == pio2) {
+ return pio2_irq0;
+ }
+ #endif
return pio == pio0 ? pio0_irq0 : pio1_irq0;
}
@@ -172,6 +184,12 @@ void rp2_pio_deinit(void) {
irq_set_enabled(PIO1_IRQ_0, false);
irq_remove_handler(PIO1_IRQ_0, pio1_irq0);
}
+ #if NUM_PIOS >= 3
+ if (irq_get_exclusive_handler(PIO2_IRQ_0) == pio2_irq0) {
+ irq_set_enabled(PIO2_IRQ_0, false);
+ irq_remove_handler(PIO2_IRQ_0, pio2_irq0);
+ }
+ #endif
rp2_state_machine_reset_all();
@@ -180,6 +198,9 @@ void rp2_pio_deinit(void) {
// and their PIO programs should remain intact.
rp2_pio_remove_all_managed_programs(pio0);
rp2_pio_remove_all_managed_programs(pio1);
+ #if NUM_PIOS >= 3
+ rp2_pio_remove_all_managed_programs(pio2);
+ #endif
}
/******************************************************************************/
@@ -212,7 +233,7 @@ static void asm_pio_override_shiftctrl(mp_obj_t arg, uint32_t bits, uint32_t lsb
}
}
-static void asm_pio_get_pins(const char *type, mp_obj_t prog_pins, mp_obj_t arg_base, asm_pio_config_t *config) {
+static void asm_pio_get_pins(PIO pio, const char *type, mp_obj_t prog_pins, mp_obj_t arg_base, asm_pio_config_t *config) {
if (prog_pins != mp_const_none) {
// The PIO program specified pins for initialisation on out/set/sideset.
if (mp_obj_is_integer(prog_pins)) {
@@ -238,13 +259,21 @@ static void asm_pio_get_pins(const char *type, mp_obj_t prog_pins, mp_obj_t arg_
if (arg_base != mp_const_none) {
// The instantiation of the PIO program specified a base pin.
config->base = mp_hal_get_pin_obj(arg_base);
+
+ #if PICO_PIO_USE_GPIO_BASE
+ // Check the base is within range of the configured gpio_base.
+ uint gpio_base = pio_get_gpio_base(pio);
+ if ((gpio_base == 0 && config->base >= 32) || (gpio_base == 16 && config->base < 16)) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%s_base not within gpio_base range"), type);
+ }
+ #endif
}
}
static void asm_pio_init_gpio(PIO pio, uint32_t sm, asm_pio_config_t *config) {
- uint32_t pinmask = ((1 << config->count) - 1) << config->base;
- pio_sm_set_pins_with_mask(pio, sm, config->pinvals << config->base, pinmask);
- pio_sm_set_pindirs_with_mask(pio, sm, config->pindirs << config->base, pinmask);
+ uint32_t pinmask = ((1 << config->count) - 1) << (config->base - pio_get_gpio_base(pio));
+ pio_sm_set_pins_with_mask(pio, sm, config->pinvals << (config->base - pio_get_gpio_base(pio)), pinmask);
+ pio_sm_set_pindirs_with_mask(pio, sm, config->pindirs << (config->base - pio_get_gpio_base(pio)), pinmask);
for (size_t i = 0; i < config->count; ++i) {
gpio_set_function(config->base + i, GPIO_FUNC_PIO0 + pio_get_index(pio));
}
@@ -258,6 +287,9 @@ static const mp_irq_methods_t rp2_pio_irq_methods;
static rp2_pio_obj_t rp2_pio_obj[] = {
{ { &rp2_pio_type }, pio0, PIO0_IRQ_0 },
{ { &rp2_pio_type }, pio1, PIO1_IRQ_0 },
+ #if NUM_PIOS >= 3
+ { { &rp2_pio_type }, pio2, PIO2_IRQ_0 },
+ #endif
};
static void rp2_pio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
@@ -357,6 +389,31 @@ static mp_obj_t rp2_pio_state_machine(size_t n_args, const mp_obj_t *pos_args, m
}
MP_DEFINE_CONST_FUN_OBJ_KW(rp2_pio_state_machine_obj, 2, rp2_pio_state_machine);
+#if PICO_PIO_USE_GPIO_BASE
+// PIO.gpio_base([base])
+static mp_obj_t rp2_pio_gpio_base(size_t n_args, const mp_obj_t *args) {
+ rp2_pio_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (n_args > 1) {
+ // Set gpio_base value.
+ uint gpio_base = mp_hal_get_pin_obj(args[1]);
+
+ // Must be 0 for GPIOs 0 to 31 inclusive, or 16 for GPIOs 16 to 48 inclusive.
+ if (!(gpio_base == 0 || gpio_base == 16)) {
+ mp_raise_ValueError("invalid GPIO base");
+ }
+
+ if (pio_set_gpio_base(self->pio, gpio_base) != PICO_OK) {
+ mp_raise_OSError(MP_EINVAL);
+ }
+ }
+
+ // Return current gpio_base value.
+ return pio_get_gpio_base(self->pio) == 0 ? (mp_obj_t)pin_GPIO0 : (mp_obj_t)pin_GPIO16;
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_pio_gpio_base_obj, 1, 2, rp2_pio_gpio_base);
+#endif
+
// PIO.irq(handler=None, trigger=IRQ_SM0|IRQ_SM1|IRQ_SM2|IRQ_SM3, hard=False)
static mp_obj_t rp2_pio_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_handler, ARG_trigger, ARG_hard };
@@ -410,6 +467,9 @@ static mp_obj_t rp2_pio_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
static MP_DEFINE_CONST_FUN_OBJ_KW(rp2_pio_irq_obj, 1, rp2_pio_irq);
static const mp_rom_map_elem_t rp2_pio_locals_dict_table[] = {
+ #if PICO_PIO_USE_GPIO_BASE
+ { MP_ROM_QSTR(MP_QSTR_gpio_base), MP_ROM_PTR(&rp2_pio_gpio_base_obj) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_add_program), MP_ROM_PTR(&rp2_pio_add_program_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove_program), MP_ROM_PTR(&rp2_pio_remove_program_obj) },
{ MP_ROM_QSTR(MP_QSTR_state_machine), MP_ROM_PTR(&rp2_pio_state_machine_obj) },
@@ -486,6 +546,12 @@ static const rp2_state_machine_obj_t rp2_state_machine_obj[] = {
{ { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 1, 5 },
{ { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 2, 6 },
{ { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 3, 7 },
+ #if NUM_PIOS >= 3
+ { { &rp2_state_machine_type }, pio2, PIO2_IRQ_0, 0, 8 },
+ { { &rp2_state_machine_type }, pio2, PIO2_IRQ_0, 1, 9 },
+ { { &rp2_state_machine_type }, pio2, PIO2_IRQ_0, 2, 10 },
+ { { &rp2_state_machine_type }, pio2, PIO2_IRQ_0, 3, 11 },
+ #endif
};
static const rp2_state_machine_obj_t *rp2_state_machine_get_object(mp_int_t sm_id) {
@@ -604,14 +670,14 @@ static mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel
// Configure out pins, if needed.
asm_pio_config_t out_config = ASM_PIO_CONFIG_DEFAULT;
- asm_pio_get_pins("out", prog[PROG_OUT_PINS], args[ARG_out_base].u_obj, &out_config);
+ asm_pio_get_pins(self->pio, "out", prog[PROG_OUT_PINS], args[ARG_out_base].u_obj, &out_config);
if (out_config.base >= 0) {
sm_config_set_out_pins(&config, out_config.base, out_config.count);
}
// Configure set pin, if needed.
asm_pio_config_t set_config = ASM_PIO_CONFIG_DEFAULT;
- asm_pio_get_pins("set", prog[PROG_SET_PINS], args[ARG_set_base].u_obj, &set_config);
+ asm_pio_get_pins(self->pio, "set", prog[PROG_SET_PINS], args[ARG_set_base].u_obj, &set_config);
if (set_config.base >= 0) {
sm_config_set_set_pins(&config, set_config.base, set_config.count);
}
@@ -623,7 +689,7 @@ static mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel
// Configure sideset pin, if needed.
asm_pio_config_t sideset_config = ASM_PIO_CONFIG_DEFAULT;
- asm_pio_get_pins("sideset", prog[PROG_SIDESET_PINS], args[ARG_sideset_base].u_obj, &sideset_config);
+ asm_pio_get_pins(self->pio, "sideset", prog[PROG_SIDESET_PINS], args[ARG_sideset_base].u_obj, &sideset_config);
if (sideset_config.base >= 0) {
uint32_t count = sideset_config.count;
if (config.execctrl & (1 << PIO_SM0_EXECCTRL_SIDE_EN_LSB)) {
@@ -951,5 +1017,5 @@ static const mp_irq_methods_t rp2_state_machine_irq_methods = {
.info = rp2_state_machine_irq_info,
};
-MP_REGISTER_ROOT_POINTER(void *rp2_pio_irq_obj[2]);
-MP_REGISTER_ROOT_POINTER(void *rp2_state_machine_irq_obj[8]);
+MP_REGISTER_ROOT_POINTER(void *rp2_pio_irq_obj[NUM_PIOS]);
+MP_REGISTER_ROOT_POINTER(void *rp2_state_machine_irq_obj[NUM_PIOS * 4]);