diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-06-14 16:22:14 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-06-14 16:22:14 +0200 |
| commit | 0dafd8f763a65558b88b2c7d55c933863c481d39 (patch) | |
| tree | 833f4531578d64e276765bcd23e3f8c6663c2602 | |
| parent | 85f172dd93227e637724d37e76bbcd7d886678f9 (diff) | |
| parent | 531093f28189573818d5ebcfd4ccf56389d3972f (diff) | |
Merge pull request #241 from lulf/get-clock-frequencies
Provide a way for a peripheral to query its clock frequency
| -rw-r--r-- | embassy-macros/src/chip/stm32.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/clock.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f4/mod.rs | 205 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h7/mod.rs | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l0/mod.rs | 160 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l4/mod.rs | 204 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 53 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/types.rs | 94 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/wb55/mod.rs | 204 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v1.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v2.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v3.rs | 2 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/spi.rs | 1 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/spi.rs | 1 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spi.rs | 1 | ||||
| -rw-r--r-- | stm32-metapac/gen/src/lib.rs | 21 |
16 files changed, 804 insertions, 171 deletions
diff --git a/embassy-macros/src/chip/stm32.rs b/embassy-macros/src/chip/stm32.rs index 0a3a5abb9..9cd0111c9 100644 --- a/embassy-macros/src/chip/stm32.rs +++ b/embassy-macros/src/chip/stm32.rs | |||
| @@ -17,9 +17,7 @@ pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream | |||
| 17 | ); | 17 | ); |
| 18 | let clock = unsafe { make_static(&mut c) }; | 18 | let clock = unsafe { make_static(&mut c) }; |
| 19 | 19 | ||
| 20 | // TODO: Is TIM2 always APB1? | 20 | clock.start(); |
| 21 | let timer_freq = unsafe { #embassy_stm32_path::rcc::get_freqs().apb1_clk }; | ||
| 22 | clock.start(timer_freq); | ||
| 23 | 21 | ||
| 24 | let mut alarm = clock.alarm1(); | 22 | let mut alarm = clock.alarm1(); |
| 25 | unsafe { #embassy_path::time::set_clock(clock) }; | 23 | unsafe { #embassy_path::time::set_clock(clock) }; |
diff --git a/embassy-stm32/src/clock.rs b/embassy-stm32/src/clock.rs index 39a96402a..6c3175789 100644 --- a/embassy-stm32/src/clock.rs +++ b/embassy-stm32/src/clock.rs | |||
| @@ -77,12 +77,14 @@ impl<T: Instance> Clock<T> { | |||
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | pub fn start(&'static self, timer_freq: Hertz) { | 80 | pub fn start(&'static self) { |
| 81 | let inner = T::inner(); | 81 | let inner = T::inner(); |
| 82 | 82 | ||
| 83 | T::enable(); | 83 | T::enable(); |
| 84 | T::reset(); | 84 | T::reset(); |
| 85 | 85 | ||
| 86 | let timer_freq = T::frequency(); | ||
| 87 | |||
| 86 | // NOTE(unsafe) Critical section to use the unsafe methods | 88 | // NOTE(unsafe) Critical section to use the unsafe methods |
| 87 | critical_section::with(|_| { | 89 | critical_section::with(|_| { |
| 88 | unsafe { | 90 | unsafe { |
diff --git a/embassy-stm32/src/rcc/f4/mod.rs b/embassy-stm32/src/rcc/f4/mod.rs new file mode 100644 index 000000000..e8709b5fc --- /dev/null +++ b/embassy-stm32/src/rcc/f4/mod.rs | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | pub use super::types::*; | ||
| 2 | use crate::pac; | ||
| 3 | use crate::peripherals::{self, RCC}; | ||
| 4 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 5 | use crate::time::Hertz; | ||
| 6 | use crate::time::U32Ext; | ||
| 7 | use core::marker::PhantomData; | ||
| 8 | use embassy::util::Unborrow; | ||
| 9 | use embassy_extras::unborrow; | ||
| 10 | use pac::rcc::vals::{Hpre, Ppre, Sw}; | ||
| 11 | |||
| 12 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | ||
| 13 | /// and with the addition of the init function to configure a system clock. | ||
| 14 | |||
| 15 | /// Only the basic setup using the HSE and HSI clocks are supported as of now. | ||
| 16 | |||
| 17 | /// HSI speed | ||
| 18 | pub const HSI_FREQ: u32 = 16_000_000; | ||
| 19 | |||
| 20 | /// System clock mux source | ||
| 21 | #[derive(Clone, Copy)] | ||
| 22 | pub enum ClockSrc { | ||
| 23 | HSE(Hertz), | ||
| 24 | HSI16, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl Into<Ppre> for APBPrescaler { | ||
| 28 | fn into(self) -> Ppre { | ||
| 29 | match self { | ||
| 30 | APBPrescaler::NotDivided => Ppre::DIV1, | ||
| 31 | APBPrescaler::Div2 => Ppre::DIV2, | ||
| 32 | APBPrescaler::Div4 => Ppre::DIV4, | ||
| 33 | APBPrescaler::Div8 => Ppre::DIV8, | ||
| 34 | APBPrescaler::Div16 => Ppre::DIV16, | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | impl Into<Hpre> for AHBPrescaler { | ||
| 40 | fn into(self) -> Hpre { | ||
| 41 | match self { | ||
| 42 | AHBPrescaler::NotDivided => Hpre::DIV1, | ||
| 43 | AHBPrescaler::Div2 => Hpre::DIV2, | ||
| 44 | AHBPrescaler::Div4 => Hpre::DIV4, | ||
| 45 | AHBPrescaler::Div8 => Hpre::DIV8, | ||
| 46 | AHBPrescaler::Div16 => Hpre::DIV16, | ||
| 47 | AHBPrescaler::Div64 => Hpre::DIV64, | ||
| 48 | AHBPrescaler::Div128 => Hpre::DIV128, | ||
| 49 | AHBPrescaler::Div256 => Hpre::DIV256, | ||
| 50 | AHBPrescaler::Div512 => Hpre::DIV512, | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | /// Clocks configutation | ||
| 56 | pub struct Config { | ||
| 57 | mux: ClockSrc, | ||
| 58 | ahb_pre: AHBPrescaler, | ||
| 59 | apb1_pre: APBPrescaler, | ||
| 60 | apb2_pre: APBPrescaler, | ||
| 61 | } | ||
| 62 | |||
| 63 | impl Default for Config { | ||
| 64 | #[inline] | ||
| 65 | fn default() -> Config { | ||
| 66 | Config { | ||
| 67 | mux: ClockSrc::HSI16, | ||
| 68 | ahb_pre: AHBPrescaler::NotDivided, | ||
| 69 | apb1_pre: APBPrescaler::NotDivided, | ||
| 70 | apb2_pre: APBPrescaler::NotDivided, | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | impl Config { | ||
| 76 | #[inline] | ||
| 77 | pub fn clock_src(mut self, mux: ClockSrc) -> Self { | ||
| 78 | self.mux = mux; | ||
| 79 | self | ||
| 80 | } | ||
| 81 | |||
| 82 | #[inline] | ||
| 83 | pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self { | ||
| 84 | self.ahb_pre = pre; | ||
| 85 | self | ||
| 86 | } | ||
| 87 | |||
| 88 | #[inline] | ||
| 89 | pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self { | ||
| 90 | self.apb1_pre = pre; | ||
| 91 | self | ||
| 92 | } | ||
| 93 | |||
| 94 | #[inline] | ||
| 95 | pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self { | ||
| 96 | self.apb2_pre = pre; | ||
| 97 | self | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | /// RCC peripheral | ||
| 102 | pub struct Rcc<'d> { | ||
| 103 | _rb: peripherals::RCC, | ||
| 104 | phantom: PhantomData<&'d mut peripherals::RCC>, | ||
| 105 | } | ||
| 106 | |||
| 107 | impl<'d> Rcc<'d> { | ||
| 108 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | ||
| 109 | unborrow!(rcc); | ||
| 110 | Self { | ||
| 111 | _rb: rcc, | ||
| 112 | phantom: PhantomData, | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | // Safety: RCC init must have been called | ||
| 117 | pub fn clocks(&self) -> &'static Clocks { | ||
| 118 | unsafe { get_freqs() } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 123 | pub trait RccExt { | ||
| 124 | fn freeze(self, config: Config) -> Clocks; | ||
| 125 | } | ||
| 126 | |||
| 127 | impl RccExt for RCC { | ||
| 128 | #[inline] | ||
| 129 | fn freeze(self, cfgr: Config) -> Clocks { | ||
| 130 | let rcc = pac::RCC; | ||
| 131 | let (sys_clk, sw) = match cfgr.mux { | ||
| 132 | ClockSrc::HSI16 => { | ||
| 133 | // Enable HSI16 | ||
| 134 | unsafe { | ||
| 135 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 136 | while !rcc.cr().read().hsirdy() {} | ||
| 137 | } | ||
| 138 | |||
| 139 | (HSI_FREQ, Sw::HSI) | ||
| 140 | } | ||
| 141 | ClockSrc::HSE(freq) => { | ||
| 142 | // Enable HSE | ||
| 143 | unsafe { | ||
| 144 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 145 | while !rcc.cr().read().hserdy() {} | ||
| 146 | } | ||
| 147 | |||
| 148 | (freq.0, Sw::HSE) | ||
| 149 | } | ||
| 150 | }; | ||
| 151 | |||
| 152 | unsafe { | ||
| 153 | rcc.cfgr().modify(|w| { | ||
| 154 | w.set_sw(sw.into()); | ||
| 155 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 156 | w.set_ppre1(cfgr.apb1_pre.into()); | ||
| 157 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 158 | }); | ||
| 159 | } | ||
| 160 | |||
| 161 | let ahb_freq: u32 = match cfgr.ahb_pre { | ||
| 162 | AHBPrescaler::NotDivided => sys_clk, | ||
| 163 | pre => { | ||
| 164 | let pre: Hpre = pre.into(); | ||
| 165 | let pre = 1 << (pre.0 as u32 - 7); | ||
| 166 | sys_clk / pre | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | |||
| 170 | let apb1_freq = match cfgr.apb1_pre { | ||
| 171 | APBPrescaler::NotDivided => ahb_freq, | ||
| 172 | pre => { | ||
| 173 | let pre: Ppre = pre.into(); | ||
| 174 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 175 | let freq = ahb_freq / pre as u32; | ||
| 176 | freq | ||
| 177 | } | ||
| 178 | }; | ||
| 179 | |||
| 180 | let apb2_freq = match cfgr.apb2_pre { | ||
| 181 | APBPrescaler::NotDivided => ahb_freq, | ||
| 182 | pre => { | ||
| 183 | let pre: Ppre = pre.into(); | ||
| 184 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 185 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 186 | freq | ||
| 187 | } | ||
| 188 | }; | ||
| 189 | |||
| 190 | Clocks { | ||
| 191 | sys: sys_clk.hz(), | ||
| 192 | ahb1: ahb_freq.hz(), | ||
| 193 | ahb2: ahb_freq.hz(), | ||
| 194 | ahb3: ahb_freq.hz(), | ||
| 195 | apb1: apb1_freq.hz(), | ||
| 196 | apb2: apb2_freq.hz(), | ||
| 197 | } | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | pub unsafe fn init(config: Config) { | ||
| 202 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | ||
| 203 | let clocks = r.freeze(config); | ||
| 204 | set_freqs(clocks); | ||
| 205 | } | ||
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs index f15dbe075..4bb50be3e 100644 --- a/embassy-stm32/src/rcc/h7/mod.rs +++ b/embassy-stm32/src/rcc/h7/mod.rs | |||
| @@ -6,6 +6,7 @@ use crate::pac::rcc::vals::Timpre; | |||
| 6 | use crate::pac::{DBGMCU, RCC, SYSCFG}; | 6 | use crate::pac::{DBGMCU, RCC, SYSCFG}; |
| 7 | use crate::peripherals; | 7 | use crate::peripherals; |
| 8 | use crate::pwr::{Power, VoltageScale}; | 8 | use crate::pwr::{Power, VoltageScale}; |
| 9 | use crate::rcc::{set_freqs, Clocks}; | ||
| 9 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 10 | 11 | ||
| 11 | mod pll; | 12 | mod pll; |
| @@ -522,5 +523,17 @@ impl<'d> Rcc<'d> { | |||
| 522 | } | 523 | } |
| 523 | } | 524 | } |
| 524 | 525 | ||
| 525 | // TODO | 526 | pub unsafe fn init(config: Config) { |
| 526 | pub unsafe fn init(_config: Config) {} | 527 | let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false); |
| 528 | let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config); | ||
| 529 | let core_clocks = rcc.freeze(&mut power); | ||
| 530 | set_freqs(Clocks { | ||
| 531 | sys: core_clocks.c_ck, | ||
| 532 | ahb1: core_clocks.hclk, | ||
| 533 | ahb2: core_clocks.hclk, | ||
| 534 | ahb3: core_clocks.hclk, | ||
| 535 | apb1: core_clocks.pclk1, | ||
| 536 | apb2: core_clocks.pclk2, | ||
| 537 | apb4: core_clocks.pclk4, | ||
| 538 | }); | ||
| 539 | } | ||
diff --git a/embassy-stm32/src/rcc/l0/mod.rs b/embassy-stm32/src/rcc/l0/mod.rs index d08c32b17..2d51c690f 100644 --- a/embassy-stm32/src/rcc/l0/mod.rs +++ b/embassy-stm32/src/rcc/l0/mod.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | pub use super::types::*; | ||
| 1 | use crate::pac; | 2 | use crate::pac; |
| 2 | use crate::peripherals::{self, CRS, RCC, SYSCFG}; | 3 | use crate::peripherals::{self, CRS, RCC, SYSCFG}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | 4 | use crate::rcc::{get_freqs, set_freqs, Clocks}; |
| @@ -12,6 +13,9 @@ use pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; | |||
| 12 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | 13 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, |
| 13 | /// and with the addition of the init function to configure a system clock. | 14 | /// and with the addition of the init function to configure a system clock. |
| 14 | 15 | ||
| 16 | /// HSI speed | ||
| 17 | pub const HSI_FREQ: u32 = 16_000_000; | ||
| 18 | |||
| 15 | /// System clock mux source | 19 | /// System clock mux source |
| 16 | #[derive(Clone, Copy)] | 20 | #[derive(Clone, Copy)] |
| 17 | pub enum ClockSrc { | 21 | pub enum ClockSrc { |
| @@ -21,90 +25,6 @@ pub enum ClockSrc { | |||
| 21 | HSI16, | 25 | HSI16, |
| 22 | } | 26 | } |
| 23 | 27 | ||
| 24 | /// MSI Clock Range | ||
| 25 | /// | ||
| 26 | /// These ranges control the frequency of the MSI. Internally, these ranges map | ||
| 27 | /// to the `MSIRANGE` bits in the `RCC_ICSCR` register. | ||
| 28 | #[derive(Clone, Copy)] | ||
| 29 | pub enum MSIRange { | ||
| 30 | /// Around 65.536 kHz | ||
| 31 | Range0, | ||
| 32 | /// Around 131.072 kHz | ||
| 33 | Range1, | ||
| 34 | /// Around 262.144 kHz | ||
| 35 | Range2, | ||
| 36 | /// Around 524.288 kHz | ||
| 37 | Range3, | ||
| 38 | /// Around 1.048 MHz | ||
| 39 | Range4, | ||
| 40 | /// Around 2.097 MHz (reset value) | ||
| 41 | Range5, | ||
| 42 | /// Around 4.194 MHz | ||
| 43 | Range6, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl Default for MSIRange { | ||
| 47 | fn default() -> MSIRange { | ||
| 48 | MSIRange::Range5 | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | /// PLL divider | ||
| 53 | #[derive(Clone, Copy)] | ||
| 54 | pub enum PLLDiv { | ||
| 55 | Div2, | ||
| 56 | Div3, | ||
| 57 | Div4, | ||
| 58 | } | ||
| 59 | |||
| 60 | /// PLL multiplier | ||
| 61 | #[derive(Clone, Copy)] | ||
| 62 | pub enum PLLMul { | ||
| 63 | Mul3, | ||
| 64 | Mul4, | ||
| 65 | Mul6, | ||
| 66 | Mul8, | ||
| 67 | Mul12, | ||
| 68 | Mul16, | ||
| 69 | Mul24, | ||
| 70 | Mul32, | ||
| 71 | Mul48, | ||
| 72 | } | ||
| 73 | |||
| 74 | /// AHB prescaler | ||
| 75 | #[derive(Clone, Copy)] | ||
| 76 | pub enum AHBPrescaler { | ||
| 77 | NotDivided, | ||
| 78 | Div2, | ||
| 79 | Div4, | ||
| 80 | Div8, | ||
| 81 | Div16, | ||
| 82 | Div64, | ||
| 83 | Div128, | ||
| 84 | Div256, | ||
| 85 | Div512, | ||
| 86 | } | ||
| 87 | |||
| 88 | /// APB prescaler | ||
| 89 | #[derive(Clone, Copy)] | ||
| 90 | pub enum APBPrescaler { | ||
| 91 | NotDivided, | ||
| 92 | Div2, | ||
| 93 | Div4, | ||
| 94 | Div8, | ||
| 95 | Div16, | ||
| 96 | } | ||
| 97 | |||
| 98 | /// PLL clock input source | ||
| 99 | #[derive(Clone, Copy)] | ||
| 100 | pub enum PLLSource { | ||
| 101 | HSI16, | ||
| 102 | HSE(Hertz), | ||
| 103 | } | ||
| 104 | |||
| 105 | /// HSI speed | ||
| 106 | pub const HSI_FREQ: u32 = 16_000_000; | ||
| 107 | |||
| 108 | impl Into<Pllmul> for PLLMul { | 28 | impl Into<Pllmul> for PLLMul { |
| 109 | fn into(self) -> Pllmul { | 29 | fn into(self) -> Pllmul { |
| 110 | match self { | 30 | match self { |
| @@ -248,18 +168,6 @@ impl<'d> Rcc<'d> { | |||
| 248 | unsafe { get_freqs() } | 168 | unsafe { get_freqs() } |
| 249 | } | 169 | } |
| 250 | 170 | ||
| 251 | /* | ||
| 252 | pub fn enable_lse(&mut self, _: &PWR) -> LSE { | ||
| 253 | self.rb.csr.modify(|_, w| { | ||
| 254 | // Enable LSE clock | ||
| 255 | w.lseon().set_bit() | ||
| 256 | }); | ||
| 257 | while self.rb.csr.read().lserdy().bit_is_clear() {} | ||
| 258 | LSE(()) | ||
| 259 | } | ||
| 260 | } | ||
| 261 | */ | ||
| 262 | |||
| 263 | pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) { | 171 | pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) { |
| 264 | // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU | 172 | // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU |
| 265 | unsafe { | 173 | unsafe { |
| @@ -319,30 +227,6 @@ impl<'d> Rcc<'d> { | |||
| 319 | HSI48(()) | 227 | HSI48(()) |
| 320 | } | 228 | } |
| 321 | } | 229 | } |
| 322 | /* | ||
| 323 | |||
| 324 | impl Rcc { | ||
| 325 | /// Configure MCO (Microcontroller Clock Output). | ||
| 326 | pub fn configure_mco<P>( | ||
| 327 | &mut self, | ||
| 328 | source: MCOSEL_A, | ||
| 329 | prescaler: MCOPRE_A, | ||
| 330 | output_pin: P, | ||
| 331 | ) -> MCOEnabled | ||
| 332 | where | ||
| 333 | P: mco::Pin, | ||
| 334 | { | ||
| 335 | output_pin.into_mco(); | ||
| 336 | |||
| 337 | self.rb.cfgr.modify(|_, w| { | ||
| 338 | w.mcosel().variant(source); | ||
| 339 | w.mcopre().variant(prescaler) | ||
| 340 | }); | ||
| 341 | |||
| 342 | MCOEnabled(()) | ||
| 343 | } | ||
| 344 | } | ||
| 345 | */ | ||
| 346 | 230 | ||
| 347 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | 231 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration |
| 348 | pub trait RccExt { | 232 | pub trait RccExt { |
| @@ -469,35 +353,31 @@ impl RccExt for RCC { | |||
| 469 | } | 353 | } |
| 470 | }; | 354 | }; |
| 471 | 355 | ||
| 472 | let (apb1_freq, apb1_tim_freq, apb1_pre) = match cfgr.apb1_pre { | 356 | let apb1_freq = match cfgr.apb1_pre { |
| 473 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq, 1), | 357 | APBPrescaler::NotDivided => ahb_freq, |
| 474 | pre => { | 358 | pre => { |
| 475 | let pre: Ppre = pre.into(); | 359 | let pre: Ppre = pre.into(); |
| 476 | let pre: u8 = 1 << (pre.0 - 3); | 360 | let pre: u8 = 1 << (pre.0 - 3); |
| 477 | let freq = ahb_freq / pre as u32; | 361 | let freq = ahb_freq / pre as u32; |
| 478 | (freq, freq * 2, pre as u8) | 362 | freq |
| 479 | } | 363 | } |
| 480 | }; | 364 | }; |
| 481 | 365 | ||
| 482 | let (apb2_freq, apb2_tim_freq, apb2_pre) = match cfgr.apb2_pre { | 366 | let apb2_freq = match cfgr.apb2_pre { |
| 483 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq, 1), | 367 | APBPrescaler::NotDivided => ahb_freq, |
| 484 | pre => { | 368 | pre => { |
| 485 | let pre: Ppre = pre.into(); | 369 | let pre: Ppre = pre.into(); |
| 486 | let pre: u8 = 1 << (pre.0 - 3); | 370 | let pre: u8 = 1 << (pre.0 - 3); |
| 487 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | 371 | let freq = ahb_freq / (1 << (pre as u8 - 3)); |
| 488 | (freq, freq * 2, pre as u8) | 372 | freq |
| 489 | } | 373 | } |
| 490 | }; | 374 | }; |
| 491 | 375 | ||
| 492 | Clocks { | 376 | Clocks { |
| 493 | sys_clk: sys_clk.hz(), | 377 | sys: sys_clk.hz(), |
| 494 | ahb_clk: ahb_freq.hz(), | 378 | ahb: ahb_freq.hz(), |
| 495 | apb1_clk: apb1_freq.hz(), | 379 | apb1: apb1_freq.hz(), |
| 496 | apb2_clk: apb2_freq.hz(), | 380 | apb2: apb2_freq.hz(), |
| 497 | apb1_tim_clk: apb1_tim_freq.hz(), | ||
| 498 | apb2_tim_clk: apb2_tim_freq.hz(), | ||
| 499 | apb1_pre, | ||
| 500 | apb2_pre, | ||
| 501 | } | 381 | } |
| 502 | } | 382 | } |
| 503 | } | 383 | } |
| @@ -508,18 +388,6 @@ impl RccExt for RCC { | |||
| 508 | #[derive(Clone, Copy)] | 388 | #[derive(Clone, Copy)] |
| 509 | pub struct HSI48(()); | 389 | pub struct HSI48(()); |
| 510 | 390 | ||
| 511 | /// Token that exists only if MCO (Microcontroller Clock Out) has been enabled. | ||
| 512 | /// | ||
| 513 | /// You can get an instance of this struct by calling [`Rcc::configure_mco`]. | ||
| 514 | #[derive(Clone, Copy)] | ||
| 515 | pub struct MCOEnabled(()); | ||
| 516 | |||
| 517 | /// Token that exists only, if the LSE clock has been enabled | ||
| 518 | /// | ||
| 519 | /// You can get an instance of this struct by calling [`Rcc::enable_lse`]. | ||
| 520 | #[derive(Clone, Copy)] | ||
| 521 | pub struct LSE(()); | ||
| 522 | |||
| 523 | pub unsafe fn init(config: Config) { | 391 | pub unsafe fn init(config: Config) { |
| 524 | let rcc = pac::RCC; | 392 | let rcc = pac::RCC; |
| 525 | rcc.iopenr().write(|w| { | 393 | rcc.iopenr().write(|w| { |
diff --git a/embassy-stm32/src/rcc/l4/mod.rs b/embassy-stm32/src/rcc/l4/mod.rs new file mode 100644 index 000000000..9ae6d62b9 --- /dev/null +++ b/embassy-stm32/src/rcc/l4/mod.rs | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | pub use super::types::*; | ||
| 2 | use crate::pac; | ||
| 3 | use crate::peripherals::{self, RCC}; | ||
| 4 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 5 | use crate::time::Hertz; | ||
| 6 | use crate::time::U32Ext; | ||
| 7 | use core::marker::PhantomData; | ||
| 8 | use embassy::util::Unborrow; | ||
| 9 | use embassy_extras::unborrow; | ||
| 10 | |||
| 11 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | ||
| 12 | /// and with the addition of the init function to configure a system clock. | ||
| 13 | |||
| 14 | /// Only the basic setup using the HSE and HSI clocks are supported as of now. | ||
| 15 | |||
| 16 | /// HSI speed | ||
| 17 | pub const HSI_FREQ: u32 = 16_000_000; | ||
| 18 | |||
| 19 | /// System clock mux source | ||
| 20 | #[derive(Clone, Copy)] | ||
| 21 | pub enum ClockSrc { | ||
| 22 | HSE(Hertz), | ||
| 23 | HSI16, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Into<u8> for APBPrescaler { | ||
| 27 | fn into(self) -> u8 { | ||
| 28 | match self { | ||
| 29 | APBPrescaler::NotDivided => 1, | ||
| 30 | APBPrescaler::Div2 => 0x04, | ||
| 31 | APBPrescaler::Div4 => 0x05, | ||
| 32 | APBPrescaler::Div8 => 0x06, | ||
| 33 | APBPrescaler::Div16 => 0x07, | ||
| 34 | } | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | impl Into<u8> for AHBPrescaler { | ||
| 39 | fn into(self) -> u8 { | ||
| 40 | match self { | ||
| 41 | AHBPrescaler::NotDivided => 1, | ||
| 42 | AHBPrescaler::Div2 => 0x08, | ||
| 43 | AHBPrescaler::Div4 => 0x09, | ||
| 44 | AHBPrescaler::Div8 => 0x0a, | ||
| 45 | AHBPrescaler::Div16 => 0x0b, | ||
| 46 | AHBPrescaler::Div64 => 0x0c, | ||
| 47 | AHBPrescaler::Div128 => 0x0d, | ||
| 48 | AHBPrescaler::Div256 => 0x0e, | ||
| 49 | AHBPrescaler::Div512 => 0x0f, | ||
| 50 | } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | /// Clocks configutation | ||
| 55 | pub struct Config { | ||
| 56 | mux: ClockSrc, | ||
| 57 | ahb_pre: AHBPrescaler, | ||
| 58 | apb1_pre: APBPrescaler, | ||
| 59 | apb2_pre: APBPrescaler, | ||
| 60 | } | ||
| 61 | |||
| 62 | impl Default for Config { | ||
| 63 | #[inline] | ||
| 64 | fn default() -> Config { | ||
| 65 | Config { | ||
| 66 | mux: ClockSrc::HSI16, | ||
| 67 | ahb_pre: AHBPrescaler::NotDivided, | ||
| 68 | apb1_pre: APBPrescaler::NotDivided, | ||
| 69 | apb2_pre: APBPrescaler::NotDivided, | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | impl Config { | ||
| 75 | #[inline] | ||
| 76 | pub fn clock_src(mut self, mux: ClockSrc) -> Self { | ||
| 77 | self.mux = mux; | ||
| 78 | self | ||
| 79 | } | ||
| 80 | |||
| 81 | #[inline] | ||
| 82 | pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self { | ||
| 83 | self.ahb_pre = pre; | ||
| 84 | self | ||
| 85 | } | ||
| 86 | |||
| 87 | #[inline] | ||
| 88 | pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self { | ||
| 89 | self.apb1_pre = pre; | ||
| 90 | self | ||
| 91 | } | ||
| 92 | |||
| 93 | #[inline] | ||
| 94 | pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self { | ||
| 95 | self.apb2_pre = pre; | ||
| 96 | self | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | /// RCC peripheral | ||
| 101 | pub struct Rcc<'d> { | ||
| 102 | _rb: peripherals::RCC, | ||
| 103 | phantom: PhantomData<&'d mut peripherals::RCC>, | ||
| 104 | } | ||
| 105 | |||
| 106 | impl<'d> Rcc<'d> { | ||
| 107 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | ||
| 108 | unborrow!(rcc); | ||
| 109 | Self { | ||
| 110 | _rb: rcc, | ||
| 111 | phantom: PhantomData, | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | // Safety: RCC init must have been called | ||
| 116 | pub fn clocks(&self) -> &'static Clocks { | ||
| 117 | unsafe { get_freqs() } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 122 | pub trait RccExt { | ||
| 123 | fn freeze(self, config: Config) -> Clocks; | ||
| 124 | } | ||
| 125 | |||
| 126 | impl RccExt for RCC { | ||
| 127 | #[inline] | ||
| 128 | fn freeze(self, cfgr: Config) -> Clocks { | ||
| 129 | let rcc = pac::RCC; | ||
| 130 | let (sys_clk, sw) = match cfgr.mux { | ||
| 131 | ClockSrc::HSI16 => { | ||
| 132 | // Enable HSI16 | ||
| 133 | unsafe { | ||
| 134 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 135 | while !rcc.cr().read().hsirdy() {} | ||
| 136 | } | ||
| 137 | |||
| 138 | (HSI_FREQ, 0x01) | ||
| 139 | } | ||
| 140 | ClockSrc::HSE(freq) => { | ||
| 141 | // Enable HSE | ||
| 142 | unsafe { | ||
| 143 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 144 | while !rcc.cr().read().hserdy() {} | ||
| 145 | } | ||
| 146 | |||
| 147 | (freq.0, 0x02) | ||
| 148 | } | ||
| 149 | }; | ||
| 150 | |||
| 151 | unsafe { | ||
| 152 | rcc.cfgr().modify(|w| { | ||
| 153 | w.set_sw(sw.into()); | ||
| 154 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 155 | w.set_ppre1(cfgr.apb1_pre.into()); | ||
| 156 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 157 | }); | ||
| 158 | } | ||
| 159 | |||
| 160 | let ahb_freq: u32 = match cfgr.ahb_pre { | ||
| 161 | AHBPrescaler::NotDivided => sys_clk, | ||
| 162 | pre => { | ||
| 163 | let pre: u8 = pre.into(); | ||
| 164 | let pre = 1 << (pre as u32 - 7); | ||
| 165 | sys_clk / pre | ||
| 166 | } | ||
| 167 | }; | ||
| 168 | |||
| 169 | let apb1_freq = match cfgr.apb1_pre { | ||
| 170 | APBPrescaler::NotDivided => ahb_freq, | ||
| 171 | pre => { | ||
| 172 | let pre: u8 = pre.into(); | ||
| 173 | let pre: u8 = 1 << (pre - 3); | ||
| 174 | let freq = ahb_freq / pre as u32; | ||
| 175 | freq | ||
| 176 | } | ||
| 177 | }; | ||
| 178 | |||
| 179 | let apb2_freq = match cfgr.apb2_pre { | ||
| 180 | APBPrescaler::NotDivided => ahb_freq, | ||
| 181 | pre => { | ||
| 182 | let pre: u8 = pre.into(); | ||
| 183 | let pre: u8 = 1 << (pre - 3); | ||
| 184 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 185 | freq | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | |||
| 189 | Clocks { | ||
| 190 | sys: sys_clk.hz(), | ||
| 191 | ahb1: ahb_freq.hz(), | ||
| 192 | ahb2: ahb_freq.hz(), | ||
| 193 | ahb3: ahb_freq.hz(), | ||
| 194 | apb1: apb1_freq.hz(), | ||
| 195 | apb2: apb2_freq.hz(), | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | pub unsafe fn init(config: Config) { | ||
| 201 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | ||
| 202 | let clocks = r.freeze(config); | ||
| 203 | set_freqs(clocks); | ||
| 204 | } | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3c5b53b05..48bdb3de6 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -3,22 +3,33 @@ | |||
| 3 | use crate::peripherals; | 3 | use crate::peripherals; |
| 4 | use crate::time::Hertz; | 4 | use crate::time::Hertz; |
| 5 | use core::mem::MaybeUninit; | 5 | use core::mem::MaybeUninit; |
| 6 | mod types; | ||
| 6 | 7 | ||
| 7 | /// Frozen clock frequencies | ||
| 8 | /// | ||
| 9 | /// The existence of this value indicates that the clock configuration can no longer be changed | ||
| 10 | #[derive(Clone, Copy)] | 8 | #[derive(Clone, Copy)] |
| 11 | pub struct Clocks { | 9 | pub struct Clocks { |
| 12 | pub sys_clk: Hertz, | 10 | pub sys: Hertz, |
| 13 | pub ahb_clk: Hertz, | 11 | pub apb1: Hertz, |
| 14 | pub apb1_clk: Hertz, | 12 | pub apb2: Hertz, |
| 15 | pub apb1_tim_clk: Hertz, | 13 | |
| 16 | pub apb2_clk: Hertz, | 14 | #[cfg(any(rcc_l0))] |
| 17 | pub apb2_tim_clk: Hertz, | 15 | pub ahb: Hertz, |
| 18 | pub apb1_pre: u8, | 16 | |
| 19 | pub apb2_pre: u8, | 17 | #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55))] |
| 18 | pub ahb1: Hertz, | ||
| 19 | |||
| 20 | #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55))] | ||
| 21 | pub ahb2: Hertz, | ||
| 22 | |||
| 23 | #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55))] | ||
| 24 | pub ahb3: Hertz, | ||
| 25 | |||
| 26 | #[cfg(any(rcc_h7))] | ||
| 27 | pub apb4: Hertz, | ||
| 20 | } | 28 | } |
| 21 | 29 | ||
| 30 | /// Frozen clock frequencies | ||
| 31 | /// | ||
| 32 | /// The existence of this value indicates that the clock configuration can no longer be changed | ||
| 22 | static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); | 33 | static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); |
| 23 | 34 | ||
| 24 | /// Sets the clock frequencies | 35 | /// Sets the clock frequencies |
| @@ -40,6 +51,15 @@ cfg_if::cfg_if! { | |||
| 40 | } else if #[cfg(rcc_l0)] { | 51 | } else if #[cfg(rcc_l0)] { |
| 41 | mod l0; | 52 | mod l0; |
| 42 | pub use l0::*; | 53 | pub use l0::*; |
| 54 | } else if #[cfg(rcc_l4)] { | ||
| 55 | mod l4; | ||
| 56 | pub use l4::*; | ||
| 57 | } else if #[cfg(rcc_f4)] { | ||
| 58 | mod f4; | ||
| 59 | pub use f4::*; | ||
| 60 | } else if #[cfg(rcc_wb55)] { | ||
| 61 | mod wb55; | ||
| 62 | pub use wb55::*; | ||
| 43 | } else { | 63 | } else { |
| 44 | #[derive(Default)] | 64 | #[derive(Default)] |
| 45 | pub struct Config {} | 65 | pub struct Config {} |
| @@ -50,6 +70,7 @@ cfg_if::cfg_if! { | |||
| 50 | 70 | ||
| 51 | pub(crate) mod sealed { | 71 | pub(crate) mod sealed { |
| 52 | pub trait RccPeripheral { | 72 | pub trait RccPeripheral { |
| 73 | fn frequency() -> crate::time::Hertz; | ||
| 53 | fn reset(); | 74 | fn reset(); |
| 54 | fn enable(); | 75 | fn enable(); |
| 55 | fn disable(); | 76 | fn disable(); |
| @@ -59,8 +80,16 @@ pub(crate) mod sealed { | |||
| 59 | pub trait RccPeripheral: sealed::RccPeripheral + 'static {} | 80 | pub trait RccPeripheral: sealed::RccPeripheral + 'static {} |
| 60 | 81 | ||
| 61 | crate::pac::peripheral_rcc!( | 82 | crate::pac::peripheral_rcc!( |
| 62 | ($inst:ident, $enable:ident, $reset:ident, $perien:ident, $perirst:ident) => { | 83 | ($inst:ident, $clk:ident, $enable:ident, $reset:ident, $perien:ident, $perirst:ident) => { |
| 63 | impl sealed::RccPeripheral for peripherals::$inst { | 84 | impl sealed::RccPeripheral for peripherals::$inst { |
| 85 | fn frequency() -> crate::time::Hertz { | ||
| 86 | critical_section::with(|_| { | ||
| 87 | unsafe { | ||
| 88 | let freqs = get_freqs(); | ||
| 89 | freqs.$clk | ||
| 90 | } | ||
| 91 | }) | ||
| 92 | } | ||
| 64 | fn enable() { | 93 | fn enable() { |
| 65 | critical_section::with(|_| { | 94 | critical_section::with(|_| { |
| 66 | unsafe { | 95 | unsafe { |
diff --git a/embassy-stm32/src/rcc/types.rs b/embassy-stm32/src/rcc/types.rs new file mode 100644 index 000000000..df7917ab3 --- /dev/null +++ b/embassy-stm32/src/rcc/types.rs | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | #![allow(dead_code)] | ||
| 2 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | ||
| 3 | /// and with the addition of the init function to configure a system clock. | ||
| 4 | use crate::time::Hertz; | ||
| 5 | |||
| 6 | /// System clock mux source | ||
| 7 | #[derive(Clone, Copy)] | ||
| 8 | pub enum ClockSrc { | ||
| 9 | MSI(MSIRange), | ||
| 10 | PLL(PLLSource, PLLMul, PLLDiv), | ||
| 11 | HSE(Hertz), | ||
| 12 | HSI16, | ||
| 13 | } | ||
| 14 | |||
| 15 | /// MSI Clock Range | ||
| 16 | /// | ||
| 17 | /// These ranges control the frequency of the MSI. Internally, these ranges map | ||
| 18 | /// to the `MSIRANGE` bits in the `RCC_ICSCR` register. | ||
| 19 | #[derive(Clone, Copy)] | ||
| 20 | pub enum MSIRange { | ||
| 21 | /// Around 65.536 kHz | ||
| 22 | Range0, | ||
| 23 | /// Around 131.072 kHz | ||
| 24 | Range1, | ||
| 25 | /// Around 262.144 kHz | ||
| 26 | Range2, | ||
| 27 | /// Around 524.288 kHz | ||
| 28 | Range3, | ||
| 29 | /// Around 1.048 MHz | ||
| 30 | Range4, | ||
| 31 | /// Around 2.097 MHz (reset value) | ||
| 32 | Range5, | ||
| 33 | /// Around 4.194 MHz | ||
| 34 | Range6, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl Default for MSIRange { | ||
| 38 | fn default() -> MSIRange { | ||
| 39 | MSIRange::Range5 | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | /// PLL divider | ||
| 44 | #[derive(Clone, Copy)] | ||
| 45 | pub enum PLLDiv { | ||
| 46 | Div2, | ||
| 47 | Div3, | ||
| 48 | Div4, | ||
| 49 | } | ||
| 50 | |||
| 51 | /// PLL multiplier | ||
| 52 | #[derive(Clone, Copy)] | ||
| 53 | pub enum PLLMul { | ||
| 54 | Mul3, | ||
| 55 | Mul4, | ||
| 56 | Mul6, | ||
| 57 | Mul8, | ||
| 58 | Mul12, | ||
| 59 | Mul16, | ||
| 60 | Mul24, | ||
| 61 | Mul32, | ||
| 62 | Mul48, | ||
| 63 | } | ||
| 64 | |||
| 65 | /// AHB prescaler | ||
| 66 | #[derive(Clone, Copy)] | ||
| 67 | pub enum AHBPrescaler { | ||
| 68 | NotDivided, | ||
| 69 | Div2, | ||
| 70 | Div4, | ||
| 71 | Div8, | ||
| 72 | Div16, | ||
| 73 | Div64, | ||
| 74 | Div128, | ||
| 75 | Div256, | ||
| 76 | Div512, | ||
| 77 | } | ||
| 78 | |||
| 79 | /// APB prescaler | ||
| 80 | #[derive(Clone, Copy)] | ||
| 81 | pub enum APBPrescaler { | ||
| 82 | NotDivided, | ||
| 83 | Div2, | ||
| 84 | Div4, | ||
| 85 | Div8, | ||
| 86 | Div16, | ||
| 87 | } | ||
| 88 | |||
| 89 | /// PLL clock input source | ||
| 90 | #[derive(Clone, Copy)] | ||
| 91 | pub enum PLLSource { | ||
| 92 | HSI16, | ||
| 93 | HSE(Hertz), | ||
| 94 | } | ||
diff --git a/embassy-stm32/src/rcc/wb55/mod.rs b/embassy-stm32/src/rcc/wb55/mod.rs new file mode 100644 index 000000000..9ae6d62b9 --- /dev/null +++ b/embassy-stm32/src/rcc/wb55/mod.rs | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | pub use super::types::*; | ||
| 2 | use crate::pac; | ||
| 3 | use crate::peripherals::{self, RCC}; | ||
| 4 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 5 | use crate::time::Hertz; | ||
| 6 | use crate::time::U32Ext; | ||
| 7 | use core::marker::PhantomData; | ||
| 8 | use embassy::util::Unborrow; | ||
| 9 | use embassy_extras::unborrow; | ||
| 10 | |||
| 11 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | ||
| 12 | /// and with the addition of the init function to configure a system clock. | ||
| 13 | |||
| 14 | /// Only the basic setup using the HSE and HSI clocks are supported as of now. | ||
| 15 | |||
| 16 | /// HSI speed | ||
| 17 | pub const HSI_FREQ: u32 = 16_000_000; | ||
| 18 | |||
| 19 | /// System clock mux source | ||
| 20 | #[derive(Clone, Copy)] | ||
| 21 | pub enum ClockSrc { | ||
| 22 | HSE(Hertz), | ||
| 23 | HSI16, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Into<u8> for APBPrescaler { | ||
| 27 | fn into(self) -> u8 { | ||
| 28 | match self { | ||
| 29 | APBPrescaler::NotDivided => 1, | ||
| 30 | APBPrescaler::Div2 => 0x04, | ||
| 31 | APBPrescaler::Div4 => 0x05, | ||
| 32 | APBPrescaler::Div8 => 0x06, | ||
| 33 | APBPrescaler::Div16 => 0x07, | ||
| 34 | } | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | impl Into<u8> for AHBPrescaler { | ||
| 39 | fn into(self) -> u8 { | ||
| 40 | match self { | ||
| 41 | AHBPrescaler::NotDivided => 1, | ||
| 42 | AHBPrescaler::Div2 => 0x08, | ||
| 43 | AHBPrescaler::Div4 => 0x09, | ||
| 44 | AHBPrescaler::Div8 => 0x0a, | ||
| 45 | AHBPrescaler::Div16 => 0x0b, | ||
| 46 | AHBPrescaler::Div64 => 0x0c, | ||
| 47 | AHBPrescaler::Div128 => 0x0d, | ||
| 48 | AHBPrescaler::Div256 => 0x0e, | ||
| 49 | AHBPrescaler::Div512 => 0x0f, | ||
| 50 | } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | /// Clocks configutation | ||
| 55 | pub struct Config { | ||
| 56 | mux: ClockSrc, | ||
| 57 | ahb_pre: AHBPrescaler, | ||
| 58 | apb1_pre: APBPrescaler, | ||
| 59 | apb2_pre: APBPrescaler, | ||
| 60 | } | ||
| 61 | |||
| 62 | impl Default for Config { | ||
| 63 | #[inline] | ||
| 64 | fn default() -> Config { | ||
| 65 | Config { | ||
| 66 | mux: ClockSrc::HSI16, | ||
| 67 | ahb_pre: AHBPrescaler::NotDivided, | ||
| 68 | apb1_pre: APBPrescaler::NotDivided, | ||
| 69 | apb2_pre: APBPrescaler::NotDivided, | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | impl Config { | ||
| 75 | #[inline] | ||
| 76 | pub fn clock_src(mut self, mux: ClockSrc) -> Self { | ||
| 77 | self.mux = mux; | ||
| 78 | self | ||
| 79 | } | ||
| 80 | |||
| 81 | #[inline] | ||
| 82 | pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self { | ||
| 83 | self.ahb_pre = pre; | ||
| 84 | self | ||
| 85 | } | ||
| 86 | |||
| 87 | #[inline] | ||
| 88 | pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self { | ||
| 89 | self.apb1_pre = pre; | ||
| 90 | self | ||
| 91 | } | ||
| 92 | |||
| 93 | #[inline] | ||
| 94 | pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self { | ||
| 95 | self.apb2_pre = pre; | ||
| 96 | self | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | /// RCC peripheral | ||
| 101 | pub struct Rcc<'d> { | ||
| 102 | _rb: peripherals::RCC, | ||
| 103 | phantom: PhantomData<&'d mut peripherals::RCC>, | ||
| 104 | } | ||
| 105 | |||
| 106 | impl<'d> Rcc<'d> { | ||
| 107 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | ||
| 108 | unborrow!(rcc); | ||
| 109 | Self { | ||
| 110 | _rb: rcc, | ||
| 111 | phantom: PhantomData, | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | // Safety: RCC init must have been called | ||
| 116 | pub fn clocks(&self) -> &'static Clocks { | ||
| 117 | unsafe { get_freqs() } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 122 | pub trait RccExt { | ||
| 123 | fn freeze(self, config: Config) -> Clocks; | ||
| 124 | } | ||
| 125 | |||
| 126 | impl RccExt for RCC { | ||
| 127 | #[inline] | ||
| 128 | fn freeze(self, cfgr: Config) -> Clocks { | ||
| 129 | let rcc = pac::RCC; | ||
| 130 | let (sys_clk, sw) = match cfgr.mux { | ||
| 131 | ClockSrc::HSI16 => { | ||
| 132 | // Enable HSI16 | ||
| 133 | unsafe { | ||
| 134 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 135 | while !rcc.cr().read().hsirdy() {} | ||
| 136 | } | ||
| 137 | |||
| 138 | (HSI_FREQ, 0x01) | ||
| 139 | } | ||
| 140 | ClockSrc::HSE(freq) => { | ||
| 141 | // Enable HSE | ||
| 142 | unsafe { | ||
| 143 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 144 | while !rcc.cr().read().hserdy() {} | ||
| 145 | } | ||
| 146 | |||
| 147 | (freq.0, 0x02) | ||
| 148 | } | ||
| 149 | }; | ||
| 150 | |||
| 151 | unsafe { | ||
| 152 | rcc.cfgr().modify(|w| { | ||
| 153 | w.set_sw(sw.into()); | ||
| 154 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 155 | w.set_ppre1(cfgr.apb1_pre.into()); | ||
| 156 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 157 | }); | ||
| 158 | } | ||
| 159 | |||
| 160 | let ahb_freq: u32 = match cfgr.ahb_pre { | ||
| 161 | AHBPrescaler::NotDivided => sys_clk, | ||
| 162 | pre => { | ||
| 163 | let pre: u8 = pre.into(); | ||
| 164 | let pre = 1 << (pre as u32 - 7); | ||
| 165 | sys_clk / pre | ||
| 166 | } | ||
| 167 | }; | ||
| 168 | |||
| 169 | let apb1_freq = match cfgr.apb1_pre { | ||
| 170 | APBPrescaler::NotDivided => ahb_freq, | ||
| 171 | pre => { | ||
| 172 | let pre: u8 = pre.into(); | ||
| 173 | let pre: u8 = 1 << (pre - 3); | ||
| 174 | let freq = ahb_freq / pre as u32; | ||
| 175 | freq | ||
| 176 | } | ||
| 177 | }; | ||
| 178 | |||
| 179 | let apb2_freq = match cfgr.apb2_pre { | ||
| 180 | APBPrescaler::NotDivided => ahb_freq, | ||
| 181 | pre => { | ||
| 182 | let pre: u8 = pre.into(); | ||
| 183 | let pre: u8 = 1 << (pre - 3); | ||
| 184 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 185 | freq | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | |||
| 189 | Clocks { | ||
| 190 | sys: sys_clk.hz(), | ||
| 191 | ahb1: ahb_freq.hz(), | ||
| 192 | ahb2: ahb_freq.hz(), | ||
| 193 | ahb3: ahb_freq.hz(), | ||
| 194 | apb1: apb1_freq.hz(), | ||
| 195 | apb2: apb2_freq.hz(), | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | pub unsafe fn init(config: Config) { | ||
| 201 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | ||
| 202 | let clocks = r.freeze(config); | ||
| 203 | set_freqs(clocks); | ||
| 204 | } | ||
diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 227a36a89..01cbf86b6 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs | |||
| @@ -29,7 +29,6 @@ pub struct Spi<'d, T: Instance> { | |||
| 29 | 29 | ||
| 30 | impl<'d, T: Instance> Spi<'d, T> { | 30 | impl<'d, T: Instance> Spi<'d, T> { |
| 31 | pub fn new<F>( | 31 | pub fn new<F>( |
| 32 | pclk: Hertz, | ||
| 33 | _peri: impl Unborrow<Target = T> + 'd, | 32 | _peri: impl Unborrow<Target = T> + 'd, |
| 34 | sck: impl Unborrow<Target = impl SckPin<T>>, | 33 | sck: impl Unborrow<Target = impl SckPin<T>>, |
| 35 | mosi: impl Unborrow<Target = impl MosiPin<T>>, | 34 | mosi: impl Unborrow<Target = impl MosiPin<T>>, |
| @@ -58,6 +57,7 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 58 | }); | 57 | }); |
| 59 | } | 58 | } |
| 60 | 59 | ||
| 60 | let pclk = T::frequency(); | ||
| 61 | let br = Self::compute_baud_rate(pclk, freq.into()); | 61 | let br = Self::compute_baud_rate(pclk, freq.into()); |
| 62 | 62 | ||
| 63 | unsafe { | 63 | unsafe { |
diff --git a/embassy-stm32/src/spi/v2.rs b/embassy-stm32/src/spi/v2.rs index a7ac54cdd..4e135e9df 100644 --- a/embassy-stm32/src/spi/v2.rs +++ b/embassy-stm32/src/spi/v2.rs | |||
| @@ -37,7 +37,6 @@ pub struct Spi<'d, T: Instance> { | |||
| 37 | 37 | ||
| 38 | impl<'d, T: Instance> Spi<'d, T> { | 38 | impl<'d, T: Instance> Spi<'d, T> { |
| 39 | pub fn new<F>( | 39 | pub fn new<F>( |
| 40 | pclk: Hertz, | ||
| 41 | _peri: impl Unborrow<Target = T> + 'd, | 40 | _peri: impl Unborrow<Target = T> + 'd, |
| 42 | sck: impl Unborrow<Target = impl SckPin<T>>, | 41 | sck: impl Unborrow<Target = impl SckPin<T>>, |
| 43 | mosi: impl Unborrow<Target = impl MosiPin<T>>, | 42 | mosi: impl Unborrow<Target = impl MosiPin<T>>, |
| @@ -60,6 +59,7 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 60 | let mosi = mosi.degrade(); | 59 | let mosi = mosi.degrade(); |
| 61 | let miso = miso.degrade(); | 60 | let miso = miso.degrade(); |
| 62 | 61 | ||
| 62 | let pclk = T::frequency(); | ||
| 63 | let br = Self::compute_baud_rate(pclk, freq.into()); | 63 | let br = Self::compute_baud_rate(pclk, freq.into()); |
| 64 | 64 | ||
| 65 | unsafe { | 65 | unsafe { |
diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs index 6073616bd..0b4a71457 100644 --- a/embassy-stm32/src/spi/v3.rs +++ b/embassy-stm32/src/spi/v3.rs | |||
| @@ -37,7 +37,6 @@ pub struct Spi<'d, T: Instance> { | |||
| 37 | 37 | ||
| 38 | impl<'d, T: Instance> Spi<'d, T> { | 38 | impl<'d, T: Instance> Spi<'d, T> { |
| 39 | pub fn new<F>( | 39 | pub fn new<F>( |
| 40 | pclk: Hertz, | ||
| 41 | _peri: impl Unborrow<Target = T> + 'd, | 40 | _peri: impl Unborrow<Target = T> + 'd, |
| 42 | sck: impl Unborrow<Target = impl SckPin<T>>, | 41 | sck: impl Unborrow<Target = impl SckPin<T>>, |
| 43 | mosi: impl Unborrow<Target = impl MosiPin<T>>, | 42 | mosi: impl Unborrow<Target = impl MosiPin<T>>, |
| @@ -62,6 +61,7 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 62 | let mosi = mosi.degrade(); | 61 | let mosi = mosi.degrade(); |
| 63 | let miso = miso.degrade(); | 62 | let miso = miso.degrade(); |
| 64 | 63 | ||
| 64 | let pclk = T::frequency(); | ||
| 65 | let br = Self::compute_baud_rate(pclk, freq.into()); | 65 | let br = Self::compute_baud_rate(pclk, freq.into()); |
| 66 | unsafe { | 66 | unsafe { |
| 67 | T::enable(); | 67 | T::enable(); |
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs index af0d57412..610bb64e9 100644 --- a/examples/stm32f4/src/bin/spi.rs +++ b/examples/stm32f4/src/bin/spi.rs | |||
| @@ -50,7 +50,6 @@ fn main() -> ! { | |||
| 50 | let p = embassy_stm32::init(Default::default()); | 50 | let p = embassy_stm32::init(Default::default()); |
| 51 | 51 | ||
| 52 | let mut spi = Spi::new( | 52 | let mut spi = Spi::new( |
| 53 | Hertz(16_000_000), | ||
| 54 | p.SPI3, | 53 | p.SPI3, |
| 55 | p.PC10, | 54 | p.PC10, |
| 56 | p.PC12, | 55 | p.PC12, |
diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs index 4eb9bfdd2..0e828c436 100644 --- a/examples/stm32l0/src/bin/spi.rs +++ b/examples/stm32l0/src/bin/spi.rs | |||
| @@ -28,7 +28,6 @@ fn main() -> ! { | |||
| 28 | rcc.enable_debug_wfe(&mut p.DBGMCU, true); | 28 | rcc.enable_debug_wfe(&mut p.DBGMCU, true); |
| 29 | 29 | ||
| 30 | let mut spi = Spi::new( | 30 | let mut spi = Spi::new( |
| 31 | Hertz(16_000_000), | ||
| 32 | p.SPI1, | 31 | p.SPI1, |
| 33 | p.PB3, | 32 | p.PB3, |
| 34 | p.PA7, | 33 | p.PA7, |
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs index 9db854dc3..7c672b70d 100644 --- a/examples/stm32l4/src/bin/spi.rs +++ b/examples/stm32l4/src/bin/spi.rs | |||
| @@ -44,7 +44,6 @@ fn main() -> ! { | |||
| 44 | let p = embassy_stm32::init(Default::default()); | 44 | let p = embassy_stm32::init(Default::default()); |
| 45 | 45 | ||
| 46 | let mut spi = Spi::new( | 46 | let mut spi = Spi::new( |
| 47 | Hertz(16_000_000), | ||
| 48 | p.SPI3, | 47 | p.SPI3, |
| 49 | p.PC10, | 48 | p.PC10, |
| 50 | p.PC12, | 49 | p.PC12, |
diff --git a/stm32-metapac/gen/src/lib.rs b/stm32-metapac/gen/src/lib.rs index 399840c5b..5133aef9a 100644 --- a/stm32-metapac/gen/src/lib.rs +++ b/stm32-metapac/gen/src/lib.rs | |||
| @@ -84,7 +84,11 @@ fn find_reg_for_field<'c>( | |||
| 84 | field_name: &str, | 84 | field_name: &str, |
| 85 | ) -> Option<(&'c str, &'c str)> { | 85 | ) -> Option<(&'c str, &'c str)> { |
| 86 | rcc.fieldsets.iter().find_map(|(name, fieldset)| { | 86 | rcc.fieldsets.iter().find_map(|(name, fieldset)| { |
| 87 | if name.starts_with(reg_prefix) { | 87 | // Workaround for some families that prefix register aliases with C1_, which does |
| 88 | // not help matching for clock name. | ||
| 89 | if name.starts_with("C1") || name.starts_with("C2") { | ||
| 90 | None | ||
| 91 | } else if name.starts_with(reg_prefix) { | ||
| 88 | fieldset | 92 | fieldset |
| 89 | .fields | 93 | .fields |
| 90 | .iter() | 94 | .iter() |
| @@ -287,8 +291,23 @@ pub fn gen(options: Options) { | |||
| 287 | 291 | ||
| 288 | match (en, rst) { | 292 | match (en, rst) { |
| 289 | (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { | 293 | (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { |
| 294 | let clock = if clock_prefix == "" { | ||
| 295 | let re = Regex::new("([A-Z]+\\d*).*").unwrap(); | ||
| 296 | if !re.is_match(enable_reg) { | ||
| 297 | panic!( | ||
| 298 | "unable to derive clock name from register name {}", | ||
| 299 | enable_reg | ||
| 300 | ); | ||
| 301 | } else { | ||
| 302 | let caps = re.captures(enable_reg).unwrap(); | ||
| 303 | caps.get(1).unwrap().as_str() | ||
| 304 | } | ||
| 305 | } else { | ||
| 306 | clock_prefix | ||
| 307 | }; | ||
| 290 | peripheral_rcc_table.push(vec