Monday, 21 October 2013

Using the Raspberry Pi to Read Floppy Disks

Reversing the Process to Read TRS-80 Floppy Disks

The Catweasel is an add-on card for the PC which allows reading TRS-80 floppy disks. It works by emulating a floppy disk controller using a combination of hardware and software. At the very start of the current project I believed that similar functionality would be possible by reversing the input and output signals and connecting a TRS-80 floppy drive to the interface board. Just recently I have succeeded in doing this

Interface Card

This picture of the device shows the interface board on the left and the floppy drive connector on the right. The interface board plugs into the top of the Raspberry Pi and the floppy card edge connector plugs into the TRS-80 floppy disk drive. The logic analyzer plug is for testing and development only and is not required for operation.

Raspberry Pi

The Raspberry Pi is pictured to the left. The Pi contains connectors for a keyboard, mouse, monitor and network. The operating system on the SD card is Raspbian which is based on Debian Linux.

The interface board sits on top of the Pi during use. It is about the same size as the Raspberry Pi. No PC or Mac is required as this is a complete standalone computer system.

Complete Device

The complete device is shown to the left plugged into the Raspberry Pi and with the floppy cable plugged into an old TRS-80 floppy disk drive.

Technical Details

I used the same pins as in the original device but rewired so inputs become outputs and vice versa with one exception. The original card connected the Raspberry Pi SPI output pin to the expansion interface floppy data input line. This project needs to connect the Raspberry Pi SPI input pin (GPIO 9 - MISO) to floppy disk cable pin 30 to read floppy disk data into the Pi. To write data to the floppy disk you could connect SPI output pin (GPIO 10 - MOSI) to floppy disk cable 22 (WRITE GATE signal would also have to be connected).

I found during testing that enabling the internal pull-up resistor for GPIO 9 had no effect when SPI mode was enabled. An external 10k pull-up resistor solved the problem. Another minor issue is that, using the current pin connections, the floppy disk drive motor spins and the head is loaded during the Raspberry Pi boot since those pins seem to be output high during the boot process. I suspect that selecting different pins will solve that problem. In the meantime I use the wiringPi gpio utility during boot to set the desired pin configuration and I/O direction. (Note: solved with the use of pull-down resistors.)

Software

The initial version was written under Raspbian for the Pi and used both the WiringPi and the bcm2835 low level library. I had hoped to using WiringPi exclusively but the current state of the driver is insufficient for my needs. Reading from the SPI using WiringPi leaves gaps in the data and the methods to wait for edge detect are very slow and end up returning far too late to be useful. However, a lot of work is being done by various people to implement DMA for SPI in Raspbian and I hope eventually to make use of this work when it shows up in the standard releases.

The software initializes the Pi GPIO pins and SPI interface then sets the correct output values to step the read/write head to the desired track. Once at the desired track it starts a high-priority thread which waits for the index signal and then reads an entire track of data in a single pass. It then processes the data and writes it to the DMK file format before stepping to the next track. A single-density 35 track floppy disk can be read in under 20 seconds using the initial version of the software.

The software itself is essentially the Tim Mann cw2dmk utility rewritten to handle the input data after it has been tweaked to generate clock and data bits. In the absence of DMA support I use a data rate of approximately 3 MHZ which is sufficient for single density but would not handle double density.

Signal Details

This picture shows the raw data coming from the drive at the top and the SPI clock at the bottom. As you can see, the SPI clock is not synchronized with the data coming from the drive. This is to be expected since there is no mechanism to cause synchronization and the SPI clock divider is not granular enough to allow a perfect match. In any case, it doesn't cause a problem. The main concern is to use a SPI clock rate fast enough to avoid missing clock or data pulses that extend into the 'dead zone' between SPI bytes. The SPI interface will not see pulses that fall inside the gap between bytes so I increase the clock rate to a little over 3 MHZ and I find that a single clock or data bit from the disk drive is received as 2-3 bits through the SPI interface. Worst case, if a clock or data bit exactly straddles the gap between bytes I would expect to see a single bit set in the output. The software counts the number of zero bits between the ones and, if the number of zero bits is greater than 16 it counts it as a zero, otherwise it counts it as a one.

Because I am polling for the index signal in software there is a 10 microsecond gap between the start of the index signal and the start of data. This represents less than three clock/data pairs so is unlikely to cause problems.

I have successfully read actual floppy boot disks into the Pi and used them in the TRS-80 emulator from www.trs-80emulators.com. While I was able to read some copy-protected disks into the Pi, not all of them worked correctly in the emulator. I believe this is because the cw2dmk utility was designed to make copies of unprotected disks and, by default, ignores misplaced address marks and other deliberate errors on copy protected disks.

I have not tried to write back to a floppy disk but it should be easy to do so.