Skip to content

M4 (dynamic/rate-adjusted) laser power not zeroed on G0 block immediately following a rate-adjusted G1 block #1002

Description

@Alijambo

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), 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

  1. $32=1 (laser mode), PWM spindle with update_pwm/get_pwm set (QuadTimer/iMXRT1062 driver, spindleSetStateVariable/spindleSetSpeed per driver.c).
  2. Send M4 once.
  3. Send a G1 move with axis words and an S value large enough to be clearly visible (e.g. G1 X10 S16800 F1000).
  4. 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.
  5. 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.c laser_disable/is_rpm_rate_adjusted computation, stepper.c dynamic_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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions