Fan tachometer support (#23086)

Co-authored-by: Scott Lahteine <github@thinkyhead.com>
This commit is contained in:
Giuliano Zaro 2021-11-23 21:01:53 +01:00 committed by GitHub
parent 430a4aec34
commit 7110d11c9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 592 additions and 44 deletions

View file

@ -603,6 +603,40 @@
#define COOLER_AUTO_FAN_TEMPERATURE 18
#define COOLER_AUTO_FAN_SPEED 255
/**
* Hotend Cooling Fans tachometers
*
* Define one or more tachometer pins to enable fan speed
* monitoring, and reporting of fan speeds with M123.
*
* NOTE: Only works with fans up to 7000 RPM.
*/
//#define FOURWIRES_FANS // Needed with AUTO_FAN when 4-wire PWM fans are installed
//#define E0_FAN_TACHO_PIN -1
//#define E0_FAN_TACHO_PULLUP
//#define E0_FAN_TACHO_PULLDOWN
//#define E1_FAN_TACHO_PIN -1
//#define E1_FAN_TACHO_PULLUP
//#define E1_FAN_TACHO_PULLDOWN
//#define E2_FAN_TACHO_PIN -1
//#define E2_FAN_TACHO_PULLUP
//#define E2_FAN_TACHO_PULLDOWN
//#define E3_FAN_TACHO_PIN -1
//#define E3_FAN_TACHO_PULLUP
//#define E3_FAN_TACHO_PULLDOWN
//#define E4_FAN_TACHO_PIN -1
//#define E4_FAN_TACHO_PULLUP
//#define E4_FAN_TACHO_PULLDOWN
//#define E5_FAN_TACHO_PIN -1
//#define E5_FAN_TACHO_PULLUP
//#define E5_FAN_TACHO_PULLDOWN
//#define E6_FAN_TACHO_PIN -1
//#define E6_FAN_TACHO_PULLUP
//#define E6_FAN_TACHO_PULLDOWN
//#define E7_FAN_TACHO_PIN -1
//#define E7_FAN_TACHO_PULLUP
//#define E7_FAN_TACHO_PULLDOWN
/**
* Part-Cooling Fan Multiplexer
*
@ -3607,6 +3641,12 @@
*/
//#define CNC_COORDINATE_SYSTEMS
/**
* Auto-report fan speed with M123 S<seconds>
* Requires fans with tachometer pins
*/
//#define AUTO_REPORT_FANS
/**
* Auto-report temperatures with M155 S<seconds>
*/

View file

@ -212,6 +212,10 @@
#include "module/tool_change.h"
#if HAS_FANCHECK
#include "feature/fancheck.h"
#endif
#if ENABLED(USE_CONTROLLER_FAN)
#include "feature/controllerfan.h"
#endif
@ -829,6 +833,7 @@ void idle(bool no_stepper_sleep/*=false*/) {
#if HAS_AUTO_REPORTING
if (!gcode.autoreport_paused) {
TERN_(AUTO_REPORT_TEMPERATURES, thermalManager.auto_reporter.tick());
TERN_(AUTO_REPORT_FANS, fan_check.auto_reporter.tick());
TERN_(AUTO_REPORT_SD_STATUS, card.auto_reporter.tick());
TERN_(AUTO_REPORT_POSITION, position_auto_reporter.tick());
TERN_(BUFFER_MONITORING, queue.auto_report_buffer_statistics());
@ -1275,6 +1280,8 @@ void setup() {
SETUP_RUN(controllerFan.setup());
#endif
TERN_(HAS_FANCHECK, fan_check.init());
// UI must be initialized before EEPROM
// (because EEPROM code calls the UI).

View file

@ -140,6 +140,7 @@
#define STR_RESEND "Resend: "
#define STR_UNKNOWN_COMMAND "Unknown command: \""
#define STR_ACTIVE_EXTRUDER "Active Extruder: "
#define STR_ERR_FANSPEED "Fan speed E"
#define STR_PROBE_OFFSET "Probe Offset"
#define STR_SKEW_MIN "min_skew_factor: "

View file

@ -0,0 +1,207 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 <https://www.gnu.org/licenses/>.
*
*/
/**
* fancheck.cpp - fan tachometer check
*/
#include "../inc/MarlinConfig.h"
#if HAS_FANCHECK
#include "fancheck.h"
#include "../module/temperature.h"
#if HAS_AUTO_FAN && EXTRUDER_AUTO_FAN_SPEED != 255 && DISABLED(FOURWIRES_FANS)
bool FanCheck::measuring = false;
#endif
bool FanCheck::tacho_state[TACHO_COUNT];
uint16_t FanCheck::edge_counter[TACHO_COUNT];
uint8_t FanCheck::rps[TACHO_COUNT];
FanCheck::TachoError FanCheck::error = FanCheck::TachoError::NONE;
bool FanCheck::enabled;
void FanCheck::init() {
#define _TACHINIT(N) TERN(E##N##_FAN_TACHO_PULLUP, SET_INPUT_PULLUP, TERN(E##N##_FAN_TACHO_PULLDOWN, SET_INPUT_PULLDOWN, SET_INPUT))(E##N##_FAN_TACHO_PIN)
#if HAS_E0_FAN_TACHO
_TACHINIT(0);
#endif
#if HAS_E1_FAN_TACHO
_TACHINIT(1);
#endif
#if HAS_E2_FAN_TACHO
_TACHINIT(2);
#endif
#if HAS_E3_FAN_TACHO
_TACHINIT(3);
#endif
#if HAS_E4_FAN_TACHO
_TACHINIT(4);
#endif
#if HAS_E5_FAN_TACHO
_TACHINIT(5);
#endif
#if HAS_E6_FAN_TACHO
_TACHINIT(6);
#endif
#if HAS_E7_FAN_TACHO
_TACHINIT(7);
#endif
}
void FanCheck::update_tachometers() {
bool status;
#define _TACHO_CASE(N) case N: status = READ(E##N##_FAN_TACHO_PIN); break;
LOOP_L_N(f, TACHO_COUNT) {
switch (f) {
#if HAS_E0_FAN_TACHO
_TACHO_CASE(0)
#endif
#if HAS_E1_FAN_TACHO
_TACHO_CASE(1)
#endif
#if HAS_E2_FAN_TACHO
_TACHO_CASE(2)
#endif
#if HAS_E3_FAN_TACHO
_TACHO_CASE(3)
#endif
#if HAS_E4_FAN_TACHO
_TACHO_CASE(4)
#endif
#if HAS_E5_FAN_TACHO
_TACHO_CASE(5)
#endif
#if HAS_E6_FAN_TACHO
_TACHO_CASE(6)
#endif
#if HAS_E7_FAN_TACHO
_TACHO_CASE(7)
#endif
default: continue;
}
if (status != tacho_state[f]) {
if (measuring) ++edge_counter[f];
tacho_state[f] = status;
}
}
}
void FanCheck::compute_speed(uint16_t elapsedTime) {
static uint8_t errors_count[TACHO_COUNT];
static uint8_t fan_reported_errors_msk = 0;
uint8_t fan_error_msk = 0;
LOOP_L_N(f, TACHO_COUNT) {
switch (f) {
TERN_(HAS_E0_FAN_TACHO, case 0:)
TERN_(HAS_E1_FAN_TACHO, case 1:)
TERN_(HAS_E2_FAN_TACHO, case 2:)
TERN_(HAS_E3_FAN_TACHO, case 3:)
TERN_(HAS_E4_FAN_TACHO, case 4:)
TERN_(HAS_E5_FAN_TACHO, case 5:)
TERN_(HAS_E6_FAN_TACHO, case 6:)
TERN_(HAS_E7_FAN_TACHO, case 7:)
// Compute fan speed
rps[f] = edge_counter[f] * float(250) / elapsedTime;
edge_counter[f] = 0;
// Check fan speed
constexpr int8_t max_extruder_fan_errors = TERN(HAS_PWMFANCHECK, 10000, 5000) / Temperature::fan_update_interval_ms;
if (rps[f] >= 20 || TERN0(HAS_AUTO_FAN, thermalManager.autofan_speed[f] == 0))
errors_count[f] = 0;
else if (errors_count[f] < max_extruder_fan_errors)
++errors_count[f];
else if (enabled)
SBI(fan_error_msk, f);
break;
}
}
// Drop the error when all fans are ok
if (!fan_error_msk && error == TachoError::REPORTED) error = TachoError::FIXED;
if (error == TachoError::FIXED && !printJobOngoing() && !printingIsPaused()) {
error = TachoError::NONE; // if the issue has been fixed while the printer is idle, reenable immediately
ui.reset_alert_level();
}
if (fan_error_msk & ~fan_reported_errors_msk) {
// Handle new faults only
LOOP_L_N(f, TACHO_COUNT) if (TEST(fan_error_msk, f)) report_speed_error(f);
}
fan_reported_errors_msk = fan_error_msk;
}
void FanCheck::report_speed_error(uint8_t fan) {
if (printJobOngoing()) {
if (error == TachoError::NONE) {
if (thermalManager.degTargetHotend(fan) != 0) {
kill(GET_TEXT_F(MSG_FAN_SPEED_FAULT));
error = TachoError::REPORTED;
}
else
error = TachoError::DETECTED; // Plans error for next processed command
}
}
else if (!printingIsPaused()) {
thermalManager.setTargetHotend(0, fan); // Always disable heating
if (error == TachoError::NONE) error = TachoError::REPORTED;
}
SERIAL_ERROR_MSG(STR_ERR_FANSPEED, fan);
LCD_ALERTMESSAGE(MSG_FAN_SPEED_FAULT);
}
void FanCheck::print_fan_states() {
LOOP_L_N(s, 2) {
LOOP_L_N(f, TACHO_COUNT) {
switch (f) {
TERN_(HAS_E0_FAN_TACHO, case 0:)
TERN_(HAS_E1_FAN_TACHO, case 1:)
TERN_(HAS_E2_FAN_TACHO, case 2:)
TERN_(HAS_E3_FAN_TACHO, case 3:)
TERN_(HAS_E4_FAN_TACHO, case 4:)
TERN_(HAS_E5_FAN_TACHO, case 5:)
TERN_(HAS_E6_FAN_TACHO, case 6:)
TERN_(HAS_E7_FAN_TACHO, case 7:)
SERIAL_ECHOPGM("E", f);
if (s == 0)
SERIAL_ECHOPGM(":", 60 * rps[f], " RPM ");
else
SERIAL_ECHOPGM("@:", TERN(HAS_AUTO_FAN, thermalManager.autofan_speed[f], 255), " ");
break;
}
}
}
SERIAL_EOL();
}
#if ENABLED(AUTO_REPORT_FANS)
AutoReporter<FanCheck::AutoReportFan> FanCheck::auto_reporter;
void FanCheck::AutoReportFan::report() { print_fan_states(); }
#endif
#endif // HAS_FANCHECK

View file

@ -0,0 +1,89 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../inc/MarlinConfig.h"
#if HAS_FANCHECK
#include "../MarlinCore.h"
#include "../lcd/marlinui.h"
#if ENABLED(AUTO_REPORT_FANS)
#include "../libs/autoreport.h"
#endif
#if ENABLED(PARK_HEAD_ON_PAUSE)
#include "../gcode/queue.h"
#endif
/**
* fancheck.h
*/
#define TACHO_COUNT TERN(HAS_E7_FAN_TACHO, 8, TERN(HAS_E6_FAN_TACHO, 7, TERN(HAS_E5_FAN_TACHO, 6, TERN(HAS_E4_FAN_TACHO, 5, TERN(HAS_E3_FAN_TACHO, 4, TERN(HAS_E2_FAN_TACHO, 3, TERN(HAS_E1_FAN_TACHO, 2, 1)))))))
class FanCheck {
private:
enum class TachoError : uint8_t { NONE, DETECTED, REPORTED, FIXED };
#if HAS_PWMFANCHECK
static bool measuring; // For future use (3 wires PWM controlled fans)
#else
static constexpr bool measuring = true;
#endif
static bool tacho_state[TACHO_COUNT];
static uint16_t edge_counter[TACHO_COUNT];
static uint8_t rps[TACHO_COUNT];
static TachoError error;
static inline void report_speed_error(uint8_t fan);
public:
static bool enabled;
static void init();
static void update_tachometers();
static void compute_speed(uint16_t elapsedTime);
static void print_fan_states();
#if HAS_PWMFANCHECK
static inline void toggle_measuring() { measuring = !measuring; }
static inline bool is_measuring() { return measuring; }
#endif
static inline void check_deferred_error() {
if (error == TachoError::DETECTED) {
error = TachoError::REPORTED;
TERN(PARK_HEAD_ON_PAUSE, queue.inject(F("M125")), kill(GET_TEXT_F(MSG_FAN_SPEED_FAULT)));
}
}
#if ENABLED(AUTO_REPORT_FANS)
struct AutoReportFan { static void report(); };
static AutoReporter<AutoReportFan> auto_reporter;
#endif
};
extern FanCheck fan_check;
#endif // HAS_FANCHECK

View file

@ -22,7 +22,7 @@
#include "../gcode.h"
#include "../../lcd/marlinui.h" // for lcd_reset_alert_level
#include "../../lcd/marlinui.h" // for ui.reset_alert_level
#include "../../MarlinCore.h" // for marlin_state
#include "../queue.h" // for flush_and_request_resend

View file

@ -65,6 +65,10 @@ GcodeSuite gcode;
#include "../feature/password/password.h"
#endif
#if HAS_FANCHECK
#include "../feature/fancheck.h"
#endif
#include "../MarlinCore.h" // for idle, kill
// Inactivity shutdown
@ -296,6 +300,8 @@ void GcodeSuite::dwell(millis_t time) {
* Process the parsed command and dispatch it to its handler
*/
void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
TERN_(HAS_FANCHECK, fan_check.check_deferred_error());
KEEPALIVE_STATE(IN_HANDLER);
/**
@ -577,6 +583,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 113: M113(); break; // M113: Set Host Keepalive interval
#endif
#if HAS_FANCHECK
case 123: M123(); break; // M123: Report fan states or set fans auto-report interval
#endif
#if HAS_HEATED_BED
case 140: M140(); break; // M140: Set bed temperature
case 190: M190(); break; // M190: Wait for bed temperature to reach target

View file

@ -156,6 +156,7 @@
* M121 - Disable endstops detection.
*
* M122 - Debug stepper (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660 or L6470)
* M123 - Report fan tachometers. (Requires En_FAN_TACHO_PIN) Optionally set auto-report interval. (Requires AUTO_REPORT_FANS)
* M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE)
*
* M126 - Solenoid Air Valve Open. (Requires BARICUDA)
@ -736,6 +737,10 @@ private:
static void M120();
static void M121();
#if HAS_FANCHECK
static void M123();
#endif
#if ENABLED(PARK_HEAD_ON_PAUSE)
static void M125();
#endif

View file

@ -0,0 +1,48 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 <https://www.gnu.org/licenses/>.
*
*/
#include "../../inc/MarlinConfig.h"
#if HAS_FANCHECK
#include "../gcode.h"
#include "../../feature/fancheck.h"
/**
* M123: Report fan states -or- set interval for auto-report
*
* S<seconds> : Set auto-report interval
*/
void GcodeSuite::M123() {
#if ENABLED(AUTO_REPORT_FANS)
if (parser.seenval('S')) {
fan_check.auto_reporter.set_interval(parser.value_byte());
return;
}
#endif
fan_check.print_fan_states();
}
#endif // HAS_FANCHECK

View file

@ -2510,10 +2510,42 @@
#define AUTO_CHAMBER_IS_E 1
#endif
// Fans check
#if HAS_HOTEND && PIN_EXISTS(E0_FAN_TACHO)
#define HAS_E0_FAN_TACHO 1
#endif
#if HOTENDS > 1 && PIN_EXISTS(E1_FAN_TACHO)
#define HAS_E1_FAN_TACHO 1
#endif
#if HOTENDS > 2 && PIN_EXISTS(E2_FAN_TACHO)
#define HAS_E2_FAN_TACHO 1
#endif
#if HOTENDS > 3 && PIN_EXISTS(E3_FAN_TACHO)
#define HAS_E3_FAN_TACHO 1
#endif
#if HOTENDS > 4 && PIN_EXISTS(E4_FAN_TACHO)
#define HAS_E4_FAN_TACHO 1
#endif
#if HOTENDS > 5 && PIN_EXISTS(E5_FAN_TACHO)
#define HAS_E5_FAN_TACHO 1
#endif
#if HOTENDS > 6 && PIN_EXISTS(E6_FAN_TACHO)
#define HAS_E6_FAN_TACHO 1
#endif
#if HOTENDS > 7 && PIN_EXISTS(E7_FAN_TACHO)
#define HAS_E7_FAN_TACHO 1
#endif
#if ANY(HAS_E0_FAN_TACHO, HAS_E1_FAN_TACHO, HAS_E2_FAN_TACHO, HAS_E3_FAN_TACHO, HAS_E4_FAN_TACHO, HAS_E5_FAN_TACHO, HAS_E6_FAN_TACHO, HAS_E7_FAN_TACHO)
#define HAS_FANCHECK 1
#if HAS_AUTO_FAN && EXTRUDER_AUTO_FAN_SPEED != 255 && DISABLED(FOURWIRES_FANS)
#define HAS_PWMFANCHECK 1
#endif
#endif
#if !HAS_TEMP_SENSOR
#undef AUTO_REPORT_TEMPERATURES
#endif
#if ANY(AUTO_REPORT_TEMPERATURES, AUTO_REPORT_SD_STATUS, AUTO_REPORT_POSITION)
#if ANY(AUTO_REPORT_TEMPERATURES, AUTO_REPORT_SD_STATUS, AUTO_REPORT_POSITION, AUTO_REPORT_FANS)
#define HAS_AUTO_REPORTING 1
#endif

View file

@ -2583,6 +2583,31 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
#endif
#endif
/**
* Fan check
*/
#if HAS_FANCHECK
#if BOTH(E0_FAN_TACHO_PULLUP, E0_FAN_TACHO_PULLDOWN)
#error "Enable only one of E0_FAN_TACHO_PULLUP or E0_FAN_TACHO_PULLDOWN."
#elif BOTH(E1_FAN_TACHO_PULLUP, E1_FAN_TACHO_PULLDOWN)
#error "Enable only one of E1_FAN_TACHO_PULLUP or E1_FAN_TACHO_PULLDOWN."
#elif BOTH(E2_FAN_TACHO_PULLUP, E2_FAN_TACHO_PULLDOWN)
#error "Enable only one of E2_FAN_TACHO_PULLUP or E2_FAN_TACHO_PULLDOWN."
#elif BOTH(E3_FAN_TACHO_PULLUP, E3_FAN_TACHO_PULLDOWN)
#error "Enable only one of E3_FAN_TACHO_PULLUP or E3_FAN_TACHO_PULLDOWN."
#elif BOTH(E4_FAN_TACHO_PULLUP, E4_FAN_TACHO_PULLDOWN)
#error "Enable only one of E4_FAN_TACHO_PULLUP or E4_FAN_TACHO_PULLDOWN."
#elif BOTH(E5_FAN_TACHO_PULLUP, E5_FAN_TACHO_PULLDOWN)
#error "Enable only one of E5_FAN_TACHO_PULLUP or E5_FAN_TACHO_PULLDOWN."
#elif BOTH(E6_FAN_TACHO_PULLUP, E6_FAN_TACHO_PULLDOWN)
#error "Enable only one of E6_FAN_TACHO_PULLUP or E6_FAN_TACHO_PULLDOWN."
#elif BOTH(E7_FAN_TACHO_PULLUP, E7_FAN_TACHO_PULLDOWN)
#error "Enable only one of E7_FAN_TACHO_PULLUP or E7_FAN_TACHO_PULLDOWN."
#endif
#elif ENABLED(AUTO_REPORT_FANS)
#error "AUTO_REPORT_FANS requires one or more fans with a tachometer pin."
#endif
/**
* Make sure only one EEPROM type is enabled
*/

View file

@ -570,6 +570,7 @@ namespace Language_en {
LSTR MSG_INFO_RUNAWAY_OFF = _UxGT("Runaway Watch: OFF");
LSTR MSG_INFO_RUNAWAY_ON = _UxGT("Runaway Watch: ON");
LSTR MSG_HOTEND_IDLE_TIMEOUT = _UxGT("Hotend Idle Timeout");
LSTR MSG_FAN_SPEED_FAULT = _UxGT("Fan speed fault");
LSTR MSG_CASE_LIGHT = _UxGT("Case Light");
LSTR MSG_CASE_LIGHT_BRIGHTNESS = _UxGT("Light Brightness");
@ -613,6 +614,7 @@ namespace Language_en {
LSTR MSG_RUNOUT_SENSOR = _UxGT("Runout Sensor");
LSTR MSG_RUNOUT_DISTANCE_MM = _UxGT("Runout Dist mm");
LSTR MSG_RUNOUT_ENABLE = _UxGT("Enable Runout");
LSTR MSG_FANCHECK = _UxGT("Fan Tacho Check");
LSTR MSG_KILL_HOMING_FAILED = _UxGT("Homing Failed");
LSTR MSG_LCD_PROBING_FAILED = _UxGT("Probing Failed");

View file

@ -556,6 +556,7 @@ namespace Language_it {
LSTR MSG_INFO_RUNAWAY_OFF = _UxGT("Controllo fuga: OFF");
LSTR MSG_INFO_RUNAWAY_ON = _UxGT("Controllo fuga: ON");
LSTR MSG_HOTEND_IDLE_TIMEOUT = _UxGT("Timeout inatt.ugello");
LSTR MSG_FAN_SPEED_FAULT = _UxGT("Err.vel.della ventola");
LSTR MSG_CASE_LIGHT = _UxGT("Luci Case");
LSTR MSG_CASE_LIGHT_BRIGHTNESS = _UxGT("Luminosità Luci");
@ -597,6 +598,8 @@ namespace Language_it {
LSTR MSG_FILAMENT_CHANGE_NOZZLE = _UxGT(" Ugello: ");
LSTR MSG_RUNOUT_SENSOR = _UxGT("Sens.filo termin."); // Max 17 characters
LSTR MSG_RUNOUT_DISTANCE_MM = _UxGT("Dist mm filo term.");
LSTR MSG_RUNOUT_ENABLE = _UxGT("Abil.filo termin.");
LSTR MSG_FANCHECK = _UxGT("Verif.tacho vent."); // Max 17 characters
LSTR MSG_KILL_HOMING_FAILED = _UxGT("Home fallito");
LSTR MSG_LCD_PROBING_FAILED = _UxGT("Sondaggio fallito");

View file

@ -1566,10 +1566,6 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;
TERN_(HAS_LCD_MENU, return_to_status());
}
#if ANY(PARK_HEAD_ON_PAUSE, SDSUPPORT)
#include "../gcode/queue.h"
#endif
void MarlinUI::pause_print() {
#if HAS_LCD_MENU
synchronize(GET_TEXT(MSG_PAUSING));

View file

@ -34,6 +34,10 @@
#include "../../feature/runout.h"
#endif
#if HAS_FANCHECK
#include "../../feature/fancheck.h"
#endif
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../../feature/powerloss.h"
#endif
@ -537,6 +541,10 @@ void menu_configuration() {
EDIT_ITEM(bool, MSG_RUNOUT_SENSOR, &runout.enabled, runout.reset);
#endif
#if HAS_FANCHECK
EDIT_ITEM(bool, MSG_FANCHECK, &fan_check.enabled);
#endif
#if ENABLED(POWER_LOSS_RECOVERY)
EDIT_ITEM(bool, MSG_OUTAGE_RECOVERY, &recovery.enabled, recovery.changed);
#endif

View file

@ -154,6 +154,10 @@
#include "../libs/buzzer.h"
#endif
#if HAS_FANCHECK
#include "../feature/fancheck.h"
#endif
#if ENABLED(DGUS_LCD_UI_MKS)
#include "../lcd/extui/dgus/DGUSScreenHandler.h"
#include "../lcd/extui/dgus/DGUSDisplayDef.h"
@ -491,6 +495,13 @@ typedef struct SettingsDataStruct {
bool buzzer_enabled;
#endif
//
// Fan tachometer check
//
#if HAS_FANCHECK
bool fan_check_enabled;
#endif
//
// MKS UI controller
//
@ -1433,6 +1444,13 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(ui.buzzer_enabled);
#endif
//
// Fan tachometer check
//
#if HAS_FANCHECK
EEPROM_WRITE(fan_check.enabled);
#endif
//
// MKS UI controller
//
@ -2339,6 +2357,14 @@ void MarlinSettings::postprocess() {
EEPROM_READ(ui.buzzer_enabled);
#endif
//
// Fan tachometer check
//
#if HAS_FANCHECK
_FIELD_TEST(fan_check_enabled);
EEPROM_READ(fan_check.enabled);
#endif
//
// MKS UI controller
//
@ -3036,6 +3062,11 @@ void MarlinSettings::reset() {
#endif
#endif
//
// Fan tachometer check
//
TERN_(HAS_FANCHECK, fan_check.enabled = true);
//
// MKS UI controller
//

View file

@ -294,7 +294,7 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED);
redundant_info_t Temperature::temp_redundant;
#endif
#if ENABLED(AUTO_POWER_E_FANS)
#if EITHER(AUTO_POWER_E_FANS, HAS_FANCHECK)
uint8_t Temperature::autofan_speed[HOTENDS]; // = { 0 }
#endif
@ -526,8 +526,9 @@ volatile bool Temperature::raw_temps_ready = false;
millis_t Temperature::preheat_end_time[HOTENDS] = { 0 };
#endif
#if HAS_AUTO_FAN
millis_t Temperature::next_auto_fan_check_ms = 0;
#if HAS_FAN_LOGIC
constexpr millis_t Temperature::fan_update_interval_ms;
millis_t Temperature::fan_update_ms = 0;
#endif
#if ENABLED(FAN_SOFT_PWM)
@ -614,7 +615,7 @@ volatile bool Temperature::raw_temps_ready = false;
bool heated = false;
#endif
TERN_(HAS_AUTO_FAN, next_auto_fan_check_ms = next_temp_ms + 2500UL);
TERN_(HAS_FAN_LOGIC, fan_update_ms = next_temp_ms + fan_update_interval_ms);
TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_STARTED));
TERN_(DWIN_CREALITY_LCD_ENHANCED, DWIN_PidTuning(isbed ? PID_BED_START : PID_EXTR_START));
@ -659,12 +660,7 @@ volatile bool Temperature::raw_temps_ready = false;
ONHEATING(start_temp, current_temp, target);
#endif
#if HAS_AUTO_FAN
if (ELAPSED(ms, next_auto_fan_check_ms)) {
checkExtruderAutoFans();
next_auto_fan_check_ms = ms + 2500UL;
}
#endif
TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms));
if (heating && current_temp > target && ELAPSED(ms, t2 + 5000UL)) {
heating = false;
@ -853,6 +849,7 @@ int16_t Temperature::getHeaterPower(const heater_id_t heater_id) {
#define _EFANOVERLAP(A,B) _FANOVERLAP(E##A,B)
#if HAS_AUTO_FAN
#if EXTRUDER_AUTO_FAN_SPEED != 255
#define INIT_E_AUTO_FAN_PIN(P) do{ if (P == FAN1_PIN || P == FAN2_PIN) { SET_PWM(P); SET_FAST_PWM_FREQ(P); } else SET_OUTPUT(P); }while(0)
#else
@ -866,7 +863,7 @@ int16_t Temperature::getHeaterPower(const heater_id_t heater_id) {
#define CHAMBER_FAN_INDEX HOTENDS
void Temperature::checkExtruderAutoFans() {
void Temperature::update_autofans() {
#define _EFAN(B,A) _EFANOVERLAP(A,B) ? B :
static const uint8_t fanBit[] PROGMEM = {
0
@ -914,36 +911,43 @@ int16_t Temperature::getHeaterPower(const heater_id_t heater_id) {
break;
#endif
default:
#if ENABLED(AUTO_POWER_E_FANS)
#if EITHER(AUTO_POWER_E_FANS, HAS_FANCHECK)
autofan_speed[realFan] = fan_on ? EXTRUDER_AUTO_FAN_SPEED : 0;
#endif
break;
}
#if BOTH(HAS_FANCHECK, HAS_PWMFANCHECK)
#define _AUTOFAN_SPEED() fan_check.is_measuring() ? 255 : EXTRUDER_AUTO_FAN_SPEED
#else
#define _AUTOFAN_SPEED() 255
#endif
#define _AUTOFAN_CASE(N) case N: _UPDATE_AUTO_FAN(E##N, fan_on, _AUTOFAN_SPEED()); break
switch (f) {
#if HAS_AUTO_FAN_0
case 0: _UPDATE_AUTO_FAN(E0, fan_on, EXTRUDER_AUTO_FAN_SPEED); break;
_AUTOFAN_CASE(0);
#endif
#if HAS_AUTO_FAN_1
case 1: _UPDATE_AUTO_FAN(E1, fan_on, EXTRUDER_AUTO_FAN_SPEED); break;
_AUTOFAN_CASE(1);
#endif
#if HAS_AUTO_FAN_2
case 2: _UPDATE_AUTO_FAN(E2, fan_on, EXTRUDER_AUTO_FAN_SPEED); break;
_AUTOFAN_CASE(2);
#endif
#if HAS_AUTO_FAN_3
case 3: _UPDATE_AUTO_FAN(E3, fan_on, EXTRUDER_AUTO_FAN_SPEED); break;
_AUTOFAN_CASE(3);
#endif
#if HAS_AUTO_FAN_4
case 4: _UPDATE_AUTO_FAN(E4, fan_on, EXTRUDER_AUTO_FAN_SPEED); break;
_AUTOFAN_CASE(4);
#endif
#if HAS_AUTO_FAN_5
case 5: _UPDATE_AUTO_FAN(E5, fan_on, EXTRUDER_AUTO_FAN_SPEED); break;
_AUTOFAN_CASE(5);
#endif
#if HAS_AUTO_FAN_6
case 6: _UPDATE_AUTO_FAN(E6, fan_on, EXTRUDER_AUTO_FAN_SPEED); break;
_AUTOFAN_CASE(6);
#endif
#if HAS_AUTO_FAN_7
case 7: _UPDATE_AUTO_FAN(E7, fan_on, EXTRUDER_AUTO_FAN_SPEED); break;
_AUTOFAN_CASE(7);
#endif
#if HAS_AUTO_CHAMBER_FAN && !AUTO_CHAMBER_IS_E
case CHAMBER_FAN_INDEX: _UPDATE_AUTO_FAN(CHAMBER, fan_on, CHAMBER_AUTO_FAN_SPEED); break;
@ -1367,20 +1371,14 @@ void Temperature::manage_heater() {
_temp_error((heater_id_t)HEATER_ID(TEMP_SENSOR_REDUNDANT_TARGET), F(STR_REDUNDANCY), GET_TEXT_F(MSG_ERR_REDUNDANT_TEMP));
#endif
#if HAS_AUTO_FAN
if (ELAPSED(ms, next_auto_fan_check_ms)) { // only need to check fan state very infrequently
checkExtruderAutoFans();
next_auto_fan_check_ms = ms + 2500UL;
}
#endif
// Manage extruder auto fans and/or read fan tachometers
TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms));
#if ENABLED(FILAMENT_WIDTH_SENSOR)
/**
* Dynamically set the volumetric multiplier based
* on the delayed Filament Width measurement.
*/
filwidth.update_volumetric();
#endif
/**
* Dynamically set the volumetric multiplier based
* on the delayed Filament Width measurement.
*/
TERN_(FILAMENT_WIDTH_SENSOR, filwidth.update_volumetric());
#if HAS_HEATED_BED
@ -3501,6 +3499,9 @@ void Temperature::isr() {
babystep.task();
#endif
// Check fan tachometers
TERN_(HAS_FANCHECK, fan_check.update_tachometers());
// Poll endstops state, if required
endstops.poll();

View file

@ -37,6 +37,10 @@
#include "../libs/autoreport.h"
#endif
#if HAS_FANCHECK
#include "../feature/fancheck.h"
#endif
#ifndef SOFT_PWM_SCALE
#define SOFT_PWM_SCALE 0
#endif
@ -344,6 +348,10 @@ typedef struct { int16_t raw_min, raw_max; celsius_t mintemp, maxtemp; } temp_ra
#endif
#if HAS_AUTO_FAN || HAS_FANCHECK
#define HAS_FAN_LOGIC 1
#endif
class Temperature {
public:
@ -372,7 +380,7 @@ class Temperature {
static redundant_info_t temp_redundant;
#endif
#if ENABLED(AUTO_POWER_E_FANS)
#if EITHER(AUTO_POWER_E_FANS, HAS_FANCHECK)
static uint8_t autofan_speed[HOTENDS];
#endif
#if ENABLED(AUTO_POWER_CHAMBER_FAN)
@ -459,6 +467,10 @@ class Temperature {
static int16_t lpq_len;
#endif
#if HAS_FAN_LOGIC
static constexpr millis_t fan_update_interval_ms = TERN(HAS_PWMFANCHECK, 5000, TERN(HAS_FANCHECK, 1000, 2500));
#endif
private:
#if ENABLED(WATCH_HOTENDS)
@ -510,8 +522,28 @@ class Temperature {
static millis_t preheat_end_time[HOTENDS];
#endif
#if HAS_AUTO_FAN
static millis_t next_auto_fan_check_ms;
#if HAS_FAN_LOGIC
static millis_t fan_update_ms;
static inline void manage_extruder_fans(millis_t ms) {
if (ELAPSED(ms, fan_update_ms)) { // only need to check fan state very infrequently
const millis_t next_ms = ms + fan_update_interval_ms;
#if HAS_PWMFANCHECK
#define FAN_CHECK_DURATION 100
if (fan_check.is_measuring()) {
fan_check.compute_speed(ms + FAN_CHECK_DURATION - fan_update_ms);
fan_update_ms = next_ms;
}
else
fan_update_ms = ms + FAN_CHECK_DURATION;
fan_check.toggle_measuring();
#else
TERN_(HAS_FANCHECK, fan_check.compute_speed(next_ms - fan_update_ms));
fan_update_ms = next_ms;
#endif
TERN_(HAS_AUTO_FAN, update_autofans()); // Needed as last when HAS_PWMFANCHECK to properly force fan speed
}
}
#endif
#if ENABLED(PROBING_HEATERS_OFF)
@ -961,7 +993,7 @@ class Temperature {
static int16_t read_max_tc(TERN_(HAS_MULTI_MAX_TC, const uint8_t hindex=0));
#endif
static void checkExtruderAutoFans();
static void update_autofans();
#if HAS_HOTEND
static float get_pid_output_hotend(const uint8_t e);

View file

@ -188,6 +188,14 @@
#endif
#endif
#ifndef E0_FAN_TACHO_PIN
#ifdef MK3_FAN_PINS
#define E0_FAN_TACHO_PIN PE0 // Fan1
#else
#define E0_FAN_TACHO_PIN PE1 // Fan0
#endif
#endif
/**
* -----------------------------------BTT002 V1.0----------------------------------------
* ------ ------ |

View file

@ -107,6 +107,7 @@ CANCEL_OBJECTS = src_filter=+<src/feature/cancel_object.
CASE_LIGHT_ENABLE = src_filter=+<src/feature/caselight.cpp> +<src/gcode/feature/caselight>
EXTERNAL_CLOSED_LOOP_CONTROLLER = src_filter=+<src/feature/closedloop.cpp> +<src/gcode/calibrate/M12.cpp>
USE_CONTROLLER_FAN = src_filter=+<src/feature/controllerfan.cpp>
HAS_COOLER|LASER_COOLANT_FLOW_METER = src_filter=+<src/feature/cooler.cpp>
HAS_MOTOR_CURRENT_DAC = src_filter=+<src/feature/dac>
DIRECT_STEPPING = src_filter=+<src/feature/direct_stepping.cpp> +<src/gcode/motion/G6.cpp>
EMERGENCY_PARSER = src_filter=+<src/feature/e_parser.cpp> -<src/gcode/control/M108_*.cpp>
@ -114,6 +115,7 @@ I2C_POSITION_ENCODERS = src_filter=+<src/feature/encoder_i2c.cp
IIC_BL24CXX_EEPROM = src_filter=+<src/libs/BL24CXX.cpp>
HAS_SPI_FLASH = src_filter=+<src/libs/W25Qxx.cpp>
HAS_ETHERNET = src_filter=+<src/feature/ethernet.cpp> +<src/gcode/feature/network/M552-M554.cpp>
HAS_FANCHECK = src_filter=+<src/feature/fancheck.cpp> +<src/gcode/temp/M123.cpp>
HAS_FANMUX = src_filter=+<src/feature/fanmux.cpp>
FILAMENT_WIDTH_SENSOR = src_filter=+<src/feature/filwidth.cpp> +<src/gcode/feature/filwidth>
FWRETRACT = src_filter=+<src/feature/fwretract.cpp> +<src/gcode/feature/fwretract>
@ -211,7 +213,6 @@ GCODE_REPEAT_MARKERS = src_filter=+<src/feature/repeat.cpp> +<
HAS_EXTRUDERS = src_filter=+<src/gcode/units/M82_M83.cpp> +<src/gcode/temp/M104_M109.cpp> +<src/gcode/config/M221.cpp>
HAS_TEMP_PROBE = src_filter=+<src/gcode/temp/M192.cpp>
HAS_COOLER = src_filter=+<src/gcode/temp/M143_M193.cpp>
HAS_COOLER|LASER_COOLANT_FLOW_METER = src_filter=+<src/feature/cooler.cpp>
AUTO_REPORT_TEMPERATURES = src_filter=+<src/gcode/temp/M155.cpp>
INCH_MODE_SUPPORT = src_filter=+<src/gcode/units/G20_G21.cpp>
TEMPERATURE_UNITS_SUPPORT = src_filter=+<src/gcode/units/M149.cpp>

View file

@ -111,6 +111,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
-<src/feature/e_parser.cpp>
-<src/feature/encoder_i2c.cpp>
-<src/feature/ethernet.cpp> -<src/gcode/feature/network/M552-M554.cpp>
-<src/feature/fancheck.cpp>
-<src/feature/fanmux.cpp>
-<src/feature/filwidth.cpp> -<src/gcode/feature/filwidth>
-<src/feature/fwretract.cpp> -<src/gcode/feature/fwretract>
@ -228,6 +229,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
-<src/gcode/sd/M32.cpp>
-<src/gcode/sd/M808.cpp>
-<src/gcode/temp/M104_M109.cpp>
-<src/gcode/temp/M123.cpp>
-<src/gcode/temp/M155.cpp>
-<src/gcode/temp/M192.cpp>
-<src/gcode/units/G20_G21.cpp>