Electronic – SPI between ATmega32 and ATmega328 is not working

atmegaatmega328pavr-gccspi

I have been trying to accomplish connecting ATmega32 and ATmega328 using SPI

Hardware connections:

ATmega328     ATmega32 
master        slave
------------------
 MISO    ->   MISO
 MOSI    ->   MOSI
  SCK    ->   SCK
   SS    ->   SS

I have added some code to blink LEDs after each step to recognize if a particular step is completed.

When connected, the LED connected to master blinks once while LED connected to the slave doesn't blink at all.

What have I done wrong?

Thanks for any advice.

Code for atmega328 master

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

//Initialize SPI Master Device
void spi_init_master (void)
{
    DDRB = (1<<PORTB5)|(1<<PORTB3)|(1<<PORTB2);   // Set MOSI, SCK , SS as Output
    SPCR = (1<<SPE)|(1<<MSTR);                    // Enable SPI, Set as Master
}

//Function to send and receive data
unsigned char spi_tranceiver (unsigned char data)
{
    PORTB &= ~(1<<PINB2); //sending low signal to activate slave
    SPDR = data;                         // Load data into the buffer

    while(!((SPSR)&(1<<SPIF)));          // wait till transmission complete

    PORTC |= (1<<PINC4);
    _delay_ms(1000);
    PORTC &= ~(1<<PINC4);
    _delay_ms(1000);

    return(SPDR);                        // Return received data
}


//Main
int main(void)
{
DDRC |= (1<<PINC4);
spi_init_master();
unsigned char t = spi_tranceiver(6);
for(unsigned char i=1;i<=t;i++){
    PORTC = (1<<PINC4);
    _delay_ms(500);
    PORTC &= ~(1<<PINC4);
    _delay_ms(500);
}
}

Code for ATmega32 slave

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>

void spi_init_slave (void);
unsigned char spi_tranceiver (unsigned char data);

unsigned char lo; 

int main(void)
{
    DDRD |= (1<<PD7);
    spi_init_slave();
    while (1) 
    {
        lo = spi_tranceiver(3);
        for(unsigned char i=1;i<=lo;i++) {
            PORTD |= (1<<PD7);
            _delay_ms(100);
            PORTD &= ~(1<<PD7);
            _delay_ms(100);
       }
    }
}

// Initialize SPI Slave Device
void spi_init_slave (void)
{
    DDRB &= ~(1<<PINB5);   // Set MOSI as input
    DDRB |=  (1<<PINB6);   // Set MISO as output
    DDRB &= ~(1<<PINB4);   // SS as input
    SPCR  =  (1<<SPE);     // Enable SPI
}

unsigned char spi_tranceiver (unsigned char data)
{
// Load data into the buffer
SPDR = data;
//Wait until transmission complete
while(!(SPSR & (1<<SPIF) ));
PORTD |= (1<<PD7);
_delay_ms(100);
PORTD &= ~(1<<PD7);
_delay_ms(100);
// Return received data
return(SPDR);
}

Best Answer

After posting my problem on AVR Freaks, I was able to solve the problem. I hadn't set SCK on slave as input and SPI clock rate was not set properly. I set clock rate to f/64 where f refers to the CPU frequency of the master. I would like to mention couple of things here for being noted by future visitors.

  • If your SPI is not working, first check what is the SPI clock rate. If it's too fast or slow, it won't work.
  • Check if you have declared the pins of the SPI module correctly on the master and slave. MISO should be set to input and the rest to output on the master. On the slave, MISO should be set as output and the rest as input.
  • If both these don't work for you, then focus on more advanced things like CPOL, CPHA. Using a logic analyzer to debug will help in this case.