Does Klipper use software PWM or hardware PWM?

TL;DR: Klipper uses software PWM by default, but it can use hardware PWM on supported MCUs if you explicitly enable it in the configuration.

Software PWM is the default

When you configure a fan, heater, or generic output pin in Klipper without any special flags, Klipper runs software PWM. The important thing to understand is that the bit-banging is not done on the host/Linux side — the host only schedules the transitions and sends them to the MCU. The actual GPIO toggling happens inside the MCU firmware.

In klippy/mcu.py, the MCU_pwm class decides which path to take. If hardware_pwm is False (the default), it configures the pin as a normal digital output and sends config_digital_out plus set_digital_out_pwm_cycle to the MCU (lines 509-530). For each duty-cycle update it sends queue_digital_out with an on_ticks value that tells the MCU how many clock ticks the pin should stay high within the PWM cycle.

On the MCU side, src/gpiocmds.c implements the soft-PWM state machine:

So the PWM waveform is generated by the MCU’s timer interrupt scheduler, driven by the host’s list of future transitions.

Hardware PWM is opt-in

Hardware PWM is enabled per pin with hardware_pwm: True in the config. When this is set, the host sends config_pwm_out and queue_pwm_out commands instead, and the MCU uses the platform’s PWM peripheral.

The MCU-side dispatch is in src/pwmcmds.c. Platform-specific implementations exist for several MCUs:

For example, the STM32 implementation in gpio_pwm_setup() looks up the timer/channel for the requested pin, computes a prescaler and counter period that best matches the requested cycle time, and then writes the duty value into the timer’s capture/compare register.

The Klipper documentation explicitly warns that “most fans do not work well with hardware PWM, so it is not recommended to enable this unless there is an electrical requirement to switch at very high speeds” (Config_Reference.md).

What defines the PWM frequency?

The frequency is simply 1 / cycle_time, set in the config:

For software PWM this is the actual frequency the MCU toggles at. For hardware PWM it is the requested frequency, but the MCU timer hardware may round it to the nearest achievable value due to prescaler/counter limits. Also, multiple hardware PWM pins sharing the same timer must run at the same frequency; otherwise Klipper errors with “PWM already programmed at different speed”.

Example configuration

Fan with software PWM (default)

example.ini
[fan]
pin: PA8
cycle_time: 0.010
hardware_pwm: False

Output pin with hardware PWM

example.ini
[output_pin my_pwm]
pin: PB0
pwm: True
cycle_time: 0.001
hardware_pwm: True

Heater PWM period

example.ini
[extruder]
heater_pin: PA2
pwm_cycle_time: 0.100

Check out similar posts by category: Klipper, 3D Printing