Pulse Width Modulation (PWM) interface for hardware platforms.
More...
Pulse Width Modulation (PWM) interface for hardware platforms.
PWM is a digital waveform technique that approximates an analog level by rapidly toggling an output between low and high. Each PWM cycle has:
- A period: total cycle duration.
- A duty cycle: percentage of that period spent high.
For example, 1 kHz PWM with 25% duty is high for 250 us and low for 750 us every cycle. Common uses include LED dimming, motor speed control, and tone generation.
This module provides functions to initialize PWM outputs, configure period and duty cycle, control output state, and optionally receive wrap callbacks at period boundaries.
- Note
- On Raspberry Pi OS PWM outputs are disabled by default and must be enabled in
config.txt with a device tree overlay, for example dtoverlay=pwm,pin=18,func=2 for a single channel on GPIO18, or dtoverlay=pwm-2chan,pin=18,func=2,pin2=19,func2=2 for both channels (GPIO18/GPIO19); see /boot/firmware/overlays/README for the full pin/ function table, other pins, and other overlays. Once loaded, the kernel exposes each channel under /sys/class/pwm/pwmchipN/ rather than a fixed device path.
- Note
- Pico backend details (RP2040/RP2350): The hardware groups GPIOs into PWM slices. Each slice has two output channels (A and B) that share the same period (wrap) and divider settings but have independent duty levels. Because period settings are shared per slice, changing period on one channel affects the other channel in the same slice. The slice also has a single enable bit shared by both channels, so hw_pwm_init() or hw_pwm_set_config() on one channel can change whether the other channel's output is enabled, and hw_pwm_deinit() on one channel leaves the slice (and thus the other channel, if still open) in whatever enabled/period state that call left behind. Opening both channels of the same slice works, but callers doing so must coordinate period and enabled state between them - picofuse does not do this on their behalf.
◆ hw_pwm_callback_t
| typedef void(* hw_pwm_callback_t) (hw_pwm_t *pwm, void *userdata) |
PWM wrap callback function pointer.
Backends that support PWM wrap interrupts can invoke this callback on each counter wrap event, when the PWM counter rolls from its top value back to zero (the boundary between PWM periods).
Definition at line 80 of file pwm.h.
◆ hw_pwm_deinit()
Deinitialize a PWM handle.
- Parameters
-
◆ hw_pwm_get_config()
Read current PWM configuration.
- Parameters
-
| pwm | PWM handle. |
| out_config | Output destination for current configuration. |
- Return values
-
| true | Configuration was written to out_config. |
| false | Handle or output pointer is invalid. |
◆ hw_pwm_get_duty_percent()
| float hw_pwm_get_duty_percent |
( |
const hw_pwm_t * |
pwm | ) |
|
Get duty cycle percentage.
- Parameters
-
- Returns
- Duty cycle in [0.0, 100.0], or 0.0 on invalid handle.
◆ hw_pwm_get_enabled()
| bool hw_pwm_get_enabled |
( |
const hw_pwm_t * |
pwm | ) |
|
Query whether PWM output is enabled.
- Parameters
-
- Return values
-
| true | PWM output is enabled. |
| false | PWM output is disabled or handle is invalid. |
◆ hw_pwm_get_period_ns()
| uint64_t hw_pwm_get_period_ns |
( |
const hw_pwm_t * |
pwm | ) |
|
Get the configured PWM period.
- Parameters
-
- Returns
- PWM period in nanoseconds, or 0 on invalid handle.
◆ hw_pwm_init()
Initialize a PWM output on a GPIO pin.
- Parameters
-
| gpio | GPIO handle for a PWM-capable pin. |
| callback | Optional callback invoked on PWM counter wrap (top -> 0) events, typically once per completed PWM period. |
| userdata | User context pointer forwarded to callback. |
| config | Optional PWM configuration. Pass NULL to use defaults. |
- Returns
- PWM handle or NULL on failure. If
callback is not NULL, backends that do not support wrap interrupt callbacks return NULL.
◆ hw_pwm_init_device()
Initialize a PWM output from a platform-specific device path.
- Parameters
-
| device | Device identifier such as /sys/class/pwm/pwmchip0. |
| channel | Channel index within device, e.g. 0 for pwm0. A chip may expose more than one - see its npwm file for how many. |
| config | Optional PWM configuration. Pass NULL to use defaults. |
- Returns
- PWM handle or NULL on failure. Release it with hw_pwm_deinit().
This entry point is intended for platforms where PWM channels are exposed as named sysfs paths rather than a fixed set of slices/channels reachable via a GPIO handle. There is no callback parameter here - unlike hw_pwm_init(), this entry point has no wrap-interrupt mechanism to offer at all (see hw_pwm_irq_supported()), not merely an unsupported one.
◆ hw_pwm_irq_supported()
| bool hw_pwm_irq_supported |
( |
void |
| ) |
|
Check whether PWM wrap interrupt callbacks are supported.
- Return values
-
| true | Wrap interrupts are supported on this platform. |
| false | Wrap interrupts are unsupported. |
◆ hw_pwm_set_config()
Apply a complete PWM configuration.
- Parameters
-
| pwm | PWM handle. |
| config | PWM configuration to apply. |
- Return values
-
| true | Configuration was applied. |
| false | Configuration failed. |
◆ hw_pwm_set_duty_percent()
| bool hw_pwm_set_duty_percent |
( |
hw_pwm_t * |
pwm, |
|
|
float |
duty_percent |
|
) |
| |
Set duty cycle percentage.
- Parameters
-
| pwm | PWM handle. |
| duty_percent | Duty cycle percentage in [0.0, 100.0]. Values outside this range are clamped by the backend. |
- Return values
-
| true | Duty cycle was applied. |
| false | The handle is invalid or duty control is unsupported. |
◆ hw_pwm_set_enabled()
| void hw_pwm_set_enabled |
( |
hw_pwm_t * |
pwm, |
|
|
bool |
enabled |
|
) |
| |
Enable or disable PWM output.
- Parameters
-
| pwm | PWM handle. |
| enabled | true to enable output, false to disable. |
◆ hw_pwm_set_period_ns()
| bool hw_pwm_set_period_ns |
( |
hw_pwm_t * |
pwm, |
|
|
uint64_t |
period_ns |
|
) |
| |
Set the PWM period.
- Parameters
-
| pwm | PWM handle. |
| period_ns | PWM period in nanoseconds. |
- Return values
-
| true | Period was accepted. |
| false | Period is unsupported or the handle is invalid. |