AVR-Lib

SPI as Master

The Serial Peripheral Interface (SPI) is a very common synchronous data interface. In normal setup the master and slave is connected with 4 signal lines.

Mnemonic

Name

Master Dir.

Slave Dir.

Description

CS

Chip Select

OUT

IN

Activates target slave

SCK

Clock Signal

OUT

IN

Clock signal for byte shifting

MOSI

Master Out, Slave In

OUT

IN

Data line from master to slave

MISO

Master In, Slave Out

IN

OUT

Data line from slave to master

Some devices which are working with data transfer in only one direction (e.g. sensors or actuators) have no MOSI or no MISO line. The Atmel ATMEGA can be used in master or slave configuration. The following is a driver for ATMEGA8 or ATMEGA168 in master mode.

spi.h

Download spi.h

Toggle line numbers
   1 #ifndef _SPI_H_
   2 #define _SPI_H_
   3 #include <avr/io.h>
   4 
   5 extern void spi_init();
   6 extern void spi_transfer_sync (uint8_t * dataout, uint8_t * datain, uint8_t len);
   7 extern void spi_transmit_sync (uint8_t * dataout, uint8_t len);
   8 extern uint8_t spi_fast_shift (uint8_t data);
   9 
  10 #endif /* _SPI_H_ */

spi.c

Download spi.c

Toggle line numbers
   1 #include "spi.h"
   2 #include <avr/io.h>
   3 #include <avr/interrupt.h>
   4 
   5 #define PORT_SPI    PORTB
   6 #define DDR_SPI     DDRB
   7 #define DD_MISO     DDB4
   8 #define DD_MOSI     DDB3
   9 #define DD_SS       DDB2
  10 #define DD_SCK      DDB5
  11 
  12 
  13 void spi_init()
  14 // Initialize pins for spi communication
  15 {
  16     DDR_SPI &= ~((1<<DD_MOSI)|(1<<DD_MISO)|(1<<DD_SS)|(1<<DD_SCK));
  17     // Define the following pins as output
  18     DDR_SPI |= ((1<<DD_MOSI)|(1<<DD_SS)|(1<<DD_SCK));
  19    
  20     SPCR = ((1<<SPE)|               // SPI Enable
  21             (0<<SPIE)|              // SPI Interupt Enable
  22             (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
  23             (1<<MSTR)|              // Master/Slave select   
  24             (0<<SPR1)|(1<<SPR0)|    // SPI Clock Rate
  25             (0<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
  26             (0<<CPHA));             // Clock Phase (0:leading / 1:trailing edge sampling)
  27 
  28     SPSR = (1<<SPI2X);              // Double Clock Rate
  29 }
  30 
  31 void spi_transfer_sync (uint8_t * dataout, uint8_t * datain, uint8_t len)
  32 // Shift full array through target device
  33 {
  34        uint8_t i;      
  35        for (i = 0; i < len; i++) {
  36              SPDR = dataout[i];
  37              while((SPSR & (1<<SPIF))==0);
  38              datain[i] = SPDR;
  39        }
  40 }
  41 
  42 void spi_transmit_sync (uint8_t * dataout, uint8_t len)
  43 // Shift full array to target device without receiving any byte
  44 {
  45        uint8_t i;      
  46        for (i = 0; i < len; i++) {
  47              SPDR = dataout[i];
  48              while((SPSR & (1<<SPIF))==0);
  49        }
  50 }
  51 
  52 uint8_t spi_fast_shift (uint8_t data)
  53 // Clocks only one byte to target device and returns the received one
  54 {
  55     SPDR = data;
  56     while((SPSR & (1<<SPIF))==0);
  57     return SPDR;
  58 }

Usage

Toggle line numbers
   1 // Allocate buffer array
   2     uint8_t data_buf[1];
   3 // Initialize SPI
   4     spi_init();
   5 // Send 0xFF to spi slave and read 1 byte back to the same array
   6     data_buf[0] = 0xFF;
   7     spi_transfer_sync(data_buf,data_buf,1);
   8 // Show received byte on LEDs
   9     PORTC = ~data_buf[0];

AVRLib/SPI (last edited 2008-04-06 13:34:28 by StefanEngelke)