Diving deep into SPI Sep 21, 2016

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:

Two shift registers, connected in a circle, with bits rotating through (MSB to LSB).

The devil is in the details, though:

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:

(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:

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!

Weblog © Jean-Claude Wippler. Generated by Hugo.