diff options
| -rw-r--r-- | embassy-macros/src/chip/stm32.rs | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/clock.rs | 19 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h7/mod.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l0/mod.rs | 485 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 35 |
6 files changed, 551 insertions, 17 deletions
diff --git a/embassy-macros/src/chip/stm32.rs b/embassy-macros/src/chip/stm32.rs index a1ceadd55..274560a03 100644 --- a/embassy-macros/src/chip/stm32.rs +++ b/embassy-macros/src/chip/stm32.rs | |||
| @@ -7,20 +7,21 @@ pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream | |||
| 7 | let embassy_stm32_path = embassy_prefix.append("embassy_stm32").path(); | 7 | let embassy_stm32_path = embassy_prefix.append("embassy_stm32").path(); |
| 8 | 8 | ||
| 9 | quote!( | 9 | quote!( |
| 10 | use #embassy_stm32_path::{clock::Clock}; | 10 | use #embassy_stm32_path::{interrupt, peripherals, clock::Clock, time::Hertz}; |
| 11 | 11 | ||
| 12 | let p = #embassy_stm32_path::init(#config); | 12 | let p = #embassy_stm32_path::init(#config); |
| 13 | 13 | ||
| 14 | /* | 14 | let mut c = Clock::new( |
| 15 | let mut rtc = #embass::RTC::new(unsafe { <peripherals::TIM2 as #embassy_path::util::Steal>::steal() }, interrupt::take!(TIM2)); | 15 | unsafe { <peripherals::TIM2 as embassy::util::Steal>::steal() }, |
| 16 | let rtc = unsafe { make_static(&mut rtc) }; | 16 | interrupt::take!(TIM2), |
| 17 | rtc.start(); | 17 | ); |
| 18 | let mut alarm = rtc.alarm0(); | 18 | let clock = unsafe { make_static(&mut c) }; |
| 19 | clock.start_tim2(); | ||
| 19 | 20 | ||
| 20 | unsafe { #embassy_path::time::set_clock(rtc) }; | 21 | let mut alarm = clock.alarm1(); |
| 22 | unsafe { #embassy_path::time::set_clock(clock) }; | ||
| 21 | 23 | ||
| 22 | let alarm = unsafe { make_static(&mut alarm) }; | 24 | let alarm = unsafe { make_static(&mut alarm) }; |
| 23 | executor.set_alarm(alarm); | 25 | executor.set_alarm(alarm); |
| 24 | */ | ||
| 25 | ) | 26 | ) |
| 26 | } | 27 | } |
diff --git a/embassy-stm32/src/clock.rs b/embassy-stm32/src/clock.rs index 709a2d36c..3ae83bbb0 100644 --- a/embassy-stm32/src/clock.rs +++ b/embassy-stm32/src/clock.rs | |||
| @@ -10,6 +10,7 @@ use embassy::time::{Clock as EmbassyClock, TICKS_PER_SECOND}; | |||
| 10 | 10 | ||
| 11 | use crate::interrupt::{CriticalSection, Interrupt, Mutex}; | 11 | use crate::interrupt::{CriticalSection, Interrupt, Mutex}; |
| 12 | use crate::pac::timer::TimGp16; | 12 | use crate::pac::timer::TimGp16; |
| 13 | use crate::rcc::get_freqs; | ||
| 13 | use crate::time::Hertz; | 14 | use crate::time::Hertz; |
| 14 | 15 | ||
| 15 | // Clock timekeeping works with something we call "periods", which are time intervals | 16 | // Clock timekeeping works with something we call "periods", which are time intervals |
| @@ -75,6 +76,24 @@ impl<T: Instance> Clock<T> { | |||
| 75 | } | 76 | } |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 79 | // TODO: Temporary until clock code generation is in place | ||
| 80 | pub fn start_tim2(&'static self) { | ||
| 81 | cfg_if::cfg_if! { | ||
| 82 | if #[cfg(feature = "_stm32l0")] { | ||
| 83 | unsafe { | ||
| 84 | let rcc = crate::pac::RCC; | ||
| 85 | rcc.apb1enr() | ||
| 86 | .modify(|w| w.set_tim2en(crate::pac::rcc::vals::Lptimen::ENABLED)); | ||
| 87 | rcc.apb1rstr().modify(|w| w.set_tim2rst(true)); | ||
| 88 | rcc.apb1rstr().modify(|w| w.set_tim2rst(false)); | ||
| 89 | } | ||
| 90 | |||
| 91 | let timer_freq = unsafe { crate::rcc::get_freqs().apb1_clk }; | ||
| 92 | self.start(timer_freq); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 78 | pub fn start(&'static self, timer_freq: Hertz) { | 97 | pub fn start(&'static self, timer_freq: Hertz) { |
| 79 | let inner = T::inner(); | 98 | let inner = T::inner(); |
| 80 | 99 | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 365b58f3c..01e6ea51b 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -47,6 +47,13 @@ pub struct Config { | |||
| 47 | rcc: rcc::Config, | 47 | rcc: rcc::Config, |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | impl Config { | ||
| 51 | pub fn rcc(mut self, rcc: rcc::Config) -> Self { | ||
| 52 | self.rcc = rcc; | ||
| 53 | self | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 50 | impl Default for Config { | 57 | impl Default for Config { |
| 51 | fn default() -> Self { | 58 | fn default() -> Self { |
| 52 | Self { | 59 | Self { |
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs index 85e1cd00f..26d9f0bb9 100644 --- a/embassy-stm32/src/rcc/h7/mod.rs +++ b/embassy-stm32/src/rcc/h7/mod.rs | |||
| @@ -528,6 +528,5 @@ impl<'d> Rcc<'d> { | |||
| 528 | } | 528 | } |
| 529 | } | 529 | } |
| 530 | 530 | ||
| 531 | pub unsafe fn init(config: Config) { | 531 | // TODO |
| 532 | // TODO | 532 | pub unsafe fn init(_config: Config) {} |
| 533 | } | ||
diff --git a/embassy-stm32/src/rcc/l0/mod.rs b/embassy-stm32/src/rcc/l0/mod.rs index 000aaa9e0..0cf3c2cb7 100644 --- a/embassy-stm32/src/rcc/l0/mod.rs +++ b/embassy-stm32/src/rcc/l0/mod.rs | |||
| @@ -1,13 +1,484 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac; |
| 2 | use embassy::util::Steal; | 2 | use crate::pac::peripherals::{self, RCC}; |
| 3 | use pac::rcc::{self, vals}; | 3 | use crate::rcc::{set_freqs, Clocks}; |
| 4 | use crate::time::Hertz; | ||
| 5 | use crate::time::U32Ext; | ||
| 6 | use embassy::util::Unborrow; | ||
| 7 | use pac::rcc::vals; | ||
| 8 | use vals::{Hpre, Msirange, Plldiv, Pllmul, Pllon, Pllsrc, Ppre, Sw}; | ||
| 4 | 9 | ||
| 5 | #[derive(Default)] | 10 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, |
| 6 | pub struct Config {} | 11 | /// and with the addition of the init function to configure a system clock. |
| 12 | |||
| 13 | /// System clock mux source | ||
| 14 | #[derive(Clone, Copy)] | ||
| 15 | pub enum ClockSrc { | ||
| 16 | MSI(MSIRange), | ||
| 17 | PLL(PLLSource, PLLMul, PLLDiv), | ||
| 18 | HSE(Hertz), | ||
| 19 | HSI16, | ||
| 20 | } | ||
| 21 | |||
| 22 | /// MSI Clock Range | ||
| 23 | /// | ||
| 24 | /// These ranges control the frequency of the MSI. Internally, these ranges map | ||
| 25 | /// to the `MSIRANGE` bits in the `RCC_ICSCR` register. | ||
| 26 | #[derive(Clone, Copy)] | ||
| 27 | pub enum MSIRange { | ||
| 28 | /// Around 65.536 kHz | ||
| 29 | Range0, | ||
| 30 | /// Around 131.072 kHz | ||
| 31 | Range1, | ||
| 32 | /// Around 262.144 kHz | ||
| 33 | Range2, | ||
| 34 | /// Around 524.288 kHz | ||
| 35 | Range3, | ||
| 36 | /// Around 1.048 MHz | ||
| 37 | Range4, | ||
| 38 | /// Around 2.097 MHz (reset value) | ||
| 39 | Range5, | ||
| 40 | /// Around 4.194 MHz | ||
| 41 | Range6, | ||
| 42 | } | ||
| 43 | |||
| 44 | impl Default for MSIRange { | ||
| 45 | fn default() -> MSIRange { | ||
| 46 | MSIRange::Range5 | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | /// PLL divider | ||
| 51 | #[derive(Clone, Copy)] | ||
| 52 | pub enum PLLDiv { | ||
| 53 | Div2, | ||
| 54 | Div3, | ||
| 55 | Div4, | ||
| 56 | } | ||
| 57 | |||
| 58 | /// PLL multiplier | ||
| 59 | #[derive(Clone, Copy)] | ||
| 60 | pub enum PLLMul { | ||
| 61 | Mul3, | ||
| 62 | Mul4, | ||
| 63 | Mul6, | ||
| 64 | Mul8, | ||
| 65 | Mul12, | ||
| 66 | Mul16, | ||
| 67 | Mul24, | ||
| 68 | Mul32, | ||
| 69 | Mul48, | ||
| 70 | } | ||
| 71 | |||
| 72 | /// AHB prescaler | ||
| 73 | #[derive(Clone, Copy)] | ||
| 74 | pub enum AHBPrescaler { | ||
| 75 | NotDivided, | ||
| 76 | Div2, | ||
| 77 | Div4, | ||
| 78 | Div8, | ||
| 79 | Div16, | ||
| 80 | Div64, | ||
| 81 | Div128, | ||
| 82 | Div256, | ||
| 83 | Div512, | ||
| 84 | } | ||
| 85 | |||
| 86 | /// APB prescaler | ||
| 87 | #[derive(Clone, Copy)] | ||
| 88 | pub enum APBPrescaler { | ||
| 89 | NotDivided, | ||
| 90 | Div2, | ||
| 91 | Div4, | ||
| 92 | Div8, | ||
| 93 | Div16, | ||
| 94 | } | ||
| 95 | |||
| 96 | /// PLL clock input source | ||
| 97 | #[derive(Clone, Copy)] | ||
| 98 | pub enum PLLSource { | ||
| 99 | HSI16, | ||
| 100 | HSE(Hertz), | ||
| 101 | } | ||
| 102 | |||
| 103 | /// HSI speed | ||
| 104 | pub const HSI_FREQ: u32 = 16_000_000; | ||
| 105 | |||
| 106 | impl Into<Pllmul> for PLLMul { | ||
| 107 | fn into(self) -> Pllmul { | ||
| 108 | match self { | ||
| 109 | PLLMul::Mul3 => Pllmul::MUL3, | ||
| 110 | PLLMul::Mul4 => Pllmul::MUL4, | ||
| 111 | PLLMul::Mul6 => Pllmul::MUL6, | ||
| 112 | PLLMul::Mul8 => Pllmul::MUL8, | ||
| 113 | PLLMul::Mul12 => Pllmul::MUL12, | ||
| 114 | PLLMul::Mul16 => Pllmul::MUL16, | ||
| 115 | PLLMul::Mul24 => Pllmul::MUL24, | ||
| 116 | PLLMul::Mul32 => Pllmul::MUL32, | ||
| 117 | PLLMul::Mul48 => Pllmul::MUL48, | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | impl Into<Plldiv> for PLLDiv { | ||
| 123 | fn into(self) -> Plldiv { | ||
| 124 | match self { | ||
| 125 | PLLDiv::Div2 => Plldiv::DIV2, | ||
| 126 | PLLDiv::Div3 => Plldiv::DIV3, | ||
| 127 | PLLDiv::Div4 => Plldiv::DIV4, | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | impl Into<Pllsrc> for PLLSource { | ||
| 133 | fn into(self) -> Pllsrc { | ||
| 134 | match self { | ||
| 135 | PLLSource::HSI16 => Pllsrc::HSI16, | ||
| 136 | PLLSource::HSE(_) => Pllsrc::HSE, | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | impl Into<Ppre> for APBPrescaler { | ||
| 142 | fn into(self) -> Ppre { | ||
| 143 | match self { | ||
| 144 | APBPrescaler::NotDivided => Ppre::DIV1, | ||
| 145 | APBPrescaler::Div2 => Ppre::DIV2, | ||
| 146 | APBPrescaler::Div4 => Ppre::DIV4, | ||
| 147 | APBPrescaler::Div8 => Ppre::DIV8, | ||
| 148 | APBPrescaler::Div16 => Ppre::DIV16, | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | impl Into<Hpre> for AHBPrescaler { | ||
| 154 | fn into(self) -> Hpre { | ||
| 155 | match self { | ||
| 156 | AHBPrescaler::NotDivided => Hpre::DIV1, | ||
| 157 | AHBPrescaler::Div2 => Hpre::DIV2, | ||
| 158 | AHBPrescaler::Div4 => Hpre::DIV4, | ||
| 159 | AHBPrescaler::Div8 => Hpre::DIV8, | ||
| 160 | AHBPrescaler::Div16 => Hpre::DIV16, | ||
| 161 | AHBPrescaler::Div64 => Hpre::DIV64, | ||
| 162 | AHBPrescaler::Div128 => Hpre::DIV128, | ||
| 163 | AHBPrescaler::Div256 => Hpre::DIV256, | ||
| 164 | AHBPrescaler::Div512 => Hpre::DIV512, | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | impl Into<Msirange> for MSIRange { | ||
| 170 | fn into(self) -> Msirange { | ||
| 171 | match self { | ||
| 172 | MSIRange::Range0 => Msirange::RANGE0, | ||
| 173 | MSIRange::Range1 => Msirange::RANGE1, | ||
| 174 | MSIRange::Range2 => Msirange::RANGE2, | ||
| 175 | MSIRange::Range3 => Msirange::RANGE3, | ||
| 176 | MSIRange::Range4 => Msirange::RANGE4, | ||
| 177 | MSIRange::Range5 => Msirange::RANGE5, | ||
| 178 | MSIRange::Range6 => Msirange::RANGE6, | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | /// Clocks configutation | ||
| 184 | pub struct Config { | ||
| 185 | mux: ClockSrc, | ||
| 186 | ahb_pre: AHBPrescaler, | ||
| 187 | apb1_pre: APBPrescaler, | ||
| 188 | apb2_pre: APBPrescaler, | ||
| 189 | } | ||
| 190 | |||
| 191 | impl Default for Config { | ||
| 192 | #[inline] | ||
| 193 | fn default() -> Config { | ||
| 194 | Config { | ||
| 195 | mux: ClockSrc::MSI(MSIRange::default()), | ||
| 196 | ahb_pre: AHBPrescaler::NotDivided, | ||
| 197 | apb1_pre: APBPrescaler::NotDivided, | ||
| 198 | apb2_pre: APBPrescaler::NotDivided, | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | impl Config { | ||
| 204 | #[inline] | ||
| 205 | pub fn clock_src(mut self, mux: ClockSrc) -> Self { | ||
| 206 | self.mux = mux; | ||
| 207 | self | ||
| 208 | } | ||
| 209 | |||
| 210 | #[inline] | ||
| 211 | pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self { | ||
| 212 | self.ahb_pre = pre; | ||
| 213 | self | ||
| 214 | } | ||
| 215 | |||
| 216 | #[inline] | ||
| 217 | pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self { | ||
| 218 | self.apb1_pre = pre; | ||
| 219 | self | ||
| 220 | } | ||
| 221 | |||
| 222 | #[inline] | ||
| 223 | pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self { | ||
| 224 | self.apb2_pre = pre; | ||
| 225 | self | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | /// RCC peripheral | ||
| 230 | pub struct Rcc {} | ||
| 231 | |||
| 232 | impl Rcc { | ||
| 233 | pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'static) -> Self { | ||
| 234 | Self {} | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | /* | ||
| 239 | pub fn enable_lse(&mut self, _: &PWR) -> LSE { | ||
| 240 | self.rb.csr.modify(|_, w| { | ||
| 241 | // Enable LSE clock | ||
| 242 | w.lseon().set_bit() | ||
| 243 | }); | ||
| 244 | while self.rb.csr.read().lserdy().bit_is_clear() {} | ||
| 245 | LSE(()) | ||
| 246 | } | ||
| 247 | } | ||
| 248 | impl Rcc { | ||
| 249 | pub fn enable_hsi48(&mut self, syscfg: &mut SYSCFG, crs: CRS) -> HSI48 { | ||
| 250 | // Reset CRS peripheral | ||
| 251 | self.rb.apb1rstr.modify(|_, w| w.crsrst().set_bit()); | ||
| 252 | self.rb.apb1rstr.modify(|_, w| w.crsrst().clear_bit()); | ||
| 253 | |||
| 254 | // Enable CRS peripheral | ||
| 255 | self.rb.apb1enr.modify(|_, w| w.crsen().set_bit()); | ||
| 256 | |||
| 257 | // Initialize CRS | ||
| 258 | crs.cfgr.write(|w| | ||
| 259 | // Select LSE as synchronization source | ||
| 260 | unsafe { w.syncsrc().bits(0b01) }); | ||
| 261 | crs.cr | ||
| 262 | .modify(|_, w| w.autotrimen().set_bit().cen().set_bit()); | ||
| 263 | |||
| 264 | // Enable VREFINT reference for HSI48 oscillator | ||
| 265 | syscfg | ||
| 266 | .syscfg | ||
| 267 | .cfgr3 | ||
| 268 | .modify(|_, w| w.enref_hsi48().set_bit().en_vrefint().set_bit()); | ||
| 269 | |||
| 270 | // Select HSI48 as USB clock | ||
| 271 | self.rb.ccipr.modify(|_, w| w.hsi48msel().set_bit()); | ||
| 272 | |||
| 273 | // Enable dedicated USB clock | ||
| 274 | self.rb.crrcr.modify(|_, w| w.hsi48on().set_bit()); | ||
| 275 | while self.rb.crrcr.read().hsi48rdy().bit_is_clear() {} | ||
| 276 | |||
| 277 | HSI48(()) | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | impl Rcc { | ||
| 282 | /// Configure MCO (Microcontroller Clock Output). | ||
| 283 | pub fn configure_mco<P>( | ||
| 284 | &mut self, | ||
| 285 | source: MCOSEL_A, | ||
| 286 | prescaler: MCOPRE_A, | ||
| 287 | output_pin: P, | ||
| 288 | ) -> MCOEnabled | ||
| 289 | where | ||
| 290 | P: mco::Pin, | ||
| 291 | { | ||
| 292 | output_pin.into_mco(); | ||
| 293 | |||
| 294 | self.rb.cfgr.modify(|_, w| { | ||
| 295 | w.mcosel().variant(source); | ||
| 296 | w.mcopre().variant(prescaler) | ||
| 297 | }); | ||
| 298 | |||
| 299 | MCOEnabled(()) | ||
| 300 | } | ||
| 301 | } | ||
| 302 | */ | ||
| 303 | |||
| 304 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 305 | pub trait RccExt { | ||
| 306 | fn freeze(self, config: Config) -> Clocks; | ||
| 307 | } | ||
| 308 | |||
| 309 | impl RccExt for RCC { | ||
| 310 | // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by | ||
| 311 | // marking this function and all `Config` constructors and setters as `#[inline]`. | ||
| 312 | // This saves ~900 Bytes for the `pwr.rs` example. | ||
| 313 | #[inline] | ||
| 314 | fn freeze(self, cfgr: Config) -> Clocks { | ||
| 315 | let rcc = pac::RCC; | ||
| 316 | let (sys_clk, sw) = match cfgr.mux { | ||
| 317 | ClockSrc::MSI(range) => { | ||
| 318 | // Set MSI range | ||
| 319 | unsafe { | ||
| 320 | rcc.icscr().write(|w| w.set_msirange(range.into())); | ||
| 321 | } | ||
| 322 | |||
| 323 | // Enable MSI | ||
| 324 | unsafe { | ||
| 325 | rcc.cr().write(|w| w.set_msion(Pllon::ENABLED)); | ||
| 326 | while !rcc.cr().read().msirdy() {} | ||
| 327 | } | ||
| 328 | |||
| 329 | let freq = 32_768 * (1 << (range as u8 + 1)); | ||
| 330 | (freq, Sw::MSI) | ||
| 331 | } | ||
| 332 | ClockSrc::HSI16 => { | ||
| 333 | // Enable HSI16 | ||
| 334 | unsafe { | ||
| 335 | rcc.cr().write(|w| w.set_hsi16on(Pllon::ENABLED)); | ||
| 336 | while !rcc.cr().read().hsi16rdyf() {} | ||
| 337 | } | ||
| 338 | |||
| 339 | (HSI_FREQ, Sw::HSI16) | ||
| 340 | } | ||
| 341 | ClockSrc::HSE(freq) => { | ||
| 342 | // Enable HSE | ||
| 343 | unsafe { | ||
| 344 | rcc.cr().write(|w| w.set_hseon(Pllon::ENABLED)); | ||
| 345 | while !rcc.cr().read().hserdy() {} | ||
| 346 | } | ||
| 347 | |||
| 348 | (freq.0, Sw::HSE) | ||
| 349 | } | ||
| 350 | ClockSrc::PLL(src, mul, div) => { | ||
| 351 | let freq = match src { | ||
| 352 | PLLSource::HSE(freq) => { | ||
| 353 | // Enable HSE | ||
| 354 | unsafe { | ||
| 355 | rcc.cr().write(|w| w.set_hseon(Pllon::ENABLED)); | ||
| 356 | while !rcc.cr().read().hserdy() {} | ||
| 357 | } | ||
| 358 | freq.0 | ||
| 359 | } | ||
| 360 | PLLSource::HSI16 => { | ||
| 361 | // Enable HSI | ||
| 362 | unsafe { | ||
| 363 | rcc.cr().write(|w| w.set_hsi16on(Pllon::ENABLED)); | ||
| 364 | while !rcc.cr().read().hsi16rdyf() {} | ||
| 365 | } | ||
| 366 | HSI_FREQ | ||
| 367 | } | ||
| 368 | }; | ||
| 369 | |||
| 370 | // Disable PLL | ||
| 371 | unsafe { | ||
| 372 | rcc.cr().modify(|w| w.set_pllon(Pllon::DISABLED)); | ||
| 373 | while rcc.cr().read().pllrdy() {} | ||
| 374 | } | ||
| 375 | |||
| 376 | let freq = match mul { | ||
| 377 | PLLMul::Mul3 => freq * 3, | ||
| 378 | PLLMul::Mul4 => freq * 4, | ||
| 379 | PLLMul::Mul6 => freq * 6, | ||
| 380 | PLLMul::Mul8 => freq * 8, | ||
| 381 | PLLMul::Mul12 => freq * 12, | ||
| 382 | PLLMul::Mul16 => freq * 16, | ||
| 383 | PLLMul::Mul24 => freq * 24, | ||
| 384 | PLLMul::Mul32 => freq * 32, | ||
| 385 | PLLMul::Mul48 => freq * 48, | ||
| 386 | }; | ||
| 387 | |||
| 388 | let freq = match div { | ||
| 389 | PLLDiv::Div2 => freq / 2, | ||
| 390 | PLLDiv::Div3 => freq / 3, | ||
| 391 | PLLDiv::Div4 => freq / 4, | ||
| 392 | }; | ||
| 393 | assert!(freq <= 32_u32.mhz().0); | ||
| 394 | |||
| 395 | unsafe { | ||
| 396 | rcc.cfgr().write(move |w| { | ||
| 397 | w.set_pllmul(mul.into()); | ||
| 398 | w.set_plldiv(div.into()); | ||
| 399 | w.set_pllsrc(src.into()); | ||
| 400 | }); | ||
| 401 | |||
| 402 | // Enable PLL | ||
| 403 | rcc.cr().modify(|w| w.set_pllon(Pllon::ENABLED)); | ||
| 404 | while !rcc.cr().read().pllrdy() {} | ||
| 405 | } | ||
| 406 | |||
| 407 | (freq, Sw::PLL) | ||
| 408 | } | ||
| 409 | }; | ||
| 410 | |||
| 411 | unsafe { | ||
| 412 | rcc.cfgr().modify(|w| { | ||
| 413 | w.set_sw(sw.into()); | ||
| 414 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 415 | w.set_ppre(0, cfgr.apb1_pre.into()); | ||
| 416 | w.set_ppre(1, cfgr.apb2_pre.into()); | ||
| 417 | }); | ||
| 418 | } | ||
| 419 | |||
| 420 | let ahb_freq: u32 = match cfgr.ahb_pre { | ||
| 421 | AHBPrescaler::NotDivided => sys_clk, | ||
| 422 | pre => { | ||
| 423 | let pre: Hpre = pre.into(); | ||
| 424 | let pre = 1 << (pre.0 as u32 - 7); | ||
| 425 | sys_clk / pre | ||
| 426 | } | ||
| 427 | }; | ||
| 428 | |||
| 429 | let (apb1_freq, apb1_tim_freq, apb1_pre) = match cfgr.apb1_pre { | ||
| 430 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq, 1), | ||
| 431 | pre => { | ||
| 432 | let pre: Ppre = pre.into(); | ||
| 433 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 434 | let freq = ahb_freq / pre as u32; | ||
| 435 | (freq, freq * 2, pre as u8) | ||
| 436 | } | ||
| 437 | }; | ||
| 438 | |||
| 439 | let (apb2_freq, apb2_tim_freq, apb2_pre) = match cfgr.apb2_pre { | ||
| 440 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq, 1), | ||
| 441 | pre => { | ||
| 442 | let pre: Ppre = pre.into(); | ||
| 443 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 444 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 445 | (freq, freq * 2, pre as u8) | ||
| 446 | } | ||
| 447 | }; | ||
| 448 | |||
| 449 | Clocks { | ||
| 450 | sys_clk: sys_clk.hz(), | ||
| 451 | ahb_clk: ahb_freq.hz(), | ||
| 452 | apb1_clk: apb1_freq.hz(), | ||
| 453 | apb2_clk: apb2_freq.hz(), | ||
| 454 | apb1_tim_clk: apb1_tim_freq.hz(), | ||
| 455 | apb2_tim_clk: apb2_tim_freq.hz(), | ||
| 456 | apb1_pre, | ||
| 457 | apb2_pre, | ||
| 458 | } | ||
| 459 | } | ||
| 460 | } | ||
| 461 | |||
| 462 | /// Token that exists only, if the HSI48 clock has been enabled | ||
| 463 | /// | ||
| 464 | /// You can get an instance of this struct by calling [`Rcc::enable_hsi48`]. | ||
| 465 | #[derive(Clone, Copy)] | ||
| 466 | pub struct HSI48(()); | ||
| 467 | |||
| 468 | /// Token that exists only if MCO (Microcontroller Clock Out) has been enabled. | ||
| 469 | /// | ||
| 470 | /// You can get an instance of this struct by calling [`Rcc::configure_mco`]. | ||
| 471 | #[derive(Clone, Copy)] | ||
| 472 | pub struct MCOEnabled(()); | ||
| 473 | |||
| 474 | /// Token that exists only, if the LSE clock has been enabled | ||
| 475 | /// | ||
| 476 | /// You can get an instance of this struct by calling [`Rcc::enable_lse`]. | ||
| 477 | #[derive(Clone, Copy)] | ||
| 478 | pub struct LSE(()); | ||
| 7 | 479 | ||
| 8 | pub unsafe fn init(config: Config) { | 480 | pub unsafe fn init(config: Config) { |
| 9 | let rcc = pac::RCC; | 481 | let rcc = pac::RCC; |
| 10 | |||
| 11 | let enabled = vals::Iophen::ENABLED; | 482 | let enabled = vals::Iophen::ENABLED; |
| 12 | rcc.iopenr().write(|w| { | 483 | rcc.iopenr().write(|w| { |
| 13 | w.set_iopaen(enabled); | 484 | w.set_iopaen(enabled); |
| @@ -17,4 +488,8 @@ pub unsafe fn init(config: Config) { | |||
| 17 | w.set_iopeen(enabled); | 488 | w.set_iopeen(enabled); |
| 18 | w.set_iophen(enabled); | 489 | w.set_iophen(enabled); |
| 19 | }); | 490 | }); |
| 491 | |||
| 492 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | ||
| 493 | let clocks = r.freeze(config); | ||
| 494 | set_freqs(clocks); | ||
| 20 | } | 495 | } |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 59938e7bf..cb8780343 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -1,3 +1,35 @@ | |||
| 1 | use crate::time::Hertz; | ||
| 2 | use core::mem::MaybeUninit; | ||
| 3 | |||
| 4 | /// Frozen clock frequencies | ||
| 5 | /// | ||
| 6 | /// The existence of this value indicates that the clock configuration can no longer be changed | ||
| 7 | #[derive(Clone, Copy)] | ||
| 8 | pub struct Clocks { | ||
| 9 | pub sys_clk: Hertz, | ||
| 10 | pub ahb_clk: Hertz, | ||
| 11 | pub apb1_clk: Hertz, | ||
| 12 | pub apb1_tim_clk: Hertz, | ||
| 13 | pub apb2_clk: Hertz, | ||
| 14 | pub apb2_tim_clk: Hertz, | ||
| 15 | pub apb1_pre: u8, | ||
| 16 | pub apb2_pre: u8, | ||
| 17 | } | ||
| 18 | |||
| 19 | static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); | ||
| 20 | |||
| 21 | /// Sets the clock frequencies | ||
| 22 | /// | ||
| 23 | /// Safety: Sets a mutable global. | ||
| 24 | pub unsafe fn set_freqs(freqs: Clocks) { | ||
| 25 | CLOCK_FREQS.as_mut_ptr().write(freqs); | ||
| 26 | } | ||
| 27 | |||
| 28 | /// Safety: Reads a mutable global. | ||
| 29 | pub unsafe fn get_freqs() -> &'static Clocks { | ||
| 30 | &*CLOCK_FREQS.as_ptr() | ||
| 31 | } | ||
| 32 | |||
| 1 | cfg_if::cfg_if! { | 33 | cfg_if::cfg_if! { |
| 2 | if #[cfg(feature = "_stm32h7")] { | 34 | if #[cfg(feature = "_stm32h7")] { |
| 3 | mod h7; | 35 | mod h7; |
| @@ -8,6 +40,7 @@ cfg_if::cfg_if! { | |||
| 8 | } else { | 40 | } else { |
| 9 | #[derive(Default)] | 41 | #[derive(Default)] |
| 10 | pub struct Config {} | 42 | pub struct Config {} |
| 11 | pub fn init(_config: Config) {} | 43 | pub unsafe fn init(_config: Config) { |
| 44 | } | ||
| 12 | } | 45 | } |
| 13 | } | 46 | } |
