Skip to content

Commit 2db2f53

Browse files
AJMansfielddpgeorge
authored andcommitted
rp2/rp2_pio: Fix support for pin wrapping and RP2350B upper-bank pins.
On RP2350B where there are more than 32 pins, using `pio_sm_set_pins_with_mask()` and `pio_sm_set_pindirs_with_mask()` is not correct because their arguments are `uint32_t` and higher bits get lost when `pio.gpio_base(16)` is used. This commit fixes the issue by using the 64-bit API functions on RP2350B. It also makes sure pin wrapping is supported, i.e. using [30, 31, 0, 1] or [46, 47, 16, 17] as contiguous pin ranges for a PIO program. Fixes issue micropython#16199. Signed-off-by: Anson Mansfield <[email protected]>
1 parent b24c9cf commit 2db2f53

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

ports/rp2/rp2_pio.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,32 @@ static void asm_pio_get_pins(PIO pio, const char *type, mp_obj_t prog_pins, mp_o
271271
}
272272
}
273273

274+
static inline uint32_t rotl32a(const uint32_t x, const int k) {
275+
return (x << k) | (x >> (32 - k));
276+
}
277+
274278
static void asm_pio_init_gpio(PIO pio, uint32_t sm, asm_pio_config_t *config) {
275-
uint32_t pinmask = ((1 << config->count) - 1) << (config->base - pio_get_gpio_base(pio));
276-
pio_sm_set_pins_with_mask(pio, sm, config->pinvals << (config->base - pio_get_gpio_base(pio)), pinmask);
277-
pio_sm_set_pindirs_with_mask(pio, sm, config->pindirs << (config->base - pio_get_gpio_base(pio)), pinmask);
278-
for (size_t i = 0; i < config->count; ++i) {
279-
gpio_set_function(config->base + i, GPIO_FUNC_PIO0 + pio_get_index(pio));
279+
uint gpio_base = pio_get_gpio_base(pio);
280+
uint32_t pinmask = rotl32a(~(-1 << config->count), config->base - gpio_base);
281+
uint32_t pinvals = rotl32a(config->pinvals, config->base - gpio_base);
282+
uint32_t pindirs = rotl32a(config->pindirs, config->base - gpio_base);
283+
284+
#if !PICO_PIO_USE_GPIO_BASE
285+
// optimization: avoid 64-bit arithmetic on RP2040 and RP2350A
286+
pio_sm_set_pins_with_mask(pio, sm, pinvals, pinmask);
287+
pio_sm_set_pindirs_with_mask(pio, sm, pindirs, pinmask);
288+
#else
289+
uint64_t pinmask64 = (uint64_t)pinmask << gpio_base;
290+
uint64_t pinvals64 = (uint64_t)pinvals << gpio_base;
291+
uint64_t pindirs64 = (uint64_t)pindirs << gpio_base;
292+
pio_sm_set_pins_with_mask64(pio, sm, pinvals64, pinmask64);
293+
pio_sm_set_pindirs_with_mask64(pio, sm, pindirs64, pinmask64);
294+
#endif
295+
296+
for (size_t i = 0; i < 32; ++i) {
297+
if (pinmask & (1 << i)) {
298+
gpio_set_function(gpio_base + i, GPIO_FUNC_PIO0 + pio_get_index(pio));
299+
}
280300
}
281301
}
282302

0 commit comments

Comments
 (0)