ArduinoFDC
Library for using an Arduino as a floppy disk controller
Install / Use
/learn @dhansel/ArduinoFDCREADME
ArduinoFDC

ArduinoFDC is a sketch that implements a floppy disk controller. It works with Arduino Uno, Leonardo, Nano, Pro Mini, Micro and Mega.
ArduinoFDC consists of three parts:
- A library providing low-level functions to allow reading and writing disks at the sector level as well as low-level formatting disks.
- Integration of ChaN's brilliant FatFS library to provide file-level functions for reading and writing files and directories in a FAT (MS-DOS) file system and a high-level format function to initialize a FAT file system.
- An example sketch implementing ArduDOS, a (very) small DOS environment for browsing a FAT file system as well as a low-level disk monitor to access sector data on the disk, including the ability to transfer whole disks or single files via the XModem protocol.
ArduinoFDC works with double density (DD) as well as high density (HD) disk drives. It can read, write and format 5.25" DD (360KB), 5.25" HD (1.2MB), 3.5" DD (720KB) and 3.5" HD (1.44MB) disks.
Wiring
If you don't want to wire your disk drive up yourself then you can use a shield for Arduino Uno or Mega. See the ArduinoFDC shields section below. The shield plugs into the Arduino and provides a standard 34-pin floppy disk connector.
The table below shows how to wire the Arduino pins to the 34-pin IDC connector on the floppy drive cable.
The pin numbers are defined at the top of the ArduinoFDC.cpp file. Some of them can easily be changed whereas others are hard-coded in the controller code. Refer to the comments at the top of the ArduinoFDC.cpp file if you want to use different pin assignments.
Floppy Cable | Uno/Mini/Nano | Leonardo/Micro | Mega | Notes | Function -----------------|---------------|-----------------|--------|--------|--------------- 2 | 13 | 13/16 | 42 | 3,4,5 | Density select 8 | 7 | 8 | 47 | | Index 10 | 4 | 5 | 51 | 1,3 | Motor Enable A 12 | A1 | A1 | 40 | 1,3,4 | Drive Select B 14 | 5 | 6 | 50 | 1,3 | Drive Select A 16 | A0 | A0 | 41 | 1,3,4 | Motor Enable B 18 | 3 | 3 | 52 | 3 | Head Step Direction 20 | 2 | 2 | 53 | 3 | Head Step Pulse 22 | 9 | 9 | 46 | | Write Data 24 | 10 | 10 | 45 | | Write Gate 26 | 11 | 11/14 | 44 | 3 | Track 0 28 | 12 | 12/15 | 43 | 3,4 | Write Protect 30 | 8 | 4 | 48 | 2 | Read Data 32 | 6 | 7 | 49 | 3 | Side Select 34 | A2 | A2 | 39 | 3,4 | Disk Changed 1,3,5,...,31,33 | GND | GND | GND | 6 | Signal Ground
Note 1: The pin numbers for the SELECT/MOTOR signals assume you are wiring to the controller end of a floppy drive cable. If you are wiring directly to the floppy drive, the A/B pins will be reversed (search the web for "Floppy drive twist" for more information).
Note 2: It is highly recommended (but not entirely necessary) to add a 1k pull-up resistor to +5V to this signal. The Arduino's built-in pull-up resistors are very weak (20-50k) and may not pull the signal up quickly enough. Without the resistor you may encounter read errors (bad CRC, header not found), especially when reading HD disks. Whether it works without the resistor will depend on your specific drive, drive cable, connections and Arduino.
Note 3:
This signal can easily be moved to a different pin on the Arduino by
changing the corresponding #define PIN_XXX ... statement at the top
of ArduinoFDC.cpp
Note 4:
This signal is not essential for the functionality of the controller.
The corresponding pin can be freed by commenting out the #define PIN_XXX ...
statement at the top of ArduinoFDC.cpp
Note 5: See section "DENSITY control signal" below.
Note 6: You should be able to just pick one of the GND pins. However, some cables/drives do not actually connect all of these to ground. If your setup does not work it may be worth trying a different GND pin.
Powering the drive
In addition to the signal wiring, the floppy drive needs to be powered. 5.25" drives typically use a Molex connector while 3.5" drives usually use a Berg connector.
In my setup I used the power supply of an external hard drive adapter (something like this), which has a Molex connector, with an adapter to the 3.5" drive Berg connector.
Since most (all?) 3.5" drives do not use the 12V power line, it is possible to power such drives directly from the Arduio. Connect the 5V and GND pins from the Arduino to the 5V and GND pins on the floppy power connector. I have done that before but did run into issues when using cheap cables to connect the Arduino to the PC. What happened was that the USB cable was unable to support the power needed for the Arduino and floppy drive. This resulted in a voltage drop over the USB cable that caused the drive to not work properly.
I would generally recommend using a separate power supply for the drive.
Supported disk/drive types
To properly read/write data, the library must be configured for the drive/disk
combination that is being used. The drive type can be passed into the begin functions
or set afterwards by calling the setDriveType function. Supported types are:
- ArduinoFDC::DT_5_DD: Double-density disk in a 5.25" double-density drive
- ArduinoFDC::DT_5_DDonHD: Double-density disk in a 5.25" high-density drive
- ArduinoFDC::DT_5_HD: High-density disk in a 5.25" high-density drive
- ArduinoFDC::DT_3_DD: Double-density disk in a 3.5" double- or high-density drive
- ArduinoFDC::DT_3_HD: High-density disk in a 3.5" high-density drive
DENSITY control signal
The function of the DENSITY control signal line between the controller and the floppy drive is not well defined and varies between drives. Furthermore most drives can be configured by jumpers (also called "straps"). You may want to consult the documentation for your drive for details.
In their default configuration most 3.5" drives do not use this signal. The drive itself determines the type of disk (DD or HD) by the presence of a hole in the disk (on the opposite edge from the "write protect" hole). The controller must be configured separately for the correct type (DD or HD), otherwise reading/writing will fail.
For 5.25" HD drives this signal is generally an input from the controller to the drive. If the signal is LOW then low density mode is selected, otherwise high density is used. However, for some drives the opposite is true. Many drives can be configured via jumpers to select the expected levals.
The controller can be configured what to do with this signal by calling the "setDensityPinMode" function. The following modes are supported:
- ArduinoFDC::DP_DISCONNECT: This configures the DENSITY pin as INPUT. It does not actually read the pin.
- ArduinoFDC::DP_OUTPUT_LOW_FOR_HD: This configures the DENSITY pin as an OUTPUT and sets it LOW if the disk type is HD.
- ArduinoFDC::DP_OUTPUT_LOW_FOR_DD: This configures the DENSITY pin as an OUTPUT and sets it LOW if the disk type is DD.
By default, the mode is set to DP_DISCONNECT for 3.5" drives and DP_OUTPUT_LOW_FOR_DD for 5.25" drives.
Another way to handle the DENSITY signal is to comment out the #define PIN_DENSITY line
at the top of ArduinoFDC.cpp and hard-wire the DENSITY signal from the disk drive cable
to the proper level (or leave it disconnected).
Library functions:
To use the low-level disk access library functions (listed below), copy ArduinoFDC.h and ArduinoFDC.cpp
into your Arduino sketch directory and add #include "ArduinoFDC.h" to your sketch.
To use the FAT file system functions, additionally copy ff.h, ff.c, ffconf.h, diskio.h and diskio.cpp.
Then add #include "ff.h" and #include "ArduinoFDC.h" to your sketch. For documentation of the FatFS
functions refer to the FatFS documentation.
void ArduinoFDC.begin(driveAtype, driveBtype)
Initializes the Arduino pins used by the controller. For possible drive types see the "Supported disk/drive types" section above. If left out both types default to ArduinoFDC::DT_3_HD.
void ArduinoFDC.end()
Releases the pins initialized by ArduinoFDC.begin()
bool ArduinoFDC.selectDrive(byte drive)
Selects drive A (0) or B (1) to be used for subsequent calls to
readSector/writeSector/formatDisk. Calling begin() selects drive A.
Returns 'false' if trying to select drive 1 when the corresponding control
pins are commented out in ArduinoFDC.cpp
byte ArduinoFDC.selectedDrive()
Returns which drive is currently selected, A (0) or B (1).
void ArduinoFDC.setDriveType(driveType)
Sets the disk/drive type for the currently selected drive. For possible drive types see the "Supported disk/drive types" section above.
byte ArduinoFDC.getDriveType(driveType)
Returns the drive type of the currently selected drive.
void ArduinoFDC.setDensityPinMode(mode)
Sets the function of the DENSITY
