More "zero extruders" changes (#15213)

This commit is contained in:
Scott Lahteine
2019-09-10 02:20:49 -05:00
committed by GitHub
parent 54abf3aeba
commit 584c86bed1
27 changed files with 1068 additions and 841 deletions

View File

@ -309,7 +309,9 @@ typedef struct SettingsDataStruct {
//
// ADVANCED_PAUSE_FEATURE
//
fil_change_settings_t fc_settings[EXTRUDERS]; // M603 T U L
#if EXTRUDERS
fil_change_settings_t fc_settings[EXTRUDERS]; // M603 T U L
#endif
//
// Tool-change settings
@ -367,7 +369,7 @@ void MarlinSettings::postprocess() {
#if DISABLED(NO_VOLUMETRICS)
planner.calculate_volumetric_multipliers();
#else
#elif EXTRUDERS
for (uint8_t i = COUNT(planner.e_factor); i--;)
planner.refresh_e_factor(i);
#endif
@ -759,7 +761,7 @@ void MarlinSettings::postprocess() {
{
_FIELD_TEST(ui_preheat_hotend_temp);
#if HAS_LCD_MENU
#if HOTENDS && HAS_LCD_MENU
const int16_t (&ui_preheat_hotend_temp)[2] = ui.preheat_hotend_temp,
(&ui_preheat_bed_temp)[2] = ui.preheat_bed_temp;
const uint8_t (&ui_preheat_fan_speed)[2] = ui.preheat_fan_speed;
@ -1164,6 +1166,7 @@ void MarlinSettings::postprocess() {
//
// Advanced Pause filament load & unload lengths
//
#if EXTRUDERS
{
#if DISABLED(ADVANCED_PAUSE_FEATURE)
const fil_change_settings_t fc_settings[EXTRUDERS] = { 0, 0 };
@ -1171,6 +1174,7 @@ void MarlinSettings::postprocess() {
_FIELD_TEST(fc_settings);
EEPROM_WRITE(fc_settings);
}
#endif
//
// Multiple Extruders
@ -1560,7 +1564,7 @@ void MarlinSettings::postprocess() {
{
_FIELD_TEST(ui_preheat_hotend_temp);
#if HAS_LCD_MENU
#if HOTENDS && HAS_LCD_MENU
int16_t (&ui_preheat_hotend_temp)[2] = ui.preheat_hotend_temp,
(&ui_preheat_bed_temp)[2] = ui.preheat_bed_temp;
uint8_t (&ui_preheat_fan_speed)[2] = ui.preheat_fan_speed;
@ -1968,6 +1972,7 @@ void MarlinSettings::postprocess() {
//
// Advanced Pause filament load & unload lengths
//
#if EXTRUDERS
{
#if DISABLED(ADVANCED_PAUSE_FEATURE)
fil_change_settings_t fc_settings[EXTRUDERS];
@ -1975,6 +1980,7 @@ void MarlinSettings::postprocess() {
_FIELD_TEST(fc_settings);
EEPROM_READ(fc_settings);
}
#endif
//
// Tool-change settings
@ -2410,7 +2416,7 @@ void MarlinSettings::reset() {
// Preheat parameters
//
#if HAS_LCD_MENU
#if HOTENDS && HAS_LCD_MENU
ui.preheat_hotend_temp[0] = PREHEAT_1_TEMP_HOTEND;
ui.preheat_hotend_temp[1] = PREHEAT_2_TEMP_HOTEND;
ui.preheat_bed_temp[0] = PREHEAT_1_TEMP_BED;
@ -2956,7 +2962,7 @@ void MarlinSettings::reset() {
#endif // [XYZ]_DUAL_ENDSTOPS
#if HAS_LCD_MENU
#if HOTENDS && HAS_LCD_MENU
CONFIG_ECHO_HEADING("Material heatup parameters:");
for (uint8_t i = 0; i < COUNT(ui.preheat_hotend_temp); i++) {

View File

@ -124,8 +124,10 @@ XYZ_DEFS(signed char, home_dir, HOME_DIR);
#if HAS_HOTEND_OFFSET
extern float hotend_offset[XYZ][HOTENDS];
void reset_hotend_offsets();
#else
#elif HOTENDS > 0
constexpr float hotend_offset[XYZ][HOTENDS] = { { 0 }, { 0 }, { 0 } };
#else
constexpr float hotend_offset[XYZ][1] = { { 0 }, { 0 }, { 0 } };
#endif
typedef struct { float min, max; } axis_limits_t;

View File

@ -147,9 +147,10 @@ float Planner::steps_to_mm[XYZE_N]; // (mm) Millimeters per step
uint8_t Planner::last_extruder = 0; // Respond to extruder change
#endif
int16_t Planner::flow_percentage[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(100); // Extrusion factor for each extruder
float Planner::e_factor[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0f); // The flow percentage and volumetric multiplier combine to scale E movement
#if EXTRUDERS
int16_t Planner::flow_percentage[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(100); // Extrusion factor for each extruder
float Planner::e_factor[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0f); // The flow percentage and volumetric multiplier combine to scale E movement
#endif
#if DISABLED(NO_VOLUMETRICS)
float Planner::filament_size[EXTRUDERS], // diameter of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder
@ -1632,7 +1633,11 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
db = target[B_AXIS] - position[B_AXIS],
dc = target[C_AXIS] - position[C_AXIS];
int32_t de = target[E_AXIS] - position[E_AXIS];
#if EXTRUDERS
int32_t de = target[E_AXIS] - position[E_AXIS];
#else
constexpr int32_t de = 0;
#endif
/* <-- add a slash to enable
SERIAL_ECHOPAIR(" _populate_block FR:", fr_mm_s);
@ -1642,8 +1647,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
SERIAL_ECHOPAIR(" (", db);
SERIAL_ECHOPAIR(" steps) C:", target[C_AXIS]);
SERIAL_ECHOPAIR(" (", dc);
SERIAL_ECHOPAIR(" steps) E:", target[E_AXIS]);
SERIAL_ECHOPAIR(" (", de);
#if EXTRUDERS
SERIAL_ECHOPAIR(" steps) E:", target[E_AXIS]);
SERIAL_ECHOPAIR(" (", de);
#endif
SERIAL_ECHOLNPGM(" steps)");
//*/
@ -1712,8 +1719,12 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
#endif
if (de < 0) SBI(dm, E_AXIS);
const float esteps_float = de * e_factor[extruder];
const uint32_t esteps = ABS(esteps_float) + 0.5f;
#if EXTRUDERS
const float esteps_float = de * e_factor[extruder];
const uint32_t esteps = ABS(esteps_float) + 0.5f;
#else
constexpr uint32_t esteps = 0;
#endif
// Clear all flags, including the "busy" bit
block->flag = 0x00;
@ -1781,10 +1792,17 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
delta_mm[B_AXIS] = db * steps_to_mm[B_AXIS];
delta_mm[C_AXIS] = dc * steps_to_mm[C_AXIS];
#endif
delta_mm[E_AXIS] = esteps_float * steps_to_mm[E_AXIS_N(extruder)];
#if EXTRUDERS
delta_mm[E_AXIS] = esteps_float * steps_to_mm[E_AXIS_N(extruder)];
#endif
if (block->steps[A_AXIS] < MIN_STEPS_PER_SEGMENT && block->steps[B_AXIS] < MIN_STEPS_PER_SEGMENT && block->steps[C_AXIS] < MIN_STEPS_PER_SEGMENT) {
block->millimeters = ABS(delta_mm[E_AXIS]);
block->millimeters = (0
#if EXTRUDERS
+ ABS(delta_mm[E_AXIS])
#endif
);
}
else {
if (millimeters)
@ -1816,7 +1834,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
#endif
}
block->steps[E_AXIS] = esteps;
#if EXTRUDERS
block->steps[E_AXIS] = esteps;
#endif
block->step_event_count = _MAX(block->steps[A_AXIS], block->steps[B_AXIS], block->steps[C_AXIS], esteps);
// Bail if this is a zero-length block
@ -1874,129 +1895,131 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
#endif
// Enable extruder(s)
if (esteps) {
#if ENABLED(AUTO_POWER_CONTROL)
powerManager.power_on();
#endif
#if EXTRUDERS
if (esteps) {
#if ENABLED(AUTO_POWER_CONTROL)
powerManager.power_on();
#endif
#if ENABLED(DISABLE_INACTIVE_EXTRUDER) // Enable only the selected extruder
#if ENABLED(DISABLE_INACTIVE_EXTRUDER) // Enable only the selected extruder
#define DISABLE_IDLE_E(N) if (!g_uc_extruder_last_move[N]) disable_E##N();
#define DISABLE_IDLE_E(N) if (!g_uc_extruder_last_move[N]) disable_E##N();
for (uint8_t i = 0; i < EXTRUDERS; i++)
if (g_uc_extruder_last_move[i] > 0) g_uc_extruder_last_move[i]--;
for (uint8_t i = 0; i < EXTRUDERS; i++)
if (g_uc_extruder_last_move[i] > 0) g_uc_extruder_last_move[i]--;
switch (extruder) {
case 0:
switch (extruder) {
case 0:
#if EXTRUDERS > 1
DISABLE_IDLE_E(1);
#if EXTRUDERS > 2
DISABLE_IDLE_E(2);
#if EXTRUDERS > 3
DISABLE_IDLE_E(3);
#if EXTRUDERS > 4
DISABLE_IDLE_E(4);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif // EXTRUDERS > 5
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
#endif // EXTRUDERS > 1
enable_E0();
g_uc_extruder_last_move[0] = (BLOCK_BUFFER_SIZE) * 2;
#if HAS_DUPLICATION_MODE
if (extruder_duplication_enabled) {
enable_E1();
g_uc_extruder_last_move[1] = (BLOCK_BUFFER_SIZE) * 2;
}
#endif
break;
#if EXTRUDERS > 1
DISABLE_IDLE_E(1);
case 1:
DISABLE_IDLE_E(0);
#if EXTRUDERS > 2
DISABLE_IDLE_E(2);
#if EXTRUDERS > 3
DISABLE_IDLE_E(3);
#if EXTRUDERS > 4
DISABLE_IDLE_E(4);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif // EXTRUDERS > 5
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
enable_E1();
g_uc_extruder_last_move[1] = (BLOCK_BUFFER_SIZE) * 2;
break;
#if EXTRUDERS > 2
DISABLE_IDLE_E(2);
case 2:
DISABLE_IDLE_E(0);
DISABLE_IDLE_E(1);
#if EXTRUDERS > 3
DISABLE_IDLE_E(3);
#if EXTRUDERS > 4
DISABLE_IDLE_E(4);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif
#endif
#endif
enable_E2();
g_uc_extruder_last_move[2] = (BLOCK_BUFFER_SIZE) * 2;
break;
#if EXTRUDERS > 3
DISABLE_IDLE_E(3);
case 3:
DISABLE_IDLE_E(0);
DISABLE_IDLE_E(1);
DISABLE_IDLE_E(2);
#if EXTRUDERS > 4
DISABLE_IDLE_E(4);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif
#endif
enable_E3();
g_uc_extruder_last_move[3] = (BLOCK_BUFFER_SIZE) * 2;
break;
#if EXTRUDERS > 4
DISABLE_IDLE_E(4);
case 4:
DISABLE_IDLE_E(0);
DISABLE_IDLE_E(1);
DISABLE_IDLE_E(2);
DISABLE_IDLE_E(3);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif
enable_E4();
g_uc_extruder_last_move[4] = (BLOCK_BUFFER_SIZE) * 2;
break;
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
case 5:
DISABLE_IDLE_E(0);
DISABLE_IDLE_E(1);
DISABLE_IDLE_E(2);
DISABLE_IDLE_E(3);
DISABLE_IDLE_E(4);
enable_E5();
g_uc_extruder_last_move[5] = (BLOCK_BUFFER_SIZE) * 2;
break;
#endif // EXTRUDERS > 5
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
#endif // EXTRUDERS > 1
enable_E0();
g_uc_extruder_last_move[0] = (BLOCK_BUFFER_SIZE) * 2;
#if HAS_DUPLICATION_MODE
if (extruder_duplication_enabled) {
enable_E1();
g_uc_extruder_last_move[1] = (BLOCK_BUFFER_SIZE) * 2;
}
#endif
break;
#if EXTRUDERS > 1
case 1:
DISABLE_IDLE_E(0);
#if EXTRUDERS > 2
DISABLE_IDLE_E(2);
#if EXTRUDERS > 3
DISABLE_IDLE_E(3);
#if EXTRUDERS > 4
DISABLE_IDLE_E(4);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif // EXTRUDERS > 5
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
enable_E1();
g_uc_extruder_last_move[1] = (BLOCK_BUFFER_SIZE) * 2;
break;
#if EXTRUDERS > 2
case 2:
DISABLE_IDLE_E(0);
DISABLE_IDLE_E(1);
#if EXTRUDERS > 3
DISABLE_IDLE_E(3);
#if EXTRUDERS > 4
DISABLE_IDLE_E(4);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif
#endif
#endif
enable_E2();
g_uc_extruder_last_move[2] = (BLOCK_BUFFER_SIZE) * 2;
break;
#if EXTRUDERS > 3
case 3:
DISABLE_IDLE_E(0);
DISABLE_IDLE_E(1);
DISABLE_IDLE_E(2);
#if EXTRUDERS > 4
DISABLE_IDLE_E(4);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif
#endif
enable_E3();
g_uc_extruder_last_move[3] = (BLOCK_BUFFER_SIZE) * 2;
break;
#if EXTRUDERS > 4
case 4:
DISABLE_IDLE_E(0);
DISABLE_IDLE_E(1);
DISABLE_IDLE_E(2);
DISABLE_IDLE_E(3);
#if EXTRUDERS > 5
DISABLE_IDLE_E(5);
#endif
enable_E4();
g_uc_extruder_last_move[4] = (BLOCK_BUFFER_SIZE) * 2;
break;
#if EXTRUDERS > 5
case 5:
DISABLE_IDLE_E(0);
DISABLE_IDLE_E(1);
DISABLE_IDLE_E(2);
DISABLE_IDLE_E(3);
DISABLE_IDLE_E(4);
enable_E5();
g_uc_extruder_last_move[5] = (BLOCK_BUFFER_SIZE) * 2;
break;
#endif // EXTRUDERS > 5
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
#endif // EXTRUDERS > 1
}
#else
enable_E0();
enable_E1();
enable_E2();
enable_E3();
enable_E4();
enable_E5();
#endif
}
}
#else
enable_E0();
enable_E1();
enable_E2();
enable_E3();
enable_E4();
enable_E5();
#endif
}
#endif // EXTRUDERS
if (esteps)
NOLESS(fr_mm_s, settings.min_feedrate_mm_s);

View File

@ -226,9 +226,10 @@ class Planner {
static uint8_t last_extruder; // Respond to extruder change
#endif
static int16_t flow_percentage[EXTRUDERS]; // Extrusion factor for each extruder
static float e_factor[EXTRUDERS]; // The flow percentage and volumetric multiplier combine to scale E movement
#if EXTRUDERS
static int16_t flow_percentage[EXTRUDERS]; // Extrusion factor for each extruder
static float e_factor[EXTRUDERS]; // The flow percentage and volumetric multiplier combine to scale E movement
#endif
#if DISABLED(NO_VOLUMETRICS)
static float filament_size[EXTRUDERS], // diameter of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder
@ -357,13 +358,15 @@ class Planner {
static void reset_acceleration_rates();
static void refresh_positioning();
FORCE_INLINE static void refresh_e_factor(const uint8_t e) {
e_factor[e] = (flow_percentage[e] * 0.01f
#if DISABLED(NO_VOLUMETRICS)
* volumetric_multiplier[e]
#endif
);
}
#if EXTRUDERS
FORCE_INLINE static void refresh_e_factor(const uint8_t e) {
e_factor[e] = (flow_percentage[e] * 0.01f
#if DISABLED(NO_VOLUMETRICS)
* volumetric_multiplier[e]
#endif
);
}
#endif
// Manage fans, paste pressure, etc.
static void check_axes_activity();

View File

@ -112,11 +112,9 @@ Temperature thermalManager;
bool Temperature::adaptive_fan_slowing = true;
#endif
hotend_info_t Temperature::temp_hotend[HOTENDS
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
+ 1
#endif
]; // = { 0 }
#if HOTENDS
hotend_info_t Temperature::temp_hotend[HOTEND_TEMPS]; // = { 0 }
#endif
#if ENABLED(AUTO_POWER_E_FANS)
uint8_t Temperature::autofan_speed[HOTENDS]; // = { 0 }
@ -283,15 +281,17 @@ volatile bool Temperature::temp_meas_ready = false;
#define TEMPDIR(N) ((HEATER_##N##_RAW_LO_TEMP) < (HEATER_##N##_RAW_HI_TEMP) ? 1 : -1)
// Init mintemp and maxtemp with extreme values to prevent false errors during startup
constexpr temp_range_t sensor_heater_0 { HEATER_0_RAW_LO_TEMP, HEATER_0_RAW_HI_TEMP, 0, 16383 },
sensor_heater_1 { HEATER_1_RAW_LO_TEMP, HEATER_1_RAW_HI_TEMP, 0, 16383 },
sensor_heater_2 { HEATER_2_RAW_LO_TEMP, HEATER_2_RAW_HI_TEMP, 0, 16383 },
sensor_heater_3 { HEATER_3_RAW_LO_TEMP, HEATER_3_RAW_HI_TEMP, 0, 16383 },
sensor_heater_4 { HEATER_4_RAW_LO_TEMP, HEATER_4_RAW_HI_TEMP, 0, 16383 },
sensor_heater_5 { HEATER_5_RAW_LO_TEMP, HEATER_5_RAW_HI_TEMP, 0, 16383 };
#if HOTENDS
// Init mintemp and maxtemp with extreme values to prevent false errors during startup
constexpr temp_range_t sensor_heater_0 { HEATER_0_RAW_LO_TEMP, HEATER_0_RAW_HI_TEMP, 0, 16383 },
sensor_heater_1 { HEATER_1_RAW_LO_TEMP, HEATER_1_RAW_HI_TEMP, 0, 16383 },
sensor_heater_2 { HEATER_2_RAW_LO_TEMP, HEATER_2_RAW_HI_TEMP, 0, 16383 },
sensor_heater_3 { HEATER_3_RAW_LO_TEMP, HEATER_3_RAW_HI_TEMP, 0, 16383 },
sensor_heater_4 { HEATER_4_RAW_LO_TEMP, HEATER_4_RAW_HI_TEMP, 0, 16383 },
sensor_heater_5 { HEATER_5_RAW_LO_TEMP, HEATER_5_RAW_HI_TEMP, 0, 16383 };
temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0, sensor_heater_1, sensor_heater_2, sensor_heater_3, sensor_heater_4, sensor_heater_5);
temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0, sensor_heater_1, sensor_heater_2, sensor_heater_3, sensor_heater_4, sensor_heater_5);
#endif
#ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
uint8_t Temperature::consecutive_low_temperature_error[HOTENDS] = { 0 };
@ -627,17 +627,20 @@ temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0
* Class and Instance Methods
*/
Temperature::Temperature() { }
int16_t Temperature::getHeaterPower(const heater_ind_t heater_id) {
switch (heater_id) {
default: return temp_hotend[heater_id].soft_pwm_amount;
#if HAS_HEATED_BED
case H_BED: return temp_bed.soft_pwm_amount;
#endif
#if HAS_HEATED_CHAMBER
case H_CHAMBER: return temp_chamber.soft_pwm_amount;
#endif
default:
#if HOTENDS
return temp_hotend[heater_id].soft_pwm_amount;
#else
return 0;
#endif
}
}
@ -816,114 +819,118 @@ void Temperature::min_temp_error(const heater_ind_t heater) {
_temp_error(heater, PSTR(MSG_T_MINTEMP), TEMP_ERR_PSTR(MSG_ERR_MINTEMP, heater));
}
float Temperature::get_pid_output_hotend(const uint8_t e) {
#if HOTENDS == 1
#define _HOTEND_TEST true
#else
#define _HOTEND_TEST (e == active_extruder)
#endif
E_UNUSED();
const uint8_t ee = HOTEND_INDEX;
float pid_output;
#if ENABLED(PIDTEMP)
#if DISABLED(PID_OPENLOOP)
static hotend_pid_t work_pid[HOTENDS];
static float temp_iState[HOTENDS] = { 0 },
temp_dState[HOTENDS] = { 0 };
static bool pid_reset[HOTENDS] = { false };
const float pid_error = temp_hotend[ee].target - temp_hotend[ee].celsius;
#if HOTENDS
if (temp_hotend[ee].target == 0
|| pid_error < -(PID_FUNCTIONAL_RANGE)
#if HEATER_IDLE_HANDLER
|| hotend_idle[ee].timed_out
#endif
) {
pid_output = 0;
pid_reset[ee] = true;
}
else if (pid_error > PID_FUNCTIONAL_RANGE) {
pid_output = BANG_MAX;
pid_reset[ee] = true;
}
else {
if (pid_reset[ee]) {
temp_iState[ee] = 0.0;
work_pid[ee].Kd = 0.0;
pid_reset[ee] = false;
}
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);
const float max_power_over_i_gain = float(PID_MAX) / PID_PARAM(Ki, ee) - float(MIN_POWER);
temp_iState[ee] = constrain(temp_iState[ee] + pid_error, 0, max_power_over_i_gain);
work_pid[ee].Kp = PID_PARAM(Kp, ee) * pid_error;
work_pid[ee].Ki = PID_PARAM(Ki, ee) * temp_iState[ee];
pid_output = work_pid[ee].Kp + work_pid[ee].Ki + work_pid[ee].Kd + float(MIN_POWER);
#if ENABLED(PID_EXTRUSION_SCALING)
work_pid[ee].Kc = 0;
if (_HOTEND_TEST) {
const long e_position = stepper.position(E_AXIS);
if (e_position > last_e_position) {
lpq[lpq_ptr] = e_position - last_e_position;
last_e_position = e_position;
}
else
lpq[lpq_ptr] = 0;
if (++lpq_ptr >= lpq_len) lpq_ptr = 0;
work_pid[ee].Kc = (lpq[lpq_ptr] * planner.steps_to_mm[E_AXIS]) * PID_PARAM(Kc, ee);
pid_output += work_pid[ee].Kc;
}
#endif // PID_EXTRUSION_SCALING
LIMIT(pid_output, 0, PID_MAX);
}
temp_dState[ee] = temp_hotend[ee].celsius;
#else // PID_OPENLOOP
const float pid_output = constrain(temp_hotend[ee].target, 0, PID_MAX);
#endif // PID_OPENLOOP
#if ENABLED(PID_DEBUG)
if (e == active_extruder) {
SERIAL_ECHO_START();
SERIAL_ECHOPAIR(
MSG_PID_DEBUG, ee,
MSG_PID_DEBUG_INPUT, temp_hotend[ee].celsius,
MSG_PID_DEBUG_OUTPUT, pid_output
);
#if DISABLED(PID_OPENLOOP)
SERIAL_ECHOPAIR(
MSG_PID_DEBUG_PTERM, work_pid[ee].Kp,
MSG_PID_DEBUG_ITERM, work_pid[ee].Ki,
MSG_PID_DEBUG_DTERM, work_pid[ee].Kd
#if ENABLED(PID_EXTRUSION_SCALING)
, MSG_PID_DEBUG_CTERM, work_pid[ee].Kc
#endif
);
#endif
SERIAL_EOL();
}
#endif // PID_DEBUG
#else // No PID enabled
#if HEATER_IDLE_HANDLER
#define _TIMED_OUT_TEST hotend_idle[ee].timed_out
float Temperature::get_pid_output_hotend(const uint8_t e) {
#if HOTENDS == 1
#define _HOTEND_TEST true
#else
#define _TIMED_OUT_TEST false
#define _HOTEND_TEST (e == active_extruder)
#endif
pid_output = (!_TIMED_OUT_TEST && temp_hotend[ee].celsius < temp_hotend[ee].target) ? BANG_MAX : 0;
#undef _TIMED_OUT_TEST
E_UNUSED();
const uint8_t ee = HOTEND_INDEX;
float pid_output;
#if ENABLED(PIDTEMP)
#if DISABLED(PID_OPENLOOP)
static hotend_pid_t work_pid[HOTENDS];
static float temp_iState[HOTENDS] = { 0 },
temp_dState[HOTENDS] = { 0 };
static bool pid_reset[HOTENDS] = { false };
const float pid_error = temp_hotend[ee].target - temp_hotend[ee].celsius;
#endif
if (temp_hotend[ee].target == 0
|| pid_error < -(PID_FUNCTIONAL_RANGE)
#if HEATER_IDLE_HANDLER
|| hotend_idle[ee].timed_out
#endif
) {
pid_output = 0;
pid_reset[ee] = true;
}
else if (pid_error > PID_FUNCTIONAL_RANGE) {
pid_output = BANG_MAX;
pid_reset[ee] = true;
}
else {
if (pid_reset[ee]) {
temp_iState[ee] = 0.0;
work_pid[ee].Kd = 0.0;
pid_reset[ee] = false;
}
return pid_output;
}
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);
const float max_power_over_i_gain = float(PID_MAX) / PID_PARAM(Ki, ee) - float(MIN_POWER);
temp_iState[ee] = constrain(temp_iState[ee] + pid_error, 0, max_power_over_i_gain);
work_pid[ee].Kp = PID_PARAM(Kp, ee) * pid_error;
work_pid[ee].Ki = PID_PARAM(Ki, ee) * temp_iState[ee];
pid_output = work_pid[ee].Kp + work_pid[ee].Ki + work_pid[ee].Kd + float(MIN_POWER);
#if ENABLED(PID_EXTRUSION_SCALING)
work_pid[ee].Kc = 0;
if (_HOTEND_TEST) {
const long e_position = stepper.position(E_AXIS);
if (e_position > last_e_position) {
lpq[lpq_ptr] = e_position - last_e_position;
last_e_position = e_position;
}
else
lpq[lpq_ptr] = 0;
if (++lpq_ptr >= lpq_len) lpq_ptr = 0;
work_pid[ee].Kc = (lpq[lpq_ptr] * planner.steps_to_mm[E_AXIS]) * PID_PARAM(Kc, ee);
pid_output += work_pid[ee].Kc;
}
#endif // PID_EXTRUSION_SCALING
LIMIT(pid_output, 0, PID_MAX);
}
temp_dState[ee] = temp_hotend[ee].celsius;
#else // PID_OPENLOOP
const float pid_output = constrain(temp_hotend[ee].target, 0, PID_MAX);
#endif // PID_OPENLOOP
#if ENABLED(PID_DEBUG)
if (e == active_extruder) {
SERIAL_ECHO_START();
SERIAL_ECHOPAIR(
MSG_PID_DEBUG, ee,
MSG_PID_DEBUG_INPUT, temp_hotend[ee].celsius,
MSG_PID_DEBUG_OUTPUT, pid_output
);
#if DISABLED(PID_OPENLOOP)
SERIAL_ECHOPAIR(
MSG_PID_DEBUG_PTERM, work_pid[ee].Kp,
MSG_PID_DEBUG_ITERM, work_pid[ee].Ki,
MSG_PID_DEBUG_DTERM, work_pid[ee].Kd
#if ENABLED(PID_EXTRUSION_SCALING)
, MSG_PID_DEBUG_CTERM, work_pid[ee].Kc
#endif
);
#endif
SERIAL_EOL();
}
#endif // PID_DEBUG
#else // No PID enabled
#if HEATER_IDLE_HANDLER
#define _TIMED_OUT_TEST hotend_idle[ee].timed_out
#else
#define _TIMED_OUT_TEST false
#endif
pid_output = (!_TIMED_OUT_TEST && temp_hotend[ee].celsius < temp_hotend[ee].target) ? BANG_MAX : 0;
#undef _TIMED_OUT_TEST
#endif
return pid_output;
}
#endif // HOTENDS
#if ENABLED(PIDTEMPBED)
@ -1025,44 +1032,46 @@ void Temperature::manage_heater() {
if (temp_hotend[1].celsius < _MAX(HEATER_1_MINTEMP, HEATER_1_MAX6675_TMIN + .01)) min_temp_error(H_E1);
#endif
#if HAS_THERMAL_PROTECTION || DISABLED(PIDTEMPBED) || HAS_AUTO_FAN || HEATER_IDLE_HANDLER
millis_t ms = millis();
#endif
millis_t ms = millis();
HOTEND_LOOP() {
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
if (degHotend(e) > temp_range[e].maxtemp)
_temp_error((heater_ind_t)e, PSTR(MSG_T_THERMAL_RUNAWAY), TEMP_ERR_PSTR(MSG_THERMAL_RUNAWAY, e));
#endif
#if HOTENDS
#if HEATER_IDLE_HANDLER
hotend_idle[e].update(ms);
#endif
HOTEND_LOOP() {
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
if (degHotend(e) > temp_range[e].maxtemp)
_temp_error((heater_ind_t)e, PSTR(MSG_T_THERMAL_RUNAWAY), TEMP_ERR_PSTR(MSG_THERMAL_RUNAWAY, e));
#endif
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
// Check for thermal runaway
thermal_runaway_protection(tr_state_machine[e], temp_hotend[e].celsius, temp_hotend[e].target, (heater_ind_t)e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS);
#endif
#if HEATER_IDLE_HANDLER
hotend_idle[e].update(ms);
#endif
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;
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
// Check for thermal runaway
thermal_runaway_protection(tr_state_machine[e], temp_hotend[e].celsius, temp_hotend[e].target, (heater_ind_t)e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS);
#endif
#if WATCH_HOTENDS
// Make sure temperature is increasing
if (watch_hotend[e].next_ms && ELAPSED(ms, watch_hotend[e].next_ms)) { // Time to check this extruder?
if (degHotend(e) < watch_hotend[e].target) // Failed to increase enough?
_temp_error((heater_ind_t)e, PSTR(MSG_T_HEATING_FAILED), TEMP_ERR_PSTR(MSG_HEATING_FAILED_LCD, e));
else // Start again if the target is still far off
start_watching_hotend(e);
}
#endif
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;
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
// Make sure measured temperatures are close together
if (ABS(temp_hotend[0].celsius - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF)
_temp_error(H_E0, PSTR(MSG_REDUNDANCY), PSTR(MSG_ERR_REDUNDANT_TEMP));
#endif
#if WATCH_HOTENDS
// Make sure temperature is increasing
if (watch_hotend[e].next_ms && ELAPSED(ms, watch_hotend[e].next_ms)) { // Time to check this extruder?
if (degHotend(e) < watch_hotend[e].target) // Failed to increase enough?
_temp_error((heater_ind_t)e, PSTR(MSG_T_HEATING_FAILED), TEMP_ERR_PSTR(MSG_HEATING_FAILED_LCD, e));
else // Start again if the target is still far off
start_watching_hotend(e);
}
#endif
} // HOTEND_LOOP
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
// Make sure measured temperatures are close together
if (ABS(temp_hotend[0].celsius - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF)
_temp_error(H_E0, PSTR(MSG_REDUNDANCY), PSTR(MSG_ERR_REDUNDANT_TEMP));
#endif
} // HOTEND_LOOP
#endif // HOTENDS
#if HAS_AUTO_FAN
if (ELAPSED(ms, next_auto_fan_check_ms)) { // only need to check fan state very infrequently
@ -1206,6 +1215,8 @@ void Temperature::manage_heater() {
//temp_bed.soft_pwm_amount = WITHIN(temp_chamber.celsius, CHAMBER_MINTEMP, CHAMBER_MAXTEMP) ? (int)get_pid_output_chamber() >> 1 : 0;
#endif // HAS_HEATED_CHAMBER
UNUSED(ms);
}
#define TEMP_AD595(RAW) ((RAW) * 5.0 * 100.0 / 1024.0 / (OVERSAMPLENR) * (TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET)
@ -1358,98 +1369,100 @@ void Temperature::manage_heater() {
}
#endif
// Derived from RepRap FiveD extruder::getTemperature()
// For hot end temperature measurement.
float Temperature::analog_to_celsius_hotend(const int raw, const uint8_t e) {
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
if (e > HOTENDS)
#else
if (e >= HOTENDS)
#endif
{
SERIAL_ERROR_START();
SERIAL_ECHO((int)e);
SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER_NUM);
kill();
return 0.0;
#if HOTENDS
// Derived from RepRap FiveD extruder::getTemperature()
// For hot end temperature measurement.
float Temperature::analog_to_celsius_hotend(const int raw, const uint8_t e) {
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
if (e > HOTENDS)
#else
if (e >= HOTENDS)
#endif
{
SERIAL_ERROR_START();
SERIAL_ECHO((int)e);
SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER_NUM);
kill();
return 0.0;
}
switch (e) {
case 0:
#if ENABLED(HEATER_0_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_0, raw);
#elif ENABLED(HEATER_0_USES_MAX6675)
return raw * 0.25;
#elif ENABLED(HEATER_0_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_0_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 1:
#if ENABLED(HEATER_1_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_1, raw);
#elif ENABLED(HEATER_1_USES_MAX6675)
return raw * 0.25;
#elif ENABLED(HEATER_1_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_1_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 2:
#if ENABLED(HEATER_2_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_2, raw);
#elif ENABLED(HEATER_2_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_2_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 3:
#if ENABLED(HEATER_3_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_3, raw);
#elif ENABLED(HEATER_3_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_3_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 4:
#if ENABLED(HEATER_4_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_4, raw);
#elif ENABLED(HEATER_4_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_4_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 5:
#if ENABLED(HEATER_5_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_5, raw);
#elif ENABLED(HEATER_5_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_5_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
default: break;
}
switch (e) {
case 0:
#if ENABLED(HEATER_0_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_0, raw);
#elif ENABLED(HEATER_0_USES_MAX6675)
return raw * 0.25;
#elif ENABLED(HEATER_0_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_0_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 1:
#if ENABLED(HEATER_1_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_1, raw);
#elif ENABLED(HEATER_1_USES_MAX6675)
return raw * 0.25;
#elif ENABLED(HEATER_1_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_1_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 2:
#if ENABLED(HEATER_2_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_2, raw);
#elif ENABLED(HEATER_2_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_2_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 3:
#if ENABLED(HEATER_3_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_3, raw);
#elif ENABLED(HEATER_3_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_3_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 4:
#if ENABLED(HEATER_4_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_4, raw);
#elif ENABLED(HEATER_4_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_4_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
case 5:
#if ENABLED(HEATER_5_USER_THERMISTOR)
return user_thermistor_to_deg_c(CTI_HOTEND_5, raw);
#elif ENABLED(HEATER_5_USES_AD595)
return TEMP_AD595(raw);
#elif ENABLED(HEATER_5_USES_AD8495)
return TEMP_AD8495(raw);
#else
break;
#endif
default: break;
#if HOTEND_USES_THERMISTOR
// Thermistor with conversion table?
const short(*tt)[][2] = (short(*)[][2])(heater_ttbl_map[e]);
SCAN_THERMISTOR_TABLE((*tt), heater_ttbllen_map[e]);
#endif
return 0;
}
#if HOTEND_USES_THERMISTOR
// Thermistor with conversion table?
const short(*tt)[][2] = (short(*)[][2])(heater_ttbl_map[e]);
SCAN_THERMISTOR_TABLE((*tt), heater_ttbllen_map[e]);
#endif
return 0;
}
#endif // HOTENDS
#if HAS_HEATED_BED
// Derived from RepRap FiveD extruder::getTemperature()
@ -1500,7 +1513,9 @@ void Temperature::updateTemperaturesFromRawValues() {
#if ENABLED(HEATER_1_USES_MAX6675)
temp_hotend[1].raw = READ_MAX6675(1);
#endif
HOTEND_LOOP() temp_hotend[e].celsius = analog_to_celsius_hotend(temp_hotend[e].raw, e);
#if HOTENDS
HOTEND_LOOP() temp_hotend[e].celsius = analog_to_celsius_hotend(temp_hotend[e].raw, e);
#endif
#if HAS_HEATED_BED
temp_bed.celsius = analog_to_celsius_bed(temp_bed.raw);
#endif
@ -1802,7 +1817,7 @@ void Temperature::init() {
#endif // HOTENDS > 2
#endif // HOTENDS > 1
#endif // HOTENDS > 1
#endif // HOTENDS
#if HAS_HEATED_BED
#ifdef BED_MINTEMP
@ -1976,7 +1991,9 @@ void Temperature::disable_all_heaters() {
planner.autotemp_enabled = false;
#endif
HOTEND_LOOP() setTargetHotend(0, e);
#if HOTENDS
HOTEND_LOOP() setTargetHotend(0, e);
#endif
#if HAS_HEATED_BED
setTargetBed(0);
@ -2238,9 +2255,11 @@ void Temperature::readings_ready() {
current_raw_filwidth = raw_filwidth_value >> 10; // Divide to get to 0-16384 range since we used 1/128 IIR filter approach
#endif
HOTEND_LOOP() temp_hotend[e].reset();
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
temp_hotend[1].reset();
#if HOTENDS
HOTEND_LOOP() temp_hotend[e].reset();
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
temp_hotend[1].reset();
#endif
#endif
#if HAS_HEATED_BED
@ -2261,55 +2280,59 @@ void Temperature::readings_ready() {
joystick.z.reset();
#endif
static constexpr int8_t temp_dir[] = {
#if ENABLED(HEATER_0_USES_MAX6675)
0
#else
TEMPDIR(0)
#endif
#if HOTENDS > 1
#if ENABLED(HEATER_1_USES_MAX6675)
, 0
#else
, TEMPDIR(1)
#endif
#if HOTENDS > 2
, TEMPDIR(2)
#if HOTENDS > 3
, TEMPDIR(3)
#if HOTENDS > 4
, TEMPDIR(4)
#if HOTENDS > 5
, TEMPDIR(5)
#endif // HOTENDS > 5
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
};
#if HOTENDS
for (uint8_t e = 0; e < COUNT(temp_dir); e++) {
const int8_t tdir = temp_dir[e];
if (tdir) {
const int16_t rawtemp = temp_hotend[e].raw * tdir; // normal direction, +rawtemp, else -rawtemp
const bool heater_on = (temp_hotend[e].target > 0
#if ENABLED(PIDTEMP)
|| temp_hotend[e].soft_pwm_amount > 0
#endif
);
if (rawtemp > temp_range[e].raw_max * tdir) max_temp_error((heater_ind_t)e);
if (heater_on && rawtemp < temp_range[e].raw_min * tdir && !is_preheating(e)) {
#ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED)
#endif
min_temp_error((heater_ind_t)e);
}
#ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
else
consecutive_low_temperature_error[e] = 0;
static constexpr int8_t temp_dir[] = {
#if ENABLED(HEATER_0_USES_MAX6675)
0
#else
TEMPDIR(0)
#endif
#if HOTENDS > 1
#if ENABLED(HEATER_1_USES_MAX6675)
, 0
#else
, TEMPDIR(1)
#endif
#if HOTENDS > 2
, TEMPDIR(2)
#if HOTENDS > 3
, TEMPDIR(3)
#if HOTENDS > 4
, TEMPDIR(4)
#if HOTENDS > 5
, TEMPDIR(5)
#endif // HOTENDS > 5
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
};
for (uint8_t e = 0; e < COUNT(temp_dir); e++) {
const int8_t tdir = temp_dir[e];
if (tdir) {
const int16_t rawtemp = temp_hotend[e].raw * tdir; // normal direction, +rawtemp, else -rawtemp
const bool heater_on = (temp_hotend[e].target > 0
#if ENABLED(PIDTEMP)
|| temp_hotend[e].soft_pwm_amount > 0
#endif
);
if (rawtemp > temp_range[e].raw_max * tdir) max_temp_error((heater_ind_t)e);
if (heater_on && rawtemp < temp_range[e].raw_min * tdir && !is_preheating(e)) {
#ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED)
#endif
min_temp_error((heater_ind_t)e);
}
#ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
else
consecutive_low_temperature_error[e] = 0;
#endif
}
}
}
#endif // HOTENDS
#if HAS_HEATED_BED
#if TEMPDIR(BED) < 0
@ -2399,12 +2422,10 @@ void Temperature::isr() {
static bool ADCKey_pressed = false;
#endif
#if ENABLED(SLOW_PWM_HEATERS)
static uint8_t slow_pwm_count = 0;
#if HOTENDS
static SoftPWM soft_pwm_hotend[HOTENDS];
#endif
static SoftPWM soft_pwm_hotend[HOTENDS];
#if HAS_HEATED_BED
static SoftPWM soft_pwm_bed;
#endif
@ -2414,40 +2435,46 @@ void Temperature::isr() {
#endif
#if DISABLED(SLOW_PWM_HEATERS)
constexpr uint8_t pwm_mask =
#if ENABLED(SOFT_PWM_DITHER)
_BV(SOFT_PWM_SCALE) - 1
#else
0
#endif
;
#if HOTENDS || HAS_HEATED_BED || HAS_HEATED_CHAMBER
constexpr uint8_t pwm_mask =
#if ENABLED(SOFT_PWM_DITHER)
_BV(SOFT_PWM_SCALE) - 1
#else
0
#endif
;
#define _PWM_MOD(N,S,T) do{ \
const bool on = S.add(pwm_mask, T.soft_pwm_amount); \
WRITE_HEATER_##N(on); \
}while(0)
#endif
/**
* Standard heater PWM modulation
*/
if (pwm_count_tmp >= 127) {
pwm_count_tmp -= 127;
#define _PWM_MOD(N,S,T) do{ \
const bool on = S.add(pwm_mask, T.soft_pwm_amount); \
WRITE_HEATER_##N(on); \
}while(0)
#define _PWM_MOD_E(N) _PWM_MOD(N,soft_pwm_hotend[N],temp_hotend[N])
_PWM_MOD_E(0);
#if HOTENDS > 1
_PWM_MOD_E(1);
#if HOTENDS > 2
_PWM_MOD_E(2);
#if HOTENDS > 3
_PWM_MOD_E(3);
#if HOTENDS > 4
_PWM_MOD_E(4);
#if HOTENDS > 5
_PWM_MOD_E(5);
#endif // HOTENDS > 5
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
#if HOTENDS
#define _PWM_MOD_E(N) _PWM_MOD(N,soft_pwm_hotend[N],temp_hotend[N])
_PWM_MOD_E(0);
#if HOTENDS > 1
_PWM_MOD_E(1);
#if HOTENDS > 2
_PWM_MOD_E(2);
#if HOTENDS > 3
_PWM_MOD_E(3);
#if HOTENDS > 4
_PWM_MOD_E(4);
#if HOTENDS > 5
_PWM_MOD_E(5);
#endif // HOTENDS > 5
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
#endif // HOTENDS
#if HAS_HEATED_BED
_PWM_MOD(BED,soft_pwm_bed,temp_bed);
@ -2538,6 +2565,8 @@ void Temperature::isr() {
#define _SLOW_PWM(NR,PWM,SRC) do{ PWM.count = SRC.soft_pwm_amount; _SLOW_SET(NR,PWM,(PWM.count > 0)); }while(0)
#define _PWM_OFF(NR,PWM) do{ if (PWM.count < slow_pwm_count) _SLOW_SET(NR,PWM,0); }while(0)
static uint8_t slow_pwm_count = 0;
if (slow_pwm_count == 0) {
#if HOTENDS
@ -2634,22 +2663,24 @@ void Temperature::isr() {
slow_pwm_count++;
slow_pwm_count &= 0x7F;
soft_pwm_hotend[0].dec();
#if HOTENDS > 1
soft_pwm_hotend[1].dec();
#if HOTENDS > 2
soft_pwm_hotend[2].dec();
#if HOTENDS > 3
soft_pwm_hotend[3].dec();
#if HOTENDS > 4
soft_pwm_hotend[4].dec();
#if HOTENDS > 5
soft_pwm_hotend[5].dec();
#endif // HOTENDS > 5
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
#if HOTENDS
soft_pwm_hotend[0].dec();
#if HOTENDS > 1
soft_pwm_hotend[1].dec();
#if HOTENDS > 2
soft_pwm_hotend[2].dec();
#if HOTENDS > 3
soft_pwm_hotend[3].dec();
#if HOTENDS > 4
soft_pwm_hotend[4].dec();
#if HOTENDS > 5
soft_pwm_hotend[5].dec();
#endif // HOTENDS > 5
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
#endif // HOTENDS
#if HAS_HEATED_BED
soft_pwm_bed.dec();
#endif
@ -2940,7 +2971,7 @@ void Temperature::isr() {
#endif // AUTO_REPORT_TEMPERATURES
#if HAS_DISPLAY
#if HOTENDS && HAS_DISPLAY
void Temperature::set_heating_message(const uint8_t e) {
const bool heating = isHeatingHotend(e);
#if HOTENDS > 1

View File

@ -270,11 +270,14 @@ class Temperature {
static volatile bool in_temp_isr;
static hotend_info_t temp_hotend[HOTENDS
#if HOTENDS
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
+ 1
#define HOTEND_TEMPS (HOTENDS + 1)
#else
#define HOTEND_TEMPS HOTENDS
#endif
];
static hotend_info_t temp_hotend[HOTEND_TEMPS];
#endif
#if HAS_HEATED_BED
static bed_info_t temp_bed;
@ -349,7 +352,9 @@ class Temperature {
static lpq_ptr_t lpq_ptr;
#endif
static temp_range_t temp_range[HOTENDS];
#if HOTENDS
static temp_range_t temp_range[HOTENDS];
#endif
#if HAS_HEATED_BED
#if WATCH_BED
@ -417,8 +422,6 @@ class Temperature {
* Instance Methods
*/
Temperature();
void init();
/**
@ -456,7 +459,9 @@ class Temperature {
}
#endif
static float analog_to_celsius_hotend(const int raw, const uint8_t e);
#if HOTENDS
static float analog_to_celsius_hotend(const int raw, const uint8_t e);
#endif
#if HAS_HEATED_BED
static float analog_to_celsius_bed(const int raw);
@ -577,19 +582,31 @@ class Temperature {
FORCE_INLINE static float degHotend(const uint8_t e) {
E_UNUSED();
return temp_hotend[HOTEND_INDEX].celsius;
#if HOTENDS
return temp_hotend[HOTEND_INDEX].celsius;
#else
return 0;
#endif
}
#if ENABLED(SHOW_TEMP_ADC_VALUES)
FORCE_INLINE static int16_t rawHotendTemp(const uint8_t e) {
E_UNUSED();
return temp_hotend[HOTEND_INDEX].raw;
#if HOTENDS
return temp_hotend[HOTEND_INDEX].raw;
#else
return 0;
#endif
}
#endif
FORCE_INLINE static int16_t degTargetHotend(const uint8_t e) {
E_UNUSED();
return temp_hotend[HOTEND_INDEX].target;
#if HOTENDS
return temp_hotend[HOTEND_INDEX].target;
#else
return 0;
#endif
}
#if WATCH_HOTENDS
@ -598,52 +615,56 @@ class Temperature {
static inline void start_watching_hotend(const uint8_t e=0) { UNUSED(e); }
#endif
#if HAS_LCD_MENU
static inline void start_watching_E0() { start_watching_hotend(0); }
static inline void start_watching_E1() { start_watching_hotend(1); }
static inline void start_watching_E2() { start_watching_hotend(2); }
static inline void start_watching_E3() { start_watching_hotend(3); }
static inline void start_watching_E4() { start_watching_hotend(4); }
static inline void start_watching_E5() { start_watching_hotend(5); }
#endif
#if HOTENDS
static void setTargetHotend(const int16_t celsius, const uint8_t e) {
E_UNUSED();
const uint8_t ee = HOTEND_INDEX;
#ifdef MILLISECONDS_PREHEAT_TIME
if (celsius == 0)
reset_preheat_time(ee);
else if (temp_hotend[ee].target == 0)
start_preheat_time(ee);
#if HAS_LCD_MENU
static inline void start_watching_E0() { start_watching_hotend(0); }
static inline void start_watching_E1() { start_watching_hotend(1); }
static inline void start_watching_E2() { start_watching_hotend(2); }
static inline void start_watching_E3() { start_watching_hotend(3); }
static inline void start_watching_E4() { start_watching_hotend(4); }
static inline void start_watching_E5() { start_watching_hotend(5); }
#endif
#if ENABLED(AUTO_POWER_CONTROL)
powerManager.power_on();
#endif
temp_hotend[ee].target = _MIN(celsius, temp_range[ee].maxtemp - 15);
start_watching_hotend(ee);
}
FORCE_INLINE static bool isHeatingHotend(const uint8_t e) {
E_UNUSED();
return temp_hotend[HOTEND_INDEX].target > temp_hotend[HOTEND_INDEX].celsius;
}
FORCE_INLINE static bool isCoolingHotend(const uint8_t e) {
E_UNUSED();
return temp_hotend[HOTEND_INDEX].target < temp_hotend[HOTEND_INDEX].celsius;
}
#if HAS_TEMP_HOTEND
static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true
#if G26_CLICK_CAN_CANCEL
, const bool click_to_cancel=false
static void setTargetHotend(const int16_t celsius, const uint8_t e) {
E_UNUSED();
const uint8_t ee = HOTEND_INDEX;
#ifdef MILLISECONDS_PREHEAT_TIME
if (celsius == 0)
reset_preheat_time(ee);
else if (temp_hotend[ee].target == 0)
start_preheat_time(ee);
#endif
);
#endif
#if ENABLED(AUTO_POWER_CONTROL)
powerManager.power_on();
#endif
temp_hotend[ee].target = _MIN(celsius, temp_range[ee].maxtemp - 15);
start_watching_hotend(ee);
}
FORCE_INLINE static bool still_heating(const uint8_t e) {
return degTargetHotend(e) > TEMP_HYSTERESIS && ABS(degHotend(e) - degTargetHotend(e)) > TEMP_HYSTERESIS;
}
FORCE_INLINE static bool isHeatingHotend(const uint8_t e) {
E_UNUSED();
return temp_hotend[HOTEND_INDEX].target > temp_hotend[HOTEND_INDEX].celsius;
}
FORCE_INLINE static bool isCoolingHotend(const uint8_t e) {
E_UNUSED();
return temp_hotend[HOTEND_INDEX].target < temp_hotend[HOTEND_INDEX].celsius;
}
#if HAS_TEMP_HOTEND
static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true
#if G26_CLICK_CAN_CANCEL
, const bool click_to_cancel=false
#endif
);
#endif
FORCE_INLINE static bool still_heating(const uint8_t e) {
return degTargetHotend(e) > TEMP_HYSTERESIS && ABS(degHotend(e) - degTargetHotend(e)) > TEMP_HYSTERESIS;
}
#endif // HOTENDS
#if HAS_HEATED_BED

View File

@ -695,11 +695,13 @@ inline void fast_line_to_current(const AxisEnum fr_axis) {
#endif // ELECTROMAGNETIC_SWITCHING_TOOLHEAD
inline void invalid_extruder_error(const uint8_t e) {
SERIAL_ECHO_START();
SERIAL_CHAR('T'); SERIAL_ECHO(int(e));
SERIAL_CHAR(' '); SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER);
}
#if EXTRUDERS
inline void invalid_extruder_error(const uint8_t e) {
SERIAL_ECHO_START();
SERIAL_CHAR('T'); SERIAL_ECHO(int(e));
SERIAL_CHAR(' '); SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER);
}
#endif
#if ENABLED(DUAL_X_CARRIAGE)
@ -788,6 +790,11 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
mmu2.tool_change(new_tool);
#elif EXTRUDERS == 0
// Nothing to do
UNUSED(new_tool); UNUSED(no_move);
#elif EXTRUDERS < 2
UNUSED(no_move);