use crate::hal::timer::{Cancel, CountDown, Periodic};
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
use crate::pac::TIM1;
#[cfg(feature = "medium")]
use crate::pac::TIM4;
#[cfg(any(feature = "high", feature = "connectivity"))]
use crate::pac::TIM5;
#[cfg(any(feature = "stm32f100", feature = "high", feature = "connectivity",))]
use crate::pac::TIM6;
#[cfg(any(
all(feature = "high", any(feature = "stm32f101", feature = "stm32f103",),),
any(feature = "stm32f100", feature = "connectivity",)
))]
use crate::pac::TIM7;
#[cfg(all(feature = "stm32f103", feature = "high",))]
use crate::pac::TIM8;
use crate::pac::{DBGMCU as DBG, TIM2, TIM3};
#[cfg(feature = "stm32f100")]
use crate::pac::{TIM15, TIM16, TIM17};
#[cfg(not(feature = "stm32f101"))]
use crate::rcc::APB2;
use crate::rcc::{sealed::RccBus, Clocks, Enable, GetBusFreq, Reset, APB1};
use cast::{u16, u32, u64};
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::peripheral::SYST;
use void::Void;
use crate::time::Hertz;
pub enum Event {
Update,
}
#[derive(Debug, PartialEq)]
pub enum Error {
Canceled,
}
pub struct Timer<TIM> {
pub(crate) tim: TIM,
pub(crate) clk: Hertz,
}
pub struct CountDownTimer<TIM> {
tim: TIM,
clk: Hertz,
}
pub(crate) mod sealed {
pub trait Remap {
type Periph;
const REMAP: u8;
}
pub trait Ch1<REMAP> {}
pub trait Ch2<REMAP> {}
pub trait Ch3<REMAP> {}
pub trait Ch4<REMAP> {}
}
macro_rules! remap {
($($name:ident: ($TIMX:ident, $state:literal, $P1:ident, $P2:ident, $P3:ident, $P4:ident),)+) => {
$(
pub struct $name;
impl sealed::Remap for $name {
type Periph = $TIMX;
const REMAP: u8 = $state;
}
impl<MODE> sealed::Ch1<$name> for $P1<MODE> {}
impl<MODE> sealed::Ch2<$name> for $P2<MODE> {}
impl<MODE> sealed::Ch3<$name> for $P3<MODE> {}
impl<MODE> sealed::Ch4<$name> for $P4<MODE> {}
)+
}
}
use crate::gpio::gpioa::{PA0, PA1, PA15, PA2, PA3, PA6, PA7};
use crate::gpio::gpiob::{PB0, PB1, PB10, PB11, PB3, PB4, PB5};
use crate::gpio::gpioc::{PC6, PC7, PC8, PC9};
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
use crate::gpio::{
gpioa::{PA10, PA11, PA8, PA9},
gpioe::{PE11, PE13, PE14, PE9},
};
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
remap!(
Tim1NoRemap: (TIM1, 0b00, PA8, PA9, PA10, PA11),
Tim1FullRemap: (TIM1, 0b11, PE9, PE11, PE13, PE14),
);
remap!(
Tim2NoRemap: (TIM2, 0b00, PA0, PA1, PA2, PA3),
Tim2PartialRemap1: (TIM2, 0b01, PA15, PB3, PA2, PA3),
Tim2PartialRemap2: (TIM2, 0b10, PA0, PA1, PB10, PB11),
Tim2FullRemap: (TIM2, 0b11, PA15, PB3, PB10, PB11),
Tim3NoRemap: (TIM3, 0b00, PA6, PA7, PB0, PB1),
Tim3PartialRemap: (TIM3, 0b10, PB4, PB5, PB0, PB1),
Tim3FullRemap: (TIM3, 0b11, PC6, PC7, PC8, PC9),
);
#[cfg(feature = "medium")]
use crate::gpio::{
gpiob::{PB6, PB7, PB8, PB9},
gpiod::{PD12, PD13, PD14, PD15},
};
#[cfg(feature = "medium")]
remap!(
Tim4NoRemap: (TIM4, 0b00, PB6, PB7, PB8, PB9),
Tim4Remap: (TIM4, 0b01, PD12, PD13, PD14, PD15),
);
impl Timer<SYST> {
pub fn syst(mut syst: SYST, clocks: &Clocks) -> Self {
syst.set_clock_source(SystClkSource::Core);
Self {
tim: syst,
clk: clocks.hclk(),
}
}
pub fn start_count_down<T>(self, timeout: T) -> CountDownTimer<SYST>
where
T: Into<Hertz>,
{
let Self { tim, clk } = self;
let mut timer = CountDownTimer { tim, clk };
timer.start(timeout);
timer
}
pub fn release(self) -> SYST {
self.tim
}
}
impl CountDownTimer<SYST> {
pub fn listen(&mut self, event: Event) {
match event {
Event::Update => self.tim.enable_interrupt(),
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::Update => self.tim.disable_interrupt(),
}
}
pub fn reset(&mut self) {
self.tim.clear_current();
}
pub fn micros_since(&self) -> u32 {
let reload_value = SYST::get_reload();
let timer_clock = u64(self.clk.0);
let ticks = u64(reload_value - SYST::get_current());
u32(1_000_000 * ticks / timer_clock).unwrap()
}
pub fn stop(mut self) -> Timer<SYST> {
self.tim.disable_counter();
let Self { tim, clk } = self;
Timer { tim, clk }
}
pub fn release(self) -> SYST {
self.stop().release()
}
}
impl CountDown for CountDownTimer<SYST> {
type Time = Hertz;
fn start<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
let rvr = self.clk.0 / timeout.into().0 - 1;
assert!(rvr < (1 << 24));
self.tim.set_reload(rvr);
self.tim.clear_current();
self.tim.enable_counter();
}
fn wait(&mut self) -> nb::Result<(), Void> {
if self.tim.has_wrapped() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl Cancel for CountDownTimer<SYST> {
type Error = Error;
fn cancel(&mut self) -> Result<(), Self::Error> {
if !self.tim.is_counter_enabled() {
return Err(Self::Error::Canceled);
}
self.tim.disable_counter();
Ok(())
}
}
impl Periodic for CountDownTimer<SYST> {}
macro_rules! hal {
($($TIMX:ident: ($timX:ident, $APBx:ident, $dbg_timX_stop:ident$(,$master_timbase:ident)*),)+) => {
$(
impl Timer<$TIMX> {
pub fn $timX(tim: $TIMX, clocks: &Clocks, apb: &mut $APBx) -> Self {
$TIMX::enable(apb);
$TIMX::reset(apb);
Self { tim, clk: <$TIMX as RccBus>::Bus::get_timer_frequency(&clocks) }
}
pub fn start_count_down<T>(self, timeout: T) -> CountDownTimer<$TIMX>
where
T: Into<Hertz>,
{
let Self { tim, clk } = self;
let mut timer = CountDownTimer { tim, clk };
timer.start(timeout);
timer
}
$(
pub fn start_master<T>(self, timeout: T, mode: crate::pac::$master_timbase::cr2::MMS_A) -> CountDownTimer<$TIMX>
where
T: Into<Hertz>,
{
let Self { tim, clk } = self;
let mut timer = CountDownTimer { tim, clk };
timer.tim.cr2.modify(|_,w| w.mms().variant(mode));
timer.start(timeout);
timer
}
)?
#[inline(always)]
pub fn clocking_reset(&mut self, apb: &mut <$TIMX as RccBus>::Bus) {
$TIMX::reset(apb);
}
#[inline(always)]
pub fn stop_in_debug(&mut self, dbg: &mut DBG, state: bool) {
dbg.cr.modify(|_, w| w.$dbg_timX_stop().bit(state));
}
pub fn release(self) -> $TIMX {
self.tim
}
}
impl CountDownTimer<$TIMX> {
pub fn listen(&mut self, event: Event) {
match event {
Event::Update => self.tim.dier.write(|w| w.uie().set_bit()),
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::Update => self.tim.dier.write(|w| w.uie().clear_bit()),
}
}
pub fn stop(self) -> Timer<$TIMX> {
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
let Self { tim, clk } = self;
Timer { tim, clk }
}
pub fn clear_update_interrupt_flag(&mut self) {
self.tim.sr.modify(|_, w| w.uif().clear_bit());
}
pub fn release(self) -> $TIMX {
self.stop().release()
}
pub fn micros_since(&self) -> u32 {
let timer_clock = self.clk.0;
let psc = u32(self.tim.psc.read().psc().bits());
let freq_divider = u64(timer_clock / (psc + 1));
let cnt = u64(self.tim.cnt.read().cnt().bits());
u32(1_000_000 * cnt / freq_divider).unwrap()
}
pub fn reset(&mut self) {
self.tim.cr1.modify(|_, w| w.urs().set_bit());
self.tim.egr.write(|w| w.ug().set_bit());
self.tim.cr1.modify(|_, w| w.urs().clear_bit());
}
}
impl CountDown for CountDownTimer<$TIMX> {
type Time = Hertz;
fn start<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
let (psc, arr) = compute_arr_presc(timeout.into().0, self.clk.0);
self.tim.psc.write(|w| w.psc().bits(psc) );
#[allow(unused_unsafe)]
self.tim.arr.write(|w| unsafe { w.arr().bits(arr) });
self.reset();
self.tim.cr1.modify(|_, w| w.cen().set_bit());
}
fn wait(&mut self) -> nb::Result<(), Void> {
if self.tim.sr.read().uif().bit_is_clear() {
Err(nb::Error::WouldBlock)
} else {
self.clear_update_interrupt_flag();
Ok(())
}
}
}
impl Cancel for CountDownTimer<$TIMX>
{
type Error = Error;
fn cancel(&mut self) -> Result<(), Self::Error> {
let is_counter_enabled = self.tim.cr1.read().cen().is_enabled();
if !is_counter_enabled {
return Err(Self::Error::Canceled);
}
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
Ok(())
}
}
impl Periodic for CountDownTimer<$TIMX> {}
)+
}
}
#[inline(always)]
fn compute_arr_presc(freq: u32, clock: u32) -> (u16, u16) {
let ticks = clock / freq;
let psc = u16((ticks - 1) / (1 << 16)).unwrap();
let arr = u16(ticks / u32(psc + 1)).unwrap();
(psc, arr)
}
hal! {
TIM2: (tim2, APB1, dbg_tim2_stop, tim2),
TIM3: (tim3, APB1, dbg_tim3_stop, tim2),
}
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
hal! {
TIM1: (tim1, APB2, dbg_tim1_stop, tim1),
}
#[cfg(any(feature = "stm32f100", feature = "high", feature = "connectivity",))]
hal! {
TIM6: (tim6, APB1, dbg_tim6_stop, tim6),
}
#[cfg(any(
all(feature = "high", any(feature = "stm32f101", feature = "stm32f103",),),
any(feature = "stm32f100", feature = "connectivity",)
))]
hal! {
TIM7: (tim7, APB1, dbg_tim7_stop, tim6),
}
#[cfg(feature = "stm32f100")]
hal! {
TIM15: (tim15, APB2, dbg_tim15_stop),
TIM16: (tim16, APB2, dbg_tim16_stop),
TIM17: (tim17, APB2, dbg_tim17_stop),
}
#[cfg(feature = "medium")]
hal! {
TIM4: (tim4, APB1, dbg_tim4_stop, tim2),
}
#[cfg(any(feature = "high", feature = "connectivity"))]
hal! {
TIM5: (tim5, APB1, dbg_tim5_stop, tim2),
}
#[cfg(all(feature = "stm32f103", feature = "high",))]
hal! {
TIM8: (tim8, APB2, dbg_tim8_stop, tim1),
}