1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! Timers

use core::convert::Infallible;

use cast::{u16, u32};
use hal::timer::*;

use rcc::{ClockContext, APB1, APB2};
use time::Hertz;
//use rcc::clocking::LPTimerClkSource;
#[cfg(any(feature = "STM32L031x4", feature = "STM32L031x6"))]
use stm32l0x1::TIM22;
use stm32l0x1::{TIM2, TIM21};

/// 16-bit timer
pub struct Timer<TIM> {
    /// The underlying timer peripheral
    timer: TIM,
    /// The timer's period
    timeout: Hertz,
    /// The clock frequency
    clk_f: Hertz,
    /// The multiplier to the clock that feeds the timer
    timx_prsc: u32,
}

/// Timer events that can be subscribed to
pub enum Event {
    /// The timer has expired
    Timeout,
}

macro_rules! impl_timer {
    ($($TIMX:ident: ($timX:ident, $APB:ident, $apb:ident, $enr_bit:ident, $rstr_bit:ident),)+) => {
        $(
            impl Periodic for Timer<$TIMX> {}

            impl Cancel for Timer<$TIMX> {
                fn try_cancel(&mut self) -> Result<(), Self::Error> {
                    // disable the timer
                    self.timer.cr1.modify(|_, w| w.cen().clear_bit());
                    Ok(())
                }
            }

            impl CountDown for Timer<$TIMX> {
                type Time = Hertz;
                type Error = Infallible;

                fn try_start<T>(&mut self, timeout: T) -> Result<(), Self::Error>
                where
                    T: Into<Self::Time>
                {
                    // disable the timer
                    self.timer.cr1.modify(|_, w| w.cen().clear_bit());
                    // reset its counter
                    self.timer.cnt.reset();

                    self.timeout = timeout.into();

                    // timer clock ticks per timeout cycle
                    let ticks = self.clk_f.0 * self.timx_prsc / self.timeout.0;

                    // prescale the timer clock to account for multiples of the 16-bit counter
                    // size
                    let psc = u16((ticks - 1) / (1 << 16)).unwrap();
                    self.timer.psc.write(|w| w.psc().bits(psc));

                    // now set the auto-reload value
                    let arr = u16(ticks / u32(psc + 1)).unwrap();
                    self.timer.arr.write(|w| unsafe { w.bits(arr.into()) });

                    // Trigger an update event to load the prescaler value to the clock
                    self.timer.egr.write(|w| w.ug().set_bit());
                    // The above line raises an update event which will indicate
                    // that the timer is already finnished. Since this is not the case,
                    // it should be cleared
                    self.reset_overflow();

                    // start counter
                    self.timer.cr1.modify(|_, w| w.cen().set_bit());

                    Ok(())
                }

                fn try_wait(&mut self) -> nb::Result<(), Infallible> {
                    match self.timer.sr.read().uif().bit_is_clear() {
                        true => Err(nb::Error::WouldBlock),
                        false => {
                            self.reset_overflow();
                            Ok(())
                        }
                    }
                }
            }

            impl Timer<$TIMX> {
                /// Instantiate a new timer
                pub fn $timX<T: Into<Hertz>>(timer: $TIMX, clk_ctx: &ClockContext, timeout: T, apb: &mut $APB) -> Self {
                    // enable and reset peripheral to a clean slate state
                    apb.enr().modify(|_, w| w.$enr_bit().set_bit());
                    apb.rstr().modify(|_, w| w.$rstr_bit().set_bit());
                    apb.rstr().modify(|_, w| w.$rstr_bit().clear_bit());

                    // timer clock is multiplied by 2 is APBx presc is != 1
                    let timx_prsc = if clk_ctx.hclk_fclk() == clk_ctx.$apb() { 1 } else { 2 };

                    Timer { timer, timeout: timeout.into(), clk_f: clk_ctx.$apb(), timx_prsc }
                }

                /// Starts listening for an `event`
                pub fn subscribe(&mut self, event: Event) {
                    match event {
                        Event::Timeout => self.timer.dier.write(|w| w.uie().set_bit())
                    }
                }

                /// Stops listening for an `event`
                pub fn unsubscribe(&mut self, event: Event) {
                    match event {
                        Event::Timeout => self.timer.dier.write(|w| w.uie().clear_bit())
                    }
                }

                #[inline(always)]
                /// Resets SR's UIF register to clear status of overflow.
                ///
                /// Unless reset is done, Interrupt handler is going to be continiously called.
                pub fn reset_overflow(&mut self) {
                    self.timer.sr.modify(|_, w| w.uif().clear_bit());
                }

                /// Pauses timer and releases the TIM peripheral
                pub fn free(self) -> $TIMX {
                    self.timer.cr1.modify(|_, w| w.cen().clear_bit());
                    self.timer
                }
            }
        )+
    }
}

impl_timer! {
    TIM2: (tim2, APB1, apb1, tim2en, tim2rst),
    TIM21: (tim21, APB2, apb2, tim21en, tim21rst),
}

#[cfg(any(feature = "STM32L031x4", feature = "STM32L031x6"))]
impl_timer! {
    TIM22: (tim22, APB2, apb2, tim22en, tim22rst),
}