Fix display freeze: move I2C work out of interrupt context #8

Open
claude-fable wants to merge 2 commits from claude-fable/metronom:fix/i2c-delay-in-isr-freeze into master
3 changed files with 30 additions and 12 deletions

View File

@@ -18,11 +18,11 @@ void buttonISRstate() {
else if (countdown == 0) {
// TODO: restart metronome timer to align countdown
countdown = COUNTDOWN;
updateTube();
displayNeedsUpdate = true;
} else {
countdown = -1;
digitalWrite(BUTTON_LED_PIN, LOW);
updateTube();
displayNeedsUpdate = true;
// TODO: disable metronome timer
}
}

View File

@@ -37,18 +37,19 @@ volatile float sensorValue[SENSORS] = {};
volatile uint displaySensor = TEMPERATURE;
volatile bool displayNeedsUpdate = false;
volatile bool tubeRotated = false;
volatile bool sensorsDue = false;
int tubeTimerID;
/* I2C (BME280 reads, tube writes) must never run in interrupt context:
both libraries call delay(), which inside an ISR can spin forever
because SysTick (millis/micros) is blocked. ISRs only raise flags;
loop() does the actual bus work. */
void TasksHandler(void) {
TasksISRs.run();
}
if (displayNeedsUpdate || tubeRotated)
updateTube();
if (tubeRotated) {
TasksISRs.changeInterval(tubeTimerID, SENSOR_TIMESHARE[displaySensor]);
tubeRotated = false;
}
void scheduleSensors() {
sensorsDue = true;
}
void setup() {
@@ -62,7 +63,7 @@ void setup() {
TaskTimer.attachInterruptInterval_MS(TASK_HANDLER_INTERVAL, TasksHandler);
TasksISRs.setInterval(METRONOME_INTERVAL, runMetronome);
TasksISRs.setInterval(SENSOR_INTERVAL, readSensors);
TasksISRs.setInterval(SENSOR_INTERVAL, scheduleSensors);
tubeTimerID = TasksISRs.setInterval(SENSOR_TIMESHARE[displaySensor], rotateTube);
}
@@ -79,4 +80,17 @@ void runMetronome() {
}
}
void loop() {}
void loop() {
if (sensorsDue) {
sensorsDue = false;
readSensors();
}
if (displayNeedsUpdate || tubeRotated)
updateTube();
if (tubeRotated) {
TasksISRs.changeInterval(tubeTimerID, SENSOR_TIMESHARE[displaySensor]);
tubeRotated = false;
}
}

View File

@@ -6,7 +6,11 @@ char tubeText[5] = "";
void initTube() {
// Wire initialized by BME280 sensor
tube.setTubeType(TYPE_4, TYPE_4_DEFAULT_I2C_ADDR);
tube.setBrightness(15);
// Brightness drives LED current. The freeze correlates with '8' on the last
// multiplexed digit (most segments lit -> peak current) at full brightness 15,
// which points at a supply/I2C-bus glitch. Lowered to probe that hypothesis;
// raise back toward 15 if the display is too dim and freezes don't return.
tube.setBrightness(4);
tube.setBlinkRate(BLINK_OFF);
}