As a somewhat more substantial exercise to learn Verilog, I thought I’d write an SPI master controller - should be easy, right?
The Serial Peripheral Interface bus can deal with high speeds (at short distances), only uses 4 I/O pins, and it looks like quite an elegant bi-directional transfer mechanism:
Image may be NSFW.
Clik here to view.
Two shift registers, connected in a circle, with bits rotating through (MSB to LSB).
The devil is in the details, though:
- the actual SCLK/MOSI/MISO wires introduce some delay, so the master and slave need to be clocked on different edges of the SCLK signal
- there are four combinations of how this can be done, in terms of which edges the master and slave shift on
I’ve looked at a dozen implementations on the web, but they all appear to be more complex than necessary. My goal is to strip down this task to its essence and hopefully, that’ll translate into simple Verilog code.
My first attempt is spiSim/top.v on GitHub.
It re-uses a single 8-bit shift register for input and output, as in the above diagram. It also gates SCLK, i.e. pulses are sent to shift the data, but the clock is not a free-running divider of the main clock - it only increments while there is work to do.
One trick I’m using here, is that the internal counter is actually 5 bits large:
the low bit is the (negated) SCLK signal, bits [3..1]
are the 8-bit counter to
shift out the byte, and bit 4 is the overflow, causing the driver to return to
idle mode and stop shifting more bits. I’m assuming all flip-flops start at “0”.
Here is the simulation, with MISO being a slightly delayed copy of MOSI for this test:
Image may be NSFW.
Clik here to view.
(you can see more detail in this PDF)
If “wr
” stays high, this will be treated as a continuous write, and the
outgoing bytes will be sent out nearly back-to-back.
This is based on the timing specs of the W25Q16 serial flash memory chip:
Image may be NSFW.
Clik here to view.
Is it correct? - I don’t know. I’m not happy with the timing of the “done
“
pulse yet …
It sure takes getting used to. Verilog may look a bit like C, but all this parallel stuff brings a very different approach to coding!