0

I need to create a two way String exchanger via SPI with two Arduino UNOs. Strings and their lengths are independent variables of the main loop and they can change with every iteration. I need both of the Arduinos to communicate with each other regardless of what the strings contain. I want to see basically the same screen with the serial monitor.

It is kind of working. I am not sure how to explain it, I'll just show it below.

Basically the main idea for both of the Arduino's is like this:

Master: hey
Slave: hi

Instead I get this on the master:

Slave: 
Slave: 
Master: hey
Slave: y
Slave: 
Slave: 
.
.
.
Slave: i
Slave: 
Slave: 
.
.

And the slave displays only itself:

Slave: hi

I have created for loops to transfer every char of the string seperatly and respectively but this is still the case. I couldn't find any sample code online for independent string transfering via SPI. I know I probably have many mistakes but how can I fix them to work just as I intend to?


Connections:

Arduino1.pin13 --- Arduino2.pin13

Arduino1.pin12 --- Arduino2.pin12

Arduino1.pin11 --- Arduino2.pin11

Arduino1.pin10 --- Arduino2.pin10


Master Code

//MASTER

#include<SPI.h>

String textSend="", textReceive="";

void setup(){

  Serial.begin(115200);

  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV8);    //Sets clock for SPI communication at 8 (16/8=2Mhz)
  digitalWrite(SS,LOW);
}

void loop(){

  textSend=""; textReceive="";
  textSend = Serial.readString();
  if(textSend != ""){
    for(int i = 0; i < textSend.length(); i++){
      delayMicroseconds (20);
      SPI.transfer(textSend[i]);
    }

    Serial.print ("Master: ");
    Serial.println (textSend);
  }else{
    int i = 0;
    char c;
    do{
      delayMicroseconds (20);
      c = SPI.transfer(1);
      textReceive += c;
      i++;
    }while(textReceive[i] != 0);

    if(textReceive[i] == 0){
      Serial.print ("Slave: ");
      Serial.println (textReceive);
      textReceive = "";
    }
  }
}

Slave Code

//SLAVE

#include<SPI.h>

String textSend="";
String textReceive="";

void setup (void){
  Serial.begin(115200);
  pinMode(MISO, OUTPUT);
  SPCR |= _BV(SPE);
  SPCR |= _BV(SPIE);
  SPI.attachInterrupt();

}

ISR (SPI_STC_vect){ //Interrupt Service Routine

  byte c = SPDR;

  if(c != 1){ //Slave receives
    for(int i = 0; i < textReceive.length(); i++){
      textReceive += SPDR;
    }
    if(textReceive.length() > 0){
      Serial.print("Master: ");
      Serial.println(textReceive);
      textReceive = "";
    }
  }else{
    for(int i = 0; i < textSend.length(); i++){
      delayMicroseconds(20);
      SPDR = textSend[i];
    }
    if(textSend != ""){
      Serial.print("Slave: ");
      Serial.println(textSend);
      textSend = "";
    }
  }
}

void loop() {
  if(textSend == "")
    textSend = Serial.readString();


}
2

It's not trivial to have both arduinos communicating "with each other" as SPI is a master-slave bus. That means the slave cannot start a transmission, communication must always be initiated by the master instead. Another thing with SPI is that you can't read the slave without writing to it. SPI works like a shifting register: on every clock cycle both devices transmit the byte in their SPDR to each other. So, to read a long string from the slave the master has to transmit the exact same number of dummy-bytes and simultaniously read the incoming stream. This is great if only a specific number of bytes need to be transmitted (e.g. exchanging variables which always consist of the same number of bytes), but becomes complicate when the number of bytes varies. You will then need to implement some protocol that is able to read a variable amount of bytes from the slave (e.g. you will have to tell the master the number of bytes that have to be read).

I think serial communication like UART is perfect for your purpose as communication is real full-duplex, it's no master-slave-system and the common protocol uses a terminating character to end a data stream which makes it ideal to transmit strings. Also the arduino can run several serial interfaces (you might need another for debug output).

  • First of all, SPI is mandatory for my assignment so I can't use anything else (but thank you for suggesting an alternative for a solution). For keeping the Master listening to the slave, can we maintain a medium which the Master keeps sending a dummy byte constantly to receive Slave's bytes (when the Master does not have anything to send). Slave wouldn't take the dummy byte into consideration and add the anything else to the string? Theoratically, I think it should work that way but I can't get it to work. – Ekin Karadağ May 12 at 18:29
  • Yes, you could kind of emulate the UART protocol on SPI which means you probably will need the master to send continuously. You will then have to define a dummy-byte which will be ignored by both master/slave and a terminating byte (in UART it's typically \n) to mark the end of a string in the byte stream. Even though it's not the most elegant way I see no reason why it shouldn't work. – Sim Son May 12 at 19:01
  • The reason why it doesn't work are some mistakes in your code. E.g. while(textReceive[i] != 0); is wrong as you continuously check for a condition which can't change while you check it. So the routine either does not enter this loop or it will be stuck for ever. Your master code looks like you haven't fully understood the mechanism behind SPI. Keep in mind that you have to write and read each byte at the same time. That means that a for loop like in your case for(int i = 0; i < textSend.length(); i++) doesn't work because you don't handle the incoming bytes which by this are lost. – Sim Son May 12 at 19:20

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.