diff --git a/source/Core/Inc/Translation.h b/source/Core/Inc/Translation.h index 84e88844..1e9c7635 100644 --- a/source/Core/Inc/Translation.h +++ b/source/Core/Inc/Translation.h @@ -84,6 +84,7 @@ struct TranslationIndexTable { uint16_t LockingKeysString; uint16_t UnlockingKeysString; uint16_t WarningKeysLockedString; + uint16_t WarningThermalRunaway; uint16_t SettingRightChar; uint16_t SettingLeftChar; diff --git a/source/Core/Inc/configuration.h b/source/Core/Inc/configuration.h index 66f3f828..bbe5ffec 100644 --- a/source/Core/Inc/configuration.h +++ b/source/Core/Inc/configuration.h @@ -94,6 +94,9 @@ #define DETAILED_SOLDERING 0 // 0: Disable 1: Enable - Default 0 #define DETAILED_IDLE 0 // 0: Disable 1: Enable - Default 0 +#define THERMAL_RUNAWAY_TIME_SEC 20 +#define THERMAL_RUNAWAY_TEMP_C 20 + #define CUT_OUT_SETTING 0 // default to no cut-off voltage #define RECOM_VOL_CELL 33 // Minimum voltage per cell (Recommended 3.3V (33)) #define TEMPERATURE_INF 0 // default to 0 diff --git a/source/Core/Threads/GUIThread.cpp b/source/Core/Threads/GUIThread.cpp index df032b26..ad12452d 100644 --- a/source/Core/Threads/GUIThread.cpp +++ b/source/Core/Threads/GUIThread.cpp @@ -28,6 +28,7 @@ extern "C" { // File local variables extern uint32_t currentTempTargetDegC; extern TickType_t lastMovementTime; +extern bool heaterThermalRunaway; extern osThreadId GUITaskHandle; extern osThreadId MOVTaskHandle; extern osThreadId PIDTaskHandle; @@ -62,7 +63,7 @@ void GUIDelay() { // This limits the re-draw rate to the LCD and also lets the DMA run // As the gui task can very easily fill this bus with transactions, which will // prevent the movement detection from running - osDelay(50); + vTaskDelay(5 * TICKS_10MS); } void gui_drawTipTemp(bool symbol, const FontStyle font) { // Draw tip temp handling unit conversion & tolerance near setpoint @@ -608,7 +609,6 @@ static void gui_solderingMode(uint8_t jumpToSleep) { } } OLED::refresh(); - // Update the setpoints for the temperature if (boostModeOn) { if (systemSettings.temperatureInF) @@ -645,6 +645,15 @@ static void gui_solderingMode(uint8_t jumpToSleep) { } else { setStatusLED(LED_HEATING); } + // If we have tripped thermal runaway, turn off header and show warning + if (heaterThermalRunaway) { + currentTempTargetDegC = 0; // heaater control off + // TODO WARNING + + warnUser(translatedString(Tr->WarningThermalRunaway), 10 * TICKS_SECOND); + heaterThermalRunaway = false; + return; + } // slow down ui update rate GUIDelay(); } diff --git a/source/Core/Threads/PIDThread.cpp b/source/Core/Threads/PIDThread.cpp index e8a69073..ff90c76a 100644 --- a/source/Core/Threads/PIDThread.cpp +++ b/source/Core/Threads/PIDThread.cpp @@ -19,6 +19,7 @@ static TickType_t powerPulseDurationUnit = (5 * TICKS_100MS) / 2; // 250 ms TaskHandle_t pidTaskNotification = NULL; uint32_t currentTempTargetDegC = 0; // Current temperature target in C int32_t powerSupplyWattageLimit = 0; +bool heaterThermalRunaway = false; /* StartPIDTask function */ void startPIDTask(void const *argument __unused) { /* @@ -32,8 +33,10 @@ void startPIDTask(void const *argument __unused) { history tempError = {{0}, 0, 0}; currentTempTargetDegC = 0; // Force start with no output (off). If in sleep / soldering this will // be over-ridden rapidly - pidTaskNotification = xTaskGetCurrentTaskHandle(); - uint32_t PIDTempTarget = 0; + pidTaskNotification = xTaskGetCurrentTaskHandle(); + uint32_t PIDTempTarget = 0; + uint16_t tipTempCRunawayTemp = 0; + TickType_t runawaylastChangeTime = 0; #ifdef SLEW_LIMIT int32_t x10WattsOutLast = 0; #endif @@ -91,6 +94,33 @@ void startPIDTask(void const *argument __unused) { // and counters extra power if the iron is no longer losing temp. // basically: temp - lastTemp // Unfortunately, our temp signal is too noisy to really help. + + // Check for thermal runaway, where it has been x seconds with negligible (y) temp rise + // While trying to actively heat + if ((tError > THERMAL_RUNAWAY_TEMP_C)) { + // Temp error is high + int16_t delta = (int16_t)currentTipTempInC - (int16_t)tipTempCRunawayTemp; + if (delta < 0) { + delta = -delta; + } + if (delta > THERMAL_RUNAWAY_TEMP_C) { + // We have heated up more than the threshold, reset the timer + tipTempCRunawayTemp = currentTipTempInC; + runawaylastChangeTime = xTaskGetTickCount(); + } else { + if ((xTaskGetTickCount() - runawaylastChangeTime) > (THERMAL_RUNAWAY_TIME_SEC * TICKS_SECOND)) { + // It has taken too long to rise + heaterThermalRunaway = true; + } + } + } else { + tipTempCRunawayTemp = currentTipTempInC; + runawaylastChangeTime = xTaskGetTickCount(); + } + + } else { + tipTempCRunawayTemp = currentTipTempInC; + runawaylastChangeTime = xTaskGetTickCount(); } // If the user turns on the option of using an occasional pulse to keep the power bank on if (systemSettings.KeepAwakePulse) { @@ -111,6 +141,9 @@ void startPIDTask(void const *argument __unused) { if (getTipRawTemp(0) > (0x7FFF - 32)) { x10WattsOut = 0; } + if (heaterThermalRunaway) { + x10WattsOut = 0; + } if (systemSettings.powerLimit && x10WattsOut > (systemSettings.powerLimit * 10)) { x10WattsOut = systemSettings.powerLimit * 10; }