ZXSPI is a Verilog project to allow the Spectrum with the ZX Breakout (or any other FPGA/CPLD board) to work as an SPI master without all that inelegant bit banging in code.
- SPI clock from 3.5MHz to 14kHz
- Supports CPOL 0 (normal clock polarity) and CPOL 1 (inverted clock polarity)
- Full duplex
- Four chip selects
- Synchronous design that should work fine with an FPGA
- Requires 62 macrocells (fits an XC9572)
Caveats: I've not done a great deal of Verilog, so it's likely the implementation can be made a bit more efficient. In particular, the parallel to serial and serial to parallel shift registers are double buffered, it's the easiest way of separating the two clock domains (Z80 clock and SPI clock domains), but it's probably possible to do something more convoluted that uses fewer flip flops.
The Verilog code and Xilinx ISE project file can be obtained here, from WebSVN
There's a demonstration of it in action on YouTube here: ZX SPI and Nixie display
The project uses two IO ports, performing full 16 bit port decoding:
- Port 0x043B: SPI read/write
- Port 0x053B: Control and status register.
The control and status register
When writing to the register, the following bits are defined:
bit 7 - not used bit 6-5 - SPI chip select to use bit 4 - 1 = use clock divider, 0 = don't use clock divider bit 3-1 - set clock speed (bit 4 must be set to 1 to use this) bit 0 - select clock polarity (0 = CPOL 0, 1 = CPOL 1)
After the Spectrum is powered up or reset, the defaults are: Clock speed 3.5MHz, CPOL 0, using chip select 1.
When reading from the register, the following bits are defined:
bit 7 - 1 = Busy, 0 = Ready for a new read/write operation bit 6-5 - SPI chip select in use bit 4 - 1 = using clock divider, 0 = not using clock divider bit 3-1 - Current clock speed bit 0 - Current clock polarity
Setting SPI clock speed
Bits 4-1 of the control register (0x053B) set the SPI serial clock speed. If bit 4 is set to 0, then the clock divider is bypassed and the 3.5MHz CPU clock is used as the SPI serial clock. Otherwise, if bit 4 is set to 1, the serial clock speed is determined by a simple 8 stage clock divider. The fastest speed (1.75MHz) is basically the Z80 clock divided by two. Here's a table of the speeds selectable when bit 4 is set:
When bit 4 is set to 1: Bits 3-1 Speed 0 1.75MHz 1 875kHz 2 438kHz 3 219kHz 4 109kHz 5 55kHz 6 27kHz 7 14kHz
There are four chip selects, so you can have up to 4 SPI devices. The active chip select is specified by bits 6 and 5 of the control register. The mapping looks like this:
Bit 6 Bit 5 Chip select 0 0 1 0 1 2 1 0 3 1 1 4
Chip select pins on the ZX Breakout will be 67, 68, 71 and 74 for chip select 1 to 4 in that order.
Writing to an SPI device
After setting the SPI clock to the desired speed, writing is simply a matter of sending the byte you want to send to port 0x043B. If you need to send several bytes, and you know that the 8 bits will be written out on the SPI bus before you send the next byte, you can just write again to port 0x043B. However, if your code is in a tight machine code loop and the SPI clock is a low enough speed, it's likely the SPI write won't have finished. (A future update may be to not transfer the byte into the shift register until the previous byte has been sent so that two may be sent at once, but this is currently not the case). To check whether you can send another byte, read the control and status register and check the state of bit 7. If bit 7 is 1, then it's still busy sending. Once bit 7 goes back low you can send a new byte.
Reading from an SPI device
Reads happen simultaneously to writes. SPI devices don't have an explicit RD or WR signal to specify which one is being done. When you write to an SPI device you get a read for free. If you need to read from a device, but it's not expecting to be written to, then write whatever the device's idle state (for example, 0xFF) is when you write to port 0x043B which will initiate the operation. The data sheet for the SPI device should specify what this is. Once the SPI operation is complete, and the 'busy' bit (bit 7 of the control register) has returned to zero, then reading port 0x043B will return whatever the SPI device deposited on the MISO line.
The same comments about multiple writes in the above section (checking the control register's bit 7) applies to reading too, since they are effectively the same operation.
Speed of INI/OUTI versus SPI operations
The SPI read/write operation starts on the next rising clock edge (don't forget that the edge connector CLK signal is inverted with respect to the clock the CPU sees) after the IO write completes. The I/O operation is performed on the 4th M cycle of an INI or OTI instruction. The fastest possible read and write you will be able to do is something like this:
ld bc, 0x053B ; B must be 1 greater than I/O port ld hl, ptr outi ; write (hl) to port 0x043B inc b ; SPI write will begin during execution of this instruction outi inc b outi ...
The SPI operation takes 8 T-states to complete at full speed, since one bit is read/written to MOSI and MISO per T-stat. This starts on the next rising edge of the internal SPI clock, which will be halfway through the first T-state of INC B. Therefore the SPI operation is guaranteed to have completed before the next OUTI writes to the device. The INC B and first 3 M-cycles of OUTI will require 16 T-states to complete, and the IORQ line doesn't go low until the 17th T-state. This will mean that a 1.75MHz serial clock should be usable in the code above. In this case:
ld bc, 0x043B out (c), a out (c), d out (c), e
only the 3.5MHz serial clock is fast enough for the SPI operation to complete before the next OUT. The OUT (C), r instruction has 3 M-cycles, each 4 T-states long, so there will be 9 T-states from IORQ going high until the next OUT operation beginning.
At lower speeds you'll either need to calculate how many T-states it'll take to complete the SPI operation, and see if your code takes longer than this in between subsequent I/O operations. In the case of a slow SPI serial clock, for a machine code program you'll probably need to check the contents of bit 7 of the status register (0x053B) before starting a new I/O operation.
You can ignore contention - except on a +3 or +2A/B - because the serial clock is directly derived from the CPU clock, and so while the CPU clock is halted during contention periods, then so will the serial clock. However, this is not the case on a +3 or +2A/B since the CPU clock keeps running and contention is achieved by other means. So for these machines you'll need to use uncontended memory if you want your T-state calculations versus SPI operation calculations accurate.
If you don't modify the UCF file in the project, the SPI pins appear on the connector on the right hand side of the board, on the innermost column of pins and the adjacent pins on the top row.
The pin assignments by default are:
61 SPI clock (often known as SCL) 64 MOSI (master out slave in) 66 MISO (master in slave out) 67 Chip select 1 (active low) 68 Chip select 2 (active low) 71 Chip select 3 (active low) 74 Chip select 4 (active low)