SPI Full Duplex (Professional Code Error)

Thanks Cam , i will do this as requested and come back to you

The complexity is the root of the defiance, I suspect.

1 Like

Putting the hardware connections aside, there a some things to know/understand about what you are trying to do.

SPI slave devices such as SRAM, FLASH, I/O Expanders etc have dedicated SPI hardware that can operate very fast. When you are attempting to be an SPI slave and stuffing bytes into the SPDR, it takes a small finite amount of time for the slave device to do this. The master device needs to take this into account by introducing a small delay between each SPI transfer to allow the slave time to load up the next byte for transmission.

SPI exchanges data bidirectionally simultaneously. When the master clocks out a byte (MOSI), it is simultaneously clocking in a byte (MISO) too.

When the slave SPI interrupt triggers, to say a byte has been received, the master has already received 1 byte from the slave. This will be whatever data was already in the SPDR. Your slave code loads the first response byte into the SPDR after the first command byte has been received.

Your master will receive that first response byte when it sends out the second TX byte to the slave. If you want to send 4 bytes to the master this way, then the master needs to send out 5 bytes in order to get the 4 bytes back it wants.

Hopefully some of that made sense...!

2 Likes

HI Mark

That does make total sense, so if i add some bytes from the master to the slave that is 1 byte more than im receiving, as the slave will always send more bytes to the master, i can ignore the bytes i dont want.

What im trying to achieve is the master will send 8bit values i.e. 0 or 1, the slaves, they will use those values in if statements, for example.

if (x == 1) {
do something
} 

if x == 0 {
do something
} 

The slaves all transmit Sensor data , ADC data, etc 8/16/32 bit values to the master.

In simple terms!

Or, transfer 5 bytes each way, but recognize that the last byte from the master is meaningless, as is the first byte from each slave.

Thanks Guys, this is good stuff.

one last thing from me before i start playing with the code, is the code i have been provided with actually correct , im still concerned the code is not right , causing further issues

After looking at some of the master/slave code at

this worked for me with two Unos:

Master

#include <SPI.h>

#define SLAVE_1_CS 10

byte S1_data_out[] = { 0x76, 0x54, 0x32, 0x10 };

byte S1_data_in[] = { 0, 0, 0, 0 };

void setup() {
   Serial.begin(115200);
   digitalWrite(SLAVE_1_CS, HIGH);
   pinMode(SLAVE_1_CS, OUTPUT);
   SPI.begin();
   delay(5000);
}

void loop() {
  Slave_1_tr(S1_data_out, sizeof S1_data_out);     //send content of packet length 3, and recieve its data
  print_response(S1_data_in, sizeof S1_data_in);  //print data whose length is slave_1_data_len
  delay(2000);
}

void Slave_1_tr(uint8_t *Data_to_send, uint8_t command_length) {
  digitalWrite(SLAVE_1_CS, LOW);

  SPI.transfer(Data_to_send[0]);
  delayMicroseconds(10);
  for (int i = 1; i < command_length; i++) {
    S1_data_in[i-1] = SPI.transfer(Data_to_send[i]);
    delayMicroseconds(10);
  }
  S1_data_in[command_length-1] = SPI.transfer((byte)0);

  digitalWrite(SLAVE_1_CS, HIGH);
}

uint16_t rxCount = 0;

void print_response(uint8_t *data, uint8_t length) {
   Serial.print(++rxCount);
   Serial.print(": ");
   for (uint8_t i = 0; i < length; i++) {
      if( data[i] < 0x10 ) {
         Serial.print('0');
      }
      Serial.print(data[i], HEX);
   }
   Serial.println();
}

Slave

#include <SPI.h>

uint8_t txData[] = { 0xAB, 0xCD, 0x12, 0x34, 0 };
uint8_t rxData[5];
volatile bool flag = false;
volatile int index = 0;

void setup() {
   Serial.begin(115200);
   pinMode(MISO, OUTPUT);
   bitSet(SPCR, SPE);      // board is Slave
   bitSet(SPCR,SPIE);      // turn on interrupts
}

uint16_t rxCount = 0;
void loop() {
   if( flag ) {
      Serial.print(++rxCount);
      Serial.print(": ");
      for (int i = 0; i < 4; i++) {
         if( rxData[i] < 0x10 ) {
            Serial.print('0');
         }
         Serial.print((unsigned)rxData[i], HEX);
      }
      Serial.println();
      flag = false;
   }
}

ISR(SPI_STC_vect) {
   rxData[index] = SPDR;
   SPDR = txData[index];
   index++;
   if (index >= 5 || rxData[index-1] == 0) {
      index = 0;
      flag = true;
   }
}

The delayMicroseconds(10) in the master send code were necessary to get the slave's response and not just an echo of what had been sent. Mind you, my setup was 2 Unos sitting on a desk with hookup wires of several inches length between them, so that's not entirely unexpected.

1 Like

Van_der

You are my hero!!! i can expand this code.

Just hooked this up, the values are coming through nicely!!

I cant thank you enough.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.