M2-M3: the whole disk, once 5V got there

/ UniDisk 3.5 controller / updated 2026-10-10 m2 m3 rp2350 sony-800k gcr flux pio power

The board reads a whole disk now. a2mflux.py disk captures all 160 track sides through the Pico’s PIO, decodes them on the Mac, and writes an 800K image. On both mechanisms it came back 1600 of 1600 blocks, byte-identical to the image I wrote to the floppy, with no retries, in a bit over 2 minutes.

1600/1600 blocks good -> ../docs/private/ref/read_800k_driveA.po
compare vs /Applications/ADTPro-v.r.m/disks/REF800K.po: 0 blocks differ []

Getting there took most of the afternoon, and almost none of it was the code.

The read chain looked dead and wasn’t

The first flux capture came back empty: FLUX BEGIN 0, valid CRC, no transitions in a 2 second window. Status bits, tach, stepping and eject all still worked. On the scope, RD with the read-data address selected sat flat at about 0.4 V, at our connector and at the mechanism’s own test point.

RD at the mechanism's own test point with the motor at speed and head 0 selected, 5 us/div. Flat at about 0.4 V. This is what a sagging +5V rail looks like from the read side.
RD at the mechanism’s own test point with the motor at speed and head 0 selected, 5 us/div. Flat at about 0.4 V. This is what a sagging +5V rail looks like from the read side.

I went after the mechanism. Reseating the head flex got drive A from nothing to patchy reads: a clean track here and there, the top head never. Cleaning the heads didn’t help. I swapped in drive B and it read nothing at all, which is what finally made me stop blaming mechanisms. Two drives failing the same way pointed at something they shared.

What they shared was the bench supply wiring. With the motor running, the drive’s +5V pin measured 4.01 V and +12V measured 11.57 V. The ERS floor is 4.75 V. The supply was in CV and drawing well under half an amp, so this was IR drop through banana posts, breadboard rails and jumpers. Turning either channel on or off moved the other one, because both returns shared the same bad ground path. After reworking the contacts and adding the IF-83’s 4.7 uF 50 V bulk caps at the connector tap, both drives read every sector.

If your Sony 800K mechanism answers status reads, spins, steps and ejects but RD stays flat on the read-data address, meter +5V at the drive connector with the motor running before you touch the heads. The logic keeps working down around 4 V. The read amplifier doesn’t.

Along the way I ruled out write mode (tab protected, and an ADTPro readback of the disk was byte-identical, so nothing got erased), head position, lifted heads and the disk itself.

What a good read looks like

The histogram of one track once the power was right. Three peaks at 1, 2 and 3 bit cells of 2.04 us:

  2.0 us   22147 ############################################################
  2.1 us   14876 ########################################
  2.2 us   17083 ##############################################
  3.9 us    9868 ##########################
  4.0 us   13280 ###################################
  5.9 us    3218 ########
  6.0 us    5928 ################

The 2-cell peak sits at 4.0 us because of a fix the final code review asked for: the PIO loop leaves 4 cycles per interval uncounted, not 3, so the host adds back 2 counts instead of 1.5. probe tried all 36 byte orders for the GCR groups and checksum and the default one won, so nothing in the decoder had to change for real media.

Scan, tracks 0/5/20/40/60/79 both sidesResult
Drive A, before the power fix11 sectors decoded, side 1 never
Drive B, before the power fix0 intervals on every track
Drive B, contacts reworked124/124 sectors, all match the image
Drive A, with bulk caps124/124 sectors, all match the image

Every sector that decoded all day matched the reference byte for byte, including the patchy ones. The firmware was never the problem.

The reference disk

REF800K is an AppleCommander image filled with six 120K files of seeded random data, written to a real floppy with ADTPro on the working UniDisk. 1453 of the 1600 blocks are unique, so a block read from the wrong track or side can’t match by accident.

M2: motor, zones and a greased eject

Earlier in the day M2 got the mechanism moving. All five speed zones came in within half a percent of the ERS.

TrackrpmERS
0392394
16428429
32472472
48524525
64588590
/TACH on RD at track 0, 2 ms/div. The scope measures 392.9 Hz at 48.9 % duty, which is 392.9 rpm at 60 pulses per revolution. The firmware's tach count said 392.
/TACH on RD at track 0, 2 ms/div. The scope measures 392.9 Hz at 48.9 % duty, which is 392.9 rpm at 60 pulses per revolution. The firmware’s tach count said 392.

A full 79-track seek takes about half a second. Eject did nothing at first. The drive took the command, its EJECT status bit went high for the 2 second timeout and +12V drew 0.28 A, but the motor couldn’t turn the gear train. I tried holding the strobe for 500 ms on tashnotes’ advice before reading the ERS properly: its limit is 300 ms, and the ROM’s short strobe was fine all along. Cleaning the old grease out of drive A’s eject gears got it working. 18 ejects in a row fired, though it still sometimes stops short of fully out.

Still open