|
@@ -252,7 +252,7 @@ const char str_t_thermal_runaway[] PROGMEM = STR_T_THERMAL_RUNAWAY,
|
252
|
252
|
hotend_watch_t Temperature::watch_hotend[HOTENDS]; // = { { 0 } }
|
253
|
253
|
#endif
|
254
|
254
|
#if HEATER_IDLE_HANDLER
|
255
|
|
- hotend_idle_t Temperature::hotend_idle[HOTENDS]; // = { { 0 } }
|
|
255
|
+ Temperature::heater_idle_t Temperature::heater_idle[NR_HEATER_IDLE]; // = { { 0 } }
|
256
|
256
|
#endif
|
257
|
257
|
|
258
|
258
|
#if HAS_HEATED_BED
|
|
@@ -266,7 +266,6 @@ const char str_t_thermal_runaway[] PROGMEM = STR_T_THERMAL_RUNAWAY,
|
266
|
266
|
#endif
|
267
|
267
|
TERN_(WATCH_BED, bed_watch_t Temperature::watch_bed); // = { 0 }
|
268
|
268
|
TERN(PIDTEMPBED,, millis_t Temperature::next_bed_check_ms);
|
269
|
|
- TERN_(HEATER_IDLE_HANDLER, hotend_idle_t Temperature::bed_idle); // = { 0 }
|
270
|
269
|
#endif // HAS_HEATED_BED
|
271
|
270
|
|
272
|
271
|
#if HAS_TEMP_CHAMBER
|
|
@@ -841,7 +840,7 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
|
841
|
840
|
|
842
|
841
|
if (temp_hotend[ee].target == 0
|
843
|
842
|
|| pid_error < -(PID_FUNCTIONAL_RANGE)
|
844
|
|
- || TERN0(HEATER_IDLE_HANDLER, hotend_idle[ee].timed_out)
|
|
843
|
+ || TERN0(HEATER_IDLE_HANDLER, heater_idle[ee].timed_out)
|
845
|
844
|
) {
|
846
|
845
|
pid_output = 0;
|
847
|
846
|
pid_reset[ee] = true;
|
|
@@ -926,7 +925,7 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
|
926
|
925
|
|
927
|
926
|
#else // No PID enabled
|
928
|
927
|
|
929
|
|
- const bool is_idling = TERN0(HEATER_IDLE_HANDLER, hotend_idle[ee].timed_out);
|
|
928
|
+ const bool is_idling = TERN0(HEATER_IDLE_HANDLER, heater_idle[ee].timed_out);
|
930
|
929
|
const float pid_output = (!is_idling && temp_hotend[ee].celsius < temp_hotend[ee].target) ? BANG_MAX : 0;
|
931
|
930
|
|
932
|
931
|
#endif
|
|
@@ -1040,15 +1039,14 @@ void Temperature::manage_heater() {
|
1040
|
1039
|
|
1041
|
1040
|
HOTEND_LOOP() {
|
1042
|
1041
|
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
|
1043
|
|
- if (degHotend(e) > temp_range[e].maxtemp)
|
1044
|
|
- _temp_error((heater_id_t)e, str_t_thermal_runaway, GET_TEXT(MSG_THERMAL_RUNAWAY));
|
|
1042
|
+ if (degHotend(e) > temp_range[e].maxtemp) max_temp_error((heater_id_t)e);
|
1045
|
1043
|
#endif
|
1046
|
1044
|
|
1047
|
|
- TERN_(HEATER_IDLE_HANDLER, hotend_idle[e].update(ms));
|
|
1045
|
+ TERN_(HEATER_IDLE_HANDLER, heater_idle[e].update(ms));
|
1048
|
1046
|
|
1049
|
1047
|
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
|
1050
|
1048
|
// Check for thermal runaway
|
1051
|
|
- thermal_runaway_protection(tr_state_machine[e], temp_hotend[e].celsius, temp_hotend[e].target, (heater_id_t)e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS);
|
|
1049
|
+ tr_state_machine[e].run(temp_hotend[e].celsius, temp_hotend[e].target, (heater_id_t)e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS);
|
1052
|
1050
|
#endif
|
1053
|
1051
|
|
1054
|
1052
|
temp_hotend[e].soft_pwm_amount = (temp_hotend[e].celsius > temp_range[e].mintemp || is_preheating(e)) && temp_hotend[e].celsius < temp_range[e].maxtemp ? (int)get_pid_output_hotend(e) >> 1 : 0;
|
|
@@ -1093,8 +1091,7 @@ void Temperature::manage_heater() {
|
1093
|
1091
|
#if HAS_HEATED_BED
|
1094
|
1092
|
|
1095
|
1093
|
#if ENABLED(THERMAL_PROTECTION_BED)
|
1096
|
|
- if (degBed() > BED_MAXTEMP)
|
1097
|
|
- _temp_error(H_BED, str_t_thermal_runaway, GET_TEXT(MSG_THERMAL_RUNAWAY));
|
|
1094
|
+ if (degBed() > BED_MAXTEMP) max_temp_error(H_BED);
|
1098
|
1095
|
#endif
|
1099
|
1096
|
|
1100
|
1097
|
#if WATCH_BED
|
|
@@ -1127,12 +1124,14 @@ void Temperature::manage_heater() {
|
1127
|
1124
|
TERN_(PAUSE_CHANGE_REQD, last_pause_state = paused);
|
1128
|
1125
|
#endif
|
1129
|
1126
|
|
1130
|
|
- TERN_(HEATER_IDLE_HANDLER, bed_idle.update(ms));
|
|
1127
|
+ TERN_(HEATER_IDLE_HANDLER, heater_idle[IDLE_INDEX_BED].update(ms));
|
1131
|
1128
|
|
1132
|
|
- TERN_(HAS_THERMALLY_PROTECTED_BED, thermal_runaway_protection(tr_state_machine_bed, temp_bed.celsius, temp_bed.target, H_BED, THERMAL_PROTECTION_BED_PERIOD, THERMAL_PROTECTION_BED_HYSTERESIS));
|
|
1129
|
+ #if HAS_THERMALLY_PROTECTED_BED
|
|
1130
|
+ tr_state_machine[RUNAWAY_IND_BED].run(temp_bed.celsius, temp_bed.target, H_BED, THERMAL_PROTECTION_BED_PERIOD, THERMAL_PROTECTION_BED_HYSTERESIS);
|
|
1131
|
+ #endif
|
1133
|
1132
|
|
1134
|
1133
|
#if HEATER_IDLE_HANDLER
|
1135
|
|
- if (bed_idle.timed_out) {
|
|
1134
|
+ if (heater_idle[IDLE_INDEX_BED].timed_out) {
|
1136
|
1135
|
temp_bed.soft_pwm_amount = 0;
|
1137
|
1136
|
#if DISABLED(PIDTEMPBED)
|
1138
|
1137
|
WRITE_HEATER_BED(LOW);
|
|
@@ -1173,8 +1172,7 @@ void Temperature::manage_heater() {
|
1173
|
1172
|
#endif
|
1174
|
1173
|
|
1175
|
1174
|
#if ENABLED(THERMAL_PROTECTION_CHAMBER)
|
1176
|
|
- if (degChamber() > CHAMBER_MAXTEMP)
|
1177
|
|
- _temp_error(H_CHAMBER, str_t_thermal_runaway, GET_TEXT(MSG_THERMAL_RUNAWAY));
|
|
1175
|
+ if (degChamber() > CHAMBER_MAXTEMP) max_temp_error(H_CHAMBER);
|
1178
|
1176
|
#endif
|
1179
|
1177
|
|
1180
|
1178
|
#if WATCH_CHAMBER
|
|
@@ -1205,7 +1203,9 @@ void Temperature::manage_heater() {
|
1205
|
1203
|
WRITE_HEATER_CHAMBER(LOW);
|
1206
|
1204
|
}
|
1207
|
1205
|
|
1208
|
|
- TERN_(THERMAL_PROTECTION_CHAMBER, thermal_runaway_protection(tr_state_machine_chamber, temp_chamber.celsius, temp_chamber.target, H_CHAMBER, THERMAL_PROTECTION_CHAMBER_PERIOD, THERMAL_PROTECTION_CHAMBER_HYSTERESIS));
|
|
1206
|
+ #if ENABLED(THERMAL_PROTECTION_CHAMBER)
|
|
1207
|
+ tr_state_machine[RUNAWAY_IND_CHAMBER].run(temp_chamber.celsius, temp_chamber.target, H_CHAMBER, THERMAL_PROTECTION_CHAMBER_PERIOD, THERMAL_PROTECTION_CHAMBER_HYSTERESIS);
|
|
1208
|
+ #endif
|
1209
|
1209
|
}
|
1210
|
1210
|
|
1211
|
1211
|
// TODO: Implement true PID pwm
|
|
@@ -1935,61 +1935,66 @@ void Temperature::init() {
|
1935
|
1935
|
|
1936
|
1936
|
#if HAS_THERMAL_PROTECTION
|
1937
|
1937
|
|
1938
|
|
- #if ENABLED(THERMAL_PROTECTION_HOTENDS)
|
1939
|
|
- Temperature::tr_state_machine_t Temperature::tr_state_machine[HOTENDS]; // = { { TRInactive, 0 } };
|
1940
|
|
- #endif
|
1941
|
|
- #if HAS_THERMALLY_PROTECTED_BED
|
1942
|
|
- Temperature::tr_state_machine_t Temperature::tr_state_machine_bed; // = { TRInactive, 0 };
|
1943
|
|
- #endif
|
1944
|
|
- #if ENABLED(THERMAL_PROTECTION_CHAMBER)
|
1945
|
|
- Temperature::tr_state_machine_t Temperature::tr_state_machine_chamber; // = { TRInactive, 0 };
|
1946
|
|
- #endif
|
|
1938
|
+ Temperature::tr_state_machine_t Temperature::tr_state_machine[NR_HEATER_RUNAWAY]; // = { { TRInactive, 0 } };
|
1947
|
1939
|
|
1948
|
|
- void Temperature::thermal_runaway_protection(Temperature::tr_state_machine_t &sm, const float ¤t, const float &target, const heater_id_t heater_id, const uint16_t period_seconds, const uint16_t hysteresis_degc) {
|
|
1940
|
+ /**
|
|
1941
|
+ * @brief Thermal Runaway state machine for a single heater
|
|
1942
|
+ * @param current current measured temperature
|
|
1943
|
+ * @param target current target temperature
|
|
1944
|
+ * @param heater_id extruder index
|
|
1945
|
+ * @param period_seconds missed temperature allowed time
|
|
1946
|
+ * @param hysteresis_degc allowed distance from target
|
|
1947
|
+ *
|
|
1948
|
+ * TODO: Embed the last 3 parameters during init, if not less optimal
|
|
1949
|
+ */
|
|
1950
|
+ void Temperature::tr_state_machine_t::run(const float ¤t, const float &target, const heater_id_t heater_id, const uint16_t period_seconds, const uint16_t hysteresis_degc) {
|
1949
|
1951
|
|
1950
|
|
- static float tr_target_temperature[HOTENDS + 1] = { 0.0 };
|
|
1952
|
+ #if HEATER_IDLE_HANDLER
|
|
1953
|
+ // Convert the given heater_id_t to an idle array index
|
|
1954
|
+ const IdleIndex idle_index = idle_index_for_id(heater_id);
|
|
1955
|
+ #endif
|
1951
|
1956
|
|
1952
|
1957
|
/**
|
1953
|
1958
|
SERIAL_ECHO_START();
|
1954
|
1959
|
SERIAL_ECHOPGM("Thermal Runaway Running. Heater ID: ");
|
1955
|
|
- if (heater_id == H_CHAMBER) SERIAL_ECHOPGM("chamber");
|
1956
|
|
- if (heater_id < 0) SERIAL_ECHOPGM("bed"); else SERIAL_ECHO(heater_id);
|
1957
|
|
- SERIAL_ECHOPAIR(" ; State:", sm.state, " ; Timer:", sm.timer, " ; Temperature:", current, " ; Target Temp:", target);
|
1958
|
|
- if (heater_id >= 0)
|
1959
|
|
- SERIAL_ECHOPAIR(" ; Idle Timeout:", hotend_idle[heater_id].timed_out);
|
1960
|
|
- else
|
1961
|
|
- SERIAL_ECHOPAIR(" ; Idle Timeout:", bed_idle.timed_out);
|
1962
|
|
- SERIAL_EOL();
|
|
1960
|
+ switch (heater_id) {
|
|
1961
|
+ case H_BED: SERIAL_ECHOPGM("bed"); break;
|
|
1962
|
+ case H_CHAMBER: SERIAL_ECHOPGM("chamber"); break;
|
|
1963
|
+ default: SERIAL_ECHO(heater_id);
|
|
1964
|
+ }
|
|
1965
|
+ SERIAL_ECHOLNPAIR(
|
|
1966
|
+ " ; sizeof(running_temp):", sizeof(running_temp),
|
|
1967
|
+ " ; State:", state, " ; Timer:", timer, " ; Temperature:", current, " ; Target Temp:", target
|
|
1968
|
+ #if HEATER_IDLE_HANDLER
|
|
1969
|
+ , " ; Idle Timeout:", heater_idle[idle_index].timed_out
|
|
1970
|
+ #endif
|
|
1971
|
+ );
|
1963
|
1972
|
//*/
|
1964
|
1973
|
|
1965
|
|
- const int heater_index = heater_id >= 0 ? heater_id : HOTENDS;
|
1966
|
|
-
|
1967
|
1974
|
#if HEATER_IDLE_HANDLER
|
1968
|
1975
|
// If the heater idle timeout expires, restart
|
1969
|
|
- if ((heater_id >= 0 && hotend_idle[heater_id].timed_out)
|
1970
|
|
- || TERN0(HAS_HEATED_BED, (heater_id < 0 && bed_idle.timed_out))
|
1971
|
|
- ) {
|
1972
|
|
- sm.state = TRInactive;
|
1973
|
|
- tr_target_temperature[heater_index] = 0;
|
|
1976
|
+ if (heater_idle[idle_index].timed_out) {
|
|
1977
|
+ state = TRInactive;
|
|
1978
|
+ running_temp = 0;
|
1974
|
1979
|
}
|
1975
|
1980
|
else
|
1976
|
1981
|
#endif
|
1977
|
1982
|
{
|
1978
|
1983
|
// If the target temperature changes, restart
|
1979
|
|
- if (tr_target_temperature[heater_index] != target) {
|
1980
|
|
- tr_target_temperature[heater_index] = target;
|
1981
|
|
- sm.state = target > 0 ? TRFirstHeating : TRInactive;
|
|
1984
|
+ if (running_temp != target) {
|
|
1985
|
+ running_temp = target;
|
|
1986
|
+ state = target > 0 ? TRFirstHeating : TRInactive;
|
1982
|
1987
|
}
|
1983
|
1988
|
}
|
1984
|
1989
|
|
1985
|
|
- switch (sm.state) {
|
|
1990
|
+ switch (state) {
|
1986
|
1991
|
// Inactive state waits for a target temperature to be set
|
1987
|
1992
|
case TRInactive: break;
|
1988
|
1993
|
|
1989
|
1994
|
// When first heating, wait for the temperature to be reached then go to Stable state
|
1990
|
1995
|
case TRFirstHeating:
|
1991
|
|
- if (current < tr_target_temperature[heater_index]) break;
|
1992
|
|
- sm.state = TRStable;
|
|
1996
|
+ if (current < running_temp) break;
|
|
1997
|
+ state = TRStable;
|
1993
|
1998
|
|
1994
|
1999
|
// While the temperature is stable watch for a bad temperature
|
1995
|
2000
|
case TRStable:
|
|
@@ -1997,25 +2002,25 @@ void Temperature::init() {
|
1997
|
2002
|
#if ENABLED(ADAPTIVE_FAN_SLOWING)
|
1998
|
2003
|
if (adaptive_fan_slowing && heater_id >= 0) {
|
1999
|
2004
|
const int fan_index = _MIN(heater_id, FAN_COUNT - 1);
|
2000
|
|
- if (fan_speed[fan_index] == 0 || current >= tr_target_temperature[heater_id] - (hysteresis_degc * 0.25f))
|
|
2005
|
+ if (fan_speed[fan_index] == 0 || current >= running_temp - (hysteresis_degc * 0.25f))
|
2001
|
2006
|
fan_speed_scaler[fan_index] = 128;
|
2002
|
|
- else if (current >= tr_target_temperature[heater_id] - (hysteresis_degc * 0.3335f))
|
|
2007
|
+ else if (current >= running_temp - (hysteresis_degc * 0.3335f))
|
2003
|
2008
|
fan_speed_scaler[fan_index] = 96;
|
2004
|
|
- else if (current >= tr_target_temperature[heater_id] - (hysteresis_degc * 0.5f))
|
|
2009
|
+ else if (current >= running_temp - (hysteresis_degc * 0.5f))
|
2005
|
2010
|
fan_speed_scaler[fan_index] = 64;
|
2006
|
|
- else if (current >= tr_target_temperature[heater_id] - (hysteresis_degc * 0.8f))
|
|
2011
|
+ else if (current >= running_temp - (hysteresis_degc * 0.8f))
|
2007
|
2012
|
fan_speed_scaler[fan_index] = 32;
|
2008
|
2013
|
else
|
2009
|
2014
|
fan_speed_scaler[fan_index] = 0;
|
2010
|
2015
|
}
|
2011
|
2016
|
#endif
|
2012
|
2017
|
|
2013
|
|
- if (current >= tr_target_temperature[heater_index] - hysteresis_degc) {
|
2014
|
|
- sm.timer = millis() + SEC_TO_MS(period_seconds);
|
|
2018
|
+ if (current >= running_temp - hysteresis_degc) {
|
|
2019
|
+ timer = millis() + SEC_TO_MS(period_seconds);
|
2015
|
2020
|
break;
|
2016
|
2021
|
}
|
2017
|
|
- else if (PENDING(millis(), sm.timer)) break;
|
2018
|
|
- sm.state = TRRunaway;
|
|
2022
|
+ else if (PENDING(millis(), timer)) break;
|
|
2023
|
+ state = TRRunaway;
|
2019
|
2024
|
|
2020
|
2025
|
case TRRunaway:
|
2021
|
2026
|
TERN_(DWIN_CREALITY_LCD, Popup_Window_Temperature(0));
|
|
@@ -2086,8 +2091,8 @@ void Temperature::disable_all_heaters() {
|
2086
|
2091
|
if (p != paused) {
|
2087
|
2092
|
paused = p;
|
2088
|
2093
|
if (p) {
|
2089
|
|
- HOTEND_LOOP() hotend_idle[e].expire(); // Timeout immediately
|
2090
|
|
- TERN_(HAS_HEATED_BED, bed_idle.expire()); // Timeout immediately
|
|
2094
|
+ HOTEND_LOOP() heater_idle[e].expire(); // Timeout immediately
|
|
2095
|
+ TERN_(HAS_HEATED_BED, heater_idle[IDLE_INDEX_BED].expire()); // Timeout immediately
|
2091
|
2096
|
}
|
2092
|
2097
|
else {
|
2093
|
2098
|
HOTEND_LOOP() reset_hotend_idle_timer(e);
|
|
@@ -2333,9 +2338,7 @@ void Temperature::readings_ready() {
|
2333
|
2338
|
#else
|
2334
|
2339
|
#define BEDCMP(A,B) ((A)>(B))
|
2335
|
2340
|
#endif
|
2336
|
|
- const bool bed_on = temp_bed.target > 0
|
2337
|
|
- || TERN0(PIDTEMPBED, temp_bed.soft_pwm_amount) > 0
|
2338
|
|
- ;
|
|
2341
|
+ const bool bed_on = (temp_bed.target > 0) || TERN0(PIDTEMPBED, temp_bed.soft_pwm_amount > 0);
|
2339
|
2342
|
if (BEDCMP(temp_bed.raw, maxtemp_raw_BED)) max_temp_error(H_BED);
|
2340
|
2343
|
if (bed_on && BEDCMP(mintemp_raw_BED, temp_bed.raw)) min_temp_error(H_BED);
|
2341
|
2344
|
#endif
|