Skip to content

raspberrypi: Update usb_host for newer PIO resource usage #9999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@

picodvi_framebuffer_obj_t *active_picodvi = NULL;

static PIO pio_instances[2] = {pio0, pio1};

static void __not_in_flash_func(core1_main)(void) {
// The MPU is reset before this starts.

Expand Down Expand Up @@ -184,7 +182,7 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
size_t pio_index = NUM_PIOS;
int free_state_machines[4]; // We may find all four free. We only use the first three.
for (size_t i = 0; i < NUM_PIOS; i++) {
PIO pio = pio_instances[i];
PIO pio = pio_get_instance(i);
uint8_t free_count = 0;
for (size_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) {
if (!pio_sm_is_claimed(pio, sm)) {
Expand Down Expand Up @@ -244,7 +242,7 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
}

for (size_t i = 0; i < 3; i++) {
rp2pio_statemachine_never_reset(pio_instances[pio_index], free_state_machines[i]);
rp2pio_statemachine_never_reset(pio_get_instance(pio_index), free_state_machines[i]);
}

// For the output.
Expand All @@ -253,7 +251,7 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
self->color_depth = color_depth;

self->dvi.timing = timing;
self->dvi.ser_cfg.pio = pio_instances[pio_index];
self->dvi.ser_cfg.pio = pio_get_instance(pio_index);
self->dvi.ser_cfg.sm_tmds[0] = free_state_machines[0];
self->dvi.ser_cfg.sm_tmds[1] = free_state_machines[1];
self->dvi.ser_cfg.sm_tmds[2] = free_state_machines[2];
Expand Down
15 changes: 4 additions & 11 deletions ports/raspberrypi/common-hal/rp2pio/StateMachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,6 @@ static int8_t _sm_dma_plus_one_read[NUM_PIOS][NUM_PIO_STATE_MACHINES];
#define SM_DMA_CLEAR_CHANNEL_READ(pio_index, sm) (_sm_dma_plus_one_read[(pio_index)][(sm)] = 0)
#define SM_DMA_SET_CHANNEL_READ(pio_index, sm, channel) (_sm_dma_plus_one_read[(pio_index)][(sm)] = (channel) + 1)

static PIO pio_instances[NUM_PIOS] = {
pio0,
pio1
#if NUM_PIOS == 3
, pio2
#endif
};
typedef void (*interrupt_handler_type)(void *);
static interrupt_handler_type _interrupt_handler[NUM_PIOS][NUM_PIO_STATE_MACHINES];
static void *_interrupt_arg[NUM_PIOS][NUM_PIO_STATE_MACHINES];
Expand Down Expand Up @@ -162,7 +155,7 @@ static void _reset_statemachine(PIO pio, uint8_t sm, bool leave_pins) {

void reset_rp2pio_statemachine(void) {
for (size_t i = 0; i < NUM_PIOS; i++) {
PIO pio = pio_instances[i];
PIO pio = pio_get_instance(i);
for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) {
if (_never_reset[i][j]) {
continue;
Expand Down Expand Up @@ -252,7 +245,7 @@ static bool use_existing_program(PIO *pio_out, uint *sm_out, int *offset_inout,
}

for (size_t i = 0; i < NUM_PIOS; i++) {
PIO pio = pio_instances[i];
PIO pio = pio_get_instance(i);
if (!is_gpio_compatible(pio, required_gpio_ranges)) {
continue;
}
Expand Down Expand Up @@ -1097,7 +1090,7 @@ void common_hal_rp2pio_statemachine_set_interrupt_handler(rp2pio_statemachine_ob

static void rp2pio_statemachine_interrupt_handler(void) {
for (size_t pio_index = 0; pio_index < NUM_PIOS; pio_index++) {
PIO pio = pio_instances[pio_index];
PIO pio = pio_get_instance(pio_index);
for (size_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) {
if (!_interrupt_handler[pio_index][sm]) {
continue;
Expand Down Expand Up @@ -1452,7 +1445,7 @@ int common_hal_rp2pio_statemachine_get_offset(rp2pio_statemachine_obj_t *self) {

int common_hal_rp2pio_statemachine_get_pc(rp2pio_statemachine_obj_t *self) {
uint8_t pio_index = pio_get_index(self->pio);
PIO pio = pio_instances[pio_index];
PIO pio = pio_get_instance(pio_index);
uint8_t sm = self->state_machine;
return pio_sm_get_pc(pio, sm);
}
Expand Down
75 changes: 26 additions & 49 deletions ports/raspberrypi/common-hal/usb_host/Port.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@

usb_host_port_obj_t usb_host_instance;

static PIO pio_instances[2] = {pio0, pio1};
volatile bool _core1_ready = false;

static void __not_in_flash_func(core1_main)(void) {
Expand Down Expand Up @@ -76,7 +75,7 @@ static void __not_in_flash_func(core1_main)(void) {
}

static uint8_t _sm_free_count(uint8_t pio_index) {
PIO pio = pio_instances[pio_index];
PIO pio = pio_get_instance(pio_index);
uint8_t free_count = 0;
for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) {
if (!pio_sm_is_claimed(pio, j)) {
Expand All @@ -87,7 +86,7 @@ static uint8_t _sm_free_count(uint8_t pio_index) {
}

static bool _has_program_room(uint8_t pio_index, uint8_t program_size) {
PIO pio = pio_instances[pio_index];
PIO pio = pio_get_instance(pio_index);
pio_program_t program_struct = {
.instructions = NULL,
.length = program_size,
Expand All @@ -96,22 +95,26 @@ static bool _has_program_room(uint8_t pio_index, uint8_t program_size) {
return pio_can_add_program(pio, &program_struct);
}

// from pico-sdk/src/rp2_common/hardware_pio/pio.c
static bool is_gpio_compatible(PIO pio, uint32_t used_gpio_ranges) {
#if PICO_PIO_VERSION > 0
bool gpio_base = pio_get_gpio_base(pio);
return !((gpio_base && (used_gpio_ranges & 1)) ||
(!gpio_base && (used_gpio_ranges & 4)));
#else
((void)pio);
((void)used_gpio_ranges);
return true;
#endif
// As of 0.6.1, the PIO resource requirement is 1 PIO with 3 state machines &
// 32 instructions. Since there are only 32 instructions in a state machine, it should
// be impossible to have an allocated state machine but 32 instruction slots available;
// go ahead and check for it anyway.
//
// Since we check that ALL state machines are available, it's not possible for the GPIO
// ranges to mismatch on rp2350b
static size_t get_usb_pio(void) {
for (size_t i = 0; i < NUM_PIOS; i++) {
if (_has_program_room(i, 32) && _sm_free_count(i) == NUM_PIO_STATE_MACHINES) {
return i;
}
}
mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use"));
}


usb_host_port_obj_t *common_hal_usb_host_port_construct(const mcu_pin_obj_t *dp, const mcu_pin_obj_t *dm) {
if (dp->number + 1 != dm->number) {
if ((dp->number + 1 != dm->number)
&& (dp->number - 1 != dm->number)) {
raise_ValueError_invalid_pins();
}
usb_host_port_obj_t *self = &usb_host_instance;
Expand All @@ -127,33 +130,14 @@ usb_host_port_obj_t *common_hal_usb_host_port_construct(const mcu_pin_obj_t *dp,
assert_pin_free(dp);
assert_pin_free(dm);

#if PICO_PIO_VERSION == 0
uint32_t used_gpio_ranges = 0;
#else
uint gpio_base = dm->number;
uint gpio_count = 2;
uint32_t used_gpio_ranges = (1u << (gpio_base >> 4)) |
(1u << ((gpio_base + gpio_count - 1) >> 4));
#endif

pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.skip_alarm_pool = true;
pio_cfg.pin_dp = dp->number;
// Allocating the peripherals like this works on Pico W, where the
// "preferred PIO" for the cyw43 wifi chip is PIO 1.
pio_cfg.pio_tx_num = 1; // uses 22 instructions and 1 SM
pio_cfg.pio_rx_num = 0; // uses 31 instructions and 2 SM.
uint8_t tx_sm_free = _sm_free_count(pio_cfg.pio_tx_num);
uint8_t rx_sm_free = _sm_free_count(pio_cfg.pio_rx_num);
PIO pio_tx = pio_instances[pio_cfg.pio_tx_num];
PIO pio_rx = pio_instances[pio_cfg.pio_rx_num];

if (!_has_program_room(pio_cfg.pio_tx_num, 22) || tx_sm_free < 1 ||
!(tx_sm_free == 4 || is_gpio_compatible(pio_tx, used_gpio_ranges)) ||
!_has_program_room(pio_cfg.pio_rx_num, 31) || rx_sm_free < 2 ||
!(rx_sm_free == 4 || is_gpio_compatible(pio_rx, used_gpio_ranges))) {
mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use"));
if (dp->number - 1 == dm->number) {
pio_cfg.pinout = PIO_USB_PINOUT_DMDP;
}
pio_cfg.pio_tx_num = get_usb_pio();
pio_cfg.pio_rx_num = pio_cfg.pio_tx_num;
pio_cfg.tx_ch = dma_claim_unused_channel(false); // DMA channel
if (pio_cfg.tx_ch < 0) {
mp_raise_RuntimeError(MP_ERROR_TEXT("All dma channels in use"));
Expand All @@ -163,22 +147,15 @@ usb_host_port_obj_t *common_hal_usb_host_port_construct(const mcu_pin_obj_t *dp,
self->dp = dp;
self->dm = dm;

PIO tx_pio = pio_instances[pio_cfg.pio_tx_num];
pio_cfg.sm_tx = pio_claim_unused_sm(tx_pio, false);
PIO rx_pio = pio_instances[pio_cfg.pio_rx_num];
pio_cfg.sm_rx = pio_claim_unused_sm(rx_pio, false);
pio_cfg.sm_eop = pio_claim_unused_sm(rx_pio, false);
PIO pio = pio_get_instance(pio_cfg.pio_tx_num);

// Unclaim everything so that the library can.
dma_channel_unclaim(pio_cfg.tx_ch);
pio_sm_unclaim(tx_pio, pio_cfg.sm_tx);
pio_sm_unclaim(rx_pio, pio_cfg.sm_rx);
pio_sm_unclaim(rx_pio, pio_cfg.sm_eop);

// Set all of the state machines to never reset.
rp2pio_statemachine_never_reset(tx_pio, pio_cfg.sm_tx);
rp2pio_statemachine_never_reset(rx_pio, pio_cfg.sm_rx);
rp2pio_statemachine_never_reset(rx_pio, pio_cfg.sm_eop);
rp2pio_statemachine_never_reset(pio, pio_cfg.sm_tx);
rp2pio_statemachine_never_reset(pio, pio_cfg.sm_rx);
rp2pio_statemachine_never_reset(pio, pio_cfg.sm_eop);

common_hal_never_reset_pin(dp);
common_hal_never_reset_pin(dm);
Expand Down
2 changes: 1 addition & 1 deletion ports/raspberrypi/lib/Pico-PIO-USB