SearchA-ZR › Raspberry Pi Pico 2

Raspberry Pi Pico 2

2024 Open source · MIT Online

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.

Configurations

ConfigurationEmulatorMachineOSLegal
MicroPython REPL (Arm Cortex-M33)Raspberry Pi Pico 2Raspberry Pi Pico 2openOpen ⛶
MicroPython REPL (Hazard3 RISC-V)Raspberry Pi Pico 2Raspberry Pi Pico 2openOpen ⛶
Blink (on-board LED)Raspberry Pi Pico 2Raspberry Pi Pico 2openOpen ⛶
Hello UART (serial)Raspberry Pi Pico 2Raspberry Pi Pico 2openOpen ⛶

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:

MemberKindWhat it does
mcu.step()methodExecute one instruction on core 0 (ARM or RISC-V), catch up core 1, tick PIO + clock. The single-step primitive.
mcu.core[0]fieldThe 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.bootromfieldThe real memories as typed arrays — read side-effect-free for the hex + disassembly views.
mcu.writeUint8/16/32(addr,v)methodThe bus write path — wrapped to implement write-watchpoints.
mcu.gpio[25].valuegetterThe on-board LED pin (High/Low) — polled each frame to draw the LED.
cdc.sendSerialByte(b) / mcu.uart[0].feedByte(b)methodSerial 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.js disassembler (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.js disassembler (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 at 0x20000000, and the 32 KB boot ROM at 0x00000000 (also disassembled — the real RP2350 A2 bootrom).
  • Single step is one mcu.step(). Breakpoints are host-side checks of core.PC. Write-watchpoints wrap mcu.writeUint8/16/32 and 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 at 0x10000000; a 32 KB mask boot ROM at 0x00000000.
  • 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.