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 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  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. #define E_UNUSED() UNUSED(e)
  37. #else
  38. #define HOTEND_INDEX e
  39. #define E_UNUSED()
  40. #endif
  41. // PID storage
  42. typedef struct { float Kp, Ki, Kd; } PID_t;
  43. typedef struct { float Kp, Ki, Kd, Kc; } PIDC_t;
  44. #if ENABLED(PID_EXTRUSION_SCALING)
  45. typedef PIDC_t hotend_pid_t;
  46. #if LPQ_MAX_LEN > 255
  47. typedef uint16_t lpq_ptr_t;
  48. #else
  49. typedef uint8_t lpq_ptr_t;
  50. #endif
  51. #else
  52. typedef PID_t hotend_pid_t;
  53. #endif
  54. #define DUMMY_PID_VALUE 3000.0f
  55. #if ENABLED(PIDTEMP)
  56. #define _PID_Kp(H) Temperature::temp_hotend[H].pid.Kp
  57. #define _PID_Ki(H) Temperature::temp_hotend[H].pid.Ki
  58. #define _PID_Kd(H) Temperature::temp_hotend[H].pid.Kd
  59. #if ENABLED(PID_EXTRUSION_SCALING)
  60. #define _PID_Kc(H) Temperature::temp_hotend[H].pid.Kc
  61. #else
  62. #define _PID_Kc(H) 1
  63. #endif
  64. #else
  65. #define _PID_Kp(H) DUMMY_PID_VALUE
  66. #define _PID_Ki(H) DUMMY_PID_VALUE
  67. #define _PID_Kd(H) DUMMY_PID_VALUE
  68. #define _PID_Kc(H) 1
  69. #endif
  70. #define PID_PARAM(F,H) _PID_##F(H)
  71. /**
  72. * States for ADC reading in the ISR
  73. */
  74. enum ADCSensorState : char {
  75. StartSampling,
  76. #if HAS_TEMP_ADC_0
  77. PrepareTemp_0,
  78. MeasureTemp_0,
  79. #endif
  80. #if HAS_HEATED_BED
  81. PrepareTemp_BED,
  82. MeasureTemp_BED,
  83. #endif
  84. #if HAS_TEMP_CHAMBER
  85. PrepareTemp_CHAMBER,
  86. MeasureTemp_CHAMBER,
  87. #endif
  88. #if HAS_TEMP_ADC_1
  89. PrepareTemp_1,
  90. MeasureTemp_1,
  91. #endif
  92. #if HAS_TEMP_ADC_2
  93. PrepareTemp_2,
  94. MeasureTemp_2,
  95. #endif
  96. #if HAS_TEMP_ADC_3
  97. PrepareTemp_3,
  98. MeasureTemp_3,
  99. #endif
  100. #if HAS_TEMP_ADC_4
  101. PrepareTemp_4,
  102. MeasureTemp_4,
  103. #endif
  104. #if HAS_TEMP_ADC_5
  105. PrepareTemp_5,
  106. MeasureTemp_5,
  107. #endif
  108. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  109. Prepare_FILWIDTH,
  110. Measure_FILWIDTH,
  111. #endif
  112. #if HAS_ADC_BUTTONS
  113. Prepare_ADC_KEY,
  114. Measure_ADC_KEY,
  115. #endif
  116. SensorsReady, // Temperatures ready. Delay the next round of readings to let ADC pins settle.
  117. StartupDelay // Startup, delay initial temp reading a tiny bit so the hardware can settle
  118. };
  119. // Minimum number of Temperature::ISR loops between sensor readings.
  120. // Multiplied by 16 (OVERSAMPLENR) to obtain the total time to
  121. // get all oversampled sensor readings
  122. #define MIN_ADC_ISR_LOOPS 10
  123. #define ACTUAL_ADC_SAMPLES MAX(int(MIN_ADC_ISR_LOOPS), int(SensorsReady))
  124. #if HAS_PID_HEATING
  125. #define PID_K2 (1-float(PID_K1))
  126. #define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / TEMP_TIMER_FREQUENCY)
  127. // Apply the scale factors to the PID values
  128. #define scalePID_i(i) ( float(i) * PID_dT )
  129. #define unscalePID_i(i) ( float(i) / PID_dT )
  130. #define scalePID_d(d) ( float(d) / PID_dT )
  131. #define unscalePID_d(d) ( float(d) * PID_dT )
  132. #endif
  133. #define G26_CLICK_CAN_CANCEL (HAS_LCD_MENU && ENABLED(G26_MESH_VALIDATION))
  134. enum TempIndex : uint8_t {
  135. #if HOTENDS > 0
  136. TEMP_E0,
  137. #if HOTENDS > 1
  138. TEMP_E1,
  139. #if HOTENDS > 2
  140. TEMP_E2,
  141. #if HOTENDS > 3
  142. TEMP_E3,
  143. #if HOTENDS > 4
  144. TEMP_E4,
  145. #if HOTENDS > 5
  146. TEMP_E5,
  147. #endif
  148. #endif
  149. #endif
  150. #endif
  151. #endif
  152. #endif
  153. #if HAS_HEATED_BED
  154. TEMP_BED,
  155. #endif
  156. #if HAS_HEATED_CHAMBER
  157. TEMP_CHAMBER,
  158. #endif
  159. tempCOUNT
  160. };
  161. // A temperature sensor
  162. typedef struct TempInfo {
  163. uint16_t acc;
  164. int16_t raw;
  165. float current;
  166. } temp_info_t;
  167. // A PWM heater with temperature sensor
  168. typedef struct HeaterInfo : public TempInfo {
  169. int16_t target;
  170. uint8_t soft_pwm_amount;
  171. } heater_info_t;
  172. // A heater with PID stabilization
  173. template<typename T>
  174. struct PIDHeaterInfo : public HeaterInfo {
  175. T pid; // Initialized by settings.load()
  176. };
  177. #if ENABLED(PIDTEMP)
  178. typedef struct PIDHeaterInfo<hotend_pid_t> hotend_info_t;
  179. #else
  180. typedef heater_info_t hotend_info_t;
  181. #endif
  182. #if HAS_HEATED_BED
  183. #if ENABLED(PIDTEMPBED)
  184. typedef struct PIDHeaterInfo<PID_t> bed_info_t;
  185. #else
  186. typedef heater_info_t bed_info_t;
  187. #endif
  188. #endif
  189. #if HAS_HEATED_CHAMBER
  190. typedef heater_info_t chamber_info_t;
  191. #elif HAS_TEMP_CHAMBER
  192. typedef temp_info_t chamber_info_t;
  193. #endif
  194. // Heater idle handling
  195. typedef struct {
  196. millis_t timeout_ms;
  197. bool timed_out;
  198. inline void update(const millis_t &ms) { if (!timed_out && timeout_ms && ELAPSED(ms, timeout_ms)) timed_out = true; }
  199. inline void start(const millis_t &ms) { timeout_ms = millis() + ms; timed_out = false; }
  200. inline void reset() { timeout_ms = 0; timed_out = false; }
  201. inline void expire() { start(0); }
  202. } heater_idle_t;
  203. // Heater watch handling
  204. typedef struct {
  205. uint16_t target;
  206. millis_t next_ms;
  207. inline bool elapsed(const millis_t &ms) { return next_ms && ELAPSED(ms, next_ms); }
  208. inline bool elapsed() { return elapsed(millis()); }
  209. } heater_watch_t;
  210. // Temperature sensor read value ranges
  211. typedef struct { int16_t raw_min, raw_max; } raw_range_t;
  212. typedef struct { int16_t mintemp, maxtemp; } celsius_range_t;
  213. typedef struct { int16_t raw_min, raw_max, mintemp, maxtemp; } temp_range_t;
  214. class Temperature {
  215. public:
  216. static volatile bool in_temp_isr;
  217. static hotend_info_t temp_hotend[HOTENDS];
  218. #if HAS_HEATED_BED
  219. static bed_info_t temp_bed;
  220. #endif
  221. #if HAS_TEMP_CHAMBER
  222. static chamber_info_t temp_chamber;
  223. #endif
  224. #if ENABLED(AUTO_POWER_E_FANS)
  225. static uint8_t autofan_speed[HOTENDS];
  226. #endif
  227. #if ENABLED(FAN_SOFT_PWM)
  228. static uint8_t soft_pwm_amount_fan[FAN_COUNT],
  229. soft_pwm_count_fan[FAN_COUNT];
  230. #endif
  231. #if ENABLED(PREVENT_COLD_EXTRUSION)
  232. static bool allow_cold_extrude;
  233. static int16_t extrude_min_temp;
  234. FORCE_INLINE static bool tooCold(const int16_t temp) { return allow_cold_extrude ? false : temp < extrude_min_temp; }
  235. FORCE_INLINE static bool tooColdToExtrude(const uint8_t e) {
  236. E_UNUSED();
  237. return tooCold(degHotend(HOTEND_INDEX));
  238. }
  239. FORCE_INLINE static bool targetTooColdToExtrude(const uint8_t e) {
  240. E_UNUSED();
  241. return tooCold(degTargetHotend(HOTEND_INDEX));
  242. }
  243. #else
  244. FORCE_INLINE static bool tooColdToExtrude(const uint8_t e) { UNUSED(e); return false; }
  245. FORCE_INLINE static bool targetTooColdToExtrude(const uint8_t e) { UNUSED(e); return false; }
  246. #endif
  247. FORCE_INLINE static bool hotEnoughToExtrude(const uint8_t e) { return !tooColdToExtrude(e); }
  248. FORCE_INLINE static bool targetHotEnoughToExtrude(const uint8_t e) { return !targetTooColdToExtrude(e); }
  249. #if HEATER_IDLE_HANDLER
  250. static heater_idle_t hotend_idle[HOTENDS];
  251. #if HAS_HEATED_BED
  252. static heater_idle_t bed_idle;
  253. #endif
  254. #if HAS_HEATED_CHAMBER
  255. static heater_idle_t chamber_idle;
  256. #endif
  257. #endif
  258. private:
  259. #if EARLY_WATCHDOG
  260. static bool inited; // If temperature controller is running
  261. #endif
  262. static volatile bool temp_meas_ready;
  263. #if WATCH_HOTENDS
  264. static heater_watch_t watch_hotend[HOTENDS];
  265. #endif
  266. #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
  267. static uint16_t redundant_temperature_raw;
  268. static float redundant_temperature;
  269. #endif
  270. #if ENABLED(PID_EXTRUSION_SCALING)
  271. static int32_t last_e_position, lpq[LPQ_MAX_LEN];
  272. static lpq_ptr_t lpq_ptr;
  273. #endif
  274. static temp_range_t temp_range[HOTENDS];
  275. #if HAS_HEATED_BED
  276. #if WATCH_BED
  277. static heater_watch_t watch_bed;
  278. #endif
  279. #if DISABLED(PIDTEMPBED)
  280. static millis_t next_bed_check_ms;
  281. #endif
  282. #ifdef BED_MINTEMP
  283. static int16_t mintemp_raw_BED;
  284. #endif
  285. #ifdef BED_MAXTEMP
  286. static int16_t maxtemp_raw_BED;
  287. #endif
  288. #endif
  289. #if HAS_HEATED_CHAMBER
  290. #if WATCH_CHAMBER
  291. static heater_watch_t watch_chamber;
  292. #endif
  293. static millis_t next_chamber_check_ms;
  294. #ifdef CHAMBER_MINTEMP
  295. static int16_t mintemp_raw_CHAMBER;
  296. #endif
  297. #ifdef CHAMBER_MAXTEMP
  298. static int16_t maxtemp_raw_CHAMBER;
  299. #endif
  300. #endif
  301. #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
  302. static uint8_t consecutive_low_temperature_error[HOTENDS];
  303. #endif
  304. #ifdef MILLISECONDS_PREHEAT_TIME
  305. static millis_t preheat_end_time[HOTENDS];
  306. #endif
  307. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  308. static int8_t meas_shift_index; // Index of a delayed sample in buffer
  309. #endif
  310. #if HAS_AUTO_FAN
  311. static millis_t next_auto_fan_check_ms;
  312. #endif
  313. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  314. static uint16_t current_raw_filwidth; // Measured filament diameter - one extruder only
  315. #endif
  316. #if ENABLED(PROBING_HEATERS_OFF)
  317. static bool paused;
  318. #endif
  319. public:
  320. #if HAS_ADC_BUTTONS
  321. static uint32_t current_ADCKey_raw;
  322. static uint8_t ADCKey_count;
  323. #endif
  324. #if ENABLED(PID_EXTRUSION_SCALING)
  325. static int16_t lpq_len;
  326. #endif
  327. /**
  328. * Instance Methods
  329. */
  330. Temperature();
  331. void init();
  332. /**
  333. * Static (class) methods
  334. */
  335. static float analog_to_celsius_hotend(const int raw, const uint8_t e);
  336. #if HAS_HEATED_BED
  337. static float analog_to_celsius_bed(const int raw);
  338. #endif
  339. #if HAS_TEMP_CHAMBER
  340. static float analog_to_celsius_chamber(const int raw);
  341. #endif
  342. #if FAN_COUNT > 0
  343. static uint8_t fan_speed[FAN_COUNT];
  344. #define FANS_LOOP(I) LOOP_L_N(I, FAN_COUNT)
  345. static void set_fan_speed(const uint8_t target, const uint16_t speed);
  346. #if ENABLED(PROBING_FANS_OFF)
  347. static bool fans_paused;
  348. #endif
  349. static constexpr inline uint8_t fanPercent(const uint8_t speed) { return ui8_to_percent(speed); }
  350. #if ENABLED(ADAPTIVE_FAN_SLOWING)
  351. static uint8_t fan_speed_scaler[FAN_COUNT];
  352. #else
  353. static constexpr uint8_t fan_speed_scaler[FAN_COUNT] = ARRAY_N(FAN_COUNT, 128, 128, 128, 128, 128, 128);
  354. #endif
  355. static inline uint8_t lcd_fanSpeedActual(const uint8_t target) {
  356. return (fan_speed[target] * uint16_t(fan_speed_scaler[target])) >> 7;
  357. }
  358. #if ENABLED(EXTRA_FAN_SPEED)
  359. static uint8_t old_fan_speed[FAN_COUNT], new_fan_speed[FAN_COUNT];
  360. static void set_temp_fan_speed(const uint8_t fan, const uint16_t tmp_temp);
  361. #endif
  362. #if HAS_LCD_MENU
  363. static uint8_t lcd_tmpfan_speed[
  364. #if ENABLED(SINGLENOZZLE)
  365. MAX(EXTRUDERS, FAN_COUNT)
  366. #else
  367. FAN_COUNT
  368. #endif
  369. ];
  370. static inline void lcd_setFanSpeed(const uint8_t target) { set_fan_speed(target, lcd_tmpfan_speed[target]); }
  371. #if HAS_FAN0
  372. FORCE_INLINE static void lcd_setFanSpeed0() { lcd_setFanSpeed(0); }
  373. #endif
  374. #if HAS_FAN1 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 1)
  375. FORCE_INLINE static void lcd_setFanSpeed1() { lcd_setFanSpeed(1); }
  376. #endif
  377. #if HAS_FAN2 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 2)
  378. FORCE_INLINE static void lcd_setFanSpeed2() { lcd_setFanSpeed(2); }
  379. #endif
  380. #endif // HAS_LCD_MENU
  381. #if EITHER(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
  382. void set_fans_paused(const bool p);
  383. #endif
  384. #endif // FAN_COUNT > 0
  385. static inline void zero_fan_speeds() {
  386. #if FAN_COUNT > 0
  387. FANS_LOOP(i) set_fan_speed(i, 0);
  388. #endif
  389. }
  390. /**
  391. * Called from the Temperature ISR
  392. */
  393. static void readings_ready();
  394. static void isr();
  395. /**
  396. * Call periodically to manage heaters
  397. */
  398. static void manage_heater() _O2; // Added _O2 to work around a compiler error
  399. /**
  400. * Preheating hotends
  401. */
  402. #ifdef MILLISECONDS_PREHEAT_TIME
  403. static bool is_preheating(const uint8_t e) {
  404. E_UNUSED();
  405. return preheat_end_time[HOTEND_INDEX] && PENDING(millis(), preheat_end_time[HOTEND_INDEX]);
  406. }
  407. static void start_preheat_time(const uint8_t e) {
  408. E_UNUSED();
  409. preheat_end_time[HOTEND_INDEX] = millis() + MILLISECONDS_PREHEAT_TIME;
  410. }
  411. static void reset_preheat_time(const uint8_t e) {
  412. E_UNUSED();
  413. preheat_end_time[HOTEND_INDEX] = 0;
  414. }
  415. #else
  416. #define is_preheating(n) (false)
  417. #endif
  418. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  419. static float analog_to_mm_fil_width(); // Convert raw Filament Width to millimeters
  420. static int8_t widthFil_to_size_ratio(); // Convert Filament Width (mm) to an extrusion ratio
  421. #endif
  422. //high level conversion routines, for use outside of temperature.cpp
  423. //inline so that there is no performance decrease.
  424. //deg=degreeCelsius
  425. FORCE_INLINE static float degHotend(const uint8_t e) {
  426. E_UNUSED();
  427. return temp_hotend[HOTEND_INDEX].current;
  428. }
  429. #if ENABLED(SHOW_TEMP_ADC_VALUES)
  430. FORCE_INLINE static int16_t rawHotendTemp(const uint8_t e) {
  431. E_UNUSED();
  432. return temp_hotend[HOTEND_INDEX].raw;
  433. }
  434. #endif
  435. FORCE_INLINE static int16_t degTargetHotend(const uint8_t e) {
  436. E_UNUSED();
  437. return temp_hotend[HOTEND_INDEX].target;
  438. }
  439. #if WATCH_HOTENDS
  440. static void start_watching_heater(const uint8_t e=0);
  441. #else
  442. static inline void start_watching_heater(const uint8_t e=0) { UNUSED(e); }
  443. #endif
  444. #if HAS_LCD_MENU
  445. static inline void start_watching_E0() { start_watching_heater(0); }
  446. static inline void start_watching_E1() { start_watching_heater(1); }
  447. static inline void start_watching_E2() { start_watching_heater(2); }
  448. static inline void start_watching_E3() { start_watching_heater(3); }
  449. static inline void start_watching_E4() { start_watching_heater(4); }
  450. static inline void start_watching_E5() { start_watching_heater(5); }
  451. #endif
  452. static void setTargetHotend(const int16_t celsius, const uint8_t e) {
  453. E_UNUSED();
  454. #ifdef MILLISECONDS_PREHEAT_TIME
  455. if (celsius == 0)
  456. reset_preheat_time(HOTEND_INDEX);
  457. else if (temp_hotend[HOTEND_INDEX].target == 0)
  458. start_preheat_time(HOTEND_INDEX);
  459. #endif
  460. #if ENABLED(AUTO_POWER_CONTROL)
  461. powerManager.power_on();
  462. #endif
  463. temp_hotend[HOTEND_INDEX].target = MIN(celsius, temp_range[HOTEND_INDEX].maxtemp - 15);
  464. start_watching_heater(HOTEND_INDEX);
  465. }
  466. #if WATCH_CHAMBER
  467. static void start_watching_chamber();
  468. #else
  469. static inline void start_watching_chamber() {}
  470. #endif
  471. #if HAS_TEMP_CHAMBER
  472. static void setTargetChamber(const int16_t celsius) {
  473. #if HAS_HEATED_CHAMBER
  474. temp_chamber.target =
  475. #ifdef CHAMBER_MAXTEMP
  476. MIN(celsius, CHAMBER_MAXTEMP)
  477. #else
  478. celsius
  479. #endif
  480. ;
  481. start_watching_chamber();
  482. #endif // HAS_HEATED_CHAMBER
  483. }
  484. #endif // HAS_TEMP_CHAMBER
  485. FORCE_INLINE static bool isHeatingHotend(const uint8_t e) {
  486. E_UNUSED();
  487. return temp_hotend[HOTEND_INDEX].target > temp_hotend[HOTEND_INDEX].current;
  488. }
  489. FORCE_INLINE static bool isCoolingHotend(const uint8_t e) {
  490. E_UNUSED();
  491. return temp_hotend[HOTEND_INDEX].target < temp_hotend[HOTEND_INDEX].current;
  492. }
  493. #if HAS_TEMP_HOTEND
  494. static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true
  495. #if G26_CLICK_CAN_CANCEL
  496. , const bool click_to_cancel=false
  497. #endif
  498. );
  499. #endif
  500. #if HAS_HEATED_BED
  501. #if ENABLED(SHOW_TEMP_ADC_VALUES)
  502. FORCE_INLINE static int16_t rawBedTemp() { return temp_bed.raw; }
  503. #endif
  504. FORCE_INLINE static float degBed() { return temp_bed.current; }
  505. FORCE_INLINE static int16_t degTargetBed() { return temp_bed.target; }
  506. FORCE_INLINE static bool isHeatingBed() { return temp_bed.target > temp_bed.current; }
  507. FORCE_INLINE static bool isCoolingBed() { return temp_bed.target < temp_bed.current; }
  508. #if WATCH_BED
  509. static void start_watching_bed();
  510. #else
  511. static inline void start_watching_bed() {}
  512. #endif
  513. static void setTargetBed(const int16_t celsius) {
  514. #if ENABLED(AUTO_POWER_CONTROL)
  515. powerManager.power_on();
  516. #endif
  517. temp_bed.target =
  518. #ifdef BED_MAXTEMP
  519. MIN(celsius, BED_MAXTEMP - 10)
  520. #else
  521. celsius
  522. #endif
  523. ;
  524. start_watching_bed();
  525. }
  526. static bool wait_for_bed(const bool no_wait_for_cooling=true
  527. #if G26_CLICK_CAN_CANCEL
  528. , const bool click_to_cancel=false
  529. #endif
  530. );
  531. #endif // HAS_HEATED_BED
  532. #if HAS_TEMP_CHAMBER
  533. #if ENABLED(SHOW_TEMP_ADC_VALUES)
  534. FORCE_INLINE static int16_t rawChamberTemp() { return temp_chamber.raw; }
  535. #endif
  536. FORCE_INLINE static float degChamber() { return temp_chamber.current; }
  537. #if HAS_HEATED_CHAMBER
  538. FORCE_INLINE static bool isHeatingChamber() { return temp_chamber.target > temp_chamber.current; }
  539. FORCE_INLINE static bool isCoolingChamber() { return temp_chamber.target < temp_chamber.current; }
  540. FORCE_INLINE static int16_t degTargetChamber() {return temp_chamber.target; }
  541. #endif
  542. #endif // HAS_TEMP_CHAMBER
  543. FORCE_INLINE static bool still_heating(const uint8_t e) {
  544. return degTargetHotend(e) > TEMP_HYSTERESIS && ABS(degHotend(e) - degTargetHotend(e)) > TEMP_HYSTERESIS;
  545. }
  546. /**
  547. * The software PWM power for a heater
  548. */
  549. static int16_t getHeaterPower(const int8_t heater);
  550. /**
  551. * Switch off all heaters, set all target temperatures to 0
  552. */
  553. static void disable_all_heaters();
  554. /**
  555. * Perform auto-tuning for hotend or bed in response to M303
  556. */
  557. #if HAS_PID_HEATING
  558. static void PID_autotune(const float &target, const int8_t hotend, const int8_t ncycles, const bool set_result=false);
  559. #if ENABLED(NO_FAN_SLOWING_IN_PID_TUNING)
  560. static bool adaptive_fan_slowing;
  561. #elif ENABLED(ADAPTIVE_FAN_SLOWING)
  562. static constexpr bool adaptive_fan_slowing = true;
  563. #endif
  564. /**
  565. * Update the temp manager when PID values change
  566. */
  567. #if ENABLED(PIDTEMP)
  568. FORCE_INLINE static void updatePID() {
  569. #if ENABLED(PID_EXTRUSION_SCALING)
  570. last_e_position = 0;
  571. #endif
  572. }
  573. #endif
  574. #endif
  575. #if ENABLED(PROBING_HEATERS_OFF)
  576. static void pause(const bool p);
  577. FORCE_INLINE static bool is_paused() { return paused; }
  578. #endif
  579. #if HEATER_IDLE_HANDLER
  580. static void reset_heater_idle_timer(const uint8_t e) {
  581. E_UNUSED();
  582. hotend_idle[HOTEND_INDEX].reset();
  583. start_watching_heater(HOTEND_INDEX);
  584. }
  585. #if HAS_HEATED_BED
  586. static void reset_bed_idle_timer() {
  587. bed_idle.reset();
  588. start_watching_bed();
  589. }
  590. #endif
  591. #endif // HEATER_IDLE_HANDLER
  592. #if HAS_TEMP_SENSOR
  593. static void print_heater_states(const uint8_t target_extruder);
  594. #if ENABLED(AUTO_REPORT_TEMPERATURES)
  595. static uint8_t auto_report_temp_interval;
  596. static millis_t next_temp_report_ms;
  597. static void auto_report_temperatures(void);
  598. static inline void set_auto_report_interval(uint8_t v) {
  599. NOMORE(v, 60);
  600. auto_report_temp_interval = v;
  601. next_temp_report_ms = millis() + 1000UL * v;
  602. }
  603. #endif
  604. #endif
  605. #if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
  606. static void set_heating_message(const uint8_t e);
  607. #endif
  608. private:
  609. static void set_current_temp_raw();
  610. static void updateTemperaturesFromRawValues();
  611. #define HAS_MAX6675 EITHER(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675)
  612. #if HAS_MAX6675
  613. #if BOTH(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675)
  614. #define COUNT_6675 2
  615. #else
  616. #define COUNT_6675 1
  617. #endif
  618. #if COUNT_6675 > 1
  619. #define READ_MAX6675(N) read_max6675(N)
  620. #else
  621. #define READ_MAX6675(N) read_max6675()
  622. #endif
  623. static int read_max6675(
  624. #if COUNT_6675 > 1
  625. const uint8_t hindex=0
  626. #endif
  627. );
  628. #endif
  629. static void checkExtruderAutoFans();
  630. static float get_pid_output(const int8_t e);
  631. #if ENABLED(PIDTEMPBED)
  632. static float get_pid_output_bed();
  633. #endif
  634. #if HAS_HEATED_CHAMBER
  635. static float get_pid_output_chamber();
  636. #endif
  637. static void _temp_error(const int8_t e, PGM_P const serial_msg, PGM_P const lcd_msg);
  638. static void min_temp_error(const int8_t e);
  639. static void max_temp_error(const int8_t e);
  640. #if HAS_TEMP_CHAMBER
  641. static void chamber_temp_error(const bool max);
  642. #endif
  643. #if ENABLED(THERMAL_PROTECTION_HOTENDS) || HAS_THERMALLY_PROTECTED_BED || ENABLED(THERMAL_PROTECTION_CHAMBER)
  644. enum TRState : char { TRInactive, TRFirstHeating, TRStable, TRRunaway };
  645. typedef struct {
  646. millis_t timer = 0;
  647. TRState state = TRInactive;
  648. } tr_state_machine_t;
  649. #if ENABLED(THERMAL_PROTECTION_HOTENDS)
  650. static tr_state_machine_t tr_state_machine[HOTENDS];
  651. #endif
  652. #if HAS_THERMALLY_PROTECTED_BED
  653. static tr_state_machine_t tr_state_machine_bed;
  654. #endif
  655. #if ENABLED(THERMAL_PROTECTION_CHAMBER)
  656. static tr_state_machine_t tr_state_machine_chamber;
  657. #endif
  658. static void thermal_runaway_protection(tr_state_machine_t &state, const float &current, const float &target, const int8_t heater_id, const uint16_t period_seconds, const uint16_t hysteresis_degc);
  659. #endif // THERMAL_PROTECTION
  660. };
  661. extern Temperature thermalManager;