diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 59e0d68293..9c5e1c1cd4 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -349,6 +349,10 @@ #define WATCH_COOLER_TEMP_INCREASE 3 // Degrees Celsius #endif +#if ANY(THERMAL_PROTECTION_HOTENDS, THERMAL_PROTECTION_BED, THERMAL_PROTECTION_CHAMBER, THERMAL_PROTECTION_COOLER) + #define THERMAL_PROTECTION_VARIANCE_MONITOR // Detect a sensor malfunction preventing temperature updates +#endif + #if ENABLED(PIDTEMP) // Add an experimental additional term to the heater power, proportional to the extrusion speed. // A well-chosen Kc value should add just enough power to melt the increased material volume. diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index 8919154674..a540c9c771 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -240,6 +240,7 @@ #define STR_REDUNDANCY "Heater switched off. Temperature difference between temp sensors is too high !" #define STR_T_HEATING_FAILED "Heating failed" #define STR_T_THERMAL_RUNAWAY "Thermal Runaway" +#define STR_T_MALFUNCTION "Thermal Malfunction" #define STR_T_MAXTEMP "MAXTEMP triggered" #define STR_T_MINTEMP "MINTEMP triggered" #define STR_ERR_PROBING_FAILED "Probing Failed" diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index a3cb84adb1..08130d31b7 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -2564,6 +2564,9 @@ #if BOTH(HAS_COOLER, THERMAL_PROTECTION_COOLER) && WATCH_COOLER_TEMP_PERIOD > 0 #define WATCH_COOLER 1 #endif +#if NONE(THERMAL_PROTECTION_HOTENDS, THERMAL_PROTECTION_CHAMBER, THERMAL_PROTECTION_BED, THERMAL_PROTECTION_COOLER) + #undef THERMAL_PROTECTION_VARIANCE_MONITOR +#endif #if (ENABLED(THERMAL_PROTECTION_HOTENDS) || !EXTRUDERS) \ && (ENABLED(THERMAL_PROTECTION_BED) || !HAS_HEATED_BED) \ && (ENABLED(THERMAL_PROTECTION_CHAMBER) || !HAS_HEATED_CHAMBER) \ diff --git a/Marlin/src/lcd/language/language_el.h b/Marlin/src/lcd/language/language_el.h index 8db2425d11..f3cd7ef278 100644 --- a/Marlin/src/lcd/language/language_el.h +++ b/Marlin/src/lcd/language/language_el.h @@ -202,6 +202,7 @@ namespace Language_el { LSTR MSG_HEATING_FAILED_LCD = _UxGT("Αποτυχία θέρμανσης"); LSTR MSG_ERR_REDUNDANT_TEMP = _UxGT("ΠΛΕΟΝΑΖΟΥΣΑ ΘΕΡΜΟΤΗΤΑ"); LSTR MSG_THERMAL_RUNAWAY = _UxGT("ΘΕΡΜΙΚΗ ΔΙΑΦΥΓΗ"); + LSTR MSG_TEMP_MALFUNCTION = _UxGT("ΘΕΡΜΙΚΗ ΔΥΣΛΕΙΤΟΥΡΓΙΑ"); LSTR MSG_ERR_MAXTEMP = _UxGT("ΠΕΡΙΤΤΗ ΘΕΡΜΟΚΡΑΣΙΑ"); LSTR MSG_ERR_MINTEMP = _UxGT("ΑΝΕΠΑΡΚΗΣ ΘΕΡΜΟΚΡΑΣΙΑ"); LSTR MSG_HALTED = _UxGT("Εκτυπωτής διεκόπη"); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 8287b60d4c..12430ed4c0 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -538,6 +538,7 @@ namespace Language_en { LSTR MSG_HEATING_FAILED_LCD = _UxGT("Heating Failed"); LSTR MSG_ERR_REDUNDANT_TEMP = _UxGT("Err: REDUNDANT TEMP"); LSTR MSG_THERMAL_RUNAWAY = _UxGT("THERMAL RUNAWAY"); + LSTR MSG_TEMP_MALFUNCTION = _UxGT("TEMP MALFUNCTION"); LSTR MSG_THERMAL_RUNAWAY_BED = _UxGT("BED THERMAL RUNAWAY"); LSTR MSG_THERMAL_RUNAWAY_CHAMBER = _UxGT("CHAMBER T. RUNAWAY"); LSTR MSG_THERMAL_RUNAWAY_COOLER = _UxGT("Cooler Runaway"); diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index eff5a25a1d..bb1768054e 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -196,6 +196,7 @@ Temperature thermalManager; PGMSTR(str_t_thermal_runaway, STR_T_THERMAL_RUNAWAY); +PGMSTR(str_t_temp_malfunction, STR_T_MALFUNCTION); PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED); /** @@ -2570,14 +2571,30 @@ void Temperature::init() { ); */ - // If the heater idle timeout expires, restart - if (TERN0(HEATER_IDLE_HANDLER, heater_idle[idle_index].timed_out)) { - state = TRInactive; - running_temp = 0; - } - else if (running_temp != target) { // If the target temperature changes, restart - running_temp = target; - state = target > 0 ? TRFirstHeating : TRInactive; + #if ENABLED(THERMAL_PROTECTION_VARIANCE_MONITOR) + if (state == TRMalfunction) { // temperature invariance may continue, regardless of heater state + variance += ABS(current - last_temp); // no need for detection window now, a single change in variance is enough + last_temp = current; + if (!NEAR_ZERO(variance)) { + variance_timer = millis() + SEC_TO_MS(period_seconds); + variance = 0.0; + state = TRStable; // resume from where we detected the problem + } + } + #endif + + if (TERN1(THERMAL_PROTECTION_VARIANCE_MONITOR, state != TRMalfunction)) { + // If the heater idle timeout expires, restart + if (TERN0(HEATER_IDLE_HANDLER, heater_idle[idle_index].timed_out)) { + state = TRInactive; + running_temp = 0; + TERN_(THERMAL_PROTECTION_VARIANCE_MONITOR, variance_timer = 0); + } + else if (running_temp != target) { // If the target temperature changes, restart + running_temp = target; + state = target > 0 ? TRFirstHeating : TRInactive; + TERN_(THERMAL_PROTECTION_VARIANCE_MONITOR, variance_timer = 0); + } } switch (state) { @@ -2610,6 +2627,22 @@ void Temperature::init() { const millis_t now = millis(); + #if ENABLED(THERMAL_PROTECTION_VARIANCE_MONITOR) + if (PENDING(now, variance_timer)) { + variance += ABS(current - last_temp); + last_temp = current; + } + else { + if (NEAR_ZERO(variance) && variance_timer) { // valid variance monitoring window + state = TRMalfunction; + break; + } + variance_timer = now + SEC_TO_MS(period_seconds); + variance = 0.0; + last_temp = current; + } + #endif + if (current >= running_temp - hysteresis_degc) { timer = now + SEC_TO_MS(period_seconds); break; @@ -2622,6 +2655,12 @@ void Temperature::init() { case TRRunaway: TERN_(HAS_DWIN_E3V2_BASIC, DWIN_Popup_Temperature(0)); _temp_error(heater_id, FPSTR(str_t_thermal_runaway), GET_TEXT_F(MSG_THERMAL_RUNAWAY)); + + #if ENABLED(THERMAL_PROTECTION_VARIANCE_MONITOR) + case TRMalfunction: + TERN_(HAS_DWIN_E3V2_BASIC, DWIN_Popup_Temperature(0)); + _temp_error(heater_id, FPSTR(str_t_temp_malfunction), GET_TEXT_F(MSG_TEMP_MALFUNCTION)); + #endif } } diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index be21bf0dec..5affcf740d 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1041,12 +1041,18 @@ class Temperature { return (RunawayIndex)_MAX(heater_id, 0); } - enum TRState : char { TRInactive, TRFirstHeating, TRStable, TRRunaway }; + enum TRState : char { TRInactive, TRFirstHeating, TRStable, TRRunaway + OPTARG(THERMAL_PROTECTION_VARIANCE_MONITOR, TRMalfunction) + }; typedef struct { millis_t timer = 0; TRState state = TRInactive; float running_temp; + #if ENABLED(THERMAL_PROTECTION_VARIANCE_MONITOR) + millis_t variance_timer = 0; + celsius_float_t last_temp = 0.0, variance = 0.0; + #endif void run(const_celsius_float_t current, const_celsius_float_t target, const heater_id_t heater_id, const uint16_t period_seconds, const celsius_t hysteresis_degc); } tr_state_machine_t;