|
@@ -1318,104 +1318,101 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
|
1318
|
1318
|
}
|
1319
|
1319
|
|
1320
|
1320
|
#if ANY(PID_DEBUG, PID_BED_DEBUG, PID_CHAMBER_DEBUG)
|
1321
|
|
- bool Temperature::pid_debug_flag; // = 0
|
|
1321
|
+ #define HAS_PID_DEBUG 1
|
|
1322
|
+ bool Temperature::pid_debug_flag; // = false
|
1322
|
1323
|
#endif
|
1323
|
1324
|
|
1324
|
|
-#if HAS_HOTEND
|
|
1325
|
+#if HAS_PID_HEATING
|
1325
|
1326
|
|
1326
|
|
- float Temperature::get_pid_output_hotend(const uint8_t E_NAME) {
|
1327
|
|
- const uint8_t ee = HOTEND_INDEX;
|
1328
|
|
- #if ENABLED(PIDTEMP)
|
1329
|
|
- #if DISABLED(PID_OPENLOOP)
|
1330
|
|
- static hotend_pid_t work_pid[HOTENDS];
|
1331
|
|
- static float temp_iState[HOTENDS] = { 0 },
|
1332
|
|
- temp_dState[HOTENDS] = { 0 };
|
1333
|
|
- static Flags<HOTENDS> pid_reset;
|
1334
|
|
- const float pid_error = temp_hotend[ee].target - temp_hotend[ee].celsius;
|
1335
|
|
-
|
1336
|
|
- float pid_output;
|
1337
|
|
-
|
1338
|
|
- if (temp_hotend[ee].target == 0
|
1339
|
|
- || pid_error < -(PID_FUNCTIONAL_RANGE)
|
1340
|
|
- || TERN0(HEATER_IDLE_HANDLER, heater_idle[ee].timed_out)
|
1341
|
|
- ) {
|
1342
|
|
- pid_output = 0;
|
1343
|
|
- pid_reset.set(ee);
|
|
1327
|
+ template<typename TT, int MIN_POW, int MAX_POW>
|
|
1328
|
+ class PIDRunner {
|
|
1329
|
+ public:
|
|
1330
|
+ TT &tempinfo;
|
|
1331
|
+ __typeof__(TT::pid) work_pid{0};
|
|
1332
|
+ float temp_iState = 0, temp_dState = 0;
|
|
1333
|
+ bool pid_reset = true;
|
|
1334
|
+
|
|
1335
|
+ PIDRunner(TT &t) : tempinfo(t) { }
|
|
1336
|
+
|
|
1337
|
+ float get_pid_output() {
|
|
1338
|
+
|
|
1339
|
+ #if ENABLED(PID_OPENLOOP)
|
|
1340
|
+
|
|
1341
|
+ return constrain(tempinfo.target, 0, MAX_POW);
|
|
1342
|
+
|
|
1343
|
+ #else // !PID_OPENLOOP
|
|
1344
|
+
|
|
1345
|
+ const float pid_error = tempinfo.target - tempinfo.celsius;
|
|
1346
|
+ if (!tempinfo.target || pid_error < -(PID_FUNCTIONAL_RANGE)) {
|
|
1347
|
+ pid_reset = true;
|
|
1348
|
+ return 0;
|
1344
|
1349
|
}
|
1345
|
1350
|
else if (pid_error > PID_FUNCTIONAL_RANGE) {
|
1346
|
|
- pid_output = PID_MAX;
|
1347
|
|
- pid_reset.set(ee);
|
|
1351
|
+ pid_reset = true;
|
|
1352
|
+ return MAX_POW;
|
1348
|
1353
|
}
|
1349
|
|
- else {
|
1350
|
|
- if (pid_reset[ee]) {
|
1351
|
|
- temp_iState[ee] = 0.0;
|
1352
|
|
- work_pid[ee].Kd = 0.0;
|
1353
|
|
- pid_reset.clear(ee);
|
1354
|
|
- }
|
1355
|
1354
|
|
1356
|
|
- work_pid[ee].Kd = work_pid[ee].Kd + PID_K2 * (PID_PARAM(Kd, ee) * (temp_dState[ee] - temp_hotend[ee].celsius) - work_pid[ee].Kd);
|
1357
|
|
- const float max_power_over_i_gain = float(PID_MAX) / PID_PARAM(Ki, ee) - float(MIN_POWER);
|
1358
|
|
- temp_iState[ee] = constrain(temp_iState[ee] + pid_error, 0, max_power_over_i_gain);
|
1359
|
|
- work_pid[ee].Kp = PID_PARAM(Kp, ee) * pid_error;
|
1360
|
|
- work_pid[ee].Ki = PID_PARAM(Ki, ee) * temp_iState[ee];
|
|
1355
|
+ if (pid_reset) {
|
|
1356
|
+ pid_reset = false;
|
|
1357
|
+ temp_iState = 0.0;
|
|
1358
|
+ work_pid.Kd = 0.0;
|
|
1359
|
+ }
|
1361
|
1360
|
|
1362
|
|
- pid_output = work_pid[ee].Kp + work_pid[ee].Ki + work_pid[ee].Kd + float(MIN_POWER);
|
|
1361
|
+ const float max_power_over_i_gain = float(MAX_POW) / tempinfo.pid.Ki - float(MIN_POW);
|
|
1362
|
+ temp_iState = constrain(temp_iState + pid_error, 0, max_power_over_i_gain);
|
1363
|
1363
|
|
1364
|
|
- #if ENABLED(PID_EXTRUSION_SCALING)
|
1365
|
|
- #if HOTENDS == 1
|
1366
|
|
- constexpr bool this_hotend = true;
|
1367
|
|
- #else
|
1368
|
|
- const bool this_hotend = (ee == active_extruder);
|
1369
|
|
- #endif
|
1370
|
|
- work_pid[ee].Kc = 0;
|
1371
|
|
- if (this_hotend) {
|
1372
|
|
- const long e_position = stepper.position(E_AXIS);
|
1373
|
|
- if (e_position > pes_e_position) {
|
1374
|
|
- lpq[lpq_ptr] = e_position - pes_e_position;
|
1375
|
|
- pes_e_position = e_position;
|
1376
|
|
- }
|
1377
|
|
- else
|
1378
|
|
- lpq[lpq_ptr] = 0;
|
|
1364
|
+ work_pid.Kp = tempinfo.pid.Kp * pid_error;
|
|
1365
|
+ work_pid.Ki = tempinfo.pid.Ki * temp_iState;
|
|
1366
|
+ work_pid.Kd = work_pid.Kd + PID_K2 * (tempinfo.pid.Kd * (temp_dState - tempinfo.celsius) - work_pid.Kd);
|
1379
|
1367
|
|
1380
|
|
- if (++lpq_ptr >= lpq_len) lpq_ptr = 0;
|
1381
|
|
- work_pid[ee].Kc = (lpq[lpq_ptr] * planner.mm_per_step[E_AXIS]) * PID_PARAM(Kc, ee);
|
1382
|
|
- pid_output += work_pid[ee].Kc;
|
1383
|
|
- }
|
1384
|
|
- #endif // PID_EXTRUSION_SCALING
|
1385
|
|
- #if ENABLED(PID_FAN_SCALING)
|
1386
|
|
- if (fan_speed[active_extruder] > PID_FAN_SCALING_MIN_SPEED) {
|
1387
|
|
- work_pid[ee].Kf = PID_PARAM(Kf, ee) + (PID_FAN_SCALING_LIN_FACTOR) * fan_speed[active_extruder];
|
1388
|
|
- pid_output += work_pid[ee].Kf;
|
1389
|
|
- }
|
1390
|
|
- //pid_output -= work_pid[ee].Ki;
|
1391
|
|
- //pid_output += work_pid[ee].Ki * work_pid[ee].Kf
|
1392
|
|
- #endif // PID_FAN_SCALING
|
1393
|
|
- LIMIT(pid_output, 0, PID_MAX);
|
1394
|
|
- }
|
1395
|
|
- temp_dState[ee] = temp_hotend[ee].celsius;
|
|
1368
|
+ temp_dState = tempinfo.celsius;
|
1396
|
1369
|
|
1397
|
|
- #else // PID_OPENLOOP
|
|
1370
|
+ return constrain(work_pid.Kp + work_pid.Ki + work_pid.Kd + float(MIN_POW), 0, MAX_POW);
|
1398
|
1371
|
|
1399
|
|
- const float pid_output = constrain(temp_hotend[ee].target, 0, PID_MAX);
|
|
1372
|
+ #endif // !PID_OPENLOOP
|
|
1373
|
+ }
|
1400
|
1374
|
|
1401
|
|
- #endif // PID_OPENLOOP
|
|
1375
|
+ FORCE_INLINE void debug(const_celsius_float_t c, const_float_t pid_out, FSTR_P const name=nullptr, const int8_t index=-1) {
|
|
1376
|
+ if (TERN0(HAS_PID_DEBUG, thermalManager.pid_debug_flag)) {
|
|
1377
|
+ SERIAL_ECHO_START();
|
|
1378
|
+ if (name) SERIAL_ECHOLNF(name);
|
|
1379
|
+ if (index >= 0) SERIAL_ECHO(index);
|
|
1380
|
+ SERIAL_ECHOLNPGM(
|
|
1381
|
+ STR_PID_DEBUG_INPUT, c,
|
|
1382
|
+ STR_PID_DEBUG_OUTPUT, pid_out
|
|
1383
|
+ #if DISABLED(PID_OPENLOOP)
|
|
1384
|
+ , "pTerm", work_pid.Kp, "iTerm", work_pid.Ki, "dTerm", work_pid.Kd
|
|
1385
|
+ #endif
|
|
1386
|
+ );
|
|
1387
|
+ }
|
|
1388
|
+ }
|
|
1389
|
+ };
|
|
1390
|
+
|
|
1391
|
+#endif // HAS_PID_HEATING
|
|
1392
|
+
|
|
1393
|
+#if HAS_HOTEND
|
|
1394
|
+
|
|
1395
|
+ float Temperature::get_pid_output_hotend(const uint8_t E_NAME) {
|
|
1396
|
+ const uint8_t ee = HOTEND_INDEX;
|
|
1397
|
+
|
|
1398
|
+ #if ENABLED(PIDTEMP)
|
|
1399
|
+
|
|
1400
|
+ typedef PIDRunner<hotend_info_t, 0, PID_MAX> PIDRunnerHotend;
|
|
1401
|
+
|
|
1402
|
+ static PIDRunnerHotend hotend_pid[HOTENDS] = {
|
|
1403
|
+ #define _HOTENDPID(E) temp_hotend[E],
|
|
1404
|
+ REPEAT(HOTENDS, _HOTENDPID)
|
|
1405
|
+ };
|
|
1406
|
+
|
|
1407
|
+ const float pid_output = hotend_pid[ee].get_pid_output();
|
1402
|
1408
|
|
1403
|
1409
|
#if ENABLED(PID_DEBUG)
|
1404
|
|
- if (ee == active_extruder && pid_debug_flag) {
|
1405
|
|
- SERIAL_ECHO_MSG(STR_PID_DEBUG, ee, STR_PID_DEBUG_INPUT, temp_hotend[ee].celsius, STR_PID_DEBUG_OUTPUT, pid_output
|
1406
|
|
- #if DISABLED(PID_OPENLOOP)
|
1407
|
|
- , STR_PID_DEBUG_PTERM, work_pid[ee].Kp
|
1408
|
|
- , STR_PID_DEBUG_ITERM, work_pid[ee].Ki
|
1409
|
|
- , STR_PID_DEBUG_DTERM, work_pid[ee].Kd
|
1410
|
|
- #if ENABLED(PID_EXTRUSION_SCALING)
|
1411
|
|
- , STR_PID_DEBUG_CTERM, work_pid[ee].Kc
|
1412
|
|
- #endif
|
1413
|
|
- #endif
|
1414
|
|
- );
|
1415
|
|
- }
|
|
1410
|
+ if (ee == active_extruder)
|
|
1411
|
+ hotend_pid[ee].debug(temp_hotend[ee].celsius, pid_output, F("E"), ee);
|
1416
|
1412
|
#endif
|
1417
|
1413
|
|
1418
|
1414
|
#elif ENABLED(MPCTEMP)
|
|
1415
|
+
|
1419
|
1416
|
MPCHeaterInfo &hotend = temp_hotend[ee];
|
1420
|
1417
|
MPC_t &constants = hotend.constants;
|
1421
|
1418
|
|
|
@@ -1497,7 +1494,7 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
|
1497
|
1494
|
#else // No PID or MPC enabled
|
1498
|
1495
|
|
1499
|
1496
|
const bool is_idling = TERN0(HEATER_IDLE_HANDLER, heater_idle[ee].timed_out);
|
1500
|
|
- const float pid_output = (!is_idling && temp_hotend[ee].celsius < temp_hotend[ee].target) ? BANG_MAX : 0;
|
|
1497
|
+ const float pid_output = (!is_idling && temp_hotend[ee].is_below_target()) ? BANG_MAX : 0;
|
1501
|
1498
|
|
1502
|
1499
|
#endif
|
1503
|
1500
|
|
|
@@ -1509,61 +1506,9 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
|
1509
|
1506
|
#if ENABLED(PIDTEMPBED)
|
1510
|
1507
|
|
1511
|
1508
|
float Temperature::get_pid_output_bed() {
|
1512
|
|
-
|
1513
|
|
- #if DISABLED(PID_OPENLOOP)
|
1514
|
|
-
|
1515
|
|
- static PID_t work_pid{0};
|
1516
|
|
- static float temp_iState = 0, temp_dState = 0;
|
1517
|
|
- static bool pid_reset = true;
|
1518
|
|
- float pid_output = 0;
|
1519
|
|
- const float max_power_over_i_gain = float(MAX_BED_POWER) / temp_bed.pid.Ki - float(MIN_BED_POWER),
|
1520
|
|
- pid_error = temp_bed.target - temp_bed.celsius;
|
1521
|
|
-
|
1522
|
|
- if (!temp_bed.target || pid_error < -(PID_FUNCTIONAL_RANGE)) {
|
1523
|
|
- pid_output = 0;
|
1524
|
|
- pid_reset = true;
|
1525
|
|
- }
|
1526
|
|
- else if (pid_error > PID_FUNCTIONAL_RANGE) {
|
1527
|
|
- pid_output = MAX_BED_POWER;
|
1528
|
|
- pid_reset = true;
|
1529
|
|
- }
|
1530
|
|
- else {
|
1531
|
|
- if (pid_reset) {
|
1532
|
|
- temp_iState = 0.0;
|
1533
|
|
- work_pid.Kd = 0.0;
|
1534
|
|
- pid_reset = false;
|
1535
|
|
- }
|
1536
|
|
-
|
1537
|
|
- temp_iState = constrain(temp_iState + pid_error, 0, max_power_over_i_gain);
|
1538
|
|
-
|
1539
|
|
- work_pid.Kp = temp_bed.pid.Kp * pid_error;
|
1540
|
|
- work_pid.Ki = temp_bed.pid.Ki * temp_iState;
|
1541
|
|
- work_pid.Kd = work_pid.Kd + PID_K2 * (temp_bed.pid.Kd * (temp_dState - temp_bed.celsius) - work_pid.Kd);
|
1542
|
|
-
|
1543
|
|
- temp_dState = temp_bed.celsius;
|
1544
|
|
-
|
1545
|
|
- pid_output = constrain(work_pid.Kp + work_pid.Ki + work_pid.Kd + float(MIN_BED_POWER), 0, MAX_BED_POWER);
|
1546
|
|
- }
|
1547
|
|
-
|
1548
|
|
- #else // PID_OPENLOOP
|
1549
|
|
-
|
1550
|
|
- const float pid_output = constrain(temp_bed.target, 0, MAX_BED_POWER);
|
1551
|
|
-
|
1552
|
|
- #endif // PID_OPENLOOP
|
1553
|
|
-
|
1554
|
|
- #if ENABLED(PID_BED_DEBUG)
|
1555
|
|
- if (pid_debug_flag) {
|
1556
|
|
- SERIAL_ECHO_MSG(
|
1557
|
|
- " PID_BED_DEBUG : Input ", temp_bed.celsius, " Output ", pid_output
|
1558
|
|
- #if DISABLED(PID_OPENLOOP)
|
1559
|
|
- , STR_PID_DEBUG_PTERM, work_pid.Kp
|
1560
|
|
- , STR_PID_DEBUG_ITERM, work_pid.Ki
|
1561
|
|
- , STR_PID_DEBUG_DTERM, work_pid.Kd
|
1562
|
|
- #endif
|
1563
|
|
- );
|
1564
|
|
- }
|
1565
|
|
- #endif
|
1566
|
|
-
|
|
1509
|
+ static PIDRunner<bed_info_t, MIN_BED_POWER, MAX_BED_POWER> bed_pid(temp_bed);
|
|
1510
|
+ const float pid_output = bed_pid.get_pid_output();
|
|
1511
|
+ TERN_(PID_BED_DEBUG, bed_pid.debug(temp_bed.celsius, pid_output, F("(Bed)")));
|
1567
|
1512
|
return pid_output;
|
1568
|
1513
|
}
|
1569
|
1514
|
|
|
@@ -1572,114 +1517,17 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
|
1572
|
1517
|
#if ENABLED(PIDTEMPCHAMBER)
|
1573
|
1518
|
|
1574
|
1519
|
float Temperature::get_pid_output_chamber() {
|
1575
|
|
-
|
1576
|
|
- #if DISABLED(PID_OPENLOOP)
|
1577
|
|
-
|
1578
|
|
- static PID_t work_pid{0};
|
1579
|
|
- static float temp_iState = 0, temp_dState = 0;
|
1580
|
|
- static bool pid_reset = true;
|
1581
|
|
- float pid_output = 0;
|
1582
|
|
- const float max_power_over_i_gain = float(MAX_CHAMBER_POWER) / temp_chamber.pid.Ki - float(MIN_CHAMBER_POWER),
|
1583
|
|
- pid_error = temp_chamber.target - temp_chamber.celsius;
|
1584
|
|
-
|
1585
|
|
- if (!temp_chamber.target || pid_error < -(PID_FUNCTIONAL_RANGE)) {
|
1586
|
|
- pid_output = 0;
|
1587
|
|
- pid_reset = true;
|
1588
|
|
- }
|
1589
|
|
- else if (pid_error > PID_FUNCTIONAL_RANGE) {
|
1590
|
|
- pid_output = MAX_CHAMBER_POWER;
|
1591
|
|
- pid_reset = true;
|
1592
|
|
- }
|
1593
|
|
- else {
|
1594
|
|
- if (pid_reset) {
|
1595
|
|
- temp_iState = 0.0;
|
1596
|
|
- work_pid.Kd = 0.0;
|
1597
|
|
- pid_reset = false;
|
1598
|
|
- }
|
1599
|
|
-
|
1600
|
|
- temp_iState = constrain(temp_iState + pid_error, 0, max_power_over_i_gain);
|
1601
|
|
-
|
1602
|
|
- work_pid.Kp = temp_chamber.pid.Kp * pid_error;
|
1603
|
|
- work_pid.Ki = temp_chamber.pid.Ki * temp_iState;
|
1604
|
|
- work_pid.Kd = work_pid.Kd + PID_K2 * (temp_chamber.pid.Kd * (temp_dState - temp_chamber.celsius) - work_pid.Kd);
|
1605
|
|
-
|
1606
|
|
- temp_dState = temp_chamber.celsius;
|
1607
|
|
-
|
1608
|
|
- pid_output = constrain(work_pid.Kp + work_pid.Ki + work_pid.Kd + float(MIN_CHAMBER_POWER), 0, MAX_CHAMBER_POWER);
|
1609
|
|
- }
|
1610
|
|
-
|
1611
|
|
- #else // PID_OPENLOOP
|
1612
|
|
-
|
1613
|
|
- const float pid_output = constrain(temp_chamber.target, 0, MAX_CHAMBER_POWER);
|
1614
|
|
-
|
1615
|
|
- #endif // PID_OPENLOOP
|
1616
|
|
-
|
1617
|
|
- #if ENABLED(PID_CHAMBER_DEBUG)
|
1618
|
|
- {
|
1619
|
|
- SERIAL_ECHO_MSG(
|
1620
|
|
- " PID_CHAMBER_DEBUG : Input ", temp_chamber.celsius, " Output ", pid_output
|
1621
|
|
- #if DISABLED(PID_OPENLOOP)
|
1622
|
|
- , STR_PID_DEBUG_PTERM, work_pid.Kp
|
1623
|
|
- , STR_PID_DEBUG_ITERM, work_pid.Ki
|
1624
|
|
- , STR_PID_DEBUG_DTERM, work_pid.Kd
|
1625
|
|
- #endif
|
1626
|
|
- );
|
1627
|
|
- }
|
1628
|
|
- #endif
|
1629
|
|
-
|
|
1520
|
+ static PIDRunner<chamber_info_t, MIN_CHAMBER_POWER, MAX_CHAMBER_POWER> chamber_pid(temp_chamber);
|
|
1521
|
+ const float pid_output = chamber_pid.get_pid_output();
|
|
1522
|
+ TERN_(PID_CHAMBER_DEBUG, chamber_pid.debug(temp_chamber.celsius, pid_output, F("(Chamber)")));
|
1630
|
1523
|
return pid_output;
|
1631
|
1524
|
}
|
1632
|
1525
|
|
1633
|
1526
|
#endif // PIDTEMPCHAMBER
|
1634
|
1527
|
|
1635
|
|
-/**
|
1636
|
|
- * Manage heating activities for extruder hot-ends and a heated bed
|
1637
|
|
- * - Acquire updated temperature readings
|
1638
|
|
- * - Also resets the watchdog timer
|
1639
|
|
- * - Invoke thermal runaway protection
|
1640
|
|
- * - Manage extruder auto-fan
|
1641
|
|
- * - Apply filament width to the extrusion rate (may move)
|
1642
|
|
- * - Update the heated bed PID output value
|
1643
|
|
- */
|
1644
|
|
-void Temperature::manage_heater() {
|
1645
|
|
- if (marlin_state == MF_INITIALIZING) return hal.watchdog_refresh(); // If Marlin isn't started, at least reset the watchdog!
|
1646
|
|
-
|
1647
|
|
- static bool no_reentry = false; // Prevent recursion
|
1648
|
|
- if (no_reentry) return;
|
1649
|
|
- REMEMBER(mh, no_reentry, true);
|
1650
|
|
-
|
1651
|
|
- #if ENABLED(EMERGENCY_PARSER)
|
1652
|
|
- if (emergency_parser.killed_by_M112) kill(FPSTR(M112_KILL_STR), nullptr, true);
|
1653
|
|
-
|
1654
|
|
- if (emergency_parser.quickstop_by_M410) {
|
1655
|
|
- emergency_parser.quickstop_by_M410 = false; // quickstop_stepper may call idle so clear this now!
|
1656
|
|
- quickstop_stepper();
|
1657
|
|
- }
|
1658
|
|
- #endif
|
1659
|
|
-
|
1660
|
|
- if (!updateTemperaturesIfReady()) return; // Will also reset the watchdog if temperatures are ready
|
1661
|
|
-
|
1662
|
|
- #if DISABLED(IGNORE_THERMOCOUPLE_ERRORS)
|
1663
|
|
- #if TEMP_SENSOR_0_IS_MAX_TC
|
1664
|
|
- if (degHotend(0) > _MIN(HEATER_0_MAXTEMP, TEMP_SENSOR_0_MAX_TC_TMAX - 1.0)) max_temp_error(H_E0);
|
1665
|
|
- if (degHotend(0) < _MAX(HEATER_0_MINTEMP, TEMP_SENSOR_0_MAX_TC_TMIN + .01)) min_temp_error(H_E0);
|
1666
|
|
- #endif
|
1667
|
|
- #if TEMP_SENSOR_1_IS_MAX_TC
|
1668
|
|
- if (degHotend(1) > _MIN(HEATER_1_MAXTEMP, TEMP_SENSOR_1_MAX_TC_TMAX - 1.0)) max_temp_error(H_E1);
|
1669
|
|
- if (degHotend(1) < _MAX(HEATER_1_MINTEMP, TEMP_SENSOR_1_MAX_TC_TMIN + .01)) min_temp_error(H_E1);
|
1670
|
|
- #endif
|
1671
|
|
- #if TEMP_SENSOR_REDUNDANT_IS_MAX_TC
|
1672
|
|
- if (degRedundant() > TEMP_SENSOR_REDUNDANT_MAX_TC_TMAX - 1.0) max_temp_error(H_REDUNDANT);
|
1673
|
|
- if (degRedundant() < TEMP_SENSOR_REDUNDANT_MAX_TC_TMIN + .01) min_temp_error(H_REDUNDANT);
|
1674
|
|
- #endif
|
1675
|
|
- #else
|
1676
|
|
- #warning "Safety Alert! Disable IGNORE_THERMOCOUPLE_ERRORS for the final build!"
|
1677
|
|
- #endif
|
1678
|
|
-
|
1679
|
|
- millis_t ms = millis();
|
1680
|
|
-
|
1681
|
|
- #if HAS_HOTEND
|
|
1528
|
+#if HAS_HOTEND
|
1682
|
1529
|
|
|
1530
|
+ void Temperature::manage_hotends(const millis_t &ms) {
|
1683
|
1531
|
HOTEND_LOOP() {
|
1684
|
1532
|
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
|
1685
|
1533
|
if (degHotend(e) > temp_range[e].maxtemp) max_temp_error((heater_id_t)e);
|
|
@@ -1707,25 +1555,13 @@ void Temperature::manage_heater() {
|
1707
|
1555
|
#endif
|
1708
|
1556
|
|
1709
|
1557
|
} // HOTEND_LOOP
|
|
1558
|
+ }
|
1710
|
1559
|
|
1711
|
|
- #endif // HAS_HOTEND
|
1712
|
|
-
|
1713
|
|
- #if HAS_TEMP_REDUNDANT
|
1714
|
|
- // Make sure measured temperatures are close together
|
1715
|
|
- if (ABS(degRedundantTarget() - degRedundant()) > TEMP_SENSOR_REDUNDANT_MAX_DIFF)
|
1716
|
|
- _temp_error((heater_id_t)HEATER_ID(TEMP_SENSOR_REDUNDANT_TARGET), F(STR_REDUNDANCY), GET_TEXT_F(MSG_ERR_REDUNDANT_TEMP));
|
1717
|
|
- #endif
|
1718
|
|
-
|
1719
|
|
- // Manage extruder auto fans and/or read fan tachometers
|
1720
|
|
- TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms));
|
|
1560
|
+#endif // HAS_HOTEND
|
1721
|
1561
|
|
1722
|
|
- /**
|
1723
|
|
- * Dynamically set the volumetric multiplier based
|
1724
|
|
- * on the delayed Filament Width measurement.
|
1725
|
|
- */
|
1726
|
|
- TERN_(FILAMENT_WIDTH_SENSOR, filwidth.update_volumetric());
|
|
1562
|
+#if HAS_HEATED_BED
|
1727
|
1563
|
|
1728
|
|
- #if HAS_HEATED_BED
|
|
1564
|
+ void Temperature::manage_heated_bed(const millis_t &ms) {
|
1729
|
1565
|
|
1730
|
1566
|
#if ENABLED(THERMAL_PROTECTION_BED)
|
1731
|
1567
|
if (degBed() > BED_MAXTEMP) max_temp_error(H_BED);
|
|
@@ -1770,9 +1606,7 @@ void Temperature::manage_heater() {
|
1770
|
1606
|
#if HEATER_IDLE_HANDLER
|
1771
|
1607
|
if (heater_idle[IDLE_INDEX_BED].timed_out) {
|
1772
|
1608
|
temp_bed.soft_pwm_amount = 0;
|
1773
|
|
- #if DISABLED(PIDTEMPBED)
|
1774
|
|
- WRITE_HEATER_BED(LOW);
|
1775
|
|
- #endif
|
|
1609
|
+ if (DISABLED(PIDTEMPBED)) WRITE_HEATER_BED(LOW);
|
1776
|
1610
|
}
|
1777
|
1611
|
else
|
1778
|
1612
|
#endif
|
|
@@ -1785,10 +1619,10 @@ void Temperature::manage_heater() {
|
1785
|
1619
|
#if ENABLED(BED_LIMIT_SWITCHING)
|
1786
|
1620
|
if (temp_bed.celsius >= temp_bed.target + BED_HYSTERESIS)
|
1787
|
1621
|
temp_bed.soft_pwm_amount = 0;
|
1788
|
|
- else if (temp_bed.celsius <= temp_bed.target - (BED_HYSTERESIS))
|
|
1622
|
+ else if (temp_bed.is_below_target(-(BED_HYSTERESIS) + 1))
|
1789
|
1623
|
temp_bed.soft_pwm_amount = MAX_BED_POWER >> 1;
|
1790
|
1624
|
#else // !PIDTEMPBED && !BED_LIMIT_SWITCHING
|
1791
|
|
- temp_bed.soft_pwm_amount = temp_bed.celsius < temp_bed.target ? MAX_BED_POWER >> 1 : 0;
|
|
1625
|
+ temp_bed.soft_pwm_amount = temp_bed.is_below_target() ? MAX_BED_POWER >> 1 : 0;
|
1792
|
1626
|
#endif
|
1793
|
1627
|
}
|
1794
|
1628
|
else {
|
|
@@ -1799,10 +1633,13 @@ void Temperature::manage_heater() {
|
1799
|
1633
|
}
|
1800
|
1634
|
|
1801
|
1635
|
} while (false);
|
|
1636
|
+ }
|
1802
|
1637
|
|
1803
|
|
- #endif // HAS_HEATED_BED
|
|
1638
|
+#endif // HAS_HEATED_BED
|
1804
|
1639
|
|
1805
|
|
- #if HAS_HEATED_CHAMBER
|
|
1640
|
+#if HAS_HEATED_CHAMBER
|
|
1641
|
+
|
|
1642
|
+ void Temperature::manage_heated_chamber(const millis_t &ms) {
|
1806
|
1643
|
|
1807
|
1644
|
#ifndef CHAMBER_CHECK_INTERVAL
|
1808
|
1645
|
#define CHAMBER_CHECK_INTERVAL 1000UL
|
|
@@ -1897,17 +1734,17 @@ void Temperature::manage_heater() {
|
1897
|
1734
|
if (flag_chamber_excess_heat) {
|
1898
|
1735
|
temp_chamber.soft_pwm_amount = 0;
|
1899
|
1736
|
#if ENABLED(CHAMBER_VENT)
|
1900
|
|
- if (!flag_chamber_off) servo[CHAMBER_VENT_SERVO_NR].move(temp_chamber.celsius <= temp_chamber.target ? 0 : 90);
|
|
1737
|
+ if (!flag_chamber_off) servo[CHAMBER_VENT_SERVO_NR].move(temp_chamber.is_below_target() ? 0 : 90);
|
1901
|
1738
|
#endif
|
1902
|
1739
|
}
|
1903
|
1740
|
else {
|
1904
|
1741
|
#if ENABLED(CHAMBER_LIMIT_SWITCHING)
|
1905
|
1742
|
if (temp_chamber.celsius >= temp_chamber.target + TEMP_CHAMBER_HYSTERESIS)
|
1906
|
1743
|
temp_chamber.soft_pwm_amount = 0;
|
1907
|
|
- else if (temp_chamber.celsius <= temp_chamber.target - (TEMP_CHAMBER_HYSTERESIS))
|
|
1744
|
+ else if (temp_chamber.is_below_target(-(TEMP_CHAMBER_HYSTERESIS) + 1))
|
1908
|
1745
|
temp_chamber.soft_pwm_amount = (MAX_CHAMBER_POWER) >> 1;
|
1909
|
1746
|
#else
|
1910
|
|
- temp_chamber.soft_pwm_amount = temp_chamber.celsius < temp_chamber.target ? (MAX_CHAMBER_POWER) >> 1 : 0;
|
|
1747
|
+ temp_chamber.soft_pwm_amount = temp_chamber.is_below_target() ? (MAX_CHAMBER_POWER) >> 1 : 0;
|
1911
|
1748
|
#endif
|
1912
|
1749
|
#if ENABLED(CHAMBER_VENT)
|
1913
|
1750
|
if (!flag_chamber_off) servo[CHAMBER_VENT_SERVO_NR].move(0);
|
|
@@ -1923,10 +1760,13 @@ void Temperature::manage_heater() {
|
1923
|
1760
|
tr_state_machine[RUNAWAY_IND_CHAMBER].run(temp_chamber.celsius, temp_chamber.target, H_CHAMBER, THERMAL_PROTECTION_CHAMBER_PERIOD, THERMAL_PROTECTION_CHAMBER_HYSTERESIS);
|
1924
|
1761
|
#endif
|
1925
|
1762
|
#endif
|
|
1763
|
+ }
|
1926
|
1764
|
|
1927
|
|
- #endif // HAS_HEATED_CHAMBER
|
|
1765
|
+#endif // HAS_HEATED_CHAMBER
|
1928
|
1766
|
|
1929
|
|
- #if HAS_COOLER
|
|
1767
|
+#if HAS_COOLER
|
|
1768
|
+
|
|
1769
|
+ void Temperature::manage_cooler(const millis_t &ms) {
|
1930
|
1770
|
|
1931
|
1771
|
#ifndef COOLER_CHECK_INTERVAL
|
1932
|
1772
|
#define COOLER_CHECK_INTERVAL 2000UL
|
|
@@ -1984,8 +1824,82 @@ void Temperature::manage_heater() {
|
1984
|
1824
|
#if ENABLED(THERMAL_PROTECTION_COOLER)
|
1985
|
1825
|
tr_state_machine[RUNAWAY_IND_COOLER].run(temp_cooler.celsius, temp_cooler.target, H_COOLER, THERMAL_PROTECTION_COOLER_PERIOD, THERMAL_PROTECTION_COOLER_HYSTERESIS);
|
1986
|
1826
|
#endif
|
|
1827
|
+ }
|
1987
|
1828
|
|
1988
|
|
- #endif // HAS_COOLER
|
|
1829
|
+#endif // HAS_COOLER
|
|
1830
|
+
|
|
1831
|
+/**
|
|
1832
|
+ * Manage heating activities for extruder hot-ends and a heated bed
|
|
1833
|
+ * - Acquire updated temperature readings
|
|
1834
|
+ * - Also resets the watchdog timer
|
|
1835
|
+ * - Invoke thermal runaway protection
|
|
1836
|
+ * - Manage extruder auto-fan
|
|
1837
|
+ * - Apply filament width to the extrusion rate (may move)
|
|
1838
|
+ * - Update the heated bed PID output value
|
|
1839
|
+ */
|
|
1840
|
+void Temperature::task() {
|
|
1841
|
+ if (marlin_state == MF_INITIALIZING) return hal.watchdog_refresh(); // If Marlin isn't started, at least reset the watchdog!
|
|
1842
|
+
|
|
1843
|
+ static bool no_reentry = false; // Prevent recursion
|
|
1844
|
+ if (no_reentry) return;
|
|
1845
|
+ REMEMBER(mh, no_reentry, true);
|
|
1846
|
+
|
|
1847
|
+ #if ENABLED(EMERGENCY_PARSER)
|
|
1848
|
+ if (emergency_parser.killed_by_M112) kill(FPSTR(M112_KILL_STR), nullptr, true);
|
|
1849
|
+
|
|
1850
|
+ if (emergency_parser.quickstop_by_M410) {
|
|
1851
|
+ emergency_parser.quickstop_by_M410 = false; // quickstop_stepper may call idle so clear this now!
|
|
1852
|
+ quickstop_stepper();
|
|
1853
|
+ }
|
|
1854
|
+ #endif
|
|
1855
|
+
|
|
1856
|
+ if (!updateTemperaturesIfReady()) return; // Will also reset the watchdog if temperatures are ready
|
|
1857
|
+
|
|
1858
|
+ #if DISABLED(IGNORE_THERMOCOUPLE_ERRORS)
|
|
1859
|
+ #if TEMP_SENSOR_0_IS_MAX_TC
|
|
1860
|
+ if (degHotend(0) > _MIN(HEATER_0_MAXTEMP, TEMP_SENSOR_0_MAX_TC_TMAX - 1.0)) max_temp_error(H_E0);
|
|
1861
|
+ if (degHotend(0) < _MAX(HEATER_0_MINTEMP, TEMP_SENSOR_0_MAX_TC_TMIN + .01)) min_temp_error(H_E0);
|
|
1862
|
+ #endif
|
|
1863
|
+ #if TEMP_SENSOR_1_IS_MAX_TC
|
|
1864
|
+ if (degHotend(1) > _MIN(HEATER_1_MAXTEMP, TEMP_SENSOR_1_MAX_TC_TMAX - 1.0)) max_temp_error(H_E1);
|
|
1865
|
+ if (degHotend(1) < _MAX(HEATER_1_MINTEMP, TEMP_SENSOR_1_MAX_TC_TMIN + .01)) min_temp_error(H_E1);
|
|
1866
|
+ #endif
|
|
1867
|
+ #if TEMP_SENSOR_REDUNDANT_IS_MAX_TC
|
|
1868
|
+ if (degRedundant() > TEMP_SENSOR_REDUNDANT_MAX_TC_TMAX - 1.0) max_temp_error(H_REDUNDANT);
|
|
1869
|
+ if (degRedundant() < TEMP_SENSOR_REDUNDANT_MAX_TC_TMIN + .01) min_temp_error(H_REDUNDANT);
|
|
1870
|
+ #endif
|
|
1871
|
+ #else
|
|
1872
|
+ #warning "Safety Alert! Disable IGNORE_THERMOCOUPLE_ERRORS for the final build!"
|
|
1873
|
+ #endif
|
|
1874
|
+
|
|
1875
|
+ const millis_t ms = millis();
|
|
1876
|
+
|
|
1877
|
+ // Handle Hotend Temp Errors, Heating Watch, etc.
|
|
1878
|
+ TERN_(HAS_HOTEND, manage_hotends(ms));
|
|
1879
|
+
|
|
1880
|
+ #if HAS_TEMP_REDUNDANT
|
|
1881
|
+ // Make sure measured temperatures are close together
|
|
1882
|
+ if (ABS(degRedundantTarget() - degRedundant()) > TEMP_SENSOR_REDUNDANT_MAX_DIFF)
|
|
1883
|
+ _temp_error((heater_id_t)HEATER_ID(TEMP_SENSOR_REDUNDANT_TARGET), F(STR_REDUNDANCY), GET_TEXT_F(MSG_ERR_REDUNDANT_TEMP));
|
|
1884
|
+ #endif
|
|
1885
|
+
|
|
1886
|
+ // Manage extruder auto fans and/or read fan tachometers
|
|
1887
|
+ TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms));
|
|
1888
|
+
|
|
1889
|
+ /**
|
|
1890
|
+ * Dynamically set the volumetric multiplier based
|
|
1891
|
+ * on the delayed Filament Width measurement.
|
|
1892
|
+ */
|
|
1893
|
+ TERN_(FILAMENT_WIDTH_SENSOR, filwidth.update_volumetric());
|
|
1894
|
+
|
|
1895
|
+ // Handle Bed Temp Errors, Heating Watch, etc.
|
|
1896
|
+ TERN_(HAS_HEATED_BED, manage_heated_bed(ms));
|
|
1897
|
+
|
|
1898
|
+ // Handle Heated Chamber Temp Errors, Heating Watch, etc.
|
|
1899
|
+ TERN_(HAS_HEATED_CHAMBER, manage_heated_chamber(ms));
|
|
1900
|
+
|
|
1901
|
+ // Handle Cooler Temp Errors, Cooling Watch, etc.
|
|
1902
|
+ TERN_(HAS_COOLER, manage_cooler(ms));
|
1989
|
1903
|
|
1990
|
1904
|
#if ENABLED(LASER_COOLANT_FLOW_METER)
|
1991
|
1905
|
cooler.flowmeter_task(ms);
|
|
@@ -2479,7 +2393,7 @@ void Temperature::updateTemperaturesFromRawValues() {
|
2479
|
2393
|
/**
|
2480
|
2394
|
* Initialize the temperature manager
|
2481
|
2395
|
*
|
2482
|
|
- * The manager is implemented by periodic calls to manage_heater()
|
|
2396
|
+ * The manager is implemented by periodic calls to task()
|
2483
|
2397
|
*
|
2484
|
2398
|
* - Init (and disable) SPI thermocouples like MAX6675 and MAX31865
|
2485
|
2399
|
* - Disable RUMBA JTAG to accommodate a thermocouple extension
|
|
@@ -3111,7 +3025,7 @@ void Temperature::disable_all_heaters() {
|
3111
|
3025
|
static millis_t next_max_tc_ms[MAX_TC_COUNT] = { 0 };
|
3112
|
3026
|
|
3113
|
3027
|
// Return last-read value between readings
|
3114
|
|
- millis_t ms = millis();
|
|
3028
|
+ const millis_t ms = millis();
|
3115
|
3029
|
if (PENDING(ms, next_max_tc_ms[hindex]))
|
3116
|
3030
|
return THERMO_TEMP(hindex);
|
3117
|
3031
|
|
|
@@ -3419,16 +3333,18 @@ void Temperature::isr() {
|
3419
|
3333
|
_PWM_MOD(COOLER, soft_pwm_cooler, temp_cooler);
|
3420
|
3334
|
#endif
|
3421
|
3335
|
|
3422
|
|
- #if BOTH(USE_CONTROLLER_FAN, FAN_SOFT_PWM)
|
3423
|
|
- WRITE(CONTROLLER_FAN_PIN, soft_pwm_controller.add(pwm_mask, soft_pwm_controller_speed));
|
3424
|
|
- #endif
|
3425
|
|
-
|
3426
|
3336
|
#if ENABLED(FAN_SOFT_PWM)
|
|
3337
|
+
|
|
3338
|
+ #if ENABLED(USE_CONTROLLER_FAN)
|
|
3339
|
+ WRITE(CONTROLLER_FAN_PIN, soft_pwm_controller.add(pwm_mask, soft_pwm_controller_speed));
|
|
3340
|
+ #endif
|
|
3341
|
+
|
3427
|
3342
|
#define _FAN_PWM(N) do{ \
|
3428
|
3343
|
uint8_t &spcf = soft_pwm_count_fan[N]; \
|
3429
|
3344
|
spcf = (spcf & pwm_mask) + (soft_pwm_amount_fan[N] >> 1); \
|
3430
|
3345
|
WRITE_FAN(N, spcf > pwm_mask ? HIGH : LOW); \
|
3431
|
3346
|
}while(0)
|
|
3347
|
+
|
3432
|
3348
|
#if HAS_FAN0
|
3433
|
3349
|
_FAN_PWM(0);
|
3434
|
3350
|
#endif
|