aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/Cargo.toml6
-rw-r--r--embassy-stm32/src/low_power.rs47
-rw-r--r--embassy-stm32/src/rcc/mod.rs4
-rw-r--r--embassy-stm32/src/rtc/low_power.rs4
-rw-r--r--embassy-stm32/src/rtc/v3.rs4
-rw-r--r--examples/stm32wl5x-lp/.cargo/config.toml9
-rw-r--r--examples/stm32wl5x-lp/Cargo.toml39
-rw-r--r--examples/stm32wl5x-lp/build.rs5
-rw-r--r--examples/stm32wl5x-lp/memory.x15
-rw-r--r--examples/stm32wl5x-lp/src/bin/blinky.rs57
11 files changed, 170 insertions, 21 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 9e0d69078..ae2c0168b 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -73,6 +73,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
73- low-power: update rtc api to allow reconfig 73- low-power: update rtc api to allow reconfig
74- adc: consolidate ringbuffer 74- adc: consolidate ringbuffer
75- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716)) 75- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716))
76- feat: Added low-power support for STM32WL5x ([#5108](https://github.com/embassy-rs/embassy/pull/5108))
76- fix: Correct STM32WBA VREFBUFTRIM values 77- fix: Correct STM32WBA VREFBUFTRIM values
77- low_power: remove stop_with rtc and initialize in init if low-power feature enabled. 78- low_power: remove stop_with rtc and initialize in init if low-power feature enabled.
78- feat: stm32/dsi support zero parameter commands in `write_cmd` ([#4847](https://github.com/embassy-rs/embassy/pull/4847)) 79- feat: stm32/dsi support zero parameter commands in `write_cmd` ([#4847](https://github.com/embassy-rs/embassy/pull/4847))
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 27f26df28..55eba2695 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -200,11 +200,13 @@ aligned = "0.4.1"
200heapless = "0.9.1" 200heapless = "0.9.1"
201 201
202#stm32-metapac = { version = "18" } 202#stm32-metapac = { version = "18" }
203stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-658588478e426d68090a59ff8385bce5b407c2bc" } 203stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c0123f4251e21282c3f26114d2f6f9360c1191f1" }
204#stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" }
204 205
205[build-dependencies] 206[build-dependencies]
206#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} 207#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]}
207stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-658588478e426d68090a59ff8385bce5b407c2bc", default-features = false, features = ["metadata"] } 208stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c0123f4251e21282c3f26114d2f6f9360c1191f1", default-features = false, features = ["metadata"] }
209#stm32-metapac = { path = "../../stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"] }
208 210
209proc-macro2 = "1.0.36" 211proc-macro2 = "1.0.36"
210quote = "1.0.15" 212quote = "1.0.15"
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 02116e08a..71befcf34 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -136,10 +136,10 @@ pub fn stop_ready(stop_mode: StopMode) -> bool {
136 }) 136 })
137} 137}
138 138
139#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))] 139#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wl, stm32u0))]
140use crate::pac::pwr::vals::Lpms; 140use crate::pac::pwr::vals::Lpms;
141 141
142#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))] 142#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wl, stm32u0))]
143impl Into<Lpms> for StopMode { 143impl Into<Lpms> for StopMode {
144 fn into(self) -> Lpms { 144 fn into(self) -> Lpms {
145 match self { 145 match self {
@@ -184,19 +184,28 @@ impl Executor {
184 184
185 pub(crate) unsafe fn on_wakeup_irq_or_event() { 185 pub(crate) unsafe fn on_wakeup_irq_or_event() {
186 if !get_driver().is_stopped() { 186 if !get_driver().is_stopped() {
187 trace!("low power: time driver not stopped!");
187 return; 188 return;
188 } 189 }
189 190
190 critical_section::with(|cs| { 191 critical_section::with(|cs| {
191 #[cfg(any(stm32wlex, stm32wb))] 192 #[cfg(any(stm32wl, stm32wb))]
192 { 193 {
193 let es = crate::pac::PWR.extscr().read(); 194 let es = crate::pac::PWR.extscr().read();
194 #[cfg(stm32wlex)] 195 #[cfg(stm32wl)]
195 match (es.c1stopf(), es.c1stop2f()) { 196 match (es.c1stopf(), es.c1stop2f()) {
196 (true, false) => debug!("low power: wake from STOP1"), 197 (true, false) => debug!("low power: cpu1 wake from STOP1"),
197 (false, true) => debug!("low power: wake from STOP2"), 198 (false, true) => debug!("low power: cpu1 wake from STOP2"),
198 (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"), 199 (true, true) => debug!("low power: cpu1 wake from STOP1 and STOP2 ???"),
199 (false, false) => trace!("low power: stop mode not entered"), 200 (false, false) => trace!("low power: cpu1 stop mode not entered"),
201 };
202 #[cfg(stm32wl5x)]
203 // TODO: only for the current cpu
204 match (es.c2stopf(), es.c2stop2f()) {
205 (true, false) => debug!("low power: cpu2 wake from STOP1"),
206 (false, true) => debug!("low power: cpu2 wake from STOP2"),
207 (true, true) => debug!("low power: cpu2 wake from STOP1 and STOP2 ???"),
208 (false, false) => trace!("low power: cpu2 stop mode not entered"),
200 }; 209 };
201 210
202 #[cfg(stm32wb)] 211 #[cfg(stm32wb)]
@@ -206,9 +215,6 @@ impl Executor {
206 (true, true) => debug!("low power: cpu1 and cpu2 wake from STOP"), 215 (true, true) => debug!("low power: cpu1 and cpu2 wake from STOP"),
207 (false, false) => trace!("low power: stop mode not entered"), 216 (false, false) => trace!("low power: stop mode not entered"),
208 }; 217 };
209 crate::pac::PWR.extscr().modify(|w| {
210 w.set_c1cssf(false);
211 });
212 218
213 let _has_stopped2 = { 219 let _has_stopped2 = {
214 #[cfg(stm32wb)] 220 #[cfg(stm32wb)]
@@ -220,6 +226,12 @@ impl Executor {
220 { 226 {
221 es.c1stop2f() 227 es.c1stop2f()
222 } 228 }
229
230 #[cfg(stm32wl5x)]
231 {
232 // TODO: I think we could just use c1stop2f() here as it won't enter a stop mode unless BOTH cpus will enter it.
233 es.c1stop2f() | es.c2stop2f()
234 }
223 }; 235 };
224 236
225 #[cfg(not(stm32wb))] 237 #[cfg(not(stm32wb))]
@@ -235,6 +247,13 @@ impl Executor {
235 REFCOUNT_STOP1 = 0; 247 REFCOUNT_STOP1 = 0;
236 } 248 }
237 } 249 }
250 // Clear all stop flags
251 #[cfg(stm32wl)]
252 crate::pac::PWR.extscr().modify(|w| {
253 w.set_c1cssf(true);
254 #[cfg(stm32wl5x)]
255 w.set_c2cssf(true);
256 });
238 } 257 }
239 get_driver().resume_time(cs); 258 get_driver().resume_time(cs);
240 259
@@ -337,7 +356,7 @@ impl Executor {
337 #[cfg(all(stm32wb, feature = "low-power"))] 356 #[cfg(all(stm32wb, feature = "low-power"))]
338 self.configure_stop_stm32wb(_cs)?; 357 self.configure_stop_stm32wb(_cs)?;
339 358
340 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wlex))] 359 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wl))]
341 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 360 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
342 #[cfg(stm32h5)] 361 #[cfg(stm32h5)]
343 crate::pac::PWR.pmcr().modify(|v| { 362 crate::pac::PWR.pmcr().modify(|v| {
@@ -352,9 +371,11 @@ impl Executor {
352 fn configure_pwr(&self) { 371 fn configure_pwr(&self) {
353 Self::get_scb().clear_sleepdeep(); 372 Self::get_scb().clear_sleepdeep();
354 // Clear any previous stop flags 373 // Clear any previous stop flags
355 #[cfg(stm32wlex)] 374 #[cfg(stm32wl)]
356 crate::pac::PWR.extscr().modify(|w| { 375 crate::pac::PWR.extscr().modify(|w| {
357 w.set_c1cssf(true); 376 w.set_c1cssf(true);
377 #[cfg(stm32wl5x)]
378 w.set_c2cssf(true);
358 }); 379 });
359 380
360 #[cfg(feature = "low-power-pender")] 381 #[cfg(feature = "low-power-pender")]
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 753ee1290..c0a50615e 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -313,7 +313,7 @@ impl RccInfo {
313 313
314 #[allow(dead_code)] 314 #[allow(dead_code)]
315 fn increment_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) { 315 fn increment_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) {
316 #[cfg(all(any(stm32wlex, stm32wb), feature = "low-power"))] 316 #[cfg(all(any(stm32wl, stm32wb), feature = "low-power"))]
317 match self.stop_mode { 317 match self.stop_mode {
318 StopMode::Stop1 | StopMode::Stop2 => increment_stop_refcount(_cs, StopMode::Stop2), 318 StopMode::Stop1 | StopMode::Stop2 => increment_stop_refcount(_cs, StopMode::Stop2),
319 _ => {} 319 _ => {}
@@ -334,7 +334,7 @@ impl RccInfo {
334 334
335 #[allow(dead_code)] 335 #[allow(dead_code)]
336 fn decrement_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) { 336 fn decrement_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) {
337 #[cfg(all(any(stm32wlex, stm32wb), feature = "low-power"))] 337 #[cfg(all(any(stm32wl, stm32wb), feature = "low-power"))]
338 match self.stop_mode { 338 match self.stop_mode {
339 StopMode::Stop1 | StopMode::Stop2 => decrement_stop_refcount(_cs, StopMode::Stop2), 339 StopMode::Stop1 | StopMode::Stop2 => decrement_stop_refcount(_cs, StopMode::Stop2),
340 _ => {} 340 _ => {}
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index cd5cea081..e15eddc22 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -114,11 +114,11 @@ impl Rtc {
114 use crate::pac::EXTI; 114 use crate::pac::EXTI;
115 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 115 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
116 116
117 #[cfg(not(stm32wb))] 117 #[cfg(not(any(stm32wb, stm32wl5x)))]
118 { 118 {
119 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 119 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
120 } 120 }
121 #[cfg(stm32wb)] 121 #[cfg(any(stm32wb, stm32wl5x))]
122 { 122 {
123 EXTI.cpu(0).imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 123 EXTI.cpu(0).imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
124 } 124 }
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index f7ebea73e..49c9778df 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -131,7 +131,7 @@ impl SealedInstance for crate::peripherals::RTC {
131 131
132 #[cfg(feature = "low-power")] 132 #[cfg(feature = "low-power")]
133 cfg_if::cfg_if!( 133 cfg_if::cfg_if!(
134 if #[cfg(any(stm32g4, stm32wlex))] { 134 if #[cfg(any(stm32g4, stm32wl))] {
135 const EXTI_WAKEUP_LINE: usize = 20; 135 const EXTI_WAKEUP_LINE: usize = 20;
136 } else if #[cfg(stm32g0)] { 136 } else if #[cfg(stm32g0)] {
137 const EXTI_WAKEUP_LINE: usize = 19; 137 const EXTI_WAKEUP_LINE: usize = 19;
@@ -142,7 +142,7 @@ impl SealedInstance for crate::peripherals::RTC {
142 142
143 #[cfg(feature = "low-power")] 143 #[cfg(feature = "low-power")]
144 cfg_if::cfg_if!( 144 cfg_if::cfg_if!(
145 if #[cfg(any(stm32g4, stm32wlex))] { 145 if #[cfg(any(stm32g4, stm32wl))] {
146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
147 } else if #[cfg(any(stm32g0, stm32u0))] { 147 } else if #[cfg(any(stm32g0, stm32u0))] {
148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; 148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
diff --git a/examples/stm32wl5x-lp/.cargo/config.toml b/examples/stm32wl5x-lp/.cargo/config.toml
new file mode 100644
index 000000000..969068656
--- /dev/null
+++ b/examples/stm32wl5x-lp/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32WLE5JCIx --connect-under-reset"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "debug"
diff --git a/examples/stm32wl5x-lp/Cargo.toml b/examples/stm32wl5x-lp/Cargo.toml
new file mode 100644
index 000000000..b1823fb8a
--- /dev/null
+++ b/examples/stm32wl5x-lp/Cargo.toml
@@ -0,0 +1,39 @@
1[package]
2edition = "2024"
3name = "embassy-stm32wl5x-lp"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6publish = false
7
8[dependencies]
9# Change stm32wl55jc-cm4 to your chip name, if necessary.
10embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono", "low-power-pender"] }
11embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-embedded-hal = { version = "0.5.0", path = "../../embassy-embedded-hal" }
15
16defmt = "1.0.1"
17defmt-rtt = { version = "1.1.0", optional = true }
18defmt-serial = { git = "https://github.com/gauteh/defmt-serial", rev = "411ae7fa909b4fd2667885aff687e009b9108190", optional = true }
19
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0"
22embedded-hal = "1.0.0"
23embedded-storage = "0.3.1"
24panic-probe = { version = "1.0.0", features = ["print-defmt"] }
25chrono = { version = "^0.4", default-features = false }
26static_cell = { version = "2.1.1", default-features = false }
27
28[profile.release]
29debug = 2
30
31[package.metadata.embassy]
32build = [
33 { target = "thumbv7em-none-eabi", artifact-dir = "out/examples/stm32wl" }
34]
35
36[features]
37default = ["defmt-serial"]
38defmt-rtt = ["dep:defmt-rtt"]
39defmt-serial = ["dep:defmt-serial"]
diff --git a/examples/stm32wl5x-lp/build.rs b/examples/stm32wl5x-lp/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32wl5x-lp/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32wl5x-lp/memory.x b/examples/stm32wl5x-lp/memory.x
new file mode 100644
index 000000000..4590867a8
--- /dev/null
+++ b/examples/stm32wl5x-lp/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 256K
5 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128
6 RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 64K - 128
7}
8
9SECTIONS
10{
11 .shared_data :
12 {
13 *(.shared_data)
14 } > SHARED_RAM
15}
diff --git a/examples/stm32wl5x-lp/src/bin/blinky.rs b/examples/stm32wl5x-lp/src/bin/blinky.rs
new file mode 100644
index 000000000..60b671a77
--- /dev/null
+++ b/examples/stm32wl5x-lp/src/bin/blinky.rs
@@ -0,0 +1,57 @@
1// This example is configured for the nucleo-wl55jc board. Curret monitor should show just a few microamps when the device is in stop2 mode.
2#![no_std]
3#![no_main]
4
5use core::mem::MaybeUninit;
6
7use defmt::*;
8#[cfg(feature = "defmt-rtt")]
9use defmt_rtt as _;
10use embassy_executor::Spawner;
11use embassy_stm32::SharedData;
12use embassy_stm32::gpio::{Level, Output, Speed};
13use embassy_time::Timer;
14use panic_probe as _;
15
16#[unsafe(link_section = ".shared_data")]
17static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
18
19#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
20async fn async_main(_spawner: Spawner) {
21 let mut config = embassy_stm32::Config::default();
22 config.rcc.ls = embassy_stm32::rcc::LsConfig::default_lsi();
23 config.rcc.msi = Some(embassy_stm32::rcc::MSIRange::RANGE4M);
24 config.rcc.sys = embassy_stm32::rcc::Sysclk::MSI;
25 #[cfg(feature = "defmt-serial")]
26 {
27 // disable debug during sleep to reduce power consumption since we are
28 // using defmt-serial on LPUART1.
29 config.enable_debug_during_sleep = false;
30 }
31 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
32
33 #[cfg(feature = "defmt-serial")]
34 {
35 use embassy_stm32::mode::Blocking;
36 use embassy_stm32::usart::Uart;
37 use static_cell::StaticCell;
38 let config = embassy_stm32::usart::Config::default();
39 let uart = Uart::new_blocking(p.LPUART1, p.PA3, p.PA2, config).expect("failed to configure UART!");
40 static SERIAL: StaticCell<Uart<'static, Blocking>> = StaticCell::new();
41 defmt_serial::defmt_serial(SERIAL.init(uart));
42 }
43
44 info!("Hello World!");
45
46 let mut led = Output::new(p.PB15, Level::High, Speed::Low);
47
48 loop {
49 info!("low");
50 led.set_low();
51 Timer::after_millis(5000).await;
52
53 info!("high");
54 led.set_high();
55 Timer::after_millis(5000).await;
56 }
57}