diff options
| author | xoviat <[email protected]> | 2023-08-22 17:31:40 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-08-22 17:31:40 -0500 |
| commit | faab2d0d53d52f7f311d3958e7e72dd1ee66c3b7 (patch) | |
| tree | 6b23affaf8e883df21432fb93b8a38bcf69ad297 | |
| parent | 6d35bcc3d9818c3380e0d7071c78275b50856c90 (diff) | |
stm32: add executor to low-power mod
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 66 | ||||
| -rw-r--r-- | embassy-stm32/src/rtc/v2.rs | 4 |
3 files changed, 71 insertions, 3 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 828414f2e..048d231d5 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -38,6 +38,7 @@ embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", fea | |||
| 38 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | 38 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } |
| 39 | embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } | 39 | embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } |
| 40 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } | 40 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } |
| 41 | embassy-executor = { version = "0.2.0", path = "../embassy-executor", optional = true } | ||
| 41 | 42 | ||
| 42 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 43 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 43 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true} | 44 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true} |
| @@ -88,7 +89,8 @@ rt = ["stm32-metapac/rt"] | |||
| 88 | defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async?/defmt-03", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] | 89 | defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async?/defmt-03", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] |
| 89 | 90 | ||
| 90 | exti = [] | 91 | exti = [] |
| 91 | low-power = [] | 92 | low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ] |
| 93 | embassy-executor = [] | ||
| 92 | 94 | ||
| 93 | ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) | 95 | ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) |
| 94 | memory-x = ["stm32-metapac/memory-x"] | 96 | memory-x = ["stm32-metapac/memory-x"] |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index ddcfbbb1e..3fe28b9df 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | use core::arch::asm; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | |||
| 4 | use embassy_executor::*; | ||
| 5 | |||
| 6 | const THREAD_PENDER: usize = usize::MAX; | ||
| 7 | |||
| 1 | use crate::rtc::{Rtc, RtcInstant}; | 8 | use crate::rtc::{Rtc, RtcInstant}; |
| 2 | 9 | ||
| 3 | static mut RTC: Option<&'static Rtc> = None; | 10 | static mut RTC: Option<&'static Rtc> = None; |
| @@ -13,3 +20,62 @@ pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInst | |||
| 13 | pub fn stop_wakeup_alarm() -> RtcInstant { | 20 | pub fn stop_wakeup_alarm() -> RtcInstant { |
| 14 | unsafe { RTC }.unwrap().stop_wakeup_alarm() | 21 | unsafe { RTC }.unwrap().stop_wakeup_alarm() |
| 15 | } | 22 | } |
| 23 | |||
| 24 | /// Thread mode executor, using WFE/SEV. | ||
| 25 | /// | ||
| 26 | /// This is the simplest and most common kind of executor. It runs on | ||
| 27 | /// thread mode (at the lowest priority level), and uses the `WFE` ARM instruction | ||
| 28 | /// to sleep when it has no more work to do. When a task is woken, a `SEV` instruction | ||
| 29 | /// is executed, to make the `WFE` exit from sleep and poll the task. | ||
| 30 | /// | ||
| 31 | /// This executor allows for ultra low power consumption for chips where `WFE` | ||
| 32 | /// triggers low-power sleep without extra steps. If your chip requires extra steps, | ||
| 33 | /// you may use [`raw::Executor`] directly to program custom behavior. | ||
| 34 | pub struct Executor { | ||
| 35 | inner: raw::Executor, | ||
| 36 | not_send: PhantomData<*mut ()>, | ||
| 37 | } | ||
| 38 | |||
| 39 | impl Executor { | ||
| 40 | /// Create a new Executor. | ||
| 41 | pub fn new() -> Self { | ||
| 42 | Self { | ||
| 43 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), | ||
| 44 | not_send: PhantomData, | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | fn configure_power(&self) { | ||
| 49 | todo!() | ||
| 50 | } | ||
| 51 | |||
| 52 | /// Run the executor. | ||
| 53 | /// | ||
| 54 | /// The `init` closure is called with a [`Spawner`] that spawns tasks on | ||
| 55 | /// this executor. Use it to spawn the initial task(s). After `init` returns, | ||
| 56 | /// the executor starts running the tasks. | ||
| 57 | /// | ||
| 58 | /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), | ||
| 59 | /// for example by passing it as an argument to the initial tasks. | ||
| 60 | /// | ||
| 61 | /// This function requires `&'static mut self`. This means you have to store the | ||
| 62 | /// Executor instance in a place where it'll live forever and grants you mutable | ||
| 63 | /// access. There's a few ways to do this: | ||
| 64 | /// | ||
| 65 | /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) | ||
| 66 | /// - a `static mut` (unsafe) | ||
| 67 | /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) | ||
| 68 | /// | ||
| 69 | /// This function never returns. | ||
| 70 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | ||
| 71 | init(self.inner.spawner()); | ||
| 72 | |||
| 73 | loop { | ||
| 74 | unsafe { | ||
| 75 | self.inner.poll(); | ||
| 76 | self.configure_power(); | ||
| 77 | asm!("wfe"); | ||
| 78 | }; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 744e9a114..f6565a721 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -162,7 +162,7 @@ impl super::Rtc { | |||
| 162 | /// | 162 | /// |
| 163 | /// note: this api is exposed for testing purposes until low power is implemented. | 163 | /// note: this api is exposed for testing purposes until low power is implemented. |
| 164 | /// it is not intended to be public | 164 | /// it is not intended to be public |
| 165 | pub(crate) fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant { | 165 | pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant { |
| 166 | use embassy_time::{Duration, TICK_HZ}; | 166 | use embassy_time::{Duration, TICK_HZ}; |
| 167 | 167 | ||
| 168 | use crate::interrupt::typelevel::Interrupt; | 168 | use crate::interrupt::typelevel::Interrupt; |
| @@ -217,7 +217,7 @@ impl super::Rtc { | |||
| 217 | /// | 217 | /// |
| 218 | /// note: this api is exposed for testing purposes until low power is implemented. | 218 | /// note: this api is exposed for testing purposes until low power is implemented. |
| 219 | /// it is not intended to be public | 219 | /// it is not intended to be public |
| 220 | pub(crate) fn stop_wakeup_alarm() -> RtcInstant { | 220 | pub(crate) fn stop_wakeup_alarm(&self) -> RtcInstant { |
| 221 | use crate::interrupt::typelevel::Interrupt; | 221 | use crate::interrupt::typelevel::Interrupt; |
| 222 | 222 | ||
| 223 | crate::interrupt::typelevel::RTC_WKUP::disable(); | 223 | crate::interrupt::typelevel::RTC_WKUP::disable(); |
