embassy-rs/embassy · error

Cannot get CC register

Error message

Cannot get CC register {} of timer with {} CC registers.

What it means

Timer::cc panics when asked for a CC (capture/compare) register index n that is greater than or equal to the number of CC registers the timer instance actually has — 4 for a normal timer, 6 for an extended timer (e.g. TIMER0 on some SoCs). This guards against out-of-bounds register access on hardware.

Solutions

  1. Use the timer's actual channel count — iterate with 0..timer.cc_count() (or the ccs value) instead of a hardcoded bound.
  2. Assign the code needing 6 CC channels to an extended timer instance (e.g. one with 6 CC registers on your SoC).
  3. Check the embassy-nrf timer bindings for your chip to confirm which instances are extended before indexing.

Example fix

// before
for i in 0..6 {
    let cc = timer.cc(i); // panics on 4-CC timers
}
// after
let ccs = timer.cc_count();
for i in 0..ccs {
    let cc = timer.cc(i);
}
Defensive patterns

Strategy: validation

Validate before calling

let ccs: usize = timer.cc_count();
if n < ccs {
    let cc = timer.cc(n);
}

Type guard

fn has_cc(timer: &Timer<'_, T>, n: usize) -> bool { n < timer.cc_count() }

Prevention

When it happens

Trigger: Calling timer.cc(n) with n >= self.ccs, e.g. timer.cc(4) on a 4-channel timer, or looping 0..6 over every timer instance instead of only extended ones; also occurs when code assuming extended-timer behavior runs against a normal timer peripheral.

Common situations: Shared timer-driver code written for an extended timer reused with a plain TIMER instance; hardcoding cc(5) or cc(4); iterating a fixed count of CC channels for PWM capture/compare setup on multiple timers.

Related errors


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

Appendix: source

Thrown at embassy-nrf/src/timer.rs:225

    /// This will stop the timer if it isn't already stopped,
    /// because the timer may exhibit 'unpredictable behaviour' if it's frequency is changed while it's running.
    pub fn set_frequency(&self, frequency: Frequency) {
        self.stop();

        self.r
            .prescaler()
            // SAFETY: `frequency` is a variant of `Frequency`,
            // whose values are all in the range of 0-9 (the valid range of `prescaler`).
            .write(|w| w.set_prescaler(frequency as u8))
    }

    /// Returns this timer's `n`th CC register.
    ///
    /// # Panics
    /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
    pub fn cc(&self, n: usize) -> Cc<'d> {
        if n >= self.ccs {
            panic!("Cannot get CC register {} of timer with {} CC registers.", n, self.ccs);
        }
        Cc {
            n,
            r: self.r,
            _p: PhantomData,
        }
    }
}

impl Timer<'static> {
    /// Persist the timer's configuration for the rest of the program's lifetime. This method
    /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents
    /// accidental reuse of the underlying peripheral.
    pub fn persist(self) {
        core::mem::forget(self);
    }
}

View on GitHub (pinned to 463a07b963)