From a1f7a94c6924a5344ed29b60e11be673ca04bfcb Mon Sep 17 00:00:00 2001
From: Matous Hybl <hyblmatous@gmail.com>
Date: Wed, 8 Dec 2021 17:36:40 +0100
Subject: [PATCH] Add low level timer API.

---
 embassy-stm32/src/lib.rs       |   1 +
 embassy-stm32/src/timer/mod.rs | 224 +++++++++++++++++++++++++++++++++
 2 files changed, 225 insertions(+)
 create mode 100644 embassy-stm32/src/timer/mod.rs

diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 1ed48df3f..dfc027733 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -20,6 +20,7 @@ pub mod gpio;
 pub mod rcc;
 #[cfg(feature = "_time-driver")]
 mod time_driver;
+pub mod timer;
 
 // Sometimes-present hardware
 
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
new file mode 100644
index 000000000..ed2cb2d97
--- /dev/null
+++ b/embassy-stm32/src/timer/mod.rs
@@ -0,0 +1,224 @@
+use embassy::interrupt::Interrupt;
+
+use crate::rcc::{sealed::RccPeripheral as __RccPeri, RccPeripheral};
+use crate::time::Hertz;
+use stm32_metapac::timer::vals;
+
+#[cfg(feature = "unstable-pac")]
+pub mod low_level {
+    pub use super::sealed::*;
+}
+
+pub(crate) mod sealed {
+    use super::*;
+    pub trait Basic16bitInstance: RccPeripheral {
+        type Interrupt: Interrupt;
+
+        fn regs(&self) -> crate::pac::timer::TimBasic;
+
+        fn start(&mut self);
+
+        fn stop(&mut self);
+
+        fn reset(&mut self);
+
+        fn set_frequency<F: Into<Hertz>>(&mut self, frequency: F);
+
+        fn clear_update_interrupt(&mut self) -> bool;
+
+        fn enable_update_interrupt(&mut self, enable: bool);
+    }
+
+    pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
+        fn regs_gp16(&self) -> crate::pac::timer::TimGp16;
+    }
+
+    pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
+        fn regs_gp32(&self) -> crate::pac::timer::TimGp32;
+
+        fn set_frequency<F: Into<Hertz>>(&mut self, frequency: F);
+    }
+
+    pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
+        fn regs_advanced(&self) -> crate::pac::timer::TimAdv;
+    }
+}
+
+pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
+
+pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
+
+pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
+
+pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
+
+#[allow(unused)]
+macro_rules! impl_basic_16bit_timer {
+    ($inst:ident, $irq:ident) => {
+        impl sealed::Basic16bitInstance for crate::peripherals::$inst {
+            type Interrupt = crate::interrupt::$irq;
+
+            fn regs(&self) -> crate::pac::timer::TimBasic {
+                crate::pac::timer::TimBasic(crate::pac::$inst.0)
+            }
+
+            fn start(&mut self) {
+                unsafe {
+                    self.regs().cr1().modify(|r| r.set_cen(true));
+                }
+            }
+
+            fn stop(&mut self) {
+                let regs = self.regs();
+                unsafe {
+                    regs.cr1().modify(|r| r.set_cen(false));
+                }
+            }
+
+            fn reset(&mut self) {
+                unsafe {
+                    self.regs().cnt().write(|r| r.set_cnt(0));
+                }
+            }
+
+            fn set_frequency<F: Into<Hertz>>(&mut self, frequency: F) {
+                use core::convert::TryInto;
+                let f = frequency.into().0;
+                let timer_f = Self::frequency().0;
+                let pclk_ticks_per_timer_period = timer_f / f;
+                let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
+                let arr: u16 =
+                    unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
+
+                let regs = self.regs();
+                unsafe {
+                    regs.psc().write(|r| r.set_psc(psc));
+                    regs.arr().write(|r| r.set_arr(arr));
+
+                    regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
+                    regs.egr().write(|r| r.set_ug(true));
+                    regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
+                }
+            }
+
+            fn clear_update_interrupt(&mut self) -> bool {
+                unsafe {
+                    let sr = self.regs().sr().read();
+                    if sr.uif() {
+                        self.regs().sr().modify(|r| {
+                            r.set_uif(false);
+                        });
+                        true
+                    } else {
+                        false
+                    }
+                }
+            }
+
+            fn enable_update_interrupt(&mut self, enable: bool) {
+                unsafe {
+                    self.regs().dier().write(|r| r.set_uie(enable));
+                }
+            }
+        }
+    };
+}
+
+#[allow(unused)]
+macro_rules! impl_32bit_timer {
+    ($inst:ident) => {
+        impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst {
+            fn regs_gp32(&self) -> crate::pac::timer::TimGp32 {
+                crate::pac::$inst
+            }
+
+            fn set_frequency<F: Into<Hertz>>(&mut self, frequency: F) {
+                use core::convert::TryInto;
+                let f = frequency.into().0;
+                let timer_f = Self::frequency().0;
+                let pclk_ticks_per_timer_period = (timer_f / f) as u64;
+                let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
+                let arr: u32 =
+                    unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()));
+
+                let regs = self.regs_gp32();
+                unsafe {
+                    regs.psc().write(|r| r.set_psc(psc));
+                    regs.arr().write(|r| r.set_arr(arr));
+
+                    regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
+                    regs.egr().write(|r| r.set_ug(true));
+                    regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
+                }
+            }
+        }
+    };
+}
+
+crate::pac::interrupts! {
+    ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
+        impl_basic_16bit_timer!($inst, $irq);
+
+        impl Basic16bitInstance for crate::peripherals::$inst {
+        }
+    };
+    ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
+        impl_basic_16bit_timer!($inst, $irq);
+
+        impl Basic16bitInstance for crate::peripherals::$inst {
+        }
+
+        impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
+            fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
+                crate::pac::$inst
+            }
+        }
+
+        impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
+        }
+    };
+
+    ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
+        impl_basic_16bit_timer!($inst, $irq);
+
+        impl Basic16bitInstance for crate::peripherals::$inst {
+        }
+
+        impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
+            fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
+                crate::pac::timer::TimGp16(crate::pac::$inst.0)
+            }
+        }
+
+        impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
+        }
+
+        impl_32bit_timer!($inst);
+
+        impl GeneralPurpose32bitInstance for crate::peripherals::$inst {
+        }
+    };
+
+    ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
+        impl_basic_16bit_timer!($inst, $irq);
+
+        impl Basic16bitInstance for crate::peripherals::$inst {
+        }
+
+        impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
+            fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
+                crate::pac::timer::TimGp16(crate::pac::$inst.0)
+            }
+        }
+
+        impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
+        }
+        impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
+            fn regs_advanced(&self) -> crate::pac::timer::TimAdv {
+                crate::pac::$inst
+            }
+        }
+        impl AdvancedControlInstance for crate::peripherals::$inst {
+        }
+    };
+}