diff options
| -rw-r--r-- | embassy-stm32/src/rcc/l4/mod.rs | 147 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/rng.rs | 37 |
2 files changed, 171 insertions, 13 deletions
diff --git a/embassy-stm32/src/rcc/l4/mod.rs b/embassy-stm32/src/rcc/l4/mod.rs index aac0febe2..e1eadf856 100644 --- a/embassy-stm32/src/rcc/l4/mod.rs +++ b/embassy-stm32/src/rcc/l4/mod.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | pub use super::types::*; | ||
| 2 | use crate::pac; | 1 | use crate::pac; |
| 3 | use crate::peripherals::{self, RCC}; | 2 | use crate::peripherals::{self, RCC}; |
| 4 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; |
| @@ -14,18 +13,116 @@ use stm32_metapac::rcc::vals::Msirange; | |||
| 14 | 13 | ||
| 15 | /// Only the basic setup using the HSE and HSI clocks are supported as of now. | 14 | /// Only the basic setup using the HSE and HSI clocks are supported as of now. |
| 16 | 15 | ||
| 17 | /// HSI speed | 16 | /// HSI16 speed |
| 18 | pub const HSI_FREQ: u32 = 16_000_000; | 17 | pub const HSI16_FREQ: u32 = 16_000_000; |
| 19 | 18 | ||
| 20 | /// System clock mux source | 19 | /// System clock mux source |
| 21 | #[derive(Clone, Copy)] | 20 | #[derive(Clone, Copy)] |
| 22 | pub enum ClockSrc { | 21 | pub enum ClockSrc { |
| 23 | PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul), | 22 | PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>), |
| 24 | MSI(MSIRange), | 23 | MSI(MSIRange), |
| 25 | HSE(Hertz), | 24 | HSE(Hertz), |
| 26 | HSI16, | 25 | HSI16, |
| 27 | } | 26 | } |
| 28 | 27 | ||
| 28 | /// MSI Clock Range | ||
| 29 | /// | ||
| 30 | /// These ranges control the frequency of the MSI. Internally, these ranges map | ||
| 31 | /// to the `MSIRANGE` bits in the `RCC_ICSCR` register. | ||
| 32 | #[derive(Clone, Copy)] | ||
| 33 | pub enum MSIRange { | ||
| 34 | /// Around 100 kHz | ||
| 35 | Range0, | ||
| 36 | /// Around 200 kHz | ||
| 37 | Range1, | ||
| 38 | /// Around 400 kHz | ||
| 39 | Range2, | ||
| 40 | /// Around 800 kHz | ||
| 41 | Range3, | ||
| 42 | /// Around 1 MHz | ||
| 43 | Range4, | ||
| 44 | /// Around 2 MHz | ||
| 45 | Range5, | ||
| 46 | /// Around 4 MHz (reset value) | ||
| 47 | Range6, | ||
| 48 | /// Around 8 MHz | ||
| 49 | Range7, | ||
| 50 | /// Around 16 MHz | ||
| 51 | Range8, | ||
| 52 | /// Around 24 MHz | ||
| 53 | Range9, | ||
| 54 | /// Around 32 MHz | ||
| 55 | Range10, | ||
| 56 | /// Around 48 MHz | ||
| 57 | Range11, | ||
| 58 | } | ||
| 59 | |||
| 60 | impl Into<u32> for MSIRange { | ||
| 61 | fn into(self) -> u32 { | ||
| 62 | match self { | ||
| 63 | MSIRange::Range0 => 100_000, | ||
| 64 | MSIRange::Range1 => 200_000, | ||
| 65 | MSIRange::Range2 => 400_000, | ||
| 66 | MSIRange::Range3 => 800_000, | ||
| 67 | MSIRange::Range4 => 1_000_000, | ||
| 68 | MSIRange::Range5 => 2_000_000, | ||
| 69 | MSIRange::Range6 => 4_000_000, | ||
| 70 | MSIRange::Range7 => 8_000_000, | ||
| 71 | MSIRange::Range8 => 16_000_000, | ||
| 72 | MSIRange::Range9 => 24_000_000, | ||
| 73 | MSIRange::Range10 => 32_000_000, | ||
| 74 | MSIRange::Range11 => 48_000_000, | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | impl Default for MSIRange { | ||
| 80 | fn default() -> MSIRange { | ||
| 81 | MSIRange::Range6 | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | pub type PLL48Div = PLLClkDiv; | ||
| 86 | |||
| 87 | /// PLL divider | ||
| 88 | #[derive(Clone, Copy)] | ||
| 89 | pub enum PLLDiv { | ||
| 90 | Div2, | ||
| 91 | Div3, | ||
| 92 | Div4, | ||
| 93 | } | ||
| 94 | |||
| 95 | /// AHB prescaler | ||
| 96 | #[derive(Clone, Copy, PartialEq)] | ||
| 97 | pub enum AHBPrescaler { | ||
| 98 | NotDivided, | ||
| 99 | Div2, | ||
| 100 | Div4, | ||
| 101 | Div8, | ||
| 102 | Div16, | ||
| 103 | Div64, | ||
| 104 | Div128, | ||
| 105 | Div256, | ||
| 106 | Div512, | ||
| 107 | } | ||
| 108 | |||
| 109 | /// APB prescaler | ||
| 110 | #[derive(Clone, Copy)] | ||
| 111 | pub enum APBPrescaler { | ||
| 112 | NotDivided, | ||
| 113 | Div2, | ||
| 114 | Div4, | ||
| 115 | Div8, | ||
| 116 | Div16, | ||
| 117 | } | ||
| 118 | |||
| 119 | /// PLL clock input source | ||
| 120 | #[derive(Clone, Copy)] | ||
| 121 | pub enum PLLSource { | ||
| 122 | HSI16, | ||
| 123 | HSE(Hertz), | ||
| 124 | } | ||
| 125 | |||
| 29 | seq_macro::seq!(N in 8..=86 { | 126 | seq_macro::seq!(N in 8..=86 { |
| 30 | #[derive(Clone, Copy)] | 127 | #[derive(Clone, Copy)] |
| 31 | pub enum PLLMul { | 128 | pub enum PLLMul { |
| @@ -134,6 +231,11 @@ impl Into<Msirange> for MSIRange { | |||
| 134 | MSIRange::Range4 => Msirange::RANGE1M, | 231 | MSIRange::Range4 => Msirange::RANGE1M, |
| 135 | MSIRange::Range5 => Msirange::RANGE2M, | 232 | MSIRange::Range5 => Msirange::RANGE2M, |
| 136 | MSIRange::Range6 => Msirange::RANGE4M, | 233 | MSIRange::Range6 => Msirange::RANGE4M, |
| 234 | MSIRange::Range7 => Msirange::RANGE8M, | ||
| 235 | MSIRange::Range8 => Msirange::RANGE16M, | ||
| 236 | MSIRange::Range9 => Msirange::RANGE24M, | ||
| 237 | MSIRange::Range10 => Msirange::RANGE32M, | ||
| 238 | MSIRange::Range11 => Msirange::RANGE48M, | ||
| 137 | } | 239 | } |
| 138 | } | 240 | } |
| 139 | } | 241 | } |
| @@ -177,7 +279,7 @@ impl Default for Config { | |||
| 177 | #[inline] | 279 | #[inline] |
| 178 | fn default() -> Config { | 280 | fn default() -> Config { |
| 179 | Config { | 281 | Config { |
| 180 | mux: ClockSrc::HSI16, | 282 | mux: ClockSrc::MSI(MSIRange::Range6), |
| 181 | ahb_pre: AHBPrescaler::NotDivided, | 283 | ahb_pre: AHBPrescaler::NotDivided, |
| 182 | apb1_pre: APBPrescaler::NotDivided, | 284 | apb1_pre: APBPrescaler::NotDivided, |
| 183 | apb2_pre: APBPrescaler::NotDivided, | 285 | apb2_pre: APBPrescaler::NotDivided, |
| @@ -249,7 +351,7 @@ impl RccExt for RCC { | |||
| 249 | while !rcc.cr().read().hsirdy() {} | 351 | while !rcc.cr().read().hsirdy() {} |
| 250 | } | 352 | } |
| 251 | 353 | ||
| 252 | (HSI_FREQ, 0x01) | 354 | (HSI16_FREQ, 0b01) |
| 253 | } | 355 | } |
| 254 | ClockSrc::HSE(freq) => { | 356 | ClockSrc::HSE(freq) => { |
| 255 | // Enable HSE | 357 | // Enable HSE |
| @@ -258,22 +360,30 @@ impl RccExt for RCC { | |||
| 258 | while !rcc.cr().read().hserdy() {} | 360 | while !rcc.cr().read().hserdy() {} |
| 259 | } | 361 | } |
| 260 | 362 | ||
| 261 | (freq.0, 0x02) | 363 | (freq.0, 0b10) |
| 262 | } | 364 | } |
| 263 | ClockSrc::MSI(range) => { | 365 | ClockSrc::MSI(range) => { |
| 264 | // Enable MSI | 366 | // Enable MSI |
| 265 | unsafe { | 367 | unsafe { |
| 266 | rcc.cr().write(|w| { | 368 | rcc.cr().write(|w| { |
| 267 | w.set_msirange(range.into()); | 369 | let bits: Msirange = range.into(); |
| 370 | w.set_msirange(bits); | ||
| 371 | w.set_msipllen(false); | ||
| 372 | w.set_msirgsel(true); | ||
| 268 | w.set_msion(true); | 373 | w.set_msion(true); |
| 269 | }); | 374 | }); |
| 270 | while !rcc.cr().read().msirdy() {} | 375 | while !rcc.cr().read().msirdy() {} |
| 271 | } | ||
| 272 | 376 | ||
| 273 | let freq = 32_768 * (1 << (range as u8 + 1)); | 377 | // Enable as clock source for USB, RNG if running at 48 MHz |
| 274 | (freq, 0b00) | 378 | if let MSIRange::Range11 = range { |
| 379 | rcc.ccipr().modify(|w| { | ||
| 380 | w.set_clk48sel(0b11); | ||
| 381 | }); | ||
| 382 | } | ||
| 383 | } | ||
| 384 | (range.into(), 0b00) | ||
| 275 | } | 385 | } |
| 276 | ClockSrc::PLL(src, div, prediv, mul) => { | 386 | ClockSrc::PLL(src, div, prediv, mul, pll48div) => { |
| 277 | let freq = match src { | 387 | let freq = match src { |
| 278 | PLLSource::HSE(freq) => { | 388 | PLLSource::HSE(freq) => { |
| 279 | // Enable HSE | 389 | // Enable HSE |
| @@ -289,7 +399,7 @@ impl RccExt for RCC { | |||
| 289 | rcc.cr().write(|w| w.set_hsion(true)); | 399 | rcc.cr().write(|w| w.set_hsion(true)); |
| 290 | while !rcc.cr().read().hsirdy() {} | 400 | while !rcc.cr().read().hsirdy() {} |
| 291 | } | 401 | } |
| 292 | HSI_FREQ | 402 | HSI16_FREQ |
| 293 | } | 403 | } |
| 294 | }; | 404 | }; |
| 295 | 405 | ||
| @@ -308,9 +418,20 @@ impl RccExt for RCC { | |||
| 308 | w.set_plln(mul.into()); | 418 | w.set_plln(mul.into()); |
| 309 | w.set_pllm(prediv.into()); | 419 | w.set_pllm(prediv.into()); |
| 310 | w.set_pllr(div.into()); | 420 | w.set_pllr(div.into()); |
| 421 | if let Some(pll48div) = pll48div { | ||
| 422 | w.set_pllq(pll48div.into()); | ||
| 423 | w.set_pllqen(true); | ||
| 424 | } | ||
| 311 | w.set_pllsrc(src.into()); | 425 | w.set_pllsrc(src.into()); |
| 312 | }); | 426 | }); |
| 313 | 427 | ||
| 428 | // Enable as clock source for USB, RNG if PLL48 divisor is provided | ||
| 429 | if pll48div.is_some() { | ||
| 430 | rcc.ccipr().modify(|w| { | ||
| 431 | w.set_clk48sel(0b10); | ||
| 432 | }); | ||
| 433 | } | ||
| 434 | |||
| 314 | // Enable PLL | 435 | // Enable PLL |
| 315 | rcc.cr().modify(|w| w.set_pllon(true)); | 436 | rcc.cr().modify(|w| w.set_pllon(true)); |
| 316 | while !rcc.cr().read().pllrdy() {} | 437 | while !rcc.cr().read().pllrdy() {} |
diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs new file mode 100644 index 000000000..ee5f579f8 --- /dev/null +++ b/examples/stm32l4/src/bin/rng.rs | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | #[path = "../example_common.rs"] | ||
| 6 | mod example_common; | ||
| 7 | use embassy::executor::Spawner; | ||
| 8 | use embassy::time::{Duration, Timer}; | ||
| 9 | use embassy::traits::rng::Random; | ||
| 10 | use embassy_stm32::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv}; | ||
| 11 | use embassy_stm32::rng::Rng; | ||
| 12 | use embassy_stm32::{Config, Peripherals}; | ||
| 13 | use example_common::*; | ||
| 14 | |||
| 15 | fn config() -> Config { | ||
| 16 | let mut config = Config::default(); | ||
| 17 | config.rcc = config.rcc.clock_src(ClockSrc::PLL( | ||
| 18 | PLLSource::HSI16, | ||
| 19 | PLLClkDiv::Div2, | ||
| 20 | PLLSrcDiv::Div1, | ||
| 21 | PLLMul::Mul8, | ||
| 22 | Some(PLLClkDiv::Div2), | ||
| 23 | )); | ||
| 24 | config | ||
| 25 | } | ||
| 26 | |||
| 27 | #[embassy::main(config = "config()")] | ||
| 28 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 29 | info!("Hello World!"); | ||
| 30 | |||
| 31 | let mut rng = Random::new(Rng::new(p.RNG)); | ||
| 32 | |||
| 33 | loop { | ||
| 34 | info!("random {}", unwrap!(rng.next_u8(16).await)); | ||
| 35 | Timer::after(Duration::from_secs(1)).await; | ||
| 36 | } | ||
| 37 | } | ||
