1

We're trying to use SPI to communicate with another IC using an atmel atmega328 MCU. The target IC takes a command (the header in the code) and then feeds us back the information stored in the requested register (or writes to it if the command is a write). However, we're having two problems here:

  1. Nothing comes out of the SPI, the only change is on the CS line (which we control). No SPI clock, no data on the data lines.

  2. The first iteration of the for loop when writing the header the program does not enter the while loop (The LED on port 6 won't turn on).

Any help with this would be much appreciated, code provided down below.

#define DDR_SPI DDRB
#define DD_MISO DDB4
#define DD_MOSI DDB3
#define DD_SCK DDB5
#define DD_SS DDB6

void SPI_MasterInit(void)
{
    /* Set MOSI, SCK and CS output, all others input */
    DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
    /* Enable SPI, Master, set clock rate = System clock / 16 */
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}

int readfromspilow(uint16 headerLength, const uint8 *headerBuffer, uint32 readLength, uint8 *readBuffer)
{


    PORTB &= ~(1 << PORTB6);                // Set CS low

    for(int i=0; i<headerLength; i++)
    {
        SPDR = headerBuffer[i];             //Send entry i of the header to the spi register
        sleep_us(5);                        // Give the flag time to reset, might be unnecessary
        PORTD |= (1 << PORTD5);             //LED for diagnostics
        while(!(SPSR & (1<<SPIF))){         //Wait for SPIFinished flag
            PORTD |= (1 << PORTD6);         //LED for diagnostics
        }

        PORTD &= ~(1 << PORTD3);            //LED for diagnostics



        //readBuffer[0] = SPDR; // Dummy read as we write the header
    }

    for(int i=0; i<readLength; i++)
    {
        SPDR = 0xFF;                        // Dummy write as we read the message body
        sleep_us(5);                        // Give the flag time to reset, might be unnecessary
        while(!(SPSR & (1<<SPIF)));         //Wait for SPIFinished flag
        readBuffer[i] = SPDR ;              //Store the value in the buffer
    }

    PORTB |= (1 << PORTB6);                 // Set CS high


    return;
}

Edit: Added the defines for the initialization

Sebastian
  • 11
  • 1
  • 6
  • How you use this later in code? what are DDR_SPI and others? bits match? does while loop for waiting SPI to finish stops? – unalignedmemoryaccess Apr 04 '17 at 07:44
  • We simply call the readfromspilow with the required command as a header (Address and such to the register we wish to read) and the length of the expected answer as read length, with a point for the buffer to store the read answer. I added the defines for the SPI with an edit, not sure what you mean with "bits match?". The while gets skipped the first iteration (no idea why), but then it's stuck in it the next iteration (presumably because the SPI never signals done) – Sebastian Apr 04 '17 at 08:23

3 Answers3

1

According to the manual 19.5.2

Alternatively, the SPIF bit is cleared by first reading the SPI Status Register with SPIF set, then accessing the SPI Data Register (SPDR).

Your code does not do this so maybe there's a flag set which never gets cleared. Try to change the code to:

volatile uint8_t spsr = SPSR;       //Dummy-read the flag register to clear flags
SPDR = headerBuffer[i];             //Send entry i of the header to the spi register
PORTD |= (1 << PORTD5);             //LED for diagnostics
while(!(SPSR & (1<<SPIF))){         //Wait for SPIFinished flag
  PORTD |= (1 << PORTD6);           //LED for diagnostics
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
0

Your code seems to be correct, but due to you're not using the SPI Interrupt handler, you need to clear the SPIF bit in the SPSR before you are sending data via SPDR. The SPDR doesn't accept any data with a SPIF flag set.

fisehara
  • 176
  • 1
  • 10
0

We solved it, the problem was that the default SS on port B2 need to be defined as an output in the initialization stage, otherwise the MCU can change to Slave operation mode if the pin is left floating. This sets the SPIF-flag to 1 every time it happens, which messed with our checks.

Sebastian
  • 11
  • 1
  • 6