SPI : slave sending back a string

Hi,

I’m trying to make a Raspberry Pi 3 and an Arduino Uno communicate using SPI. Bascially, I want the master RPi to send a char like ‘r’ to the slave Uno, which would answer a string like “Hello RPi !”.

At the moment, I can display in the Uno console the received char or string sent by the RPi, but I don’t know how to send back a whole string, and the examples I find on the Internet most on the time concern harder projects (monitoring a humidity sensor, setting potentiometers, etc.). :confused:

The current code, based on a Nick Gammon’s snippet is :

// Arduino is slave, RPi is master.
// Name : Arduino pin <-> RPi pin
// SCLK : 13 <- 23
// MOSI : 11 <- 19
// MISO : 12 -> 21 /!\ voltage divider 5 V -> 3.3 V /!\ 
// SS   : 10 <- 24

#include <SPI.h>

char buf[100];
volatile byte pos;
volatile boolean process_it;

void setup()
{

  Serial.begin(230400);

  SPCR |= bit(SPE);

  pinMode(MISO, OUTPUT);

  pos = 0;

  process_it = false;

  SPI.attachInterrupt();

}

ISR(SPI_STC_vect)
{

  byte c = SPDR;

  if (pos < (sizeof(buf) - 1))
  {

    buf[pos++] = c;
    
  }

  if (c == '\n')
  {

    process_it = true;
    
  }
  
}

void loop()
{
  
  if (process_it == true)
  {

    buf[pos] = 0;

    Serial.println(buf);

    pos = 0;

    process_it = false;
    
  }

}

This code allows me to display a char or a string sent from the RPi using the WiringPi library.

Could you help me adding some code to send back a string to the RPi ?

Thank you in advance !

If that could help, the RPi C code is :

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <wiringPiSPI.h>

#define CHANNEL 0

int main(void)
{

	unsigned char buf[100];

	buf[0] = 'r';
	buf[1] = '\n';

	printf("Initilialization... ");

	if (wiringPiSPISetup(CHANNEL, 1000000) < 0)
	{

		printf(" Failed.\n");

	}

	else
	{

		printf("Done !\n");

	}

	while (1)
	{

		int recv = wiringPiSPIDataRW(CHANNEL, buf, 2);

		printf("Received : %s\n", buf);

		sleep(1);

	}

	return 1;

}

You cannot send back a string, the master says how many bytes you may transmit. SPI is not like a UART interface. The master provides clock signals for every bit it wants to send/receive to/from the slave. Although you can establish a special protocol that first request the size of the string the slave wants to send in reply to the command and then transmits that many bytes from the slave to the master, it doesn't make sense to misuse the SPI protocol for such stuff. If you want UART style communication why don't you use the real UART?

Thank you for your answer.

So if I want 10 chars to come back from the slave, I have to send 10 chars to it (one char being 1 byte) ? If so, I assume that wouldn’t be a problem, as I know exactly how many chars to send from the slave to the master, so I would have to send the same number of chars to the slave.

This work is part of an internship project, and using SPI is mandatory.

In the end, I’d like the master to send the same message to the slave each second, and the slave would send back an answer that I could display in the console on my RPi. What I send is not important, it’s only the answer from the slave that matters.

That might work. Keep in mind that SPI is bidirectional, if you send a byte to the slave a byte is also received at the same time. In most situations the content of one direction is thrown away. But that's important to calculate the correct number of bytes to clock on the master.

I hope that will work then !

So I imagine something like : 1) The master RPi sends 1 byte to the slave Uno (so the Uno also sends a byte at the same time, which wouldn't be read by the RPi), and 2) The Uno sends a string to the RPi (so the RPi also sends a string at the same time, which wouldn't be read by the Uno).

Or it can even be : the RPi sends anything as long as it is the same byte number as the expected answer, and the Uno in the same time sends the said answer. Actually, I think this solution is better, because when the RPi sends a request to the Uno, it's always for the same reason : getting an answer back, without even reading what the RPi sent.

The problem is I really don't know how to write the code that would do this, and my tests using SPI.transfer() don't give anything.

Please post a link to the level converter you use! Also post a wiring diagram of every connection between the Pi and the Arduino. Post your code, even if it doesn’t work at the moment. We won’t write the code for you but we may help you to get the idea of how to do it yourself.

Hi again,

Sorry for the delay since my last answer. I solved my problem : I was misusing the wiringPiSPIDataRW() function on the RPi, and didn't really understand what I was doing on the Arduino ; my software is now done and working. :slight_smile:

Thank you for your help.