How to Configure SPI in Embedded C: Simple Guide
To configure
SPI in Embedded C, you need to set up the SPI control registers to define clock polarity, phase, speed, and data order, then enable the SPI module. This involves initializing the SPI pins, configuring the SPI control registers like SPCR, and enabling SPI with SPE bit.Syntax
SPI configuration typically involves setting bits in control registers to define how SPI works:
- SPCR: SPI Control Register to set clock polarity, phase, speed, and enable SPI.
- SPSR: SPI Status Register for speed doubling and status flags.
- SPDR: SPI Data Register for sending/receiving data.
Common bits in SPCR include:
SPR1, SPR0: Set SPI clock rate.CPOL: Clock polarity (idle state).CPHA: Clock phase (data sampling).MSTR: Master/Slave select.SPE: SPI enable.
c
SPCR = (1 << SPE) | (1 << MSTR) | (0 << CPOL) | (0 << CPHA) | (0 << SPR1) | (1 << SPR0); // Enable SPI, Master mode, clock rate fosc/16
Example
This example shows how to configure SPI as a master on an AVR microcontroller, send a byte, and wait for transmission to complete.
c
#include <avr/io.h> void SPI_MasterInit(void) { // Set MOSI, SCK, and SS as output, others as input DDRB |= (1 << DDB3) | (1 << DDB5) | (1 << DDB2); DDRB &= ~(1 << DDB4); // MISO as input // Enable SPI, Master mode, set clock rate fosc/16 SPCR = (1 << SPE) | (1 << MSTR) | (0 << CPOL) | (0 << CPHA) | (0 << SPR1) | (1 << SPR0); } void SPI_MasterTransmit(char data) { SPDR = data; // Load data into SPI data register while (!(SPSR & (1 << SPIF))) ; // Wait until transmission complete } int main(void) { SPI_MasterInit(); SPI_MasterTransmit(0x55); // Send 0x55 while(1) {} return 0; }
Output
No visible output; SPI sends byte 0x55 on MOSI line
Common Pitfalls
- Not setting the SPI pins direction correctly (MOSI, SCK, and SS as output for master).
- Forgetting to enable SPI by setting the
SPEbit. - Incorrect clock polarity (
CPOL) and phase (CPHA) causing data mismatch. - Not waiting for the transmission complete flag (
SPIF) before sending new data. - Confusing master and slave roles by wrong
MSTRbit setting.
c
/* Wrong: Not enabling SPI */ SPCR = (1 << MSTR); /* Right: Enable SPI and set master mode */ SPCR = (1 << SPE) | (1 << MSTR);
Quick Reference
| Register/Bit | Purpose | Typical Setting for Master |
|---|---|---|
| SPCR | SPI Control Register | Set SPE=1, MSTR=1, SPR0=1 for clock fosc/16 |
| SPSR | SPI Status Register | Check SPIF bit for transfer complete |
| SPDR | SPI Data Register | Write data to send, read received data |
| CPOL | Clock Polarity | 0 for idle low, 1 for idle high |
| CPHA | Clock Phase | 0 or 1 depending on slave device timing |
| MOSI Pin | Master Out Slave In | Set as output on master |
| MISO Pin | Master In Slave Out | Set as input on master |
| SCK Pin | Serial Clock | Set as output on master |
| SS Pin | Slave Select | Set as output on master to avoid SPI reset |
Key Takeaways
Always enable SPI by setting the SPE bit in the control register.
Configure SPI pins direction correctly: MOSI, SCK, and SS as output for master.
Set clock polarity and phase to match the slave device requirements.
Wait for the SPIF flag before sending new data to ensure transmission is complete.
Use the MSTR bit to select master or slave mode properly.