The keyboard and USB
The Neo6502kbd’s keyboard is a USB keyboard, behind a hub. To read it, and to read the USB stick, Eliott65 has its own USB driver, written directly against the RP2040’s registers.
On this page
A driver written for the project
The driver talks directly to the RP2040’s USB controller, using only the pico-sdk’s register definitions. It can:
- perform the basic transactions (SETUP, IN, OUT) and control transfers;
- enumerate devices, that is, discover them and give them an address;
- manage the hub: power the ports, reset them, monitor them;
- read a keyboard in “boot” mode, the simple mode that every USB keyboard understands;
- talk to a USB stick (mass storage).
It takes into account a known RP2040 defect (erratum RP2040-E4) and the PRE packet required by low-speed devices placed behind a full-speed hub.
The “zero-call” keyboard
The keyboard is polled by the USB controller itself, every 10 ms: core 0 only has to pick up the result.
On the 6502 side, Eliott65 goes further: the program declares an 18-byte queue in its own memory. The kernel places the typed characters there, the data first, the index afterwards. To find out whether a key is waiting, the program compares two bytes, without any system call.
Key conversion handles the US (QWERTY) and FR (AZERTY) layouts, the combinations Ctrl+A to Ctrl+Z, the arrow keys, and ignores spurious repeats. The board’s keyboard is QWERTY: that is the default layout.
First connection
| Where | Device | Result |
|---|---|---|
| board | FE1.1s hub, 4 ports | enumerated |
| port 1 | keyboard, Low Speed | working: ten keys typed, ten received |
| port 4 | mouse, Low Speed | enumerated (not used yet) |
| port 3 | USB stick, Full Speed | failure |
The device that did not answer
The stick accepted the first stage of the request, then the next one timed out after 50 ms, even after three attempts. Slow devices got through; only fast devices behind the hub failed. A hardware fault came to mind.
The diagnosis showed something else: no line errors, only “not ready yet” replies. The cause was the 50 ms timeout, chosen because it seemed reasonable. But the USB standard allows a device up to 500 ms to answer certain requests, and a stick needs it just after being reset. With the standard’s timeout, the stick enumerates.
The USB stick
A stick speaks the Bulk-Only protocol and SCSI commands: a 31-byte command block, data in 64-byte packets, a 13-byte status block. The driver handles stalls (STALL) and inconsistencies by resetting the transport.
The test stick reports “General USB Flash Disk”, 15,669,248 blocks of 512 bytes (7.5 GiB).
The STOCKAGE service reads and writes a block directly at the chosen address in the 6502’s memory, with no intermediate copy. First try: block 0 is read, its signature is correct and the first partition is indeed FAT32.
Writing to someone else’s stick
Writing was first tested on a fake disk in memory, not on the stick: it might contain data. With its owner’s agreement, the real test targeted the stick’s last block: read and back up, write a pattern, read back, restore, read back.
Surprise: this block “at the end of the stick” was not empty (489 non-zero bytes). The backup was not an unnecessary precaution.
Faster: several blocks per command, deferred FAT
Starting measurement: writing 64 KiB took 1.6 s. Two changes:
- multi-block commands (up to 128 per command);
- a write-deferred FAT: the allocation table is no longer rewritten on every cluster, but once per modified sector, at the end of the operation.
The real culprit was the second: around a hundred small 512-byte writes, at about 14 ms each on this stick.
| 64 KiB | Before | After |
|---|---|---|
| write | 1.6 s | 0.238 s (275 KiB/s, × 6.7) |
| read after rewrite | 1.9 s | 0.357 s (184 KiB/s, × 5.3) |
Withstanding transient errors
The emulator’s USB test bench revealed a defect: a single stall while reading the shell was enough to stop it from starting, with no message. Now every read or write is retried three times; a real failure is reported to the kernel without hanging.
Plugging in and unplugging
The driver polls the hub’s ports every second. A stick or keyboard removed and plugged back in is forgotten, re-enumerated, and the file system is remounted. In the emulator, the stick was even yanked out during a write, at many different moments (swept in steps of 2,500 cycles): the program receives an error, and the FAT stays sound or suffers only minor damage. See Files.