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>
This commit is contained in:
parent
a3d1c59ca3
commit
e6093c0fbd
@ -27,6 +27,17 @@ Constructors
|
|||||||
Methods
|
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)
|
.. method:: PIO.add_program(program)
|
||||||
|
|
||||||
Add the *program* to the instruction memory of this PIO instance.
|
Add the *program* to the instruction memory of this PIO instance.
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
#include "py/mperrno.h"
|
#include "py/mperrno.h"
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "shared/runtime/mpirq.h"
|
#include "shared/runtime/mpirq.h"
|
||||||
|
#include "machine_pin.h"
|
||||||
#include "modrp2.h"
|
#include "modrp2.h"
|
||||||
|
|
||||||
#include "hardware/clocks.h"
|
#include "hardware/clocks.h"
|
||||||
@ -54,7 +55,7 @@ typedef struct _rp2_state_machine_obj_t {
|
|||||||
PIO pio;
|
PIO pio;
|
||||||
uint8_t irq;
|
uint8_t irq;
|
||||||
uint8_t sm; // 0-3
|
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;
|
} rp2_state_machine_obj_t;
|
||||||
|
|
||||||
typedef struct _rp2_state_machine_irq_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;
|
uint8_t trigger;
|
||||||
} rp2_state_machine_irq_obj_t;
|
} rp2_state_machine_irq_obj_t;
|
||||||
|
|
||||||
static const rp2_state_machine_obj_t rp2_state_machine_obj[8];
|
static const rp2_state_machine_obj_t rp2_state_machine_obj[NUM_PIOS * 4];
|
||||||
static uint8_t rp2_state_machine_initial_pc[8];
|
static uint8_t rp2_state_machine_initial_pc[NUM_PIOS * 4];
|
||||||
|
|
||||||
// These masks keep track of PIO instruction memory used by this module.
|
// 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 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 void rp2_state_machine_reset_all(void);
|
||||||
@ -104,8 +105,19 @@ static void pio1_irq0(void) {
|
|||||||
pio_irq0(pio1);
|
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
|
// Returns the correct irq0 handler wrapper for a given pio
|
||||||
static inline irq_handler_t rp2_pio_get_irq_handler(PIO 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;
|
return pio == pio0 ? pio0_irq0 : pio1_irq0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +184,12 @@ void rp2_pio_deinit(void) {
|
|||||||
irq_set_enabled(PIO1_IRQ_0, false);
|
irq_set_enabled(PIO1_IRQ_0, false);
|
||||||
irq_remove_handler(PIO1_IRQ_0, pio1_irq0);
|
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();
|
rp2_state_machine_reset_all();
|
||||||
|
|
||||||
@ -180,6 +198,9 @@ void rp2_pio_deinit(void) {
|
|||||||
// and their PIO programs should remain intact.
|
// and their PIO programs should remain intact.
|
||||||
rp2_pio_remove_all_managed_programs(pio0);
|
rp2_pio_remove_all_managed_programs(pio0);
|
||||||
rp2_pio_remove_all_managed_programs(pio1);
|
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) {
|
if (prog_pins != mp_const_none) {
|
||||||
// The PIO program specified pins for initialisation on out/set/sideset.
|
// The PIO program specified pins for initialisation on out/set/sideset.
|
||||||
if (mp_obj_is_integer(prog_pins)) {
|
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) {
|
if (arg_base != mp_const_none) {
|
||||||
// The instantiation of the PIO program specified a base pin.
|
// The instantiation of the PIO program specified a base pin.
|
||||||
config->base = mp_hal_get_pin_obj(arg_base);
|
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) {
|
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;
|
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, pinmask);
|
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, 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) {
|
for (size_t i = 0; i < config->count; ++i) {
|
||||||
gpio_set_function(config->base + i, GPIO_FUNC_PIO0 + pio_get_index(pio));
|
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[] = {
|
static rp2_pio_obj_t rp2_pio_obj[] = {
|
||||||
{ { &rp2_pio_type }, pio0, PIO0_IRQ_0 },
|
{ { &rp2_pio_type }, pio0, PIO0_IRQ_0 },
|
||||||
{ { &rp2_pio_type }, pio1, PIO1_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) {
|
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);
|
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)
|
// 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) {
|
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 };
|
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 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[] = {
|
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_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_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) },
|
{ 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, 1, 5 },
|
||||||
{ { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 2, 6 },
|
{ { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 2, 6 },
|
||||||
{ { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 3, 7 },
|
{ { &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) {
|
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.
|
// Configure out pins, if needed.
|
||||||
asm_pio_config_t out_config = ASM_PIO_CONFIG_DEFAULT;
|
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) {
|
if (out_config.base >= 0) {
|
||||||
sm_config_set_out_pins(&config, out_config.base, out_config.count);
|
sm_config_set_out_pins(&config, out_config.base, out_config.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure set pin, if needed.
|
// Configure set pin, if needed.
|
||||||
asm_pio_config_t set_config = ASM_PIO_CONFIG_DEFAULT;
|
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) {
|
if (set_config.base >= 0) {
|
||||||
sm_config_set_set_pins(&config, set_config.base, set_config.count);
|
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.
|
// Configure sideset pin, if needed.
|
||||||
asm_pio_config_t sideset_config = ASM_PIO_CONFIG_DEFAULT;
|
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) {
|
if (sideset_config.base >= 0) {
|
||||||
uint32_t count = sideset_config.count;
|
uint32_t count = sideset_config.count;
|
||||||
if (config.execctrl & (1 << PIO_SM0_EXECCTRL_SIDE_EN_LSB)) {
|
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,
|
.info = rp2_state_machine_irq_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
MP_REGISTER_ROOT_POINTER(void *rp2_pio_irq_obj[2]);
|
MP_REGISTER_ROOT_POINTER(void *rp2_pio_irq_obj[NUM_PIOS]);
|
||||||
MP_REGISTER_ROOT_POINTER(void *rp2_state_machine_irq_obj[8]);
|
MP_REGISTER_ROOT_POINTER(void *rp2_state_machine_irq_obj[NUM_PIOS * 4]);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user