From d3af40eef16e15c329e2ece091fb53f328c32d19 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 30 Oct 2021 08:22:36 +0300 Subject: [PATCH] BusClock & macro cleanups --- CHANGELOG.md | 4 + src/rcc.rs | 61 ++++++++++ src/serial.rs | 102 ++++++---------- src/spi.rs | 11 +- src/timer.rs | 315 ++++++++++++++++---------------------------------- 5 files changed, 204 insertions(+), 289 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cdbc5629..15d2883cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- `BusClock` and `BusTimerClock` traits ([#302]) +- `RccBus`, `Enable`, `Reset` traits and implementations for peripherals ([#299]) - Support cortex-m-rt `v0.7.0` but still allow `v0.6.13` ([#283]) ### Fixed @@ -500,6 +502,8 @@ let clocks = rcc [defmt]: https://github.com/knurling-rs/defmt [filter]: https://defmt.ferrous-systems.com/filtering.html +[#302]: https://github.com/stm32-rs/stm32f3xx-hal/pull/302 +[#299]: https://github.com/stm32-rs/stm32f3xx-hal/pull/299 [#291]: https://github.com/stm32-rs/stm32f3xx-hal/pull/291 [#283]: https://github.com/stm32-rs/stm32f3xx-hal/pull/283 [#282]: https://github.com/stm32-rs/stm32f3xx-hal/pull/282 diff --git a/src/rcc.rs b/src/rcc.rs index db8f3e550..cb73a6e7c 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -226,6 +226,67 @@ pub trait Reset: RccBus { unsafe fn reset_unchecked(); } +/// Frequency on bus that peripheral is connected in +pub trait BusClock { + /// Calculates frequency depending on `Clock` state + fn clock(clocks: &Clocks) -> Hertz; +} + +impl BusClock for T +where + T: RccBus, + T::Bus: BusClock, +{ + fn clock(clocks: &Clocks) -> Hertz { + T::Bus::clock(clocks) + } +} + +impl BusClock for AHB { + fn clock(clocks: &Clocks) -> Hertz { + clocks.hclk + } +} +impl BusClock for APB1 { + fn clock(clocks: &Clocks) -> Hertz { + clocks.pclk1 + } +} +impl BusClock for APB2 { + fn clock(clocks: &Clocks) -> Hertz { + clocks.pclk2 + } +} + +/// Frequency on bus that timer is connected in +pub trait BusTimerClock { + /// Calculates base frequency of timer depending on `Clock` state + fn timer_clock(clocks: &Clocks) -> Hertz; +} + +impl BusTimerClock for T +where + T: RccBus, + T::Bus: BusTimerClock, +{ + fn timer_clock(clocks: &Clocks) -> Hertz { + T::Bus::timer_clock(clocks) + } +} + +impl BusTimerClock for APB1 { + fn timer_clock(clocks: &Clocks) -> Hertz { + let pclk_mul = if clocks.ppre1 > 1 { 2 } else { 1 }; + Hertz(clocks.pclk1.0 * pclk_mul) + } +} +impl BusTimerClock for APB2 { + fn timer_clock(clocks: &Clocks) -> Hertz { + let pclk_mul = if clocks.ppre2 > 1 { 2 } else { 1 }; + Hertz(clocks.pclk2.0 * pclk_mul) + } +} + /// Frequency of interal hardware RC oscillator (HSI OSC) pub const HSI: Hertz = Hertz(8_000_000); /// Frequency of external 32.768 kHz oscillator (LSE OSC) diff --git a/src/serial.rs b/src/serial.rs index 776a847fc..1f0d66264 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -1195,13 +1195,7 @@ pub trait Instance: macro_rules! usart { ( $( - $USARTX:ident: ( - $usartXen:ident, - $INTERRUPT:path, - $pclkX:ident, - $usartXsw:ident, - $usartXclock:ident - ), + $USARTX:ident: ($INTERRUPT:path), )+ ) => { $( @@ -1210,16 +1204,6 @@ macro_rules! usart { const INTERRUPT: Interrupt = $INTERRUPT; } - impl Instance for $USARTX { - fn clock(clocks: &Clocks) -> Hertz { - // Use the function created via another macro outside of this one, - // because the implementation is dependend on the type $USARTX. - // But macros can not differentiate between types. - $usartXclock(clocks) - } - } - - impl Serial<$USARTX, (Tx, Rx)> where Tx: TxPin<$USARTX>, Rx: RxPin<$USARTX> { /// Splits the [`Serial`] abstraction into a transmitter and a receiver half. @@ -1275,17 +1259,11 @@ macro_rules! usart { )+ }; - ([ $(($X:literal, $APB:literal, $INTERRUPT:path)),+ ]) => { + ([ $(($X:literal, $INTERRUPT:path)),+ ]) => { paste::paste! { usart!( $( - []: ( - [], - $INTERRUPT, - [], - [], - [] - ), + []: ($INTERRUPT), )+ ); } @@ -1296,19 +1274,19 @@ macro_rules! usart { /// the only clock source can be the peripheral clock #[allow(unused_macros)] macro_rules! usart_static_clock { - ($($usartXclock:ident, $pclkX:ident),+) => { + ($($USARTX:ident),+) => { $( - /// Return the currently set source frequency the UART peripheral - /// depending on the clock source. - fn $usartXclock(clocks: &Clocks) -> Hertz { - clocks.$pclkX() + impl Instance for $USARTX { + fn clock(clocks: &Clocks) -> Hertz { + <$USARTX as rcc::BusClock>::clock(clocks) + } } )+ }; - ([ $(($X:literal, $APB:literal)),+ ]) => { + ($($X:literal),+) => { paste::paste! { usart_static_clock!( - $([], []),+ + $([]),+ ); } }; @@ -1317,25 +1295,25 @@ macro_rules! usart_static_clock { /// Generates a clock function for UART Peripherals, where /// the clock source can vary. macro_rules! usart_var_clock { - ($($usartXclock:ident, $usartXsw:ident, $pclkX:ident),+) => { + ($($USARTX:ident, $usartXsw:ident),+) => { $( - /// Return the currently set source frequency for the UART peripheral - /// depending on the clock source. - fn $usartXclock(clocks: &Clocks) -> Hertz { - // NOTE(unsafe): atomic read with no side effects - match unsafe {(*RCC::ptr()).cfgr3.read().$usartXsw().variant()} { - USART1SW_A::PCLK => clocks.$pclkX(), - USART1SW_A::HSI => crate::rcc::HSI, - USART1SW_A::SYSCLK => clocks.sysclk(), - USART1SW_A::LSE => crate::rcc::LSE, + impl Instance for $USARTX { + fn clock(clocks: &Clocks) -> Hertz { + // NOTE(unsafe): atomic read with no side effects + match unsafe {(*RCC::ptr()).cfgr3.read().$usartXsw().variant()} { + USART1SW_A::PCLK => <$USARTX as rcc::BusClock>::clock(clocks), + USART1SW_A::HSI => crate::rcc::HSI, + USART1SW_A::SYSCLK => clocks.sysclk(), + USART1SW_A::LSE => crate::rcc::LSE, + } } } )+ }; - ([ $(($X:literal, $APB:literal)),+ ]) => { + ($($X:literal),+) => { paste::paste! { usart_var_clock!( - $([], [], []),+ + $([], []),+ ); } }; @@ -1357,26 +1335,26 @@ cfg_if::cfg_if! { ))] { // USART1 is accessed through APB2, // but USART1SW_A::PCLK will connect its phy to PCLK1. - usart_var_clock!([(1,1)]); + usart_var_clock!(1); // These are uart peripherals, where the only clock source // is the PCLK (peripheral clock). - usart_static_clock!([(2,1), (3,1)]); + usart_static_clock!(2, 3); } else { - usart_var_clock!([(1, 2), (2, 1), (3, 1)]); + usart_var_clock!(1, 2, 3); } } #[cfg(not(feature = "svd-f373"))] usart!([ - (1, 2, Interrupt::USART1_EXTI25), - (2, 1, Interrupt::USART2_EXTI26), - (3, 1, Interrupt::USART3_EXTI28) + (1, Interrupt::USART1_EXTI25), + (2, Interrupt::USART2_EXTI26), + (3, Interrupt::USART3_EXTI28) ]); #[cfg(feature = "svd-f373")] usart!([ - (1, 2, Interrupt::USART1), - (2, 1, Interrupt::USART2), - (3, 1, Interrupt::USART3) + (1, Interrupt::USART1), + (2, Interrupt::USART2), + (3, Interrupt::USART3) ]); cfg_if::cfg_if! { @@ -1384,17 +1362,11 @@ cfg_if::cfg_if! { if #[cfg(any(feature = "gpio-f303", feature = "gpio-f303e"))] { macro_rules! uart { - ([ $(($X:literal, $APB:literal, $INTERRUPT:path)),+ ]) => { + ([ $(($X:literal, $INTERRUPT:path)),+ ]) => { paste::paste! { usart!( $( - []: ( - [], - $INTERRUPT, - [], - [], - [] - ), + []: ($INTERRUPT), )+ ); } @@ -1402,17 +1374,17 @@ cfg_if::cfg_if! { } macro_rules! uart_var_clock { - ([ $(($X:literal, $APB:literal)),+ ]) => { + ($($X:literal),+) => { paste::paste! { usart_var_clock!( - $([], [], []),+ + $([], []),+ ); } }; } - uart_var_clock!([(4,1), (5,1)]); - uart!([(4,1, Interrupt::UART4_EXTI34), (5,1, Interrupt::UART5_EXTI35)]); + uart_var_clock!(4, 5); + uart!([(4, Interrupt::UART4_EXTI34), (5, Interrupt::UART5_EXTI35)]); impl Dma for UART4 {} diff --git a/src/spi.rs b/src/spi.rs index 9fc5a51e5..c0379d461 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -22,7 +22,7 @@ use crate::pac::{ use crate::{ gpio::{self, PushPull, AF5, AF6}, rcc::{self, Clocks}, - time::rate::{self, Hertz}, + time::rate, }; /// SPI error @@ -401,9 +401,8 @@ pub trait Instance: + crate::private::Sealed + rcc::Enable + rcc::Reset + + rcc::BusClock { - #[doc(hidden)] - fn clock(clocks: &Clocks) -> Hertz; } macro_rules! spi { @@ -414,11 +413,7 @@ macro_rules! spi { const INTERRUPT: Self::Interrupt = interrupts::$SPIX; } - impl Instance for pac::$SPIX { - fn clock(clocks: &Clocks) -> Hertz { - clocks.$pclkX() - } - } + impl Instance for pac::$SPIX { } #[cfg(feature = "defmt")] impl defmt::Format for Spi { diff --git a/src/timer.rs b/src/timer.rs index 1e8b155cd..4618c089a 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -15,7 +15,7 @@ use void::Void; use crate::hal::timer::{Cancel, CountDown, Periodic}; #[allow(unused)] -use crate::pac::RCC; +use crate::pac::{self, RCC}; use crate::rcc::{self, Clocks}; use crate::time::{duration, fixed_point::FixedPoint, rate::Hertz}; @@ -351,100 +351,61 @@ pub trait Instance: } macro_rules! timer { - ($({ - $TIMX:ident: ( - $timXsw:ident, - $timerXclock:ident, - $pclkX:ident, - $PCLKX:ident, - $ppreX:ident, - $INTERRUPT:ident - ), - },)+) => { - $( - impl CommonRegisterBlock for crate::pac::$TIMX { - #[inline] - fn set_cr1_cen(&mut self, enable: bool) { - self.cr1.modify(|_, w| w.cen().bit(enable)); - } - - #[inline] - fn is_cr1_cen_set(&mut self) -> bool { - self.cr1.read().cen().bit() - } - - #[inline] - fn set_dier_uie(&mut self, enable: bool) { - self.dier.modify(|_, w| w.uie().bit(enable)); - } - - #[inline] - fn is_dier_uie_set(&self) -> bool { - self.dier.read().uie().bit() - } - - #[inline] - fn clear_sr_uief(&mut self) { - self.sr.modify(|_, w| w.uif().clear()) - } + ($TIMX:ident) => { + impl CommonRegisterBlock for crate::pac::$TIMX { + #[inline] + fn set_cr1_cen(&mut self, enable: bool) { + self.cr1.modify(|_, w| w.cen().bit(enable)); + } - #[inline] - fn clear_sr(&mut self) { - // SAFETY: This atomic write clears all flags and ignores the reserverd bit fields. - self.sr.write(|w| unsafe { w.bits(0) }); - } + #[inline] + fn is_cr1_cen_set(&mut self) -> bool { + self.cr1.read().cen().bit() + } - #[inline] - fn is_sr_uief_set(&self) -> bool { - self.sr.read().uif().is_update_pending() - } + #[inline] + fn set_dier_uie(&mut self, enable: bool) { + self.dier.modify(|_, w| w.uie().bit(enable)); + } - #[inline] - fn set_egr_ug(&mut self) { - // NOTE(write): uses all bits in this register. - self.egr.write(|w| w.ug().update()); - } + #[inline] + fn is_dier_uie_set(&self) -> bool { + self.dier.read().uie().bit() + } - #[inline] - fn set_psc(&mut self, psc: u16) { - // NOTE(write): uses all bits in this register. - self.psc.write(|w| w.psc().bits(psc)); - } + #[inline] + fn clear_sr_uief(&mut self) { + self.sr.modify(|_, w| w.uif().clear()) + } - #[inline] - fn set_arr(&mut self, arr: u16) { - // TODO (sh3rm4n) - // self.tim.arr.write(|w| { w.arr().bits(arr) }); - self.arr.write(|w| unsafe { w.bits(u32::from(arr)) }); - } + #[inline] + fn clear_sr(&mut self) { + // SAFETY: This atomic write clears all flags and ignores the reserverd bit fields. + self.sr.write(|w| unsafe { w.bits(0) }); } - impl Instance for crate::pac::$TIMX { - #[inline] - fn clock(clocks: &Clocks) -> Hertz { - $timerXclock(clocks) - } + #[inline] + fn is_sr_uief_set(&self) -> bool { + self.sr.read().uif().is_update_pending() + } + #[inline] + fn set_egr_ug(&mut self) { + // NOTE(write): uses all bits in this register. + self.egr.write(|w| w.ug().update()); + } + #[inline] + fn set_psc(&mut self, psc: u16) { + // NOTE(write): uses all bits in this register. + self.psc.write(|w| w.psc().bits(psc)); } - )+ - }; - ([ $(($X:literal, $APB:literal)),+ ]) => { - paste::paste! { - timer! { - $( - { - []: ( - [], - [], - [], - [], - [], - [] - ), - }, - )+ + #[inline] + fn set_arr(&mut self, arr: u16) { + // TODO (sh3rm4n) + // self.tim.arr.write(|w| { w.arr().bits(arr) }); + self.arr.write(|w| unsafe { w.bits(u32::from(arr)) }); } } }; @@ -452,74 +413,68 @@ macro_rules! timer { #[allow(unused)] macro_rules! timer_var_clock { - ($($timerXclock:ident, $timXsw:ident, $pclkX:ident, $ppreX:ident),+) => { + ($($TIMX:ident, $timXsw:ident),+) => { $( - /// Return the currently set source frequency for the UART peripheral - /// depending on the clock source. - fn $timerXclock(clocks: &Clocks) -> Hertz { - // SAFETY: Atomic read with no side-effects. - match unsafe {(*RCC::ptr()).cfgr3.read().$timXsw().variant()} { - // PCLK2 is really the wrong name, as depending on the type of chip, it is - // pclk1 or pclk2. This distinction is however not made in stm32f3. - crate::pac::rcc::cfgr3::TIM1SW_A::PCLK2 => { - // Conditional mutliplier after APB prescaler is used. - // See RM0316 Fig 13. - if clocks.$ppreX() > 1 { - clocks.$pclkX() * 2 - } else { - clocks.$pclkX() + impl Instance for crate::pac::$TIMX { + #[inline] + fn clock(clocks: &Clocks) -> Hertz { + // SAFETY: Atomic read with no side-effects. + match unsafe {(*RCC::ptr()).cfgr3.read().$timXsw().variant()} { + // PCLK2 is really the wrong name, as depending on the type of chip, it is + // pclk1 or pclk2. This distinction is however not made in stm32f3. + crate::pac::rcc::cfgr3::TIM1SW_A::PCLK2 => { + // Conditional mutliplier after APB prescaler is used. + // See RM0316 Fig 13. + ::timer_clock(clocks) } - } - crate::pac::rcc::cfgr3::TIM1SW_A::PLL => { - if let Some(pllclk) = clocks.pllclk() { - pllclk * 2 - } else { - // This state should currently not be possible, - // because the software source can not be configured right now. - crate::panic!("Invalid timer clock source."); + crate::pac::rcc::cfgr3::TIM1SW_A::PLL => { + if let Some(pllclk) = clocks.pllclk() { + pllclk * 2 + } else { + // This state should currently not be possible, + // because the software source can not be configured right now. + crate::panic!("Invalid timer clock source."); + } } } } } + + timer!($TIMX); )+ }; - ([ $(($X:literal, $Y:literal, $APB:literal)),+ ]) => { + ($(($X:literal: $Y:literal)),+) => { paste::paste! { timer_var_clock!( - $([], [], [], []),+ + $([], []),+ ); } - - timer!([$(($X, $APB)),+]); }; - ([ $(($X:literal, $APB:literal)),+ ]) => { - timer_var_clock!([$(($X, $X, $APB)),+]); + ($($X:literal),+) => { + timer_var_clock!($(($X: $X)),+); }; } macro_rules! timer_static_clock { - ($($timerXclock:ident, $pclkX:ident, $ppreX:ident),+) => { + ($($TIMX:ident),+) => { $( - /// Return the currently set source frequency the UART peripheral - /// depending on the clock source. - fn $timerXclock(clocks: &Clocks) -> Hertz { - if clocks.$ppreX() > 1 { - clocks.$pclkX() * 2 - } else { - clocks.$pclkX() + impl Instance for crate::pac::$TIMX { + #[inline] + fn clock(clocks: &Clocks) -> Hertz { + ::timer_clock(clocks) } } + + timer!($TIMX); )+ }; - ([ $(($X:literal, $APB:literal)),+ ]) => { + ($($X:literal),+) => { paste::paste! { timer_static_clock!( - $([], [], []),+ + $([]),+ ); } - - timer!([$(($X, $APB)),+]); }; } @@ -535,39 +490,23 @@ cfg_if::cfg_if! { // (Interrupt::TIM7_IRQ), TIM7 has no chapter is nowwhere to be mentioned. Also tim7sw() does // not exsist. if #[cfg(feature = "svd-f301")] { - timer_static_clock!([(2, 1), (6, 1)]); - timer_var_clock!([(1, 2), (15, 2), (16, 2), (17, 2)]); + timer_static_clock!(2, 6); + timer_var_clock!(1, 15, 16, 17); } } cfg_if::cfg_if! { // RM0365 Fig. 12 if #[cfg(all(feature = "svd-f302", feature = "gpio-f303"))] { - timer_static_clock!([ - (2, 1), - (3, 1), - (4, 1), - (6, 1), - (15, 2), - (16, 2), - (17, 2) - ]); - timer_var_clock!([(1, 2)]); + timer_static_clock!(2, 3, 4, 6, 15, 16, 17); + timer_var_clock!(1); } // RM0365 Fig. 13 else if #[cfg(all(feature = "svd-f302", feature = "gpio-f303e"))] { - timer_static_clock!([ - (6, 1) - ]); - timer_var_clock!([ - (1, 2), - (2, 1), - (15, 2), - (16, 2), - (17, 2) - ]); - timer_var_clock!([(3, 34, 1), (4, 34, 1)]); + timer_static_clock!(6); + timer_var_clock!(1, 2, 15, 16, 17); + timer_var_clock!((3: 34), (4: 34)); } // RM0365 Fig. 14 @@ -576,60 +515,27 @@ cfg_if::cfg_if! { // (Interrupt::TIM7_IRQ), TIM7 has no chapter is nowhere to be mentioned. Also tim7sw() does // not exsist. else if #[cfg(all(feature = "svd-f302", feature = "gpio-f302"))] { - timer_static_clock!([ - (2, 1), - (6, 1) - ]); - timer_var_clock!([ - (1, 2), - (15, 2), - (16, 2), - (17, 2) - ]); + timer_static_clock!(2, 6); + timer_var_clock!(1, 15, 16, 17); } // RM0316 Fig. 13 else if #[cfg(all(feature = "svd-f303", feature = "gpio-f303"))] { - timer_static_clock!([ - (2, 1), - (3, 1), - (4, 1), - (6, 1), - (7, 1), - (15, 2), - (16, 2), - (17, 2) - ]); - timer_var_clock!([(1, 2), (8, 2)]); + timer_static_clock!(2, 3, 4, 6, 7, 15, 16, 17); + timer_var_clock!(1, 8); } // RM0316 Fig. 14 else if #[cfg(all(feature = "svd-f303", feature = "gpio-f303e"))] { - timer_static_clock!([(6, 1), (7, 1)]); - timer_var_clock!([ - (1, 2), - (2, 1), - (8, 2), - (15, 2), - (16, 2), - (17, 2), - (20, 2) - ]); - timer_var_clock!([(3, 34, 1), (4, 34, 1)]); + timer_static_clock!(6, 7); + timer_var_clock!(1, 2, 8, 15, 16, 17, 20); + timer_var_clock!((3: 34), (4: 34)); } // RM0316 Fig. 15 else if #[cfg(all(feature = "svd-f303", feature = "gpio-f333"))] { - timer_static_clock!([ - (2, 1), - (3, 1), - (6, 1), - (7, 1), - (15, 2), - (16, 2), - (17, 2) - ]); - timer_var_clock!([(1, 2)]); + timer_static_clock!(2, 3, 6, 7, 15, 16, 17); + timer_var_clock!(1); } // RM0313 Fig. 12 - this clock does not deliver the information about the timers. @@ -638,35 +544,12 @@ cfg_if::cfg_if! { // The information, which APB is connected to the timer, is only avaliable while looking // at the apb[1,2]rst registers. else if #[cfg(feature = "gpio-f373")] { - timer_static_clock!([ - (2, 1), - (3, 1), - (4, 1), - (5, 1), - (6, 1), - (7, 1), - (12, 1), - (13, 1), - (14, 1), - (15, 2), - (16, 2), - (17, 2), - (18, 1), - (19, 2) - ]); + timer_static_clock!(2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, 18, 19); } // RM0364 Fig. 10 else if #[cfg(all(feature = "svd-f3x4", feature = "gpio-f333"))] { - timer_static_clock!([ - (2, 1), - (3, 1), - (6, 1), - (7, 1), - (15, 2), - (16, 2), - (17, 2) - ]); - timer_var_clock!([(1, 2)]); + timer_static_clock!(2, 3, 6, 7, 15, 16, 17); + timer_var_clock!(1); } }