fan: latch HBR tach above max_rpm/2 to absorb soft-PWM transients - #185
Open
DRracer wants to merge 1 commit into
Open
fan: latch HBR tach above max_rpm/2 to absorb soft-PWM transients#185DRracer wants to merge 1 commit into
DRracer wants to merge 1 commit into
Conversation
On the MK4 board, PF13 is multiplexed between the hotend (HBR) and print
fan tach lines (HBR.tach-disable <- PF13, PRINT.tach-disable <- PF13
inverted in prusa-mk4.c) and is also bit-banged by the at21csxx loveboard
EEPROM (read once at boot, then idle LOW). The firmware's Fans::tick()
toggles PF13 at 1 kHz to scan both fans; on real silicon the mux is a
passive input read by a glue chip, but in QEMU there is no HiZ — the
GPIO sticks at whatever the FW last drove — so the sim's tach_blocked
path masks the HBR tach roughly half the time during normal operation.
This is invisible during the standalone fan selftest (FW puts the fan
into selftest_mode, which short-circuits is_fan_ok()). After the heater
test, autoFan re-engages and the software_pwm device's 256-tick window
averaging yields small-but-nonzero intermediate values during the
PWM=0 → PWM=255 transition. is_fan_ok() treats *zero* RPM as OK
(short-circuit) but *small* RPM as a failure when commanded PWM is up,
firing WarningType::HotendFanError ("Hotend fan not spinning") about
25 s into the cool-down. That kills the rest of the selftest snake.
Add a per-device `always_emit_tach` bool. When set:
1. fan_tach_expire ignores tach_blocked — pulses always reach the GPIO.
2. fan_pwm_change latches current_rpm at max_rpm whenever the new
computed value drops below max_rpm/2 AND the previous value was
above max_rpm/2. So once the fan has spun up, it stays at full RPM
through PWM transients (rotor-inertia approximation).
Enable on fans[FAN_HBR] in prusa-mk4.c; print fan is unchanged. The
standalone Fan Test still passes both phases: HBR-100% reads max_rpm
(= cfg.f_rpms[1] = 7500), inside the FW's [6800, 8700] window; HBR-40%
reads max_rpm, inside the wide [10, 10000] window. The print-fan tach
phase runs with HBR PWM=0, so HBR emits no pulses regardless of the
latch and doesn't contaminate the print-fan reading.
The proper long-term fix is to honour STM32 GPIOx_MODER bits so the
mux-select GPIO models HiZ correctly; this latch is a targeted
workaround that unblocks the full first-boot selftest in sim.
Verified end-to-end on Buddy 6.6.0+14739 with mk4_release_noboot.bin:
sim/harness/walk_full_selftest.py drives Fans -> XYCheck -> ZAlign ->
Loadcell -> ZCheck -> Heaters -> Gears (skipped) -> FS calibration to
the home screen, no spurious HotendFanError.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
always_emit_tachbool property on thefandevice. When set,fan_tach_expireignorestach_blockedandfan_pwm_changelatchescurrent_rpmatmax_rpmonce it has been abovemax_rpm/2.fans[FAN_HBR]inprusa-mk4.c(print fan behaviour unchanged).cfg.f_rpms[1] = 7500, inside the FW's[6800, 8700]acceptance window.Motivation
On the MK4 board, PF13 is multiplexed between the HBR and print fan tach lines (
HBR.tach-disable <- PF13,PRINT.tach-disable <- PF13inverted inprusa-mk4.c:920-934) and is also bit-banged by theat21csxxloveboard EEPROM. The firmware'sFans::tick()toggles PF13 at 1 kHz to scan both fans; on real silicon the mux is a passive input read by a glue chip, but in QEMU there is no HiZ — the GPIO holds whatever the FW last drove — so the sim'stach_blockedpath masks the HBR tach roughly half the time during normal operation.This is invisible during the standalone fan selftest (the FW puts the fan into
selftest_mode, which short-circuitsCFanCtlCommon::is_fan_ok()), but after the heater test, autoFan re-engages and thesoftware_pwmdevice's 256-tick window averaging yields small-but-nonzero intermediate values during the PWM=0 → PWM=255 transition.is_fan_ok()treats zero RPM as OK (short-circuit) but small RPM as a failure when commanded PWM is up, firingWarningType::HotendFanError("Hotend fan not spinning") about 25 s into the cool-down — which kills the rest of the selftest snake.The proper long-term fix is probably to honour STM32
GPIOx_MODERbits so the mux-select GPIO models HiZ correctly. This latch is a targeted workaround that unblocks the full first-boot selftest in sim.Test plan
MINI404.prusa-mk4-027cwithmk4_release_noboot.bin(Buddy 6.6.0+14739): Print 6552/2658 RPM in range, Heatbreak 7500 RPM in range at both 100% and 40% PWM phases.HotendFanErrorafter the heater test on the same FW build.set_warning(0)in the CDC log.