You may consider making your ISR non-reentrant and just enabling interrupts at the top. Note that sei() is not available on other Arduino architectures but interrupts() is.
How to make the ISR non-reentrant while also enabling interrupts for Wire()? Seems contradictory to disable interrupts (to prevent reentry) while enabling interrupts (to use Wire). I haven't found where Sketch offers this granularity.
I changed sei() to interrupts().
I also noticed that the code that copies global variables into local buffered space is vulnerable to getting interrupted. This would garble the copy if interrupted mid-byte. Theoretically possible. So I save the interrupt flag, stop the interrupts, copy the globals into local variables, and then restart. Code below:
uint8_t SaveSREG = SREG; // save interrupt flag
nointerrupts(); // stop interrupts when grabbing the globals
Variable_1_Local = Variable_1_Global; // copy the global variables into local copies
Variable_2_Local = Variable_2_Global;
Variable_3_Local = Variable_3_Global;
interrupts();
SREG = SaveSREG; // restore the interrupt flag
Whole code below, original code, not using vbextreme's optimizations. There's more optimizations but that's outside of the OP scope of handling tasks.
#include <math.h>
#include <Wire.h>
volatile float Variable_1_Global;
volatile float Variable_2_Global;
volatile float Variable_3_Global;
volatile int dataready;
void setup() {
Serial.begin(115200);
delay(100);
Serial.println(" Starting I2C Init");
Wire.begin();
delay(100);
// this is where I setup my I2C device and init variables
Serial.println("Finished I2C Init");
}
void loop() {
char tmp1[10];
char tmp2[10];
char tmp3[10];
char outputstring[60];
int serialbuffer;
float Variable_1_Local;
float Variable_2_Local;
float Variable_3_Local;
Serial.println("Configure Timer Interrupt");
noInterrupts()
TCCR1A = 0;
TCCR1B = 0;
OCR1A = 45; // set interrupt at 3000us (using 1024 prescalar)
TCCR1B |= (1 << WGM12); // turn on CTC mode:
TCCR1B |= (1 << CS10); // prescalar
TCCR1B |= (1 << CS12); // prescalar 1024
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt:
interrupts();
Serial.println("Timer Interrupt Enabled");
while(1 > 0){ // forever loop
serialbuffer = Serial.availableForWrite(); // check serial TX buffer
if(serialbuffer > 60){ // if serial TX buffer is (nearly) empty
if(dataready > 0) { // if data is ready
uint8_t SaveSREG = SREG; // save interrupt flag
nointerrupts(); // stop interrupts when grabbing the globals
Variable_1_Local = Variable_1_Global; // copy the global variables into local copies
Variable_2_Local = Variable_2_Global;
Variable_3_Local = Variable_3_Global;
interrupts();
SREG = SaveSREG; // restore the interrupt flag
dtostrf(Variable_1_Local,6,4,tmp1); // Convert variables into char[] strings
dtostrf(Variable_2_Local,6,4,tmp2);
dtostrf(Variable_3_Local,6,4,tmp3);
outputstring[0] = (char)0; // reset the output char[] string
strncat(outputstring,tmp1,5); // Assemble output char[] strings
strncat(outputstring,",",1);
strncat(outputstring,tmp2,5);
strncat(outputstring,",",1);
strncat(outputstring,tmp3,5);
Serial.println(outputstring); // Print the output char[] string
dataready = 0; // clear the flag and wait for new data
}
}
}
}
ISR(TIMER1_COMPA_vect) {
interrupts(); // restart interrupts to use Wire() for I2C comms
Wire.read(); // I2C comms
Wire.write(); // I2C comms
nointerrupts(); // stop interrupts to prevent reentrant
Variable_1_Global = 1; // save parameters as global variables
Variable_2_Global = 2;
Variable_3_Global = 3;
dataready = 1; // set global flag that data is ready to be handled
}