Skip to main content

vorago_shared_hal/timer/
mod.rs

1pub mod regs;
2
3use core::convert::Infallible;
4
5#[cfg(feature = "vor1x")]
6pub use crate::InterruptConfig;
7#[cfg(feature = "vor1x")]
8use crate::sysconfig::enable_peripheral_clock;
9pub use regs::{CascadeSource, InvalidTimerIndex, TimId};
10
11use crate::{enable_nvic_interrupt, sealed::Sealed, time::Hertz};
12use crate::{gpio::DynPinId, ioconfig::regs::FunctionSelect, pins::AnyPin};
13use fugit::RateExtU32;
14
15#[cfg(feature = "vor1x")]
16use crate::PeripheralSelect;
17
18#[cfg(feature = "vor1x")]
19use va108xx as pac;
20#[cfg(feature = "vor4x")]
21use va416xx as pac;
22
23#[cfg(feature = "vor4x")]
24pub const TIM_IRQ_OFFSET: usize = 48;
25
26//==================================================================================================
27// Defintions
28//==================================================================================================
29
30#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub struct CascadeControl {
33    /// Enable Cascade 0 signal active as a requirement for counting
34    pub enable_src_0: bool,
35    /// Invert Cascade 0, making it active low
36    pub inv_src_0: regs::CascadeInvert,
37    /// Enable Cascade 1 signal active as a requirement for counting
38    pub enable_src_1: bool,
39    /// Invert Cascade 1, making it active low
40    pub inv_src_1: regs::CascadeInvert,
41    /// Specify required operation if both Cascade 0 and Cascade 1 are active.
42    /// 0 is a logical AND of both cascade signals, 1 is a logical OR
43    pub dual_operation: regs::DualCascadeOp,
44    /// Enable trigger mode for Cascade 0. In trigger mode, couting will start with the selected
45    /// cascade signal active, but once the counter is active, cascade control will be ignored
46    pub trigger_mode_0: bool,
47    /// Trigger mode, identical to [Self::trigger_mode_0] but for Cascade 1
48    pub trigger_mode_1: bool,
49    /// Enable Cascade 2 signal active as a requirement to stop counting. This mode is similar
50    /// to the REQ_STOP control bit, but signalled by a Cascade source
51    pub enable_stop_src_2: bool,
52    /// Invert Cascade 2, making it active low
53    pub inv_src_2: regs::CascadeInvert,
54    /// The counter is automatically disabled if the corresponding Cascade 2 level-sensitive input
55    /// souce is active when the count reaches 0. If the counter is not 0, the cascade control is
56    /// ignored
57    pub trigger_mode_2: bool,
58}
59
60#[derive(Debug, PartialEq, Eq)]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62pub enum CascadeSelect {
63    Csd0 = 0,
64    Csd1 = 1,
65    Csd2 = 2,
66}
67
68//==================================================================================================
69// Valid TIM and PIN combinations
70//==================================================================================================
71
72macro_rules! define_tim_pin_traits {
73    ([$(($tim_name:ident, $index:expr)),* $(,)?]) => {
74        $(
75            pub trait $tim_name: AnyPin {
76                const PIN_ID: DynPinId;
77                const FUNC_SEL: FunctionSelect;
78                const TIM_ID: TimId = TimId::new_unchecked($index);
79            }
80        )*
81    };
82}
83
84define_tim_pin_traits!([
85    (Tim0Pin, 0),
86    (Tim1Pin, 1),
87    (Tim2Pin, 2),
88    (Tim3Pin, 3),
89    (Tim4Pin, 4),
90    (Tim5Pin, 5),
91    (Tim6Pin, 6),
92    (Tim7Pin, 7),
93    (Tim8Pin, 8),
94    (Tim9Pin, 9),
95    (Tim10Pin, 10),
96    (Tim11Pin, 11),
97    (Tim12Pin, 12),
98    (Tim13Pin, 13),
99    (Tim14Pin, 14),
100    (Tim15Pin, 15),
101    (Tim16Pin, 16),
102    (Tim17Pin, 17),
103    (Tim18Pin, 18),
104    (Tim19Pin, 19),
105    (Tim20Pin, 20),
106    (Tim21Pin, 21),
107    (Tim22Pin, 22),
108    (Tim23Pin, 23),
109]);
110
111pub trait TimInstance: Sealed {
112    const ID: TimId;
113
114    #[cfg(feature = "vor4x")]
115    const IRQ: va416xx::Interrupt;
116
117    #[cfg(feature = "vor4x")]
118    fn clock(clocks: &crate::clock::Clocks) -> Hertz {
119        if Self::ID.value() < 16 {
120            clocks.apb1()
121        } else {
122            clocks.apb2()
123        }
124    }
125}
126
127pub trait Tim0Instance: TimInstance {}
128pub trait Tim1Instance: TimInstance {}
129pub trait Tim2Instance: TimInstance {}
130pub trait Tim3Instance: TimInstance {}
131pub trait Tim4Instance: TimInstance {}
132pub trait Tim5Instance: TimInstance {}
133pub trait Tim6Instance: TimInstance {}
134pub trait Tim7Instance: TimInstance {}
135pub trait Tim8Instance: TimInstance {}
136pub trait Tim9Instance: TimInstance {}
137pub trait Tim10Instance: TimInstance {}
138pub trait Tim11Instance: TimInstance {}
139pub trait Tim12Instance: TimInstance {}
140pub trait Tim13Instance: TimInstance {}
141pub trait Tim14Instance: TimInstance {}
142pub trait Tim15Instance: TimInstance {}
143pub trait Tim16Instance: TimInstance {}
144pub trait Tim17Instance: TimInstance {}
145pub trait Tim18Instance: TimInstance {}
146pub trait Tim19Instance: TimInstance {}
147pub trait Tim20Instance: TimInstance {}
148pub trait Tim21Instance: TimInstance {}
149pub trait Tim22Instance: TimInstance {}
150pub trait Tim23Instance: TimInstance {}
151
152macro_rules! tim_marker {
153    ($TIMX:path, $Trait:ident, $ID:expr) => {
154        impl Sealed for $TIMX {}
155
156        impl TimInstance for $TIMX {
157            const ID: TimId = TimId::new_unchecked($ID);
158        }
159
160        impl $Trait for $TIMX {}
161    };
162    ($TIMX:path, $Trait:ident, $ID:expr, $IrqId:ident) => {
163        impl Sealed for $TIMX {}
164
165        impl TimInstance for $TIMX {
166            const ID: TimId = TimId::new_unchecked($ID);
167            const IRQ: va416xx::Interrupt = va416xx::Interrupt::$IrqId;
168        }
169
170        impl $Trait for $TIMX {}
171    };
172}
173
174cfg_if::cfg_if! {
175    if #[cfg(feature = "vor1x")] {
176        tim_marker!(pac::Tim0, Tim0Instance, 0);
177        tim_marker!(pac::Tim1, Tim1Instance, 1);
178        tim_marker!(pac::Tim2, Tim2Instance, 2);
179        tim_marker!(pac::Tim3, Tim3Instance, 3);
180        tim_marker!(pac::Tim4, Tim4Instance, 4);
181        tim_marker!(pac::Tim5, Tim5Instance, 5);
182        tim_marker!(pac::Tim6, Tim6Instance, 6);
183        tim_marker!(pac::Tim7, Tim7Instance, 7);
184        tim_marker!(pac::Tim8, Tim8Instance, 8);
185        tim_marker!(pac::Tim9, Tim9Instance, 9);
186        tim_marker!(pac::Tim10, Tim10Instance, 10);
187        tim_marker!(pac::Tim11, Tim11Instance, 11);
188        tim_marker!(pac::Tim12, Tim12Instance, 12);
189        tim_marker!(pac::Tim13, Tim13Instance, 13);
190        tim_marker!(pac::Tim14, Tim14Instance, 14);
191        tim_marker!(pac::Tim15, Tim15Instance, 15);
192        tim_marker!(pac::Tim16, Tim16Instance, 16);
193        tim_marker!(pac::Tim17, Tim17Instance, 17);
194        tim_marker!(pac::Tim18, Tim18Instance, 18);
195        tim_marker!(pac::Tim19, Tim19Instance, 19);
196        tim_marker!(pac::Tim20, Tim20Instance, 20);
197        tim_marker!(pac::Tim21, Tim21Instance, 21);
198        tim_marker!(pac::Tim22, Tim22Instance, 22);
199        tim_marker!(pac::Tim23, Tim23Instance, 23);
200    } else if #[cfg(feature = "vor4x")] {
201        tim_marker!(pac::Tim0, Tim0Instance, 0, TIM0);
202        tim_marker!(pac::Tim1, Tim1Instance, 1, TIM1);
203        tim_marker!(pac::Tim2, Tim2Instance, 2, TIM2);
204        tim_marker!(pac::Tim3, Tim3Instance, 3, TIM3);
205        tim_marker!(pac::Tim4, Tim4Instance, 4, TIM4);
206        tim_marker!(pac::Tim5, Tim5Instance, 5, TIM5);
207        tim_marker!(pac::Tim6, Tim6Instance, 6, TIM6);
208        tim_marker!(pac::Tim7, Tim7Instance, 7, TIM7);
209        tim_marker!(pac::Tim8, Tim8Instance, 8, TIM8);
210        tim_marker!(pac::Tim9, Tim9Instance, 9, TIM9);
211        tim_marker!(pac::Tim10, Tim10Instance, 10, TIM10);
212        tim_marker!(pac::Tim11, Tim11Instance, 11, TIM11);
213        tim_marker!(pac::Tim12, Tim12Instance, 12, TIM12);
214        tim_marker!(pac::Tim13, Tim13Instance, 13, TIM13);
215        tim_marker!(pac::Tim14, Tim14Instance, 14, TIM14);
216        tim_marker!(pac::Tim15, Tim15Instance, 15, TIM15);
217        tim_marker!(pac::Tim16, Tim16Instance, 16, TIM16);
218        tim_marker!(pac::Tim17, Tim17Instance, 17, TIM17);
219        tim_marker!(pac::Tim18, Tim18Instance, 18, TIM18);
220        tim_marker!(pac::Tim19, Tim19Instance, 19, TIM19);
221        tim_marker!(pac::Tim20, Tim20Instance, 20, TIM20);
222        tim_marker!(pac::Tim21, Tim21Instance, 21, TIM21);
223        tim_marker!(pac::Tim22, Tim22Instance, 22, TIM22);
224        tim_marker!(pac::Tim23, Tim23Instance, 23, TIM23);
225    }
226}
227
228pub trait ValidTimAndPin0<Pin: Tim0Pin, Tim: Tim0Instance>: Sealed {}
229pub trait ValidTimAndPin1<Pin: Tim1Pin, Tim: Tim1Instance>: Sealed {}
230pub trait ValidTimAndPin2<Pin: Tim2Pin, Tim: Tim2Instance>: Sealed {}
231pub trait ValidTimAndPin3<Pin: Tim3Pin, Tim: Tim3Instance>: Sealed {}
232pub trait ValidTimAndPin4<Pin: Tim4Pin, Tim: Tim4Instance>: Sealed {}
233pub trait ValidTimAndPin5<Pin: Tim5Pin, Tim: Tim5Instance>: Sealed {}
234pub trait ValidTimAndPin6<Pin: Tim6Pin, Tim: Tim6Instance>: Sealed {}
235pub trait ValidTimAndPin7<Pin: Tim7Pin, Tim: Tim7Instance>: Sealed {}
236pub trait ValidTimAndPin8<Pin: Tim8Pin, Tim: Tim8Instance>: Sealed {}
237pub trait ValidTimAndPin9<Pin: Tim9Pin, Tim: Tim9Instance>: Sealed {}
238pub trait ValidTimAndPin10<Pin: Tim10Pin, Tim: Tim10Instance>: Sealed {}
239pub trait ValidTimAndPin11<Pin: Tim11Pin, Tim: Tim11Instance>: Sealed {}
240pub trait ValidTimAndPin12<Pin: Tim12Pin, Tim: Tim12Instance>: Sealed {}
241pub trait ValidTimAndPin13<Pin: Tim13Pin, Tim: Tim13Instance>: Sealed {}
242pub trait ValidTimAndPin14<Pin: Tim14Pin, Tim: Tim14Instance>: Sealed {}
243pub trait ValidTimAndPin15<Pin: Tim15Pin, Tim: Tim15Instance>: Sealed {}
244pub trait ValidTimAndPin16<Pin: Tim16Pin, Tim: Tim16Instance>: Sealed {}
245pub trait ValidTimAndPin17<Pin: Tim17Pin, Tim: Tim17Instance>: Sealed {}
246pub trait ValidTimAndPin18<Pin: Tim18Pin, Tim: Tim18Instance>: Sealed {}
247pub trait ValidTimAndPin19<Pin: Tim19Pin, Tim: Tim19Instance>: Sealed {}
248pub trait ValidTimAndPin20<Pin: Tim20Pin, Tim: Tim20Instance>: Sealed {}
249pub trait ValidTimAndPin21<Pin: Tim21Pin, Tim: Tim21Instance>: Sealed {}
250pub trait ValidTimAndPin22<Pin: Tim22Pin, Tim: Tim22Instance>: Sealed {}
251pub trait ValidTimAndPin23<Pin: Tim23Pin, Tim: Tim23Instance>: Sealed {}
252
253#[macro_use]
254mod macros {
255    macro_rules! pin_and_tim {
256        ($Px:ident, $FunSel:path, $ID:expr) => {
257            paste::paste! {
258                impl [<Tim $ID Pin>] for crate::pins::Pin<$Px>
259                where
260                    $Px: crate::pins::PinId,
261                {
262                    const PIN_ID: crate::pins::DynPinId = $Px::ID;
263                    const FUNC_SEL: crate::FunctionSelect = $FunSel;
264                    const TIM_ID: crate::timer::TimId = crate::timer::TimId::new_unchecked($ID);
265                }
266            }
267        };
268    }
269}
270
271#[cfg(feature = "vor1x")]
272pub mod pins_vor1x;
273#[cfg(feature = "vor4x")]
274pub mod pins_vor4x;
275
276//==================================================================================================
277// Timers
278//==================================================================================================
279
280/// Hardware timers
281pub struct CountdownTimer {
282    id: TimId,
283    regs: regs::MmioTimer<'static>,
284    curr_freq: Hertz,
285    ref_clk: Hertz,
286    rst_val: u32,
287    last_cnt: u32,
288}
289
290impl CountdownTimer {
291    /// Create a countdown timer structure for a given TIM peripheral.
292    ///
293    /// This does not enable the timer. You can use the [Self::load], [Self::start],
294    /// [Self::enable_interrupt] and [Self::enable] API to set up and configure the countdown
295    /// timer.
296    #[cfg(feature = "vor1x")]
297    pub fn new<Tim: TimInstance>(_tim: Tim, sys_clk: Hertz) -> Self {
298        enable_tim_clk(Tim::ID);
299        assert_tim_reset_for_cycles(Tim::ID, 2);
300        CountdownTimer {
301            id: Tim::ID,
302            regs: regs::Timer::new_mmio(Tim::ID),
303            ref_clk: sys_clk,
304            rst_val: 0,
305            curr_freq: 0.Hz(),
306            last_cnt: 0,
307        }
308    }
309
310    /// Create a countdown timer structure for a given TIM peripheral.
311    ///
312    /// This does not enable the timer. You can use the [Self::load], [Self::start],
313    /// [Self::enable_interrupt] and [Self::enable] API to set up and configure the countdown
314    /// timer.
315    #[cfg(feature = "vor4x")]
316    pub fn new<Tim: TimInstance>(_tim: Tim, clks: &crate::clock::Clocks) -> Self {
317        enable_tim_clk(Tim::ID);
318        assert_tim_reset_for_cycles(Tim::ID, 2);
319        CountdownTimer {
320            id: Tim::ID,
321            regs: regs::Timer::new_mmio(Tim::ID),
322            ref_clk: clks.apb1(),
323            rst_val: 0,
324            curr_freq: 0.Hz(),
325            last_cnt: 0,
326        }
327    }
328
329    #[inline]
330    pub fn perid(&self) -> u32 {
331        self.regs.read_perid()
332    }
333
334    #[inline(always)]
335    pub fn enable(&mut self) {
336        self.regs
337            .write_enable_control(regs::EnableControl::new_enable());
338    }
339    #[inline(always)]
340    pub fn disable(&mut self) {
341        self.regs
342            .write_enable_control(regs::EnableControl::new_disable());
343    }
344
345    #[cfg(feature = "vor1x")]
346    pub fn enable_interrupt(&mut self, irq_cfg: InterruptConfig) {
347        if irq_cfg.route {
348            let irqsel = unsafe { pac::Irqsel::steal() };
349            enable_peripheral_clock(PeripheralSelect::Irqsel);
350            irqsel
351                .tim(self.id.value() as usize)
352                .write(|w| unsafe { w.bits(irq_cfg.id as u32) });
353        }
354        if irq_cfg.enable_in_nvic {
355            unsafe { enable_nvic_interrupt(irq_cfg.id) };
356        }
357        self.regs.modify_control(|mut value| {
358            value.set_irq_enable(true);
359            value
360        });
361    }
362
363    #[cfg(feature = "vor4x")]
364    #[inline(always)]
365    pub fn enable_interrupt(&mut self, enable_in_nvic: bool) {
366        if enable_in_nvic {
367            unsafe { enable_nvic_interrupt(self.id.interrupt_id()) };
368        }
369        self.regs.modify_control(|mut value| {
370            value.set_irq_enable(true);
371            value
372        });
373    }
374
375    /// This function only clears the interrupt enable bit.
376    ///
377    /// It does not mask the interrupt in the NVIC or un-route the IRQ.
378    #[inline(always)]
379    pub fn disable_interrupt(&mut self) {
380        self.regs.modify_control(|mut value| {
381            value.set_irq_enable(false);
382            value
383        });
384    }
385
386    /// Calls [Self::load] to configure the specified frequency and then calls [Self::enable].
387    pub fn start(&mut self, frequency: impl Into<Hertz>) {
388        self.load(frequency);
389        self.enable();
390    }
391
392    /// Return `Ok` if the timer has wrapped. Peripheral will automatically clear the
393    /// flag and restart the time if configured correctly
394    pub fn wait(&mut self) -> nb::Result<(), Infallible> {
395        let cnt = self.counter();
396        if (cnt > self.last_cnt) || cnt == 0 {
397            self.last_cnt = self.rst_val;
398            Ok(())
399        } else {
400            self.last_cnt = cnt;
401            Err(nb::Error::WouldBlock)
402        }
403    }
404
405    /// Load the count down timer with a timeout but do not start it.
406    pub fn load(&mut self, timeout: impl Into<Hertz>) {
407        self.disable();
408        self.curr_freq = timeout.into();
409        self.rst_val = self.ref_clk.to_raw() / self.curr_freq.to_raw();
410        self.set_reload(self.rst_val);
411        self.set_count(self.rst_val);
412    }
413
414    #[inline(always)]
415    pub fn set_reload(&mut self, val: u32) {
416        self.regs.write_reset_value(val);
417    }
418
419    #[inline(always)]
420    pub fn set_count(&mut self, val: u32) {
421        self.regs.write_count_value(val);
422    }
423
424    #[inline(always)]
425    pub fn counter(&self) -> u32 {
426        self.regs.read_count_value()
427    }
428
429    /// Disable the counter, setting both enable and active bit to 0
430    #[inline]
431    pub fn auto_disable(&mut self, enable: bool) {
432        self.regs.modify_control(|mut value| {
433            value.set_auto_disable(enable);
434            value
435        });
436    }
437
438    /// This option only applies when the Auto-Disable functionality is 0.
439    ///
440    /// The active bit is changed to 0 when count reaches 0, but the counter stays
441    /// enabled. When Auto-Disable is 1, Auto-Deactivate is implied
442    #[inline]
443    pub fn auto_deactivate(&mut self, enable: bool) {
444        self.regs.modify_control(|mut value| {
445            value.set_auto_deactivate(enable);
446            value
447        });
448    }
449
450    /// Configure the cascade parameters
451    pub fn cascade_control(&mut self, ctrl: CascadeControl) {
452        self.regs.write_cascade_control(
453            regs::CascadeControl::builder()
454                .with_trigger2(ctrl.trigger_mode_2)
455                .with_inv2(ctrl.inv_src_2)
456                .with_en2(ctrl.enable_stop_src_2)
457                .with_trigger1(ctrl.trigger_mode_1)
458                .with_trigger0(ctrl.trigger_mode_0)
459                .with_dual_cascade_op(ctrl.dual_operation)
460                .with_inv1(ctrl.inv_src_1)
461                .with_en1(ctrl.enable_src_1)
462                .with_inv0(ctrl.inv_src_0)
463                .with_en0(ctrl.enable_src_0)
464                .build(),
465        );
466    }
467
468    pub fn cascade_source(
469        &mut self,
470        cascade_index: CascadeSelect,
471        src: regs::CascadeSource,
472    ) -> Result<(), regs::InvalidCascadeSourceId> {
473        // Safety: Index range safe by enum values.
474        unsafe {
475            self.regs
476                .write_cascade_unchecked(cascade_index as usize, regs::CascadeSourceReg::new(src)?);
477        }
478        Ok(())
479    }
480
481    pub fn curr_freq(&self) -> Hertz {
482        self.curr_freq
483    }
484
485    /// Disables the TIM and the dedicated TIM clock.
486    pub fn stop_with_clock_disable(mut self) {
487        self.disable();
488        unsafe { pac::Sysconfig::steal() }
489            .tim_clk_enable()
490            .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.id.value())) });
491    }
492}
493
494//==================================================================================================
495// Delay implementations
496//==================================================================================================
497//
498impl embedded_hal::delay::DelayNs for CountdownTimer {
499    fn delay_ns(&mut self, ns: u32) {
500        let ticks = (u64::from(ns)) * (u64::from(self.ref_clk.to_raw())) / 1_000_000_000;
501
502        let full_cycles = ticks >> 32;
503        let mut last_count;
504        let mut new_count;
505        if full_cycles > 0 {
506            self.set_reload(u32::MAX);
507            self.set_count(u32::MAX);
508            self.enable();
509
510            for _ in 0..full_cycles {
511                // Always ensure that both values are the same at the start.
512                new_count = self.counter();
513                last_count = new_count;
514                loop {
515                    new_count = self.counter();
516                    if new_count == 0 {
517                        // Wait till timer has wrapped.
518                        while self.counter() == 0 {
519                            cortex_m::asm::nop()
520                        }
521                        break;
522                    }
523                    // Timer has definitely wrapped.
524                    if new_count > last_count {
525                        break;
526                    }
527                    last_count = new_count;
528                }
529            }
530        }
531        let ticks = (ticks & u32::MAX as u64) as u32;
532        self.disable();
533        if ticks > 1 {
534            self.set_reload(ticks);
535            self.set_count(ticks);
536            self.enable();
537            last_count = ticks;
538
539            loop {
540                new_count = self.counter();
541                if new_count == 0 || (new_count > last_count) {
542                    break;
543                }
544                last_count = new_count;
545            }
546        }
547
548        self.disable();
549    }
550}
551
552#[inline(always)]
553pub fn enable_tim_clk(id: TimId) {
554    unsafe { pac::Sysconfig::steal() }
555        .tim_clk_enable()
556        .modify(|r, w| unsafe { w.bits(r.bits() | (1 << id.value())) });
557}
558
559#[inline(always)]
560pub fn disable_tim_clk(id: TimId) {
561    unsafe { pac::Sysconfig::steal() }
562        .tim_clk_enable()
563        .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (id.value()))) });
564}
565
566/// Clear the reset bit of the TIM, holding it in reset
567///
568/// # Safety
569///
570/// Only the bit related to the corresponding TIM peripheral is modified
571#[inline]
572pub fn assert_tim_reset(id: TimId) {
573    unsafe { pac::Peripherals::steal() }
574        .sysconfig
575        .tim_reset()
576        .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << id.value())) });
577}
578
579#[inline]
580pub fn deassert_tim_reset(tim: TimId) {
581    unsafe { pac::Peripherals::steal() }
582        .sysconfig
583        .tim_reset()
584        .modify(|r, w| unsafe { w.bits(r.bits() | (1 << tim.value())) });
585}
586
587pub fn assert_tim_reset_for_cycles(tim: TimId, cycles: u32) {
588    assert_tim_reset(tim);
589    cortex_m::asm::delay(cycles);
590    deassert_tim_reset(tim);
591}