diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs index a88174a0c..f1ec19ac1 100644 --- a/embassy-executor/src/raw/run_queue.rs +++ b/embassy-executor/src/raw/run_queue.rs @@ -4,15 +4,16 @@ use core::ptr::NonNull; use atomic_polyfill::{AtomicPtr, Ordering}; use super::{TaskHeader, TaskRef}; +use crate::raw::util::SyncUnsafeCell; pub(crate) struct RunQueueItem { - next: AtomicPtr, + next: SyncUnsafeCell>, } impl RunQueueItem { pub const fn new() -> Self { Self { - next: AtomicPtr::new(ptr::null_mut()), + next: SyncUnsafeCell::new(None), } } } @@ -51,7 +52,12 @@ impl RunQueue { self.head .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| { was_empty = prev.is_null(); - task.header().run_queue_item.next.store(prev, Ordering::Relaxed); + unsafe { + // safety: the pointer is either null or valid + let prev = NonNull::new(prev).map(|ptr| TaskRef::from_ptr(ptr.as_ptr())); + // safety: there are no concurrent accesses to `next` + task.header().run_queue_item.next.set(prev); + } Some(task.as_ptr() as *mut _) }) .ok(); @@ -64,18 +70,19 @@ impl RunQueue { /// and will be processed by the *next* call to `dequeue_all`, *not* the current one. pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) { // Atomically empty the queue. - let mut ptr = self.head.swap(ptr::null_mut(), Ordering::AcqRel); + let ptr = self.head.swap(ptr::null_mut(), Ordering::AcqRel); + + // safety: the pointer is either null or valid + let mut next = unsafe { NonNull::new(ptr).map(|ptr| TaskRef::from_ptr(ptr.as_ptr())) }; // Iterate the linked list of tasks that were previously in the queue. - while let Some(task) = NonNull::new(ptr) { - let task = unsafe { TaskRef::from_ptr(task.as_ptr()) }; + while let Some(task) = next { // If the task re-enqueues itself, the `next` pointer will get overwritten. // Therefore, first read the next pointer, and only then process the task. - let next = task.header().run_queue_item.next.load(Ordering::Relaxed); + // safety: there are no concurrent accesses to `next` + next = unsafe { task.header().run_queue_item.next.get() }; on_task(task); - - ptr = next } } } diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 2a17eb9b0..e0929ca49 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -29,10 +29,66 @@ pub struct Config { pub pclk1: Option, pub pclk2: Option, + #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] + pub plli2s: Option, + pub pll48: bool, } -unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bool) -> PllResults { +#[cfg(stm32f410)] +unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option) -> Option { + None +} + +// Not currently implemented, but will be in the future +#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] +unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option) -> Option { + None +} + +#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] +unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option) -> Option { + let min_div = 2; + let max_div = 7; + let target = match plli2s { + Some(target) => target, + None => return None, + }; + + // We loop through the possible divider values to find the best configuration. Looping + // through all possible "N" values would result in more iterations. + let (n, outdiv, output, _error) = (min_div..=max_div) + .filter_map(|outdiv| { + let target_vco_out = match target.checked_mul(outdiv) { + Some(x) => x, + None => return None, + }; + let n = (target_vco_out + (vco_in >> 1)) / vco_in; + let vco_out = vco_in * n; + if !(100_000_000..=432_000_000).contains(&vco_out) { + return None; + } + let output = vco_out / outdiv; + let error = (output as i32 - target as i32).unsigned_abs(); + Some((n, outdiv, output, error)) + }) + .min_by_key(|(_, _, _, error)| *error)?; + + RCC.plli2scfgr().modify(|w| { + w.set_plli2sn(n as u16); + w.set_plli2sr(outdiv as u8); + }); + + Some(output) +} + +unsafe fn setup_pll( + pllsrcclk: u32, + use_hse: bool, + pllsysclk: Option, + plli2s: Option, + pll48clk: bool, +) -> PllResults { use crate::pac::rcc::vals::{Pllp, Pllsrc}; let sysclk = pllsysclk.unwrap_or(pllsrcclk); @@ -43,6 +99,7 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48 use_pll: false, pllsysclk: None, pll48clk: None, + plli2sclk: None, }; } // Input divisor from PLL source clock, must result to frequency in @@ -101,6 +158,7 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48 use_pll: true, pllsysclk: Some(real_pllsysclk), pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, + plli2sclk: setup_i2s_pll(vco_in, plli2s), } } @@ -286,6 +344,10 @@ pub(crate) unsafe fn init(config: Config) { pllsrcclk, config.hse.is_some(), if sysclk_on_pll { Some(sysclk) } else { None }, + #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] + config.plli2s.map(|i2s| i2s.0), + #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] + None, config.pll48, ); @@ -376,6 +438,13 @@ pub(crate) unsafe fn init(config: Config) { while !RCC.cr().read().pllrdy() {} } + #[cfg(not(stm32f410))] + if plls.plli2sclk.is_some() { + RCC.cr().modify(|w| w.set_plli2son(true)); + + while !RCC.cr().read().plli2srdy() {} + } + RCC.cfgr().modify(|w| { w.set_ppre2(Ppre(ppre2_bits)); w.set_ppre1(Ppre(ppre1_bits)); @@ -409,6 +478,12 @@ pub(crate) unsafe fn init(config: Config) { ahb3: Hertz(hclk), pll48: plls.pll48clk.map(Hertz), + + #[cfg(not(stm32f410))] + plli2s: plls.plli2sclk.map(Hertz), + + #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] + pllsai: None, }); } @@ -416,6 +491,8 @@ struct PllResults { use_pll: bool, pllsysclk: Option, pll48clk: Option, + #[allow(dead_code)] + plli2sclk: Option, } mod max { diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index d6a31f17b..d6816d6a8 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -60,6 +60,12 @@ pub struct Clocks { #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] pub pll48: Option, + #[cfg(all(rcc_f4, not(stm32f410)))] + pub plli2s: Option, + + #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] + pub pllsai: Option, + #[cfg(stm32f1)] pub adc: Hertz,