rp23xx: add CYW43439 wifi driver and Pimoroni Pico Plus 2 W board#19533
Open
casaroli wants to merge 2 commits into
Open
rp23xx: add CYW43439 wifi driver and Pimoroni Pico Plus 2 W board#19533casaroli wants to merge 2 commits into
casaroli wants to merge 2 commits into
Conversation
casaroli
force-pushed
the
rp23xx-cyw43439-pimoroni-pico-plus-2-w
branch
from
July 25, 2026 10:51
5c1d144 to
49dfc06
Compare
acassis
previously approved these changes
Jul 25, 2026
Provide the transport half of the bcmf FullMAC driver on RP2350, so that
boards carrying an Infineon CYW43439 (or the Raspberry Pi RM2 module that
houses one) can bring up a wlan0 interface. The chip's half-duplex gSPI bus
is driven by a six-instruction PIO program with DMA in both directions, and
the driver fills in the gspi_dev_t operations that bcmf_gspi_initialize()
expects.
This is a port of the equivalent rp2040 driver. Three differences in the
RP2350 hardware and its NuttX support had to be accounted for:
- The GPIO_STATUS register no longer has an OEFROMPERI field, so the wait
for the PIO program to release the shared data line watches OETOPAD
instead. No override is configured on that pad, so the two fields carry
the same value.
- rp23xx GPIO interrupt modes are enumerated as indices rather than as the
bitmask rp2040 uses, so passing the rp2040 constant would have selected
the wrong trigger.
- RP23XX_PIO_NUM is three, and the DREQ definitions live in
hardware/rp23xx_dreq.h.
The data and clock lines are also explicitly pulled down rather than left on
the reset default. The data line doubles as the chip's active-high interrupt
request and is serviced with a level-high interrupt, so it must read low
whenever the CYW43439 has released it.
Finally, the state machine returned by rp23xx_pio_claim_unused_sm() is
collected in a signed temporary before being stored, so that the "no state
machine available" test is not defeated by an unsigned comparison.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
The Pimoroni Pico Plus 2 W is a Pico form-factor board built around the
RP2350B, the 80-pin part with 48 GPIOs, carrying 16MB of flash, 8MB of PSRAM
and a Raspberry Pi RM2 module for 2.4GHz WiFi. The RM2 houses an Infineon
CYW43439, wired to the same pins the Raspberry Pi Pico W uses: GPIO 23 for
power enable, 24 for the shared gSPI data and interrupt line, 25 for chip
select and 29 for the clock.
Three configurations are provided: nsh and usbnsh without the wireless chip,
and wifi, which brings up wlan0 in station mode with WAPI, a DHCP client and
ping. The CYW43439 firmware and CLM blob are linked in from the pico-sdk at
build time, as on the Pico W; CONFIG_CYW43439_FIRMWARE_BIN_PATH selects the
file and the board documentation covers converting it out of the C header that
pico-sdk 2.x ships in place of the binary. rp23xx_firmware.c is placed in the
common source directory so that a future board with the same chip can reuse
it, and unlike rp2040 the blob is staged for the CMake build as well.
Two board details are worth calling out:
- The only LED is wired to GPIO 0 of the CYW43439 rather than to a pin of
the RP2350, so driving it means an iovar request over the gSPI bus. That
works for CONFIG_USERLED but not for CONFIG_ARCH_LEDS, whose
board_autoled_on() is called from interrupt handlers and from assertion
handling, so a build selecting CONFIG_ARCH_LEDS is rejected with an
explicit message. The LED also only responds once wlan0 has been brought
up, because that is when the chip's firmware is downloaded.
- The BOOT button is also wired to GPIO 45, so it can be read as an ordinary
user button once NuttX is running. Its internal pull-up is enabled
deliberately: erratum RP2350-E9 means a floating Bank 0 input on RP2350 A2
leaks enough current to settle around 2.2V, which the internal pull-down
cannot overcome.
Tested on the board with a Raspberry Pi Debug Probe: nsh and wifi boot on
UART0, wlan0 reports the MAC read from the chip, wapi scan lists access
points, and association to a WPA2 network followed by DHCP gives a working
route with ping succeeding to both a literal address and a resolved name.
The LED and the BOOT button were confirmed by hand.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
casaroli
force-pushed
the
rp23xx-cyw43439-pimoroni-pico-plus-2-w
branch
from
July 25, 2026 13:59
49dfc06 to
0bd195b
Compare
xiaoxiang781216
approved these changes
Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RP2350 had no wireless support, although the bcmf FullMAC driver and its gSPI
bus binding have been in tree since the Raspberry Pi Pico W port. This adds the
missing transport for rp23xx and a board that uses it.
arch/arm/rp23xx: Add gSPI driver for the Infineon CYW43439.Provides thegspi_dev_toperations thatbcmf_gspi_initialize()expects, driving thechip's half-duplex gSPI bus with a six-instruction PIO program and DMA in both
directions. It is a port of
rp2040_cyw43439.c; three differences in the RP2350hardware and its NuttX support had to be handled:
GPIO_STATUSregister no longer has anOEFROMPERIfield, so the waitfor the PIO program to release the shared data line watches
OETOPAD. Nooverride is configured on that pad, so the two fields carry the same value.
bitmask rp2040 uses, so passing the rp2040 constant would have selected the
wrong trigger.
RP23XX_PIO_NUMis three, and the DREQ definitions live inhardware/rp23xx_dreq.h.The data and clock lines are also pulled down explicitly rather than left on
the reset default. The data line doubles as the chip's active-high interrupt
request and is serviced with a level-high interrupt, so it must read low
whenever the CYW43439 has released it. Finally the state machine returned by
rp23xx_pio_claim_unused_sm()is collected in a signed temporary before beingstored, so the "none available" test is not defeated by an unsigned comparison.
boards/arm/rp23xx: Add support for the Pimoroni Pico Plus 2 W.A Picoform-factor board built around the RP2350B — the 80-pin part with 48 GPIOs —
with 16MB of flash, 8MB of PSRAM and a Raspberry Pi RM2 module for 2.4GHz WiFi.
The RM2 houses a CYW43439 wired to the same pins the Pico W uses: GPIO 23 power
enable, 24 shared gSPI data and interrupt, 25 chip select, 29 clock.
Three configurations:
nshandusbnshwithout the wireless chip, andwifi,which brings up
wlan0in station mode with WAPI, a DHCP client andping.The firmware and CLM blob are linked in from the pico-sdk at build time exactly
as on the Pico W, selected by
CONFIG_CYW43439_FIRMWARE_BIN_PATH. pico-sdk 2.xno longer ships that blob as a binary, only as a C header, so the board
documentation covers converting it back.
rp23xx_firmware.cis placed in thecommon source directory so a future board with the same chip reuses it, and
unlike rp2040 the blob is staged for the CMake build as well as for Make.
Two board details drove design decisions:
driving it means an iovar request over the gSPI bus. That is fine for
CONFIG_USERLEDbut not forCONFIG_ARCH_LEDS, whoseboard_autoled_on()is called from interrupt handlers and from assertion handling. A build
selecting
CONFIG_ARCH_LEDSis therefore rejected with an explicit messagerather than silently doing nothing. The LED also only responds once
wlan0has been brought up, because that is when the chip's firmware is downloaded.
button once NuttX is running. Its internal pull-up is enabled deliberately:
erratum RP2350-E9 means a floating Bank 0 input on RP2350 A2 leaks around
120uA and settles near 2.2V, which the internal pull-down cannot overcome.
Impact
IEEE80211_INFINEON_CYW43439, sonothing changes for current users; with it disabled neither new source file
is compiled.
arm(rp23xx / RP2350). New chip source built only underCONFIG_IEEE80211_INFINEON_CYW43439.pimoroni-pico-plus-2-w. The rp23xx commonMake.defsandCMakeLists.txtgain a block forrp23xx_firmware.c, alsoguarded by
CONFIG_IEEE80211_INFINEON_CYW43439, so other rp23xx boards areunaffected.
CONFIG_CYW43439_FIRMWARE_BIN_PATH. If it is absent a placeholder is used sothe tree still compiles, matching the existing rp2040 behaviour; the wireless
chip then does not come up. No blob is added to the repository.
symbols.
Documentation/platforms/arm/rp23xx/boards/.Testing
Host: macOS 15 (arm64), Arm GNU Toolchain 14.2.Rel1.
Hardware: Pimoroni Pico Plus 2 W, RP2350 A2 in QFN80 (confirmed with
picotool info). Flashed over SWD with a Raspberry Pi Debug Probe (probe-rs);console on UART0 at 115200 through the probe's UART bridge.
SSIDs and BSSIDs below are masked; they were real values in the session.
Builds
All three configurations built from a clean tree, each reaching
LD: nuttx:tools/checkpatch.sh -fpasses on every added C and header file.Blob embedding verified in the linked ELF:
g_cyw43439_clm_blob_imagesitsexactly
224256bytes afterg_cyw43439_firmware_image(the 224190-bytefirmware rounded up to a 256-byte boundary) and begins with the CLM
BLOBmagic, so the real blob is linked rather than the placeholder.
Base configuration, on hardware
Wireless, on hardware
wlan0is registered with the MAC read from the chip:Scan:
Association, DHCP and connectivity:
DNS resolution working confirms the full path through the driver in both
directions, not just ICMP to a literal address.
The association sequence was re-run after every change to the firmware staging
layout and after rebasing onto current master, with the same result.
LED and button, on hardware
The LED on CYW43439 GPIO 0 was driven with the
ledsexample and observedblinking on the board:
The BOOT button on GPIO 45 was read through
/dev/buttonswith thebuttonsexample, pressing it by hand:
Not tested
usbnshwas build-tested only. RP2350 USB device support is still markedexperimental and the CDC/ACM console corrupts data after a few commands on
any rp23xx board, which is pre-existing and unrelated to this change.