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
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
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
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];