I have been experimenting with transferring data from an Arduino running as a slave. There are examples of the master and slave programs below. The master is requesting, in turn, a byte from a character array that is defined in the slave. The master prints out each byte as it is received. The program works.
However, the slave has to respond immediately to the Wire.requestFrom() issued by the master. What I want to be able to do is have the slave pause before it sends the response. The slave on receipt of the request from the master may need to go off and perform some task such as read or write to some other bit of hardware it has which could be SPI or serial based for instance.
If in the slaves requestEvent() I set a flag and detect it in loop() and then do the Wire.write(), then it does not work, the message is not returned to the master.
I have had it a type of ‘handshaking’ working on ATMega328Ps, with both Arduinos swapping packets as masters, but that does not work on an XIAO SAMD21, one of the microcontrollers I might want to use.
So, is it possible for the slave to delay returning data to the master ?
//master program
#include <Wire.h>
#define SLAVE_ADDRESS 0x30 // Define Slave I2C Address
void loop()
{
uint8_t index;
uint8_t character;
for (index = 0; index <= 17; index++)
{
character = readMessage(index);
Serial.write(character);
}
Serial.println();
delay(5000);
}
uint8_t readMessage(int16_t addr)
{
uint8_t messagedata;
Wire.beginTransmission(SLAVE_ADDRESS);
Wire.write(1); //command value for register read
Wire.write(addr); //character in message to read
Wire.endTransmission();
delayMicroseconds(250); //delay needed here to prevent read fail
Wire.requestFrom(SLAVE_ADDRESS, 1); //Read one byte response from Slave
messagedata = Wire.read();
return messagedata;
}
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(F("2_I2C_Master"));
Wire.begin(); //Initialize I2C communications as Slave
}
//Slave program
#include <Wire.h>
#define SLAVE_ADDRESS 0x30 // Define Slave I2C Address
volatile uint8_t rxbuff[33]; //buffer for data recieved over I2C
uint8_t message[] = "This is a message"; //buffer for data to be read by master
volatile bool received = false;
volatile bool requested = false;
volatile uint8_t returndata;
void loop()
{
if (received)
{
received = false;
switch (rxbuff[0])
{
case 1:
returndata = message[rxbuff[1]];
break;
default:
break;
}
}
if (requested)
{
requested = false;
Wire.write(returndata);
}
}
void requestEvent()
{
//requested = true; //setting this flag and dealing with the read in loop() does not work
Wire.write(returndata);
}
void receiveEvent(int howmany)
{
//this saves the bytes received to a globally accessible buffer
uint8_t index;
for (index = 0; index < howmany; index++)
{
rxbuff[index] = Wire.read();
}
received = true; //set flag to indicate data has been received
}
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("1_I2C_Slave");
Serial.println();
Wire.begin(SLAVE_ADDRESS); // Initialize I2C communications as Slave
Wire.onRequest(requestEvent); // Function to run when data requested by master
Wire.onReceive(receiveEvent); // Function to run when data received from master
}