Skip to content

embassy-rp/cyw43-pio: fix input_sync_bypass for pins >= 32 (GPIOBASE offset)#6391

Open
cedrivard wants to merge 4 commits into
embassy-rs:mainfrom
cedrivard:fix-input-sync-bypass-gpiobase
Open

embassy-rp/cyw43-pio: fix input_sync_bypass for pins >= 32 (GPIOBASE offset)#6391
cedrivard wants to merge 4 commits into
embassy-rs:mainfrom
cedrivard:fix-input-sync-bypass-gpiobase

Conversation

@cedrivard

Copy link
Copy Markdown

Problem

Pio::Pin::set_input_sync_bypass builds the bitmask from the absolute pin
number (1 << self.pin()), but input_sync_bypass is indexed relative to the
PIO's GPIOBASE
(0 or 16 on RP235x). On RP235xB with GPIOBASE = 16, a pin

= 32 (e.g. GPIO 38) shifts by the full pin number: it panics in debug, and in
release wraps to the wrong bit (38 -> bit 6).

This breaks cyw43-pio on boards that wire the CYW43 data line to a high pin.
On the SparkFun IoT RedBoard RP2350 (RP2350B; CYW43 on GPIO 36/37/38),
cyw43::new() hangs: without a working sync bypass the PIO samples stale data
and the link never comes up.

Fix

1. embassy-rp — offset the mask by GPIOBASE. Shift by pin - offset,
reading the offset (0/16) from the GPIOBASE register instead of assuming a
fixed value (resolving the 16..31 ambiguity from #5116).

2. cyw43-pio — call it after set_config. GPIOBASE is only written by
StateMachine::set_config, but the call was at pin creation, before
set_config, so the register read returned a stale 0. Moving it after
sm.set_config(&cfg) makes the offset correct.

Testing

Verified on hardware (SparkFun IoT RedBoard RP2350, RP2350B): cyw43::new()
succeeds and WiFi associates, replacing a manual INPUT_SYNC_BYPASS write I'd
been carrying downstream.

Supersedes #5116 (same root cause); credit to @diogo464 for the original report
and the ordering insight, and @Dirbaio for the GPIOBASE review note.

Cedric Rivard added 2 commits June 20, 2026 12:14
set_input_sync_bypass built the bitmask with the absolute pin number, but
input_sync_bypass is indexed relative to the PIO's GPIOBASE. On RP235xB with
GPIOBASE=16, a pin >= 32 (e.g. GPIO 38) shifted by the full pin number, which
panics in debug and wraps to the wrong bit in release. Subtract the GPIOBASE
offset (read from the register) before shifting.
input_sync_bypass is indexed relative to GPIOBASE, which is only established by
StateMachine::set_config. Calling it at pin creation (before set_config) read a
stale GPIOBASE of 0, so the offset was wrong for the CYW43 data pin on boards
that wire it to a pin >= 32 (RP235xB). Move the call after set_config.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant