SPI: a clock, two data lines and a chip select
- 192parts on the bench
- 25boards running now
- 1.00xreal time, on every board
SPI is the bus you reach for when I2C is too slow or a chip simply does not speak I2C: LED matrix drivers, TFT displays, SD cards, most radio modules. It has no addresses and no acknowledge. Instead it has a clock that the controller drives, a data line in each direction, and a chip select wire for every device, so choosing who to talk to is a matter of pulling one wire low.
The circuit above is an Arduino Uno bouncing a ball round an 8x8 LED matrix driven by a MAX7219. The chip’s clock (CLK) is on pin 13, its data in (DIN) on pin 11 and its chip select (CS, called LOAD on some modules) on pin 10, which are the Uno’s own SPI pins. A logic analyzer is on all three with its decoder set to SPI: D0 on the clock, D1 on the data and D3 on chip select. Press Run and the strip reads "SPI mode 0" and counts the transfers, and the labels over the trace show each packet as two bytes, for example 0x04 and then 0x18. The 0x00 printed beside each byte is the MISO channel, which has nothing connected to it here.
The four signals
SCK is the clock, and only the controller drives it. MOSI (controller out, peripheral in, also written COPI or SDO) carries data to the device. MISO (controller in, peripheral out, CIPO or SDI) carries data back. CS, also called SS, is active low: a device ignores the clock until its chip select goes low, and a transfer ends when it goes high again.
Every clock pulse moves one bit each way at the same time, so SPI is full duplex. When a chip has nothing to say, like the MAX7219, it simply has no MISO pin, and that is why D2 on the analyzer is left unconnected here. To add a second device you share SCK, MOSI and MISO and give it its own chip select pin. There is no address to clash.
Reading a MAX7219 packet
The MAX7219 takes 16-bit packets, most significant bit first: an 8-bit register number followed by an 8-bit value. It shifts bits in on each rising clock edge and copies the packet into the register when CS rises. On a matrix module, registers 1 to 8 are the eight rows and each bit of the value is one LED in that row.
So when the analyzer shows 0x04 then 0x18, it is reading "row 4 gets 0001 1000": two lit LEDs in the middle, which is one row of the 2x2 ball. The same frame shows 0x05 0x18 for the row below it and 0x00 for the empty rows. At the end of each frame comes 0x0A 0x08, register 10, the intensity, set to 8 of 15. When the ball hits a wall the sketch raises that to 15 for one frame, and you can catch the 0x0A 0x0F go past.
The analyzer’s window on this circuit is 400 microseconds, short enough to read individual bytes. Widen it in the properties panel and whole frames come into view: eight row packets and one intensity packet every 90 milliseconds, each fenced by CS going low and high.
Modes, bit order and speed
SPI has four modes, from two settings. CPOL says whether the clock idles low (0) or high (1). CPHA says whether data is sampled on the first clock edge of each bit (0) or the second (1). The MAX7219 uses mode 0, clock idle low and data read on the rising edge, which is the most common. Get the mode wrong and every byte arrives shifted by one bit, which looks like random garbage with no framing error to warn you.
Bit order is the other setting to match. Most chips want the most significant bit first; a few want the least significant first. The datasheet will say, usually in a timing diagram rather than in words.
On a real Uno the SPI peripheral can clock at up to 8 MHz, forty times faster than standard I2C. Mokxi’s ATmega328P model does not include that peripheral, so the matrix driver here toggles the pins in software, which the MAX7219 accepts at any speed. The wiring, the packets and the mode are what the real hardware peripheral would produce; only the clock rate is slower.
Common mistakes on the bench
Leaving chip select low for the whole program. Many chips, the MAX7219 included, act on the rising edge of CS, so a packet is not applied until CS goes high again. If nothing on the display changes, check that CS toggles around every packet.
Two devices with MISO driving at once. A well-behaved SPI chip releases MISO when it is not selected, but some modules (certain SD card adapters, for example) do not, and they corrupt every other device on the bus. A resistor or a tri-state buffer on that module’s MISO fixes it.
Long wires at high speed. SPI has no error checking, so a clock edge that rings on a 30 cm jumper can clock a bit twice. Keep the wires short, lower the clock with SPI.beginTransaction, or both.
Questions
SPI or I2C: which should I use?
Use whatever the chip supports. When a chip offers both, I2C saves pins (two wires for every device) and SPI is faster and simpler to debug. Displays that redraw a lot of pixels are usually SPI for the speed.
Which pins are SPI on an Arduino Uno?
Pin 13 is SCK, 11 is MOSI and 12 is MISO. Pin 10 is the usual chip select, and it must stay an output even if you use another pin for CS, or the Uno’s SPI hardware can drop into peripheral mode.
Can I chain several MAX7219 modules?
Yes. Each module’s DOUT goes to the next one’s DIN, and all share CLK and CS. A 16-bit packet shifted into the first chip comes out of its DOUT sixteen clocks later, so you send one packet per module before raising CS once.
Why is there no MISO wire in this circuit?
The MAX7219 never sends anything back, so it has no data out towards the controller. Many SPI output devices are write-only like this; sensors and memory chips use MISO.
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.