Writing an OS Kernel from Scratch | 349: SPI Bus — High-Speed Serial Communication
Abstract: SPI is a higher-speed serial bus compared to I2C, commonly used with Flash storage, displays, sensors, and more. This article details SPI’s four modes, protocol timing, the Linux spidev driver, and its application in Flash storage.
1. SPI Protocol: Four-Wire Full-Duplex
1.1 Signal Lines
SPI has 4 core signal lines (sometimes multiple CS lines):
Master Slave
┌──────┐ ┌──────┐
CLK ─┤ ├────────────────┤ ├── CLK
MOSI ─┤ ├────────────────┤ ├── MOSI (sometimes called SDO)
MISO ─┤ │◄───────────────┤ ├── MISO (sometimes called SDI)
CS ──┤ ├────────────────┤ ├── CS
└──────┘ └──────┘- SCLK / CLK: Clock line, generated by Master
- MOSI (Master Out Slave In): Data from master to slave
- MISO (Master In Slave Out): Data from slave to master
- CS / SS: Chip select line, can have multiple, each selects one slave
1.2 Full-Duplex vs. Half-Duplex
SPI is full-duplex: While the Master sends 1 bit, the Slave returns 1 bit. So SPI’s actual throughput is 2× the clock frequency (each data line transfers 1 bit per clock).
Clock: ─┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──
└──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘
MOSI: ──[D7]──[D6]──[D5]──[D4]──[D3]──[D2]──[D1]──[D0]
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
MISO: ──[R7]──[R6]──[R5]──[R4]──[R3]──[R2]──[R1]──[R0]
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
MSB first, each bit sampled on clock rising or falling edge (configurable)1.3 Four Modes (Mode 0/1/2/3)
SPI has 4 modes, determined by two parameters:
| Mode | CPOL (Clock Polarity) | CPHA (Clock Phase) | Idle Clock | Sample Edge |
|---|---|---|---|---|
| Mode 0 | 0 | 0 | Low | Rising |
| Mode 1 | 0 | 1 | Low | Falling |
| Mode 2 | 1 | 0 | High | Falling |
| Mode 3 | 1 | 1 | High | Rising |
Mode 0 (CPOL=0, CPHA=0):
SCLK: ____________/
└──┘└──┘└──┘
MOSI: ─[D7]──[D6]──
↑ Sample (rising edge)
MISO: ─[R7]──[R6]──
Mode 1 (CPOL=0, CPHA=1):
SCLK: ____________/
└──┘└──┘└──┘
MOSI: ─[D7]──[D6]──
↑ Sample (falling edge)Different slave devices use different modes. Always check the datasheet. A common mistake is assuming all SPI devices are compatible with Mode 0, but many sensors prefer Mode 3.
2. Flash Storage: SPI’s Home Turf
2.1 NOR Flash vs. NAND Flash
SPI NOR Flash vs. NAND Flash:
SPI NOR Flash NAND Flash
Interface SPI Parallel (8/16-bit)
Read speed Fast (random access) Fast (sequential)
Write speed Slow Fast (page-based)
Erase Sector (4KB) Block (128KB+)
Density Low (< 512Mb) High (> 1Gb)
Application Boot, code storage Mass storage
XIP (Execute in Place) Yes No
SPI NOR is commonly used:
- Boot ROM for embedded devices
- Firmware storage
- Configuration data
- FPGA configuration (bitstream)2.2 Linux spidev Usage
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int main() {
int fd = open("/dev/spidev0.0", O_RDWR);
// Configure SPI mode and speed
uint8_t mode = SPI_MODE_0;
uint32_t speed = 10000000; // 10 MHz
uint8_t bits = 8;
ioctl(fd, SPI_IOC_WR_MODE, &mode);
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
// Transfer data
uint8_t tx[4] = {0x03, 0x00, 0x00, 0x00}; // Read command
uint8_t rx[4] = {0};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = 4,
.speed_hz = speed,
.delay_usecs = 0,
.bits_per_word = bits,
};
ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
close(fd);
return 0;
}
Comments