aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/ipcc.rs56
-rw-r--r--embassy-stm32/src/rcc/mod.rs8
-rw-r--r--embassy-stm32/src/rcc/wb.rs342
-rw-r--r--tests/stm32/src/bin/wpan_ble.rs6
-rw-r--r--tests/stm32/src/bin/wpan_mac.rs6
5 files changed, 313 insertions, 105 deletions
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index a24cba9f0..e100ca5cc 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -265,63 +265,9 @@ pub(crate) mod sealed {
265} 265}
266 266
267fn _configure_pwr() { 267fn _configure_pwr() {
268 // TODO: move this to RCC 268 // TODO: move the rest of this to rcc
269
270 let pwr = crate::pac::PWR;
271 let rcc = crate::pac::RCC; 269 let rcc = crate::pac::RCC;
272 270
273 rcc.cfgr().modify(|w| w.set_stopwuck(true));
274
275 pwr.cr1().modify(|w| w.set_dbp(true));
276 pwr.cr1().modify(|w| w.set_dbp(true));
277
278 // configure LSE
279 rcc.bdcr().modify(|w| w.set_lseon(true));
280
281 // select system clock source = PLL
282 // set PLL coefficients
283 // m: 2,
284 // n: 12,
285 // r: 3,
286 // q: 4,
287 // p: 3,
288 let src_bits = 0b11;
289 let pllp = (3 - 1) & 0b11111;
290 let pllq = (4 - 1) & 0b111;
291 let pllr = (3 - 1) & 0b111;
292 let plln = 12 & 0b1111111;
293 let pllm = (2 - 1) & 0b111;
294 rcc.pllcfgr().modify(|w| {
295 w.set_pllsrc(src_bits);
296 w.set_pllm(pllm);
297 w.set_plln(plln);
298 w.set_pllr(pllr);
299 w.set_pllp(pllp);
300 w.set_pllpen(true);
301 w.set_pllq(pllq);
302 w.set_pllqen(true);
303 });
304 // enable PLL
305 rcc.cr().modify(|w| w.set_pllon(true));
306 rcc.cr().write(|w| w.set_hsion(false));
307 // while !rcc.cr().read().pllrdy() {}
308
309 // configure SYSCLK mux to use PLL clocl
310 rcc.cfgr().modify(|w| w.set_sw(0b11));
311
312 // configure CPU1 & CPU2 dividers
313 rcc.cfgr().modify(|w| w.set_hpre(0)); // not divided
314 rcc.extcfgr().modify(|w| {
315 w.set_c2hpre(0b1000); // div2
316 w.set_shdhpre(0); // not divided
317 });
318
319 // apply APB1 / APB2 values
320 rcc.cfgr().modify(|w| {
321 w.set_ppre1(0b000); // not divided
322 w.set_ppre2(0b000); // not divided
323 });
324
325 // TODO: required 271 // TODO: required
326 // set RF wake-up clock = LSE 272 // set RF wake-up clock = LSE
327 rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); 273 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 886fc0b93..4ae65d3e6 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -78,6 +78,14 @@ pub struct Clocks {
78/// The existence of this value indicates that the clock configuration can no longer be changed 78/// The existence of this value indicates that the clock configuration can no longer be changed
79static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); 79static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
80 80
81#[cfg(stm32wb)]
82/// RCC initialization function
83pub(crate) unsafe fn init(config: Config) {
84 set_freqs(compute_clocks(&config));
85
86 configure_clocks(&config);
87}
88
81/// Sets the clock frequencies 89/// Sets the clock frequencies
82/// 90///
83/// Safety: Sets a mutable global. 91/// Safety: Sets a mutable global.
diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs
index e6123821a..4322b950a 100644
--- a/embassy-stm32/src/rcc/wb.rs
+++ b/embassy-stm32/src/rcc/wb.rs
@@ -1,6 +1,5 @@
1use crate::pac::RCC; 1use crate::rcc::Clocks;
2use crate::rcc::{set_freqs, Clocks}; 2use crate::time::{khz, mhz, Hertz};
3use crate::time::Hertz;
4 3
5/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, 4/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
6/// and with the addition of the init function to configure a system clock. 5/// and with the addition of the init function to configure a system clock.
@@ -13,11 +12,94 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
13/// LSI speed 12/// LSI speed
14pub const LSI_FREQ: Hertz = Hertz(32_000); 13pub const LSI_FREQ: Hertz = Hertz(32_000);
15 14
16/// System clock mux source
17#[derive(Clone, Copy)] 15#[derive(Clone, Copy)]
18pub enum ClockSrc { 16pub enum HsePrescaler {
19 HSE(Hertz), 17 NotDivided,
20 HSI16, 18 Div2,
19}
20
21impl From<HsePrescaler> for bool {
22 fn from(value: HsePrescaler) -> Self {
23 match value {
24 HsePrescaler::NotDivided => false,
25 HsePrescaler::Div2 => true,
26 }
27 }
28}
29
30pub struct Hse {
31 pub prediv: HsePrescaler,
32
33 pub frequency: Hertz,
34}
35
36/// System clock mux source
37#[derive(Clone, Copy, PartialEq)]
38pub enum Sysclk {
39 /// MSI selected as sysclk
40 MSI,
41 /// HSI selected as sysclk
42 HSI,
43 /// HSE selected as sysclk
44 HSE,
45 /// PLL selected as sysclk
46 Pll,
47}
48
49impl From<Sysclk> for u8 {
50 fn from(value: Sysclk) -> Self {
51 match value {
52 Sysclk::MSI => 0b00,
53 Sysclk::HSI => 0b01,
54 Sysclk::HSE => 0b10,
55 Sysclk::Pll => 0b11,
56 }
57 }
58}
59
60#[derive(Clone, Copy, PartialEq)]
61pub enum PllSource {
62 Hsi,
63 Msi,
64 Hse,
65}
66
67impl From<PllSource> for u8 {
68 fn from(value: PllSource) -> Self {
69 match value {
70 PllSource::Msi => 0b01,
71 PllSource::Hsi => 0b10,
72 PllSource::Hse => 0b11,
73 }
74 }
75}
76
77pub enum Pll48Source {
78 PllSai,
79 Pll,
80 Msi,
81 Hsi48,
82}
83
84pub struct PllMux {
85 /// Source clock selection.
86 pub source: PllSource,
87
88 /// PLL pre-divider (DIVM). Must be between 1 and 63.
89 pub prediv: u8,
90}
91
92pub struct Pll {
93 /// PLL multiplication factor. Must be between 4 and 512.
94 pub mul: u16,
95
96 /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
97 /// On PLL1, it must be even (in particular, it cannot be 1.)
98 pub divp: Option<u16>,
99 /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
100 pub divq: Option<u16>,
101 /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
102 pub divr: Option<u16>,
21} 103}
22 104
23/// AHB prescaler 105/// AHB prescaler
@@ -84,86 +166,250 @@ impl Into<u8> for AHBPrescaler {
84 166
85/// Clocks configutation 167/// Clocks configutation
86pub struct Config { 168pub struct Config {
87 pub mux: ClockSrc, 169 pub hse: Option<Hse>,
88 pub ahb_pre: AHBPrescaler, 170 pub lse: Option<Hertz>,
171 pub sys: Sysclk,
172 pub mux: Option<PllMux>,
173 pub pll48: Option<Pll48Source>,
174
175 pub pll: Option<Pll>,
176 pub pllsai: Option<Pll>,
177
178 pub ahb1_pre: AHBPrescaler,
179 pub ahb2_pre: AHBPrescaler,
180 pub ahb3_pre: AHBPrescaler,
89 pub apb1_pre: APBPrescaler, 181 pub apb1_pre: APBPrescaler,
90 pub apb2_pre: APBPrescaler, 182 pub apb2_pre: APBPrescaler,
91} 183}
92 184
185pub const WPAN_DEFAULT: Config = Config {
186 hse: Some(Hse {
187 frequency: mhz(32),
188 prediv: HsePrescaler::NotDivided,
189 }),
190 lse: Some(khz(32)),
191 sys: Sysclk::Pll,
192 mux: Some(PllMux {
193 source: PllSource::Hse,
194 prediv: 2,
195 }),
196 pll48: None,
197
198 pll: Some(Pll {
199 mul: 12,
200 divp: Some(3),
201 divq: Some(4),
202 divr: Some(3),
203 }),
204 pllsai: None,
205
206 ahb1_pre: AHBPrescaler::NotDivided,
207 ahb2_pre: AHBPrescaler::Div2,
208 ahb3_pre: AHBPrescaler::NotDivided,
209 apb1_pre: APBPrescaler::NotDivided,
210 apb2_pre: APBPrescaler::NotDivided,
211};
212
93impl Default for Config { 213impl Default for Config {
94 #[inline] 214 #[inline]
95 fn default() -> Config { 215 fn default() -> Config {
96 Config { 216 Config {
97 mux: ClockSrc::HSI16, 217 hse: None,
98 ahb_pre: AHBPrescaler::NotDivided, 218 lse: None,
219 sys: Sysclk::HSI,
220 mux: None,
221 pll48: None,
222 pll: None,
223 pllsai: None,
224
225 ahb1_pre: AHBPrescaler::NotDivided,
226 ahb2_pre: AHBPrescaler::NotDivided,
227 ahb3_pre: AHBPrescaler::NotDivided,
99 apb1_pre: APBPrescaler::NotDivided, 228 apb1_pre: APBPrescaler::NotDivided,
100 apb2_pre: APBPrescaler::NotDivided, 229 apb2_pre: APBPrescaler::NotDivided,
101 } 230 }
102 } 231 }
103} 232}
104 233
105pub(crate) unsafe fn init(config: Config) { 234pub(crate) fn compute_clocks(config: &Config) -> Clocks {
106 let (sys_clk, sw) = match config.mux { 235 let hse_clk = config.hse.as_ref().map(|hse| match hse.prediv {
107 ClockSrc::HSI16 => { 236 HsePrescaler::NotDivided => hse.frequency,
108 // Enable HSI16 237 HsePrescaler::Div2 => hse.frequency / 2u32,
109 RCC.cr().write(|w| w.set_hsion(true)); 238 });
110 while !RCC.cr().read().hsirdy() {}
111 239
112 (HSI_FREQ.0, 0x01) 240 let mux_clk = config.mux.as_ref().map(|pll_mux| {
241 (match pll_mux.source {
242 PllSource::Hse => hse_clk.unwrap(),
243 PllSource::Hsi => HSI_FREQ,
244 _ => unreachable!(),
245 } / pll_mux.prediv)
246 });
247
248 let (pll_r, _pll_q, _pll_p) = match &config.pll {
249 Some(pll) => {
250 let pll_vco = mux_clk.unwrap() * pll.mul as u32;
251
252 (
253 pll.divr.map(|divr| pll_vco / divr),
254 pll.divq.map(|divq| pll_vco / divq),
255 pll.divp.map(|divp| pll_vco / divp),
256 )
113 } 257 }
114 ClockSrc::HSE(freq) => { 258 None => (None, None, None),
115 // Enable HSE 259 };
116 RCC.cr().write(|w| w.set_hseon(true));
117 while !RCC.cr().read().hserdy() {}
118 260
119 (freq.0, 0x02) 261 let sys_clk = match config.sys {
262 Sysclk::HSE => hse_clk.unwrap(),
263 Sysclk::HSI => HSI_FREQ,
264 Sysclk::Pll => pll_r.unwrap(),
265 _ => unreachable!(),
266 };
267
268 let ahb1_clk = match config.ahb1_pre {
269 AHBPrescaler::NotDivided => sys_clk,
270 pre => {
271 let pre: u8 = pre.into();
272 let pre = 1u32 << (pre as u32 - 7);
273 sys_clk / pre
120 } 274 }
121 }; 275 };
122 276
123 RCC.cfgr().modify(|w| { 277 let ahb2_clk = match config.ahb2_pre {
124 w.set_sw(sw.into()); 278 AHBPrescaler::NotDivided => sys_clk,
125 w.set_hpre(config.ahb_pre.into()); 279 pre => {
126 w.set_ppre1(config.apb1_pre.into()); 280 let pre: u8 = pre.into();
127 w.set_ppre2(config.apb2_pre.into()); 281 let pre = 1u32 << (pre as u32 - 7);
128 }); 282 sys_clk / pre
283 }
284 };
129 285
130 let ahb_freq: u32 = match config.ahb_pre { 286 let ahb3_clk = match config.ahb3_pre {
131 AHBPrescaler::NotDivided => sys_clk, 287 AHBPrescaler::NotDivided => sys_clk,
132 pre => { 288 pre => {
133 let pre: u8 = pre.into(); 289 let pre: u8 = pre.into();
134 let pre = 1 << (pre as u32 - 7); 290 let pre = 1u32 << (pre as u32 - 7);
135 sys_clk / pre 291 sys_clk / pre
136 } 292 }
137 }; 293 };
138 294
139 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 295 let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
140 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 296 APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk),
141 pre => { 297 pre => {
142 let pre: u8 = pre.into(); 298 let pre: u8 = pre.into();
143 let pre: u8 = 1 << (pre - 3); 299 let pre: u8 = 1 << (pre - 3);
144 let freq = ahb_freq / pre as u32; 300 let freq = ahb1_clk / pre as u32;
145 (freq, freq * 2) 301 (freq, freq * 2u32)
146 } 302 }
147 }; 303 };
148 304
149 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 305 let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
150 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 306 APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk),
151 pre => { 307 pre => {
152 let pre: u8 = pre.into(); 308 let pre: u8 = pre.into();
153 let pre: u8 = 1 << (pre - 3); 309 let pre: u8 = 1 << (pre - 3);
154 let freq = ahb_freq / pre as u32; 310 let freq = ahb1_clk / pre as u32;
155 (freq, freq * 2) 311 (freq, freq * 2u32)
312 }
313 };
314
315 Clocks {
316 sys: sys_clk,
317 ahb1: ahb1_clk,
318 ahb2: ahb2_clk,
319 ahb3: ahb3_clk,
320 apb1: apb1_clk,
321 apb2: apb2_clk,
322 apb1_tim: apb1_tim_clk,
323 apb2_tim: apb2_tim_clk,
324 }
325}
326
327pub(crate) fn configure_clocks(config: &Config) {
328 let pwr = crate::pac::PWR;
329 let rcc = crate::pac::RCC;
330
331 let needs_hsi = if let Some(pll_mux) = &config.mux {
332 pll_mux.source == PllSource::Hsi
333 } else {
334 false
335 };
336
337 if needs_hsi || config.sys == Sysclk::HSI {
338 rcc.cr().modify(|w| {
339 w.set_hsion(true);
340 });
341
342 while !rcc.cr().read().hsirdy() {}
343 }
344
345 match &config.lse {
346 Some(_) => {
347 rcc.cfgr().modify(|w| w.set_stopwuck(true));
348
349 pwr.cr1().modify(|w| w.set_dbp(true));
350 pwr.cr1().modify(|w| w.set_dbp(true));
351
352 rcc.bdcr().modify(|w| w.set_lseon(true));
353 }
354 _ => {}
355 }
356
357 match &config.hse {
358 Some(hse) => {
359 rcc.cr().modify(|w| {
360 w.set_hsepre(hse.prediv.into());
361 w.set_hseon(true);
362 });
363
364 while !rcc.cr().read().hserdy() {}
365 }
366 _ => {}
367 }
368
369 match &config.mux {
370 Some(pll_mux) => {
371 rcc.pllcfgr().modify(|w| {
372 w.set_pllm(pll_mux.prediv);
373 w.set_pllsrc(pll_mux.source.into());
374 });
156 } 375 }
376 _ => {}
157 }; 377 };
158 378
159 set_freqs(Clocks { 379 match &config.pll {
160 sys: Hertz(sys_clk), 380 Some(pll) => {
161 ahb1: Hertz(ahb_freq), 381 rcc.pllcfgr().modify(|w| {
162 ahb2: Hertz(ahb_freq), 382 w.set_plln(pll.mul as u8);
163 ahb3: Hertz(ahb_freq), 383 pll.divp.map(|divp| {
164 apb1: Hertz(apb1_freq), 384 w.set_pllpen(true);
165 apb2: Hertz(apb2_freq), 385 w.set_pllp((divp - 1) as u8)
166 apb1_tim: Hertz(apb1_tim_freq), 386 });
167 apb2_tim: Hertz(apb2_tim_freq), 387 pll.divq.map(|divq| {
388 w.set_pllqen(true);
389 w.set_pllq((divq - 1) as u8)
390 });
391 pll.divr.map(|divr| {
392 // w.set_pllren(true);
393 w.set_pllr((divr - 1) as u8);
394 });
395 });
396
397 rcc.cr().modify(|w| w.set_pllon(true));
398
399 while !rcc.cr().read().pllrdy() {}
400 }
401 _ => {}
402 }
403
404 rcc.cfgr().modify(|w| {
405 w.set_sw(config.sys.into());
406 w.set_hpre(config.ahb1_pre.into());
407 w.set_ppre1(config.apb1_pre.into());
408 w.set_ppre2(config.apb2_pre.into());
409 });
410
411 rcc.extcfgr().modify(|w| {
412 w.set_c2hpre(config.ahb2_pre.into());
413 w.set_shdhpre(config.ahb3_pre.into());
168 }); 414 });
169} 415}
diff --git a/tests/stm32/src/bin/wpan_ble.rs b/tests/stm32/src/bin/wpan_ble.rs
index 3ad8aca4e..452da77a4 100644
--- a/tests/stm32/src/bin/wpan_ble.rs
+++ b/tests/stm32/src/bin/wpan_ble.rs
@@ -12,6 +12,7 @@ use common::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_stm32::bind_interrupts; 13use embassy_stm32::bind_interrupts;
14use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; 14use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
15use embassy_stm32::rcc::WPAN_DEFAULT;
15use embassy_stm32_wpan::hci::host::uart::UartHci; 16use embassy_stm32_wpan::hci::host::uart::UartHci;
16use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; 17use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
17use embassy_stm32_wpan::hci::types::AdvertisingType; 18use embassy_stm32_wpan::hci::types::AdvertisingType;
@@ -40,7 +41,10 @@ async fn run_mm_queue(memory_manager: mm::MemoryManager) {
40 41
41#[embassy_executor::main] 42#[embassy_executor::main]
42async fn main(spawner: Spawner) { 43async fn main(spawner: Spawner) {
43 let p = embassy_stm32::init(config()); 44 let mut config = config();
45 config.rcc = WPAN_DEFAULT;
46
47 let p = embassy_stm32::init(config);
44 info!("Hello World!"); 48 info!("Hello World!");
45 49
46 let config = Config::default(); 50 let config = Config::default();
diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs
index b04a19ee9..7eab2fd38 100644
--- a/tests/stm32/src/bin/wpan_mac.rs
+++ b/tests/stm32/src/bin/wpan_mac.rs
@@ -10,6 +10,7 @@ use common::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_stm32::bind_interrupts; 11use embassy_stm32::bind_interrupts;
12use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; 12use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
13use embassy_stm32::rcc::WPAN_DEFAULT;
13use embassy_stm32_wpan::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest}; 14use embassy_stm32_wpan::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest};
14use embassy_stm32_wpan::mac::event::MacEvent; 15use embassy_stm32_wpan::mac::event::MacEvent;
15use embassy_stm32_wpan::mac::typedefs::{ 16use embassy_stm32_wpan::mac::typedefs::{
@@ -31,7 +32,10 @@ async fn run_mm_queue(memory_manager: mm::MemoryManager) {
31 32
32#[embassy_executor::main] 33#[embassy_executor::main]
33async fn main(spawner: Spawner) { 34async fn main(spawner: Spawner) {
34 let p = embassy_stm32::init(config()); 35 let mut config = config();
36 config.rcc = WPAN_DEFAULT;
37
38 let p = embassy_stm32::init(config);
35 info!("Hello World!"); 39 info!("Hello World!");
36 40
37 let config = Config::default(); 41 let config = Config::default();