AVR SPI Master in C: Driving 74HC595 Shift Registers with SPCR and SPDR

The Serial Peripheral Interface (SPI) is a fast, synchronous bus used by SD cards, flash memories, displays, ADCs and many sensors. The AVR has a hardware SPI module that can shift out a byte in as little as two CPU clocks per bit, far faster than toggling pins in software.

In this tutorial you will configure the ATmega328P SPI as a master and use it to drive two 74HC595 serial-in, parallel-out shift registers. Three wires give you 16 extra outputs, and more chips can be chained for more. The same SPI functions work with any SPI slave device later.

How SPI Works

SPI uses four signals: SCK (clock, from master), MOSI (master out, slave in), MISO (master in, slave out) and SS or chip select (active low, one per slave). The master generates eight clock pulses per byte; on each pulse one bit leaves on MOSI and one bit arrives on MISO, so sending and receiving happen at the same time. The two data registers of master and slave effectively form one 16-bit circular shift register.

Clock polarity (CPOL) and clock phase (CPHA) define four SPI modes. Mode 0 (CPOL = 0, CPHA = 0) keeps SCK low when idle and samples data on the rising edge. The 74HC595 shifts on the rising edge of its shift clock, so mode 0 is correct for it.

SignalATmega328P pinUno pinATmega16/32 pin
SSPB2 (DIP 16)D10PB4
MOSIPB3 (DIP 17)D11PB5
MISOPB4 (DIP 18)D12PB6
SCKPB5 (DIP 19)D13PB7

SPI Registers

RegisterBitMeaning
SPCRSPESPI enable
SPCRMSTR1 = master mode
SPCRDORD0 = MSB first, 1 = LSB first
SPCRCPOL, CPHASPI mode selection
SPCRSPR1, SPR0Clock rate: 00 = f/4, 01 = f/16, 10 = f/64, 11 = f/128
SPSRSPI2XDoubles the SPI clock (f/2 possible)
SPSRSPIFSet when a transfer completes
SPDR-Write to start a transfer, read to get received byte

74HC595 Wiring

The 74HC595 has an 8-bit shift register and a separate 8-bit storage (latch) register. Data shifts in without disturbing the outputs; a rising edge on the latch pin then copies all eight bits to the outputs at once, so LEDs do not flicker during shifting. The QH' pin outputs the bit shifted out of the last stage, which feeds the next chip in a chain.

74HC595 pinNameConnection
14SER (data in)Chip 1: MOSI (PB3). Chip 2: QH' of chip 1
11SRCLK (shift clock)SCK (PB5), both chips
12RCLK (latch)PB2, both chips
13OE (output enable, active low)GND
10SRCLR (clear, active low)+5 V
9QH' (serial out)SER of the next chip
15, 1 to 7QA to QHLEDs through 330 Ω resistors to GND
16 / 8VCC / GND+5 V / GND, with 100 nF decoupling

Here PB2 serves both as SS (so it is an output, satisfying the master-mode rule) and as the latch signal. MISO is not used because the 74HC595 sends nothing back. Note that on an Uno, PB5 also drives the on-board LED, which will flicker during transfers.

Program: 16-LED Knight Rider Pattern

Hardware SPI master driving two chained 74HC595 chips (ATmega328P, 16 MHz)
#define F_CPU 16000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>

#define LATCH_PIN PB2              /* also the SPI SS pin */

static void spi_master_init(void)
{
    /* MOSI, SCK and SS as outputs; MISO stays input */
    DDRB |= (1 << DDB3) | (1 << DDB5) | (1 << DDB2);
    PORTB &= ~(1 << LATCH_PIN);

    /* Enable SPI, master, mode 0, MSB first, f/16 = 1 MHz */
    SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
    SPSR = 0;                      /* SPI2X off */
}

/* Send one byte and return the byte received at the same time */
static uint8_t spi_transfer(uint8_t data)
{
    SPDR = data;                   /* start transmission */
    while (!(SPSR & (1 << SPIF)))  /* wait for completion */
        ;
    return SPDR;                   /* reading SPDR clears SPIF */
}

/* Write 16 bits to two chained 74HC595s */
static void shift_out16(uint16_t value)
{
    spi_transfer(value >> 8);      /* goes to the far chip (chip 2) */
    spi_transfer(value & 0xFF);    /* stays in the near chip (chip 1) */
    PORTB |= (1 << LATCH_PIN);     /* rising edge copies to outputs */
    PORTB &= ~(1 << LATCH_PIN);
}

int main(void)
{
    spi_master_init();

    while (1) {
        for (uint8_t i = 0; i < 16; i++) {      /* move right to left */
            shift_out16((uint16_t)1 << i);
            _delay_ms(60);
        }
        for (int8_t i = 14; i > 0; i--) {       /* and back */
            shift_out16((uint16_t)1 << i);
            _delay_ms(60);
        }
    }
}

How the Code Works

SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); enables SPI in master mode with the clock divided by 16, giving 1 MHz at 16 MHz. The 74HC595 can run much faster on a breadboard, but a modest clock is more tolerant of long jumper wires. Clearing CPOL and CPHA selects mode 0, and DORD = 0 sends the most significant bit first.

Writing to SPDR starts the transfer immediately. The loop waits for SPIF, and reading SPDR afterwards both returns the received byte and completes the flag-clearing sequence. With two chips in a chain, the first byte sent ends up in the far chip because it is pushed through the near one by the second byte. After both bytes, a pulse on RCLK latches all 16 outputs simultaneously.

To connect a real SPI slave such as an SD card or an MCP3008 ADC, use a separate GPIO as its chip select, pull it low before spi_transfer() calls and high afterwards, and check the device datasheet for the required SPI mode and maximum clock.

Troubleshooting

  • SPI stops working after the first byte: SS (PB2) is an input and floated low, so the module dropped to slave mode.
  • Outputs show the right pattern on the wrong chip: the bytes are sent in the wrong order for your chain.
  • Random LEDs light at power-up: the 74HC595 registers start in an undefined state. Send zeros early in main(), or drive OE from a pin and keep it high until the first latch.
  • Programming the AVR fails with the 595s connected: the ISP also uses MOSI, MISO and SCK. Heavy loads on these pins can disturb programming; keep loads light or add series resistors.

Summary

The AVR SPI master is set up with SPE, MSTR, the mode bits and a clock divider in SPCR. A write to SPDR starts a full-duplex transfer that completes when SPIF is set. Keep SS as an output in master mode. With 74HC595 shift registers on the bus, three pins drive any number of outputs, latched cleanly by RCLK.