SPI not working, ATmega328 only sending 1 byte

atmegaavrmicrocontrollerspi

I am trying to get SPI working on an ATmega328. This is my code:

#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<<PORTB5)|(1<<PORTB3);              //Set MOSI, SCK 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)
{
    PORTC = 1<<PORTC2;
    PORTC = 0<<PORTC2;

    SPDR = data;                       //Load data into the buffer
    while(!(SPSR)&(1<<SPIF));
    return(SPDR);                      //Return received data
}


//Main
int main(void)
{
    DDRC= 0XFF; 
    spi_init_master();
    spi_tranceiver(6); 
    //spi_tranceiver(6);
    //spi_tranceiver(6); 


}

This is the output from the logic analyzer:

enter image description here

Notice those two comment lines. spi_tranceiver(6); If I remove those comments, I should get, from the logic analyzer:

  • 3 times the amount of clock pulses for the blue layer.
  • 3 times the amount of data sent, and;
  • 3 times the amount of PORTC2 pules.

This is not the case. I get the below:

enter image description here

The device I am trying to SPI with isn't configured correctly. Does this matter?

Best Answer

It looks like you have the parantheses in the wrong spot while waiting for the SPI transaction to complete. Because the ! operator has a higher precedence than & it will be trying to do a bitwise not of the SPSR register first. Instead you want something like this:

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

At the moment presumably that wait is returning immediately so the SPDR register is getting set three times in rapid succession without enough time for the data to be transferred.