SPI bi-directional communtion issue

Hello everybody,

I am currently working on a robotics project for a university. I am using two Arduino boards that are communicating via SPI. The robot has to perform a variety of tasks and I decided to split up the tasks; the robotic arm will be operated by the master Arduino board and the sensors will be operated by the slave Arduino board. As such, I need the two Arduino boards to communicate in both directions.

I have searched topics about SPI on this forum and I found this great website:

I decided to model my code on the SPI bi-directional example (title example is called How to get a response from a slave) in that website. However, I have some questions on exactly how to implement the code. My questions are with regards to the SPI interrupt functions and the code in the loop function of the master code.

I have attached the entire code from the website for both the master and slave and the results. My first question is with regards to this section of master code executed in the loop function:

// enable Slave Select
digitalWrite(SS, LOW);

transferAndWait ('a'); // add command
transferAndWait (10);
a = transferAndWait (17);
b = transferAndWait (33);
c = transferAndWait (42);
d = transferAndWait (0);

// disable Slave Select
digitalWrite(SS, HIGH);

In addition, here is the SPI function used in the master code:

byte transferAndWait (const byte what)
{
byte a = SPI.transfer (what);
delayMicroseconds (20);
return a;
} // end of transferAndWait

In order to receive data from the slave, the master has to send data first. But what I want to do on my code is for the master to send a SPI command to the the slave, the slave starts the sensors, collects data, and then send the results to the master. My sensor code will be executed in the loop function. Is it possible for me to execute code in the loop function of the slave and then uses SPI to send the results back to the master?

Here is the interrupt code used by the slave:
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;

switch (command)
{
// no command? then this is the command
case 0:
command = c;
SPDR = 0;
break;

// add to incoming byte, return result
case 'a':
SPDR = c + 15; // add 15
break;

// subtract from incoming byte, return result
case 's':
SPDR = c - 8; // subtract 8
break;

} // end of switch

} // end of interrupt service routine (ISR) SPI_STC_vect

Do I have to execute my slave sensor code within that interrupt on the slave? Or is it possible to easily execute the sensor code in the loop?

Someone might ask as to why don't I just one Arduino Mega board. The reason why is because the slave board will be doing a lot more than just sensor code by the time this project is done. A lot of hardware will be connected to both boards and I decided that two boards working together is better than jamming all the hardware into one mega board. In addition, one mega does not have available all the hard interrupts that I need. I need to use two boards.

Thanks everyone for reading and your time,
David

SPI master.txt (1.62 KB)

SPI output results.txt (136 Bytes)

SPI slave.txt (972 Bytes)

In order to receive data from the slave, the master has to send data first. But what I want to do on my code is for the master to send a SPI command to the the slave, the slave starts the sensors, collects data, and then send the results to the master. My sensor code will be executed in the loop function.

This does not make sense. If the loop() function gets data from the sensors on every pass, then "starts the sensors" in the slave's interrupt handler does not make sense.

Suppose I called you now and then, on no fixed schedule, and I needed to know the temperature where you are. You could, when I called, run out to the store, buy a thermometer, run back home, and check the temperature. Or, you could know that I will be calling at some point, so, you get a thermometer once, and read it every 5 minutes. When I call, you have an instant answer, albeit it one up to 5 minutes old.

If 5 minute old data is unacceptable, read more often. But, always be prepared to return the latest data without needing to get data.

Hi Paul,

Thanks for the reply. I understand what I did to do. I need to write code in the loop function that runs the sensors and collects the data and sends the data as soon as it is finished. The master Arduino will stay running idle until it receives a response for the slave.

But my question is what would the SPI code on the slave look like? Do I just use the SPI.transfer function and if so, how do I use?

The example that I saw in the gammon website requires that the master send a byte to the slave and then another immediate SPI command has to be sent by the master in order to get a response.

Is there another way for me to do this?

Thanks,
David

SPI works by exchanging the contents of two registers. One is on the master and one is on the slave. After each 8 bits transferred, the contents of the registers have changed places. Then it's up to the code on each end to read that register and save it in a buffer or whatever, then load the register with the next byte to send.