Arduino Mega2560 floppy drive controller

In other words, finding a more creative use for the Arduino Mega than a neon clock: to be able to read all sorts of old data storage media and send’em over USB, blending old technology with the new.
Originally inspired by the ArduinoFDC project, I have decided to try a different approach: instead of using the Arduino to talk to a floppy drive directly, why not leave the hard work on a chip that can be salvaged from an old PC?

A Seagate SCSI hard disk drive card with a DP8473V-based floppy controller.
The same controller can be found on certain Adaptec cards, too.

And I surely learned a thing or two during the process ๐Ÿ™‚
I did originally try out ArduinoFDC on a Uno board, and it worked just fine with a 3.5″ drive, but encountered timing/CRC errors and reliability issues trying to work with older, 5 1/4″ media, especially during experiments with the IBM 5150 or PCjr – and it can be a pain trying to transfer old floppies with these old machines.
So instead of having an Arduino bit-banging the I/O pins of an old drive directly, Iย  made a prototype board with a proper, PC-compatible FDC such as the DP8473 pictured above, wired to a Mega2560. With this setup, the Arduino board acts as an interface to the FDC – with a keyboard and display, basic disk operations and commands can be launched standalone, without needing a computer or terminal connected. Having a dedicated FDC chip with its own PLL and data discriminator, the reliability of disk transfers increased dramatically whilst the circuit is still kept simple – by itself, it is just a datasheet “typical application” of the controller, just with its address lines wired to the Arduino. In addition, custom disk geometries can be defined and stored to the EEPROM to auto-load them upon startup – up to 4 drives are supported on one controller – and I have also added some experimental 8″ filesystem support to work with SSSD CP/M disks.
With the increased RAM capabilities of the Mega compared to the Uno (8K vs 2K), multi-sector operations can be done in one go. The RAM is still not enough to load whole tracks at once, but with a 3K disk buffer I have managed to cut down time required to image a 1.44MB disk from 10 minutes (with ArduinoFDC doing single sector operations) to around 3 minutes 40 seconds.

Standalone setup with two drives (PSU not pictured)
Of course the circuit will work just fine without the keyboard and display, over the serial interface

This circuit will work with any PC compatible FDC, as the communication protocol between the Arduino and FDC is NEC uPD765 software compatible. A DP8473V was chosen by me just because I had a couple of these chips in my spare parts collection (as I had an Adaptec ISA card with a non-functioning one, ready to be switched). In addition, these chips were found for cheap on a certain “Far Eastern” website and are most likely to be counterfeit – nevertheless, they work fine on all the 8-inch, 5 1/4 inch and 3 1/2 inch drives I have lying around ๐Ÿ™‚

I think I should have went with a green backlit display, this looks like a BSoD ๐Ÿ™‚
The LCD was from a “RepRapDiscount Full Graphic Smart Controller” interface from a former 3D printer setup, others will work fine using Oli Kraus’ u8g2 library

Inside the source code, or the config header to be precise, the optional accessories (display, keyboard, configuration switches etc) can be configured to use a different pinout on the Mega2560 board. The only interface whose pins can not be configured, is the FDC itself – this is because working with the address lines is time sensitive, there’s no DMA in the Arduino to handle the data transfer as soon as it is ready, and the wiring order of all 8 bits of data lines must correspond to bits of one single AVR port access, using direct port manipulation. A “nice” example of this is an ISR written in “naked assembly” to support a 1Mbps data rate for 2.88MB drives – it needs to service the data interrupt within six microseconds, or else it fails with data overrun errors. (For an illustration, the Arduino overhead to enter an ISR written in C, takes just that before executing the actual code.)

Schematic of the whole setup for all supported data rates using a DP8473 FDC.
Others (with 8 data and 3 address lines) can be used too, e.g. the Intelย  82077AA etc.

The 2nd pinheader for drives 3 and 4 and the optional modules at the bottom (configuration switches, RS-232 nullmodem interface, PS/2 keyboard input and display), these are all optional.
Code available on my GitHub repository
.

As mentioned above, the circuit can communicate via display and keyboard, utilizing the serial interface only to send over disk images or files from the floppy, or via the serial interface exclusively, i.e. including the command prompt and setup. This can be done either through the USB port of the Mega2560, or through a simple level shifter with a null-modem serial cable: this option will not trigger a reset once the serial connection has been established.

Directory listing on a blue screen 128×64 display:
left: FAT-formatted disk, right: 250K 8″ CP/M floppy (FM encoding)

During boot, the controller is initialized to check if it responds to a Reset/Sense interrupt command, and after successful completion, up to 4 drives can be configured either in the “simple” mode (using predefined disk media geometries), or in the “advanced” mode, where the setup will ask for all supported parameters. Optional CP/M filesystem support is turned on if selecting an 8″ drive with a 26x128byte geometry; FAT12 filesystem support can be turned on if using 512 bytes per sector – it is on by default in all predefined geometries. As of now, simple read and write of files, and directory traversal, is possible on FAT, utilizing Elm-Chan’s FATFS library, and my own simple CP/M implementation to read and erase files off an 8″, 250K floppy.

Going through a few basic commands on a FAT-formatted floppy

The supported commands are quite “DOS-like” and self explanatory – HELP is used to invoke and give short details of each supported command. RESET can be used to reset and reconfigure settings of a particular drive – or the whole board, reinvoking setup for all.
DRIVPARM shows drive and disk media parameters of chosen drive; PERSIST makes them persistent into the EEPROM so they can be loaded upon boot-up without reconfiguring.
FORMAT and VERIFY do what they are told, according to the currently configured disk geometry. IMAGE is used to create a disk image that can be sent over USB or serial link via XMODEM, or vice versa – written to the floppy using currently set disk geometry. XMODEM-1K packets are used where available, and if enabled with Yes.
During IMAGE transfer, any potential bad sectors are filled with zeros and the operation is continued whenever possible – an improvement over the original ArduinoFDC.

Advanced setup ofย  drive A:
Up to 4 drives can be configured, if connected.

If filesystem support is turned on, QFORMAT can be used to “quick format” – recreate the root directory in a FAT or a CP/M filesystem (the disk must be formatted before). DIR will display the contents of a specified directory (or of the current working directory). TYPE types out text contents of a file, DEL erases a file, XFER performs single-file transfer over the serial link, either read or write (as opposed to IMAGE, which works on the whole disk).
On FAT12, CD can be used to nest into subdirectories, or to show the current working directory; absolute paths in command line arguments are not supported due to memory constraints. MD and RD are equivalents of MKDIR and RMDIR. PROMPTPATH is used to either display drive letter only in the prompt (for small displays), or the whole path by default. Finally, TYPEINTO creates a simple text file from the keyboard input.

Making the prototype board

Even though there’s multi drive support, and certain commands can work with differently configured drives (e.g. RESET B:, DRIVPARM C:, FORMAT D: etc), due to tight memory constraints of an Arduino, all of the file commands work in the current drive/current working directory only, and there are no advanced commands such as COPY, MOVE, DELTREE, or support for wildcards in names. As an example, to copy a file from A:\DOS\AUTOEXEC.BAT to drive B:, the XFER AUTOEXEC.BAT command is invoked first to transfer the file over serial link, then the drive is switched to B: and XFER AUTOEXEC.BAT is called again, this time to receive and write it to disk. Gimme more than 8K of RAM and I’ll do stuff. ๐Ÿ™‚

It wouldn’t be a prototype if there was not some kind of patching involved

And that’s about the size of it – a portable floppy controller in a box, with some basic and some advanced functionality that allow you to pop a 3, 5 or 8 inch drive through USB and have both read and write support on a today’s machine. Yes, it’s not one thing fits all and there are limitations, just as with anything in life. ๐Ÿ™‚

The following disk drives, media and geometries were tested to work with this setup, read and write:
8″, FM, 250K (77x26x128B), single sided, CP/M 2.2 filesystem; 250K data rate, 500K transfer rate;
the following 8 inchers are hangovers from 8FORMAT experiments ๐Ÿ™‚
8″, MFM, 77x9x512B, one and two sides, FAT12;
8″, MFM, 1.2M (77x16x512B), FAT12;
5.25″, 160K, 180K (8spt, 9spt single sided), 320K, 360K (8spt, 9spt double sided), 1.2M, FAT12 each,
5.25″ double-density media in a high density drive (300K data rate),
3.5″ 720K and 1.44MB (9 and 18spt double sided).
I do not have any 3.5″ 2.88MB drives and media to test, but the ISR written in ASM should be fast enough to support the 1 Mbit/s data rate. At least there was a difference when compiled with the single FDCxxx() interrupt handlers, which were slow enough to give Data Overrun errors when the 1Mbps rate was used with a 1.44MB drive config. However, with the ASM ISR compiled, this changed to consistent “No address mark” on 1.44MB media – which makes perfect sense as these disks cannot be formatted such way.

Example interface with 8″, 5.25″ and 3.5″ drives with serial data transfer

Leave a Reply

Your email address will not be published. Required fields are marked *