Browse Source

rp2/rp2_pio: Add support for RP2350A/B variants in PIO interface.

Add support for 32 and 48 pin variants of RP2350.

Add new `PIO.gpio_base()` method, mirroring the Pico SDK.

Signed-off-by: Phil Howard <phil@gadgetoid.com>
Signed-off-by: Damien George <damien@micropython.org>
pull/15619/head
Phil Howard 4 months ago
committed by Damien George
parent
commit
e6093c0fbd
  1. 11
      docs/library/rp2.PIO.rst
  2. 92
      ports/rp2/rp2_pio.c

11
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.

92
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]);

Loading…
Cancel
Save