aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-19 15:24:05 -0600
committerxoviat <[email protected]>2025-11-19 15:24:05 -0600
commit4104d114955be79cf419cb4cfb5c0e72b0abd261 (patch)
treee67e5a10072606f3be2c326870ce3790696c4653
parenta68b5d5d29514dcaf0a6ed08207d3a1f1fa9b464 (diff)
stm32: impl. stop for stm32wb
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/hsem/mod.rs60
-rw-r--r--embassy-stm32/src/lib.rs3
-rw-r--r--embassy-stm32/src/low_power.rs68
-rw-r--r--examples/stm32wb/Cargo.toml2
5 files changed, 112 insertions, 22 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 597cbb192..7d8e7c617 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
9 9
10- feat: implement stop for stm32wb.
10- change: rework hsem and add HIL test for some chips. 11- change: rework hsem and add HIL test for some chips.
11- change: stm32/eth: ethernet no longer has a hard dependency on station management, and station management can be used independently ([#4871](https://github.com/embassy-rs/embassy/pull/4871)) 12- change: stm32/eth: ethernet no longer has a hard dependency on station management, and station management can be used independently ([#4871](https://github.com/embassy-rs/embassy/pull/4871))
12- feat: allow embassy_executor::main for low power 13- feat: allow embassy_executor::main for low power
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index a6b910a53..5f1ed9b09 100644
--- a/embassy-stm32/src/hsem/mod.rs
+++ b/embassy-stm32/src/hsem/mod.rs
@@ -5,6 +5,8 @@ use core::marker::PhantomData;
5use core::sync::atomic::{Ordering, compiler_fence}; 5use core::sync::atomic::{Ordering, compiler_fence};
6use core::task::Poll; 6use core::task::Poll;
7 7
8#[cfg(all(stm32wb, feature = "low-power"))]
9use critical_section::CriticalSection;
8use embassy_hal_internal::PeripheralType; 10use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
10 12
@@ -78,6 +80,12 @@ impl CoreId {
78 } 80 }
79} 81}
80 82
83#[cfg(not(all(stm32wb, feature = "low-power")))]
84const PUB_CHANNELS: usize = 6;
85
86#[cfg(all(stm32wb, feature = "low-power"))]
87const PUB_CHANNELS: usize = 4;
88
81/// TX interrupt handler. 89/// TX interrupt handler.
82pub struct HardwareSemaphoreInterruptHandler<T: Instance> { 90pub struct HardwareSemaphoreInterruptHandler<T: Instance> {
83 _phantom: PhantomData<T>, 91 _phantom: PhantomData<T>,
@@ -127,7 +135,7 @@ pub struct HardwareSemaphoreChannel<'a, T: Instance> {
127} 135}
128 136
129impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> { 137impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> {
130 pub(self) const fn new(number: u8) -> Self { 138 pub(crate) const fn new(number: u8) -> Self {
131 core::assert!(number > 0 && number <= 6); 139 core::assert!(number > 0 && number <= 6);
132 140
133 Self { 141 Self {
@@ -151,19 +159,29 @@ impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> {
151 .ier(core_id.to_index()) 159 .ier(core_id.to_index())
152 .modify(|w| w.set_ise(self.index as usize, true)); 160 .modify(|w| w.set_ise(self.index as usize, true));
153 161
154 if self.two_step_lock(process_id).is_ok() { 162 match self.try_lock(process_id) {
155 Poll::Ready(HardwareSemaphoreMutex { 163 Some(mutex) => Poll::Ready(mutex),
156 index: self.index, 164 None => Poll::Pending,
157 process_id: process_id,
158 _lifetime: PhantomData,
159 })
160 } else {
161 Poll::Pending
162 } 165 }
163 }) 166 })
164 .await 167 .await
165 } 168 }
166 169
170 /// Try to lock the semaphor
171 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
172 /// check if the lock has been successful, carried out from the HSEM_Rx register.
173 pub fn try_lock(&mut self, process_id: u8) -> Option<HardwareSemaphoreMutex<'a, T>> {
174 if self.two_step_lock(process_id).is_ok() {
175 Some(HardwareSemaphoreMutex {
176 index: self.index,
177 process_id: process_id,
178 _lifetime: PhantomData,
179 })
180 } else {
181 None
182 }
183 }
184
167 /// Locks the semaphore. 185 /// Locks the semaphore.
168 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to 186 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
169 /// check if the lock has been successful, carried out from the HSEM_Rx register. 187 /// check if the lock has been successful, carried out from the HSEM_Rx register.
@@ -206,9 +224,9 @@ impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> {
206 }); 224 });
207 } 225 }
208 226
209 /// Checks if the semaphore is locked. 227 /// Return the channel number
210 pub fn is_semaphore_locked(&self) -> bool { 228 pub const fn channel(&self) -> u8 {
211 T::regs().r(self.index as usize).read().lock() 229 self.index + 1
212 } 230 }
213} 231}
214 232
@@ -230,15 +248,22 @@ impl<T: Instance> HardwareSemaphore<T> {
230 248
231 /// Get a single channel, and keep the global struct 249 /// Get a single channel, and keep the global struct
232 pub const fn channel_for<'a>(&'a mut self, number: u8) -> HardwareSemaphoreChannel<'a, T> { 250 pub const fn channel_for<'a>(&'a mut self, number: u8) -> HardwareSemaphoreChannel<'a, T> {
251 #[cfg(all(stm32wb, feature = "low-power"))]
252 core::assert!(number != 3 && number != 4);
253
233 HardwareSemaphoreChannel::new(number) 254 HardwareSemaphoreChannel::new(number)
234 } 255 }
235 256
236 /// Split the global struct into channels 257 /// Split the global struct into channels
237 pub const fn split<'a>(self) -> [HardwareSemaphoreChannel<'a, T>; 6] { 258 ///
259 /// If using low-power mode, channels 3 and 4 will not be returned
260 pub const fn split<'a>(self) -> [HardwareSemaphoreChannel<'a, T>; PUB_CHANNELS] {
238 [ 261 [
239 HardwareSemaphoreChannel::new(1), 262 HardwareSemaphoreChannel::new(1),
240 HardwareSemaphoreChannel::new(2), 263 HardwareSemaphoreChannel::new(2),
264 #[cfg(not(all(stm32wb, feature = "low-power")))]
241 HardwareSemaphoreChannel::new(3), 265 HardwareSemaphoreChannel::new(3),
266 #[cfg(not(all(stm32wb, feature = "low-power")))]
242 HardwareSemaphoreChannel::new(4), 267 HardwareSemaphoreChannel::new(4),
243 HardwareSemaphoreChannel::new(5), 268 HardwareSemaphoreChannel::new(5),
244 HardwareSemaphoreChannel::new(6), 269 HardwareSemaphoreChannel::new(6),
@@ -267,6 +292,11 @@ impl<T: Instance> HardwareSemaphore<T> {
267 } 292 }
268} 293}
269 294
295#[cfg(all(stm32wb, feature = "low-power"))]
296pub(crate) fn init_hsem(_cs: CriticalSection) {
297 rcc::enable_and_reset::<crate::peripherals::HSEM>();
298}
299
270struct State { 300struct State {
271 wakers: [AtomicWaker; 6], 301 wakers: [AtomicWaker; 6],
272} 302}
@@ -278,8 +308,8 @@ impl State {
278 } 308 }
279 } 309 }
280 310
281 const fn waker_for(&self, number: u8) -> &AtomicWaker { 311 const fn waker_for(&self, index: u8) -> &AtomicWaker {
282 &self.wakers[number as usize] 312 &self.wakers[index as usize]
283 } 313 }
284} 314}
285 315
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 7c3770643..ef6f1d6dc 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -650,6 +650,9 @@ fn init_hw(config: Config) -> Peripherals {
650 650
651 #[cfg(feature = "low-power")] 651 #[cfg(feature = "low-power")]
652 rtc::init_rtc(cs, config.rtc, config.min_stop_pause); 652 rtc::init_rtc(cs, config.rtc, config.min_stop_pause);
653
654 #[cfg(all(stm32wb, feature = "low-power"))]
655 hsem::init_hsem(cs);
653 } 656 }
654 657
655 p 658 p
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index cf8f2b393..15478eed4 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -148,7 +148,7 @@ pub enum StopMode {
148} 148}
149 149
150#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))] 150#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))]
151use stm32_metapac::pwr::vals::Lpms; 151use crate::pac::pwr::vals::Lpms;
152 152
153#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))] 153#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))]
154impl Into<Lpms> for StopMode { 154impl Into<Lpms> for StopMode {
@@ -242,8 +242,63 @@ impl Executor {
242 } 242 }
243 } 243 }
244 244
245 #[cfg(all(stm32wb, feature = "low-power"))]
246 fn configure_stop_stm32wb(&self, _stop_mode: StopMode) -> Result<(), ()> {
247 use core::task::Poll;
248
249 use embassy_futures::poll_once;
250
251 use crate::hsem::HardwareSemaphoreChannel;
252 use crate::pac::rcc::vals::{Smps, Sw};
253 use crate::pac::{PWR, RCC};
254
255 let sem3_mutex = match poll_once(HardwareSemaphoreChannel::<crate::peripherals::HSEM>::new(3).lock(0)) {
256 Poll::Pending => None,
257 Poll::Ready(mutex) => Some(mutex),
258 }
259 .ok_or(())?;
260
261 let sem4_mutex = HardwareSemaphoreChannel::<crate::peripherals::HSEM>::new(4).try_lock(0);
262 if let Some(sem4_mutex) = sem4_mutex {
263 if PWR.extscr().read().c2ds() {
264 drop(sem4_mutex);
265 } else {
266 return Ok(());
267 }
268 }
269
270 // Sem4 not granted
271 // Set HSION
272 RCC.cr().modify(|w| {
273 w.set_hsion(true);
274 });
275
276 // Wait for HSIRDY
277 while !RCC.cr().read().hsirdy() {}
278
279 // Set SW to HSI
280 RCC.cfgr().modify(|w| {
281 w.set_sw(Sw::HSI);
282 });
283
284 // Wait for SWS to report HSI
285 while !RCC.cfgr().read().sws().eq(&Sw::HSI) {}
286
287 // Set SMPSSEL to HSI
288 RCC.smpscr().modify(|w| {
289 w.set_smpssel(Smps::HSI);
290 });
291
292 drop(sem3_mutex);
293
294 Ok(())
295 }
296
245 #[allow(unused_variables)] 297 #[allow(unused_variables)]
246 fn configure_stop(&self, stop_mode: StopMode) { 298 fn configure_stop(&self, stop_mode: StopMode) -> Result<(), ()> {
299 #[cfg(all(stm32wb, feature = "low-power"))]
300 self.configure_stop_stm32wb(stop_mode)?;
301
247 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))] 302 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))]
248 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 303 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
249 #[cfg(stm32h5)] 304 #[cfg(stm32h5)]
@@ -252,6 +307,8 @@ impl Executor {
252 v.set_lpms(vals::Lpms::STOP); 307 v.set_lpms(vals::Lpms::STOP);
253 v.set_svos(vals::Svos::SCALE3); 308 v.set_svos(vals::Svos::SCALE3);
254 }); 309 });
310
311 Ok(())
255 } 312 }
256 313
257 fn configure_pwr(&self) { 314 fn configure_pwr(&self) {
@@ -267,12 +324,11 @@ impl Executor {
267 critical_section::with(|cs| { 324 critical_section::with(|cs| {
268 let stop_mode = Self::stop_mode(cs)?; 325 let stop_mode = Self::stop_mode(cs)?;
269 let _ = get_driver().pause_time(cs).ok()?; 326 let _ = get_driver().pause_time(cs).ok()?;
327 self.configure_stop(stop_mode).ok()?;
270 328
271 Some(stop_mode) 329 Some(())
272 }) 330 })
273 .map(|stop_mode| { 331 .map(|_| {
274 self.configure_stop(stop_mode);
275
276 #[cfg(not(feature = "low-power-debug-with-sleep"))] 332 #[cfg(not(feature = "low-power-debug-with-sleep"))]
277 Self::get_scb().set_sleepdeep(); 333 Self::get_scb().set_sleepdeep();
278 }); 334 });
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 783690c11..83119e3a0 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
7 7
8[dependencies] 8[dependencies]
9# Change stm32wb55rg to your chip name in both dependencies, if necessary. 9# Change stm32wb55rg to your chip name in both dependencies, if necessary.
10embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 10embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti", "low-power"] }
11embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } 11embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
13embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 13embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }