2
\$\begingroup\$

For a project I want to have two microcontrollers talk to each other via an SPI interface. I wrote the following code for the slave:

volatile uint8_t data;

void spi_init_slave (void)
{
 DDRB=(1<<PINB4);               //MISO as OUTPUT
 SPCR=(1<<SPE)|(1<<SPIE);       //Enable SPI && interrupt enable bit
 SPDR=0;
}

uint8_t SPI_SlaveReceive(void)
{      
  /* Wait for reception complete */
  while (!(SPSR & (1<<SPIF)))   ;
  /* Return data register */
  return    SPDR;
}

ISR(SPI_STC_vect)
{
  uint8_t y = SPI_SlaveReceive();
  PORTD = y;
}

int main(void)
{
    DDRD = (1<<PIND0) | (1<<PIND1) | (1<<PIND2) | (1<<PIND3) | (1<<PIND4);
    spi_init_slave();                             //Initialize slave SPI

    sei();
    while(1)
    {

    }
}

The master is sending a number which the slave displays using the LEDs attached to port D. I'm using an Atmega8P for this project.

\$\endgroup\$
  • \$\begingroup\$ Above code is working now, fixed typo. \$\endgroup\$ – BoboProg Apr 19 '14 at 11:17
5
\$\begingroup\$

The most apparent problem I can see is the following line:

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

Is missing a less than sign and should include (1<<SPIE) to enable the SPI interrupt. Note that the current expression (1<SPIE) will be equivalent to the boolean expression (1 < 7) which will result in a value of 1. So that also means at the moment you'll be setting SPR0 for a speed of fosc/16 on the master.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ You've made my day. Thanks! Only the slave doesn't have to "match" the speed of the master. Quoted atmel datasheep pp 126: "Bits 1, 0 – SPR1, SPR0: SPI Clock Rate Select 1 and 0. These two bits control the SCK rate of the dev ice configured as a Master. SPR1 and SPR0 have no effect on the Slave." \$\endgroup\$ – BoboProg Apr 19 '14 at 11:15
  • \$\begingroup\$ Ahh yes good point of course I re-worded that part. \$\endgroup\$ – PeterJ Apr 19 '14 at 11:21
2
\$\begingroup\$

I know this is a year old, but I thought I would just point out that when I tried implementing your code, the interrupt routine was only firing every other SPI transfer.

I believe this is because of this line:

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

when you actually want:

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

Hopefully that saves someone else some of the time I spent scratching my head.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

I used also your source code. My slave got only every 2 message. The cause was this line in the SPI_SlaveReceive function:

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

This is only important when you use SPI by polling. If you want to use SPI communication controlled by interrupts - slave side, delete this line.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Better late than never right ? Just had the same problem myself, and none of the answers above is correct execpt the one above me.

The function "uint8_t SPI_SlaveReceive(void)" is meant to be used in main. to have it interrupt driven you just need to read the SPDR directly in your isr.

ISR(SPI_STC_vect) { uint8_t y = SPDR; PORTD = y; }

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.