Thursday, 26 September 2013

SPI - the Key to the Project

Using SPI to Output Track Data

I looked at several floppy disk projects for ideas on how to make the Raspberry Pi work as a virtual floppy disk. On in particular has been quite useful - the SVD. It was based on a MicroChip PIC controller and bit-banged the output line representing the floppy disk track data. The difficulty with this approach is that it relies on assembler code and very tight timing where each instruction time is measured and accounted for. This is not compatible with an operating system where interrupts could stop the flow of execution and cause gaps in the output data.

Let the Hardware do the Heavy Lifting

After a bit of investigation I decided to try the SPI bus instead. This would let the specialized hardware of the Raspberry Pi do a lot of the work for me. Put simply, I'm ignoring the SPI protocol and asking the SPI hardware to perform parallel to serial conversions and to do it according to a specified clock rate. The logic analyzer screen shot below shows the SPI clock on channel 1 and the SPI output on channel 0. The first two output bytes are 0xFF and the third byte is 0x00.

Note that the SPI clock is not continuous. There are eight clock pulses for each output byte followed by a one clock cycle pause. So what we actually have on the output are eight bits that can be toggled on and off followed by a ninth 'spacer' bit which is always zero. The challenge is to use this capability to output a signal that emulates the floppy drive data output.

The initial attempt set the SPI clock so that the total time for the eight bits plus the ninth 'spacer' bit equaled 8 microseconds. A value of 0x80 was transmitted for a data bit 0 which only has the clock bit set and a value of 0x88 was transmitted for a data bit 1 which has both clock and data bits set. Therefore each byte of track data was translated into eight bytes of SPI data where each byte of SPI data represents a single bit of track data. The screenshot below shows the timing.

The output signal deviated from the ideal signal because of the spacer bit, but the floppy disk controller was still able to decode this correctly as the bits appeared within the expected timing window.

A more accurate approach doubled the SPI clock speed and represented each clock or data bit with a single SPI byte using a bit pattern of 11000000b or 0xC0 in hexadecimal for a '1' and zero for a '0'. (Clock bits are always '1' except for the special address marks noted in the previous blog post.) Note that because the clock speed is doubled we have to set two bits instead of one for each output '1'. Therefore each byte of track data was translated into sixteen bytes of SPI data where the even bytes of SPI data represented the clock bits and the odd bytes represented the data bits. The screenshot below shoes the timing. The clock and data bits are still .888 ┬Ás but the output pulses and gaps are now much closer to the ideal signal.

With the double-rate scheme a single-density track becomes 50,000 bytes of SPI data which must be transmitted every 200 milliseconds or one byte every four microseconds. You may wonder what happens if the software is interrupted for a period greater than four microseconds. Will there be a gap in the SPI output signal? Fortunately the Raspberry Pi SPI has a 64 byte input buffer which will take 256 microseconds to empty using the double-rate scheme. The current software runs on Risc OS where the recommended maximum time to disable interrupts is 100 microseconds so even in the worst case situation the buffer is unlikely to be emptied while the operating system is handling an interrupt. If I ever figure out how to enable DMA for the SPI even faster data rates would be possible.

More on SPI and GPIO programming in later blog posts.