aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2024-07-08 16:54:06 +0200
committerDion Dokter <[email protected]>2024-07-08 16:54:06 +0200
commit203297b56912c05d2dd6a009ffeb433fb2ffbea6 (patch)
treefa1708215925ad861d68dc8454069c11ae5c861c /embassy-stm32/src
parentb1ea90a87e5ce6b16bbc155ad30d6d3473a998bb (diff)
Make clocks repr C.
Add shared data. Modify freq functions to use shared data. Modify examples to use new init/
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/lib.rs116
-rw-r--r--embassy-stm32/src/rcc/mod.rs27
-rw-r--r--embassy-stm32/src/rtc/mod.rs2
-rw-r--r--embassy-stm32/src/time.rs36
4 files changed, 180 insertions, 1 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
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 024c63cf5..587231b0c 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -48,11 +48,22 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
48/// May be read without a critical section 48/// May be read without a critical section
49pub(crate) static mut REFCOUNT_STOP2: u32 = 0; 49pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
50 50
51#[cfg(not(feature = "_dual-core"))]
51/// Frozen clock frequencies 52/// Frozen clock frequencies
52/// 53///
53/// The existence of this value indicates that the clock configuration can no longer be changed 54/// The existence of this value indicates that the clock configuration can no longer be changed
54static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); 55static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
55 56
57#[cfg(feature = "_dual-core")]
58static CLOCK_FREQS_PTR: core::sync::atomic::AtomicPtr<MaybeUninit<Clocks>> =
59 core::sync::atomic::AtomicPtr::new(core::ptr::null_mut());
60
61#[cfg(feature = "_dual-core")]
62pub(crate) fn set_freqs_ptr(freqs: &'static MaybeUninit<Clocks>) {
63 CLOCK_FREQS_PTR.store(freqs as *const _ as *mut _, core::sync::atomic::Ordering::SeqCst);
64}
65
66#[cfg(not(feature = "_dual-core"))]
56/// Sets the clock frequencies 67/// Sets the clock frequencies
57/// 68///
58/// Safety: Sets a mutable global. 69/// Safety: Sets a mutable global.
@@ -61,11 +72,27 @@ pub(crate) unsafe fn set_freqs(freqs: Clocks) {
61 CLOCK_FREQS = MaybeUninit::new(freqs); 72 CLOCK_FREQS = MaybeUninit::new(freqs);
62} 73}
63 74
75#[cfg(feature = "_dual-core")]
76/// Sets the clock frequencies
77///
78/// Safety: Sets a mutable global.
79pub(crate) unsafe fn set_freqs(freqs: Clocks) {
80 debug!("rcc: {:?}", freqs);
81 CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).write(MaybeUninit::new(freqs));
82}
83
84#[cfg(not(feature = "_dual-core"))]
64/// Safety: Reads a mutable global. 85/// Safety: Reads a mutable global.
65pub(crate) unsafe fn get_freqs() -> &'static Clocks { 86pub(crate) unsafe fn get_freqs() -> &'static Clocks {
66 CLOCK_FREQS.assume_init_ref() 87 CLOCK_FREQS.assume_init_ref()
67} 88}
68 89
90#[cfg(feature = "_dual-core")]
91/// Safety: Reads a mutable global.
92pub(crate) unsafe fn get_freqs() -> &'static Clocks {
93 unwrap!(CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).as_ref()).assume_init_ref()
94}
95
69pub(crate) trait SealedRccPeripheral { 96pub(crate) trait SealedRccPeripheral {
70 fn frequency() -> Hertz; 97 fn frequency() -> Hertz;
71 const RCC_INFO: RccInfo; 98 const RCC_INFO: RccInfo;
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index a7f70b153..fe57cfe66 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -168,7 +168,7 @@ impl Rtc {
168 168
169 fn frequency() -> Hertz { 169 fn frequency() -> Hertz {
170 let freqs = unsafe { crate::rcc::get_freqs() }; 170 let freqs = unsafe { crate::rcc::get_freqs() };
171 freqs.rtc.unwrap() 171 freqs.rtc.to_hertz().unwrap()
172 } 172 }
173 173
174 /// Acquire a [`RtcTimeProvider`] instance. 174 /// Acquire a [`RtcTimeProvider`] instance.
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index 17690aefc..d7337191d 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -87,3 +87,39 @@ impl Div<Hertz> for Hertz {
87 self.0 / rhs.0 87 self.0 / rhs.0
88 } 88 }
89} 89}
90
91#[repr(C)]
92#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
94/// A variant on [Hertz] that acts as an `Option<Hertz>` that is smaller and repr C.
95///
96/// An `Option<Hertz>` can be `.into()`'d into this type and back.
97/// The only restriction is that that [Hertz] cannot have the value 0 since that's
98/// seen as the `None` variant.
99pub struct MaybeHertz(u32);
100
101impl MaybeHertz {
102 /// Same as calling the `.into()` function, but without type inference.
103 pub fn to_hertz(self) -> Option<Hertz> {
104 self.into()
105 }
106}
107
108impl From<Option<Hertz>> for MaybeHertz {
109 fn from(value: Option<Hertz>) -> Self {
110 match value {
111 Some(Hertz(0)) => panic!("Hertz cannot be 0"),
112 Some(Hertz(val)) => Self(val),
113 None => Self(0),
114 }
115 }
116}
117
118impl From<MaybeHertz> for Option<Hertz> {
119 fn from(value: MaybeHertz) -> Self {
120 match value {
121 MaybeHertz(0) => None,
122 MaybeHertz(val) => Some(Hertz(val)),
123 }
124 }
125}