SPI Communication synchronization

atmegaavrcspi

I am trying to transmit data from one Microcontroller (ATMega8A default clock frequency) to another Microcontroller (ATMega16 16MHz-crystal).

I have setup ATMega16 as master with

DDRB |= (1 << DDB7) | (1 << DDB5); //Set MOSI, SCK as Output
SPCR |= (1 << SPE) | (1 << MSTR) | (1<<SPIE) | (1 << SPR0);//Enable SPI, Set as Master

I have a receive function

 unsigned char ReceiveData(unsigned char Data)
 {
     SPDR = Data;
     while(!(SPSR & (1<<SPIF) ));
     return(SPDR);
}

The SS' pin of ATMega8A (slave) is connected to PB3 and in the main loop I have

for(;;)
{
    PORTB &= ~(1<<PB3); //clear SS' of slave
    Data = ReceiveData(0x05); //sending dummy 0x08 to slave;
    if(Data == 0x08)
        //TOGGLE(SOME_PORT,SOMEPINWITHLED); toggle #defined
    _delay_ms(200);
    PORTB |= (1<<PB3);
}

In the slave device I have

int main() // slave main module
{
     DDRB |= (1<<DDB4); //MISO as OUTPUT
     SPCR |= (1<<SPE); //Enable SPI
     DDRB |= (1<<DDB0);
     char Data = 2, SendValue = 8;
     for(;;)
     {
          TOGGLE(PORTB,PB0); // #define'd TOGGLE(A,B) A ^= (1<<B);

          Data = SendData(SendValue); // exact same as ReceiveData() on master.
     }
     return 0;
}              

The led doesn't toggle at the master module but does at the slave module. Could you suggest me what have I done wrong here. May be the master and slave are not synchronized.

  1. Should I check `while(!(SPSR & (1 <<SPIF) ));` on the slave or `SPDR = Data; return (SPDR);` is sufficient on the slave.
  2. How does the master know when the slave is sending data? So, when should maser check `while(!(SPSR & (1 <<SPIF) ));`?

P.S: In the future I plan to use multiple slaves and a single master.

Edit : I corrected from DDRB |= (1 << DDB3) | (1 << DDB5);

Best Answer

The only problem I can find is the initialization of the SPI port on the Master, plus the use of ReceiveData.

On the Master, you as setting B3 and B5 as outputs. But according to this document for the ATmega16, SS = PB4, MOSI = PB5, MISO = PB6, and SCK = PB7 and your SS is PB3. So you should have:

DDRB |= (1 << DDB3) | (1 << DDB5) | (1 << DDB7);

And according to this document for the ATmega8, SS = PB2, MOSI = PB3, MISO = PB4, and SCK = PB5. You should have PB4 configured as an output for MISO, and you do.

I'm not sure what you're using PB0 for, if it is to synchronize the two processors its unneeded.

Your method of sending and receiving data in ReceiveData is correct and should be used for both the Master and Slave (from the previous transmission).

Remember every time you send a byte, you get a byte back from the other end.