stm32: Add some documentation to low_power

This begins to explain the operation of the low-power executor.
This commit is contained in:
Ben Gamari 2023-10-30 13:36:52 -04:00
parent b6fc682117
commit aa97fe7cbd
2 changed files with 52 additions and 1 deletions

View File

@ -1,3 +1,50 @@
/// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating
/// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which
/// can use knowledge of which peripherals are currently blocked upon to transparently and safely
/// enter such low-power modes (currently, only `STOP2`) when idle.
///
/// The executor determines which peripherals are active by their RCC state; consequently,
/// low-power states can only be entered if all peripherals have been `drop`'d. There are a few
/// exceptions to this rule:
///
/// * `GPIO`
/// * `RCC`
///
/// Since entering and leaving low-power modes typically incurs a significant latency, the
/// low-power executor will only attempt to enter when the next timer event is at least
/// [`time_driver::MIN_STOP_PAUSE`] in the future.
///
/// Currently there is no macro analogous to `embassy_executor::main` for this executor;
/// consequently one must define their entrypoint manually. Moveover, you must relinquish control
/// of the `RTC` peripheral to the executor. This will typically look like
///
/// ```rust,no_run
/// use embassy_executor::Spawner;
/// use embassy_stm32::low_power::Executor;
/// use embassy_stm32::rtc::{Rtc, RtcConfig};
/// use static_cell::make_static;
///
/// #[cortex_m_rt::entry]
/// fn main() -> ! {
/// Executor::take().run(|spawner| {
/// unwrap!(spawner.spawn(async_main(spawner)));
/// });
/// }
///
/// #[embassy_executor::task]
/// async fn async_main(spawner: Spawner) {
/// // initialize the platform...
/// let mut config = embassy_stm32::Config::default();
/// let p = embassy_stm32::init(config);
///
/// // give the RTC to the executor...
/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
/// let rtc = make_static!(rtc);
/// embassy_stm32::low_power::stop_with_rtc(rtc);
///
/// // your application here...
/// }
/// ```
use core::arch::asm;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};

View File

@ -345,6 +345,10 @@ impl RtcDriver {
});
}
#[cfg(feature = "low-power")]
/// The minimum pause time beyond which the executor will enter a low-power state.
pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250);
#[cfg(feature = "low-power")]
/// Pause the timer if ready; return err if not
pub(crate) fn pause_time(&self) -> Result<(), ()> {
@ -357,7 +361,7 @@ impl RtcDriver {
self.stop_wakeup_alarm(cs);
let time_until_next_alarm = self.time_until_next_alarm(cs);
if time_until_next_alarm < embassy_time::Duration::from_millis(250) {
if time_until_next_alarm < Self::MIN_STOP_PAUSE {
Err(())
} else {
self.rtc