Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PWM

micro/pwm provides pulse-width modulation for motor control, LED dimming, and tone generation.

Basic Usage

use micro/pwm
use micro/gpio
use std/time

fn main() -> never {
    let mut ch = pwm.channel(0)
        .pin(gpio.pin(25))
        .init()?

    // Fade LED up then down
    loop {
        for duty in 0..=100 {
            ch.set_duty_percent(duty)
            time.sleep_ms(10)
        }
        for i in 0..=100 {
            ch.set_duty_percent(100 - i)
            time.sleep_ms(10)
        }
    }
}

Initialization

let mut ch = pwm.channel(0)
    .pin(gpio.pin(25))      // output pin
    .freq(1000)             // frequency in Hz (optional, target default if omitted)
    .init()?

The terminal init() is fallible. After initialization, duty-cycle updates are infallible.

Setting Duty Cycle

ch.set_duty_percent(50)    // 50% duty (0..=100)
ch.set_duty(2048)          // raw 16-bit duty value
ch.off()                   // 0% duty (output low)
ch.full()                  // 100% duty (output high)

The default full-scale is a 16-bit duty range (0..=65535), matching the standard RP2040 PWM wrap value. set_duty_percent maps 0-100 to that range.

LED Fade Example

From examples/rp2040/fade_led:

use micro/pwm
use micro/gpio
use std/time

const LED_PIN: u32 = 25

fn main() -> never {
    let mut led = pwm.channel(0)
        .pin(gpio.pin(LED_PIN))
        .init()

    let mut rising = true
    let mut level: u16 = 0

    const BRIGHT_STEP: u16 = 512
    const BRIGHT_MAX: u16 = 65535
    const BRIGHT_TURN: u16 = 65535

    loop {
        match rising {
            true when level >= BRIGHT_TURN => {
                level = BRIGHT_MAX
                rising = false
            }
            true => level += BRIGHT_STEP
            false when level <= BRIGHT_STEP => {
                level = 0
                rising = true
            }
            _ => level -= BRIGHT_STEP
        }

        led.set_duty(level)
        time.sleep_ms(10)
    }
}

Do and Don’t

// Do: use set_duty_percent for simple 0-100% control
ch.set_duty_percent(75)

// Do: use off() and full() for clean extremes
ch.off()
ch.full()

// Avoid: computing raw duty values with magic numbers
// ch.set_duty(49151)    // what is this?
// Prefer:
ch.set_duty_percent(75)

// Avoid: reinitializing PWM in a loop; configure once at startup