Search › A-Z › R › Raspberry Pi Pico W
Raspberry Pi Pico W
The real Raspberry Pi Pico W, in the browser. The RP2040's two ARM Cortex-M0+ cores run on the vendored rp2040js SoC — a complete Raspberry Pi Pico with XIP flash, 264 KB SRAM, GPIO, timers, UART and a USB device controller. The Pico W's signature detail is that its on-board LED is not an RP2040 pin: it hangs off the added Infineon CYW43439 WiFi chip's WL_GPIO0 and is driven over the chip's gSPI bus. A high-level model of the CYW43439 speaks that gSPI protocol back to the real driver, so setting the LED over the WiFi chip actually lights the on-board LED. It boots the official MicroPython firmware to an interactive REPL over USB-CDC, shows the CYW43 LED and serial console on screen, and wires the whole ARM Cortex-M0+ into this site's shared Thumb debugger. Being a bare Pico W, it is naturally silent — there is no on-board audio.
Visit the official Raspberry Pi Pico W page ↗
Runs on: Web browser
Raspberry Pi Pico W Online Emulator
Play Raspberry Pi Pico W using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| MicroPython REPL | Raspberry Pi Pico W | Raspberry Pi Pico W | open | Open ⛶ | |
| CYW43 LED (via WiFi chip) | Raspberry Pi Pico W | Raspberry Pi Pico W | open | Open ⛶ | |
| Hello UART (serial) | Raspberry Pi Pico W | Raspberry Pi Pico W | open | Open ⛶ |
Chips
Notes
Embedding
The RP2040 SoC is Uri Shaked's rp2040js (MIT), a complete in-browser Raspberry Pi Pico: two Cortex-M0+ cores, XIP flash, 264 KB SRAM, the SIO/GPIO block, timers, UART, a USB device controller with a USB-CDC class, and the PIO. It is used unmodified, bundled once to a single file-safe browser global (window.rp2040js) with esbuild — no core was reinvented.
The Raspberry Pi Pico W adds an Infineon CYW43439 WiFi chip. Crucially, the board's on-board LED is wired to that chip's WL_GPIO0, not to an RP2040 pin, and the RP2040 talks to the CYW43439 over a bit-banged gSPI bus (a PIO program on GPIO24 DATA, GPIO25 CS, GPIO29 CLK, power on GPIO23). rp2040js runs that PIO, so the real driver's gSPI words flow through PIO1's TX/RX FIFOs. Our cyw43.js intercepts those FIFO words and answers as a high-level model of the CYW43439's gSPI slave:
// esbuild entry.ts --bundle --format=iife -> window.rp2040js
var R = window.rp2040js;
var sim = new R.Simulator(); // owns the RP2040 + a simulation clock
var mcu = sim.rp2040;
mcu.loadBootrom(R.bootromB1);
loadUF2(firmwareBytes, mcu); // real Pico W MicroPython UF2 -> mcu.flash
CYW43.attach(mcu, R, { onLED: setLed }); // HLE CYW43439 on PIO1's gSPI FIFOs
var cdc = new R.USBCDC(mcu.usbCtrl); // USB-CDC = the MicroPython REPL
The gSPI slave. The real cyw43-driver frames every bus access as a 32-bit command word (write<<31 | inc<<30 | fn<<28 | addr<<11 | len). The chip boots little-endian with 16-bit halves swapped until SPI_BUS_CONTROL selects 32-bit big-endian; cyw43.js honours both. It answers the 0xFEEDBEAD detect, the ALP/HT clock handshake (SDIO_CHIP_CLOCK_CSR), the backplane address windowing, and the ARM-core reset registers, and it decodes the SDPCM/CDC control channel. The on-board LED is set by the WLC_SET_VAR "gpioout" ioctl for WL_GPIO0 — cyw43.js recognises that exact frame and toggles the panel LED. WiFi RF itself is not modelled; the chip-GPIO/LED path is.
| Member | Kind | What it does |
|---|---|---|
mcu.core.executeInstruction() | method | Execute one Thumb instruction on core 0, advancing core.PC; returns a cycle estimate. The single-step primitive. |
mcu.core.registers (Uint32Array 16) | field | r0-r12, SP(13), LR(14), PC(15), plus core.xPSR and the flag fields — all readable and writable. |
mcu.flash / mcu.sram / mcu.bootrom | field | The real memories as typed arrays — read side-effect-free for the hex + disassembly views. |
mcu.pio[1] TXF0 / RXF0 | hook | PIO1's gSPI FIFOs; cyw43.js intercepts these words to model the CYW43439 slave and drive WL_GPIO0. |
cdc.sendSerialByte(b) / mcu.uart[0].feedByte(b) | method | Serial RX in — the keyboard drives the MicroPython REPL through the USB-CDC port. |
Debugger integration
The plug-in (pico-w-debug.js) describes the RP2040 to the shared debugger and nothing more — rp2040js is not patched:
- Reused decoder. The Cortex-M0+ runs ARMv6-M Thumb, a subset of the existing
/debugger/src/cpus/cortex-m7.jsdisassembler (written for the Playdate-ARM Cortex-M7). It is reused as-is under the display name "ARM Cortex-M0+"; no new decoder was needed. - Registers are read live each refresh: r0-r12, SP, LR, PC, xPSR, the APSR flags N Z C V, and PRIMASK / nPRIV. Each has a
set()that writes straight back intocore.registers/ the core's flag fields. - Memory is exposed as three chips, all read side-effect-free directly off the typed arrays, each with its real base address so the disassembly lines up with PC: the XIP flash at
0x10000000(disassembled), the SRAM at0x20000000, and the 16 KB boot ROM at0x00000000(also disassembled). - Single step is one
executeInstruction(). Breakpoints are host-side checks ofcore.PC. Write-watchpoints wrapmcu.writeUint8/16/32and pause the loop the moment a watched bus address is written.
Architecture
The Raspberry Pi Pico W (2022) is the wireless member of the Pico family: the same RP2040 as the Pico, with an added Infineon CYW43439 2.4 GHz WiFi + Bluetooth chip.
- Dual ARM Cortex-M0+ — two 32-bit ARMv6-M cores at up to 133 MHz (modelled here at 125 MHz), Thumb instruction set, sharing the bus through the SIO single-cycle I/O block.
- Memory — 264 KB on-chip SRAM at
0x20000000; code executes in place (XIP) from external QSPI flash at0x10000000; a 16 KB mask boot ROM at0x00000000. - On-board LED via the WiFi chip — this is the Pico W's signature quirk. Unlike the Pico (LED on GPIO25), the Pico W's on-board LED is wired to the CYW43439's WL_GPIO0. GPIO25 is instead the CYW43 chip-select. Software toggles the LED with
machine.Pin('LED')in MicroPython orcyw43_arch_gpio_put()in C, both of which send a chip-GPIO ioctl to the CYW43439 over the gSPI bus. - CYW43439 gSPI — the RP2040 drives the WiFi chip over a PIO-bit-banged gSPI bus (GPIO24 DATA, GPIO25 CS, GPIO29 CLK, GPIO23 power). Here it is modelled by
cyw43.js, a high-level emulation of the chip's gSPI slave, so the LED-over-WiFi-chip path works end-to-end. - Serial — firmware talks to a host over UART0 or, as MicroPython does, over a USB-CDC virtual serial port — which is where the MicroPython REPL appears.
The default firmware is the official MicroPython for Raspberry Pi Pico W (.uf2) — real, unmodified firmware. It boots through the same path as on hardware to an interactive >>> prompt on the USB-CDC console, and its cyw43-driver really does bring the CYW43439 up over our gSPI model. The CYW43 LED firmware then demonstrates the quirk directly: a small bare-metal program that issues the authentic CYW43439 gSPI command stream (the SPI_BUS_CONTROL endian select and the gpioout chip-GPIO ioctl) and visibly blinks the on-board LED through the WiFi chip.
Honest limits. rp2040js is cycle-approximate. The CYW43439 is a high-level model of its gSPI/GPIO surface — the chip's own firmware, WiFi RF, scanning and networking are not emulated. In the stock MicroPython image, machine.Pin('LED') makes the real driver bit-bang the CYW43 bus through our model (chip detect, endian, clock handshake, backplane windowing and ARM-core reset all real); the driver then streams its ~225 KB WLAN firmware to the chip over a PIO-paced DMA transfer, which the vendored rp2040js does not clock through, so MicroPython's own LED bring-up stops there. The dedicated bare-metal CYW43 LED firmware drives the same authentic chip-GPIO ioctl over the CPU-fed FIFO path and blinks the LED end-to-end. The bare Pico W has no on-board sound hardware, so this emulator is naturally silent.