aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/rcc/l4/mod.rs147
-rw-r--r--examples/stm32l4/src/bin/rng.rs37
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 @@
1pub use super::types::*;
2use crate::pac; 1use crate::pac;
3use crate::peripherals::{self, RCC}; 2use crate::peripherals::{self, RCC};
4use crate::rcc::{get_freqs, set_freqs, Clocks}; 3use 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
18pub const HSI_FREQ: u32 = 16_000_000; 17pub 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)]
22pub enum ClockSrc { 21pub 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)]
33pub 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
60impl 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
79impl Default for MSIRange {
80 fn default() -> MSIRange {
81 MSIRange::Range6
82 }
83}
84
85pub type PLL48Div = PLLClkDiv;
86
87/// PLL divider
88#[derive(Clone, Copy)]
89pub enum PLLDiv {
90 Div2,
91 Div3,
92 Div4,
93}
94
95/// AHB prescaler
96#[derive(Clone, Copy, PartialEq)]
97pub 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)]
111pub enum APBPrescaler {
112 NotDivided,
113 Div2,
114 Div4,
115 Div8,
116 Div16,
117}
118
119/// PLL clock input source
120#[derive(Clone, Copy)]
121pub enum PLLSource {
122 HSI16,
123 HSE(Hertz),
124}
125
29seq_macro::seq!(N in 8..=86 { 126seq_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"]
6mod example_common;
7use embassy::executor::Spawner;
8use embassy::time::{Duration, Timer};
9use embassy::traits::rng::Random;
10use embassy_stm32::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv};
11use embassy_stm32::rng::Rng;
12use embassy_stm32::{Config, Peripherals};
13use example_common::*;
14
15fn 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()")]
28async 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}