diff --git a/inc/sp140/system_monitors.h b/inc/sp140/system_monitors.h index a7dec9a..3e09e68 100644 --- a/inc/sp140/system_monitors.h +++ b/inc/sp140/system_monitors.h @@ -7,7 +7,14 @@ void addInternalMonitors(); void addAltimeterMonitors(); -// Thread-safe cached CPU temperature reading (updates max once per second) +// Prime the CPU temperature cache during single-threaded setup. +void primeCpuTemperatureCache(); + +// Refresh the sensor at most once per second. ctrlSensorTask is the sole +// runtime owner; all other tasks must use getCachedCpuTemperature(). +float refreshCpuTemperature(); + +// Cross-core read of the last published CPU temperature; never touches tsens. float getCachedCpuTemperature(); #endif // INC_SP140_SYSTEM_MONITORS_H_ diff --git a/src/sp140/main.cpp b/src/sp140/main.cpp index 57b7889..81d0bf5 100644 --- a/src/sp140/main.cpp +++ b/src/sp140/main.cpp @@ -310,10 +310,9 @@ void throttleTask(void *pvParameters) { } // Lightweight task: reads controller sensors and writes to TelemetryHub at 10Hz. -// Uses CACHED barometer/CPU values — uiTask is the sole I2C reader, and -// getCachedCpuTemperature throttles tsens access. This avoids i2cMutex -// contention and the "tsens: Do not configure..." error that arises when -// multiple tasks call temperatureRead() concurrently. +// Uses CACHED barometer/CPU values — uiTask is the sole I2C reader, and this +// task is the sole runtime owner of tsens refresh. Other tasks only consume the +// atomically published CPU temperature. void ctrlSensorTask(void *pvParameters) { (void)pvParameters; TickType_t lastWake = xTaskGetTickCount(); @@ -327,7 +326,7 @@ void ctrlSensorTask(void *pvParameters) { float bt = getBaroTemperature(); float bp = getBaroPressure(); float vs = getCachedVerticalSpeed(); - float mt = getCachedCpuTemperature(); + float mt = refreshCpuTemperature(); uint16_t pr = getLastThrottleRaw(); telemetryHubWriteController(alt, bt, bp, vs, mt, pr, now); vTaskDelayUntil(&lastWake, sensorTicks); diff --git a/src/sp140/simple_monitor.cpp b/src/sp140/simple_monitor.cpp index 50752e4..15ffd3b 100644 --- a/src/sp140/simple_monitor.cpp +++ b/src/sp140/simple_monitor.cpp @@ -307,6 +307,9 @@ void initSimpleMonitor() { addESCMonitors(); addBMSMonitors(); addAltimeterMonitors(); + // Prime while setup is still single-threaded so monitor readers never see + // the zero-initialized cache and no runtime task races tsens initialization. + primeCpuTemperatureCache(); addInternalMonitors(); USBSerial.printf("Monitoring %d sensors\n", monitors.size()); } diff --git a/src/sp140/system_monitors.cpp b/src/sp140/system_monitors.cpp index e426205..8af9410 100644 --- a/src/sp140/system_monitors.cpp +++ b/src/sp140/system_monitors.cpp @@ -2,6 +2,7 @@ #include "sp140/monitor_config.h" #include "sp140/altimeter.h" #include +#include // External references to core monitoring infrastructure extern std::vector monitors; @@ -10,18 +11,28 @@ extern MultiLogger multiLogger; // External reference to BMP sensor status extern bool bmpPresent; -// Cached CPU temperature to avoid "tsens: Do not configure the temp sensor when it's running!" error -static float cachedCpuTemp = 0.0f; +// ESP32 tsens configuration is not safe from concurrent tasks. One task owns +// temperatureRead(); readers consume this atomic cross-core publication. +static std::atomic cachedCpuTemp{0.0f}; static unsigned long lastCpuTempRead = 0; static const unsigned long CPU_TEMP_READ_INTERVAL = 1000; // Read every 1 second -float getCachedCpuTemperature() { +void primeCpuTemperatureCache() { + cachedCpuTemp.store(temperatureRead(), std::memory_order_relaxed); + lastCpuTempRead = millis(); +} + +float refreshCpuTemperature() { unsigned long now = millis(); if (now - lastCpuTempRead >= CPU_TEMP_READ_INTERVAL) { - cachedCpuTemp = temperatureRead(); + cachedCpuTemp.store(temperatureRead(), std::memory_order_relaxed); lastCpuTempRead = now; } - return cachedCpuTemp; + return cachedCpuTemp.load(std::memory_order_relaxed); +} + +float getCachedCpuTemperature() { + return cachedCpuTemp.load(std::memory_order_relaxed); } void addInternalMonitors() {