Learning SPI

SPI Background

SPI and Synchronous Serial

SPI is a particular type of synchronous serial. We'll start by discussing the characteristics of synchronous serial.

Serial vs. Parallel

Serial (as opposed to Parallel) means one bit (1 or 0) is placed on the bus (wire or wires) at a time.

Synchronous serial vs. Asynchronous serial

With asynchronous serial, such as RS-232, the receiver is responsible for figuring out exactly when a bit should be read from the bus. To do this microcontrollers typically use a timer, and kept track of how much time has elapsed since some synchronization event. At certain time intervals the value on the bus is sampled.

With synchronous serial, things are more straightforward. We are explicitly told when we should read the data line. To do this, another wire is added (for a total of 2 wires). This other wire, called the clock (CLK) line, tells us when to read the data line.

How the clock line tells us when to read the data line

There are several ways in which the clock line could tell us when to read the data line. For example, maybe we should read the data line whenever the clock line is a logic 1. A better way is to use the "edge," or "transition" between logic states to indicate that the data line should be read. This has the advantage of being a single event -- a single snapshot in time -- rather than a region of time. This reduces any ambiguity about when exactly the data line should be read.

Rising edge or Falling edge?

The rising edge (also called positive edge, or posedge) is when the state changes from a low to a high (o to a 1). The falling edge (also called negative edge, or negedge) is when the state changed from a high to a low (1 to 0). In SPI, data is only ever valid (should be read) on either the rising or falling edge. Which one it is - rising or falling edge - depends on the implementation. For existing parts and systems, you'll have to look it up (typically in a datasheet). In some applications you may have the flexibility to use either -- you'll need to pick one, and then make sure everyone sticks to the standard.

Synchronization - which bit belongs to which byte?

We know when to read a bit, but how do we know which bit we are reading? In other words, how do we synchronize? The most straightforward way to synchronize is to use a 3rd wire. Ahead of time, we decide that a rising (or falling) edge of that wire will be our synchronization event. Typically this wire is called enable (or reset, but it's the same idea.) It allows the different parts of a system to synchronize -- to revert to a known starting state.

Enable and Disable

The enable line is used for synchronization - but it usually also serves another purpose. Its state (0 or 1) indicates if something should be enabled or disabled. For example, maybe you don't need a particular device to be running all the time. You may be able to disable it, putting it into a low power mode. In SPI, this has the added benefit of choosing which device you want to talk to. You simply disable all the devices except the one you want to talk to.

A simple implementation of synchronous serial -- the Shift Register

In practice, shift registers are often used in the implementation of SPI.

Point to point connection

There are many possible ways in which synchronous serial could be used with more than two devices. One simple way is that each pair of devices that needs to communicate has dedicated connections. Notice however, that the number of connections you need quickly becomes unmanageable. So this isn't a great solution.

Bus

A bus is a collection of wires, shared by many devices. Notice that a bus uses far fewer connections. However there are some limitations.

Only one device can "talk" at a time

If two devices talk at a time, this is a "bus collision". Imagine what happens if one device outputs a 0 at the same time as another device outputs a 1. This is a short circuit!

  • A device needs some way of knowing is someone is already talking on the bus.
  • The bus needs to recover from potential conflicts, and have a way to figure out who gets to go first

While a bus topology like the one shown is very powerful, it requires electrical and protocol-level complexity to deal with the issues raised above. It's not ideal for very cheap and simple devices.

The SPI way

SPI uses a bus, but makes a few compromises to make things very simple.

Only one master

In SPI, only one of the devices is in charge. It alone decided who can on the bus. Furthermore, devices can only talk to the master device, they can't talk to each other.

The lowly slaves

All other devices on the SPI are called slaves.

Choosing which Slave gets to talk with the Master

In SPI, the master uses an enable line for each and every slave. In this way the master can select which slave is active. Generally speaking only one slave can be active at a time.

SS or EN

In SPI, the enable line is usually called SS (slave select) or EN (enable). It's all the same thing.

Enable (EN or SS) is active low

The SPI enable line is almost always inverted: 1 means disabled, and 0 means enabled.

Communications with the active slave

MOSI

In SPI, the master has a dedicated data output line, called MOSI (master out, slave in). All the slaves listen on this line, but ignore it if they are not active. In SPI, data is typically sent most significant bit first. (MSB first)

MISO

The master also has a dedicated data input line, called MISO (master in, slave out). Only the active slave is allowed to transmit on this line. All the other slaves MUST transition to high-z mode when they are not active - i.e. they may not drive the line. This is the function of a tri-state buffer. In SPI, data is typically sent most significant bit first. (MSB first)

CLK

Since this is synchronous serial, there needs to be a clock, which is typically called CLK. The clock is used with both the MOSI and MISO data lines.

The unspecified details

SPI leaves a couple things unspecified. For sample, should a slave read the MOSI line on CLK's rising edge, or its falling edge?

Clock polarity and phase - CPOL and CPHA

Datasheets specify the previously mentioned details in terms of clock polarity (CPOL) and clock phase (CPHA).

Clock polarity (CPOL) is the state of the clock at the moment a slave's enable line becomes active. CPOL=0 means that the clock is low (0) as the slave becomes enabled. CPOL=1 means the clock is high (1) when the slave becomes enabled.

At some point after a slave becomes active, the clock will transition for the first time. If the data on MOSI and MISO should be read on this first edge, the Clock Phase (CPHA) is 0.

Alternatively, if data on MOSI and MISO should be read the 2nd time the CLK changes, the Clock Phase (CPHA) is 1.

CPOL = 0, CPHA = 0

  • CLK starts out LOW
  • MOSI/MISO is read on each RISING edge of CLK.

CPOL = 0, CPHA = 1

  • CLK starts out LOW
  • MOSI/MISO is read on each FALLING edge of CLK.

CPOL = 1, CPHA = 0

  • CLK starts out HIGH
  • MOSI/MISO is read on each FALLING edge of CLK.

CPOL = 1, CPHA = 1

  • CLK starts out HIGH
  • MOSI/MISO is read on each RISING edge of CLK.

SPI Variations / Settings

Clock Polarity & Clock Phase

The SPI variations you'll typically need to worry the most about is the clock polarity and clock phase discussed above.

Bit Rate

The bit rate is the fastest speed the CLK line will operate at. This can vary wildly with the application, from a few hundred bits per second, to many tens of MHz. Since the CLK line provides us when to read the data line, there is no significant difference in how things operate, assuming all the devices can keep up.

Bit Order

Data is sent over the SPI most significant bit first. However, you may find yourself using SPI code or a SPI hardware peripheral with synchronous serial that isn't strictly SPI.

Bits per transfer/word

In most applications data sent over and SPI is byte oriented. However, there is no fast rule in this area, so technically any number of bits could comprise a word. SPI synchronizes using the Enable (or SS) line - there is no delimiter to specify when one word ends and the next begins.

Enable/Slave Select polarity

SPI applications typically use logic 0 as the active state for the enable line. For synchronous serial more generally, this could easily be the other way around.