stm32/low-power: refactor refcount
This commit is contained in:
		@@ -564,7 +564,7 @@ fn main() {
 | 
				
			|||||||
                    fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
 | 
					                    fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
 | 
				
			||||||
                        #before_enable
 | 
					                        #before_enable
 | 
				
			||||||
                        #[cfg(feature = "low-power")]
 | 
					                        #[cfg(feature = "low-power")]
 | 
				
			||||||
                        crate::rcc::clock_refcount_add(_cs);
 | 
					                        unsafe { crate::rcc::REFCOUNT_STOP2 += 1 };
 | 
				
			||||||
                        crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
 | 
					                        crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
 | 
				
			||||||
                        #after_enable
 | 
					                        #after_enable
 | 
				
			||||||
                        #rst
 | 
					                        #rst
 | 
				
			||||||
@@ -573,7 +573,7 @@ fn main() {
 | 
				
			|||||||
                        #before_disable
 | 
					                        #before_disable
 | 
				
			||||||
                        crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
 | 
					                        crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
 | 
				
			||||||
                        #[cfg(feature = "low-power")]
 | 
					                        #[cfg(feature = "low-power")]
 | 
				
			||||||
                        crate::rcc::clock_refcount_sub(_cs);
 | 
					                        unsafe { crate::rcc::REFCOUNT_STOP2 -= 1 };
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -226,9 +226,9 @@ pub fn init(config: Config) -> Peripherals {
 | 
				
			|||||||
            time_driver::init(cs);
 | 
					            time_driver::init(cs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #[cfg(feature = "low-power")]
 | 
					            #[cfg(feature = "low-power")]
 | 
				
			||||||
            while !crate::rcc::low_power_ready() {
 | 
					            {
 | 
				
			||||||
                crate::rcc::clock_refcount_sub(cs);
 | 
					                crate::rcc::REFCOUNT_STOP2 = 0
 | 
				
			||||||
            }
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        p
 | 
					        p
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,6 @@ use cortex_m::peripheral::SCB;
 | 
				
			|||||||
use embassy_executor::*;
 | 
					use embassy_executor::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::interrupt;
 | 
					use crate::interrupt;
 | 
				
			||||||
use crate::rcc::low_power_ready;
 | 
					 | 
				
			||||||
use crate::time_driver::{get_driver, RtcDriver};
 | 
					use crate::time_driver::{get_driver, RtcDriver};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const THREAD_PENDER: usize = usize::MAX;
 | 
					const THREAD_PENDER: usize = usize::MAX;
 | 
				
			||||||
@@ -33,6 +32,15 @@ pub fn stop_with_rtc(rtc: &'static Rtc) {
 | 
				
			|||||||
    unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
 | 
					    unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn stop_ready(stop_mode: StopMode) -> bool {
 | 
				
			||||||
 | 
					    unsafe { EXECUTOR.as_mut().unwrap() }.stop_ready(stop_mode)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[non_exhaustive]
 | 
				
			||||||
 | 
					pub enum StopMode {
 | 
				
			||||||
 | 
					    Stop2,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Thread mode executor, using WFE/SEV.
 | 
					/// Thread mode executor, using WFE/SEV.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// This is the simplest and most common kind of executor. It runs on
 | 
					/// This is the simplest and most common kind of executor. It runs on
 | 
				
			||||||
@@ -80,12 +88,18 @@ impl Executor {
 | 
				
			|||||||
        trace!("low power: stop with rtc configured");
 | 
					        trace!("low power: stop with rtc configured");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn stop_ready(&self, stop_mode: StopMode) -> bool {
 | 
				
			||||||
 | 
					        match stop_mode {
 | 
				
			||||||
 | 
					            StopMode::Stop2 => unsafe { crate::rcc::REFCOUNT_STOP2 == 0 },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn configure_pwr(&mut self) {
 | 
					    fn configure_pwr(&mut self) {
 | 
				
			||||||
        self.scb.clear_sleepdeep();
 | 
					        self.scb.clear_sleepdeep();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        compiler_fence(Ordering::SeqCst);
 | 
					        compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if !low_power_ready() {
 | 
					        if !self.stop_ready(StopMode::Stop2) {
 | 
				
			||||||
            trace!("low power: not ready to stop");
 | 
					            trace!("low power: not ready to stop");
 | 
				
			||||||
        } else if self.time_driver.pause_time().is_err() {
 | 
					        } else if self.time_driver.pause_time().is_err() {
 | 
				
			||||||
            trace!("low power: failed to pause time");
 | 
					            trace!("low power: failed to pause time");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,8 +23,6 @@ pub use mco::*;
 | 
				
			|||||||
#[cfg_attr(rcc_u5, path = "u5.rs")]
 | 
					#[cfg_attr(rcc_u5, path = "u5.rs")]
 | 
				
			||||||
#[cfg_attr(rcc_wba, path = "wba.rs")]
 | 
					#[cfg_attr(rcc_wba, path = "wba.rs")]
 | 
				
			||||||
mod _version;
 | 
					mod _version;
 | 
				
			||||||
#[cfg(feature = "low-power")]
 | 
					 | 
				
			||||||
use core::sync::atomic::{AtomicU32, Ordering};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use _version::*;
 | 
					pub use _version::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -183,27 +181,7 @@ pub struct Clocks {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(feature = "low-power")]
 | 
					#[cfg(feature = "low-power")]
 | 
				
			||||||
static CLOCK_REFCOUNT: AtomicU32 = AtomicU32::new(0);
 | 
					pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(feature = "low-power")]
 | 
					 | 
				
			||||||
pub fn low_power_ready() -> bool {
 | 
					 | 
				
			||||||
    // trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst));
 | 
					 | 
				
			||||||
    CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(feature = "low-power")]
 | 
					 | 
				
			||||||
pub(crate) fn clock_refcount_add(_cs: critical_section::CriticalSection) {
 | 
					 | 
				
			||||||
    // We don't check for overflow because constructing more than u32 peripherals is unlikely
 | 
					 | 
				
			||||||
    let n = CLOCK_REFCOUNT.load(Ordering::Relaxed);
 | 
					 | 
				
			||||||
    CLOCK_REFCOUNT.store(n + 1, Ordering::Relaxed);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(feature = "low-power")]
 | 
					 | 
				
			||||||
pub(crate) fn clock_refcount_sub(_cs: critical_section::CriticalSection) {
 | 
					 | 
				
			||||||
    let n = CLOCK_REFCOUNT.load(Ordering::Relaxed);
 | 
					 | 
				
			||||||
    assert!(n != 0);
 | 
					 | 
				
			||||||
    CLOCK_REFCOUNT.store(n - 1, Ordering::Relaxed);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Frozen clock frequencies
 | 
					/// Frozen clock frequencies
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,7 +187,9 @@ impl Rtc {
 | 
				
			|||||||
        critical_section::with(|cs| {
 | 
					        critical_section::with(|cs| {
 | 
				
			||||||
            <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(cs);
 | 
					            <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(cs);
 | 
				
			||||||
            #[cfg(feature = "low-power")]
 | 
					            #[cfg(feature = "low-power")]
 | 
				
			||||||
            crate::rcc::clock_refcount_sub(cs);
 | 
					            unsafe {
 | 
				
			||||||
 | 
					                crate::rcc::REFCOUNT_STOP2 -= 1
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut this = Self {
 | 
					        let mut this = Self {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,8 @@ use chrono::NaiveDate;
 | 
				
			|||||||
use common::*;
 | 
					use common::*;
 | 
				
			||||||
use cortex_m_rt::entry;
 | 
					use cortex_m_rt::entry;
 | 
				
			||||||
use embassy_executor::Spawner;
 | 
					use embassy_executor::Spawner;
 | 
				
			||||||
use embassy_stm32::low_power::{stop_with_rtc, Executor};
 | 
					use embassy_stm32::low_power::{stop_ready, stop_with_rtc, Executor, StopMode};
 | 
				
			||||||
use embassy_stm32::rcc::{low_power_ready, LsConfig};
 | 
					use embassy_stm32::rcc::LsConfig;
 | 
				
			||||||
use embassy_stm32::rtc::{Rtc, RtcConfig};
 | 
					use embassy_stm32::rtc::{Rtc, RtcConfig};
 | 
				
			||||||
use embassy_stm32::Config;
 | 
					use embassy_stm32::Config;
 | 
				
			||||||
use embassy_time::Timer;
 | 
					use embassy_time::Timer;
 | 
				
			||||||
@@ -28,7 +28,7 @@ fn main() -> ! {
 | 
				
			|||||||
async fn task_1() {
 | 
					async fn task_1() {
 | 
				
			||||||
    for _ in 0..9 {
 | 
					    for _ in 0..9 {
 | 
				
			||||||
        info!("task 1: waiting for 500ms...");
 | 
					        info!("task 1: waiting for 500ms...");
 | 
				
			||||||
        defmt::assert!(low_power_ready());
 | 
					        defmt::assert!(stop_ready(StopMode::Stop2));
 | 
				
			||||||
        Timer::after_millis(500).await;
 | 
					        Timer::after_millis(500).await;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -37,7 +37,7 @@ async fn task_1() {
 | 
				
			|||||||
async fn task_2() {
 | 
					async fn task_2() {
 | 
				
			||||||
    for _ in 0..5 {
 | 
					    for _ in 0..5 {
 | 
				
			||||||
        info!("task 2: waiting for 1000ms...");
 | 
					        info!("task 2: waiting for 1000ms...");
 | 
				
			||||||
        defmt::assert!(low_power_ready());
 | 
					        defmt::assert!(stop_ready(StopMode::Stop2));
 | 
				
			||||||
        Timer::after_millis(1000).await;
 | 
					        Timer::after_millis(1000).await;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user