Spi between two 328p

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I'm trying to transfer data between two atmega 328p (arduino uno board). I have made a small program understand how SPI work. I need it for a bigger project. 

Here is the code on slave and master  : 

 

Master :

#include "Arduino.h"

void setup(){

  DDRB = (1 << 3) | (1 << 5) | (1<<2); // Set MOSI, SCK and SS as Output
  DDRB &= ~(1<<4); //set MISO as INPUT
  PORTB &= ~(1 << 2); // SS Low

  //SPi,interup and master
  SPCR = (1<<SPE)| (1 << SPIE) |(1<<MSTR);

  char clr;
  clr=SPSR;
  clr=SPDR;
  SPDR = 40;  //start
  Serial.begin(9600);

}

ISR(SPI_STC_vect){
  uint8_t val;

  val=SPDR;

  Serial.print(val); //should display 250
  Serial.print("\n");

  SPDR = 12;
}

void loop(){
}

Slave : 

#include "Arduino.h"
//SLAVE
void setup(){

  DDRB = (1 << 4);                 //MISO as OUTPUT

  SPCR = (1 << SPE) | (1 << SPIE); //enable spi and interupt

  Serial.begin(9600);

}

ISR(SPI_STC_vect){

  uint8_t val;

    val = SPDR;

    Serial.print(val); //should display 12
    Serial.print("\n");

    SPDR = 250;

}
void loop(){

}

 

Sadly, both boards display "12".  

Am I doing something wrong ? 

 

Thanks in advance.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My understanding of the SPI protocol is that the slave only responds to the master, hence SPDR won't contain 250 until after the master has transmitted 12.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try sending a dummy byte from SPI master after the first byte, to read out a byte from the slave.

 

Tom

signature

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't see an sei() anywhere. Does Arduino need it?

 

Second, I don't think that you are continuing to clock the SPI during the return time. The master HAS to provide the clock during all transfers, whether they originate from the master or from the slave. You don't put 250 into the slave data register until AFTER the data from the master is received. So, have the master send the data byte, then one more; the second only serves to transfer the slave's data back to the master. 

 

You CAN put 250 into the slave data register, before hand, and have it waiting there for action by the master. Then, while the master is sending, the slave will also be sending, and you will have your double transfer with one 8-bit clock burst and the second clock burst described in the preceding paragraph is not needed.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Sun. Feb 10, 2019 - 01:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1. Only master sends values.

2. The wire between SS pins is not needed when there is only one slave. Still the master SS pin should be configured as output. Slave SS is configured as input and wired to GND.

3. Command "SPDR = byte" on the master side causes that SPDR registers in master and slave exchange their values. The same command in slave only writes a value to SPDR with no further action.

 

Example

Suppose we want to send number 3 to the slave and we want the slave to multiply received number by 4 and return the result to master. In slave SPDR register is zero.

In master we write "SPDR = 3". The communication starts and numbers in SPDR-slave and SPDR-master are exchanged.

Now we have number 3 in slave and 0 in master. Master is not interested about this number so it only waits a moment.

In slave an interrupt is fired. In ISR we read SPDR value, multiply it by 4 and write the result back to SPDR.

Master sends a dummy byte, say 255. Registers again exchange. Then we have number 255 in the slave and 12 (3x4) in master.

Master reads SPDR and prints the result.

 

// MASTER

uint8_t val=1, recval;
//-------------------------------------------
void setup(){

  DDRB = (1 << 3) | (1 << 5) | (1<<2); // Set MOSI, SCK and SS as Output
  PORTB &= ~(1 << 2); // SS Low
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);  //divider 128
  Serial.begin(9600);
}
//--------------------------------------------
void loop()
{
    SPDR = val++;  // send 'val' and increment  (sends 1, 2, 3...)
    delay(1);
    SPDR = 0xff;   // send a dummy byte
    delay(1);
    recval = SPDR; // read slave answer

    Serial.println(recval);                      // prints 4, 8, 12...
    delay(1000);
}
// SLAVE
// connect pin SS to GND

ISR(SPI_STC_vect)
{
uint8_t rec_byte;
  rec_byte = SPDR;
  delayMicroseconds(10);
  SPDR = rec_byte*4;
}
//---------------------------
void setup()
{
  DDRB = (1 << 4);  // MISO as OUTPUT
  SPCR = (1 << SPE) | (1 << SPIE); //enable spi and interupt
  interrupts();
}
//---------------------------
void loop(){}