2

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 Mar 22 '17 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 Mar 22 '17 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 Mar 23 '17 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 Mar 23 '17 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 Mar 23 '17 at 15:44
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...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.