I've been struggling for 3 weeks looking for a solution to my problem concerning SPI communication.
So, I need to establish a SPI communication between two Arduino devices: for instance, the master sends a letter 'a' to the slave; the slave receives it and does some processing. In my case, it should set one of his 8 pins to high then read all pins and send the report back to the master.
The part where the master sends 'a' and the slave processing it works fine but the master doesn't seem to receive the correct values. Instead it always receives 0.
Here's the code:
Slave:
#include <SPI.h>;
volatile byte command = 0;
byte ett =8; //nbr of test points
byte motif= 0b000000000 ; //intiatition of my varible which will contain my pin's states
byte end[8] = { 2,3,4,5,6,7,8,9}; //array containing the pins
void setup (void) {
Serial.begin (9600);
// 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);
} // end of setup
// SPI interrupt routine
ISR (SPI_STC_vect) {
byte c = SPDR;
switch (command) {
//////////////Slave traitement/////////////
// no command? then this is the command
case 0:
command = c;
SPDR = 0;
break;
case 'z': ////case 'z", set all pins to INPUT
for (int i=0; i<8; i++){
pinMode (end[i], INPUT);
}
break;
case 'a': // //if 'a' : Set one pin to high then read all pin's satete to verify if there is any open circuit or short circuit
for (int j = 0; j < ett; j++) {
pinMode(end[j], INPUT); // set all pins as INPUT
}
motif = 0;
pinMode(end[0], OUTPUT); // Set one pin as OUTPUT
digitalWrite(end[0], HIGH); // Set the output pin to HIGH
Serial.println();
Serial.print(" ");
for (int k = 0; k < ett ; k++) { // scan
if (digitalRead(end[k]) == HIGH) {
// if pin == HIGH add '1' to my vector
Serial.print("| ");
motif = motif + 1; // +1
} else { // if pin == LOW
Serial.print(". ");
}
motif = motif << 1; // shift left
}
Serial.print(" -MOTIF LU= ");
Serial.print(motif, BIN);
SPDR = byte (motif); //SPDR is the SPI Data Register: it contains the data that will be sent to the Master
Serial.print(" ");
break;
}
}
void loop (void) {
// if SPI not active, clear current command
if (digitalRead (SS) == HIGH)
command = 0;
}
Master:
#include <SPI.h>
byte CS0=10;
byte CS1=9;
void setup (void) {
Serial.begin (9600);
Serial.println ();
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 a = SPI.transfer (what);
delayMicroseconds (1000);
return a;
} // end of transferAndWait
///traitement au niveau du maitre
void loop (void) {
byte esclave0_testpin0;
/////////////Set the first slave's pin to High then read all pins
digitalWrite (CS0,LOW); //activate the slave
transferAndWait ('a'); // set first slave's pin to high
esclave0_testpin0 = transferAndWait ('z'); //read all slave's pins and report it in the variable esclave0_testpin0
digitalWrite (CS0,HIGH); //disactivate the slave
Serial.println ("test_0");
Serial.println (esclave0_testpin0, BIN);
delay (1000); // 1 second delay
} // end of loop
-
Double check your SPI protocol. Is the order correct? A state machine might help understand the sequencing. Also avoid Serial print in ISRs.Mikael Patel– Mikael Patel2017年03月22日 13:23:59 +00:00Commented Mar 22, 2017 at 13:23
-
Some tips: 1) use ctrl-t to autoformat, 2) use { and } consequently regarding new lines, 3) use more clear variable names (also for loop iterators), 4) Write also comments in code in English, 5) motif = motif + 1 , more c is motir++;Michel Keijzers– Michel Keijzers2017年03月22日 14:12:10 +00:00Commented Mar 22, 2017 at 14:12
-
@MichelKeijzers : Thank you for the tips, but "motif =motif +1"works in my program; i'll add a screenshot of the simulation.The display on the slave monitor is correct. I made a short circuit between the first and the second pins and i i've got " -MOTIF LU= 11000000 ".Saha222– Saha2222017年03月23日 14:10:29 +00:00Commented Mar 23, 2017 at 14:10
-
@MikaelPatel: wrote my code based on this link [gammon.com.au/forum/?id=10892&reply=2#reply2] (Part: How to get a response from a slave) . I tested its code and it worked very well. I did not change anything except the process at the slave level: instead of adding or subtracting I read the state of the slave's pins and report it to the master.Saha222– Saha2222017年03月23日 14:11:39 +00:00Commented Mar 23, 2017 at 14:11
-
@Saha222 Yes it is the same, but it's more 'C' style to write motif++ instead of motif = motif + 1 ... or motif += 1; ...I'm glad you sorted out the problem.Michel Keijzers– Michel Keijzers2017年03月23日 15:44:15 +00:00Commented Mar 23, 2017 at 15:44
1 Answer 1
In slave, command is always 0. You problably meant:
void loop(void) {
command = (digitalRead(SS) == HIGH ? 0 : 1);
}
and at ISR:
ISR (SPI_STC_vect) {
byte input = SPDR;
byte output = 0;
if (command) {
switch (input) {
case 'a':
//...
break;
case 'z':
//...
break;
}
}
// send data back
SPDR = output;
}
As a best practice, avoid to implement the logic within the ISR and use global volatile variables to pass state changes to the code in the main loop. Probably you will have to implement a circular buffer to receive from and send to the SPI bus...