My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

temperature.h 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (C) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #pragma once
  23. /**
  24. * temperature.h - temperature controller
  25. */
  26. #include "thermistor/thermistors.h"
  27. #include "../inc/MarlinConfig.h"
  28. #if ENABLED(AUTO_POWER_CONTROL)
  29. #include "../feature/power.h"
  30. #endif
  31. #ifndef SOFT_PWM_SCALE
  32. #define SOFT_PWM_SCALE 0
  33. #endif
  34. #if HOTENDS == 1
  35. #define HOTEND_INDEX 0
  36. #else
  37. #define HOTEND_INDEX e
  38. #endif
  39. // PID storage
  40. typedef struct { float Kp, Ki, Kd; } PID_t;
  41. typedef struct { float Kp, Ki, Kd, Kc; } PIDC_t;
  42. #if ENABLED(PID_EXTRUSION_SCALING)
  43. typedef PIDC_t hotend_pid_t;
  44. #else
  45. typedef PID_t hotend_pid_t;
  46. #endif
  47. #define DUMMY_PID_VALUE 3000.0f
  48. #if ENABLED(PIDTEMP)
  49. #define _PID_Kp(H) Temperature::pid[H].Kp
  50. #define _PID_Ki(H) Temperature::pid[H].Ki
  51. #define _PID_Kd(H) Temperature::pid[H].Kd
  52. #if ENABLED(PID_EXTRUSION_SCALING)
  53. #define _PID_Kc(H) Temperature::pid[H].Kc
  54. #else
  55. #define _PID_Kc(H) 1
  56. #endif
  57. #else
  58. #define _PID_Kp(H) DUMMY_PID_VALUE
  59. #define _PID_Ki(H) DUMMY_PID_VALUE
  60. #define _PID_Kd(H) DUMMY_PID_VALUE
  61. #define _PID_Kc(H) 1
  62. #endif
  63. #define PID_PARAM(F,H) _PID_##F(H)
  64. /**
  65. * States for ADC reading in the ISR
  66. */
  67. enum ADCSensorState : char {
  68. StartSampling,
  69. #if HAS_TEMP_ADC_0
  70. PrepareTemp_0,
  71. MeasureTemp_0,
  72. #endif
  73. #if HAS_TEMP_ADC_1
  74. PrepareTemp_1,
  75. MeasureTemp_1,
  76. #endif
  77. #if HAS_TEMP_ADC_2
  78. PrepareTemp_2,
  79. MeasureTemp_2,
  80. #endif
  81. #if HAS_TEMP_ADC_3
  82. PrepareTemp_3,
  83. MeasureTemp_3,
  84. #endif
  85. #if HAS_TEMP_ADC_4
  86. PrepareTemp_4,
  87. MeasureTemp_4,
  88. #endif
  89. #if HAS_HEATED_BED
  90. PrepareTemp_BED,
  91. MeasureTemp_BED,
  92. #endif
  93. #if HAS_TEMP_CHAMBER
  94. PrepareTemp_CHAMBER,
  95. MeasureTemp_CHAMBER,
  96. #endif
  97. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  98. Prepare_FILWIDTH,
  99. Measure_FILWIDTH,
  100. #endif
  101. #if HAS_ADC_BUTTONS
  102. Prepare_ADC_KEY,
  103. Measure_ADC_KEY,
  104. #endif
  105. SensorsReady, // Temperatures ready. Delay the next round of readings to let ADC pins settle.
  106. StartupDelay // Startup, delay initial temp reading a tiny bit so the hardware can settle
  107. };
  108. // Minimum number of Temperature::ISR loops between sensor readings.
  109. // Multiplied by 16 (OVERSAMPLENR) to obtain the total time to
  110. // get all oversampled sensor readings
  111. #define MIN_ADC_ISR_LOOPS 10
  112. #define ACTUAL_ADC_SAMPLES MAX(int(MIN_ADC_ISR_LOOPS), int(SensorsReady))
  113. #if HAS_PID_HEATING
  114. #define PID_K2 (1-float(PID_K1))
  115. #define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / TEMP_TIMER_FREQUENCY)
  116. // Apply the scale factors to the PID values
  117. #define scalePID_i(i) ( float(i) * PID_dT )
  118. #define unscalePID_i(i) ( float(i) / PID_dT )
  119. #define scalePID_d(d) ( float(d) / PID_dT )
  120. #define unscalePID_d(d) ( float(d) * PID_dT )
  121. #endif
  122. #define G26_CLICK_CAN_CANCEL (HAS_LCD_MENU && ENABLED(G26_MESH_VALIDATION))
  123. class Temperature {
  124. public:
  125. static volatile bool in_temp_isr;
  126. static float current_temperature[HOTENDS];
  127. static int16_t current_temperature_raw[HOTENDS],
  128. target_temperature[HOTENDS];
  129. static uint8_t soft_pwm_amount[HOTENDS];
  130. #if ENABLED(AUTO_POWER_E_FANS)
  131. static uint8_t autofan_speed[HOTENDS];
  132. #endif
  133. #if ENABLED(FAN_SOFT_PWM)
  134. static uint8_t soft_pwm_amount_fan[FAN_COUNT],
  135. soft_pwm_count_fan[FAN_COUNT];
  136. #endif
  137. #if ENABLED(PIDTEMP)
  138. static hotend_pid_t pid[HOTENDS];
  139. #endif
  140. #if HAS_HEATED_BED
  141. static float current_temperature_bed;
  142. static int16_t current_temperature_bed_raw, target_temperature_bed;
  143. static uint8_t soft_pwm_amount_bed;
  144. #if ENABLED(PIDTEMPBED)
  145. static PID_t bed_pid;
  146. #endif
  147. #endif
  148. #if ENABLED(BABYSTEPPING)
  149. static volatile int16_t babystepsTodo[3];
  150. #endif
  151. #if ENABLED(PREVENT_COLD_EXTRUSION)
  152. static bool allow_cold_extrude;
  153. static int16_t extrude_min_temp;
  154. FORCE_INLINE static bool tooCold(const int16_t temp) { return allow_cold_extrude ? false : temp < extrude_min_temp; }
  155. FORCE_INLINE static bool tooColdToExtrude(const uint8_t e) {
  156. #if HOTENDS == 1
  157. UNUSED(e);
  158. #endif
  159. return tooCold(degHotend(HOTEND_INDEX));
  160. }
  161. FORCE_INLINE static bool targetTooColdToExtrude(const uint8_t e) {
  162. #if HOTENDS == 1
  163. UNUSED(e);
  164. #endif
  165. return tooCold(degTargetHotend(HOTEND_INDEX));
  166. }
  167. #else
  168. FORCE_INLINE static bool tooColdToExtrude(const uint8_t e) { UNUSED(e); return false; }
  169. FORCE_INLINE static bool targetTooColdToExtrude(const uint8_t e) { UNUSED(e); return false; }
  170. #endif
  171. FORCE_INLINE static bool hotEnoughToExtrude(const uint8_t e) { return !tooColdToExtrude(e); }
  172. FORCE_INLINE static bool targetHotEnoughToExtrude(const uint8_t e) { return !targetTooColdToExtrude(e); }
  173. private:
  174. #if EARLY_WATCHDOG
  175. static bool inited; // If temperature controller is running
  176. #endif
  177. static volatile bool temp_meas_ready;
  178. static uint16_t raw_temp_value[MAX_EXTRUDERS];
  179. #if WATCH_HOTENDS
  180. static uint16_t watch_target_temp[HOTENDS];
  181. static millis_t watch_heater_next_ms[HOTENDS];
  182. #endif
  183. #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
  184. static uint16_t redundant_temperature_raw;
  185. static float redundant_temperature;
  186. #endif
  187. #if ENABLED(PID_EXTRUSION_SCALING)
  188. static long last_e_position;
  189. static long lpq[LPQ_MAX_LEN];
  190. static int lpq_ptr;
  191. #endif
  192. // Init min and max temp with extreme values to prevent false errors during startup
  193. static int16_t minttemp_raw[HOTENDS],
  194. maxttemp_raw[HOTENDS],
  195. minttemp[HOTENDS],
  196. maxttemp[HOTENDS];
  197. #if HAS_HEATED_BED
  198. static uint16_t raw_temp_bed_value;
  199. #if WATCH_THE_BED
  200. static uint16_t watch_target_bed_temp;
  201. static millis_t watch_bed_next_ms;
  202. #endif
  203. #if DISABLED(PIDTEMPBED)
  204. static millis_t next_bed_check_ms;
  205. #endif
  206. #if HEATER_IDLE_HANDLER
  207. static millis_t bed_idle_timeout_ms;
  208. static bool bed_idle_timeout_exceeded;
  209. #endif
  210. #ifdef BED_MINTEMP
  211. static int16_t bed_minttemp_raw;
  212. #endif
  213. #ifdef BED_MAXTEMP
  214. static int16_t bed_maxttemp_raw;
  215. #endif
  216. #endif
  217. #if HAS_TEMP_CHAMBER
  218. static uint16_t raw_temp_chamber_value;
  219. static float current_temperature_chamber;
  220. static int16_t current_temperature_chamber_raw;
  221. #endif
  222. #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
  223. static uint8_t consecutive_low_temperature_error[HOTENDS];
  224. #endif
  225. #ifdef MILLISECONDS_PREHEAT_TIME
  226. static millis_t preheat_end_time[HOTENDS];
  227. #endif
  228. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  229. static int8_t meas_shift_index; // Index of a delayed sample in buffer
  230. #endif
  231. #if HAS_AUTO_FAN
  232. static millis_t next_auto_fan_check_ms;
  233. #endif
  234. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  235. static uint16_t current_raw_filwidth; // Measured filament diameter - one extruder only
  236. #endif
  237. #if ENABLED(PROBING_HEATERS_OFF)
  238. static bool paused;
  239. #endif
  240. #if HEATER_IDLE_HANDLER
  241. static millis_t heater_idle_timeout_ms[HOTENDS];
  242. static bool heater_idle_timeout_exceeded[HOTENDS];
  243. #endif
  244. public:
  245. #if HAS_ADC_BUTTONS
  246. static uint32_t current_ADCKey_raw;
  247. static uint8_t ADCKey_count;
  248. #endif
  249. #if ENABLED(PID_EXTRUSION_SCALING)
  250. static int16_t lpq_len;
  251. #endif
  252. /**
  253. * Instance Methods
  254. */
  255. Temperature();
  256. void init();
  257. /**
  258. * Static (class) methods
  259. */
  260. static float analog_to_celsius_hotend(const int raw, const uint8_t e);
  261. #if HAS_HEATED_BED
  262. static float analog_to_celsius_bed(const int raw);
  263. #endif
  264. #if HAS_TEMP_CHAMBER
  265. static float analog_to_celsiusChamber(const int raw);
  266. #endif
  267. #if FAN_COUNT > 0
  268. static uint8_t fan_speed[FAN_COUNT];
  269. #define FANS_LOOP(I) LOOP_L_N(I, FAN_COUNT)
  270. static void set_fan_speed(const uint8_t target, const uint16_t speed);
  271. #if ENABLED(PROBING_FANS_OFF)
  272. static bool fans_paused;
  273. static uint8_t paused_fan_speed[FAN_COUNT];
  274. #endif
  275. static constexpr inline uint8_t fanPercent(const uint8_t speed) { return (int(speed) * 100 + 127) / 255; }
  276. #if ENABLED(ADAPTIVE_FAN_SLOWING)
  277. static uint8_t fan_speed_scaler[FAN_COUNT];
  278. #else
  279. static constexpr uint8_t fan_speed_scaler[FAN_COUNT] = ARRAY_N(FAN_COUNT, 128, 128, 128, 128, 128, 128);
  280. #endif
  281. static inline uint8_t lcd_fanSpeedActual(const uint8_t target) {
  282. return (fan_speed[target] * uint16_t(fan_speed_scaler[target])) >> 7;
  283. }
  284. #if ENABLED(EXTRA_FAN_SPEED)
  285. static uint8_t old_fan_speed[FAN_COUNT], new_fan_speed[FAN_COUNT];
  286. static void set_temp_fan_speed(const uint8_t fan, const uint16_t tmp_temp);
  287. #endif
  288. #if HAS_LCD_MENU
  289. static uint8_t lcd_tmpfan_speed[
  290. #if ENABLED(SINGLENOZZLE)
  291. MAX(EXTRUDERS, FAN_COUNT)
  292. #else
  293. FAN_COUNT
  294. #endif
  295. ];
  296. static inline void lcd_setFanSpeed(const uint8_t target) { set_fan_speed(target, lcd_tmpfan_speed[target]); }
  297. #if HAS_FAN0
  298. FORCE_INLINE static void lcd_setFanSpeed0() { lcd_setFanSpeed(0); }
  299. #endif
  300. #if HAS_FAN1 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 1)
  301. FORCE_INLINE static void lcd_setFanSpeed1() { lcd_setFanSpeed(1); }
  302. #endif
  303. #if HAS_FAN2 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 2)
  304. FORCE_INLINE static void lcd_setFanSpeed2() { lcd_setFanSpeed(2); }
  305. #endif
  306. #endif // HAS_LCD_MENU
  307. #if ENABLED(PROBING_FANS_OFF)
  308. void set_fans_paused(const bool p);
  309. #endif
  310. #endif // FAN_COUNT > 0
  311. static inline void zero_fan_speeds() {
  312. #if FAN_COUNT > 0
  313. FANS_LOOP(i) set_fan_speed(i, 0);
  314. #endif
  315. }
  316. /**
  317. * Called from the Temperature ISR
  318. */
  319. static void readings_ready();
  320. static void isr();
  321. /**
  322. * Call periodically to manage heaters
  323. */
  324. static void manage_heater() _O2; // Added _O2 to work around a compiler error
  325. /**
  326. * Preheating hotends
  327. */
  328. #ifdef MILLISECONDS_PREHEAT_TIME
  329. static bool is_preheating(const uint8_t e) {
  330. #if HOTENDS == 1
  331. UNUSED(e);
  332. #endif
  333. return preheat_end_time[HOTEND_INDEX] && PENDING(millis(), preheat_end_time[HOTEND_INDEX]);
  334. }
  335. static void start_preheat_time(const uint8_t e) {
  336. #if HOTENDS == 1
  337. UNUSED(e);
  338. #endif
  339. preheat_end_time[HOTEND_INDEX] = millis() + MILLISECONDS_PREHEAT_TIME;
  340. }
  341. static void reset_preheat_time(const uint8_t e) {
  342. #if HOTENDS == 1
  343. UNUSED(e);
  344. #endif
  345. preheat_end_time[HOTEND_INDEX] = 0;
  346. }
  347. #else
  348. #define is_preheating(n) (false)
  349. #endif
  350. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  351. static float analog_to_mm_fil_width(); // Convert raw Filament Width to millimeters
  352. static int8_t widthFil_to_size_ratio(); // Convert Filament Width (mm) to an extrusion ratio
  353. #endif
  354. //high level conversion routines, for use outside of temperature.cpp
  355. //inline so that there is no performance decrease.
  356. //deg=degreeCelsius
  357. FORCE_INLINE static float degHotend(const uint8_t e) {
  358. #if HOTENDS == 1
  359. UNUSED(e);
  360. #endif
  361. return current_temperature[HOTEND_INDEX];
  362. }
  363. #if ENABLED(SHOW_TEMP_ADC_VALUES)
  364. FORCE_INLINE static int16_t rawHotendTemp(const uint8_t e) {
  365. #if HOTENDS == 1
  366. UNUSED(e);
  367. #endif
  368. return current_temperature_raw[HOTEND_INDEX];
  369. }
  370. #endif
  371. FORCE_INLINE static int16_t degTargetHotend(const uint8_t e) {
  372. #if HOTENDS == 1
  373. UNUSED(e);
  374. #endif
  375. return target_temperature[HOTEND_INDEX];
  376. }
  377. #if WATCH_HOTENDS
  378. static void start_watching_heater(const uint8_t e = 0);
  379. #endif
  380. static void setTargetHotend(const int16_t celsius, const uint8_t e) {
  381. #if HOTENDS == 1
  382. UNUSED(e);
  383. #endif
  384. #ifdef MILLISECONDS_PREHEAT_TIME
  385. if (celsius == 0)
  386. reset_preheat_time(HOTEND_INDEX);
  387. else if (target_temperature[HOTEND_INDEX] == 0)
  388. start_preheat_time(HOTEND_INDEX);
  389. #endif
  390. #if ENABLED(AUTO_POWER_CONTROL)
  391. powerManager.power_on();
  392. #endif
  393. target_temperature[HOTEND_INDEX] = MIN(celsius, maxttemp[HOTEND_INDEX] - 15);
  394. #if WATCH_HOTENDS
  395. start_watching_heater(HOTEND_INDEX);
  396. #endif
  397. }
  398. FORCE_INLINE static bool isHeatingHotend(const uint8_t e) {
  399. #if HOTENDS == 1
  400. UNUSED(e);
  401. #endif
  402. return target_temperature[HOTEND_INDEX] > current_temperature[HOTEND_INDEX];
  403. }
  404. FORCE_INLINE static bool isCoolingHotend(const uint8_t e) {
  405. #if HOTENDS == 1
  406. UNUSED(e);
  407. #endif
  408. return target_temperature[HOTEND_INDEX] < current_temperature[HOTEND_INDEX];
  409. }
  410. #if HAS_TEMP_HOTEND
  411. static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true
  412. #if G26_CLICK_CAN_CANCEL
  413. , const bool click_to_cancel=false
  414. #endif
  415. );
  416. #endif
  417. #if HAS_HEATED_BED
  418. #if ENABLED(SHOW_TEMP_ADC_VALUES)
  419. FORCE_INLINE static int16_t rawBedTemp() { return current_temperature_bed_raw; }
  420. #endif
  421. FORCE_INLINE static float degBed() { return current_temperature_bed; }
  422. FORCE_INLINE static int16_t degTargetBed() { return target_temperature_bed; }
  423. FORCE_INLINE static bool isHeatingBed() { return target_temperature_bed > current_temperature_bed; }
  424. FORCE_INLINE static bool isCoolingBed() { return target_temperature_bed < current_temperature_bed; }
  425. static void setTargetBed(const int16_t celsius) {
  426. #if ENABLED(AUTO_POWER_CONTROL)
  427. powerManager.power_on();
  428. #endif
  429. target_temperature_bed =
  430. #ifdef BED_MAXTEMP
  431. MIN(celsius, BED_MAXTEMP - 15)
  432. #else
  433. celsius
  434. #endif
  435. ;
  436. #if WATCH_THE_BED
  437. start_watching_bed();
  438. #endif
  439. }
  440. #if WATCH_THE_BED
  441. static void start_watching_bed();
  442. #endif
  443. static bool wait_for_bed(const bool no_wait_for_cooling=true
  444. #if G26_CLICK_CAN_CANCEL
  445. , const bool click_to_cancel=false
  446. #endif
  447. );
  448. #endif // HAS_HEATED_BED
  449. #if HAS_TEMP_CHAMBER
  450. #if ENABLED(SHOW_TEMP_ADC_VALUES)
  451. FORCE_INLINE static int16_t rawChamberTemp() { return current_temperature_chamber_raw; }
  452. #endif
  453. FORCE_INLINE static float degChamber() { return current_temperature_chamber; }
  454. #endif
  455. FORCE_INLINE static bool still_heating(const uint8_t e) {
  456. return degTargetHotend(e) > TEMP_HYSTERESIS && ABS(degHotend(e) - degTargetHotend(e)) > TEMP_HYSTERESIS;
  457. }
  458. /**
  459. * The software PWM power for a heater
  460. */
  461. static int getHeaterPower(const int heater);
  462. /**
  463. * Switch off all heaters, set all target temperatures to 0
  464. */
  465. static void disable_all_heaters();
  466. /**
  467. * Perform auto-tuning for hotend or bed in response to M303
  468. */
  469. #if HAS_PID_HEATING
  470. static void PID_autotune(const float &target, const int8_t hotend, const int8_t ncycles, const bool set_result=false);
  471. #if ENABLED(NO_FAN_SLOWING_IN_PID_TUNING)
  472. static bool adaptive_fan_slowing;
  473. #elif ENABLED(ADAPTIVE_FAN_SLOWING)
  474. constexpr static bool adaptive_fan_slowing = true;
  475. #endif
  476. /**
  477. * Update the temp manager when PID values change
  478. */
  479. #if ENABLED(PIDTEMP)
  480. FORCE_INLINE static void updatePID() {
  481. #if ENABLED(PID_EXTRUSION_SCALING)
  482. last_e_position = 0;
  483. #endif
  484. }
  485. #endif
  486. #endif
  487. #if ENABLED(BABYSTEPPING)
  488. static void babystep_axis(const AxisEnum axis, const int16_t distance);
  489. #endif
  490. #if ENABLED(PROBING_HEATERS_OFF)
  491. static void pause(const bool p);
  492. FORCE_INLINE static bool is_paused() { return paused; }
  493. #endif
  494. #if HEATER_IDLE_HANDLER
  495. static void start_heater_idle_timer(const uint8_t e, const millis_t timeout_ms) {
  496. #if HOTENDS == 1
  497. UNUSED(e);
  498. #endif
  499. heater_idle_timeout_ms[HOTEND_INDEX] = millis() + timeout_ms;
  500. heater_idle_timeout_exceeded[HOTEND_INDEX] = false;
  501. }
  502. static void reset_heater_idle_timer(const uint8_t e) {
  503. #if HOTENDS == 1
  504. UNUSED(e);
  505. #endif
  506. heater_idle_timeout_ms[HOTEND_INDEX] = 0;
  507. heater_idle_timeout_exceeded[HOTEND_INDEX] = false;
  508. #if WATCH_HOTENDS
  509. start_watching_heater(HOTEND_INDEX);
  510. #endif
  511. }
  512. FORCE_INLINE static bool is_heater_idle(const uint8_t e) {
  513. #if HOTENDS == 1
  514. UNUSED(e);
  515. #endif
  516. return heater_idle_timeout_exceeded[HOTEND_INDEX];
  517. }
  518. #if HAS_HEATED_BED
  519. static void start_bed_idle_timer(const millis_t timeout_ms) {
  520. bed_idle_timeout_ms = millis() + timeout_ms;
  521. bed_idle_timeout_exceeded = false;
  522. }
  523. static void reset_bed_idle_timer() {
  524. bed_idle_timeout_ms = 0;
  525. bed_idle_timeout_exceeded = false;
  526. #if WATCH_THE_BED
  527. start_watching_bed();
  528. #endif
  529. }
  530. FORCE_INLINE static bool is_bed_idle() { return bed_idle_timeout_exceeded; }
  531. #endif
  532. #endif // HEATER_IDLE_HANDLER
  533. #if HAS_TEMP_SENSOR
  534. static void print_heater_states(const uint8_t target_extruder);
  535. #if ENABLED(AUTO_REPORT_TEMPERATURES)
  536. static uint8_t auto_report_temp_interval;
  537. static millis_t next_temp_report_ms;
  538. static void auto_report_temperatures(void);
  539. FORCE_INLINE void set_auto_report_interval(uint8_t v) {
  540. NOMORE(v, 60);
  541. auto_report_temp_interval = v;
  542. next_temp_report_ms = millis() + 1000UL * v;
  543. }
  544. #endif
  545. #endif
  546. #if ENABLED(ULTRA_LCD) || ENABLED(EXTENSIBLE_UI)
  547. static void set_heating_message(const uint8_t e);
  548. #endif
  549. private:
  550. #if ENABLED(FAST_PWM_FAN)
  551. static void setPwmFrequency(const pin_t pin, int val);
  552. #endif
  553. static void set_current_temp_raw();
  554. static void updateTemperaturesFromRawValues();
  555. #define HAS_MAX6675 (ENABLED(HEATER_0_USES_MAX6675) || ENABLED(HEATER_1_USES_MAX6675))
  556. #if HAS_MAX6675
  557. #if ENABLED(HEATER_0_USES_MAX6675) && ENABLED(HEATER_1_USES_MAX6675)
  558. #define COUNT_6675 2
  559. #else
  560. #define COUNT_6675 1
  561. #endif
  562. #if COUNT_6675 > 1
  563. #define READ_MAX6675(N) read_max6675(N)
  564. #else
  565. #define READ_MAX6675(N) read_max6675()
  566. #endif
  567. static int read_max6675(
  568. #if COUNT_6675 > 1
  569. const uint8_t hindex=0
  570. #endif
  571. );
  572. #endif
  573. static void checkExtruderAutoFans();
  574. static float get_pid_output(const int8_t e);
  575. #if ENABLED(PIDTEMPBED)
  576. static float get_pid_output_bed();
  577. #endif
  578. static void _temp_error(const int8_t e, PGM_P const serial_msg, PGM_P const lcd_msg);
  579. static void min_temp_error(const int8_t e);
  580. static void max_temp_error(const int8_t e);
  581. #if ENABLED(THERMAL_PROTECTION_HOTENDS) || HAS_THERMALLY_PROTECTED_BED
  582. enum TRState : char { TRInactive, TRFirstHeating, TRStable, TRRunaway };
  583. static void thermal_runaway_protection(TRState * const state, millis_t * const timer, const float &current, const float &target, const int8_t heater_id, const uint16_t period_seconds, const uint16_t hysteresis_degc);
  584. #if ENABLED(THERMAL_PROTECTION_HOTENDS)
  585. static TRState thermal_runaway_state_machine[HOTENDS];
  586. static millis_t thermal_runaway_timer[HOTENDS];
  587. #endif
  588. #if HAS_THERMALLY_PROTECTED_BED
  589. static TRState thermal_runaway_bed_state_machine;
  590. static millis_t thermal_runaway_bed_timer;
  591. #endif
  592. #endif // THERMAL_PROTECTION
  593. };
  594. extern Temperature thermalManager;