use core::convert::Infallible;
use embedded_hal::delay::DelayNs;
use embedded_hal::pwm::{ErrorType, SetDutyCycle};
use crate::gpio::{Alternate, Pin};
use crate::pac;
use crate::rcu::{Clocks, Enable, Rcu, Reset};
use crate::time::{Duration, Hertz, NanosDuration};
const MAX_COUNT: u32 = 1 << 16;
fn dividers(ticks: u32) -> (u16, u16) {
let ticks = ticks.max(1);
let psc = ticks.div_ceil(MAX_COUNT);
let car = ticks / psc;
((psc - 1) as u16, (car - 1) as u16)
}
fn interval_to_ticks<const NOM: u64, const DENOM: u64>(
interval: Duration<u32, NOM, DENOM>,
clock: Hertz,
) -> u32 {
let raw_time = u64::from(interval.as_ticks());
let raw_freq = u64::from(clock.to_Hz());
(raw_time.saturating_mul(raw_freq).saturating_mul(NOM) / DENOM).min(u32::MAX.into()) as u32
}
fn ticks_to_interval<const NOM: u64, const DENOM: u64>(
ticks: u16,
psc: u16,
clock: Hertz,
) -> Duration<u32, NOM, DENOM> {
let ticks = u64::from(ticks);
let psc = u64::from(psc);
let clock = u64::from(clock.to_Hz());
Duration::<u32, NOM, DENOM>::from_ticks(
(ticks.saturating_mul(psc + 1).saturating_mul(DENOM) / clock.saturating_mul(NOM))
.min(u32::MAX.into()) as u32,
)
}
fn start_counter<TIMERX: Instance>(timer: &mut TIMERX, psc: u16, car: u16) {
timer.set_psc(psc);
timer.set_car(car);
timer.set_ups(true);
timer.gen_update();
timer.set_cen(true);
}
fn wait_update<TIMERX: Instance>(timer: &mut TIMERX) {
while !timer.read_upif() {}
timer.clear_upif();
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Event {
Update,
}
fn set_listening<TIMERX: Instance>(timer: &mut TIMERX, event: Event, on: bool) {
match event {
Event::Update => timer.set_upie(on),
}
}
fn is_listening<TIMERX: Instance>(timer: &TIMERX, event: Event) -> bool {
match event {
Event::Update => timer.read_upie(),
}
}
fn is_pending<TIMERX: Instance>(timer: &TIMERX, event: Event) -> bool {
match event {
Event::Update => timer.read_upif(),
}
}
fn clear_pending<TIMERX: Instance>(timer: &mut TIMERX, event: Event) {
match event {
Event::Update => timer.clear_upif(),
}
}
pub trait Instance: Enable + Reset {
fn clk(clocks: &Clocks) -> Hertz;
fn set_psc(&mut self, psc: u16);
fn read_psc(&self) -> u16;
fn set_car(&mut self, car: u16);
fn read_car(&self) -> u16;
fn read_cnt(&self) -> u16;
fn gen_update(&mut self);
fn set_cen(&mut self, on: bool);
fn set_ups(&mut self, on: bool);
fn set_upie(&mut self, on: bool);
fn read_upie(&self) -> bool;
fn read_upif(&self) -> bool;
fn clear_upif(&mut self);
#[must_use]
unsafe fn steal(&self) -> Self;
}
macro_rules! timer_instance {
($($TIMERX:ty => $clk:ident,)+) => {
$(
impl Instance for $TIMERX {
#[inline]
fn clk(clocks: &Clocks) -> Hertz {
clocks.$clk()
}
#[inline]
fn set_psc(&mut self, psc: u16) {
self.psc().write(|w| w.psc().bits(psc));
}
#[inline]
fn read_psc(&self) -> u16 {
self.psc().read().psc().bits()
}
#[allow(unused_unsafe)]
#[inline]
fn set_car(&mut self, car: u16) {
self.car().write(|w| unsafe { w.car().bits(car) });
}
#[inline]
fn read_car(&self) -> u16 {
self.car().read().car().bits()
}
#[inline]
fn read_cnt(&self) -> u16 {
self.cnt().read().cnt().bits()
}
#[inline]
fn gen_update(&mut self) {
self.swevg().write(|w| w.upg().set_bit());
}
#[inline]
fn set_cen(&mut self, on: bool) {
self.ctl0().modify(|_, w| w.cen().bit(on));
}
#[inline]
fn set_ups(&mut self, on: bool) {
self.ctl0().modify(|_, w| w.ups().bit(on));
}
#[inline]
fn set_upie(&mut self, on: bool) {
self.dmainten().modify(|_, w| w.upie().bit(on));
}
#[inline]
fn read_upie(&self) -> bool {
self.dmainten().read().upie().bit_is_set()
}
#[inline]
fn read_upif(&self) -> bool {
self.intf().read().upif().bit_is_set()
}
#[inline]
fn clear_upif(&mut self) {
self.intf().modify(|_, w| w.upif().clear());
}
unsafe fn steal(&self) -> Self {
unsafe { Self::steal() }
}
}
)+
};
}
timer_instance! {
pac::Timer2 => pclk1_tim,
pac::Timer5 => pclk1_tim,
pac::Timer13 => pclk1_tim,
pac::Timer0 => pclk2_tim,
pac::Timer15 => pclk2_tim,
pac::Timer16 => pclk2_tim,
}
#[cfg(has_timer14)]
timer_instance! {
pac::Timer14 => pclk2_tim,
}
pub struct Timer<TIMERX> {
timer: TIMERX,
clk: Hertz,
}
impl<TIMERX: Instance> Timer<TIMERX> {
pub fn release(self, rcu: &mut Rcu) -> TIMERX {
TIMERX::disable(rcu);
self.timer
}
pub fn start(mut self, psc: u16, car: u16) -> CountDownTimer<TIMERX> {
start_counter(&mut self.timer, psc, car);
CountDownTimer {
timer: self.timer,
clk: self.clk,
}
}
pub fn start_interval<const NOM: u64, const DENOM: u64>(
self,
interval: Duration<u32, NOM, DENOM>,
) -> CountDownTimer<TIMERX> {
let (psc, car) = dividers(interval_to_ticks(interval, self.clk));
self.start(psc, car)
}
pub fn into_delay(self) -> Delay<TIMERX> {
Delay {
timer: self.timer,
clk: self.clk,
}
}
pub fn into_pwm(mut self, psc: u16, car: u16) -> Pwm<TIMERX> {
start_counter(&mut self.timer, psc, car);
Pwm {
timer: self.timer,
clk: self.clk,
channels: 0,
}
}
pub fn into_pwm_interval<const NOM: u64, const DENOM: u64>(
self,
interval: Duration<u32, NOM, DENOM>,
) -> Pwm<TIMERX> {
let (psc, car) = dividers(interval_to_ticks(interval, self.clk));
self.into_pwm(psc, car)
}
pub fn into_capture(mut self, psc: u16) -> Capture<TIMERX> {
start_counter(&mut self.timer, psc, u16::MAX);
Capture {
timer: self.timer,
clk: self.clk,
channels: 0,
}
}
}
pub struct CountDownTimer<TIMERX> {
timer: TIMERX,
clk: Hertz,
}
impl<TIMERX: Instance> CountDownTimer<TIMERX> {
pub fn cnt(&self) -> u16 {
self.timer.read_cnt()
}
pub fn car(&self) -> u16 {
self.timer.read_car()
}
pub fn psc(&self) -> u16 {
self.timer.read_psc()
}
pub fn elapsed<const NOM: u64, const DENOM: u64>(&self) -> Duration<u32, NOM, DENOM> {
ticks_to_interval(self.cnt(), self.psc(), self.clk)
}
pub fn listen(&mut self, event: Event) {
set_listening(&mut self.timer, event, true);
}
pub fn unlisten(&mut self, event: Event) {
set_listening(&mut self.timer, event, false);
}
pub fn is_listening(&self, event: Event) -> bool {
is_listening(&self.timer, event)
}
pub fn is_pending(&self, event: Event) -> bool {
is_pending(&self.timer, event)
}
pub fn clear_interrupt(&mut self, event: Event) {
clear_pending(&mut self.timer, event);
}
pub fn wait(&mut self) {
wait_update(&mut self.timer);
}
pub fn stop(mut self) -> Timer<TIMERX> {
self.unlisten(Event::Update);
self.timer.set_cen(false);
Timer {
timer: self.timer,
clk: self.clk,
}
}
pub fn release(self, rcu: &mut Rcu) -> TIMERX {
self.stop().release(rcu)
}
}
pub struct Delay<TIMERX> {
timer: TIMERX,
clk: Hertz,
}
impl<TIMERX: Instance> Delay<TIMERX> {
pub fn delay<const NOM: u64, const DENOM: u64>(&mut self, interval: Duration<u32, NOM, DENOM>) {
let (psc, car) = dividers(interval_to_ticks(interval, self.clk));
start_counter(&mut self.timer, psc, car);
wait_update(&mut self.timer);
self.timer.set_cen(false);
}
pub fn into_timer(self) -> Timer<TIMERX> {
Timer {
timer: self.timer,
clk: self.clk,
}
}
pub fn release(self, rcu: &mut Rcu) -> TIMERX {
self.into_timer().release(rcu)
}
}
pub struct Pwm<TIMERX> {
timer: TIMERX,
clk: Hertz,
channels: u8,
}
impl<TIMERX: Instance> Pwm<TIMERX> {
pub fn channel<PIN, const C: u8>(&mut self, pin: PIN) -> PwmChannel<TIMERX, PIN, C>
where
PIN: ChannelPin<TIMERX, C>,
TIMERX: PwmOps<C>,
{
self.timer.apply_pwm_mode();
self.channels += 1;
PwmChannel {
timer: unsafe { self.timer.steal() },
pin,
}
}
pub fn release_channel<PIN, const C: u8>(
&mut self,
mut channel: PwmChannel<TIMERX, PIN, C>,
) -> PIN
where
PIN: ChannelPin<TIMERX, C>,
TIMERX: PwmOps<C>,
{
channel.unlisten();
channel.disable();
self.channels -= 1;
channel.pin
}
pub fn listen(&mut self, event: Event) {
set_listening(&mut self.timer, event, true);
}
pub fn unlisten(&mut self, event: Event) {
set_listening(&mut self.timer, event, false);
}
pub fn is_listening(&self, event: Event) -> bool {
is_listening(&self.timer, event)
}
pub fn is_pending(&self, event: Event) -> bool {
is_pending(&self.timer, event)
}
pub fn clear_interrupt(&mut self, event: Event) {
clear_pending(&mut self.timer, event);
}
pub fn set_period(&mut self, psc: u16, car: u16) {
self.timer.set_psc(psc);
self.timer.set_car(car);
}
pub fn set_period_interval<const NOM: u64, const DENOM: u64>(
&mut self,
interval: Duration<u32, NOM, DENOM>,
) {
let (psc, car) = dividers(interval_to_ticks(interval, self.clk));
self.set_period(psc, car);
}
pub fn into_timer(mut self) -> Timer<TIMERX> {
assert!(self.channels == 0, "PWM channels still handed out");
self.unlisten(Event::Update);
self.timer.set_cen(false);
Timer {
timer: self.timer,
clk: self.clk,
}
}
pub fn release(self, rcu: &mut Rcu) -> TIMERX {
self.into_timer().release(rcu)
}
pub fn try_release(self, rcu: &mut Rcu) -> Result<TIMERX, Self> {
if self.channels == 0 {
Ok(self.release(rcu))
} else {
Err(self)
}
}
}
impl<TIMERX> Pwm<TIMERX>
where
TIMERX: PrimaryOutput,
{
pub fn enable_output(&mut self) {
self.timer.set_poen(true);
}
pub fn disable_output(&mut self) {
self.timer.set_poen(false);
}
}
pub struct Capture<TIMERX> {
timer: TIMERX,
clk: Hertz,
channels: u8,
}
impl<TIMERX: Instance> Capture<TIMERX> {
pub fn channel<PIN, const C: u8>(
&mut self,
pin: PIN,
edge: Edge,
) -> CaptureChannel<TIMERX, PIN, C>
where
PIN: ChannelPin<TIMERX, C>,
TIMERX: CaptureOps<C>,
{
self.timer.apply_capture_mode();
self.timer.select_edge(edge);
self.channels += 1;
CaptureChannel {
timer: unsafe { self.timer.steal() },
pin,
clk: self.clk,
}
}
pub fn release_channel<PIN, const C: u8>(
&mut self,
mut channel: CaptureChannel<TIMERX, PIN, C>,
) -> PIN
where
PIN: ChannelPin<TIMERX, C>,
TIMERX: CaptureOps<C>,
{
channel.unlisten();
channel.disable();
self.channels -= 1;
channel.pin
}
pub fn listen(&mut self, event: Event) {
set_listening(&mut self.timer, event, true);
}
pub fn unlisten(&mut self, event: Event) {
set_listening(&mut self.timer, event, false);
}
pub fn is_listening(&self, event: Event) -> bool {
is_listening(&self.timer, event)
}
pub fn is_pending(&self, event: Event) -> bool {
is_pending(&self.timer, event)
}
pub fn clear_interrupt(&mut self, event: Event) {
clear_pending(&mut self.timer, event);
}
pub fn into_timer(mut self) -> Timer<TIMERX> {
assert!(self.channels == 0, "capture channels still handed out");
self.unlisten(Event::Update);
self.timer.set_cen(false);
Timer {
timer: self.timer,
clk: self.clk,
}
}
pub fn release(self, rcu: &mut Rcu) -> TIMERX {
self.into_timer().release(rcu)
}
pub fn try_release(self, rcu: &mut Rcu) -> Result<TIMERX, Self> {
if self.channels == 0 {
Ok(self.release(rcu))
} else {
Err(self)
}
}
}
impl<TIMERX: Instance> DelayNs for Delay<TIMERX> {
fn delay_ns(&mut self, ns: u32) {
self.delay(NanosDuration::from_nanos(ns));
}
}
pub trait TimerExt: Sized {
fn constrain(self, rcu: &mut Rcu) -> Timer<Self>;
}
impl<TIMERX: Instance> TimerExt for TIMERX {
fn constrain(self, rcu: &mut Rcu) -> Timer<Self> {
let clocks = rcu.clocks();
TIMERX::enable(rcu);
TIMERX::reset(rcu);
Timer {
timer: self,
clk: TIMERX::clk(&clocks),
}
}
}
pub trait ChannelEnable<const C: u8>: Instance {
fn set_chxen(&mut self, on: bool);
fn set_chxie(&mut self, on: bool);
fn read_chxie(&self) -> bool;
fn read_chxif(&self) -> bool;
fn clear_chxif(&mut self);
}
macro_rules! channel_enable {
{$($Timer:ty => [$($Ch:literal$(,)?)+]$(,)?)+} => {
paste::paste! { $($(impl ChannelEnable<$Ch> for $Timer {
fn set_chxen(&mut self, on: bool) {
self.chctl2().modify(|_, w| match on {
true => w.[<ch $Ch en>]().enabled(),
false => w.[<ch $Ch en>]().disabled(),
})
}
fn set_chxie(&mut self, on: bool) {
self.dmainten().modify(|_, w| w.[<ch $Ch ie>]().bit(on));
}
fn read_chxie(&self) -> bool {
self.dmainten().read().[<ch $Ch ie>]().bit_is_set()
}
fn read_chxif(&self) -> bool {
self.intf().read().[<ch $Ch if>]().bit_is_set()
}
fn clear_chxif(&mut self) {
self.intf().modify(|_, w| w.[<ch $Ch if>]().clear())
}
})+)+ }
};
}
channel_enable! {
pac::Timer0 => [0, 1, 2, 3],
pac::Timer2 => [0, 1, 2, 3],
pac::Timer13 => [0],
pac::Timer15 => [0],
pac::Timer16 => [0]
}
#[cfg(has_timer14)]
channel_enable! {
pac::Timer14 => [0, 1]
}
pub trait PwmOps<const C: u8>: ChannelEnable<C> {
fn apply_pwm_mode(&mut self);
fn set_chxcv(&mut self, cv: u16);
}
macro_rules! pwm {
{$($Timer:ty => [
$(
($Ch:literal, $chctl_reg:ident)$(,)?
)+]$(,)?)+
} => {
paste::paste! { $($(impl PwmOps<$Ch> for $Timer {
fn apply_pwm_mode(&mut self) {
self.chctl2().modify(|_, w| w.[<ch $Ch p>]().not_inverted());
self.$chctl_reg().modify(|_, w| {
w.[<ch $Ch ms>]()
.output()
.[<ch $Ch comctl>]()
.pwm_mode0()
.[<ch $Ch comsen>]()
.enabled()
});
}
#[allow(unused_unsafe)]
fn set_chxcv(&mut self, cv: u16) {
self.[<ch $Ch cv>]().write(|w| unsafe { w.[<ch $Ch val>]().bits(cv) });
}
})+)+ }
};
}
pwm! {
pac::Timer0 => [(0, chctl0_output), (1, chctl0_output),
(2, chctl1_output), (3, chctl1_output)],
pac::Timer2 => [(0, chctl0_output), (1, chctl0_output),
(2, chctl1_output), (3, chctl1_output)],
pac::Timer13 => [(0, chctl0_output)],
pac::Timer15 => [(0, chctl0_output)],
pac::Timer16 => [(0, chctl0_output)]
}
#[cfg(has_timer14)]
pwm! {
pac::Timer14 => [(0, chctl0_output), (1, chctl0_output)]
}
pub trait PrimaryOutput: Instance {
fn set_poen(&mut self, on: bool);
}
macro_rules! poen {
($($Timer:ty$(,)?)+) => {
$(impl PrimaryOutput for $Timer {
fn set_poen(&mut self, on: bool) {
self.cchp().modify(|_, w| match on {
true => w.poen().enabled(),
false => w.poen().disabled(),
});
}
})+
};
}
poen!(pac::Timer0, pac::Timer15, pac::Timer16);
#[cfg(has_timer14)]
poen!(pac::Timer14);
pub trait ChannelPin<TIMERX, const C: u8> {}
macro_rules! channel_pins {
( $( $TIMERX:ty: $( $C:literal: [ $($(#[$cfg:meta])? $p:literal $n:literal : $af:literal),* $(,)? ] )* ),* $(,)? ) => {
$($($( $(#[$cfg])? impl ChannelPin<$TIMERX, $C> for Pin<$p, $n, Alternate<$af>> {} )*)*)*
};
}
channel_pins! {
pac::Timer0:
0: [ #[cfg(pads_ge_24)] 'A' 8:2 ]
1: [ 'A' 9:2 ]
2: [ 'A' 10:2 ]
3: [ #[cfg(pads_ge_lqfp32)] 'A' 11:2 ],
pac::Timer2:
0: [ 'A' 6:1, #[cfg(pads_ge_28)] 'B' 4:1 ]
1: [ 'A' 7:1, #[cfg(pads_ge_28)] 'B' 5:1 ]
2: [ #[cfg(pads_ge_24)] 'B' 0:1 ]
3: [ 'B' 1:1 ],
pac::Timer13:
0: [ 'A' 4:4, 'A' 7:4, 'B' 1:2 ],
pac::Timer15:
0: [ 'A' 6:5, #[cfg(pads_ge_qfn32)] 'B' 8:2 ],
pac::Timer16:
0: [ 'A' 7:5, #[cfg(pads_ge_48)] 'B' 9:2 ],
}
#[cfg(has_timer14)]
channel_pins! {
pac::Timer14:
0: [ 'A' 2:0, #[cfg(pads_ge_48)] 'B' 14:1 ]
1: [ 'A' 3:0, #[cfg(pads_ge_48)] 'B' 15:1 ],
}
pub struct PwmChannel<TIMERX, PIN, const C: u8> {
timer: TIMERX,
pin: PIN,
}
impl<TIMERX: PwmOps<C>, PIN: ChannelPin<TIMERX, C>, const C: u8> PwmChannel<TIMERX, PIN, C> {
pub fn enable(&mut self) {
self.timer.set_chxen(true);
}
pub fn disable(&mut self) {
self.timer.set_chxen(false);
}
pub fn set_duty(&mut self, cv: u16) {
self.timer.set_chxcv(cv);
}
pub fn max_duty(&self) -> u16 {
self.timer.read_car().saturating_add(1)
}
pub fn listen(&mut self) {
self.timer.set_chxie(true);
}
pub fn unlisten(&mut self) {
self.timer.set_chxie(false);
}
pub fn is_listening(&self) -> bool {
self.timer.read_chxie()
}
pub fn is_pending(&self) -> bool {
self.timer.read_chxif()
}
pub fn clear_interrupt(&mut self) {
self.timer.clear_chxif();
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
Overcapture,
}
pub struct CaptureChannel<TIMERX, PIN, const C: u8> {
timer: TIMERX,
pin: PIN,
clk: Hertz,
}
impl<TIMERX: CaptureOps<C>, PIN: ChannelPin<TIMERX, C>, const C: u8>
CaptureChannel<TIMERX, PIN, C>
{
pub fn enable(&mut self) {
self.timer.set_chxen(true);
}
pub fn disable(&mut self) {
self.timer.set_chxen(false);
}
pub fn select_edge(&mut self, edge: Edge) {
self.timer.select_edge(edge);
}
pub fn listen(&mut self) {
self.timer.set_chxie(true);
}
pub fn unlisten(&mut self) {
self.timer.set_chxie(false);
}
pub fn is_listening(&self) -> bool {
self.timer.read_chxie()
}
pub fn is_pending(&self) -> bool {
self.timer.read_chxif()
}
pub fn read(&mut self) -> nb::Result<u16, Error> {
if !self.timer.read_chxif() {
return Err(nb::Error::WouldBlock);
}
let cv = self.timer.read_chxcv();
let lost = self.timer.read_chxof();
self.timer.clear_chxif();
if lost {
self.timer.clear_chxof();
Err(nb::Error::Other(Error::Overcapture))
} else {
Ok(cv)
}
}
pub fn interval<const NOM: u64, const DENOM: u64>(
&self,
from: u16,
to: u16,
) -> Duration<u32, NOM, DENOM> {
ticks_to_interval(to.wrapping_sub(from), self.timer.read_psc(), self.clk)
}
}
impl<TIMERX: PwmOps<C>, PIN: ChannelPin<TIMERX, C>, const C: u8> ErrorType
for PwmChannel<TIMERX, PIN, C>
{
type Error = Infallible;
}
impl<TIMERX: PwmOps<C>, PIN: ChannelPin<TIMERX, C>, const C: u8> SetDutyCycle
for PwmChannel<TIMERX, PIN, C>
{
fn max_duty_cycle(&self) -> u16 {
self.max_duty()
}
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
self.set_duty(duty);
Ok(())
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(missing_docs)]
pub enum Edge {
Rising,
Falling,
}
pub trait CaptureOps<const C: u8>: ChannelEnable<C> {
fn apply_capture_mode(&mut self);
fn select_edge(&mut self, edge: Edge);
fn read_chxcv(&self) -> u16;
fn read_chxof(&self) -> bool;
fn clear_chxof(&mut self);
}
macro_rules! capture {
{$($Timer:ty => [
$(
($Ch:literal, $chctl_reg:ident $(, $chnp:ident)?)$(,)?
)+]$(,)?)+
} => {
paste::paste! { $($(impl CaptureOps<$Ch> for $Timer {
fn apply_capture_mode(&mut self) {
$(self.chctl2().modify(|_, w| w.$chnp().not_inverted());)?
self.$chctl_reg().modify(|_, w| {
w.[<ch $Ch ms>]()
.ci0()
.[<ch $Ch capflt>]()
.no_filter()
.[<ch $Ch cappsc>]()
.div1()
})
}
fn select_edge(&mut self, edge: Edge) {
self.chctl2().modify(|_, w| match edge {
Edge::Rising => w.[<ch $Ch p>]().not_inverted(),
Edge::Falling => w.[<ch $Ch p>]().inverted()
})
}
fn read_chxcv(&self) -> u16 {
self.[<ch $Ch cv>]().read().[<ch $Ch val>]().bits()
}
fn read_chxof(&self) -> bool {
self.intf().read().[<ch $Ch of>]().bit_is_set()
}
fn clear_chxof(&mut self) {
self.intf().modify(|_, w| w.[<ch $Ch of>]().clear())
}
})+)+ }
};
}
capture! {
pac::Timer0 => [(0, chctl0_input, ch0np), (1, chctl0_input, ch1np),
(2, chctl1_input, ch2np), (3, chctl1_input)],
pac::Timer2 => [(0, chctl0_input, ch0np), (1, chctl0_input, ch1np),
(2, chctl1_input, ch2np), (3, chctl1_input)],
pac::Timer13 => [(0, chctl0_input, ch0np)],
pac::Timer15 => [(0, chctl0_input, ch0np)],
pac::Timer16 => [(0, chctl0_input, ch0np)]
}
#[cfg(has_timer14)]
capture! {
pac::Timer14 => [(0, chctl0_input, ch0np), (1, chctl0_input, ch1np)]
}