I'm using I2C to link two Arduino Nano Every boards together. Both boards have a lot of work to do, so the timing of when they exchange data must be coordinated. I'm open to and would appreciate better ideas if anyone has one, but here is the solution I'm trying to implement.
I use a digital I/O line, and when the slave has completed its calculations, it sets the line to HIGH, then sits and waits for the master to send a Wire.requestFrom command. The onRequest handler sends the data, then sets a flag to indicate the data has been sent, releasing the main loop to continue.
#define SLAVE_ADDRESS 20
#define PIN_WAITING 6
bool dataSent = false;
// pin states and other initializing tasks handled in setup()
void loop()
{
delay(2000); // Pretend we're doing something
showTime("Ready"); // This method prints the message "Ready" and the current time
// in millis() to the Serial Monitor. Commenting out these
// lines does not help.
dataSent = false; // Set flag to indicate not data has not been sent
digitalWrite(PIN_WAITING, LOW); // Turn off LED to indicate data has not been sent
digitalWrite(SLAVE_ADDRESS, HIGH); // Put I/O line to HIGH telling master data is ready
while (dataSent == false) {} // Wait until data has been sent, then continue
showTime("Done waiting"); // Tell Serial Monitor that we're moving on again
}
void requestEvent() {
sendData(); // Send the data - this is working because the master receives the data
dataSent = true; // Set flag to indicate data was sent
digitalWrite(PIN_WAITING, HIGH); // Turn on LED to indicate data was sent
}
As indicated by the output to the serial monitor, the data received by the master, and the status of the LEDs, the slave puts the I/O indicator line to high and waits in the while (dataSent == false) {} loop. The master detects the signal, issues the requestFrom command, the slave responds in requestEvent, the data is sent and received, the dataSent and LED flags are both set to true/HIGH, and the I/O line goes LOW - all is working normally and as intended up to this point.
Except that the while (dataSent == false) {} loop never releases (even though dataSent goes to true) and the program hangs at that point without advancing. Through prior experiments, I know that if dataSent is true before the while (dataSent == false) {} loop starts, it moves past just fine.
To better understand what is happening, I replaced the while (dataSent == false) {} loop with the following:
waitHere = true;
while (waitHere) {
if (dataSent) {
blink(LED_BUILTIN, 200, 2); } // this blinks LED_BUILTIN 2 times for 200 ms
else {
blink(LED_BUILTIN, 400, 3); } // this blinks 3 time for 400 ms
waitHere = !dataSent; }
Result - the built-in LED turn on and stays on solid. I also tried commenting out all lines that put data to the serial monitor, but that also did not help.
If I manually trigger the I/O line HIGH by momentarily tapping it to the 5V line, the Master sends a new request, the slave responds, data is exchanged, all within the requestEvent handler, but the main loop remains frozen in place and the built-in LED never flickers. It appears that the main loop is truly frozen even though the requestEvent is still working.
Any thoughts on what is going on here or how to get past this?