embassy-rs/embassy · error

Requested divider is too large

Error message

Requested divider is too large

What it means

PWM channel configuration in embassy-rp validates that the clock divider fits the hardware's 4.12 fixed-point field (12 integer bits + 4 fractional bits, max 0xFFF bits). `set_config`/`configure` panics when `Config::divider` exceeds this maximum, because the value would be truncated in the DIV register.

Solutions

  1. Clamp the divider to the representable range before configuring (max FixedU16<U4>::from_bits(0xFFF))
  2. Use `try_set_config` (fallible variant) and handle the error instead of panicking
  3. Lower the PWM top/counter period to achieve the target frequency instead of raising the divider beyond hardware limits
  4. Compute the divider with saturation: `divider.min(FixedU16::<U4>::from_bits(0xFFF))`

Example fix

// before
let config = Config { divider: 8192.into(), top: 100, .. }; // panics
// after
let div = FixedU16::<U4>::from_num(8192.0).min(FixedU16::<U4>::from_bits(0xFFF));
let config = Config { divider: div, top: 65535, .. }; // lower freq via larger top
Defensive patterns

Strategy: validation

Validate before calling

use fixed::types::U4;
fn divider_valid(d: FixedU16<U4>) -> bool {
    d <= FixedU16::<U4>::from_bits(0xFFF)
}

Type guard

fn try_divider(d: FixedU16<U4>) -> Option<FixedU16<U4>> {
    (d <= FixedU16::<U4>::from_bits(0xFFF)).then_some(d)
}

Prevention

When it happens

Trigger: Setting `Config { divider, .. }` to a value greater than 4095.9375 (0xFFF in U16F4 bits) and calling `Pwm::set_config` or `Pwm::new`.

Common situations: Computing a divider as u32/f32 and converting without clamping; aiming for a very low PWM frequency on a high clk_sys and overshooting the divider range; copying a divider value from a datasheet formula that isn't range-checked.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/5fd180a276b4452d. Report an issue: GitHub.

Appendix: source

Thrown at embassy-rp/src/pwm.rs:255

    ) -> Self {
        Self::new_inner(
            slice.number(),
            Some(a.into()),
            Some(b.into()),
            b_pull,
            config,
            mode.into(),
        )
    }

    /// Set the PWM config.
    pub fn set_config(&mut self, config: &Config) {
        Self::configure(pac::PWM.ch(self.slice), config);
    }

    fn configure(p: pac::pwm::Channel, config: &Config) {
        if config.divider > FixedU16::<fixed::types::extra::U4>::from_bits(0xFFF) {
            panic!("Requested divider is too large");
        }

        p.div().write_value(ChDiv(config.divider.to_bits() as u32));
        p.cc().write(|w| {
            w.set_a(config.compare_a);
            w.set_b(config.compare_b);
        });
        p.top().write(|w| w.set_top(config.top));
        p.csr().modify(|w| {
            w.set_a_inv(config.invert_a);
            w.set_b_inv(config.invert_b);
            w.set_ph_correct(config.phase_correct);
            w.set_en(config.enable);
        });
    }

    /// Advances a slice's output phase by one count while it is running
    /// by inserting a pulse into the clock enable. The counter

View on GitHub (pinned to 463a07b963)