You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With $32=1 (laser mode) and a spindle driven via PWM (update_pwm/get_pwm, QuadTimer-based on this driver), issuing M4 once at the start of a job and then alternating G1 (cut, with S value) / G0 (travel) blocks — the standard pattern for LightBurn's "dynamic power" / automatic G0-suppression mode — the laser does not reliably turn off during G0 travel moves that immediately follow a rate-adjusted G1 cut. It stays on, apparently outputting whatever PWM duty the previous cut's velocity-scaled power last computed to, until the next G1 re-establishes power.
This is fully reproducible and confirmed independent of hardware: multimeter checks confirm no floating-pin issue on the laser's TTL input (deliberate ~1k pull-down present on all three input options on the adapter board), and the exact same G-code/job run through the GRBL-M3 device profile (explicit per-segment M3/S0/M5, no dynamic power) behaves correctly — laser reliably off during every travel move. Switching purely between the GRBL/M4 and GRBL-M3 device profiles, with no other change, reproduces/resolves the symptom every time.
Steps to Reproduce
$32=1 (laser mode), PWM spindle with update_pwm/get_pwm set (QuadTimer/iMXRT1062 driver, spindleSetStateVariable/spindleSetSpeed per driver.c).
Send M4 once.
Send a G1 move with axis words and an S value large enough to be clearly visible (e.g. G1 X10 S16800 F1000).
Immediately follow with a G0 travel move with axis words and no S word (S is sticky/modal from the prior line), e.g. G0 X5 Y5.
Observe laser output during step 4.
Expected Behavior
Per motion_is_lasercut() (gcode.c), G0 is never a lasercut motion, so laser_disable is set and plan_data.spindle.rpm is planned as 0.0f for the block regardless of the modal S value. stepper.c:1080-1081 additionally forces sys.step_control.update_spindle_rpm on for every new block when cap.laser is set, which should force a fresh RPM-and-PWM recompute at the very start of the new G0 block, overriding whatever the previous G1 block's dynamic-power segments last commanded.
Actual Behavior
Laser output continues at (or near) the level from the end of the preceding G1 block's dynamic-power ramp, through the G0 travel move, until the next G1 block re-establishes commanded power.
Analysis / What's Been Ruled Out
Not a hardware/wiring issue. Laser TTL input confirmed pulled down (~1k) with board unpowered; PSU power-up sequencing in Start G-code was reordered (mode/RPM settings established before power-up) with no change in behavior.
Not the previously-fixed M3-in-G0/G80 issue (Unexpected Laser Behaviour #644). That fix (e8a0aee) is already present; also, our reproduction is specific to M4/CCW (is_rpm_rate_adjusted) blocks, not stationary M3 S<n> commands.
Not a PWM-timer stale-duty-register issue at settings-change time. We independently found and fixed a real, separate bug where spindleConfig() (driver.c) re-arms the QuadTimer's compare mode via pwm_config() without resetting the duty register, causing spurious full-power output on any $30/$31/$32 write. That fix is unrelated to this issue — this M4/G0 symptom persists after that fix, with no $-setting writes involved during the run at all.
Parser-level logic traced and appears correct, per the code reading above (gcode.claser_disable/is_rpm_rate_adjusted computation, stepper.cdynamic_rpm per-block flag and the update_spindle_rpm |= cap.laser force-update at block start). We could not identify a structural gap through static code reading alone; this looks like it may be a timing-sensitive issue in the stepper ISR at the G1(dynamic)→G0(non-dynamic) block boundary, which is difficult to confirm without a live debugger/oscilloscope on the PWM output.
Additional Context
Given the safety implications of a laser that doesn't reliably turn off during rapid moves, we are not currently using M4/dynamic power for real jobs and have reverted to M3 (constant power, explicit per-segment on/off), which is fully confirmed reliable. Happy to provide the full reproduction G-code file, run further tests, or add temporary debug instrumentation if that would help pin down the exact point of failure in the stepper ISR.
Title
M4 (dynamic/rate-adjusted) laser power not zeroed on G0 block immediately following a rate-adjusted G1 block
Environment
Description
With
$32=1(laser mode) and a spindle driven via PWM (update_pwm/get_pwm, QuadTimer-based on this driver), issuingM4once at the start of a job and then alternatingG1(cut, withSvalue) /G0(travel) blocks — the standard pattern for LightBurn's "dynamic power" / automatic G0-suppression mode — the laser does not reliably turn off duringG0travel moves that immediately follow a rate-adjustedG1cut. It stays on, apparently outputting whatever PWM duty the previous cut's velocity-scaled power last computed to, until the nextG1re-establishes power.This is fully reproducible and confirmed independent of hardware: multimeter checks confirm no floating-pin issue on the laser's TTL input (deliberate ~1k pull-down present on all three input options on the adapter board), and the exact same G-code/job run through the
GRBL-M3device profile (explicit per-segmentM3/S0/M5, no dynamic power) behaves correctly — laser reliably off during every travel move. Switching purely between theGRBL/M4andGRBL-M3device profiles, with no other change, reproduces/resolves the symptom every time.Steps to Reproduce
$32=1(laser mode), PWM spindle withupdate_pwm/get_pwmset (QuadTimer/iMXRT1062 driver,spindleSetStateVariable/spindleSetSpeedperdriver.c).M4once.G1move with axis words and anSvalue large enough to be clearly visible (e.g.G1 X10 S16800 F1000).G0travel move with axis words and noSword (Sis sticky/modal from the prior line), e.g.G0 X5 Y5.Expected Behavior
Per
motion_is_lasercut()(gcode.c),G0is never a lasercut motion, solaser_disableis set andplan_data.spindle.rpmis planned as0.0ffor the block regardless of the modalSvalue.stepper.c:1080-1081additionally forcessys.step_control.update_spindle_rpmon for every new block whencap.laseris set, which should force a fresh RPM-and-PWM recompute at the very start of the newG0block, overriding whatever the previousG1block's dynamic-power segments last commanded.Actual Behavior
Laser output continues at (or near) the level from the end of the preceding
G1block's dynamic-power ramp, through theG0travel move, until the nextG1block re-establishes commanded power.Analysis / What's Been Ruled Out
M3-in-G0/G80issue (Unexpected Laser Behaviour #644). That fix (e8a0aee) is already present; also, our reproduction is specific toM4/CCW (is_rpm_rate_adjusted) blocks, not stationaryM3 S<n>commands.spindleConfig()(driver.c) re-arms the QuadTimer's compare mode viapwm_config()without resetting the duty register, causing spurious full-power output on any$30/$31/$32write. That fix is unrelated to this issue — thisM4/G0symptom persists after that fix, with no$-setting writes involved during the run at all.gcode.claser_disable/is_rpm_rate_adjustedcomputation,stepper.cdynamic_rpmper-block flag and theupdate_spindle_rpm |= cap.laserforce-update at block start). We could not identify a structural gap through static code reading alone; this looks like it may be a timing-sensitive issue in the stepper ISR at theG1(dynamic)→G0(non-dynamic) block boundary, which is difficult to confirm without a live debugger/oscilloscope on the PWM output.Additional Context
Given the safety implications of a laser that doesn't reliably turn off during rapid moves, we are not currently using
M4/dynamic power for real jobs and have reverted toM3(constant power, explicit per-segment on/off), which is fully confirmed reliable. Happy to provide the full reproduction G-code file, run further tests, or add temporary debug instrumentation if that would help pin down the exact point of failure in the stepper ISR.