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