[solved] SPI datatransfer

Hello everyone,

I am having trouble understanding the data transfer via SPI.

I looked at the SPI example from Nick Gammon (very well done) and read a few articles. The example worked great.

My basic understanding is, that the data I want is gathered the second time the transfer() is called:
sending ('a') -> returns a byte in the buffer (garbage)
sending ('X') -> returns the byte which command 'a' handled one iteration ago

Long story short, here is my code

Master:

#include <Arduino.h>
#include <Wire.h>

const byte BUFSIZE = 32;
/*
  Master
*/

#include <SPI.h>

void setup (void) {
  Serial.begin (9600);
  Serial.println("--- Master ---");

  digitalWrite(SS, HIGH);  // ensure SS stays high for now

  // Put SCK, MOSI, SS pins into output mode
  // also put SCK, MOSI into LOW state, and SS into HIGH state.
  // Then put SPI hardware into Master mode and turn SPI on
  SPI.begin ();

  // Slow down the master a bit
  SPI.setClockDivider(SPI_CLOCK_DIV8);


}  // end of setup

byte transferAndWait (const byte what)
{
  byte a1 = SPI.transfer(what);
  delayMicroseconds (20);
  return a1;
} // end of transferAndWait

byte* SPI_send(const byte* b, byte size) {

  // enable Slave Select
  digitalWrite(SS, LOW);
  for(byte i=0; i<size; i++) {
    SPI.transfer(b[i]);
    delay(10);
  }

  // disable Slave Select
  digitalWrite(SS, HIGH);


}

void SPI_clear() {
  digitalWrite(SS, LOW);
  SPI.transfer('\0');
  SPI.transfer('\0');
  digitalWrite(SS, HIGH);
}

void loop (void) {

  byte send,res;


  digitalWrite(SS, LOW);
  send = 'a';
  res = SPI.transfer(send); // garbage byte
  Serial.print ("garbage -> "); Serial.println (res);
  delay(2500);
  send = 'a';
  res = SPI.transfer(send); // last transfer is here
  Serial.print ("a(97): (65) -> "); Serial.println (res);
  delay(2500);

  digitalWrite(SS, HIGH);

  delay(1000);
  SPI_clear();

  Serial.println("");
  delay(10000);




}  // end of loop

Slave:

#include <Arduino.h>
#include <Wire.h>

/*
  SLAVE
*/

void setup (void) {

  Serial.begin(9600);
  Serial.println("--- Slave ---");
  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);

  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // turn on interrupts
  SPCR |= _BV(SPIE);

  // Serial.print("SPDR: "); Serial.println(SPDR);

}  // end of setup


// SPI interrupt routine
byte remember = '\0';
ISR (SPI_STC_vect) {
  byte c = SPDR;
  Serial.print("interrupt: "); Serial.print(c); Serial.print("\tsending: "); Serial.print(remember);
  Serial.print("\tremember: ");

  SPDR = remember;

  if(c=='a') {
    Serial.println("A(65)");
    remember = 'A';
    // SPCR = 'M';
  } else if(c=='b') {
    Serial.println("B(66)");
    remember = 'B';
  } else if(c=='c') {
    Serial.println("C(67)");
    remember = 'C';
  } else if(c=='\0') {
    Serial.println("Null(0)");
    remember = '\0';
  } else {
    Serial.println("Z(90)");
    remember = 'Z';
  }

  Serial.println(" ");



}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void) {

  // if SPI not active, clear current command
  if (digitalRead (SS) == HIGH) {
    command = 0;
  }

  // delay(5);
}  // end of loop

The idea is that the command 'a' sends 'A' back to the master. Therefore I store the variable I want to send next in 'remember' and set SPDR=remember the next time it is called.

The output of the master reads:

garbage -> 0
a(97): (65) -> 0

where the output of the slave reads:

interrupt: 97	sending: 0	remember: A(65)    -> 1. Iteration (should remember 65) 
interrupt: 88	sending: 65	remember: Z(90)    -> 2. Iteration (should send 65) 
interrupt: 0	sending: 90	remember: Null(0)    --> clear statement 
interrupt: 0	sending: 0	remember: Null(0)    --> clear statement

What am I missing here?

Thanks for the help

Hello,

SPI interface allows to transmit and receive data simultaneously on two lines (MOSI and MISO)

SPI Transfer Modes

SPI transfer is based on a simultaneous send and receive: the received data is returned in receivedVal (or receivedVal16). In case of buffer transfers the received data is stored in the buffer in-place (the old data is replaced with the data received).

Arduino - SPITransfer

The word simultaneously through me off, because it was the second transfer which retrieved the data.

I stored the data for the next iteration and did not treat it as the same transfer process.

Thanks for reminding me to read more carefully.

P.s.: I noticed that there is a chapter named 'networking', this thread should go there

byte* SPI_send(const byte* b, byte size) {

  // enable Slave Select
  digitalWrite(SS, LOW);
  for(byte i=0; i<size; i++) {
    SPI.transfer(b[i]);
    delay(10);
  }

  // disable Slave Select
  digitalWrite(SS, HIGH);


}

You lied. You said that this function would return a pointer to a byte. It does NOT.

Why do you care what the response is when sending one byte, even though you know it might be garbage, but not when sending multiple bytes?

Take it easy @PaulS or else you may have a heart attack! :wink:

I wouldnt say that I lied. Either the functionality will be added later or I just defined it wrong.

The function 'SPI_send' is intended to just send data (length unknown). Another function checks if the Slave is done with its calculation (0-2s). I have to add another function 'SPI_receive' where I read a byte array from the SPI and interpret the result on the master.