diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index 7c7d61e7eb..90d3d2fd65 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -47,7 +47,7 @@ bool FilamentMonitorBase::enabled = true, #if HAS_FILAMENT_RUNOUT_DISTANCE float RunoutResponseDelayed::runout_distance_mm = FILAMENT_RUNOUT_DISTANCE_MM; - volatile countdown_t RunoutResponseDelayed::mm_countdown; + countdown_t RunoutResponseDelayed::mm_countdown; #if ENABLED(FILAMENT_MOTION_SENSOR) uint8_t FilamentSensorEncoder::motion_detected; #endif diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index a001459e9d..847413d25a 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -30,7 +30,8 @@ #include "../module/planner.h" #include "../module/stepper.h" // for block_t #include "../gcode/queue.h" -#include "../feature/pause.h" +#include "../feature/pause.h" // for did_pause_print +#include "../MarlinCore.h" // for printingIsActive() #include "../inc/MarlinConfig.h" @@ -50,9 +51,16 @@ #define HAS_FILAMENT_SWITCH 1 #endif -typedef Flags<8> runout_flags_t; +typedef Flags< + #if NUM_MOTION_SENSORS > NUM_RUNOUT_SENSORS + NUM_MOTION_SENSORS + #else + NUM_RUNOUT_SENSORS + #endif + > runout_flags_t; void event_filament_runout(const uint8_t extruder); +inline bool should_monitor_runout() { return did_pause_print || printingIsActive(); } template class TFilamentMonitor; @@ -128,7 +136,7 @@ class TFilamentMonitor : public FilamentMonitorBase { // Give the response a chance to update its counter. static void run() { - if (enabled && !filament_ran_out && (printingIsActive() || did_pause_print)) { + if (enabled && !filament_ran_out && should_monitor_runout()) { TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, cli()); // Prevent RunoutResponseDelayed::block_completed from accumulating here response.run(); sensor.run(); @@ -340,8 +348,10 @@ class FilamentSensorBase { typedef struct { float runout[NUM_RUNOUT_SENSORS]; + Flags runout_reset; // Reset runout later #if ENABLED(FILAMENT_SWITCH_AND_MOTION) float motion[NUM_MOTION_SENSORS]; + Flags motion_reset; // Reset motion later #endif } countdown_t; @@ -350,7 +360,7 @@ class FilamentSensorBase { // during a runout condition. class RunoutResponseDelayed { private: - static volatile countdown_t mm_countdown; + static countdown_t mm_countdown; public: static float runout_distance_mm; @@ -389,26 +399,56 @@ class FilamentSensorBase { } static void filament_present(const uint8_t extruder) { - mm_countdown.runout[extruder] = runout_distance_mm; + if (mm_countdown.runout[extruder] < runout_distance_mm || did_pause_print) { + // Reset runout only if it is smaller than runout_distance or printing is paused. + // On Bowden systems retract may be larger than runout_distance_mm, so if retract + // was added leave it in place, or the following unretract will cause runout event. + mm_countdown.runout[extruder] = runout_distance_mm; + mm_countdown.runout_reset.clear(extruder); + } + else { + // If runout is larger than runout distance, we cannot reset right now, as Bowden and retract + // distance larger than runout_distance_mm leads to negative runout right after unretract. + // But we cannot ignore filament_present event. After unretract, runout will become smaller + // than runout_distance_mm and should be reset after that. So activate delayed reset. + mm_countdown.runout_reset.set(extruder); + } } #if ENABLED(FILAMENT_SWITCH_AND_MOTION) static void filament_motion_present(const uint8_t extruder) { - mm_countdown.motion[extruder] = runout_distance_mm; + // Same logic as filament_present + if (mm_countdown.motion[extruder] < runout_distance_mm || did_pause_print) { + mm_countdown.motion[extruder] = runout_distance_mm; + mm_countdown.motion_reset.clear(extruder); + } + else + mm_countdown.motion_reset.set(extruder); } #endif static void block_completed(const block_t * const b) { - if (b->steps.x || b->steps.y || b->steps.z || did_pause_print) { // Allow pause purge move to re-trigger runout state - // Only trigger on extrusion with XYZ movement to allow filament change and retract/recover. - const uint8_t e = b->extruder; - const int32_t steps = b->steps.e; - const float mm = (b->direction_bits.e ? steps : -steps) * planner.mm_per_step[E_AXIS_N(e)]; - if (e < NUM_RUNOUT_SENSORS) mm_countdown.runout[e] -= mm; - #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - if (e < NUM_MOTION_SENSORS) mm_countdown.motion[e] -= mm; - #endif + const int32_t esteps = b->steps.e; + if (!esteps) return; + + // No calculation unless paused or printing + if (!should_monitor_runout()) return; + + // No need to ignore retract/unretract movement since they complement each other + const uint8_t e = b->extruder; + const float mm = (b->direction_bits.e ? esteps : -esteps) * planner.mm_per_step[E_AXIS_N(e)]; + + if (e < NUM_RUNOUT_SENSORS) { + mm_countdown.runout[e] -= mm; + if (mm_countdown.runout_reset[e]) filament_present(e); // Reset pending. Try to reset. } + + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + if (e < NUM_MOTION_SENSORS) { + mm_countdown.motion[e] -= mm; + if (mm_countdown.motion_reset[e]) filament_motion_present(e); // Reset pending. Try to reset. + } + #endif } };