The bench tools
Three wires on the SWD connector, and the PC can see inside the running RP2040. Almost all of the project’s tools go through it, right down to typing on the keyboard or copying files to the USB stick.
On this page
The probe
The bench uses a CMSIS-DAP probe connected to the board’s SWD1 connector: a Raspberry Pi
Debugprobe over USB, or, since v0.59, Eliott65Sonde, a wireless probe written by the project,
which goes over Wi-Fi; it has its own wiki. A single
variable, E65_SONDE, sends every tool through it; with the current wiring, flashing is done at
200 kHz (E65_SWD_KHZ=200). SWD is the debug port of ARM processors: it can read and write the RP2040’s memory, and
control its two cores, while the firmware is running.
The PC-side software is OpenOCD, in its development version: version 0.12.0, as shipped by distributions, does not recognise the board’s Puya flash.
Flashing without being overwritten
One day, flashing started to fail (“double fault”, “failed to exit flash XIP mode”). The cause was a
delightful one: OpenOCD runs its flash-writing program in RAM, by default at address
0x20010000… which is the 6502’s memory. With the DMA bus still running, the 6502 was
incrementing a counter in zero page and overwriting OpenOCD’s program.
The flashing script now places this work area elsewhere, in unused RAM, and fails loudly if verification does not pass.
The main tools
| Tool | What it does |
|---|---|
flasher.sh | flashes the firmware over SWD, with verification |
sonde.py | reads the kernel state and the 6502’s memory, and measures its frequency |
verifier_carte.py, run_tests.sh --carte | full acceptance test on the board |
ecran.py | rebuilds the expected image and decodes the video buffers actually sent out |
usb.py | displays the USB driver log and the keyboard state |
appel.py | makes system calls from the PC |
copier_sur_cle.py, verifier_cle.py | copy files to the USB stick, then verify, without removing it |
taper.py, touches.py | type on the 6502’s keyboard, control keys included |
redemarrer_carte.sh | restarts the board through the watchdog |
Calling the kernel from the PC
appel.py uses the most useful property of the board’s 6502: it can be frozen. The tool stops
the bus PIO state machine (the 6502, a static core, waits without complaint), places a parameter
block, triggers the gate, waits for the kernel, then restores everything and restarts the 6502. It
notices nothing.
This is how the first tests of writing to the USB stick were done, before any 6502 program even knew how to write a file.
Copying to the USB stick without unplugging it
At the user’s request, programs are copied to the USB stick through the probe, without removing it from the board. The tool freezes the 6502, goes through the kernel’s STOCKAGE calls, and uses a cautious FAT writer: it backs up each block before modifying it, refuses duplicates, updates both copies of the FAT and reads back every block written. A read-only “dry run” always precedes the real copy.
To make all this fast, a persistent OpenOCD session is driven through its command port: an operation takes a few milliseconds instead of about half a second.
Typing without touching the board
taper.py places characters as a real keyboard would. For control keys (arrows, Esc,
and kernel shortcuts such as Ctrl+Tab), touches.py goes one level lower: it
places a complete HID report in a firmware mailbox, processed exactly like a report from the real
keyboard. The idea comes from the Trinity project, which drives its keyboard in the same way.
The probe’s pitfalls
- A restart through the watchdog did nothing without a register that the SDK writes before triggering it: earlier “restarts” had in fact been done by flashing.
- When OpenOCD leaves a core halted, the RP2040’s timer pauses, and the kernel’s waits never end. The firmware disables this pause.
- The SWD link proved unstable on several occasions (“Failed to connect multidrop”); at times it took a physical intervention on the board. Rule adopted: check the link with several reads before writing to the USB stick, and retry a single read that fails.