diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp
index 6d672e3b8c..17d5efc6eb 100644
--- a/Marlin/src/MarlinCore.cpp
+++ b/Marlin/src/MarlinCore.cpp
@@ -989,7 +989,7 @@ void Marlin::stop() {
print_job_timer.stop();
#if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
- thermalManager.set_fans_paused(false); // Un-pause fans for safety
+ Fan::all_pause(false); // Un-pause fans for safety
#endif
if (!isStopped()) {
diff --git a/Marlin/src/feature/controllerfan.cpp b/Marlin/src/feature/controllerfan.cpp
index 0636402136..b31640be2f 100644
--- a/Marlin/src/feature/controllerfan.cpp
+++ b/Marlin/src/feature/controllerfan.cpp
@@ -71,98 +71,99 @@ void ControllerFan::setup() {
init();
}
-void ControllerFan::set_fan_speed(const uint8_t s) {
- speed = s < (CONTROLLERFAN_SPEED_MIN) ? 0 : s; // Fan OFF below minimum
-}
-
void ControllerFan::update() {
- static millis_t lastComponentOn = 0, // Last time a stepper, heater, etc. was turned on
- nextFanCheck = 0; // Last time the state was checked
const millis_t ms = millis();
- if (ELAPSED(ms, nextFanCheck)) {
- nextFanCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s
- /**
- * If any triggers for the controller fan are true...
- * - At least one stepper driver is enabled
- * - The heated bed (MOSFET) is enabled
- * - TEMP_SENSOR_BOARD is reporting >= CONTROLLER_FAN_MIN_BOARD_TEMP
- * - TEMP_SENSOR_SOC is reporting >= CONTROLLER_FAN_MIN_SOC_TEMP
- */
- const ena_mask_t axis_mask = TERN(CONTROLLER_FAN_USE_Z_ONLY, _BV(Z_AXIS), (ena_mask_t)~TERN0(CONTROLLER_FAN_IGNORE_Z, _BV(Z_AXIS)));
- if ( (stepper.axis_enabled.bits & axis_mask)
- #if ALL(HAS_HEATED_BED, CONTROLLER_FAN_BED_HEATING)
- || thermalManager.temp_bed.soft_pwm_amount > 0
- #endif
- #ifdef CONTROLLER_FAN_MIN_BOARD_TEMP
- || thermalManager.wholeDegBoard() >= CONTROLLER_FAN_MIN_BOARD_TEMP
- #endif
- #ifdef CONTROLLER_FAN_MIN_SOC_TEMP
- || thermalManager.wholeDegSoc() >= CONTROLLER_FAN_MIN_SOC_TEMP
- #endif
- ) lastComponentOn = ms; //... set time to NOW so the fan will turn on
+ static millis_t nextFanCheck = 0; // Last time the state was checked
+ if (PENDING(ms, nextFanCheck)) return;
+ nextFanCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s
- /**
- * Fan Settings. Set fan > 0:
- * - If AutoMode is on and hot components have been powered for CONTROLLERFAN_IDLE_TIME seconds.
- * - If System is on idle and idle fan speed settings is activated.
- */
- set_fan_speed(
- settings.auto_mode && lastComponentOn && PENDING(ms, lastComponentOn, SEC_TO_MS(settings.duration))
- ? settings.active_speed : settings.idle_speed
- );
-
- speed = CALC_FAN_SPEED(speed);
-
- #if FAN_KICKSTART_TIME
- static millis_t fan_kick_end = 0;
- if (speed > FAN_OFF_PWM) {
- if (!fan_kick_end) {
- fan_kick_end = ms + FAN_KICKSTART_TIME; // May be longer based on slow update interval for controller fn check. Sets minimum
- speed = FAN_KICKSTART_POWER;
- }
- else if (PENDING(ms, fan_kick_end))
- speed = FAN_KICKSTART_POWER;
- }
- else
- fan_kick_end = 0;
+ /**
+ * If any triggers for the controller fan are true...
+ * - At least one stepper driver is enabled
+ * - The heated bed (MOSFET) is enabled
+ * - TEMP_SENSOR_BOARD is reporting >= CONTROLLER_FAN_MIN_BOARD_TEMP
+ * - TEMP_SENSOR_SOC is reporting >= CONTROLLER_FAN_MIN_SOC_TEMP
+ */
+ static millis_t lastComponentOn = 0; // Last time a stepper, heater, etc. was turned on
+ const ena_mask_t axis_mask = TERN(CONTROLLER_FAN_USE_Z_ONLY, _BV(Z_AXIS), (ena_mask_t)~TERN0(CONTROLLER_FAN_IGNORE_Z, _BV(Z_AXIS)));
+ if ( (stepper.axis_enabled.bits & axis_mask)
+ #if ALL(HAS_HEATED_BED, CONTROLLER_FAN_BED_HEATING)
+ || thermalManager.temp_bed.soft_pwm_amount > 0
#endif
+ #ifdef CONTROLLER_FAN_MIN_BOARD_TEMP
+ || thermalManager.wholeDegBoard() >= CONTROLLER_FAN_MIN_BOARD_TEMP
+ #endif
+ #ifdef CONTROLLER_FAN_MIN_SOC_TEMP
+ || thermalManager.wholeDegSoc() >= CONTROLLER_FAN_MIN_SOC_TEMP
+ #endif
+ ) lastComponentOn = ms; //... set time to NOW so the fan will turn on
+
+ /**
+ * Fan Settings. Set fan > 0:
+ * - If AutoMode is on and hot components have been powered for CONTROLLERFAN_IDLE_TIME seconds.
+ * - If System is on idle and idle fan speed settings is activated.
+ */
+ uint8_t s = settings.auto_mode && lastComponentOn && PENDING(ms, lastComponentOn, SEC_TO_MS(settings.duration))
+ ? settings.active_speed
+ : settings.idle_speed;
+
+ // Convert 1-255 to the MIN-MAX PWM range
+ s = CALC_FAN_SPEED(s);
+
+ // When the fan first starts up it can run at high power for a short period
+ #if FAN_KICKSTART_TIME
+
+ static millis_t kick_end_ms = 0;
+
+ if (s > FAN_OFF_PWM) { // Is the fan turned on?
+ if (!kick_end_ms) { // No kickstart yet?
+ kick_end_ms = ms + FAN_KICKSTART_TIME; // Set a future time at which to stop
+ s = FAN_KICKSTART_POWER; // Override the power
+ }
+ else if (PENDING(ms, kick_end_ms)) // Still waiting for end of kickstart time?
+ s = FAN_KICKSTART_POWER; // Override the power
+ }
+ else
+ kick_end_ms = 0; // Reset kick_end_ms for kickstart on next enable
+
+ #endif // FAN_KICKSTART_TIME
+
+ #if ENABLED(FAN_SOFT_PWM)
+ soft_pwm_speed = speed >> 1; // Controller Fan Soft PWM uses 0-127 as 0-100% so cut the 0-255 range in half.
+ #else
#define SET_CONTROLLER_FAN(N) do { \
if (PWM_PIN(CONTROLLER_FAN##N##_PIN)) hal.set_pwm_duty(pin_t(CONTROLLER_FAN##N##_PIN), speed); \
else WRITE(CONTROLLER_FAN##N##_PIN, speed > 0);\
} while (0)
- #if ENABLED(FAN_SOFT_PWM)
- soft_pwm_speed = speed >> 1; // Controller Fan Soft PWM uses 0-127 as 0-100% so cut the 0-255 range in half.
- #else
- SET_CONTROLLER_FAN();
- #if PIN_EXISTS(CONTROLLER_FAN2)
- SET_CONTROLLER_FAN(2);
- #endif
- #if PIN_EXISTS(CONTROLLER_FAN3)
- SET_CONTROLLER_FAN(3);
- #endif
- #if PIN_EXISTS(CONTROLLER_FAN4)
- SET_CONTROLLER_FAN(4);
- #endif
- #if PIN_EXISTS(CONTROLLER_FAN5)
- SET_CONTROLLER_FAN(5);
- #endif
- #if PIN_EXISTS(CONTROLLER_FAN6)
- SET_CONTROLLER_FAN(6);
- #endif
- #if PIN_EXISTS(CONTROLLER_FAN7)
- SET_CONTROLLER_FAN(7);
- #endif
- #if PIN_EXISTS(CONTROLLER_FAN8)
- SET_CONTROLLER_FAN(8);
- #endif
- #if PIN_EXISTS(CONTROLLER_FAN9)
- SET_CONTROLLER_FAN(9);
- #endif
+ SET_CONTROLLER_FAN();
+ #if PIN_EXISTS(CONTROLLER_FAN2)
+ SET_CONTROLLER_FAN(2);
#endif
- }
+ #if PIN_EXISTS(CONTROLLER_FAN3)
+ SET_CONTROLLER_FAN(3);
+ #endif
+ #if PIN_EXISTS(CONTROLLER_FAN4)
+ SET_CONTROLLER_FAN(4);
+ #endif
+ #if PIN_EXISTS(CONTROLLER_FAN5)
+ SET_CONTROLLER_FAN(5);
+ #endif
+ #if PIN_EXISTS(CONTROLLER_FAN6)
+ SET_CONTROLLER_FAN(6);
+ #endif
+ #if PIN_EXISTS(CONTROLLER_FAN7)
+ SET_CONTROLLER_FAN(7);
+ #endif
+ #if PIN_EXISTS(CONTROLLER_FAN8)
+ SET_CONTROLLER_FAN(8);
+ #endif
+ #if PIN_EXISTS(CONTROLLER_FAN9)
+ SET_CONTROLLER_FAN(9);
+ #endif
+ #endif
}
#endif // USE_CONTROLLER_FAN
diff --git a/Marlin/src/feature/controllerfan.h b/Marlin/src/feature/controllerfan.h
index 68502afa66..ac422f015f 100644
--- a/Marlin/src/feature/controllerfan.h
+++ b/Marlin/src/feature/controllerfan.h
@@ -52,7 +52,8 @@ static constexpr controllerFan_settings_t controllerFan_defaults = {
class ControllerFan {
private:
static uint8_t speed;
- static void set_fan_speed(const uint8_t s);
+ static uint8_t limited_fan_speed(const uint8_t s) { return s < (CONTROLLERFAN_SPEED_MIN) ? 0 : s; } // Fan OFF below minimum
+ static void set_fan_speed(const uint8_t s) { speed = limited_fan_speed(s); }
public:
#if ENABLED(CONTROLLER_FAN_EDITABLE)
diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp
index 025bcb8383..db237dada0 100644
--- a/Marlin/src/feature/pause.cpp
+++ b/Marlin/src/feature/pause.cpp
@@ -462,7 +462,7 @@ bool pause_print(const float retract, const xyz_pos_t &park_point, const bool sh
planner.synchronize();
#if ALL(ADVANCED_PAUSE_FANS_PAUSE, HAS_FAN)
- thermalManager.set_fans_paused(true);
+ Fan::all_pause(true);
#endif
// Initial retract before move to filament change position
@@ -763,8 +763,8 @@ void resume_print(
}
#endif
- #if ENABLED(ADVANCED_PAUSE_FANS_PAUSE) && HAS_FAN
- thermalManager.set_fans_paused(false);
+ #if ALL(ADVANCED_PAUSE_FANS_PAUSE, HAS_FAN)
+ Fan::all_pause(false);
#endif
TERN_(HAS_FILAMENT_SENSOR, runout.reset());
diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp
index 2068558fe9..b877d460ea 100644
--- a/Marlin/src/feature/power.cpp
+++ b/Marlin/src/feature/power.cpp
@@ -210,9 +210,8 @@ void Power::power_off() {
if (marlin.printJobOngoing() || marlin.printingIsPaused()) return true;
- #if ENABLED(AUTO_POWER_FANS)
- FANS_LOOP(i) if (thermalManager.fan_speed[i]) return true;
- #endif
+ // Do any fans need power?
+ if (TERN0(AUTO_POWER_FANS, Fan::is_power_needed())) return true;
#if ENABLED(AUTO_POWER_E_FANS)
HOTEND_LOOP() if (thermalManager.autofan_speed[e]) return true;
diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp
index 0dd19808bc..106e346e7c 100644
--- a/Marlin/src/feature/powerloss.cpp
+++ b/Marlin/src/feature/powerloss.cpp
@@ -246,7 +246,9 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW
TERN_(HAS_HEATED_CHAMBER, info.target_temperature_chamber = thermalManager.degTargetChamber());
- TERN_(HAS_FAN, COPY(info.fan_speed, thermalManager.fan_speed));
+ #if HAS_FAN
+ FANS_LOOP(f) info.fan_speed[f] = fans[f].speed;
+ #endif
#if HAS_LEVELING
info.flag.leveling = planner.leveling_active;
diff --git a/Marlin/src/gcode/control/M42.cpp b/Marlin/src/gcode/control/M42.cpp
index 717b0695a4..fbb40ef755 100644
--- a/Marlin/src/gcode/control/M42.cpp
+++ b/Marlin/src/gcode/control/M42.cpp
@@ -87,7 +87,7 @@ void GcodeSuite::M42() {
#if HAS_FAN
switch (pin) {
- #define _CASE(N) case FAN##N##_PIN: thermalManager.fan_speed[N] = pin_status; return;
+ #define _CASE(N) case FAN##N##_PIN: fans[N].speed = pin_status; return;
REPEAT(FAN_COUNT, _CASE)
}
#endif
diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp
index a7653a4037..8fb8be8c37 100644
--- a/Marlin/src/gcode/control/M80_M81.cpp
+++ b/Marlin/src/gcode/control/M80_M81.cpp
@@ -84,8 +84,7 @@ void GcodeSuite::M81() {
print_job_timer.stop();
#if ALL(HAS_FAN, PROBING_FANS_OFF)
- thermalManager.fans_paused = false;
- ZERO(thermalManager.saved_fan_speed);
+ Fan::power_off();
#endif
TERN_(POWER_LOSS_RECOVERY, recovery.purge()); // Clear PLR on intentional shutdown
diff --git a/Marlin/src/gcode/temp/M106_M107.cpp b/Marlin/src/gcode/temp/M106_M107.cpp
index dc0c3d6b27..bdcbda9169 100644
--- a/Marlin/src/gcode/temp/M106_M107.cpp
+++ b/Marlin/src/gcode/temp/M106_M107.cpp
@@ -71,7 +71,7 @@ void GcodeSuite::M106() {
}
#endif
- const uint16_t dspeed = parser.seen_test('A') ? thermalManager.fan_speed[active_extruder] : 255;
+ const uint16_t dspeed = parser.seen_test('A') ? fans[active_extruder].speed : 255;
uint16_t speed = dspeed;
diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h
index 024eb42f51..d75d77dab8 100644
--- a/Marlin/src/inc/Conditionals-5-post.h
+++ b/Marlin/src/inc/Conditionals-5-post.h
@@ -2973,6 +2973,9 @@
#if FAN_COUNT > 0
#define HAS_FAN 1
+#else
+ #undef FAN_SOFT_PWM
+ #undef FAN_SOFT_PWM_REQUIRED
#endif
#if PIN_EXISTS(FANMUX0)
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index 5856723c77..34c6d8ea8b 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -981,9 +981,9 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L
#if HAS_FANMUX && !HAS_FAN0
#error "FAN0_PIN must be defined to use Fan Multiplexing."
#elif PIN_EXISTS(FANMUX1) && !PIN_EXISTS(FANMUX0)
- #error "FANMUX0_PIN must be set before FANMUX1_PIN can be set."
+ #error "FANMUX0_PIN must be defined before FANMUX1_PIN can be defined."
#elif PIN_EXISTS(FANMUX2) && !PINS_EXIST(FANMUX0, FANMUX1)
- #error "FANMUX0_PIN and FANMUX1_PIN must be set before FANMUX2_PIN can be set."
+ #error "FANMUX0_PIN and FANMUX1_PIN must be defined before FANMUX2_PIN can be defined."
#endif
// PID Fan Scaling requires a fan
diff --git a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp
index 81063d5e2e..482bd7df3e 100644
--- a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp
+++ b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp
@@ -1128,15 +1128,15 @@ void MarlinUI::draw_status_screen() {
#if HAS_FAN0
if (true
#if ALL(HAS_EXTRUDERS, ADAPTIVE_FAN_SLOWING)
- && (blink || thermalManager.fan_speed_scaler[0] < 128)
+ && (blink || fans[0].speed_scaler < 128)
#endif
) {
- uint16_t spd = thermalManager.fan_speed[0];
+ uint16_t spd = fans[0].speed;
if (blink) c = 'F';
#if ENABLED(ADAPTIVE_FAN_SLOWING)
- else { c = '*'; spd = thermalManager.scaledFanSpeed(0, spd); }
+ else { c = '*'; spd = fans[0].scaled_speed(spd); }
#endif
- pct = thermalManager.pwmToPercent(spd);
+ pct = Fan::pwmToPercent(spd);
}
else
#endif
@@ -1390,14 +1390,14 @@ void MarlinUI::draw_status_screen() {
if (TERN0(HAS_HOTEND, thermalManager.degTargetHotend(0) > 0)) leds |= LED_B;
#if HAS_FAN
- if ( TERN0(HAS_FAN0, thermalManager.fan_speed[0])
- || TERN0(HAS_FAN1, thermalManager.fan_speed[1])
- || TERN0(HAS_FAN2, thermalManager.fan_speed[2])
- || TERN0(HAS_FAN3, thermalManager.fan_speed[3])
- || TERN0(HAS_FAN4, thermalManager.fan_speed[4])
- || TERN0(HAS_FAN5, thermalManager.fan_speed[5])
- || TERN0(HAS_FAN6, thermalManager.fan_speed[6])
- || TERN0(HAS_FAN7, thermalManager.fan_speed[7])
+ if ( TERN0(HAS_FAN0, fans[0].speed)
+ || TERN0(HAS_FAN1, fans[1].speed)
+ || TERN0(HAS_FAN2, fans[2].speed)
+ || TERN0(HAS_FAN3, fans[3].speed)
+ || TERN0(HAS_FAN4, fans[4].speed)
+ || TERN0(HAS_FAN5, fans[5].speed)
+ || TERN0(HAS_FAN6, fans[6].speed)
+ || TERN0(HAS_FAN7, fans[7].speed)
) leds |= LED_C;
#endif // HAS_FAN
diff --git a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp
index cdb18a74b7..10476c6cb0 100644
--- a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp
+++ b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp
@@ -906,11 +906,11 @@ void MarlinUI::draw_status_screen() {
#endif
#if HAS_FAN
- uint16_t spd = thermalManager.fan_speed[0];
+ uint16_t spd = fans[0].speed;
#if ENABLED(ADAPTIVE_FAN_SLOWING)
- if (!blink) spd = thermalManager.scaledFanSpeed(0, spd);
+ if (!blink) spd = fans[0].scaled_speed(spd);
#endif
- uint16_t per = thermalManager.pwmToPercent(spd);
+ const uint16_t pct = Fan::pwmToPercent(spd);
#if HOTENDS < 2
#define FANX 11
@@ -920,9 +920,9 @@ void MarlinUI::draw_status_screen() {
lcd_moveto(FANX, 5); lcd_put_u8str(F("FAN"));
lcd_moveto(FANX + 1, 6); lcd.write('%');
lcd_moveto(FANX, 7);
- lcd.print(i16tostr3rj(per));
+ lcd.print(i16tostr3rj(pct));
- if (TERN0(HAS_FAN0, thermalManager.fan_speed[0]) || TERN0(HAS_FAN1, thermalManager.fan_speed[1]) || TERN0(HAS_FAN2, thermalManager.fan_speed[2]))
+ if (TERN0(HAS_FAN0, fans[0].speed) || TERN0(HAS_FAN1, fans[1].speed) || TERN0(HAS_FAN2, fans[2].speed))
picBits |= ICON_FAN;
else
picBits &= ~ICON_FAN;
diff --git a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
index 7fd3052772..c8606255ec 100644
--- a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
+++ b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
@@ -674,7 +674,7 @@ void MarlinUI::draw_status_screen() {
static uint8_t fan_frame;
if (old_blink != blink) {
old_blink = blink;
- if (!thermalManager.fan_speed[0] || ++fan_frame >= STATUS_FAN_FRAMES) fan_frame = 0;
+ if (!fans[0].speed || ++fan_frame >= STATUS_FAN_FRAMES) fan_frame = 0;
}
#endif
if (PAGE_CONTAINS(STATUS_FAN_Y, STATUS_FAN_Y + STATUS_FAN_HEIGHT - 1))
@@ -686,7 +686,7 @@ void MarlinUI::draw_status_screen() {
fan_frame == 3 ? status_fan3_bmp :
#endif
#elif STATUS_FAN_FRAMES > 1
- blink && thermalManager.fan_speed[0] ? status_fan1_bmp :
+ blink && fans[0].speed ? status_fan1_bmp :
#endif
status_fan0_bmp
);
@@ -758,15 +758,15 @@ void MarlinUI::draw_status_screen() {
#if DO_DRAW_FAN
if (PAGE_CONTAINS(STATUS_FAN_TEXT_Y - INFO_FONT_ASCENT, STATUS_FAN_TEXT_Y - 1)) {
char c = '%';
- uint16_t spd = thermalManager.fan_speed[0];
+ uint16_t spd = fans[0].speed;
if (spd) {
#if ENABLED(ADAPTIVE_FAN_SLOWING)
- if (!blink && thermalManager.fan_speed_scaler[0] < 128) {
- spd = thermalManager.scaledFanSpeed(0, spd);
+ if (!blink && fans[0].speed_scaler < 128) {
+ spd = fans[0].scaled_speed(spd);
c = '*';
}
#endif
- lcd_put_u8str(STATUS_FAN_TEXT_X, STATUS_FAN_TEXT_Y, i16tostr3rj(thermalManager.pwmToPercent(spd)));
+ lcd_put_u8str(STATUS_FAN_TEXT_X, STATUS_FAN_TEXT_Y, i16tostr3rj(Fan::pwmToPercent(spd)));
lcd_put_lchar(c);
}
}
diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
index ac7941f844..cc408c7136 100644
--- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
+++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
@@ -637,7 +637,7 @@ bool ST7920_Lite_Status_Screen::indicators_changed() {
// them only during blinks we gain a bit of stability.
const bool blink = ui.get_blink();
const uint16_t feedrate_perc = feedrate_percentage;
- const uint16_t fs = thermalManager.scaledFanSpeed(0);
+ const uint16_t fs = fans[0].scaled_speed();
const celsius_t extruder_1_target = thermalManager.degTargetHotend(0);
#if HAS_MULTI_HOTEND
const celsius_t extruder_2_target = thermalManager.degTargetHotend(1);
@@ -819,12 +819,12 @@ void ST7920_Lite_Status_Screen::update_indicators(const bool forceUpdate) {
TERN_(HAS_HEATED_BED, draw_bed_temp(bed_temp, bed_target, forceUpdate));
// Update the fan and bed animations
- uint8_t spd = thermalManager.fan_speed[0];
+ uint8_t spd = fans[0].speed;
#if ENABLED(ADAPTIVE_FAN_SLOWING)
- if (!blink && thermalManager.fan_speed_scaler[0] < 128)
- spd = thermalManager.scaledFanSpeed(0, spd);
+ if (!blink && fans[0].speed_scaler < 128)
+ spd = fans[0].scaled_speed(spd);
#endif
- draw_fan_speed(thermalManager.pwmToPercent(spd));
+ draw_fan_speed(Fan::pwmToPercent(spd));
if (spd) draw_fan_icon(blink);
TERN_(HAS_HEATED_BED, draw_heat_icon(bed_target > 0 && blink, bed_target > 0));
diff --git a/Marlin/src/lcd/dwin/creality/dwin.cpp b/Marlin/src/lcd/dwin/creality/dwin.cpp
index 875dfd5fd1..4240659af8 100644
--- a/Marlin/src/lcd/dwin/creality/dwin.cpp
+++ b/Marlin/src/lcd/dwin/creality/dwin.cpp
@@ -984,7 +984,7 @@ void drawTuneMenu() {
#endif
#if HAS_FAN
drawMenuLine(TUNE_CASE_FAN, ICON_FanSpeed);
- drawEditInteger3(TUNE_CASE_FAN, thermalManager.fan_speed[0]);
+ drawEditInteger3(TUNE_CASE_FAN, fans[0].speed);
#endif
#if HAS_ZOFFSET_ITEM
drawMenuLine(TUNE_CASE_ZOFF, ICON_Zoffset);
@@ -1713,8 +1713,8 @@ void updateVariable() {
#endif
#if HAS_FAN
static uint8_t _fanspeed = 0;
- const bool _new_fanspeed = _fanspeed != thermalManager.fan_speed[0];
- if (_new_fanspeed) _fanspeed = thermalManager.fan_speed[0];
+ const bool _new_fanspeed = _fanspeed != fans[0].speed;
+ if (_new_fanspeed) _fanspeed = fans[0].speed;
#endif
if (checkkey == ID_Tune) {
@@ -1775,7 +1775,7 @@ void updateVariable() {
#if HAS_FAN
if (_new_fanspeed) {
- _fanspeed = thermalManager.fan_speed[0];
+ _fanspeed = fans[0].speed;
drawStatInt(195 + 2 * STAT_CHR_W, 384, _fanspeed);
}
#endif
@@ -2026,7 +2026,7 @@ void drawStatusArea(const bool with_update) {
#if HAS_FAN
dwinIconShow(ICON, ICON_FanSpeed, 187, 383);
- drawStatInt(195 + 2 * STAT_CHR_W, 384, thermalManager.fan_speed[0]);
+ drawStatInt(195 + 2 * STAT_CHR_W, 384, fans[0].speed);
#endif
#if HAS_ZOFFSET_ITEM
@@ -2278,7 +2278,7 @@ void hmiSelectFile() {
// All fans on for Ender-3 v2 ?
// The slicer should manage this for us.
//for (uint8_t i = 0; i < FAN_COUNT; i++)
- // thermalManager.fan_speed[i] = 255;
+ // fans[i].speed = 255;
#endif
_card_percent = 0;
@@ -2873,7 +2873,7 @@ void drawTemperatureMenu() {
#endif
#if HAS_FAN
_TMENU_ICON(TEMP_CASE_FAN);
- drawEditInteger3(i, thermalManager.fan_speed[0]);
+ drawEditInteger3(i, fans[0].speed);
#endif
#if HAS_PREHEAT
// PLA/ABS items have submenus
@@ -3104,7 +3104,7 @@ void hmiTemperature() {
#if HAS_FAN
case TEMP_CASE_FAN:
checkkey = ID_FanSpeed;
- hmiValues.fanSpeed = thermalManager.fan_speed[0];
+ hmiValues.fanSpeed = fans[0].speed;
drawEditInteger3(3, hmiValues.fanSpeed, true);
encoderRate.enabled = true;
break;
@@ -3831,7 +3831,7 @@ void hmiTune() {
#if HAS_FAN
case TUNE_CASE_FAN: // Fan speed
checkkey = ID_FanSpeed;
- hmiValues.fanSpeed = thermalManager.fan_speed[0];
+ hmiValues.fanSpeed = fans[0].speed;
drawEditInteger3(TUNE_CASE_FAN + MROWS - index_tune, hmiValues.fanSpeed, true);
encoderRate.enabled = true;
break;
diff --git a/Marlin/src/lcd/dwin/jyersui/dwin.cpp b/Marlin/src/lcd/dwin/jyersui/dwin.cpp
index d451526540..910e823d86 100644
--- a/Marlin/src/lcd/dwin/jyersui/dwin.cpp
+++ b/Marlin/src/lcd/dwin/jyersui/dwin.cpp
@@ -849,9 +849,9 @@ void JyersDWIN::drawStatusArea(const bool icons/*=false*/) {
fan = -1;
dwinIconShow(ICON, ICON_FanSpeed, 187, 383);
}
- if (thermalManager.fan_speed[0] != fan) {
- fan = thermalManager.fan_speed[0];
- dwinDrawIntValue(true, true, 0, DWIN_FONT_STAT, getColor(eeprom_settings.status_area_text, COLOR_WHITE), COLOR_BG_BLACK, 3, 195 + 2 * STAT_CHR_W, 384, thermalManager.fan_speed[0]);
+ if (fans[0].speed != fan) {
+ fan = fans[0].speed;
+ dwinDrawIntValue(true, true, 0, DWIN_FONT_STAT, getColor(eeprom_settings.status_area_text, COLOR_WHITE), COLOR_BG_BLACK, 3, 195 + 2 * STAT_CHR_W, 384, fans[0].speed);
}
#endif
@@ -2012,10 +2012,10 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
case TEMP_FAN:
if (draw) {
drawMenuItem(row, ICON_FanSpeed, GET_TEXT_F(MSG_FAN_SPEED));
- drawFloat(thermalManager.fan_speed[0], row, false, 1);
+ drawFloat(fans[0].speed, row, false, 1);
}
else
- modifyValue(thermalManager.fan_speed[0], MIN_FAN_SPEED, MAX_FAN_SPEED, 1);
+ modifyValue(fans[0].speed, MIN_FAN_SPEED, MAX_FAN_SPEED, 1);
break;
#endif
#if ANY(PIDTEMP, PIDTEMPBED)
@@ -3877,10 +3877,10 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
case TUNE_FAN:
if (draw) {
drawMenuItem(row, ICON_FanSpeed, GET_TEXT_F(MSG_FAN_SPEED));
- drawFloat(thermalManager.fan_speed[0], row, false, 1);
+ drawFloat(fans[0].speed, row, false, 1);
}
else
- modifyValue(thermalManager.fan_speed[0], MIN_FAN_SPEED, MAX_FAN_SPEED, 1);
+ modifyValue(fans[0].speed, MIN_FAN_SPEED, MAX_FAN_SPEED, 1);
break;
#endif
@@ -4606,7 +4606,7 @@ void JyersDWIN::printScreenControl() {
#if HAS_EXTRUDERS
queue.inject(TS(F("M109 S"), pausetemp));
#endif
- TERN_(HAS_FAN, thermalManager.fan_speed[0] = pausefan);
+ TERN_(HAS_FAN, fans[0].speed = pausefan);
planner.synchronize();
TERN_(HAS_MEDIA, queue.inject(FPSTR(M24_STR)));
#endif
@@ -4656,7 +4656,7 @@ void JyersDWIN::popupControl() {
queue.inject(F("M25"));
TERN_(HAS_HOTEND, pausetemp = thermalManager.degTargetHotend(0));
TERN_(HAS_HEATED_BED, pausebed = thermalManager.degTargetBed());
- TERN_(HAS_FAN, pausefan = thermalManager.fan_speed[0]);
+ TERN_(HAS_FAN, pausefan = fans[0].speed);
thermalManager.cooldown();
#endif
}
@@ -5040,8 +5040,8 @@ void JyersDWIN::screenUpdate() {
}
#endif
#if HAS_FAN
- if (thermalManager.fan_speed[0] != fanspeed) {
- fanspeed = thermalManager.fan_speed[0];
+ if (fans[0].speed != fanspeed) {
+ fanspeed = fans[0].speed;
if (scrollpos <= TEMP_FAN && TEMP_FAN <= scrollpos + MROWS) {
if (process != Proc_Value || selection != TEMP_HOTEND - scrollpos)
drawFloat(fanspeed, TEMP_FAN - scrollpos, false, 1);
@@ -5069,8 +5069,8 @@ void JyersDWIN::screenUpdate() {
}
#endif
#if HAS_FAN
- if (thermalManager.fan_speed[0] != fanspeed) {
- fanspeed = thermalManager.fan_speed[0];
+ if (fans[0].speed != fanspeed) {
+ fanspeed = fans[0].speed;
if (scrollpos <= TUNE_FAN && TUNE_FAN <= scrollpos + MROWS) {
if (process != Proc_Value || selection != TEMP_HOTEND - scrollpos)
drawFloat(fanspeed, TUNE_FAN - scrollpos, false, 1);
diff --git a/Marlin/src/lcd/dwin/marlinui/ui_status_480x272.cpp b/Marlin/src/lcd/dwin/marlinui/ui_status_480x272.cpp
index dbeb02dc67..fc55853786 100644
--- a/Marlin/src/lcd/dwin/marlinui/ui_status_480x272.cpp
+++ b/Marlin/src/lcd/dwin/marlinui/ui_status_480x272.cpp
@@ -149,10 +149,10 @@ void _draw_axis_value(const AxisEnum axis, const char *value, const bool blink,
//
FORCE_INLINE void _draw_fan_status(const uint16_t x, const uint16_t y) {
const uint16_t fanx = (4 * STATUS_CHR_WIDTH - STATUS_FAN_WIDTH) / 2;
- const bool fan_on = !!thermalManager.scaledFanSpeed(0);
+ const bool fan_on = !!fans[0].scaled_speed();
if (fan_on) {
dwinIconAnimation(0, fan_on, ICON, ICON_Fan0, ICON_Fan3, x + fanx, y, 25);
- dwin_string.set(i8tostr3rj(thermalManager.scaledFanSpeedPercent(0)));
+ dwin_string.set(i8tostr3rj(fans[0].speed_pct_scaled()));
dwin_string.add('%');
dwinDrawString(true, font14x28, COLOR_WHITE, COLOR_BG_BLACK, x, y + STATUS_FAN_HEIGHT, S(dwin_string.string()));
}
diff --git a/Marlin/src/lcd/dwin/proui/dwin.cpp b/Marlin/src/lcd/dwin/proui/dwin.cpp
index ae94ee0025..55726cb3df 100644
--- a/Marlin/src/lcd/dwin/proui/dwin.cpp
+++ b/Marlin/src/lcd/dwin/proui/dwin.cpp
@@ -826,8 +826,8 @@ void updateVariable() {
#if HAS_FAN
static uint8_t _fanspeed = 0;
- const bool _new_fanspeed = _fanspeed != thermalManager.fan_speed[0];
- if (_new_fanspeed) _fanspeed = thermalManager.fan_speed[0];
+ const bool _new_fanspeed = _fanspeed != fans[0].speed;
+ if (_new_fanspeed) _fanspeed = fans[0].speed;
#endif
if (isMenu(tuneMenu) || isMenu(temperatureMenu)) {
@@ -1096,7 +1096,7 @@ void dwinDrawDashboard() {
#if HAS_FAN
DWINUI::drawIcon(ICON_FanSpeed, 187, 383);
- DWINUI::drawInt(DWIN_FONT_STAT, hmiData.colorIndicator, hmiData.colorBackground, 3, 195 + 2 * STAT_CHR_W, 384, thermalManager.fan_speed[0]);
+ DWINUI::drawInt(DWIN_FONT_STAT, hmiData.colorIndicator, hmiData.colorBackground, 3, 195 + 2 * STAT_CHR_W, 384, fans[0].speed);
#endif
#if HAS_ZOFFSET_ITEM
@@ -2398,7 +2398,7 @@ void setFlow() { setPIntOnClick(FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refres
#if HAS_FAN
void applyFanSpeed() { thermalManager.set_fan_speed(0, menuData.value); }
- void setFanSpeed() { setIntOnClick(0, 255, thermalManager.fan_speed[0], applyFanSpeed); }
+ void setFanSpeed() { setIntOnClick(0, 255, fans[0].speed, applyFanSpeed); }
#endif
#if ENABLED(NOZZLE_PARK_FEATURE)
@@ -3531,7 +3531,7 @@ void drawTuneMenu() {
bedTargetItem = EDIT_ITEM(ICON_BedTemp, MSG_UBL_SET_TEMP_BED, onDrawBedTemp, setBedTemp, &thermalManager.temp_bed.target);
#endif
#if HAS_FAN
- fanSpeedItem = EDIT_ITEM(ICON_FanSpeed, MSG_FAN_SPEED, onDrawFanSpeed, setFanSpeed, &thermalManager.fan_speed[0]);
+ fanSpeedItem = EDIT_ITEM(ICON_FanSpeed, MSG_FAN_SPEED, onDrawFanSpeed, setFanSpeed, &fans[0].speed);
#endif
#if ALL(HAS_ZOFFSET_ITEM, HAS_BED_PROBE, BABYSTEP_ZPROBE_OFFSET, BABYSTEPPING)
EDIT_ITEM(ICON_Zoffset, MSG_BABYSTEP_PROBE_Z, onDrawZOffset, setZOffset, &BABY_Z_VAR);
@@ -3828,7 +3828,7 @@ void drawTemperatureMenu() {
bedTargetItem = EDIT_ITEM(ICON_BedTemp, MSG_UBL_SET_TEMP_BED, onDrawBedTemp, setBedTemp, &thermalManager.temp_bed.target);
#endif
#if HAS_FAN
- fanSpeedItem = EDIT_ITEM(ICON_FanSpeed, MSG_FAN_SPEED, onDrawFanSpeed, setFanSpeed, &thermalManager.fan_speed[0]);
+ fanSpeedItem = EDIT_ITEM(ICON_FanSpeed, MSG_FAN_SPEED, onDrawFanSpeed, setFanSpeed, &fans[0].speed);
#endif
#if HAS_PREHEAT
#define _ITEM_SETPREHEAT(N) MENU_ITEM(ICON_SetPreheat##N, MSG_PREHEAT_## N ##_SETTINGS, onDrawSubMenu, drawPreheat## N ##Menu);
diff --git a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp
index 9ec98779c8..e85889e4a1 100644
--- a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp
+++ b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp
@@ -414,9 +414,9 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
#define FAN_CONTROL 4
#endif
#define FAN_VPHELPER(N) \
- VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \
- VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
- VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay),
+ VPHELPER(VP_Fan##N##_Percentage, &fans[N].speed, screen.percentageToUint8, screen.sendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &fans[N].speed, screen.handleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &fans[N].speed, nullptr, screen.sendFanStatusToDisplay),
REPEAT(FAN_CONTROL, FAN_VPHELPER)
#endif
diff --git a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp
index db0ebbc903..e06edbf27d 100644
--- a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp
+++ b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp
@@ -407,9 +407,9 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
#define FAN_CONTROL 2
#endif
#define FAN_VPHELPER(N) \
- VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \
- VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
- VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay),
+ VPHELPER(VP_Fan##N##_Percentage, &fans[N].speed, screen.percentageToUint8, screen.sendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &fans[N].speed, screen.handleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &fans[N].speed, nullptr, screen.sendFanStatusToDisplay),
REPEAT(FAN_CONTROL, FAN_VPHELPER)
#endif
diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp
index b108dab0a0..6d1e1944d1 100644
--- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp
+++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp
@@ -535,9 +535,9 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
#define FAN_CONTROL 4
#endif
#define FAN_VPHELPER(N) \
- VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendFanToDisplay), \
- VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
- VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay),
+ VPHELPER(VP_Fan##N##_Percentage, &fans[N].speed, screen.percentageToUint8, screen.sendFanToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &fans[N].speed, screen.handleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &fans[N].speed, nullptr, screen.sendFanStatusToDisplay),
REPEAT(FAN_CONTROL, FAN_VPHELPER)
#endif
diff --git a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp
index 2cb7bd6f83..ac357468bd 100644
--- a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp
+++ b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp
@@ -215,9 +215,9 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
#define FAN_CONTROL 2
#endif
#define FAN_VPHELPER(N) \
- VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \
- VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
- VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay),
+ VPHELPER(VP_Fan##N##_Percentage, &fans[N].speed, screen.percentageToUint8, screen.sendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &fans[N].speed, screen.handleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &fans[N].speed, nullptr, screen.sendFanStatusToDisplay),
REPEAT(FAN_CONTROL, FAN_VPHELPER)
#endif
diff --git a/Marlin/src/lcd/extui/mks_ui/draw_fan.cpp b/Marlin/src/lcd/extui/mks_ui/draw_fan.cpp
index ea7469980b..4389a453ca 100644
--- a/Marlin/src/lcd/extui/mks_ui/draw_fan.cpp
+++ b/Marlin/src/lcd/extui/mks_ui/draw_fan.cpp
@@ -47,7 +47,7 @@ enum {
uint8_t fanPercent = 0;
static void event_handler(lv_obj_t *obj, lv_event_t event) {
if (event != LV_EVENT_RELEASED) return;
- const uint8_t temp = map(thermalManager.fan_speed[0], 0, 255, 0, 100);
+ const uint8_t temp = map(fans[0].speed, 0, 255, 0, 100);
if (abs(fanPercent - temp) > 2) fanPercent = temp;
switch (obj->mks_obj_id) {
case ID_F_ADD: if (fanPercent < 100) fanPercent++; break;
diff --git a/Marlin/src/lcd/extui/mks_ui/draw_printing.cpp b/Marlin/src/lcd/extui/mks_ui/draw_printing.cpp
index 5c13eeaa01..b8ae09a9e0 100644
--- a/Marlin/src/lcd/extui/mks_ui/draw_printing.cpp
+++ b/Marlin/src/lcd/extui/mks_ui/draw_printing.cpp
@@ -239,7 +239,7 @@ void disp_bed_temp() {
}
void disp_fan_speed() {
- sprintf_P(public_buf_l, PSTR("%d%%"), (int)thermalManager.fanSpeedPercent(0));
+ sprintf_P(public_buf_l, PSTR("%d%%"), (int)fans[0].speed_pct());
lv_label_set_text(labelFan, public_buf_l);
}
diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp b/Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp
index a3b31e33b5..257d33a299 100644
--- a/Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp
+++ b/Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp
@@ -233,7 +233,7 @@ void lv_temp_refr() {
lv_obj_align(labelBed, buttonBedstate, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
#endif
#if HAS_FAN
- sprintf_P(public_buf_l, PSTR("%d%%"), (int)thermalManager.fanSpeedPercent(0));
+ sprintf_P(public_buf_l, PSTR("%d%%"), (int)fans[0].speed_pct());
lv_label_set_text(labelFan, public_buf_l);
lv_obj_align(labelFan, buttonFanstate, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
#endif
diff --git a/Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp b/Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp
index c216eb7e63..5b8c33043e 100644
--- a/Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp
+++ b/Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp
@@ -261,7 +261,7 @@
void mks_hardware_test() {
if (millis() % 2000 < 1000) {
- thermalManager.fan_speed[0] = 255;
+ fans[0].speed = 255;
#if HAS_X_AXIS
WRITE(X_DIR_PIN, LOW);
#endif
@@ -288,7 +288,7 @@
#endif
}
else {
- thermalManager.fan_speed[0] = 0;
+ fans[0].speed = 0;
#if HAS_X_AXIS
WRITE(X_DIR_PIN, HIGH);
#endif
diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp
index 608e632854..97084cb6f8 100644
--- a/Marlin/src/lcd/extui/ui_api.cpp
+++ b/Marlin/src/lcd/extui/ui_api.cpp
@@ -314,12 +314,12 @@ namespace ExtUI {
//
uint8_t getTargetFan_percent(const fan_t fan) {
UNUSED(fan);
- return TERN0(HAS_FAN, thermalManager.fanSpeedPercent(fan - FAN0));
+ return TERN0(HAS_FAN, fans[fan - FAN0].speed_pct());
}
uint8_t getActualFan_percent(const fan_t fan) {
UNUSED(fan);
- return TERN0(HAS_FAN, thermalManager.scaledFanSpeedPercent(fan - FAN0));
+ return TERN0(HAS_FAN, fans[fan - FAN0].speed_pct_scaled());
}
//
diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h
index 8b23ab1b9c..d1931ed90f 100644
--- a/Marlin/src/lcd/menu/menu_item.h
+++ b/Marlin/src/lcd/menu/menu_item.h
@@ -631,9 +631,9 @@ class MenuItem_bool : public MenuEditItemBase {
#endif
#define _FAN_EDIT_ITEMS(F,L) do{ \
- editable.uint8 = thermalManager.fan_speed[F]; \
+ editable.uint8 = fans[F].speed; \
EDIT_ITEM_FAST_N(percent, F, MSG_##L, &editable.uint8, 0, 255, on_fan_update); \
- EDIT_EXTRA_FAN_SPEED(percent, F, MSG_EXTRA_##L, &thermalManager.extra_fan_speed[F].speed, 3, 255); \
+ EDIT_EXTRA_FAN_SPEED(percent, F, MSG_EXTRA_##L, &fans[F].extra.speed, 3, 255); \
}while(0)
#if FAN_COUNT > 1
diff --git a/Marlin/src/lcd/tft/touch.cpp b/Marlin/src/lcd/tft/touch.cpp
index 661a013323..954e7ec775 100644
--- a/Marlin/src/lcd/tft/touch.cpp
+++ b/Marlin/src/lcd/tft/touch.cpp
@@ -265,10 +265,11 @@ void Touch::touch(touch_control_t * const control) {
case FAN: {
ui.clear_for_drawing();
- static uint8_t fan, fan_speed;
- fan = 0;
- fan_speed = thermalManager.fan_speed[fan];
- MenuItem_percent::action(GET_TEXT_F(MSG_FIRST_FAN_SPEED), &fan_speed, 0, 255, []{ thermalManager.set_fan_speed(fan, fan_speed); TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS));});
+ editable.uint8 = fans[0].speed;
+ MenuItem_percent::action(GET_TEXT_F(MSG_FIRST_FAN_SPEED), &editable.uint8, 0, 255, []{
+ thermalManager.set_fan_speed(0, editable.uint8);
+ TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS));
+ });
} break;
case FEEDRATE:
diff --git a/Marlin/src/lcd/tft/ui_color_ui.cpp b/Marlin/src/lcd/tft/ui_color_ui.cpp
index 53b3b0d068..2d2eec53ad 100644
--- a/Marlin/src/lcd/tft/ui_color_ui.cpp
+++ b/Marlin/src/lcd/tft/ui_color_ui.cpp
@@ -204,7 +204,7 @@ void draw_fan_status(uint16_t x, uint16_t y, const bool blink) {
tft.canvas(x, y, TEMP_FAN_CONTROL_W, TEMP_FAN_CONTROL_H);
tft.set_background(COLOR_BACKGROUND);
- uint8_t fanSpeed = thermalManager.fan_speed[0];
+ uint8_t fanSpeed = fans[0].speed;
MarlinImage image;
if (fanSpeed >= 127)
@@ -216,7 +216,7 @@ void draw_fan_status(uint16_t x, uint16_t y, const bool blink) {
tft.add_image(FAN_ICON_X, FAN_ICON_Y, image, COLOR_FAN);
- tft_string.set(ui8tostr4pctrj(thermalManager.fan_speed[0]));
+ tft_string.set(ui8tostr4pctrj(fans[0].speed));
tft_string.trim();
tft.add_text(FAN_TEXT_X, FAN_TEXT_Y, COLOR_FAN, tft_string);
}
diff --git a/Marlin/src/module/fans.cpp b/Marlin/src/module/fans.cpp
new file mode 100644
index 0000000000..c7cfc80e1e
--- /dev/null
+++ b/Marlin/src/module/fans.cpp
@@ -0,0 +1,89 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/**
+ * fans.cpp - Fan class
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if HAS_FAN
+
+#include "fans.h"
+
+#define _FANDEF(N) Fan(N),
+Fan fans[FAN_COUNT] = { REPEAT(FAN_COUNT, _FANDEF) };
+
+#if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
+ bool Fan::paused; // = false
+#endif
+
+void Fan::init_pins() {
+ #define _INIT(N) fans[N].init();
+ REPEAT(FAN_COUNT, _INIT)
+}
+
+#if ENABLED(REPORT_FAN_CHANGE)
+ /**
+ * Report print fan speed for a target extruder
+ */
+ void Fan::report_speed(const uint8_t fan_index) {
+ PORT_REDIRECT(SerialMask::All);
+ SERIAL_ECHOLNPGM("M106 P", fan_index, " S", speed);
+ }
+#endif
+
+#if ENABLED(EXTRA_FAN_SPEED)
+ /**
+ * Handle the M106 P T command:
+ * T1 = Restore fan speed saved on the last T2
+ * T2 = Save the fan speed, then set to the last T<3-255> value
+ * T<3-255> = Set the "extra fan speed"
+ */
+ void Fan::set_temp_speed(const uint16_t command_or_speed) {
+ switch (command_or_speed) {
+ case 1: break;
+ case 2: extra.saved = speed; break;
+ default: extra.speed = _MIN(command_or_speed, 255U); break;
+ }
+ }
+#endif
+
+#if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
+ void Fan::pause(const bool p) {
+ if (p) {
+ pause_speed = speed;
+ speed = 0;
+ }
+ else
+ speed = pause_speed;
+ }
+
+ void Fan::all_pause(const bool p) {
+ if (p != paused) {
+ paused = p;
+ FANS_LOOP(i) fans[i].pause(p);
+ }
+ }
+#endif
+
+#endif // HAS_FAN
diff --git a/Marlin/src/module/fans.h b/Marlin/src/module/fans.h
new file mode 100644
index 0000000000..312d021a87
--- /dev/null
+++ b/Marlin/src/module/fans.h
@@ -0,0 +1,209 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+/**
+ * fans.h - Fan class
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if ANY(HAS_FAN, USE_CONTROLLER_FAN)
+ // Init fans according to whether they're native PWM or Software PWM
+ #ifdef BOARD_OPENDRAIN_MOSFETS
+ #define _INIT_SOFT_FAN(P) OUT_WRITE_OD(P, ENABLED(FAN_INVERTING) ? LOW : HIGH)
+ #else
+ #define _INIT_SOFT_FAN(P) OUT_WRITE(P, ENABLED(FAN_INVERTING) ? LOW : HIGH)
+ #endif
+ #if ENABLED(FAN_SOFT_PWM)
+ #define _INIT_FAN_PIN(P) _INIT_SOFT_FAN(P)
+ #else
+ #define _INIT_FAN_PIN(P) do{ if (PWM_PIN(P)) SET_PWM(P); else _INIT_SOFT_FAN(P); }while(0)
+ #endif
+ #if ENABLED(FAST_PWM_FAN)
+ #define SET_FAST_PWM_FREQ(P) hal.set_pwm_frequency(pin_t(P), FAST_PWM_FAN_FREQUENCY)
+ #else
+ #define SET_FAST_PWM_FREQ(P) NOOP
+ #endif
+ #define INIT_FAN_PIN(P) do{ _INIT_FAN_PIN(P); SET_FAST_PWM_FREQ(P); }while(0)
+#endif
+
+#if HAS_FAN
+
+ #define PWM_MASK TERN0(SOFT_PWM_DITHER, _BV(SOFT_PWM_SCALE) - 1)
+
+ #if ENABLED(FAN_SOFT_PWM)
+
+ #define _SOFT_PWM(N) do{ \
+ soft_pwm_count &= PWM_MASK; \
+ soft_pwm_count += (soft_pwm_amount >> 1); \
+ write(N, soft_pwm_count > PWM_MASK ? HIGH : LOW); \
+ }while(0)
+
+ #define _SLOW_PWM(N) do{ \
+ soft_pwm_count = soft_pwm_amount >> 1; \
+ write(N, soft_pwm_count > 0 ? HIGH : LOW); \
+ }while(0)
+
+ #endif
+
+ #define FANS_LOOP(I) for (uint8_t I = 0; I < FAN_COUNT; ++I)
+
+ class Fan;
+ extern Fan fans[FAN_COUNT];
+
+ class Fan {
+ public:
+ uint8_t index;
+
+ Fan(const uint8_t fi) : index(fi) {}
+
+ void init() {
+ #define _INIT(N) if (index == N) INIT_FAN_PIN(FAN##N##_PIN);
+ REPEAT(FAN_COUNT, _INIT)
+ #undef _INIT
+ }
+ static void init_pins();
+
+ static constexpr uint8_t pwmToPercent(const uint8_t spd) { return ui8_to_percent(spd); }
+
+ #if ENABLED(FAN_SOFT_PWM)
+ uint8_t soft_pwm_amount, soft_pwm_count;
+ void soft_pwm_on() {
+ #define _CASE(N) if (index == N) _SOFT_PWM(N);
+ REPEAT(FAN_COUNT, _CASE)
+ #undef _CASE
+ }
+ void slow_soft_pwm() {
+ #define _CASE(N) if (index == N) _SLOW_PWM(N);
+ REPEAT(FAN_COUNT, _CASE)
+ #undef _CASE
+ }
+ void soft_pwm_off(const uint8_t count) {
+ #define _CASE(N) if (index == N) if (soft_pwm_count <= count) write(LOW);
+ REPEAT(FAN_COUNT, _CASE)
+ #undef _CASE
+ }
+ #endif
+
+ uint8_t speed;
+ uint8_t speed_pct() { return pwmToPercent(speed); }
+
+ #if ENABLED(REPORT_FAN_CHANGE)
+ void report_speed(const uint8_t fan_index);
+ #endif
+
+ #if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
+ uint8_t pause_speed;
+ static bool paused;
+ static void all_pause(const bool p);
+ static void power_off() { paused = false; FANS_LOOP(i) fans[i].pause_speed = 0; }
+ void pause(const bool p);
+ #endif
+
+ #if ENABLED(AUTO_POWER_FANS)
+ static bool is_power_needed() {
+ FANS_LOOP(f) if (fans[f].speed) return true;
+ return false;
+ }
+ #endif
+
+ #if FAN_KICKSTART_TIME
+ millis_t kick_end_ms = 0;
+ #if ENABLED(FAN_KICKSTART_LINEAR)
+ uint8_t prev_fan_speed = 0;
+ #endif
+ void kickstart(const millis_t &ms) {
+ if (speed > FAN_OFF_PWM) {
+ const bool first_kick = kick_end_ms == 0 && TERN1(FAN_KICKSTART_LINEAR, speed > prev_fan_speed);
+ if (first_kick)
+ kick_end_ms = ms + MUL_TERN(FAN_KICKSTART_LINEAR, FAN_KICKSTART_TIME, (speed - prev_fan_speed) / 255);
+ if (first_kick || PENDING(ms, kick_end_ms)) {
+ speed = FAN_KICKSTART_POWER;
+ return;
+ }
+ }
+ else
+ kick_end_ms = 0;
+ TERN_(FAN_KICKSTART_LINEAR, prev_fan_speed = speed);
+ }
+ #else
+ void kickstart(const millis_t&) {}
+ #endif
+
+ #if ENABLED(EXTRA_FAN_SPEED)
+ struct { uint8_t saved, speed; } extra;
+ void set_temp_speed(const uint16_t command_or_speed);
+ #endif
+
+ #if DISABLED(LASER_SYNCHRONOUS_M106_M107)
+ #define HAS_TAIL_FAN_SPEED 1
+ uint8_t tail_speed = 13;
+ #endif
+
+ #if ENABLED(ADAPTIVE_FAN_SLOWING)
+ uint8_t speed_scaler = 128;
+ uint8_t scaled_speed(const uint8_t fs) const { return (fs * uint16_t(speed_scaler)) >> 7; }
+ #else
+ static constexpr uint8_t scaled_speed(const uint8_t fs) { return fs; }
+ #endif
+ uint8_t scaled_speed() const { return scaled_speed(speed); }
+ uint8_t speed_pct_scaled() const { return ui8_to_percent(scaled_speed()); }
+
+ uint8_t pwm() {
+ #if FAN_MIN_PWM != 0 || FAN_MAX_PWM != 255
+ return speed ? map(speed, 1, 255, FAN_MIN_PWM, FAN_MAX_PWM) : FAN_OFF_PWM;
+ #else
+ return speed ?: FAN_OFF_PWM;
+ #endif
+ }
+
+ void sync(const millis_t &ms, const pin_t pin) {
+ kickstart(ms);
+ #if ENABLED(FAN_SOFT_PWM)
+ UNUSED(pin);
+ soft_pwm_amount = pwm();
+ #else
+ hal.set_pwm_duty(pin, pwm());
+ #endif
+ }
+
+ static void sync_speeds() {
+ const millis_t ms = millis();
+ #define FAN_SET(F) fans[F].sync(ms, pin_t(FAN##F##_PIN));
+ REPEAT(FAN_COUNT, FAN_SET)
+ #undef FAN_SET
+ }
+ static void sync_speeds(uint8_t (&fanspeed)[FAN_COUNT]) {
+ FANS_LOOP(f) fans[f].speed = fanspeed[f];
+ sync_speeds();
+ }
+
+ static void write(const uint8_t fi, const uint8_t state) {
+ #define _CASE(N) if (fi == N) WRITE(FAN ##N## _PIN, (state) ^ ENABLED(FAN_INVERTING));
+ REPEAT(FAN_COUNT, _CASE)
+ #undef _CASE
+ }
+ void write(const uint8_t state) { write(index, state); }
+ };
+
+#endif // HAS_FAN
diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp
index b4e9eb5f09..c2a2d1ed5b 100644
--- a/Marlin/src/module/planner.cpp
+++ b/Marlin/src/module/planner.cpp
@@ -1205,51 +1205,6 @@ void Planner::recalculate(const float safe_exit_speed_sqr) {
recalculate_trapezoids(safe_exit_speed_sqr);
}
-/**
- * Apply fan speeds
- */
-#if HAS_FAN
-
- void Planner::sync_fan_speeds(uint8_t (&fan_speed)[FAN_COUNT]) {
-
- #if ENABLED(FAN_SOFT_PWM)
- #define _FAN_SET(F) thermalManager.soft_pwm_amount_fan[F] = CALC_FAN_SPEED(fan_speed[F]);
- #else
- #define _FAN_SET(F) hal.set_pwm_duty(pin_t(FAN##F##_PIN), CALC_FAN_SPEED(fan_speed[F]));
- #endif
- #define FAN_SET(F) do{ kickstart_fan(fan_speed, ms, F); _FAN_SET(F); }while(0)
-
- const millis_t ms = millis();
- TERN_(HAS_FAN0, FAN_SET(0)); TERN_(HAS_FAN1, FAN_SET(1));
- TERN_(HAS_FAN2, FAN_SET(2)); TERN_(HAS_FAN3, FAN_SET(3));
- TERN_(HAS_FAN4, FAN_SET(4)); TERN_(HAS_FAN5, FAN_SET(5));
- TERN_(HAS_FAN6, FAN_SET(6)); TERN_(HAS_FAN7, FAN_SET(7));
- }
-
- #if FAN_KICKSTART_TIME
-
- void Planner::kickstart_fan(uint8_t (&fan_speed)[FAN_COUNT], const millis_t &ms, const uint8_t f) {
- static millis_t fan_kick_end[FAN_COUNT] = { 0 };
- #if ENABLED(FAN_KICKSTART_LINEAR)
- static uint8_t set_fan_speed[FAN_COUNT] = { 0 };
- #endif
- if (fan_speed[f] > FAN_OFF_PWM) {
- const bool first_kick = fan_kick_end[f] == 0 && TERN1(FAN_KICKSTART_LINEAR, fan_speed[f] > set_fan_speed[f]);
- if (first_kick)
- fan_kick_end[f] = ms + MUL_TERN(FAN_KICKSTART_LINEAR, FAN_KICKSTART_TIME, (fan_speed[f] - set_fan_speed[f]) / 255);
- if (first_kick || PENDING(ms, fan_kick_end[f])) {
- fan_speed[f] = FAN_KICKSTART_POWER;
- return;
- }
- }
- fan_kick_end[f] = 0;
- TERN_(FAN_KICKSTART_LINEAR, set_fan_speed[f] = fan_speed[f]);
- }
-
- #endif
-
-#endif // HAS_FAN
-
/**
* Maintain fans, paste extruder pressure, spindle/laser power
*/
@@ -1259,9 +1214,7 @@ void Planner::check_axes_activity() {
xyze_bool_t axis_active = { false };
#endif
- #if HAS_FAN && DISABLED(LASER_SYNCHRONOUS_M106_M107)
- #define HAS_TAIL_FAN_SPEED 1
- static uint8_t tail_fan_speed[FAN_COUNT] = ARRAY_N_1(FAN_COUNT, 13);
+ #if HAS_TAIL_FAN_SPEED
bool fans_need_update = false;
#endif
@@ -1282,10 +1235,11 @@ void Planner::check_axes_activity() {
#if HAS_TAIL_FAN_SPEED
FANS_LOOP(i) {
- const uint8_t spd = thermalManager.scaledFanSpeed(i, block->fan_speed[i]);
- if (tail_fan_speed[i] != spd) {
+ Fan &fan = fans[i];
+ const uint8_t spd = fan.scaled_speed(block->fan_speed[i]);
+ if (fan.tail_speed != spd) {
+ fan.tail_speed = spd;
fans_need_update = true;
- tail_fan_speed[i] = spd;
}
}
#endif
@@ -1319,10 +1273,11 @@ void Planner::check_axes_activity() {
#if HAS_TAIL_FAN_SPEED
FANS_LOOP(i) {
- const uint8_t spd = thermalManager.scaledFanSpeed(i);
- if (tail_fan_speed[i] != spd) {
+ Fan &fan = fans[i];
+ const uint8_t spd = fan.scaled_speed();
+ if (fan.tail_speed != spd) {
fans_need_update = true;
- tail_fan_speed[i] = spd;
+ fan.tail_speed = spd;
}
}
#endif
@@ -1355,7 +1310,7 @@ void Planner::check_axes_activity() {
// Update Fan speeds
// Only if synchronous M106/M107 is disabled
//
- TERN_(HAS_TAIL_FAN_SPEED, if (fans_need_update) sync_fan_speeds(tail_fan_speed));
+ TERN_(HAS_TAIL_FAN_SPEED, if (fans_need_update) Fan::sync_speeds());
// Update hotend temperature based on extruder speed
TERN_(AUTOTEMP, thermalManager.autotemp_task());
@@ -2087,7 +2042,7 @@ bool Planner::_populate_block(
TERN_(MIXING_EXTRUDER, mixer.populate_block(block->b_color));
#if HAS_FAN
- FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
+ FANS_LOOP(i) block->fan_speed[i] = fans[i].speed;
#endif
#if ENABLED(BARICUDA)
@@ -2798,7 +2753,7 @@ void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_PO
#endif
#if ENABLED(LASER_SYNCHRONOUS_M106_M107)
- FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
+ FANS_LOOP(i) block->fan_speed[i] = fans[i].speed;
#endif
/**
@@ -3078,7 +3033,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const feedRate_t fr_mm_s
block->flag.reset(BLOCK_BIT_PAGE);
#if HAS_FAN
- FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
+ FANS_LOOP(i) block->fan_speed[i] = fans[i].speed;
#endif
E_TERN_(block->extruder = extruder);
diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h
index 2838fb90c3..8d69544137 100644
--- a/Marlin/src/module/planner.h
+++ b/Marlin/src/module/planner.h
@@ -53,6 +53,10 @@
#include "motion.h"
#include "../gcode/queue.h"
+#if HAS_FAN
+ #include "temperature.h"
+#endif
+
#if ENABLED(DELTA)
#include "delta.h"
#elif ENABLED(POLARGRAPH)
@@ -298,7 +302,7 @@ typedef struct PlannerBlock {
#endif
#if HAS_FAN
- uint8_t fan_speed[FAN_COUNT];
+ uint8_t fan_speed[FAN_COUNT]; // Speeds of all fans
#endif
#if ENABLED(BARICUDA)
@@ -684,16 +688,6 @@ class Planner {
static float get_high_e_speed();
#endif
- // Apply fan speeds
- #if HAS_FAN
- static void sync_fan_speeds(uint8_t (&fan_speed)[FAN_COUNT]);
- #if FAN_KICKSTART_TIME
- static void kickstart_fan(uint8_t (&fan_speed)[FAN_COUNT], const millis_t &ms, const uint8_t f);
- #else
- FORCE_INLINE static void kickstart_fan(uint8_t (&)[FAN_COUNT], const millis_t &, const uint8_t) {}
- #endif
- #endif
-
#if ENABLED(FILAMENT_WIDTH_SENSOR)
void apply_filament_width_sensor(const int8_t encoded_ratio);
diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp
index 3a8bb2b6c6..98edfaba6d 100644
--- a/Marlin/src/module/probe.cpp
+++ b/Marlin/src/module/probe.cpp
@@ -351,7 +351,7 @@ xyz_pos_t Probe::offset; // Initialized by settings.load
*/
void Probe::set_devices_paused_for_probing(const bool dopause) {
TERN_(PROBING_HEATERS_OFF, thermalManager.pause_heaters(dopause));
- TERN_(PROBING_FANS_OFF, thermalManager.set_fans_paused(dopause));
+ TERN_(PROBING_FANS_OFF, Fan::all_pause(dopause));
TERN_(PROBING_ESTEPPERS_OFF, if (dopause) stepper.disable_e_steppers());
#if ENABLED(PROBING_STEPPERS_OFF)
static main_axes_bits_t old_trusted;
diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp
index 84924b6f65..74fb761005 100644
--- a/Marlin/src/module/stepper.cpp
+++ b/Marlin/src/module/stepper.cpp
@@ -2659,7 +2659,7 @@ void Stepper::isr() {
// Set "fan speeds" for a laser module
#if ENABLED(LASER_SYNCHRONOUS_M106_M107)
- if (current_block->is_sync_fan()) planner.sync_fan_speeds(current_block->fan_speed);
+ if (current_block->is_sync_fan()) Fan::sync_speeds(current_block->fan_speed);
#endif
// Set position
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index f0ca49ef66..c13c0c2ceb 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -410,69 +410,8 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED);
uint8_t Temperature::coolerfan_speed = FAN_OFF_PWM;
#endif
-#if ALL(FAN_SOFT_PWM, USE_CONTROLLER_FAN)
- uint8_t Temperature::soft_pwm_controllerfan_speed = FAN_OFF_PWM;
-#endif
-
-// Init fans according to whether they're native PWM or Software PWM
-#ifdef BOARD_OPENDRAIN_MOSFETS
- #define _INIT_SOFT_FAN(P) OUT_WRITE_OD(P, ENABLED(FAN_INVERTING) ? LOW : HIGH)
-#else
- #define _INIT_SOFT_FAN(P) OUT_WRITE(P, ENABLED(FAN_INVERTING) ? LOW : HIGH)
-#endif
-#if ENABLED(FAN_SOFT_PWM)
- #define _INIT_FAN_PIN(P) _INIT_SOFT_FAN(P)
-#else
- #define _INIT_FAN_PIN(P) do{ if (PWM_PIN(P)) SET_PWM(P); else _INIT_SOFT_FAN(P); }while(0)
-#endif
-#if ENABLED(FAST_PWM_FAN)
- #define SET_FAST_PWM_FREQ(P) hal.set_pwm_frequency(pin_t(P), FAST_PWM_FAN_FREQUENCY)
-#else
- #define SET_FAST_PWM_FREQ(P) NOOP
-#endif
-#define INIT_FAN_PIN(P) do{ _INIT_FAN_PIN(P); SET_FAST_PWM_FREQ(P); }while(0)
-
// HAS_FAN does not include CONTROLLER_FAN
#if HAS_FAN
-
- uint8_t Temperature::fan_speed[FAN_COUNT] = ARRAY_N_1(FAN_COUNT, FAN_OFF_PWM);
-
- #if ENABLED(EXTRA_FAN_SPEED)
-
- Temperature::extra_fan_t Temperature::extra_fan_speed[FAN_COUNT] = ARRAY_N_1(FAN_COUNT, FAN_OFF_PWM);
-
- /**
- * Handle the M106 P T command:
- * T1 = Restore fan speed saved on the last T2
- * T2 = Save the fan speed, then set to the last T<3-255> value
- * T<3-255> = Set the "extra fan speed"
- */
- void Temperature::set_temp_fan_speed(const uint8_t fan, const uint16_t command_or_speed) {
- switch (command_or_speed) {
- case 1:
- set_fan_speed(fan, extra_fan_speed[fan].saved);
- break;
- case 2:
- extra_fan_speed[fan].saved = fan_speed[fan];
- set_fan_speed(fan, extra_fan_speed[fan].speed);
- break;
- default:
- extra_fan_speed[fan].speed = _MIN(command_or_speed, 255U);
- break;
- }
- }
-
- #endif
-
- #if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
- bool Temperature::fans_paused; // = false
- uint8_t Temperature::saved_fan_speed[FAN_COUNT] = ARRAY_N_1(FAN_COUNT, FAN_OFF_PWM);
- #endif
-
- #if ENABLED(ADAPTIVE_FAN_SLOWING)
- uint8_t Temperature::fan_speed_scaler[FAN_COUNT] = ARRAY_N_1(FAN_COUNT, 128);
- #endif
-
/**
* Set the print fan speed for a target extruder
*/
@@ -491,43 +430,46 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED);
if (fan >= FAN_COUNT) return;
- fan_speed[fan] = speed;
+ fans[fan].speed = speed;
#if NUM_REDUNDANT_FANS
if (fan == 0) {
for (uint8_t f = REDUNDANT_PART_COOLING_FAN; f < REDUNDANT_PART_COOLING_FAN + NUM_REDUNDANT_FANS; ++f)
- set_fan_speed(f, speed);
+ fans[f].speed = speed;
}
#endif
TERN_(REPORT_FAN_CHANGE, report_fan_speed(fan));
}
+ #if ENABLED(EXTRA_FAN_SPEED)
+ /**
+ * Handle the M106 P T command:
+ * T1 = Restore fan speed saved on the last T2
+ * T2 = Save the fan speed, then set to the last T<3-255> value
+ * T<3-255> = Set the "extra fan speed"
+ */
+ void Temperature::set_temp_fan_speed(const uint8_t fan, const uint16_t command_or_speed) {
+ fans[fan].set_temp_speed(command_or_speed);
+ switch (command_or_speed) {
+ case 1: set_fan_speed(fan, fans[fan].extra.saved); break;
+ case 2: set_fan_speed(fan, fans[fan].extra.speed); break;
+ default: break;
+ }
+ }
+
+ #endif
+
#if ENABLED(REPORT_FAN_CHANGE)
/**
* Report print fan speed for a target extruder
*/
void Temperature::report_fan_speed(const uint8_t fan) {
if (fan >= FAN_COUNT) return;
- PORT_REDIRECT(SerialMask::All);
- SERIAL_ECHOLNPGM("M106 P", fan, " S", fan_speed[fan]);
+ fans[fan].report_speed(fan);
}
#endif
- #if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
-
- void Temperature::set_fans_paused(const bool p) {
- if (p != fans_paused) {
- fans_paused = p;
- if (p)
- FANS_LOOP(i) { saved_fan_speed[i] = fan_speed[i]; fan_speed[i] = 0; }
- else
- FANS_LOOP(i) fan_speed[i] = saved_fan_speed[i];
- }
- }
-
- #endif
-
#endif // HAS_FAN
#if WATCH_HOTENDS
@@ -657,11 +599,6 @@ volatile bool Temperature::raw_temps_ready = false;
millis_t Temperature::fan_update_ms = 0;
#endif
-#if ENABLED(FAN_SOFT_PWM)
- uint8_t Temperature::soft_pwm_amount_fan[FAN_COUNT],
- Temperature::soft_pwm_count_fan[FAN_COUNT];
-#endif
-
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
celsius_t Temperature::singlenozzle_temp[EXTRUDERS];
#endif
@@ -1065,7 +1002,7 @@ void Temperature::factory_reset() {
temp_hotend[e].soft_pwm_amount = 0;
#if HAS_FAN
set_fan_speed(TERN(SINGLEFAN, 0, e), 0);
- planner.sync_fan_speeds(fan_speed);
+ Fan::sync_speeds();
#endif
do_z_clearance(MPC_TUNING_END_Z, false);
@@ -1219,7 +1156,7 @@ void Temperature::factory_reset() {
#if HAS_FAN
else if (ELAPSED(curr_time_ms, test_end_ms) && !fan0_done) {
set_fan_speed(TERN(SINGLEFAN, 0, e), 255);
- planner.sync_fan_speeds(fan_speed);
+ Fan::sync_speeds();
settle_end_ms = curr_time_ms + settle_time;
test_end_ms = settle_end_ms + test_duration;
fan0_done = true;
@@ -1295,7 +1232,7 @@ void Temperature::factory_reset() {
#if HAS_FAN
zero_fan_speeds();
set_fan_speed(TERN(SINGLEFAN, 0, e), 255);
- planner.sync_fan_speeds(fan_speed);
+ Fan::sync_speeds();
#endif
do_blocking_move_to(xyz_pos_t(MPC_TUNING_POS));
@@ -1309,7 +1246,7 @@ void Temperature::factory_reset() {
#if HAS_FAN
set_fan_speed(TERN(SINGLEFAN, 0, e), 0);
- planner.sync_fan_speeds(fan_speed);
+ Fan::sync_speeds();
#endif
// Heat to 200 degrees
@@ -1370,7 +1307,6 @@ void Temperature::factory_reset() {
mpc.ambient_xfer_coeff_fan0 = tuner.get_power_fan0() / (hotend.target - tuner.get_ambient_temp());
#if HAS_FAN
const float ambient_xfer_coeff_fan255 = tuner.get_power_fan255() / (hotend.target - tuner.get_ambient_temp());
- mpc.applyFanAdjustment(ambient_xfer_coeff_fan255);
#endif
if (tuning_type == AUTO || tuning_type == FORCE_ASYMPTOTIC) {
@@ -1379,9 +1315,10 @@ void Temperature::factory_reset() {
block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.get_sample_interval();
#if ENABLED(MPC_AUTOTUNE_DEBUG)
- SERIAL_ECHOLNPGM("Refining estimates for:");
- SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp);
- SERIAL_ECHOLNPGM("block_responsiveness ", p_float_t(block_responsiveness, 4));
+ SERIAL_ECHOLNPGM(
+ "Refining estimates for: asymp_temp=", asymp_temp,
+ " block_responsiveness=", p_float_t(block_responsiveness, 4)
+ );
#endif
// Update analytic tuning values based on the above
@@ -1434,18 +1371,19 @@ int16_t Temperature::getHeaterPower(const heater_id_t heater_id) {
#define _EFANOVERLAP(I,N) ((I != N) && _FANOVERLAP(I,E##N))
+ #define _INIT_FAN_PWM_PIN(P) do{ if (PWM_PIN(P)) { SET_PWM(P); SET_FAST_PWM_FREQ(P); } else SET_OUTPUT(P); }while(0)
#if EXTRUDER_AUTO_FAN_SPEED != 255
- #define INIT_E_AUTO_FAN_PIN(P) do{ if (PWM_PIN(P)) { SET_PWM(P); SET_FAST_PWM_FREQ(P); } else SET_OUTPUT(P); }while(0)
+ #define INIT_E_AUTO_FAN_PIN(P) _INIT_FAN_PWM_PIN(P)
#else
#define INIT_E_AUTO_FAN_PIN(P) SET_OUTPUT(P)
#endif
#if CHAMBER_AUTO_FAN_SPEED != 255
- #define INIT_CHAMBER_AUTO_FAN_PIN(P) do{ if (PWM_PIN(P)) { SET_PWM(P); SET_FAST_PWM_FREQ(P); } else SET_OUTPUT(P); }while(0)
+ #define INIT_CHAMBER_AUTO_FAN_PIN(P) _INIT_FAN_PWM_PIN(P)
#else
#define INIT_CHAMBER_AUTO_FAN_PIN(P) SET_OUTPUT(P)
#endif
#if COOLER_AUTO_FAN_SPEED != 255
- #define INIT_COOLER_AUTO_FAN_PIN(P) do{ if (PWM_PIN(P)) { SET_PWM(P); SET_FAST_PWM_FREQ(P); } else SET_OUTPUT(P); }while(0)
+ #define INIT_COOLER_AUTO_FAN_PIN(P) _INIT_FAN_PWM_PIN(P)
#else
#define INIT_COOLER_AUTO_FAN_PIN(P) SET_OUTPUT(P)
#endif
@@ -1722,7 +1660,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T
float out = tempinfo.pid.get_pid_output(tempinfo.target, tempinfo.celsius);
#if ENABLED(PID_FAN_SCALING)
- out += tempinfo.pid.get_fan_scale_output(thermalManager.fan_speed[extr]);
+ out += tempinfo.pid.get_fan_scale_output(fans[extr].speed);
#endif
#if ENABLED(PID_EXTRUSION_SCALING)
@@ -1805,7 +1743,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T
float ambient_xfer_coeff = mpc.ambient_xfer_coeff_fan0;
#if ENABLED(MPC_INCLUDE_FAN)
const uint8_t fan_index = TERN(SINGLEFAN, 0, ee);
- const float fan_fraction = TERN0(MPC_FAN_0_ACTIVE_HOTEND, !this_hotend) ? 0.0f : fan_speed[fan_index] * RECIPROCAL(255);
+ const float fan_fraction = TERN0(MPC_FAN_0_ACTIVE_HOTEND, !this_hotend) ? 0.0f : fans[fan_index].speed * RECIPROCAL(255);
ambient_xfer_coeff += fan_fraction * mpc.fan255_adjustment;
#endif
@@ -3110,9 +3048,7 @@ void Temperature::init() {
OUT_WRITE(COOLER_PIN, ENABLED(COOLER_INVERTING));
#endif
- #define _INIT_FAN(N) TERF(HAS_FAN##N, INIT_FAN_PIN)(FAN##N##_PIN);
- REPEAT(FAN_COUNT, _INIT_FAN);
-
+ TERN_(HAS_FAN, Fan::init_pins());
TERF(USE_CONTROLLER_FAN, INIT_FAN_PIN)(CONTROLLER_FAN_PIN);
TERN_(HAS_MAXTC_SW_SPI, max_tc_spi.init());
@@ -3396,7 +3332,7 @@ void Temperature::init() {
if (adaptive_fan_slowing && heater_id >= 0) {
const int_fast8_t fan_index = _MIN(heater_id, FAN_COUNT - 1);
uint8_t scale;
- if (fan_speed[fan_index] == 0 || rdiff <= hysteresis_degc * 0.25f)
+ if (fans[fan_index].speed == 0 || rdiff <= hysteresis_degc * 0.25f)
scale = 128;
else if (rdiff <= hysteresis_degc * 0.3335f)
scale = 96;
@@ -3408,12 +3344,12 @@ void Temperature::init() {
scale = 0;
if (TERN0(REPORT_ADAPTIVE_FAN_SLOWING, DEBUGGING(INFO))) {
- const uint8_t fss7 = fan_speed_scaler[fan_index] & 0x80;
+ const uint8_t fss7 = fans[fan_index].speed_scaler & 0x80;
if (fss7 ^ (scale & 0x80))
serial_ternary(F("Adaptive Fan Slowing "), fss7, nullptr, F("de"), F("activated.\n"));
}
- fan_speed_scaler[fan_index] = scale;
+ fans[fan_index].speed_scaler = scale;
}
#endif // ADAPTIVE_FAN_SLOWING
@@ -3546,8 +3482,8 @@ void Temperature::disable_all_heaters() {
void Temperature::singlenozzle_change(const uint8_t old_tool, const uint8_t new_tool) {
#if ENABLED(SINGLENOZZLE_STANDBY_FAN)
- singlenozzle_fan_speed[old_tool] = fan_speed[0];
- fan_speed[0] = singlenozzle_fan_speed[new_tool];
+ singlenozzle_fan_speed[old_tool] = fans[0].speed;
+ fans[0].speed = singlenozzle_fan_speed[new_tool];
#endif
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
singlenozzle_temp[old_tool] = temp_hotend[0].target;
@@ -4027,12 +3963,6 @@ void Temperature::isr() {
static SoftPWM soft_pwm_controllerfan;
#endif
- #define WRITE_FAN(n, v) WRITE(FAN##n##_PIN, (v) ^ ENABLED(FAN_INVERTING))
-
- #if ENABLED(FAN_SOFT_PWM)
- #define _FAN_LOW(N) if (TERN0(HAS_FAN##N, soft_pwm_count_fan[N] <= pwm_count_tmp)) { TERF(HAS_FAN##N, WRITE_FAN)(N, LOW); };
- #endif
-
#if DISABLED(SLOW_PWM_HEATERS)
#if ANY(HAS_HOTEND, HAS_HEATED_BED, HAS_HEATED_CHAMBER, HAS_COOLER, FAN_SOFT_PWM)
@@ -4050,7 +3980,7 @@ void Temperature::isr() {
pwm_count_tmp -= 127;
#if HAS_HOTEND
- #define _PWM_MOD_E(N) _PWM_MOD(N,soft_pwm_hotend[N],temp_hotend[N]);
+ #define _PWM_MOD_E(N) _PWM_MOD(N, soft_pwm_hotend[N], temp_hotend[N]);
REPEAT(HOTENDS, _PWM_MOD_E);
#endif
@@ -4064,18 +3994,11 @@ void Temperature::isr() {
TERF(HAS_COOLER, _PWM_MOD)(COOLER, soft_pwm_cooler, temp_cooler);
#if ENABLED(FAN_SOFT_PWM)
-
#if ENABLED(USE_CONTROLLER_FAN)
WRITE(CONTROLLER_FAN_PIN, soft_pwm_controllerfan.add(pwm_mask, controllerFan.soft_pwm_speed));
#endif
-
- #define __FAN_PWM(N) do{ \
- uint8_t &spcf = soft_pwm_count_fan[N]; \
- spcf = (spcf & pwm_mask) + (soft_pwm_amount_fan[N] >> 1); \
- WRITE_FAN(N, spcf > pwm_mask ? HIGH : LOW); \
- }while(0)
- #define _FAN_PWM(N) TERF(HAS_FAN##N, __FAN_PWM)(N);
- REPEAT(FAN_COUNT, _FAN_PWM);
+ #define _SOFT_PWM_ON(N) TERN_(HAS_FAN##N, fans[N].soft_pwm_on());
+ REPEAT(FAN_COUNT, _SOFT_PWM_ON)
#endif
}
else {
@@ -4090,7 +4013,8 @@ void Temperature::isr() {
TERF(HAS_COOLER, _PWM_LOW)(COOLER, soft_pwm_cooler);
#if ENABLED(FAN_SOFT_PWM)
- REPEAT(FAN_COUNT, _FAN_LOW);
+ #define _SOFT_PWM_2(N) fans[N].soft_pwm_off(pwm_count_tmp);
+ REPEAT(FAN_COUNT, _SOFT_PWM_2)
#if ENABLED(USE_CONTROLLER_FAN)
if (soft_pwm_controllerfan.count <= pwm_count_tmp) WRITE(CONTROLLER_FAN_PIN, LOW);
#endif
@@ -4145,15 +4069,10 @@ void Temperature::isr() {
#if ENABLED(FAN_SOFT_PWM)
if (pwm_count_tmp >= 127) {
pwm_count_tmp = 0;
- #define __PWM_FAN(N) do{ \
- soft_pwm_count_fan[N] = soft_pwm_amount_fan[N] >> 1; \
- WRITE_FAN(N, soft_pwm_count_fan[N] > 0 ? HIGH : LOW); \
- }while(0)
- #define _PWM_FAN(N) TERF(HAS_FAN##N, __PWM_FAN)(N);
- REPEAT(FAN_COUNT, _PWM_FAN);
+ FANS_LOOP(f) fans[f].slow_soft_pwm();
}
- REPEAT(FAN_COUNT, _FAN_LOW);
- #endif // FAN_SOFT_PWM
+ FANS_LOOP(f) fans[f].soft_pwm_off(pwm_count_tmp);
+ #endif
// SOFT_PWM_SCALE to frequency:
//
diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h
index f2ef4d0f6c..ee3f1b78bb 100644
--- a/Marlin/src/module/temperature.h
+++ b/Marlin/src/module/temperature.h
@@ -25,10 +25,11 @@
* temperature.h - temperature controller
*/
-#include "thermistor/thermistors.h"
-
#include "../inc/MarlinConfig.h"
+#include "thermistor/thermistors.h"
+#include "fans.h"
+
#if ENABLED(AUTO_POWER_CONTROL)
#include "../feature/power.h"
#endif
@@ -680,15 +681,6 @@ class Temperature {
static uint8_t coolerfan_speed;
#endif
- #if ENABLED(FAN_SOFT_PWM)
- static uint8_t soft_pwm_amount_fan[FAN_COUNT],
- soft_pwm_count_fan[FAN_COUNT];
- #endif
-
- #if ALL(FAN_SOFT_PWM, USE_CONTROLLER_FAN)
- static uint8_t soft_pwm_controllerfan_speed;
- #endif
-
#if ALL(HAS_MARLINUI_MENU, PREVENT_COLD_EXTRUSION) && E_MANUAL > 0
static bool allow_cold_extrude_override;
static void set_menu_cold_override(const bool allow) { allow_cold_extrude_override = allow; }
@@ -916,48 +908,13 @@ class Temperature {
#endif
#if HAS_FAN
-
- static uint8_t fan_speed[FAN_COUNT];
- #define FANS_LOOP(I) for (uint8_t I = 0; I < FAN_COUNT; ++I)
-
static void set_fan_speed(const uint8_t fan, const uint16_t speed);
-
#if ENABLED(REPORT_FAN_CHANGE)
static void report_fan_speed(const uint8_t fan);
#endif
-
- #if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
- static bool fans_paused;
- static uint8_t saved_fan_speed[FAN_COUNT];
- #endif
-
- #if ENABLED(ADAPTIVE_FAN_SLOWING)
- static uint8_t fan_speed_scaler[FAN_COUNT];
- #endif
-
- static uint8_t scaledFanSpeed(const uint8_t fan, const uint8_t fs) {
- UNUSED(fan); // Potentially unused!
- return (fs * uint16_t(TERN(ADAPTIVE_FAN_SLOWING, fan_speed_scaler[fan], 128))) >> 7;
- }
-
- static uint8_t scaledFanSpeed(const uint8_t fan) {
- return scaledFanSpeed(fan, fan_speed[fan]);
- }
-
- static constexpr inline uint8_t pwmToPercent(const uint8_t speed) { return ui8_to_percent(speed); }
- static uint8_t fanSpeedPercent(const uint8_t fan) { return ui8_to_percent(fan_speed[fan]); }
- static uint8_t scaledFanSpeedPercent(const uint8_t fan) { return ui8_to_percent(scaledFanSpeed(fan)); }
-
#if ENABLED(EXTRA_FAN_SPEED)
- typedef struct { uint8_t saved, speed; } extra_fan_t;
- static extra_fan_t extra_fan_speed[FAN_COUNT];
static void set_temp_fan_speed(const uint8_t fan, const uint16_t command_or_speed);
#endif
-
- #if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
- void set_fans_paused(const bool p);
- #endif
-
#endif // HAS_FAN
static void zero_fan_speeds() {
diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp
index e13d75d5c4..5111a9f616 100644
--- a/Marlin/src/module/tool_change.cpp
+++ b/Marlin/src/module/tool_change.cpp
@@ -912,9 +912,9 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0.
// Cool down with fan
inline void filament_swap_cooling() {
#if HAS_FAN && TOOLCHANGE_FS_FAN >= 0
- thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed;
+ fans[TOOLCHANGE_FS_FAN].speed = toolchange_settings.fan_speed;
gcode.dwell(SEC_TO_MS(toolchange_settings.fan_time));
- thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = FAN_OFF_PWM;
+ fans[TOOLCHANGE_FS_FAN].speed = FAN_OFF_PWM;
#endif
}
@@ -1036,7 +1036,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0.
#if HAS_FAN && TOOLCHANGE_FS_FAN >= 0
// Store and stop fan. Restored on any exit.
- REMEMBER(fan, thermalManager.fan_speed[TOOLCHANGE_FS_FAN], 0);
+ REMEMBER(fan, fans[TOOLCHANGE_FS_FAN].speed, 0);
#endif
// Z raise
@@ -1194,7 +1194,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
#if ALL(TOOLCHANGE_FILAMENT_SWAP, HAS_FAN) && TOOLCHANGE_FS_FAN >= 0
// Store and stop fan. Restored on any exit.
- REMEMBER(fan, thermalManager.fan_speed[TOOLCHANGE_FS_FAN], 0);
+ REMEMBER(fan, fans[TOOLCHANGE_FS_FAN].speed, 0);
#endif
// Z raise before retraction
diff --git a/buildroot/tests/mega2560 b/buildroot/tests/mega2560
index f90e2074ab..d1714006e3 100755
--- a/buildroot/tests/mega2560
+++ b/buildroot/tests/mega2560
@@ -69,7 +69,7 @@ opt_enable VIKI2 BOOT_MARLIN_LOGO_ANIMATED SDSUPPORT AUTO_REPORT_SD_STATUS \
EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL AUTO_REPORT_POSITION \
NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \
DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \
- FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING FIL_RUNOUT3_PULLUP
+ FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE ADVANCED_PAUSE_FANS_PAUSE Z_SAFE_HOMING FIL_RUNOUT3_PULLUP
exec_test $1 $2 "Azteeg X3 Pro | EXTRUDERS 4 | VIKI2 | Servo Probe | Multiple runout sensors (x4)" "$3"
#
diff --git a/ini/features.ini b/ini/features.ini
index 03a9bdbba8..0cd2487821 100644
--- a/ini/features.ini
+++ b/ini/features.ini
@@ -359,7 +359,7 @@ HAS_MEDIA_SUBCALLS = build_src_filter=+ +
HAS_EXTRUDERS = build_src_filter=+ +
HAS_HOTEND = build_src_filter=+
-HAS_FAN = build_src_filter=+
+HAS_FAN = build_src_filter=+ +
HAS_HEATED_BED = build_src_filter=+
HAS_HEATED_CHAMBER = build_src_filter=+
HAS_COOLER = build_src_filter=+