Pages Menu
Categories Menu

Posted by on Nov 26, 2013 in Atmel AVR, Microcontrollers | 81 comments

The SPI of the AVR

The SPI of the AVR

Continuing with the series of tutorials on Serial Communication, here is another one, and much awaited, the Serial Peripheral Interface (SPI) of AVR! Before proceeding ahead, I would suggest you to read Mayank’s tutorial on the basics of SPI.


Serial Peripheral Interface (SPI) – Basics Revisited

Here we will discuss some basics of Serial Peripheral Interface (SPI, pronounced spy or ess-pee-eye). Mayank has already dealt with the basics of SPI and SPI bus transactions in the previous tutorial, but I will go over some of the nitty-gritties here again.

Serial Peripheral Interfacing is one of the most used serial communication protocols, and very simple to use! As a matter of fact, I find this one much simpler than USART! ;)

Since SPI has been accepted as a de facto standard, it is available in almost all architectures, including 8051, x86, ARM, PIC, AVR, MSP etc., and is thus widely used. This means that there shouldn’t be any portability issues and you can connect devices of two different architectures together as well!

So here are the most popular applications of SPI:

  1. Wired transmission of data (though the first preference is mostly USART, but SPI can be used when we are using multiple slave or master systems, as addressing is much simpler in SPI).
  2. Wireless transmissions through Zigbee, 2.4GHz etc.
  3. Programming your AVR chips (Yes! They are programmed through the SPI! You’ll would have read about it in Mayank’s Post on SPI).
  4. It is also used to talk to various peripherals – like sensors, memory devices, real time clocks, communication protocols like Ethernet, etc.

Advantages of SPI

SPI uses 4 pins for communications (which is described later in this post) while the other communication protocols available on AVR use lesser number of pins like 2 or 3. Then why does one use SPI? Here are some of the advantages of SPI:

  1. Extremely easy to interface! (It took me much less time to setup and transmit data through SPI as compared to I2C and UART!)
  2. Full duplex communication
  3. Less power consumption as compared to I2C
  4. Higher hit rates (or throughput)

And a lot more!

But there are some disadvantages as well, like higher number of wires in the bus, needs more pins on the microcontroller, etc.

Master and Slave

In SPI, every device connected is either a Master or a Slave.

The Master device is the one which initiates the connection and controls it. Once the connection is initiated, then the Master and one or more Slave(s) can transmit and/or receive data. As mentioned earlier, this is a full-duplex connection, which means that Master can send data to Slave(s) and the Slave(s) can also send the data to the Master at the same time.

As I said earlier, SPI uses 4 pins for data communication. So let’s move on to the pin description.

Pin Description

The SPI typically uses 4 pins for communication, wiz. MISO, MOSI, SCK, and SS. These pins are directly related to the SPI bus interface.

  1. MISO – MISO stands for Master In Slave Out. MISO is the input pin for Master AVR, and output pin for Slave AVR device. Data transfer from Slave to Master takes place through this channel.
  2. MOSI – MOSI stands for Master Out Slave In. This pin is the output pin for Master and input pin for Slave. Data transfer from Master to Slave takes place through this channel.
  3. SCK – This is the SPI clock line (since SPI is a synchronous communication).
  4. SS – This stands for Slave Select. This pin would be discussed in detail later in the post.

Now we move on to the SPI of AVR!

The SPI of the AVR

The SPI of AVRs is one of the most simplest peripherals to program. As the AVR has an 8-bit architecture, so the SPI of AVR is also 8-bit. In fact, usually the SPI bus is of 8-bit width. It is available on PORTB on all of the ICs, whether 28 pin or 40 pin.

Some of the images used in this tutorial are taken from the AVR datasheets.

SPI pins on 28 pin ATmega8

SPI pins on 28 pin ATmega8

SPI pins on 40 pin ATmega16/32

SPI pins on 40 pin ATmega16/32

Register Descriptions

The AVR contains the following three registers that deal with SPI:

  1. SPCR – SPI Control Register – This register is basically the master register i.e. it contains the bits to initialize SPI and control it.
  2. SPSR – SPI Status Register – This is the status register. This register is used to read the status of the bus lines.
  3. SPDR – SPI Data Register – The SPI Data Register is the read/write register where the actual data transfer takes place.

The SPI Control Register (SPCR)

As is obvious from the name, this register controls the SPI. We will find the bits that enable SPI, set up clock speed, configure master/slave, etc. Following are the bits in the SPCR Register.

SPCR Register

SPCR Register

Bit 7: SPIE – SPI Interrupt Enable
The SPI Interrupt Enable bit is used to enable interrupts in the SPI. Note that global interrupts must be enabled to use the interrupt functions. Set this bit to ‘1’ to enable interrupts.

Bit 6: SPE – SPI Enable
The SPI Enable bit is used to enable SPI as a whole. When this bit is set to 1, the SPI is enabled or else it is disabled. When SPI is enabled, the normal I/O functions of the pins are overridden.

Bit 5: DORD – Data Order
DORD stands for Data ORDer. Set this bit to 1 if you want to transmit LSB first, else set it to 0, in which case it sends out MSB first.

Bit 4: MSTR – Master/Slave Select
This bit is used to configure the device as Master or as Slave. When this bit is set to 1, the SPI is in Master mode (i.e. clock will be generated by the particular device), else when it is set to 0, the device is in SPI Slave mode.

Bit 3: CPOL – Clock Polarity
This bit selects the clock polarity when the bus is idle. Set this bit to 1 to ensure that SCK is HIGH when the bus is idle, otherwise set it to 0 so that SCK is LOW in case of idle bus.

This means that when CPOL = 0, then the leading edge of SCK is the rising edge of the clock. When CPOL = 1, then the leading edge of SCK will actually be the falling edge of the clock. Confused? Well, we will get back to it a little later in this post again.

CPOL Functionality

CPOL Functionality

Bit 2: CPHA – Clock Phase
This bit determines when the data needs to be sampled. Set this bit to 1 to sample data at the leading (first) edge of SCK, otherwise set it to 0 to sample data at the trailing (second) edge of SCK.

CPHA Functionality

CPHA Functionality

Bit 1,0: SPR1, SPR0 – SPI Clock Rate Select
These bits, along with the SPI2X bit in the SPSR register (discussed next), are used to choose the oscillator frequency divider, wherein the fOSC stands for internal clock, or the frequency of the crystal in case of an external oscillator.

The table below gives a detailed description.

Frequency Divider

Frequency Divider

The SPI Status Register (SPSR)

The SPI Status Register is the register from where we can get the status of the SPI bus and interrupt flag is also set in this register. Following are the bits in the SPSR register.

SPSR Register

SPSR Register

Bit 7: SPIF – SPI Interrupt Flag
The SPI Interrupt Flag is set whenever a serial transfer is complete. An interrupt is also generated if SPIE bit (bit 7 in SPCR) is enabled and global interrupts are enabled. This flag is cleared when the corresponding ISR is executed.

Bit 6: WCOL – Write Collision Flag
The Write COLlision flag is set when data is written on the SPI Data Register (SPDR, discussed next) when there is an impending transfer or the data lines are busy.

This flag can be cleared by first reading the SPI Data Register when the WCOL is set. Usually if we give the commands of data transfer properly, this error does not occur. We will discuss about how this error can be avoided, in the later stages of the post.

Bit 5:1
These are reserved bits.

Bit 0: SPI2x – SPI Double Speed Mode
The SPI double speed mode bit reduces the frequency divider from 4x to 2x, hence doubling the speed. Usually this bit is not needed, unless we need very specific transfer speeds, or very high transfer speeds. Set this bit to 1 to enable SPI Double Speed Mode. This bit is used in conjunction with the SPR1:0 bits of SPCR Register.

The SPI Data Register (SPDR)

The SPI Data register is an 8-bit read/write register. This is the register from where we read the incoming data, and write the data to which we want to transmit.

SPDR Register

SPDR Register

The 7th bit is obviously, the Most Significant Bit (MSB), while the 0th bit is the Least Significant Bit (LSB).

Now we can relate it to bit 5 of SPCR – the DORD bit. When DORD is set to 1, then LSB, i.e. the 0th bit of the SPDR is transmitted first, and vice versa.

Data Modes

The SPI offers 4 data modes for data communication, wiz SPI Mode 0,1,2 and 3, the only difference in these modes being the clock edge at which data is sampled. This is based upon the selection of CPOL and CPHA bits.

The table below gives a detailed description and you would like to refer to this for a more detailed explanation and timing diagrams.

SPI Data Modes

SPI Data Modes

The Slave Select (SS’) Pin

As you would see in the next section, the codes of SPI are fairly simple as compared to those of UART, but the major headache lies here: the SS’ pin!

SS’ (means SS complemented) works in active low configuration. Which means to select a particular slave, a LOW signal must be passed to it.

When set as input, the SS’ pin should be given as HIGH (Vcc) on as Master device, and a LOW (Grounded) on a Slave device.

When as an output pin on the Master microcontroller, the SS’ pin can be used as a GPIO pin.

The SS pin is actually what makes the SPI very interesting! But before we proceed, one question is that why do we need to set these pins to some value?

The answer is, that when we are communicating between multiple devices working on SPI through the same bus, the SS’ pin is used to select the slave to which we want to communicate with.

Let us consider the following two cases to understand this better:

  1. When there are multiple slaves and a single master.
    In this case, the SS’ pins of all the slaves are connected to the master microcontroller. Since we want only a specific slave to receive the data, the master microcontroller would give a low signal to the SS’ pin of that specific microcontroller, and hence only that slave microcontroller would receive data.
  2. When there are multiple masters and a single slave.
    A similar setup as above can be used in this case as well, the difference being that the SS’ lines of all the masters is controlled by the slave, while the slave SS’ line is always held low. The slave would select the master through which it has to receive data by pulling its SS’ high.Alternatively, a multiplexed system can be used where each master microcontroller can control every other master microcontroller’s SS’ pin, and hence when it has to transmit data, it would pull down every other master microcontroller’s SS’ Pin, while declaring its own SS’ as output.

You can also refer to this if you are still confused regarding Slave Select.

SPI Coded!

Up till now, we only discussed about the advantages, uses, and register description, hardware connections etc. of the SPI. Now lets see how we Code it!

Enabling SPI on Master

// Initialize SPI Master Device (with SPI interrupt)
void spi_init_master (void)
    // Set MOSI, SCK as Output

    // Enable SPI, Set as Master
    // Prescaler: Fosc/16, Enable Interrupts
    //The MOSI, SCK pins are as per ATMega8

    // Enable Global Interrupts

In the SPI Control Register (SPCR), the SPE bit is set to 1 to enable SPI of AVR. To set the microcontroller as Master, the MSTR bit in the SPCR is also set to 1. To enable the SPI transfer/receive complete interrupt, the SPIE is set to 1.

In case you don’t wish to use the SPI interrupt, do not set the SPIE bit to 1, and do not enable the global interrupts. This will make it look somewhat like this-

// Initialize SPI Master Device (without interrupt)
void spi_init_master (void)
    // Set MOSI, SCK as Output
    DDRB = (1<<5)|(1<<3);

    // Enable SPI, Set as Master
    //Prescaler: Fosc/16, Enable Interrupts
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);

When a microcontroller is set as Master, the Clock prescaler is also to be set using the SPRx bits.

Enabling SPI on Slave

// Initialize SPI Slave Device
void spi_init_slave (void)
    DDRB = (1<<6);     //MISO as OUTPUT
    SPCR = (1<<SPE);   //Enable SPI

For setting an microcontroller as a slave, one just needs to set the SPE Bit in the SPCR to 1, and direct the MISO pin (PB4 in case of ATmega16A) as OUTPUT.

Sending and Receiving Data

//Function to send and receive data for both master and slave
unsigned char spi_tranceiver (unsigned char data)
    // Load data into the buffer
    SPDR = data;

    //Wait until transmission complete
    while(!(SPSR & (1<<SPIF) ));

    // Return received data

The codes for sending and receiving data are same for both the slave as well as the master. To send data, load the data into the SPI Data Register (SPDR), and then, wait until the SPIF flag is set. When the SPIF flag is set, the data to be transmitted is already transmitted and is replaced by the received data. So, simply return the value of the SPI Data Register (SPDR) to receive data. We use the return type as unsigned char because it occupies 8 bits and its value is in the range 0-255.

Problem Statement

Enough of reading, time to get your hands dirty now! Get your hardware toolkit ready and open up your software. Let’s demonstrate the working of SPI practically.

Let’s assume a problem statement. Say the given problem statement is to send some data from Master to Slave. The Slave in return sends an acknowledgement (ACK) data back to the Master. The Master should check for this ACK in order to confirm that the data transmission has completed. This is a typical example of full duplex communication. While the Master sends the data to the Slave, it receives the ACK from the Slave simultaneously.


We would use the primary microcontroller (ATmega8 in this case) as the Master device, and a secondary microcontroller (ATmega16 in this case) as the Slave device. A counter increments in the Master device, which is being sent to the Slave device. The Master then checks whether the received data is the same as ACK or not (ACK is set as 0x7E in this case). If the received data is the same as ACK, it implies that data has been successfully sent and received by the Master device. Thus, the Master blinks an LED connected to it as many number of times as the value of the counter which was sent to the Slave. If the Master does not receive the ACK correctly, it blinks the LED for a very long time, thus notifying of a possible error.

On the other hand, Slave waits for data to be received from the Master. As soon as data transmission begins (from Master to Slave, the Slave sends ACK (which is 0x7E in this case) to the Master. The Slave then displays the received data in an LCD.

Hardware Connections

Hardware connections are simple. Both the MOSI pins are connected together, MISO pins are connected together and the SCK pins are also connected together. The SS’ pin of the slave is grounded whereas that of master is left unconnected. And then we have connected the LCD to the slave as well. Check Mayank’s tutorial on LCD interfacing. We also connect an LED to the master to demonstrate the SPI interrupt. Here are the schematics–

SPI Hardware Connections (Click to Enlarge)

SPI Hardware Connections (Click to Enlarge)

And here is how my final set up looks like–

Final Setup

Final Setup

Full Code

The codes for the Master and Slave are given below. The codes are well commented, so it should be easy to understand what is going on in the code. In case something doesn’t make sense, feel free to drop in a comment below. The full comments can viewed by scrolling the code sideways. You can also find the code in the AVR code gallery.

Master Code

#ifndef F_CPU
#define F_CPU 16000000UL

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

#define ACK 0x7E
#define LONG_TIME 10000

//Initialize SPI Master Device
void spi_init_master (void)
    DDRB = (1<<5)|(1<<3);              //Set MOSI, SCK as Output
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); //Enable SPI, Set as Master
                                       //Prescaler: Fosc/16, Enable Interrupts

//Function to send and receive data
unsigned char spi_tranceiver (unsigned char data)
    SPDR = data;                       //Load data into the buffer
    while(!(SPSR & (1<<SPIF) ));       //Wait until transmission complete
    return(SPDR);                      //Return received data

//Function to blink LED
void led_blink (uint16_t i)
    //Blink LED "i" number of times
    for (; i>0; --i)

int main(void)
    spi_init_master();                  //Initialize SPI Master
    DDRD |= 0x01;                       //PD0 as Output

    unsigned char data;                 //Received data stored here
    uint8_t x = 0;                      //Counter value which is sent

        data = 0x00;                    //Reset ACK in "data"
        data = spi_tranceiver(++x);     //Send "x", receive ACK in "data"
        if(data == ACK) {               //Check condition
            //If received data is the same as ACK, blink LED "x" number of times
        else {
            //If received data is not ACK, then blink LED for a long time so as to determine error
        _delay_ms(500);                 //Wait

Slave Code

#ifndef F_CPU
#define F_CPU 16000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "lcd.h"

#define ACK 0x7E

void spi_init_slave (void)
    DDRB=(1<<6);                                  //MISO as OUTPUT
    SPCR=(1<<SPE);                                //Enable SPI

//Function to send and receive data
unsigned char spi_tranceiver (unsigned char data)
    SPDR = data;                                  //Load data into buffer
    while(!(SPSR & (1<<SPIF) ));                  //Wait until transmission complete
    return(SPDR);                                 //Return received data

int main(void)
    lcd_init(LCD_DISP_ON_CURSOR_BLINK);           //Initialize LCD
    spi_init_slave();                             //Initialize slave SPI
    unsigned char data, buffer[10];
    DDRA  = 0x00;                                 //Initialize PORTA as INPUT
    PORTA = 0xFF;                                 //Enable Pull-Up Resistors
        lcd_clrscr();                             //LCD Clear screen
        lcd_home();                               //LCD move cursor to home
        data = spi_tranceiver(ACK);               //Receive data, send ACK
        itoa(data, buffer, 10);                   //Convert integer into string
        lcd_puts(buffer);                         //Display received data
        _delay_ms(20);                            //Wait


Here is short demonstration of how this setup operates.

Using Interrupts

In case you are interested in using the SPI Interrupt of the AVR, you should keep in mind the following things–

  • Be sure to include #include <avr/interrupt.h> header.
  • Set the SPIE bit to 1 in the SPCR register.
  • Enable global interrupts using sei().

Next thing is to write an Interrupt Service Routine (ISR), which can be written something like this–

// SPI Transmission/reception complete ISR
    // Code to execute
    // whenever transmission/reception
    // is complete.

If you want to know what are interrupts, may be this little introduction might be useful.


Let’s have a look what we have learnt in this post–

  • SPI is a serial communication protocol where all the devices are classified as either Master or Slave. It requires four pins to communicate – MISO, MOSI, SCK and SS’.
  • Almost every AVR microcontroller supports SPI and has some specific pins multiplexed with SPI functionality.
  • In AVR microcontrollers, the three registers which monitors the SPI are SPCR, SPSR and SPDR.
  • SPI has four data modes of operation.
  • Multiple slaves can be connected to the same SPI bus using Slave Select (SS’) pin.
  • We have also discussed how to program the SPI of an AVR with a relevant example featuring full duplex communication between two AVR microcontrollers.

So that’s it folks! In serial communication, we have discussed about RS232, UART/USART and SPI. Next is I2C! Subscribe to maxEmbedded so as not to miss upon any updates! Let us know your views, queries and comments through the text box at the end of this post.

Thank you.

Written by Yash Tambi and Mayank (Max) Prasad

Last updated on February 9, 2016


  1. thanks for your wonderful explanation . your code is just awesome..but i am facing some problem using multiple slaves with one master. data transmission from master to particular slave works fine but when a slave send some data master cannot read. i have tried all possible way but could not find any solution .can you give me any code where there is multiple slaves communicating with master…thanks

    • Hello Asif,
      When you send data from the master to the slaves, do all the slaves receive the data perfectly? Are you switching between the slaves properly using SS’? Have you made the right connections? Can you share the code that you tried to implement so that we can look into it and help you out if we could? To share the code, go to, paste your code there (use ‘C’ for syntax highlighting), and then share the link here.

      Thanks, Max.

      • sorry for my late reply…i was trying but could not access to this websites for couple of hours…yes when i send the data from master to slaves all slaves receive data perfectly and one of the slave also transmitting data perfectly. but i think switching is the problem..but i cant figure it out.
        this link for master

        this link for slave_1

        this link for slave_2

        i have used atmega32 for master and atmega16 for each slaves..

    • I am not able to connect to a single Slave
      with the same connections as described
      I am using two atmega 16 as master and slave
      so can you please help

      • So what’s your problem? Please give us some more information! Thanks!

  2. Hi
    thanks a lot for your helpful tutorials.
    i have a question :

    i think this command is true :

    and this one is wrong :

    because SPIF flag is set when transmission completed !
    but your code said that : transmission completed when SPIF flag is clear(0).


    • My bad.. I am sorry. The SPIF is set after the transmission/reception is complete.
      Youre Correct. Thanks for pointing out! :)

    • SPIF flag is set when transmission is completed.
      While(x) remains in loop as long as x is not zero.

      Using while(SPSR&(1<<SPIF)) would be zero and it would exit on first check. With while(!(SPSR&(1<<SPIF))) it's 1 as long as SPIF is zero and turns 0 when SPIF is set and transmission is completed, thus quiting the loop.

  3. Thanks for another great tutorial. I have learned a lot here. I am currently working on a project where I need to send multiple bytes in one transmission. I am wondering if you can point me in the direction of resources where I might learn to accomplish this?

    • Hi Devin,
      Do you want to transmit multiple bytes of data together (at the same time)? That would be kind of parallel communication. Or do you want multiple bytes to be sent one by one without breaking the transmission? In that case, you could perhaps use I2C, wherein in between start and stop sequences, you can transmit any number of bytes one by one.

      • Hi Mayank,
        Thank you for responding to my question. I apologize, I should have read further into the datasheet of the device I am trying to communicate with before I started asking questions. The devices’ manufacturer has header files to use in conjunction with developing the app that utilizes the device (VM800B display module made by FTDI, if you are curious). I believe these header files handle the transfer of Bytes to the device. I just have to figure out how to set up the API so the software knows how to access the SPI of my AVR (ATmega 328) The example application code from FTDI is developed for arduino, of which I really know nothing about, so I will have to figure out how to translate it for an AVR in Studio 6.1 . Any advice or suggestions on how I might quickly learn how to accomplish this would be greatly appreciated. Thank you.

  4. Great guide! Easy to read and understand. Cant wait to hook up my OLED and start writing some code.

    • Great! Let me know how it goes! :)

  5. hello Mayank! very good explanation there! i have pic18f45k22 and the transciever i am using is nRF24L01 for both MCU. one PIC is as a TX and other one as RX. i want to send data over RF but i dont know where to write the data in the program. i have the program code. the RF is working well such that when the TX is switch on, then the LED on the RX site lights up. when TX is disconnected the LED on RX gone. i just want to add up simple program like when i press button on the TX site, the LED on the RX will light up.. can u guide me please sir.. any help is much appreciated!

    • Before interfacing the RF modules, did you try to send and receive data over the SPI correctly? You’ll need to send the data from inside the while(1) loop like the one shown in the example above.

  6. Hello Mayank, i am a little confused here.Before, in hardware connections you say that ” Both the MOSI pins are connected together, MISO pins are connected together and the SCK pins are also connected together”. Now, when i check the schematic i see that the MOSI pin of ATmega8 (Master) is connected to the MISO (?) pin ATmega16(slave) and the MOSI pin of ATmega16 goes to MISO of ATmega8. I thought that they should be MOSI—–MOSI

    • Hi Lefteris,
      Yes you are correct, The MOSI goes to MOSI and the MISO goes to MISO. For more information regarding connections between two AVR Micro-controllers using SPI please see this.
      Hope this helps!

  7. Estimado Max, como puedo transferir datos tipo “float” mediante SPI

    • Dear Max, as I can transfer type “float” data through SPI

      • Yes you can. Computers can store only integers. In order for them to store floating point numbers, they need to convert it to integer.
        So ideally, whenever you store a float, it is actually a 32 bit integer data. You should be able to send this data directly through SPI. At the receiver’s end, make sure you read it into a float variable, and the rest is taken care of by the compiler. Read this and this about representing floats in memory.

        • but it is possible to send multiple data by the SPI port?

  8. Hi again , and thanks for the great post . in the schematic above mosi pin( from master) goes to miso(of the slave) and mosi( of the slave) goes to miso (of the master). I am a little confused .. shouldn’t mosi go to mosi and miso to miso? Thanks a lot

    • Yes, MOSI should go to MOSI and MISO should go to MISO. There’s a mistake and thanks for finding it out! I’ll correct it asap. :)

      • I was wondering though, if i don’t have a slave device to connect it to the micro-controller(master) can i connect the MOSI (of the master) to send data and the MISO pin (of the master again) to receive these data? In simple words, connect the MOSI pin to the MISO pin of the micro-controller like the USART topology loop-back test (Tx to Rx ) ?

        Thanks a lot for the great help

        • Theoretically, yes, it’s possible. Try it out.

          • Well, i tried it with an ATmega32 but nothing happens. The MOSI pin does not send the data i give . I tested it with an oscilloscope and no pulse comes out as i expected. Here is the simple code i tried:

          • You haven’t included any delays. Try that out.

  9. HI Max,
    I am a bit confused about how you control the slave.
    I have come across this one from the data sheet of atmeaga8

    “When configured as a Master, the SPI interface has no automatic control of the SS line. This
    must be handled by user software before communication can start”

    Can you please explain how you handled SS

    • Sohail,
      Check out the image here. The SS1′, SS2′ and SS3′ pins are just any other GPIO pins of the Master. Let’s say, in your Master device, SS1′ is PC0 pin, whereas SS2′ is PC1 pin. Then we write something like this:

      DDRC = 0x03; // PC0 and PC1 as output pins
      PORTC = 0x01; // SS2 device is selected (remember, active low)
      PORTC = 0x02; // SS1 device is selected (remember, active low)

      This is what they mean by no automatic control. You’ll need to explicitly specify in the software which device you’re talking to. Does that sound good to you?

      • Thank you Max,
        That is what I was looking for. My concern was that I couldn’t find it in the example master code or slave code, and that’s what caused the confusion.

  10. MAX Sir, Pleas show a tutorial for writing and burning program on 8051 or AT89c51 micro-controllers.

    • Hello Abhishek,
      Sorry, but out focus is not on 8051. 8051 is an outdated and obsolete microcontroller anyways.

      • but what about Atmel’s AT89C51 micro-controllers.

  11. Great job! I’d like to use the slave device (i.e. sensor, temperature sensor, etc) to send data to the master. What would be different with the code?



    • Nothing much. Just go for it!

  12. Code did not work. Should be

    while(!(SPSR &(1<<SPIF)));

    instead of


    • Really? Which code is it? I can’t find it anywhere.

  13. Max, your tutorials are awesome!! Good work. Well explained and of great basic knowledge.
    It makes me want to read all other articles you have posted…

    • Thanks!
      Keep reading :D

  14. I think there has been a mistake in your harware connections diagram where the atmega 8 SPI pins are connected in a misleading manner to the slave atmega16.
    I am notifying this because i tested the hardware connections and it seems to work only if you connect MOSI to MOSI and MISO to MISO.

    • Yes, thank you! Really appreciate that. Someone else brought this to our notice earlier as well, but we forgot about it. Thank you, we’ll add it to our to-do fixes list.

  15. I need C code to send data to LCD using SPI communication, atmega 128 ? Any idea ?

    • Open up the datasheet of the LCD and read through it!

  16. Ist I would like to thanks for this post, is too good. I already read SPI, but after reading your post, got something new with clear some doubts as well.

    I’m little bit confused, as I interfaced MAX7221 with ATmega32 (SPI mode), I need of SS’ pin to interface with slave device and configured in my programming as well.
    Now question is this, here in your sample code (ATmega8_Master, ATmega16 & LCD_Slave), why didn’t we use this pin LOW & HIGH for data transfer as I used SS’ LOW & HIGH with MAx7221.
    So when we use both AVR (microcontroller) as Single Master and Single Slave, then we don’t need to enable this SS’ pin or something else plz let me clear this issue with some example, if possible. thankx

    and here is little mistake, i think (CPHA Bit’s logic 1 & 0 is exchang)
    Bit 2: CPHA – Clock Phase
    This bit determines when the data needs to be sampled. Set this bit to 1 to sample data at the leading (first) edge of SCK, otherwise set it to 0 to sample data at the trailing (second) edge of SCK.

    • Hi Manish!

      Basically, when you have only one slave to interface with the master, you never really have to select a slave. There is only one slave, always. So, by grounding the SS’ pin on the slave by hard-wiring it to ground in such a setup means that that slave will always be selected, and that is okay since there is no other slave that we might want to select at any other point of time.

      And about the CPHA, it does select when the the data needs to be sampled, and is correctly explained in the post. When is set to 0, it samples at the leading edge, and when set to 1, it samples at the trailing edge. Check your resources maybe?

      Hope this helps!

  17. i am used above code but nothing show on LCD…any body help?

    • Are you sure you interfaced the LCD properly? Refer to the LCD tutorial to know more.

  18. hi thanks for such a great informative tutorial but i have issue to connect sd card with avr atmega 32/16/8 can u help me for interfacing sd card with any three controller thanks

    • sd card interfacing using spi protocol just i have to initlze the sd card nd want to write some data on sd card but confusion is how to implemnt code of sd card

  19. Hey Max,
    Is there any possibility of communicating with xbee module via android smartphone…?
    If yes then how can I possibly achieve it,I don’t need code,I’ll code it myself but just the concept and you are best at it :)

Leave a Reply

%d bloggers like this: