Introduction: Atmega32 - Atmega8 Master-Slave SPI Communication

About: DIY projects

The SPI is a very simply Synchronous Peripheral Interfacing(allows devices to send and receive data at the same time) is full duplex communication. This protocol is developed by Motorola. With this interface, one Master device which initiates and controls the communication, and one or more slaves who receive and transmit to the Master.

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

Applications of SPI:

  • Wired communication (multiple slave or master systems, as addressing is much simpler in SPI)
  • Wireless transmissions through Zigbee, Bluetooth etc.
  • Programming AVR chips
  • Various peripherals – like sensors, memory devices, real time clocks, communication protocols like Ethernet, etc.

Advantages of SPI:

  1. Easy to interface.
  2. Full duplex communication.
  3. Less power consumption as compared to I2C.
  4. Higher hit rates (or throughput).

SPI - 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. 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.

SPI - Pin Details: Pin positions may vary MCU to MCU according to architectures. But, Things are same...

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

Step 1: Serial Communication

. One data bit is transferred or received at a time.

Serial data can be transferred in two modes –

  • asynchronous and
  • synchronous.

Asynchronous:

  • Data Transfer is called Asynchronous when data bits are not “synchronized” with a clock line, i.e. there is no clock connected.
  • The first bit is always the START bit (which signifies the start of communication on the serial line), followed by DATA bits (usually 8-bits), followed by a STOP bit (which signals the end of data packet). There may be a Parity bit just before the STOP bit. The Parity bit was earlier used for error checking, but is seldom used these days.
  • The START bit is always low (0) while the STOP bit is always high (1).

Synchronous:

  • Synchronous data transfer is when the data bits are “synchronized” with a clock pulse.
  • The basic principle is that data bit sampling (or in other words, say, ‘recording’) is done with respect to clock pluses, as you can see in the timing diagrams.
  • Since data is sampled depending upon clock pulses, and since the clock sources are very reliable, so there is much less error in synchronous as compared to asynchronous.

Baud Rate: Baud commonly refers to bits per second.Different baud rates are available for use. The most common ones are 2400, 4800, 9600, 19200, 38400 etc.

Step 2: SPI-Register Details and Working Principle

SPI - Register Details:

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

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

SPI Control Register (SPCR):

This register controls the SPI. We will get bits that enable SPI, set up clock speed, configure master/slave, etc.

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

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

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 fOSCstands for internal clock, or the frequency of the crystal in case of an external oscillator.

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.

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.

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.

The 7th bit is 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.

SPI-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.

SPI-Slave Select (SS) Pin

SS’ (means SS complemented) works in active low configuration, 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.

Joining multiple slave is a issue, so I will discuss it later, but my motive is to start working in SPI with some basic idea.

Step 3: SPI Working in Details

Working Principle:

Master-Function()---->---[Master(send data)]------->-------->--------[(receive data)Slave]----->------Slave-Function()

Master-Slave Configurations:
1. Cascaded slaves:-

Figure: "m-s.jpg"

2. Parallel slave:-

Figure: "m-s-p.jpg"

SPI DATA TRANSMISSION

1) The master outputs the clock signal:-

fig: "m1.png"

2) The master switches the SS/CS pin to a low voltage state, which activates the slave:-

fig: "m2.png"

3) The master sends the data one bit at a time to the slave along the MOSI line. The slave reads the bits as they are received:

fig: "m3.png"

4) If a response is needed, the slave returns data one bit at a time to the master along the MISO line. The master reads the bits as they are received:

fig: "m4.png"

ADVANTAGES

  • No start and stop bits, so the data can be streamed continuously without interruption
  • No complicated slave addressing system like I2C
  • Higher data transfer rate than I2C (almost twice as fast)
  • Separate MISO and MOSI lines, so data can be sent and received at the same time

DISADVANTAGES

  • Uses four wires (I2C and UARTs use two)
  • No acknowledgement that the data has been successfully received (I2C has this)
  • No form of error checking like the parity bit in UART
  • Only allows for a single master

Step 4: Code and Implementation

Circuit is connected as above diagram.

Coding as below:-

Enabling SPI on Master

// Initialize SPI Master Device (with SPI 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
    //The MOSI, SCK pins are as per ATMega8

   SPCR=(1<<SPE)|(1<<MSTR);

 // Enable Global Interrupts  
 sei();
}

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.

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

  return(SPDR);
}

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.