Search › A-Z › R › Raspberry Pi Pico 2
Raspberry Pi Pico 2
The real Raspberry Pi Pico 2, in the browser. The RP2350's two Arm Cortex-M33 cores run on the vendored rp2350js SoC — a complete Raspberry Pi Pico 2 with XIP flash, 264 KB SRAM, GPIO, timers, UART and a USB device controller. It boots the official MicroPython firmware to an interactive REPL over USB-CDC, and also runs bare-metal firmware, with the on-board LED (GPIO25) and serial console on screen and the whole Arm Cortex-M33 wired into this site's shared Thumb debugger. Being a bare Pico, it is naturally silent — there is no on-board audio.
Visit the official Raspberry Pi Pico 2 page ↗
Runs on: Web browser
Raspberry Pi Pico 2 Online Emulator
Play Raspberry Pi Pico 2 using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| MicroPython REPL (Arm Cortex-M33) | Raspberry Pi Pico 2 | Raspberry Pi Pico 2 | open | Open ⛶ | |
| MicroPython REPL (Hazard3 RISC-V) | Raspberry Pi Pico 2 | Raspberry Pi Pico 2 | open | Open ⛶ | |
| Blink (on-board LED) | Raspberry Pi Pico 2 | Raspberry Pi Pico 2 | open | Open ⛶ | |
| Hello UART (serial) | Raspberry Pi Pico 2 | Raspberry Pi Pico 2 | open | Open ⛶ |
Chips
Notes
Embedding
The RP2350 SoC is c1570's rp2350js (MIT), a much-improved fork of Uri Shaked's rp2040js that adds the Raspberry Pi Pico 2 chip: two processor sockets that are either dual ARM Cortex-M33 (ARMv8-M Mainline + FPU) or dual Hazard3 RISC-V (RV32), 520 KB SRAM, XIP flash, SIO/GPIO, PIO, DMA, timers, UART and a USB device controller with a USB-CDC class. It is a TypeScript project; it was bundled once to a single file-safe browser global (window.rp2350js) with esbuild and is used unmodified — no core was reinvented.
// esbuild entry.ts --bundle --format=iife --platform=browser -> window.rp2350js
var R = window.rp2350js;
var mcu = new R.RP2350({ coreArch: 'arm' }); // 'arm' (Cortex-M33) or 'riscv' (Hazard3)
loadUF2(firmwareBytes, mcu); // decode UF2 blocks straight into mcu.flash
mcu.reset(); // real A2 boot ROM scans flash + hands off to firmware
var cdc = new R.USBCDC(mcu.usbCtrl); // USB-CDC = the MicroPython REPL serial port
cdc.onSerialData = function(bytes){ /* -> console */ };
mcu.uart[0].onByte = function(b){ /* UART0 TX -> console */ };
We own the run loop so the debugger can drive it. Each frame runs a time-boxed budget of mcu.step() (one Cortex-M33/Hazard3 instruction on core 0, the second core caught up, PIO and the simulation clock advanced). Bare-metal images are entered with a flat Cortex-M reset (MSP ← word0, PC ← word1); MicroPython is entered through the real boot ROM. Everything is plain JavaScript state:
| Member | Kind | What it does |
|---|---|---|
mcu.step() | method | Execute one instruction on core 0 (ARM or RISC-V), catch up core 1, tick PIO + clock. The single-step primitive. |
mcu.core[0] | field | The concrete core: CortexM33Core (.regs.r, .regs.xpsr, .regs.s FPU) when arch is 'arm', or the Hazard3 CPU (.regs Int32Array, .csrs) when 'riscv'. .PC on both. |
mcu.flash / mcu.sram / mcu.bootrom | field | The real memories as typed arrays — read side-effect-free for the hex + disassembly views. |
mcu.writeUint8/16/32(addr,v) | method | The bus write path — wrapped to implement write-watchpoints. |
mcu.gpio[25].value | getter | The on-board LED pin (High/Low) — polled each frame to draw the LED. |
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 (rp2350-debug.js) describes the RP2350 to the shared debugger and nothing more — rp2350js is not patched. It adapts to whichever core the selected firmware runs on:
- Reused decoders. The ARM Cortex-M33 runs ARMv8-M Thumb, decoded by the existing
/debugger/src/cpus/cortex-m7.jsdisassembler (Thumb-2 is the same encoding family) under the display name "ARM Cortex-M33". The Hazard3 RISC-V core is decoded by the existing/debugger/src/cpus/riscv.jsdisassembler (RV32I + M + the C compressed forms). No new decoder was written. - Registers are read live each refresh. ARM: r0-r12, SP, LR, PC, xPSR, the APSR flags N Z C V, PRIMASK/CONTROL, and the FPv5 file s0-s31. RISC-V: x0-x31 (ABI names) + PC. Each has a
set()that writes straight back into the live register file. - Memory is exposed as three chips, all read side-effect-free directly off the typed arrays, each at its real base so the disassembly lines up with PC: the XIP flash at
0x10000000(disassembled), the SRAM at0x20000000, and the 32 KB boot ROM at0x00000000(also disassembled — the real RP2350 A2 bootrom). - Single step is one
mcu.step(). Breakpoints are host-side checks ofcore.PC. Write-watchpoints wrapmcu.writeUint8/16/32and pause the moment a watched bus address is written.
Architecture
The Raspberry Pi Pico 2 (2024) is Raspberry Pi's second in-house microcontroller board, built around their RP2350 — the successor to the RP2040:
- Two cores, two architectures. The RP2350 carries both a pair of Arm Cortex-M33 cores (ARMv8-M Mainline, with the FPv5 single-precision FPU and DSP) and a pair of open-hardware Hazard3 RISC-V cores (RV32IMAC). At boot the chip selects which pair runs; this emulator ships both, and real MicroPython runs on either.
- Memory — 520 KB on-chip SRAM at
0x20000000; code executes in place (XIP) from external QSPI flash mapped at0x10000000; a 32 KB mask boot ROM at0x00000000. - On-board LED — a single user LED on GPIO25, driven through the SIO GPIO block. This is the Pico 2's only on-board indicator; there are no other lights, displays, buttons or audio on the bare board.
- Serial — the RP2350 exposes PL011 UARTs plus a full-speed USB 1.1 device controller. 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 the Raspberry Pi Pico 2 (.uf2, v1.28.0) — real, unmodified firmware. It boots through the real A2 boot ROM and drops you at an interactive >>> prompt on the USB-CDC console. The RISC-V build is the same MicroPython release compiled for the Hazard3 cores; it boots to the same REPL, reporting itself as "Raspberry Pi Pico2 with RP2350-RISCV". Because it is real machine code on a real SoC model, every instruction single-steps in the debugger, and Python that touches machine.Pin(25) visibly toggles the on-board LED.
Honest limits. rp2350js is cycle-approximate, not cycle-exact; the second core, PIO and DMA are modelled and present but not exercised by these particular firmwares (MicroPython drives core 0); the debugger single-steps core 0. The bare Pico 2 has no on-board sound hardware (PWM audio needs an external speaker), so this emulator is naturally, deliberately silent.