Millis() and i2c interrupt issue

Hi everyone.

I have nine arduino megas connected via i2c, one as master and eight slaves. The master collects information from the slaves and sends commands to them to turn an IO on or off (they act as a pool of ~450 digital outputs for a control system).

The one issue I have is with a bit of code intended as a fail safe on the slaves whereby if the slave doesn't hear from the master in 2000ms it will turn off every digital output on the assumption that the master has failed.

This is achieved through a volatile unsigned long variable named lastUpdateMillis which is set to the value of millis() every time the master requests a status update.

Then in the loop, i check for if((unsigned long)(millis()-lastUpdateMillis)>=2000){ and turn all outputs off.

I'm getting this loop fired randomly and have been troubleshooting for some time. Recording the values of the above if statement, it would appear that SOMETIMES millis()-lastUpdateMillis equals 4294967201, 4294967200 or 4294967199 - which would suggest to me that millis was less than lastUpdateMillis at the time of checking and that the result is an overflow?

This happens a couple of times a minute potentially, the master is checking the status of the slave every 160ms or so. I'm assuming that the i2c request triggers an interrupt and that the value is lastUpdateMillis is changing whilst the above statement is being executed???

Does that make any sense or am I going mad, is there any other way to achieve this?

no full sketch = no help likely

If this variable is qualified as volatile, does that mean it is updated in interrupt context?
And do you remember to take a copy of it with interrupts disabled when you access it in non-interrupt context?

No, he did not.

Apologies. I have stripped everything not needed from the script to keep it really simple and confirmed that this exhibits the same issue.

Code for master:

#include <Wire.h>

void setup() {
  Wire.begin();
  Wire.setClock(400000L);
  Serial.begin(115200);//For testing only
}

void loop() {
  unsigned long lastMillisSlave=0;
  
  if((unsigned long)(millis()-lastMillisSlave)>=50){
    lastMillisSlave=millis();
    requestStatusFromSlave();
  }
}

void requestStatusFromSlave(){
  Serial.println("Requesting status");
  Wire.requestFrom(1, 32);
  
  while(Wire.available()){
    char c=Wire.read();
    Serial.print(c);
  }
  Serial.println("");
}

And Slave *** this is the one that will give the serial output of the error:

#include <Wire.h>

volatile unsigned long lastUpdateMillis=0;

void setup() {
  Wire.begin(1);
  Wire.setClock(400000L);
  Wire.onRequest(requestStatus);
  Serial.begin(115200);//For testing only
}

void loop() {
  unsigned long thisNum=millis()-lastUpdateMillis;
  if(thisNum>=2000){
    Serial.print("thisNum is ");
    Serial.println(thisNum);
    Serial.print("Millis is ");
    Serial.println(millis());
    Serial.print("lastUpdateMillis is  ");
    Serial.println(lastUpdateMillis);
    
    //Turn off all digital IOs
  }
}

/* Report status back to Master */
void requestStatus(){
  lastUpdateMillis=millis();
  
  for(byte i=0;i<32;i++) Wire.write("A");
}
void loop() {
  noInterrupts ();
  uint32_t lastUpdateTime = lastUpdateMillis;
  interrupts ();
  unsigned long thisNum=millis()-lastUpdateTime;
  if(thisNum>=2000){