Overview
Relive the days when storage was counted out in kilobytes, not gigabytes, using the Adafruit Floppy FeatherWing on a Feather board. This is perfect for interfacing with 34-Pin IDC Connector floppy drives that were ubiquitous on PC's. This 'Wing has level shifting and a ready-to-plug connector that works with 3.5" or 5.25" floppy disks for reading or writing!
Floppy disks have an interesting data transfer method where raw bit transitions are measured and converted to data. This data streams pretty fast from the disk drive, so you'll want to use a fast microcontroller that has large SRAM storage and ideally, a peripheral to DMA the data signal. For that reason, we only have this FeatherWing working with the Feather M4 or Feather RP2040. ESP32, ATmega, nRF52, etc have not been ported to our support library!
Floppy disk drives require 5V power and logic. For the logic level shifting, we have a small boost converter on the 'Wing that will give 5V logic levels out the 34-pin connector. It will also shift the incoming signals down to a Feather-safe 3.3V.
For floppy drive powering you will likely need a separate external 5V power supply that can provide 5V at 2 A. You can't power most drives off of USB power, they have big motors that require more current than USB can provide!
There is code and there are examples for three use cases:
- Reading floppy disks and storing the raw bit patterns and/or converted data format for data archiving. For this use case we recommend using the 'Wing with a Feather programmed to act as a greaseweazle or fluxengine client device. Then run those command line programs on your computer to have the Feather send the raw track data to the computer for analysis, bit-repair and format interpretation. You can also write some formats via those two programs, for use with older computers. There is a 'Write Disable' switch on the board specifically for this use case so that it is not possible for the write-enable pin to accidentally be activated.
- Reading/Writing FAT formatted floppy disks from Arduino, CircuitPython or a computer that is connected via USB. Floppy disks can still be used to save, read data from! This is great for retro-themed projects or if you want to write data to floppy disks for them to be used by IBM PC compatibles or other devices that are expecting FAT-formatted floppy disks
- Cool floppy music sequencing!
Each order comes with one FeatherWing with the 2x17 header attached and level shifting circuitry built in. Before it can be used to read/write floppies, you will need to:
- Solder pin headers on to attach to a Feather board.Â
- Attach an M4 or RP2040 Feather as the driver/brains.
- Find a 34-pin IDC Floppy Drive that works
- Connect a 34-pin DC cable between the 'Wing and the Floppy drive.
- Provide 5VÂ power to the floppy drive, as much as 2 Amps. 5.25" disk drives will also need a 12V power supply!
- Find some floppy disks to read/write
Many of these items are no longer sold, and will require some sleuthing to locate!
Compatible power supplies can be bought inexpensively as part of a "USB to IDE" kit. See this one as an example, they can be found at many retailers for reasonable prices.
Optional for 5.25" floppies:
Page last edited March 08, 2024
Text editor powered by tinymce.
Pinouts
The Adafruit Floppy Featherwing is intended for use with the Feather RP2040 or Feather M4. Note that most of the views below show the bottom side of the FeatherWing. A bunch of pins are required, but note that the standard I2C and SPI pins are left free so you'll be able to incorporate displays or sensors into your project if needed!
To keep easy access to the RP2040's BOOT button consider putting this FeatherWing side by side with the Feather RP2040 on a Feather Doubler, Tripler, or Quadrupler.
The Adafruit 34-pin rainbow ribbon connector is polarized, so insert it noting the location of the "key" and aligning it with the notch on the Floppy FeatherWing. The brown wire is pin 1, and the other pins can be "counted off" according to the standard resistor code: red is 2, orange is 3, and so on; black is 10, and then the next brown is 11. This makes last wire yellow, because there are 34 wires in all.
Then, do the same at the drive. However, note that some drives lack a keying notch; and others have a notch but it does not match modern convention! (the author's own Sony MFP520-1 with 9411 date code is such a drive) In the case that the drive's polarization notch is missing or incorrectly positioned, you may have to carefully use a tool to shave off the polarizing tab from the cable, or find an alternate non-polarized cable.
Therefore, it's important to check whether the cable is installed correctly before applying any power. Use a multimeter in continuity mode to check that GND on the floppy drive is connected to GND on the FeatherWing.
Only once everything else is connected should you provide power to the floppy drive on its dedicated +5/+12V power connector. Remember that floppies were not designed for hot-plugging of their power or data connections.
CH: Media change. When HIGH, the drive indicates a media change operation is in progress. When LOW a media change operation is not in progress. This is connected to D5 on the common Feather pinout, and pin 34 of the IDC connector. This pin is also known as "media ready". Based on some floppy drives your author tested, this signal is not particularly useful but is included for the sake of completeness.
RD: Read Data. Alternates between HIGH and LOW according to the flux stored on the floppy disk. The specific interpretation of the pulses depends on the floppy disk format. This is connected to D9 on the common Feather pinout.
Trk: Track 0 (home) sense. Pulled LOW when the disk head is moved to the "track zero", or home position. HIGH when not at the home position. This is connected to D10 on the common Feather pinout, and pin 26 on the IDC connector.
Pr: Write Protect Sense. Pulled LOW when the disk is write protected (e.g., by the sliding tab on a 3.5" floppy disk). HIGH when the disk is not write protected. This is connected to D11 on the common Feather pinout, and pin 28 on the IDC connector.
Idx: Gives a LOW pulse once per revolution of the floppy (or, for the unusual "hard sectored" floppy, once for each sector mark). Connected to A5 (aka D25) on the common Feather pinout, and pin 8 on the IDC connector.
Outputs (to floppy drive)
All outputs include a pull-up resistor and 5V level shifter. They may be driven as open collector pins or as push-pull pins.
Sel: Select signal. When LOW, "selects" (activates) the floppy disk. Connected to A0 on the common Feather pinout and pin 12 ("Select1") on the IDC connector.
En: Enable signal. When LOW enables the selected floppy drive spindle motor. Connected to pin A2 on the common Feather pinout and pin 16 on the IDC connector.
Pulling these two pins LOW together selects a drive connected with a straight-through cable, or to the un-twisted portion of a multi-drive connector.
There is no connection for the Select0/2/3 pins of the IDC connector. Consequently, it's only possible to select a drive on the un-twisted part of the cable. So if you have an old floppy drive cable, make sure you plug the floppy drive into the correct position.
Dir: Direction. Selects whether a step pulse moves inward to a smaller track number (LOW) or outward to a higher track number (HIGH). Connected to pin A3 on the standard Feather pinout and pin 20 on the IDC connector.
Stp: Step. Each LOW going pulse moves one step. Depending on the drive & format, more than one step may be required in order to move by one full track.
Sid: Side select. HIGH to select "Side 0" of the floppy, LOW to select "Side 1". Connected to D6 on the common Feather pinout and pin 32 of the IDC connector.
Den: Density selection. Some drives use this pin to select whether to write at "high density" (pin pulled LOW) or "double density" (pin pulled HIGH). Connected to A1 on the common Feather pinout and pin 2 of the IDC connector.
Write Enable: Depending on its position, this switch either isolates (NoWr) or connects (WrOK) the WG signal from the microcontroller to the floppy drive.
WG: Write Gate. When pulled LOW, puts the drive in writing mode. If the Write Enable switch is in the position labeled NoWr then this is physically disconnected from the microcontroller and it is not possible to write to a floppy (or, with buggy code, to accidentally erase a floppy!) Connected to D12 on the common Feather pinout and pin 24 on the IDC connector.
WD: Write Data. When WG is pulled low (and the Write Enable switch is in the WrOK position and the inserted disk is not write protected), data on this pin is written to the disk. The specific encoding of the data on this pin depends on the floppy format being written. Connected to D13 on the common feather pinout and pin 22 on the IDC connector.
The screw terminal is connected to the Feather's USB5V line and to GND. Depending on the USB power supply to the Feather, this can be used to power some low-power laptop floppy disk drives, but should not be used to power desktop floppy drives.
Dealing with Backpowering
On some setups, there may be an issue related to backpowering from the floppy power source into the host Feather board. This currently has only been observed to affect the Feather RP2040. See related forum thread here:
When this happens, there is a potential for the Feather RP2040 to get stuck in bootloader mode, with the RPI-RP2 folder showing up. If this happens, press the reset button on the Feather RP2040 once everything is powered.
Page last edited March 08, 2024
Text editor powered by tinymce.
Archiving Floppies with GreaseWeazle Compatible Firmware
Adafruit provides a GreaseWeazle compatible firmware for the Adafruit Floppy FeatherWing paired with the Adafruit Feather RP2040.
This firmware can be used together with GreaseWeazle or FluxEngine software on a host computer to archive the data from floppies onto a modern PC. They each have slightly different capabilities, so it's great that they both work with the same device firmware.
Upload the firmware to the Feather RP2040
Grab the latest release from GitHub. Pick the file named "feather_rp2040_tinyusb.zip" and unzip it.
Plug in the Feather and then place it in bootloader mode by holding the BOOT button and clicking RESET.
Drag the GreaseWeazle UF2 file to the RPI-RP2 volume. It will automatically restart with the new firmware.
Determine the serial port name
Depending on your operating system, the device will be assigned a serial port name. On Windows, a serial port name is a string like "COM6" or "COM33"; on Mac and Linux it's a string starting "/dev/". Check out this guide page for more info on finding the serial port name: "COM / Serial Port Name"
When you run FluxEngine or GreaseWeazle, you'll need to manually specify the serial port name.
Install & Use FluxEngine
Grab the appropriate installer (exe or pkg) from the releases page on GitHub.
After installing it, insert a floppy disk and close the door. In a terminal and run the FluxEngine command to check that everything's working (change COM6 to the serial device name that's right for your computer):
C:\fluxengine>fluxengine rpm --usb.greaseweazle.port=COM6 Using GreaseWeazle on serial port COM6 Rotational period is 198.445 ms (302.351 rpm)
FluxEngine supports a wide range of disk formats. Check out the official FluxEngine documentation for detailed information on how to use it. To whet your appetite, here's how to use FluxEngine to read the content of a 1.44MB 3.5" DOS/Windows disk to an image file:
C:\fluxengine> fluxengine read --usb.greaseweazle.port=COM6 ibm
Windows users can grab a compiled version from the releases page on GitHub. Others can install the source with the command pipx install git+https://github.com/keirf/greaseweazle or by cloning the git repo and running its make command.
After installing it, open a terminal and run the gw command to check that everything's working:
C:\greaseweazle>python3 gw info --device COM6 Host Tools: v0.34 Device: Port: COM6 Model: Adafruit Floppy Generic Firmware: v1.0 Serial: 2E1A9C125337543239202020FF0B160C USB Rate: Full Speed (12 Mbit/s)
GreaseWeazle also supports a wide range of formats. There's an official greaseweazle documentation wiki for more information on how to use it. To get you started, here's how to read the content of a 1.44MB 3.5" DOS/Windows disk to an image file (change COM6 to the serial device name that's right for your computer):
C:\greaseweazle> gw read --device COM6 --format ibm.1440 output.img
Page last edited March 08, 2024
Text editor powered by tinymce.
Examining IMG Files
Examining IMG files
Once you have imaged the IBM PC floppy, you can safely put it away and look at the data on the image you've made.
If you want a known-good FAT12 formatted IBM PC 1.44MB disk image to practice with, this zip download contains one image from fluxengine. Note you have to uncompress the zip and remove the image file within!
Windows
Even though IMG files are 'byte for byte' disk images, Windows doesn't have native ability to mount it as a floppy disk like CD-ROM ISOs. Not sure why, but that's how it is.
You can use https://www.7-zip.org/ instead, which happens to have support for FAT12 format images.
In the FluxEngine folder, right click on the img file created, select 7-Zip and Open archive (or you can Extract files...)
You can then interact with the files as you like:
Page last edited March 08, 2024
Text editor powered by tinymce.
USB Floppy Drive
Adafruit provides a USB Mass Storage Device firmware for the Adafruit Floppy FeatherWing paired with the Adafruit Feather RP2040.
With this firmware installed, you can directly read a DOS/Window (FAT)-formatted 1.44MB floppy disk on standard computers.
Under the covers, the RP2040 is reading the raw flux and performing MFM decoding before it sends the decoded data to your PC.
Upload the firmware to the Feather RP2040
Grab the latest release from GitHub (pick the file named "feather_rp2040_tinyusb.zip" and unzip it).
Plug in the Feather and then place it in bootloader mode by holding the BOOT button and clicking RESET.
Drag the msd_test uf2 file to the RPI-RP2 volume. It will automatically restart with the new firmware.
Use the USB Floppy Drive
Insert a floppy drive and then click the device's reset button. It will connect to your computer as a USB floppy disk. Note that the floppy disk is read-only, and only 1.44MB PC-format disks can be used.
Page last edited March 08, 2024
Text editor powered by tinymce.
Using Arduino adafruit_floppy
Adafruit has an Arduino library & example code ready to go with this FeatherWing. The library is optimized for the Adafruit Feather RP2040 microcontroller board.
This library needs to be installed using the Arduino Library Manager. From the Arduino “Sketch” menu, select “Include Library” then “Manage Libraries…”.
Type “floppy” in the search field to quickly find the library — Adafruit_Floppy:
If prompted to install additional libraries, say "yes"; Adafruit_Floppy relies on Adafruit BusIO and SdFat - Adafruit Fork.
You have to make specific selections in the Tools menu:
- Board: "Adafruit Feather RP2040"
- CPU Speed: "200 MHz (Overclock)"
- Optimize: "Optimize Even More (-O3)"
- USB Stack: "Adafruit TinyUSB"
After restarting the Arduino software, you should see a new example folder called Adafruit_Floppy, and inside, an example called floppy_capture_track_test. Upload the sketch to your Arduino and open the serial monitor. Place a disk in your floppy drive, and reset the board. Your floppy should "spin up" and you should see information about the flux data on your floppy's "track zero". For a formatted floppy, the "flux bins" (a histogram of times between adacent flux transitions) should cluster preferentially into 3 to 4 different groups of values with large gaps between them. For example, here's the frequency information from an MFM-formatted (DOS) floppy. The peaks correspond to 4, 6, and 8µs, or 96, 144, and 192 counts at 24MHz:
[12:22:39] its time for a nice floppy transfer! [12:22:39] Sample freqency 24.00MHz [12:22:40] Waiting for index pulse...Found! [12:22:40] Seeking track...Going to track 0 [12:22:40] Going to track 0 [12:22:40] done! [12:22:40] Captured 45282 flux transitions [12:22:40] ------- [12:22:40] 93: 130 [12:22:40] 94: 1460 [12:22:40] 95: 6257 [12:22:40] 96: 13469 [12:22:40] 97: 10962 [12:22:40] 98: 3345 [12:22:40] 99: 836 [12:22:40] 100: 302 [12:22:40] ------- [12:22:40] 139: 122 [12:22:40] 140: 273 [12:22:40] 141: 464 [12:22:40] 142: 848 [12:22:40] 143: 1083 [12:22:40] 144: 1258 [12:22:40] 145: 1265 [12:22:40] 146: 1098 [12:22:40] 147: 700 [12:22:40] 148: 296 [12:22:40] ------- [12:22:40] 192: 115 [12:22:40] 193: 122 [12:22:40] 194: 142 [12:22:40] 195: 111 [12:22:40] 196: 111 [12:22:40] Ready? No [12:22:40] Write Protected? Yes [12:22:40] Track 0? Yes
Because the floppy is inherently an analog device, the exact counts in each flux bin will vary slightly from run to run.
MFM (DOS/Windows) Floppy Decoding
There are a lot of floppy formats, but one ubiquitous one at the end of the floppy era was the IBM PC compatible MFM floppy. The example "mfm_test" will decode the content of such a floppy disk and display it on the serial monitor in hex and ASCII.
Seeking track 8 head 1 Going to track 8 Captured 9 sectors Validity: VVVVVVVVV 00000000 65 76 65 72 61 6c 20 6c 6f 77 65 72 20 63 6f 75 | everal lower cou 00000010 72 74 20 6f 70 69 6e 69 6f 6e 73 2c 20 69 6e 63 | rt opinions, inc 00000020 6c 75 64 69 6e 67 20 0d 0a 74 68 65 20 6f 70 69 | luding the opi 00000030 6e 69 6f 6e 73 20 69 6e 20 41 6d 65 72 61 64 61 | nions in Amerada 00000040 20 48 65 73 73 20 61 6e 64 20 4c 54 56 20 53 65 | Hess and LTV Se 00000050 63 75 72 69 74 69 65 73 20 74 68 61 74 20 61 72 | curities that ar 00000060 65 20 73 6f 20 0d 0a 66 72 65 71 75 65 6e 74 6c | e so frequentl 00000070 79 20 63 69 74 65 64 20 69 6e 20 73 75 70 70 6f | y cited in suppo 00000080 72 74 20 6f 66 20 74 68 65 20 62 72 6f 61 64 65 | rt of the broade 00000090 72 20 73 63 6f 70 65 20 66 6f 72 20 74 68 65 20 | r scope for the 000000a0 0d 0a 70 72 69 76 69 6c 65 67 65 2e 18 11 31 31 | privilege. 11 000000b0 32 18 20 20 54 68 65 72 65 20 69 73 20 6e 6f 20 | 2 There is no 000000c0 63 61 75 74 69 6f 6e 20 74 68 61 74 20 74 68 65 | caution that the 000000d0 20 6c 61 6e 67 75 61 67 65 20 71 75 6f 74 65 64 | language quoted 000000e0 20 66 72 6f 6d 20 0d 0a 41 6d 65 72 61 64 61 20 | from Amerada 000000f0 48 65 73 73 20 6d 61 79 20 62 65 20 6e 6f 20 6d | Hess may be no m
For full details of the Adafruit Floppy library, see the API documentation. Here are some key details, though:
Pins & Construction
There are a lot of pins, so we put a standard definition block at the top of the examples for you to cut & paste into your code:
// these are for Adafruit Feather RP2040
#define DENSITY_PIN A1 // IDC 2
#define INDEX_PIN 25 // IDC 8
#define SELECT_PIN A0 // IDC 12
#define MOTOR_PIN A2 // IDC 16
#define DIR_PIN A3 // IDC 18
#define STEP_PIN 24 // IDC 20
#define WRDATA_PIN 13 // IDC 22
#define WRGATE_PIN 12 // IDC 24
#define TRK0_PIN 10 // IDC 26
#define PROT_PIN 11 // IDC 28
#define READ_PIN 9 // IDC 30
#define SIDE_PIN 8 // IDC 32
#define READY_PIN 7 // IDC 34
Adafruit_Floppy floppy(DENSITY_PIN, INDEX_PIN, SELECT_PIN,
MOTOR_PIN, DIR_PIN, STEP_PIN,
WRDATA_PIN, WRGATE_PIN, TRK0_PIN,
PROT_PIN, READ_PIN, SIDE_PIN, READY_PIN);
Usually, you'll start with the sequence: begin, select, spin_motor, and goto_track:
if (!floppy.begin()) {
Serial.println("Failed to initialize floppy interface");
while (1) yield();
}
floppy.select(true);
if (! floppy.spin_motor(true)) {
Serial.println("Failed to spin up motor & find index pulse");
while (1) yield();
}
Serial.print("Seeking track...");
if (! floppy.goto_track(0)) {
Serial.println("Failed to seek to track");
while (1) yield();
}
// outside any function // WARNING! there are 150K max flux pulses per track! uint8_t flux_transitions[MAX_FLUX_PULSE_PER_TRACK]; // inside loop() or other function int32_t index_pulse_offset; uint32_t captured_flux = floppy.capture_track(flux_transitions, sizeof(flux_transitions), &index_pulse_offset, true);
Decoding MFM flux data
Or use an Adafruit_MFM_Floppy object to get block-level access to a MFM-formatted floppy disk:
// outside any function, after defining floppy object
Adafruit_Floppy floppy(DENSITY_PIN, INDEX_PIN, SELECT_PIN,
MOTOR_PIN, DIR_PIN, STEP_PIN,
WRDATA_PIN, WRGATE_PIN, TRK0_PIN,
PROT_PIN, READ_PIN, SIDE_PIN, READY_PIN);
// You can select IBMPC1440K or IBMPC360K (check adafruit_floppy_disk_t options!)
Adafruit_MFM_Floppy mfm_floppy(&floppy, IBMPC360K);
// in loop() or other function
int32_t captured_sectors = mfm_floppy.readTrack(track, head);
// then access mfm_floppy.track_validity, mfm_floppy.track_data, and other fields
Page last edited March 08, 2024
Text editor powered by tinymce.
Using CircuitPython: adafruit_floppy
Adafruit has a CircuitPython library called adafruit_floppy for working with raw flux and with MFM-encoded data.
In this example using the library, information about the raw flux on track 0 of the inserted floppy is printed.
To use with CircuitPython, you need to first install a few libraries, into the lib folder on your CIRCUITPY drive. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, open the directory examples/ and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your CIRCUITPY drive.
Your CIRCUITPY drive should now look similar to the following image:
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2022 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
# On an Adafruit Feather M4 or Adafruit Feather RP2040 with Floppy Featherwing,
# do some track-to-track seeking and flux reading.
import board
import adafruit_floppy
D24 = getattr(board, "D24") or getattr(board, "A4")
D25 = getattr(board, "D25") or getattr(board, "A5")
floppy = adafruit_floppy.MFMFloppy(
densitypin=board.A1,
indexpin=D25,
selectpin=board.A0,
motorpin=board.A2,
directionpin=board.A3,
steppin=D24,
track0pin=board.D10,
protectpin=board.D11,
rddatapin=board.D9,
sidepin=board.D6,
readypin=board.D5,
)
floppy.selected = True
floppy.spin = True
print("Seek track 8")
floppy.track = 8
print("Seek track 0")
floppy.track = 0
print("Read partial track raw flux data")
buf = bytearray(30000)
n_read = floppy.flux_readinto(buf)
print("read", n_read)
buckets = [0] * 256
for b in buf:
buckets[b] += 1
oi = -1
for i, bi in enumerate(buckets):
if bi > 10:
if i != oi + 1:
print("---")
oi = i
print(f"{i:3} {bi:5}")
First, necessary modules are imported. Then, some conditional lines are used to adapt between boards that call the pins "A4/A5" and boards that call the pins "D24/D25". After that, an MFMFloppy object is created that refers to all of the appropriate pins:
import board
import adafruit_floppy
D24 = getattr(board, "D24") or getattr(board, "A4")
D25 = getattr(board, "D25") or getattr(board, "A5")
floppy = adafruit_floppy.MFMFloppy(
densitypin=board.A1,
indexpin=D25,
selectpin=board.A0,
motorpin=board.A2,
directionpin=board.A3,
steppin=D24,
track0pin=board.D10,
protectpin=board.D11,
rddatapin=board.D9,
sidepin=board.D6,
readypin=board.D5,
)
The next steps are to select and spin the floppy disk:
floppy.selected = True
floppy.spin = True
print("Seek track 8")
floppy.track = 8
print("Seek track 0")
floppy.track = 0
Finally, raw flux data can be captured and printed:
print("Read partial track raw flux data")
buf = bytearray(30000)
n_read = floppy.flux_readinto(buf)
print("read", n_read)
buckets = [0] * 256
for b in buf:
buckets[b] += 1
oi = -1
for i, bi in enumerate(buckets):
if bi > 10:
if i != oi + 1:
print("---")
oi = i
print(f"{i:3} {bi:5}")
Typical output:
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable. code.py output: Seek track 8 Seek track 0 Read partial track raw flux data read 30000 --- 94 121 95 1122 96 3999 97 8439 98 7044 99 2403 100 713 101 299 102 80 103 15 --- 141 47 142 110 143 221 144 376 145 559 146 726 147 761 148 833 149 682 150 441 151 172 152 55 153 14 --- 194 22 195 32 196 61 197 91 198 113 199 110 200 93 201 75 202 51 203 24 204 19
Page last edited March 08, 2024
Text editor powered by tinymce.
Downloads
Page last edited March 08, 2024
Text editor powered by tinymce.