From 31f78894993099e667a3b56f8d3556fac081538b Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 25 Jan 2025 11:08:03 -0600 Subject: [PATCH 1/4] raspberrypi: Update usb_host for newer PIO resource usage Closes: #9958 --- ports/raspberrypi/common-hal/usb_host/Port.c | 65 ++++++-------------- 1 file changed, 20 insertions(+), 45 deletions(-) diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c index cf242dc809268..b7d3457810d30 100644 --- a/ports/raspberrypi/common-hal/usb_host/Port.c +++ b/ports/raspberrypi/common-hal/usb_host/Port.c @@ -96,17 +96,20 @@ 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")); } @@ -127,33 +130,12 @@ 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")); } + 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")); @@ -163,22 +145,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_instances[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); From 53d8da63d012a0fce040f47f0353253a6a34d5db Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 25 Jan 2025 11:08:28 -0600 Subject: [PATCH 2/4] raspberrypi: usb_host: Allow swapped DP/DM pin usage --- ports/raspberrypi/common-hal/usb_host/Port.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c index b7d3457810d30..4c64f7143d672 100644 --- a/ports/raspberrypi/common-hal/usb_host/Port.c +++ b/ports/raspberrypi/common-hal/usb_host/Port.c @@ -114,7 +114,8 @@ static size_t get_usb_pio(void) { 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; @@ -133,6 +134,8 @@ usb_host_port_obj_t *common_hal_usb_host_port_construct(const mcu_pin_obj_t *dp, pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; pio_cfg.skip_alarm_pool = true; pio_cfg.pin_dp = dp->number; + 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; From a2bf8fee4fdfc80df3ef222925d910010b66406d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 26 Jan 2025 09:34:11 -0600 Subject: [PATCH 3/4] Use SDK API function to turn PIO index into PIO pointer --- .../common-hal/picodvi/Framebuffer_RP2040.c | 8 +++----- .../raspberrypi/common-hal/rp2pio/StateMachine.c | 15 ++++----------- ports/raspberrypi/common-hal/usb_host/Port.c | 7 +++---- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c index b244fb8bbd015..5b69610ace785 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -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. @@ -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)) { @@ -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. @@ -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]; diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index acbf0e3ab2841..880480599b163 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -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]; @@ -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; @@ -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; } @@ -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; @@ -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); } diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c index 4c64f7143d672..e350c288f71a5 100644 --- a/ports/raspberrypi/common-hal/usb_host/Port.c +++ b/ports/raspberrypi/common-hal/usb_host/Port.c @@ -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) { @@ -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)) { @@ -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, @@ -148,7 +147,7 @@ usb_host_port_obj_t *common_hal_usb_host_port_construct(const mcu_pin_obj_t *dp, self->dp = dp; self->dm = dm; - PIO pio = pio_instances[pio_cfg.pio_tx_num]; + PIO pio = pio_get_instance(pio_cfg.pio_tx_num); // Unclaim everything so that the library can. dma_channel_unclaim(pio_cfg.tx_ch); From 2eed793862217da1fb7a2dda0b3f0dbb05f95e2a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 26 Jan 2025 10:57:13 -0600 Subject: [PATCH 4/4] Pull in Pico-PIO-USB changes for pio2 --- ports/raspberrypi/lib/Pico-PIO-USB | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/lib/Pico-PIO-USB b/ports/raspberrypi/lib/Pico-PIO-USB index f4e50b21b42dc..b559b3e1637ea 160000 --- a/ports/raspberrypi/lib/Pico-PIO-USB +++ b/ports/raspberrypi/lib/Pico-PIO-USB @@ -1 +1 @@ -Subproject commit f4e50b21b42dc43faf5279e43123a1de6f275792 +Subproject commit b559b3e1637ead1768514b0de962e21a99a9adbf