M5: the UniDisk reads a disk my board wrote

/ UniDisk 3.5 controller / updated 2026-10-11 unidisk rp2350 gcr pio firmware m5

The board writes now. It formatted a blank-ish scratch disk in 46 s, wrote all 1600 blocks of my REF800K test image onto it, and then I put that disk in the working UniDisk on the IIe. ProDOS listed it. ADTPro pulled an image back through the UniDisk and it matched the original byte for byte.

TESTWRITE2.po (ADTPro image of disk 2 via the working UniDisk) vs REF800K: 0 blocks differ []
sha256 bfed064fef52e305 ref bfed064fef52e305
Disk 2, formatted and written by the RP2350, cataloged by the stock UniDisk on the IIe (Bitsy Bye, S5,D1).
Disk 2, formatted and written by the RP2350, cataloged by the stock UniDisk on the IIe (Bitsy Bye, S5,D1).
StepResult
First write, block 100 on disk 1status 00, verified on the first write; full re-read differs only in block 100
Whole disk written onto disk 1855 s, 0 soft errors, 0 blocks differ
Board format of disk 246.1 s, all 160 track sides on the first try
Whole disk written onto disk 2853 s, 0 blocks differ
Disk 2 in the stock UniDiskcatalogs as /REF800K, ADTPro image identical

The format sounds just like formatting one on the Apple II. Same layout, same order, same stepping rhythm.

How a write catches its sector

3.5" GCR has no index hole, so the only way to know where you are is to read. Core 1 decodes the track live, one flux interval at a time, and when the target sector’s header goes past it starts the write. A second PIO program does the writing. It takes a byte image from DMA and toggles WRTDATA once per 1 bit, 32 PIO cycles per bit cell, with /WRTGATE dropped one cell before the first edge and raised one cell after the last. The program raises the gate itself, so a firmware bug can’t leave it low.

The bytes it writes are the ones the original drive ROM writes: same sync patterns, same gaps, same 4:1 interleave. I used the ROM disassembly as the reference and didn’t copy its code.

What the scope says

MeasureMeasuredERS spec
Gate low to first WRTDATA edge2.17 usat least 1.8 us
Bit cell2.040 to 2.048 us2.0425 us
Last edge to gate high4.02 usat least 2 us
One sector’s data field11.70 ms716 bytes
One track side during format165.95 msone revolution is 152 ms
Header seen to gate low3.1 usthe old data mark is about 160 us away
Start of a sector write, 1 us/div. Yellow /WRTGATE, magenta WRTDATA, cyan RD. First WRTDATA edge 2.17 us after the gate drops.
Start of a sector write, 1 us/div. Yellow /WRTGATE, magenta WRTDATA, cyan RD. First WRTDATA edge 2.17 us after the gate drops.

I got the latency off RD rather than trusting the firmware. I saved the RD trace before the gate dropped, decoded it in Python, and found the header in it: D5 AA 96 9D A7 96 DB DF DE AA. The gate fell 3.1 us after the first flux edge that follows that last AA, which is the earliest the decoder can know the header is done. The original drive takes something like 16 to 30 us there.

A format write is one long gate with no index, and it’s longer than a revolution on purpose. The tail of the track lands on top of the sync bytes at the start, so it doesn’t matter where the head was when it began.

Formatting track 0 side 0, 20 ms/div. The gate is low for 165.95 ms, longer than one 152 ms revolution, so the tail lands on the start of the track.
Formatting track 0 side 0, 20 ms/div. The gate is low for 165.95 ms, longer than one 152 ms revolution, so the tail lands on the start of the track.

Reads went quiet as soon as I clipped the probes on

Right after the probes went on, every read failed. RD sat at about 0.4 V with no flux on either head and either disk, while status, tach and stepping kept working. A cold reboot didn’t fix it. It was the M3 problem again: CN104 pin 11 read 4.6 V with the motor running, and the ERS minimum is 4.75 V. I swapped the +5V jumper for solid-core wire and turned the supply up to 5.55 V to get 4.94 V at the pin. That’s 0.6 V lost in the bench wiring, so the real fix is still owed.

If your Sony 800K mechanism answers status but RD is flat, meter +5V at the connector with the motor spinning before you look at anything else.

Also worth writing down: CN104 pins 13, 15, 17 and 19 are +12 V, and RD (16) and WRTDATA (18) sit right between them. Ground is 1, 3, 5 and 7. Probes go on with the drive powered off from now on.

Format burned all 10 tries without writing

The first format 0 0 after starting the server came back failed in 0.7 s, and the scope never saw the gate move. Seeking to track 0 from an unknown position recalibrates, finds it’s already on the right track, and returned before the drive said READY. The format loop then saw not-ready on every try. Now the seek waits for READY after a recal too. After a reflash it formatted cold on the first try, and then the whole disk with no retries.

Writing a whole disk is slow

writedisk takes about 14 minutes, one block every half second or so. Each block waits for its header, writes for 12 ms, and then waits a full revolution for the same sector to come back around so it can be verified. The rest looks like the Python tool polling the serial port with 0.2 s reads. The original ROM doesn’t verify writes at all, so that’s a decision for when the Apple is the one asking.

Still open