aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/lib.rs')
-rw-r--r--embassy-stm32/src/lib.rs116
1 files changed, 116 insertions, 0 deletions
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 95f59360a..8f001f03b 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -273,7 +273,123 @@ impl Default for Config {
273/// This returns the peripheral singletons that can be used for creating drivers. 273/// This returns the peripheral singletons that can be used for creating drivers.
274/// 274///
275/// This should only be called once at startup, otherwise it panics. 275/// This should only be called once at startup, otherwise it panics.
276#[cfg(not(feature = "_dual-core"))]
276pub fn init(config: Config) -> Peripherals { 277pub fn init(config: Config) -> Peripherals {
278 init_hw(config)
279}
280
281#[cfg(feature = "_dual-core")]
282mod dual_core {
283 use rcc::Clocks;
284
285 use super::*;
286 use core::{
287 mem::MaybeUninit,
288 sync::atomic::{AtomicUsize, Ordering},
289 };
290
291 /// Object containing data that embassy needs to share between cores.
292 ///
293 /// It cannot be initialized by the user. The intended use is:
294 ///
295 /// ```
296 /// #[link_section = ".ram_d3"]
297 /// static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
298 ///
299 /// init_secondary(&SHARED_DATA);
300 /// ```
301 ///
302 /// This static must be placed in the same position for both cores. How and where this is done is left to the user.
303 pub struct SharedData {
304 init_flag: AtomicUsize,
305 clocks: MaybeUninit<Clocks>,
306 }
307
308 const INIT_DONE_FLAG: usize = 0xca11ab1e;
309
310 /// Initialize the `embassy-stm32` HAL with the provided configuration.
311 /// This function does the actual initialization of the hardware, in contrast to [init_secondary] or [try_init_secondary].
312 /// Any core can do the init, but it's important only one core does it.
313 ///
314 /// This returns the peripheral singletons that can be used for creating drivers.
315 ///
316 /// This should only be called once at startup, otherwise it panics.
317 ///
318 /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs
319 /// for more information on its requirements.
320 pub fn init_primary(config: Config, shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
321 let shared_data = unsafe { shared_data.assume_init_ref() };
322
323 rcc::set_freqs_ptr(&shared_data.clocks);
324 let p = init_hw(config);
325
326 shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst);
327
328 p
329 }
330
331 /// Try to initialize the `embassy-stm32` HAL based on the init done by the other core using [init_primary].
332 ///
333 /// This returns the peripheral singletons that can be used for creating drivers if the other core is done with its init.
334 /// If the other core is not done yet, this will return `None`.
335 ///
336 /// This should only be called once at startup, otherwise it may panic.
337 ///
338 /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs
339 /// for more information on its requirements.
340 pub fn try_init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Option<Peripherals> {
341 let shared_data = unsafe { shared_data.assume_init_ref() };
342
343 if shared_data
344 .init_flag
345 .compare_exchange(INIT_DONE_FLAG, 0, Ordering::SeqCst, Ordering::SeqCst)
346 .is_err()
347 {
348 return None;
349 }
350
351 Some(init_secondary_hw(shared_data))
352 }
353
354 /// Initialize the `embassy-stm32` HAL based on the init done by the other core using [init_primary].
355 ///
356 /// This returns the peripheral singletons that can be used for creating drivers when the other core is done with its init.
357 /// If the other core is not done yet, this will spinloop wait on it.
358 ///
359 /// This should only be called once at startup, otherwise it may panic.
360 ///
361 /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs
362 /// for more information on its requirements.
363 pub fn init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
364 let shared_data = unsafe { shared_data.assume_init_ref() };
365
366 while shared_data
367 .init_flag
368 .compare_exchange(INIT_DONE_FLAG, 0, Ordering::SeqCst, Ordering::SeqCst)
369 .is_err()
370 {}
371
372 init_secondary_hw(shared_data)
373 }
374
375 fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals {
376 rcc::set_freqs_ptr(&shared_data.clocks);
377
378 // We use different timers on the different cores, so we have to still initialize one here
379 critical_section::with(|cs| {
380 // must be after rcc init
381 #[cfg(feature = "_time-driver")]
382 time_driver::init(cs);
383 });
384
385 Peripherals::take()
386 }
387}
388
389#[cfg(feature = "_dual-core")]
390pub use dual_core::*;
391
392fn init_hw(config: Config) -> Peripherals {
277 critical_section::with(|cs| { 393 critical_section::with(|cs| {
278 let p = Peripherals::take_with_cs(cs); 394 let p = Peripherals::take_with_cs(cs);
279 395