Use a floppy-disk as a multi-frame-buffer, store audio-samples, and increase capacity to boot!

Similar projects worth following
Using PWM, rather than MFM, to store data on magnetic media, I believe it possible to increase the storage capacity dramatically without compromising data-integrity. With a simple 8-bit uC at 16MHz, 8 bits could be stored in 5 bits' space!

A single track, then, contains enough data to be used as a frame-buffer for a small LCD. 160 tracks makes for a digital-picture-frame, something like HyperCard, or even short videos.

But first, I'll store audio-samples, 80 tracks per side is perfect for a MIDI controlled synth-patch, etc. Yep, it's a bit crazy.

that name... just now imagined, might just do the trick... (was trying to figure out what to demo with this thing)

Herein, I plan to document plausibly the most ridiculous of my endeavors, to date...

Wherein there are planned two subprojects to demonstrate a technique I've come up with for increasing the amount of data that can be stored on media such as floppy disks, and maybe extendable to similar media still in use today, such as hard-disks.

(It's plausible this technique already exists, but I have not read of it previously).

The first subproject will use this technique to store and play-back audio directly on a diskette using an unmodified drive and a handful of discrete components (comparators, mostly). No microcontroller is necessary for concept-demonstration, though may be added later for increased functionality.

The second subproject, and likely my most-ridiculous, ever, will use this new storage technique to use a floppy diskette as a framebuffer for an LCD.

Briefly: each track will contain an entire frame, refreshing the LCD once with each revolution, at 5Hz.

(160 images! Think: HyperCard, or maybe a digital picture frame).


A standard 3.5in 1.44MB diskette is recorded at 500kb/s, and spins at 300RPM, or 5 rotations per second, 100,000 bits per rotation... left spinning on a single track, those 100,000 bits repeat...

A 240x160 LCD has 115,200 pixels... it's like a sign or something.

(Actually, it has 38,400 three-color pixels)

A) the 500kbps data rate is a guarantee by design, and can likely be bumped up a bit, especially on outer tracks... so a 15.2% increase should be doable. That doesn't include invisible pixel-clocks, used by the "porches", but... worst-case we lose some pixels at the right or bottom... definitely feasible.

But That's Irrelevent because:

B) a different, and possibly new, technique of magnetic data-storage is proposed:

North...  _____________
South... /       \_\_\_\_______/

Floppies store data as magnetic flux transitions. The 500kbps limitation is due, largely, as I understand, to the minimum distance at which two "magnets" can be placed on the innermost track without repelling or attracting each other too dramatically as to affect the stored data.

The typical approach is to store these flux transitions at one of two locations, depending on whether the bit is a one or zero. Thus, data is stored such that each data bit occupies essentially the minimum amount of space which can accomodate *either* flux-transition mapping without affecting the next bit. 

What I'm trying to say is that every bit contains (or at least is big enough to contain) a flux transition in either of two locations, one of which always goes unused...

But it needn't be that way...

Imagine a digital oscilloscope... Say it samples at 100MS/s. Analog-to-digital converters that fast are typically quite expensive. So a trick often used is to have, say, two 50MS/s ADCs which are offset by 1/2 of their sample-period. Bam... 100MS/s.

Now look at it the other way... the ADCs aren't restricted to 50MS/s... they could just as easily be bumped down to 49.9999MS/s. It's not a factor of sample-rates divisible by 50, it's a matter of the resolution of the sample-clock. And the limitation of 50MS/s is merely a matter of the maximum number of samples that can be crammed into a second, put more clearly, a matter of how fast a single sample can be processed.

But those samples don't have to be evenly spaced throughout a second! One could just as well sample one sample at 1/50millionth of a second, and sample the next at 1/49.999 sec, thereafter (being nowhere near some multiple of 1/50mil).

Oy... bad explanation. Let's think about synchronous logic... say...

Read more »

  • so, technically...

    esot.eric05/07/2018 at 00:33 0 comments

    a normal 3.5in floppy disk holds 2MB. That's not due to rounding.

    The disk spins at 300RPM, thus 5 rotations per second. The data-rate is 1Mb/s... but that's MFM bits, two of which make a data bit, so 500Kb/s of data-bits. Thus, 100Kb fit on each track, or 12.5KB. There are 160 tracks: 80 cylinders, two sides... 2 mega bytes.

    1.44MB for storage is due to formatting. Sector-headers, CRCs, and a few other things. Most computers are capable of different formatting, at the hardware level, but software doesn't usually support that by default. Thus, it's more than possible to cram more than 1.44MB of user-data on a disk, but less than 2MB, by using a different format (fewer and larger sectors means fewer bits wasted on headers, more for data), *without* using compression.

    But all that's moot to this project.

    This project replaces MFM-bits with PWM-nibbles. Each MFM-bit is 1us long (1Mb/s data rate), each data-bit, encoded in MFM, is 2us long.

    Each PWM-nibble, as I've currently defined it, is 5us long: four bits of data gets stored in that space. 

    Thus, in MFM, 5us would contain 2.5 data-bits, here it contains 4.

    That's 3.2MB per disk, vs 2MB. Of course sector-headers can be equally-relevant in decreasing the capacity for user-data... but I see no reason why it would be more overhead than on an MFM disk. 

    That'd make the user-data storage-capacity of a PWM-3.5in floppy 2.3MB vs. an MFM-floppy's 1.44MB.


  • Random syncing thoughts

    esot.eric04/23/2018 at 05:58 0 comments

    Part of me has gained quite a bit of interest in trying to implement this thing (at least read-back) with discrete logic, like TTL/7400-series.

    Sync: There's no reason it has to be the same duration as a PWM-nibble. 4us seems better to me.

    The key concept of the sync pulses is to make it easy to detect which falling-edge from the Read-Data pin corresponds to the start of the PWM cycle.

    Here, for sync, the falling-edge pulses occur farther-apart than they would in a PWM-data nibble. So, 4us is plenty.

    Clock-syncing: 1us is divided into 16 possible values... so 16MHz sampling, roughly. 

    "Roughly" because, realistically, it'd be kinda absurd to expect a floppy to spin at *exactly* 300RPM, or even exactly the same RPM each time it's accessed. And, frankly, it's entirely possible the spin-rate may vary several times per revolution!(e.g. the disk is worn in a spot that drags differently on the read-head). So it's actually rather necessary to have some amount of flexibility in the reader/writer's sampling-frequency, which means somehow adjusting that frequency to match that on-disk.

    I've been neglecting that part, for simplicity, assuming that the spin-rate on the same drive/disk will be relatively constant most of the time...

    So, now, two potential branches for the course of this project. A) get it working as simply as possible... That was the original goal... And, part of the intent behind that is to demonstrate possibilities to those who may otherwise be intimidated B) essentially rebuild the entire floppy-system from scratch, for the sake of learning, I guess. E.G. I've always kinda wanted to figure things like PLLs out, at a low-level... Now I'm thinking about how that'd work... to synchronize a clock with a pulse that's 64x slower (if I use 4us for syncing)... I've a vague idea of a 7bit counter, a <=> comparator, and... what for actually generating the clock? I think the norm is a voltage-controlled oscillator... But, then, it occurs to me the same could be done with an AVR and the OSCAL register, realtime varying of the AVR's clock to match a varying-frequency external source... weird concept, but kinda intriguing, potentially very useful... And... not at all in-line with the TTL-idea.

    I guess this is how my brain works, or doesn't.

    Anyways, TTL-implementation is more a thought-experiment, for the time being. Actually, the whole project is, so-far... Been meaning to solder up that proto, and get coding, but it never seems like the right time/setting, these days.

    So, 4us for sync-pulses, 6-bit counter. Data is only valid during the 1us window between 2us and 3us after the start of the PWM cycle... that fits within our 6-bit counter, as well. 

    Now, here's a thing I'd briefly pondered in the past: After the Data-edge occurs, we really don't care where the next PWM-start-edge occurs. It just has to be at least 2us after the data-edge. Thus, our counter needn't go higher than 48... it'll get reset to 0 at the next PWM-start, whenever it occurs.

    So, one potential benefit of this (dependent on the write-mechanism, and its alignment with the read-head), is the possibility to modify individual nibbles. Maybe a stretch, or maybe not... e.g. bumping the 'buffers' to 3us might allow for it, reliably.

    Another potential benefit is increased capacity... if you're writing a lot of 0's, each nibble is only 4us, a lot of 0xf's would be 5us, each. Handy, then, for Write-Once, Read-Many drives, like a CD or movie. Not so much for read/write media.

    In the case of this frame-buffer, it makes sense to keep every nibble the same length, for the sake of a steady pixel-lock (which isn't really necessary with this display). 

    But, anyhow, with a counter limited to 48 or 64, not requiring a specific duration for every nibble, those options are possibilities. Simplify the thing, open new doors, I guess. OTOH, with specific-width PWM cycles, clock-syncing is inherent to every nibble... which...

    Read more »

  • PWM-sync OBVIOUS!

    esot.eric04/21/2018 at 07:39 0 comments

    "How'm I gonna know which edge corresponds to the start of a PWM cycle, and which to its duty-cycle?"

  • 160+ 'sectors'?

    esot.eric04/21/2018 at 05:30 0 comments

    just an idea... 

    a brief intro to the problem: one of the dilemmas of trying to load an image onto each track is that the entire track/image would have to be written in one fell-swoop, in realtime. This because it'd be darn-near impossible to expect the read and write heads to be aligned so perfectly as to be able to manipulate individual bits on the disk...

    This, I presume, is a huge factor in why disks are written in sectors. 512 bytes of consecutive data, prepended by a header that gives info about that sector, and that header prepended with numerous repeating bytes which indicate the beginning of a sector, allowing the controller to resync its clock with this new and likely misaligned stream of data. (Misaligned with respect to the previous sector, as each is typically written in different rotational-cycles).

    Writing the whole image-frame in one fell-swoop would be challenging... The uC itself probably isn't fast enough to render in realtime, so I was planning to send images from a host computer... but the math wound up requiring a serial connection at 1Mbps. That should be doable. The problem is that that data stream can't be interrupted, e.g. if the host computer decides to task-switch to handle a mouse movement.

    I'm sure it's doable, a receive-buffer would help, xon/xoff, a faster baud rate, 'renice' at a high priority, a custom downloader program, a few other things.

    But, not ideal... Also because it means the only images that could be stored would have to be pre-rendered... and, again, loaded from a computer.

    So, it occurs to me... Why not write the floppy in chunks... yahknow, like... sectors! Duh.


    Here's the thing, I know all about sectors... I was trying to avoid them, for the sake of a simple demo... The uC would've basically been doing nothing more than could've been handled with a few TTL parts, in translating the stream of PWM data coming from the Floppy drive into the parallel data-bits required to drive the display-timing and draw the image. I like that idea.

    ... So, I've been avoiding sectors. But, the fact is, I *will* be using a uC in this project... at least for writing the images to disk, And then, for readback, because the hardware would already be set up. Also, the solution to the other day's 'duh moment' would be a bit more difficult to do with TTL.


    But, tonight occurred to me that a stripped-down sort of 'sector' could be quite easy to implement. What if *every* line was a 'sector'... my display is 160 lines tall. So, after each Hsync, maybe the uC just writes a bunch of Hsyncs repeating. When read-back, the first latches the uC's Hsync output signal and indicates to the uC to resync the PWM-data, etc. Then the beginning of the next line of data will overwrite some of those repeating Hsyncs with a short header just long enough to assure the PWM-data is being read correctly, then the uC will switch Hsync off when appropriate, beginning the next line.

    This'd be easier than regular sectors for a ton of reasons, one of which is that there's 16 possible PWM-data values in each PWM-nibble, but only 9 or 10 are allocated (8 colors, hsync, maybe vsync). Thus, the beginning of the next line/sector-data could be prepended with an 'hsync-off' nibble. Easy-peasy.

    This is all further aided by the fact that the 'sectors' will always be read-back sequentially and in realtime. Older computers, of the era when floppies were invented, just couldn't handle that much processing... floppy controllers were even dumber. They couldn't process two sectors back-to-back (thus interleaving). Further still, there was no hard requirement that sectors would always be a certain lenght! So, sector-headers had to contain enough information to be located at-random. Here there's no need for all that. These 'line secctors' are all sequential and all the same length. A line-data-header, here, could probably be no more than 4 PWM-nibbles, just enough...

    Read more »

  • 'duh' moment...

    esot.eric04/16/2018 at 08:37 2 comments

    OK, but there's really no [easy] way to determine whether we're looking at the *start* of a PWM cycle, or the falling-edge of the duty-cycle, itself... because: every edge is stored as a falling-edge.

    This doesn't matter for *audio*, because an inversion in the PWM output-signal results in an inversion in duty-cycle, around 50%... and *that* is nothing more than an inversion in polarity on the speaker-cone, which doesn't matter when only dealing with mono.

    But for *data* (e.g. the image-frames), we definitely need to keep track of which falling-edge corresponds to the beginning of a PWM pulse, and which corresponds to the duty-cycle's edge.

    I feel like I must've figured this out once before...

    Best I can come up with is to align the PWM with the "Index" output (which occurs once every rotation). But, that may be iffy, as well... E.G. the Write-head and Read-head may not be perfectly aligned... in which case, writing at the start of an index-pulse may be read-back after! Oy! Then, of course, the odds of the "index" outputs on differing drives being perfectly-timed with the read/write-heads... Even less likely.

    Some amount of reconstruction should be possible... e.g. let it run for several pulses, then figure out which edge occurs at the same period, then that's the PWM-start edge. But... well, anyways, it's getting a little more complicated.

    An interesting artifact will occur when switching tracks... (e.g. data will be garbled while the head races to the next track, *but* the screen will most-likely continue to refresh with that garbled data since the uC will be regenerating the pixel-clock... but hsyncs will be missed, or even randomly-injected...) I've looked forward to seeing that. And with this new dilemma, it could be even more interesting (e.g. colors may be inverted for one frame, even after the read-head has stopped seeking).

    Frankly, I consider these things to be one of the major driving-factors for this project... I already know the project should work as-planned, with maybe a few unexpecteds which can likely be worked-out... But these other things, probably not *useful* per-se, but hard to predict, so akin, maybe, to the draw to watching a flame. And sometimes these sortsa things wind-up being *very* useful... Moldy bread, yahknow? Moldy-milk, Moldy grapes, Moldy oats-grains-and-hops... Post-its! (oh, wait...) Once it's running, I'll probably spend more time looking into that stuff than actually making it useful (turning it into a game, etc.) If nothing else, maybe I could use it as a random-number-generator...


    Another idea, (I feel like I'm reinventing the standard method) is to have a "header" at the start of each track, immediately after the index-pulse. This'd contain a string of PWM-values with the same (not 50%) duty-cycle. Oh No! Wait a minute... It'd have to be *vastly-differing* duty-cycles, from one to the next. Then, use this time to look for the edges which are periodic, as described earlier.

    The original plan was to use the "index" pulse *as* the Vsync pulse... Doing-so, here, wouldn't be so useful... Unless, maybe, I choose to use the trailing-edge for Vsync, and the leading-edge for beginning the header. Hmmm.

    If that *doesn't* work, then we'd have a string of data that can't be used immediately after the vsync, which'd leave garbled pixels on the first row of the screen. (Which could be interesting, anyhow).

    But, it could be that we're back to having a specific nibble-value to indicate Vsync. Not so bad, really. Better, probably, what with the alignment concerns.

    And, again, I'm planning on storing 4-bits per PWM-value, that's 16 different duty-cycles within a 1us time-frame, which corresponds to our 16MHz processing-speed. (Or, plausibly, 16 values in 2us, allowing for some lee-way, in case the disk decides to spin at a slightly different rate from time-to-time; due to temperature, maybe, etc. Or different drives...). But, with these processing-speeds, it might be difficult...

    Read more »

  • Audio preparations

    esot.eric04/16/2018 at 00:55 0 comments

    Before I actually start writing audio (and images!) to disk, I need to make sure my write/read technique/circuitry is "sound"...

    I've implemented the test-circuitry via comparators, just for the heck of it. And to (later) demonstrate how easy it is to make use of floppy-data... no microcontroller necessary! But, we're still a ways off from that.

    First, the audio is converted to PWM.

    Then both PWM edges are converted to falling-edge pulses.

    This, then, could be fed directly into a floppy drive's "write data" input, storing the PWM on-disk.

    When read-back from the disk, the floppy drive will give these same falling-edge pulses to indicate each edge of the recorded PWM.

    That, then, gets fed into my single-comparator T-Flip-Flop, to convert those falling-edges back into PWM, then directly drives a speaker.

  • WIP: MFM (normal diskette) data-storage

    esot.eric04/13/2018 at 04:04 0 comments

    Most floppy drives use a method called Modified Frequency Modulation (MFM) to store binary data-bits on the magnetic media.

    This method encodes each data-bit into two MFM 'bits'. E.G. the data-bit '1' is always encoded in MFM as "01", the data-bit '0' is either stored as MFM "00" or "10", depending on whether this follows a '0' or a '1' in the previous bit.

    This seemingly over-complicated scheme serves several purposes. First and foremost, it assures somewhat regularly-spaced transitions/alternating between North and South polarity on the media, regardless of the binary data stored. Thus, the floppy disk controller is able to keep its serial-data clock synchronized with the data-bits on-disk. Essentially, MFM encodes both the data-bit *and* the serial clock into each MFM bit-pair. This alternating polarity is also essential for the inductive read-head/pickup, which can only detect *changes* in magnetism. 

    Thus, MFM assures that even 1KB of consecutive 0x00's (e.g. after a format) will be stored on-disk as alternating between North and South, once for every 0-valued data-bit.


    But, note, again, that data-bit '0' has two separate encodings "00" and "10". If MFM "0110" were written to disk (binary data "10"), we'd have a problem... and this is where things get a bit more detailed, and we need to take a step back and analyze what's actually being stored on the disk.

    Each MFM bit represents a potential for transition in magnetic flux. Wow that's badly-worded. Let's try again.

    Most any position on the disk surface can either be North-polarized or South-polarized. MFM assures that North and South alternate somewhat regularly. Great!

    BUT, placing these opposing polarities too close together can cause problems. Maybe the read-head is too large, picking up two (or three?) polarities at the same time, unable to discern which it's reading. Maybe there's some inherent granularity* in the media? There could be many factors, but as I understand, it boils down to these "magnets," each one MFM-bit wide, attracting and repelling each other.

    Here's how I understand it: If you place two magnets on a table, so their North polarities face each other, then those two magnets will repel each other, up to a certain distance, at which point friction prevents further repulsion. 

    Placing a weaker magnet's South pole between the two would probably reduce the effect, but not eliminate it. The two stronger magnets still repel, and placing a compass above the weaker magnet's south pole will still show a net North polarity.

    (*Note that 'precompensation' is another topic entirely, but if granularity was a concern, precompensation wouldn't be possible)

    Thus, there is a minimum space which can reliably contain two flux-transitions (three polarities alternating, NSN or SNS). That minimum space is two MFM-bits long, on the innermost track, where the bits are most-densely packed.

    (binary values: High and Low. MFM values: Change and No-Change. Read/Write values: Hi-Z/floating and Low. Polarity values: North and South)

    Anyhow, an MFM '1' bit does not correspond to a polarity on the disk, it corresponds to a *change* in polarity on the disk. A "change in flux".

    And two changes in flux can only occur at greater than some minimum distance (2us on the smallest/inner track on a spinning disk). Thus, MFM encoding does not allow for a "11" pattern. The first data-bit '0' after a data-bit '1' is, therefore, encoded as "00" rather than "10", giving data="10" mfm="0100", rather than mfm="0110"; no consecutive '1's in the MFM encoding.

    All That To Say: diskettes guarantee proper data-retention when each singular magetic polarity is at least 2us long, but also alternates regularly. And, MFM assures that.


    So, the shortest single-polarity...

    Read more »

  • PWMing 2

    esot.eric04/12/2018 at 01:29 0 comments

    Again, we cannot send our PWM *data* directly to the floppy-drive's /Write-data pin. Instead we need to send two falling-edge pulses for each PWM-nibble. Confusingly, I plan to use a PWM-output from the microcontroller to create those *two* precisely-timed falling-edges. Thus requiring *two* uC-PWM cycles to write *one* PWM-nibble to disk.

    In order to write the PWM-data, I've come up with a couple possibilities: 

    In both cases, the negative-going /WR pulses will vary in duration depending on the value of the PWM-nibble to be written. This shouldn't matter, as the flux-transition is triggered by the falling-edge.

    The second case is a little less-intuitive, as the PWM-output cycle starts midway through the PWM-data signal.

    Importantly: the PWM-signal will have a constant period, possibly saving several instruction-cycles, which may be near the limit.

    These cases both assume a PWM-output that starts high and goes low after a set duration... AVRs allow for the opposite, or it could easily be done with an inverter, but I've yet to analyze whether that could be helpful (e.g. in aligning a *data* start with a *signal* start?). My intuition is that doing-so would require both PWM-output cycles to vary in period, e.g. duration1=value, duration2=2us-value, eating into our valuable instruction-cycles.

  • PWMing

    esot.eric11/26/2017 at 09:07 0 comments

    The read/write data pins on a floppy drive do not correspond to flux-value (e.g. 1 for North, 0 for South). Instead these signals supply a falling-edge at each flux transition... and the duration of the low pulse is somewhat arbitrary. Thus, I don't think it's possible to know the polarity on the disk. Though that doesn't matter. What does matter is that we can't just drive the /WD pin with our PWM signal, as will be stored on the media...

View all 9 project logs

Enjoy this project?



Lee Djavaherian wrote 04/24/2018 at 00:23 point

You have many interesting projects, and your writing style is really enjoyable to read.  I like the ways that you re-use older tech, the techno-archeology you perform, and how you also change gears and publish those inexpensive lifehacks like the automotive repairs. (By the way, I also have a makeshift heater-core bypass in my car, and it's a true Apollo 13 cabin experience in the winter! And I have a Marantz 2230 that I need to fix, but I digress...)

This Floppy-bird project, though, is really interesting and several orders of magnitude more complex; I keep coming back to it for some reason--it sticks in the mind--something that shouldn't exist in our reality, but something that I would like to see exist.  I've e-wasted so many of those drives years ago and felt bad about it every time. 

It is fascinating how old and new tech often have these weird similarities that sometimes allow their mystical conjunction, so to speak, that "sign or something" you mention.  The tech you are combining are shifted slightly in time and purpose such that they can't be connected directly, yet they share the unifying element of the picture frame, which they can all deal with in different ways.  It's great to see you engage these kinds of alignments and perform further exploration, and you are going pretty deep into floppysophic territory on this one.  Impressive.

  Are you sure? yes | no

zakqwy wrote 04/12/2018 at 13:35 point

man I miss hypercard.

  Are you sure? yes | no

esot.eric wrote 04/13/2018 at 05:39 point

Those were The Dayz!

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates