Problem about SPI transferring byte data with nano

First i got 2 arduino nano to test for SPI(master and slave)

Then i copy the code from this post

it is fine when transferring "Hello World" only

so i edited some of its code to directly transfer byte instead
and i can see what is the actual data transferring with a software

but i can't get the right value from the slave received

here is my code

For master side:

#include <SPI.h>
uint8_t p[4];
void setup (void) {
   Serial.begin(115200); //set baud rate to 115200 for usart
   digitalWrite(SS, HIGH); // disable Slave Select
   SPI.begin ();
   
   //SPI.setClockDivider(SPI_CLOCK_DIV2);//divide the clock by 8
   p[0]=0x12;
   p[1]=0x32;
   p[2]=0x53;
   p[3]=0xAB;
}

void loop (void) {
   char c;
   digitalWrite(SS, LOW); // enable Slave Select
   // send test string
   
   SPI.beginTransaction(SPISettings(8000000,MSBFIRST,SPI_MODE0));
   {
   SPI.transfer (0x12);
   SPI.transfer (0x32);
   SPI.transfer (0x53);
   SPI.transfer (0xAB);
   }
   SPI.endTransaction();
   digitalWrite(SS, HIGH); // disable Slave Select
   Serial.print("SEnt");
   delay(2000);
}

=========================================================
For Slave side:

#include <SPI.h>
byte buff [50];
volatile byte indx;
volatile boolean process;

void setup (void) {
   Serial.begin (115200);
   pinMode(MISO, OUTPUT); // have to send on master in so it set as output
   SPCR |= _BV(SPE); // turn on SPI in slave mode
   indx = 0; // buffer empty
   process = false;
   
   SPI.attachInterrupt(); // turn on interrupt
}
ISR (SPI_STC_vect){ // SPI interrupt routine {
  
   byte c = SPDR; // read byte from SPI Data Register
   //
   if (indx < sizeof buff) {
      buff [indx++] = c; // save data in the next index in the array buff
      if (c == 0xAB) //check for the end of the word
      process = true;
   }
   
   Serial.print("Output:");
   Serial.println(c,HEX);
}

void loop (void) {

   if (process) {
      process = false; //reset the process
      
      Serial.print (buff[0],HEX); //print the array on serial monitor
      Serial.print (buff[1],HEX); //print the array on serial monitor
      Serial.print (buff[2],HEX); //print the array on serial monitor
      Serial.println (buff[3],HEX); //print the array on serial monitor
      indx= 0; //reset button to zero
   }
}

=================================================

Cause i can't get the last byte with 0xAB ,so i just print out instantly to see what it got.

so my master side sent 0x12 0x32 0x53 0xAB
but my slave constantly get 0x57 and 0x65

when i alter my softer to see the data with cpha = 1
it somehow can read the byte as 0x25 0x65 0xA7 0x57
which contains the wrong data that slave side receive.

i don't know if it is my code wrong or i should alter the setting on slave side

Please help

The attached file contains some theory and few examples (1-byte, 3-byte, and float) which may help you to understand the data exchange mechanism between two Arduino using SPI Port. After that, it is hoped, you will be able to correct your sketch of post #1.
Ch-8SPILec.pdf (352.5 KB)

Did you see this:

Your Read byte (0x25 0x65 0xA7 0x57) equal
1 + double your Send bytes (0x12 0x32 0x53 0xAB)

Perhaps you are reading twice for every send?

The settings of master and slave must match. Try without begin/endTransaction?

This indicates that the SPDR already has shifted in another bit. The constant +1 is not related to sent data, it looks like the idle state of the MOSI signal from a SPI mode mismatch (wrong clock polarity).

That document does not match the shown signals (MOSI...).

Also, Serial.print in an ISR may give or cause misleading results.

Are these results from your logic analyser?
If you configure it with the wrong spi mode (clock phase) you will get strange results.

@uveuvenouve

Try with the following (your sketch slightly adjusted) Slave sketch:

#include <SPI.h>
byte buff [4];  //4-byte to receive
volatile byte indx = 0;
volatile boolean process = false;

void setup ()
{
  Serial.begin (115200);
  pinMode(MISO, OUTPUT); // have to send on master in so it set as output
  SPCR |= _BV(SPE); // turn on SPI in slave mode
  SPI.attachInterrupt(); // turn on interrupt
}

void loop ()
{
  if (process) 
  {
    process = false; //reset the process

    Serial.println (buff[0], HEX); //print the array on serial monitor
    Serial.println (buff[1], HEX); //print the array on serial monitor
    Serial.println (buff[2], HEX); //print the array on serial monitor
    Serial.println (buff[3], HEX); //print the array on serial monitor
  }
}

ISR (SPI_STC_vect)
{
  buff[indx] = SPDR; // read byte from SPI Data Register
  indx++;
  if (indx == 4)
  {
    indx = 0;
    process = true;
  }
}

thank you

but i have found another cause that make my spi data transfer failed

Everything works now when the clock speed below 8Mhz
even i set 7999999 ,they work normally

When i set the clock speed at right 8Mhz
wrong data is read

So, is the fact that i bought a bad condition arduino board?
or it is not suggested to run that close at the maximum speed clock?

Try with the following moderated (your sketch) Master sketch:

#include <SPI.h>
//uint8_t p[4] = {0x12, 0x32, 0x53, 0xAB};

void setup ()
{
  Serial.begin(115200); //set baud rate to 115200 for usart
  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
  SPI.begin ();
  digitalWrite(SS, LOW); // enable Slave Select
}

void loop ()
{
  byte x1 = SPI.transfer (0x12);
  byte x2 = SPI.transfer (0x32);
  byte x3 = SPI.transfer (0x53);
  byte x4 = SPI.transfer (0xAB);
  Serial.println("Frame is Sent.");
  delay(2000);
}

If you have long wires for the SPI bus and your logic analyser is still connected, this may cause transmission errors at higher speeds.

Is SPI a bus in the same sense that I2C is a bus?

This is really another topic but SPI bus is quite a common term. The main differences between SPI and I2C are the addressing of peripherals and the direction of data flow on the data wire(s).

1 Like

Devices on a bus share signals but further individual signals may be part of a bus as well.

1 Like

may i ask another question here?

i am trying to test a device as master. and arduino to be slave to receive a 32bit data

i used the old way byte by byte to read but not work

and i take a look with the logic analyser
the only different between my device sending 32 bit data and arduino sending 4x 8bit data is the clock have no space between 8 bit data

i tried only assign a 32bit variable to get the data but not work too
like this

uint32_t c = SPDR;

If you are sending a 32bit number to an Arduino using SPI you have to send it as 4 separate bytes and join these together on the Arduino.
There are various methods for doing this. You can use a union between a byte array and a unit32_t variable, you can use bit shifting or some non-trivial pointer arithmetic.
You can also look at this format of the spi.transfer command:

SPI.transfer(buffer, size)

At the best of your practice, does the above buffer transmission code work?

SPI is a byte oriented protocol; where, only one byte (8-bit) can be exchanged during one port cycle. To transmit 32-bit data, it has to be split into 4-bytes and then to follow sketch similar to post #9.

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