aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob <[email protected]>2025-11-07 15:54:35 +0100
committerGitHub <[email protected]>2025-11-07 15:54:35 +0100
commit1fd44118a7ba5329b256e3d45c04f606722eb3e9 (patch)
tree25ecc54d755affca2a9e9abdddd4227a087ef7eb
parentf4746467438b9d385f03b85823e0eb6ce9f49ee9 (diff)
parentb68253e1aa38a9251b10219df4da3519cecf33e7 (diff)
Merge branch 'main' into into_ring_buffered_adc_for_g4
-rw-r--r--embassy-stm32/CHANGELOG.md4
-rw-r--r--embassy-stm32/Cargo.toml1
-rw-r--r--embassy-stm32/src/adc/v3.rs2
-rw-r--r--embassy-stm32/src/dsihost.rs12
-rw-r--r--embassy-stm32/src/exti.rs2
-rw-r--r--embassy-stm32/src/hrtim/mod.rs87
-rw-r--r--embassy-stm32/src/i2c/v2.rs16
-rw-r--r--embassy-stm32/src/i2s.rs3
-rw-r--r--embassy-stm32/src/lib.rs18
-rw-r--r--embassy-stm32/src/low_power.rs167
-rw-r--r--embassy-stm32/src/rtc/low_power.rs4
-rw-r--r--embassy-stm32/src/rtc/mod.rs112
-rw-r--r--embassy-stm32/src/spi/mod.rs147
-rw-r--r--embassy-stm32/src/time_driver.rs42
-rw-r--r--embassy-stm32/src/timer/mod.rs4
-rw-r--r--embassy-usb-logger/CHANGELOG.md2
-rw-r--r--embassy-usb-logger/src/lib.rs20
-rw-r--r--examples/stm32c0/src/bin/rtc.rs4
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs3
-rw-r--r--examples/stm32f4/src/bin/rtc.rs4
-rw-r--r--examples/stm32g0/src/bin/rtc.rs4
-rw-r--r--examples/stm32h5/src/bin/stop.rs5
-rw-r--r--examples/stm32h7/src/bin/rtc.rs4
-rw-r--r--examples/stm32h7/src/bin/spi.rs2
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs2
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs2
-rw-r--r--examples/stm32h7rs/src/bin/rtc.rs4
-rw-r--r--examples/stm32h7rs/src/bin/spi.rs2
-rw-r--r--examples/stm32h7rs/src/bin/spi_dma.rs2
-rw-r--r--examples/stm32l4/src/bin/rtc.rs4
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs3
-rw-r--r--examples/stm32l5/src/bin/stop.rs5
-rw-r--r--examples/stm32u0/src/bin/rtc.rs4
-rw-r--r--examples/stm32wl/src/bin/rtc.rs4
-rw-r--r--examples/stm32wle5/src/bin/adc.rs6
-rw-r--r--examples/stm32wle5/src/bin/blinky.rs6
-rw-r--r--examples/stm32wle5/src/bin/button_exti.rs6
-rw-r--r--examples/stm32wle5/src/bin/i2c.rs6
-rw-r--r--tests/stm32/Cargo.toml3
-rw-r--r--tests/stm32/src/bin/rtc.rs23
-rw-r--r--tests/stm32/src/bin/spi.rs7
-rw-r--r--tests/stm32/src/bin/spi_dma.rs7
-rw-r--r--tests/stm32/src/bin/stop.rs13
-rw-r--r--tests/stm32/src/common.rs2
44 files changed, 509 insertions, 271 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 9b8c6625a..9845fedbb 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9 9
10- feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) 10- feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840))
11- feat: Implement into_ring_buffered for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) 11- feat: Implement into_ring_buffered for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840))
12- feat: stm32/hrtim add new_chx_with_config to provide pin configuration
12- fix flash erase on L4 & L5 13- fix flash erase on L4 & L5
13- fix: Fixed STM32H5 builds requiring time feature 14- fix: Fixed STM32H5 builds requiring time feature
14- feat: Derive Clone, Copy for QSPI Config 15- feat: Derive Clone, Copy for QSPI Config
@@ -44,6 +45,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
44- adc: consolidate ringbuffer 45- adc: consolidate ringbuffer
45- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716)) 46- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716))
46- fix: Correct STM32WBA VREFBUFTRIM values 47- fix: Correct STM32WBA VREFBUFTRIM values
48- low_power: remove stop_with rtc and initialize in init if low-power feature enabled.
49- feat: stm32/dsi support zero parameter commands in `write_cmd` ([#4847](https://github.com/embassy-rs/embassy/pull/4847))
50- feat: stm32/spi: added support for slave mode ([#4388](https://github.com/embassy-rs/embassy/pull/4388))
47 51
48## 0.4.0 - 2025-08-26 52## 0.4.0 - 2025-08-26
49 53
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 7c243b350..7c64c3e17 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -313,6 +313,7 @@ single-bank = []
313 313
314## internal use only 314## internal use only
315_split-pins-enabled = [] 315_split-pins-enabled = []
316_allow-disable-rtc = []
316 317
317## internal use only 318## internal use only
318_dual-core = [] 319_dual-core = []
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 62c2da557..170b08a25 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -463,7 +463,7 @@ impl<'d, T: Instance> Adc<'d, T> {
463 ); 463 );
464 464
465 #[cfg(all(feature = "low-power", stm32wlex))] 465 #[cfg(all(feature = "low-power", stm32wlex))]
466 let _device_busy = crate::low_power::DeviceBusy::new(); 466 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
467 467
468 // Ensure no conversions are ongoing and ADC is enabled. 468 // Ensure no conversions are ongoing and ADC is enabled.
469 Self::cancel_conversions(); 469 Self::cancel_conversions();
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index fd1682d2b..59a2cbcdb 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -121,17 +121,15 @@ impl<'d, T: Instance> DsiHost<'d, T> {
121 121
122 /// DCS or Generic short/long write command 122 /// DCS or Generic short/long write command
123 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> { 123 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> {
124 assert!(data.len() > 0); 124 match data.len() {
125 125 0 => self.short_write(channel_id, PacketType::DcsShortPktWriteP0, address, 0),
126 if data.len() == 1 { 126 1 => self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]),
127 self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]) 127 _ => self.long_write(
128 } else {
129 self.long_write(
130 channel_id, 128 channel_id,
131 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well... 129 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well...
132 address, 130 address,
133 data, 131 data,
134 ) 132 ),
135 } 133 }
136 } 134 }
137 135
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 12600d4eb..2f5c3406a 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -71,7 +71,7 @@ unsafe fn on_irq() {
71 } 71 }
72 72
73 #[cfg(feature = "low-power")] 73 #[cfg(feature = "low-power")]
74 crate::low_power::on_wakeup_irq(); 74 crate::low_power::Executor::on_wakeup_irq();
75} 75}
76 76
77struct BitIter(u32); 77struct BitIter(u32);
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 6fece5eb2..6c6807479 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -10,6 +10,7 @@ pub use traits::Instance;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::rcc; 11use crate::rcc;
12use crate::time::Hertz; 12use crate::time::Hertz;
13pub use crate::timer::simple_pwm::PwmPinConfig;
13 14
14/// HRTIM burst controller instance. 15/// HRTIM burst controller instance.
15pub struct BurstController<T: Instance> { 16pub struct BurstController<T: Instance> {
@@ -73,7 +74,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
73} 74}
74 75
75macro_rules! advanced_channel_impl { 76macro_rules! advanced_channel_impl {
76 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 77 ($new_chx:ident, $new_chx_with_config:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
77 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> { 78 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
78 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 79 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
79 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { 80 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
@@ -86,6 +87,21 @@ macro_rules! advanced_channel_impl {
86 phantom: PhantomData, 87 phantom: PhantomData,
87 } 88 }
88 } 89 }
90
91 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with a specific configuration.")]
92 pub fn $new_chx_with_config(
93 pin: Peri<'d, impl $pin_trait<T>>,
94 pin_config: PwmPinConfig,
95 ) -> Self {
96 critical_section::with(|_| {
97 pin.set_low();
98 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
99 });
100 PwmPin {
101 _pin: pin.into(),
102 phantom: PhantomData,
103 }
104 }
89 } 105 }
90 106
91 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> { 107 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
@@ -100,6 +116,21 @@ macro_rules! advanced_channel_impl {
100 phantom: PhantomData, 116 phantom: PhantomData,
101 } 117 }
102 } 118 }
119
120 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance with a specific configuration.")]
121 pub fn $new_chx_with_config(
122 pin: Peri<'d, impl $complementary_pin_trait<T>>,
123 pin_config: PwmPinConfig,
124 ) -> Self {
125 critical_section::with(|_| {
126 pin.set_low();
127 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
128 });
129 ComplementaryPwmPin {
130 _pin: pin.into(),
131 phantom: PhantomData,
132 }
133 }
103 } 134 }
104 135
105 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> { 136 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> {
@@ -111,13 +142,55 @@ macro_rules! advanced_channel_impl {
111 }; 142 };
112} 143}
113 144
114advanced_channel_impl!(new_cha, ChA, 0, ChannelAPin, ChannelAComplementaryPin); 145advanced_channel_impl!(
115advanced_channel_impl!(new_chb, ChB, 1, ChannelBPin, ChannelBComplementaryPin); 146 new_cha,
116advanced_channel_impl!(new_chc, ChC, 2, ChannelCPin, ChannelCComplementaryPin); 147 new_cha_with_config,
117advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); 148 ChA,
118advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); 149 0,
150 ChannelAPin,
151 ChannelAComplementaryPin
152);
153advanced_channel_impl!(
154 new_chb,
155 new_chb_with_config,
156 ChB,
157 1,
158 ChannelBPin,
159 ChannelBComplementaryPin
160);
161advanced_channel_impl!(
162 new_chc,
163 new_chc_with_config,
164 ChC,
165 2,
166 ChannelCPin,
167 ChannelCComplementaryPin
168);
169advanced_channel_impl!(
170 new_chd,
171 new_chd_with_config,
172 ChD,
173 3,
174 ChannelDPin,
175 ChannelDComplementaryPin
176);
177advanced_channel_impl!(
178 new_che,
179 new_che_with_config,
180 ChE,
181 4,
182 ChannelEPin,
183 ChannelEComplementaryPin
184);
119#[cfg(hrtim_v2)] 185#[cfg(hrtim_v2)]
120advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); 186advanced_channel_impl!(
187 new_chf,
188 new_chf_with_config,
189 ChF,
190 5,
191 ChannelFPin,
192 ChannelFComplementaryPin
193);
121 194
122/// Struct used to divide a high resolution timer into multiple channels 195/// Struct used to divide a high resolution timer into multiple channels
123pub struct AdvancedPwm<'d, T: Instance> { 196pub struct AdvancedPwm<'d, T: Instance> {
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 6f2d03bd1..57a7acee7 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -73,7 +73,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
73 // restore the clocks to their last configured state as 73 // restore the clocks to their last configured state as
74 // much is lost in STOP modes 74 // much is lost in STOP modes
75 #[cfg(all(feature = "low-power", stm32wlex))] 75 #[cfg(all(feature = "low-power", stm32wlex))]
76 crate::low_power::on_wakeup_irq(); 76 crate::low_power::Executor::on_wakeup_irq();
77 77
78 let regs = T::info().regs; 78 let regs = T::info().regs;
79 let isr = regs.isr().read(); 79 let isr = regs.isr().read();
@@ -820,7 +820,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
820 /// Write. 820 /// Write.
821 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 821 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
822 #[cfg(all(feature = "low-power", stm32wlex))] 822 #[cfg(all(feature = "low-power", stm32wlex))]
823 let _device_busy = crate::low_power::DeviceBusy::new(); 823 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
824 let timeout = self.timeout(); 824 let timeout = self.timeout();
825 if write.is_empty() { 825 if write.is_empty() {
826 self.write_internal(address.into(), write, true, timeout) 826 self.write_internal(address.into(), write, true, timeout)
@@ -836,7 +836,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
836 /// The buffers are concatenated in a single write transaction. 836 /// The buffers are concatenated in a single write transaction.
837 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { 837 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> {
838 #[cfg(all(feature = "low-power", stm32wlex))] 838 #[cfg(all(feature = "low-power", stm32wlex))]
839 let _device_busy = crate::low_power::DeviceBusy::new(); 839 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
840 let timeout = self.timeout(); 840 let timeout = self.timeout();
841 841
842 if write.is_empty() { 842 if write.is_empty() {
@@ -861,7 +861,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
861 /// Read. 861 /// Read.
862 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 862 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
863 #[cfg(all(feature = "low-power", stm32wlex))] 863 #[cfg(all(feature = "low-power", stm32wlex))]
864 let _device_busy = crate::low_power::DeviceBusy::new(); 864 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
865 let timeout = self.timeout(); 865 let timeout = self.timeout();
866 866
867 if buffer.is_empty() { 867 if buffer.is_empty() {
@@ -875,7 +875,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
875 /// Write, restart, read. 875 /// Write, restart, read.
876 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 876 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
877 #[cfg(all(feature = "low-power", stm32wlex))] 877 #[cfg(all(feature = "low-power", stm32wlex))]
878 let _device_busy = crate::low_power::DeviceBusy::new(); 878 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
879 let timeout = self.timeout(); 879 let timeout = self.timeout();
880 880
881 if write.is_empty() { 881 if write.is_empty() {
@@ -902,7 +902,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
902 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 902 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
903 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 903 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
904 #[cfg(all(feature = "low-power", stm32wlex))] 904 #[cfg(all(feature = "low-power", stm32wlex))]
905 let _device_busy = crate::low_power::DeviceBusy::new(); 905 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
906 let _ = addr; 906 let _ = addr;
907 let _ = operations; 907 let _ = operations;
908 todo!() 908 todo!()
@@ -1196,7 +1196,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1196 1196
1197 let regs = self.info.regs; 1197 let regs = self.info.regs;
1198 1198
1199 let dma_transfer = unsafe { 1199 let mut dma_transfer = unsafe {
1200 regs.cr1().modify(|w| { 1200 regs.cr1().modify(|w| {
1201 w.set_rxdmaen(true); 1201 w.set_rxdmaen(true);
1202 w.set_stopie(true); 1202 w.set_stopie(true);
@@ -1244,6 +1244,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1244 }) 1244 })
1245 .await?; 1245 .await?;
1246 1246
1247 dma_transfer.request_pause();
1247 dma_transfer.await; 1248 dma_transfer.await;
1248 1249
1249 drop(on_drop); 1250 drop(on_drop);
@@ -1309,6 +1310,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1309 }) 1310 })
1310 .await?; 1311 .await?;
1311 1312
1313 dma_transfer.request_pause();
1312 dma_transfer.await; 1314 dma_transfer.await;
1313 1315
1314 drop(on_drop); 1316 drop(on_drop);
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index db22cfa11..df077a3ae 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -7,6 +7,7 @@ use crate::Peri;
7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer}; 7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer};
8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
9use crate::mode::Async; 9use crate::mode::Async;
10use crate::spi::mode::Master;
10use crate::spi::{Config as SpiConfig, RegsExt as _, *}; 11use crate::spi::{Config as SpiConfig, RegsExt as _, *};
11use crate::time::Hertz; 12use crate::time::Hertz;
12 13
@@ -225,7 +226,7 @@ impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
225pub struct I2S<'d, W: Word> { 226pub struct I2S<'d, W: Word> {
226 #[allow(dead_code)] 227 #[allow(dead_code)]
227 mode: Mode, 228 mode: Mode,
228 spi: Spi<'d, Async>, 229 spi: Spi<'d, Async, Master>,
229 txsd: Option<Peri<'d, AnyPin>>, 230 txsd: Option<Peri<'d, AnyPin>>,
230 rxsd: Option<Peri<'d, AnyPin>>, 231 rxsd: Option<Peri<'d, AnyPin>>,
231 ws: Option<Peri<'d, AnyPin>>, 232 ws: Option<Peri<'d, AnyPin>>,
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index dbf0fe620..85606e7de 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -241,6 +241,14 @@ pub struct Config {
241 /// RCC config. 241 /// RCC config.
242 pub rcc: rcc::Config, 242 pub rcc: rcc::Config,
243 243
244 #[cfg(feature = "low-power")]
245 /// RTC config
246 pub rtc: rtc::RtcConfig,
247
248 #[cfg(feature = "low-power")]
249 /// Minimum time to stop
250 pub min_stop_pause: embassy_time::Duration,
251
244 /// Enable debug during sleep and stop. 252 /// Enable debug during sleep and stop.
245 /// 253 ///
246 /// May increase power consumption. Defaults to true. 254 /// May increase power consumption. Defaults to true.
@@ -294,6 +302,10 @@ impl Default for Config {
294 fn default() -> Self { 302 fn default() -> Self {
295 Self { 303 Self {
296 rcc: Default::default(), 304 rcc: Default::default(),
305 #[cfg(feature = "low-power")]
306 rtc: Default::default(),
307 #[cfg(feature = "low-power")]
308 min_stop_pause: embassy_time::Duration::from_millis(250),
297 #[cfg(dbgmcu)] 309 #[cfg(dbgmcu)]
298 enable_debug_during_sleep: true, 310 enable_debug_during_sleep: true,
299 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] 311 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
@@ -623,6 +635,12 @@ fn init_hw(config: Config) -> Peripherals {
623 exti::init(cs); 635 exti::init(cs);
624 636
625 rcc::init_rcc(cs, config.rcc); 637 rcc::init_rcc(cs, config.rcc);
638
639 #[cfg(feature = "low-power")]
640 crate::rtc::init_rtc(cs, config.rtc);
641
642 #[cfg(feature = "low-power")]
643 crate::time_driver::get_driver().set_min_stop_pause(cs, config.min_stop_pause);
626 } 644 }
627 645
628 p 646 p
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index cde3153f6..696dfe83f 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -41,10 +41,6 @@
41//! config.enable_debug_during_sleep = false; 41//! config.enable_debug_during_sleep = false;
42//! let p = embassy_stm32::init(config); 42//! let p = embassy_stm32::init(config);
43//! 43//!
44//! // give the RTC to the executor...
45//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
46//! embassy_stm32::low_power::stop_with_rtc(rtc);
47//!
48//! // your application here... 44//! // your application here...
49//! } 45//! }
50//! ``` 46//! ```
@@ -57,57 +53,69 @@ use core::marker::PhantomData;
57use core::sync::atomic::{Ordering, compiler_fence}; 53use core::sync::atomic::{Ordering, compiler_fence};
58 54
59use cortex_m::peripheral::SCB; 55use cortex_m::peripheral::SCB;
56use critical_section::CriticalSection;
60use embassy_executor::*; 57use embassy_executor::*;
61 58
62use crate::interrupt; 59use crate::interrupt;
63use crate::time_driver::{RtcDriver, get_driver}; 60use crate::time_driver::get_driver;
64 61
65const THREAD_PENDER: usize = usize::MAX; 62const THREAD_PENDER: usize = usize::MAX;
66 63
67use crate::rtc::Rtc;
68
69static mut EXECUTOR: Option<Executor> = None; 64static mut EXECUTOR: Option<Executor> = None;
70 65
71#[cfg(stm32wlex)] 66/// Prevent the device from going into the stop mode if held
72pub(crate) use self::busy::DeviceBusy; 67pub struct DeviceBusy(StopMode);
73#[cfg(stm32wlex)]
74mod busy {
75 use core::sync::atomic::{AtomicU32, Ordering};
76 68
77 // Count of devices blocking STOP 69impl DeviceBusy {
78 static STOP_BLOCKED: AtomicU32 = AtomicU32::new(0); 70 /// Create a new DeviceBusy with stop1.
71 pub fn new_stop1() -> Self {
72 Self::new(StopMode::Stop1)
73 }
79 74
80 /// Check if STOP1 is blocked. 75 /// Create a new DeviceBusy with stop2.
81 pub(crate) fn stop_blocked() -> bool { 76 pub fn new_stop2() -> Self {
82 STOP_BLOCKED.load(Ordering::SeqCst) > 0 77 Self::new(StopMode::Stop2)
83 } 78 }
84 79
85 /// When ca device goes busy it will construct one of these where it will be dropped when the device goes idle. 80 /// Create a new DeviceBusy.
86 pub(crate) struct DeviceBusy {} 81 pub fn new(stop_mode: StopMode) -> Self {
82 critical_section::with(|_| unsafe {
83 match stop_mode {
84 StopMode::Stop1 => {
85 crate::rcc::REFCOUNT_STOP1 += 1;
86 }
87 StopMode::Stop2 => {
88 crate::rcc::REFCOUNT_STOP2 += 1;
89 }
90 }
91 });
87 92
88 impl DeviceBusy { 93 Self(stop_mode)
89 /// Create a new DeviceBusy.
90 pub(crate) fn new() -> Self {
91 STOP_BLOCKED.fetch_add(1, Ordering::SeqCst);
92 trace!("low power: device busy: Stop:{}", STOP_BLOCKED.load(Ordering::SeqCst));
93 Self {}
94 }
95 } 94 }
95}
96 96
97 impl Drop for DeviceBusy { 97impl Drop for DeviceBusy {
98 fn drop(&mut self) { 98 fn drop(&mut self) {
99 STOP_BLOCKED.fetch_sub(1, Ordering::SeqCst); 99 critical_section::with(|_| unsafe {
100 trace!("low power: device idle: Stop:{}", STOP_BLOCKED.load(Ordering::SeqCst)); 100 match self.0 {
101 } 101 StopMode::Stop1 => {
102 crate::rcc::REFCOUNT_STOP1 -= 1;
103 }
104 StopMode::Stop2 => {
105 crate::rcc::REFCOUNT_STOP2 -= 1;
106 }
107 }
108 });
102 } 109 }
103} 110}
111
104#[cfg(not(stm32u0))] 112#[cfg(not(stm32u0))]
105foreach_interrupt! { 113foreach_interrupt! {
106 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 114 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
107 #[interrupt] 115 #[interrupt]
108 #[allow(non_snake_case)] 116 #[allow(non_snake_case)]
109 unsafe fn $irq() { 117 unsafe fn $irq() {
110 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 118 Executor::on_wakeup_irq();
111 } 119 }
112 }; 120 };
113} 121}
@@ -118,39 +126,21 @@ foreach_interrupt! {
118 #[interrupt] 126 #[interrupt]
119 #[allow(non_snake_case)] 127 #[allow(non_snake_case)]
120 unsafe fn $irq() { 128 unsafe fn $irq() {
121 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 129 Executor::on_wakeup_irq();
122 } 130 }
123 }; 131 };
124} 132}
125 133
126#[allow(dead_code)]
127pub(crate) unsafe fn on_wakeup_irq() {
128 if EXECUTOR.is_some() {
129 trace!("low power: wakeup irq");
130 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
131 }
132}
133
134/// Configure STOP mode with RTC.
135pub fn stop_with_rtc(rtc: Rtc) {
136 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
137}
138
139/// Reconfigure the RTC, if set.
140pub fn reconfigure_rtc(f: impl FnOnce(&mut Rtc)) {
141 unsafe { EXECUTOR.as_mut().unwrap() }.reconfigure_rtc(f);
142}
143
144/// Get whether the core is ready to enter the given stop mode. 134/// Get whether the core is ready to enter the given stop mode.
145/// 135///
146/// This will return false if some peripheral driver is in use that 136/// This will return false if some peripheral driver is in use that
147/// prevents entering the given stop mode. 137/// prevents entering the given stop mode.
148pub fn stop_ready(stop_mode: StopMode) -> bool { 138pub fn stop_ready(stop_mode: StopMode) -> bool {
149 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { 139 critical_section::with(|cs| match Executor::stop_mode(cs) {
150 Some(StopMode::Stop2) => true, 140 Some(StopMode::Stop2) => true,
151 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, 141 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1,
152 None => false, 142 None => false,
153 } 143 })
154} 144}
155 145
156/// Available Stop modes. 146/// Available Stop modes.
@@ -193,7 +183,6 @@ pub struct Executor {
193 inner: raw::Executor, 183 inner: raw::Executor,
194 not_send: PhantomData<*mut ()>, 184 not_send: PhantomData<*mut ()>,
195 scb: SCB, 185 scb: SCB,
196 time_driver: &'static RtcDriver,
197} 186}
198 187
199impl Executor { 188impl Executor {
@@ -206,7 +195,6 @@ impl Executor {
206 inner: raw::Executor::new(THREAD_PENDER as *mut ()), 195 inner: raw::Executor::new(THREAD_PENDER as *mut ()),
207 not_send: PhantomData, 196 not_send: PhantomData,
208 scb: cortex_m::Peripherals::steal().SCB, 197 scb: cortex_m::Peripherals::steal().SCB,
209 time_driver: get_driver(),
210 }); 198 });
211 199
212 let executor = EXECUTOR.as_mut().unwrap(); 200 let executor = EXECUTOR.as_mut().unwrap();
@@ -215,54 +203,33 @@ impl Executor {
215 }) 203 })
216 } 204 }
217 205
218 unsafe fn on_wakeup_irq(&mut self) { 206 pub(crate) unsafe fn on_wakeup_irq() {
219 #[cfg(stm32wlex)] 207 critical_section::with(|cs| {
220 { 208 #[cfg(stm32wlex)]
221 let extscr = crate::pac::PWR.extscr().read(); 209 {
222 if extscr.c1stop2f() || extscr.c1stopf() { 210 let extscr = crate::pac::PWR.extscr().read();
223 // when we wake from any stop mode we need to re-initialize the rcc 211 if extscr.c1stop2f() || extscr.c1stopf() {
224 crate::rcc::apply_resume_config(); 212 // when we wake from any stop mode we need to re-initialize the rcc
225 if extscr.c1stop2f() { 213 crate::rcc::apply_resume_config();
226 // when we wake from STOP2, we need to re-initialize the time driver 214 if extscr.c1stop2f() {
227 critical_section::with(|cs| crate::time_driver::init_timer(cs)); 215 // when we wake from STOP2, we need to re-initialize the time driver
228 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) 216 crate::time_driver::init_timer(cs);
229 // and given that we just woke from STOP2, we can reset them 217 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
230 crate::rcc::REFCOUNT_STOP2 = 0; 218 // and given that we just woke from STOP2, we can reset them
231 crate::rcc::REFCOUNT_STOP1 = 0; 219 crate::rcc::REFCOUNT_STOP2 = 0;
220 crate::rcc::REFCOUNT_STOP1 = 0;
221 }
232 } 222 }
233 } 223 }
234 } 224 get_driver().resume_time(cs);
235 self.time_driver.resume_time(); 225 trace!("low power: resume");
236 trace!("low power: resume"); 226 });
237 }
238
239 pub(self) fn stop_with_rtc(&mut self, rtc: Rtc) {
240 self.time_driver.set_rtc(rtc);
241 self.time_driver.reconfigure_rtc(|rtc| rtc.enable_wakeup_line());
242
243 trace!("low power: stop with rtc configured");
244 }
245
246 pub(self) fn reconfigure_rtc(&mut self, f: impl FnOnce(&mut Rtc)) {
247 self.time_driver.reconfigure_rtc(f);
248 }
249
250 fn stop1_ok_to_enter(&self) -> bool {
251 #[cfg(stm32wlex)]
252 if self::busy::stop_blocked() {
253 return false;
254 }
255 unsafe { crate::rcc::REFCOUNT_STOP1 == 0 }
256 }
257
258 fn stop2_ok_to_enter(&self) -> bool {
259 self.stop1_ok_to_enter() && unsafe { crate::rcc::REFCOUNT_STOP2 == 0 }
260 } 227 }
261 228
262 fn stop_mode(&self) -> Option<StopMode> { 229 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> {
263 if self.stop2_ok_to_enter() { 230 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 && crate::rcc::REFCOUNT_STOP1 == 0 } {
264 Some(StopMode::Stop2) 231 Some(StopMode::Stop2)
265 } else if self.stop1_ok_to_enter() { 232 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } {
266 Some(StopMode::Stop1) 233 Some(StopMode::Stop1)
267 } else { 234 } else {
268 None 235 None
@@ -291,14 +258,14 @@ impl Executor {
291 258
292 compiler_fence(Ordering::SeqCst); 259 compiler_fence(Ordering::SeqCst);
293 260
294 let stop_mode = self.stop_mode(); 261 let stop_mode = critical_section::with(|cs| Self::stop_mode(cs));
295 262
296 if stop_mode.is_none() { 263 if stop_mode.is_none() {
297 trace!("low power: not ready to stop"); 264 trace!("low power: not ready to stop");
298 return; 265 return;
299 } 266 }
300 267
301 if self.time_driver.pause_time().is_err() { 268 if get_driver().pause_time().is_err() {
302 trace!("low power: failed to pause time"); 269 trace!("low power: failed to pause time");
303 return; 270 return;
304 } 271 }
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index e09d5afb0..e5bf30927 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -4,7 +4,7 @@ use embassy_time::{Duration, TICK_HZ};
4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; 4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte};
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::peripherals::RTC; 6use crate::peripherals::RTC;
7use crate::rtc::SealedInstance; 7use crate::rtc::{RtcTimeProvider, SealedInstance};
8 8
9/// Represents an instant in time that can be substracted to compute a duration 9/// Represents an instant in time that can be substracted to compute a duration
10pub(super) struct RtcInstant { 10pub(super) struct RtcInstant {
@@ -117,7 +117,7 @@ impl WakeupPrescaler {
117impl Rtc { 117impl Rtc {
118 /// Return the current instant. 118 /// Return the current instant.
119 fn instant(&self) -> Result<RtcInstant, RtcError> { 119 fn instant(&self) -> Result<RtcInstant, RtcError> {
120 self.time_provider().read(|_, tr, ss| { 120 RtcTimeProvider::new().read(|_, tr, ss| {
121 let second = bcd2_to_byte((tr.st(), tr.su())); 121 let second = bcd2_to_byte((tr.st(), tr.su()));
122 122
123 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) 123 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index bc6df528b..116b3c7ed 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -5,9 +5,13 @@ mod datetime;
5mod low_power; 5mod low_power;
6 6
7#[cfg(feature = "low-power")] 7#[cfg(feature = "low-power")]
8use core::cell::Cell; 8use core::cell::{Cell, RefCell, RefMut};
9#[cfg(feature = "low-power")]
10use core::ops;
9 11
10#[cfg(feature = "low-power")] 12#[cfg(feature = "low-power")]
13use critical_section::CriticalSection;
14#[cfg(feature = "low-power")]
11use embassy_sync::blocking_mutex::Mutex; 15use embassy_sync::blocking_mutex::Mutex;
12#[cfg(feature = "low-power")] 16#[cfg(feature = "low-power")]
13use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 17use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
@@ -44,11 +48,17 @@ pub enum RtcError {
44} 48}
45 49
46/// Provides immutable access to the current time of the RTC. 50/// Provides immutable access to the current time of the RTC.
51#[derive(Clone)]
47pub struct RtcTimeProvider { 52pub struct RtcTimeProvider {
48 _private: (), 53 _private: (),
49} 54}
50 55
51impl RtcTimeProvider { 56impl RtcTimeProvider {
57 /// Create a new RTC time provider instance.
58 pub(self) const fn new() -> Self {
59 Self { _private: () }
60 }
61
52 /// Return the current datetime. 62 /// Return the current datetime.
53 /// 63 ///
54 /// # Errors 64 /// # Errors
@@ -106,6 +116,50 @@ impl RtcTimeProvider {
106 } 116 }
107} 117}
108 118
119#[cfg(feature = "low-power")]
120/// Contains an RTC driver.
121pub struct RtcContainer {
122 pub(self) mutex: &'static Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
123}
124
125#[cfg(feature = "low-power")]
126impl RtcContainer {
127 pub(self) const fn new() -> Self {
128 Self {
129 mutex: &crate::time_driver::get_driver().rtc,
130 }
131 }
132
133 /// Acquire an RTC borrow.
134 pub fn borrow_mut<'a>(&self, cs: CriticalSection<'a>) -> RtcBorrow<'a> {
135 RtcBorrow {
136 ref_mut: self.mutex.borrow(cs).borrow_mut(),
137 }
138 }
139}
140
141#[cfg(feature = "low-power")]
142/// Contains an RTC borrow.
143pub struct RtcBorrow<'a> {
144 pub(self) ref_mut: RefMut<'a, Option<Rtc>>,
145}
146
147#[cfg(feature = "low-power")]
148impl<'a> ops::Deref for RtcBorrow<'a> {
149 type Target = Rtc;
150
151 fn deref(&self) -> &Self::Target {
152 self.ref_mut.as_ref().unwrap()
153 }
154}
155
156#[cfg(feature = "low-power")]
157impl<'a> ops::DerefMut for RtcBorrow<'a> {
158 fn deref_mut(&mut self) -> &mut Self::Target {
159 self.ref_mut.as_mut().unwrap()
160 }
161}
162
109/// RTC driver. 163/// RTC driver.
110pub struct Rtc { 164pub struct Rtc {
111 #[cfg(feature = "low-power")] 165 #[cfg(feature = "low-power")]
@@ -121,13 +175,21 @@ pub struct RtcConfig {
121 /// 175 ///
122 /// A high counter frequency may impact stop power consumption 176 /// A high counter frequency may impact stop power consumption
123 pub frequency: Hertz, 177 pub frequency: Hertz,
178
179 #[cfg(feature = "_allow-disable-rtc")]
180 /// Allow disabling the rtc, even when stop is configured
181 pub _disable_rtc: bool,
124} 182}
125 183
126impl Default for RtcConfig { 184impl Default for RtcConfig {
127 /// LSI with prescalers assuming 32.768 kHz. 185 /// LSI with prescalers assuming 32.768 kHz.
128 /// Raw sub-seconds in 1/256. 186 /// Raw sub-seconds in 1/256.
129 fn default() -> Self { 187 fn default() -> Self {
130 RtcConfig { frequency: Hertz(256) } 188 RtcConfig {
189 frequency: Hertz(256),
190 #[cfg(feature = "_allow-disable-rtc")]
191 _disable_rtc: false,
192 }
131 } 193 }
132} 194}
133 195
@@ -145,8 +207,19 @@ pub enum RtcCalibrationCyclePeriod {
145} 207}
146 208
147impl Rtc { 209impl Rtc {
210 #[cfg(not(feature = "low-power"))]
211 /// Create a new RTC instance.
212 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> (Self, RtcTimeProvider) {
213 (Self::new_inner(rtc_config), RtcTimeProvider::new())
214 }
215
216 #[cfg(feature = "low-power")]
148 /// Create a new RTC instance. 217 /// Create a new RTC instance.
149 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { 218 pub fn new(_rtc: Peri<'static, RTC>) -> (RtcContainer, RtcTimeProvider) {
219 (RtcContainer::new(), RtcTimeProvider::new())
220 }
221
222 pub(self) fn new_inner(rtc_config: RtcConfig) -> Self {
150 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 223 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
151 crate::rcc::enable_and_reset::<RTC>(); 224 crate::rcc::enable_and_reset::<RTC>();
152 225
@@ -165,10 +238,13 @@ impl Rtc {
165 // Wait for the clock to update after initialization 238 // Wait for the clock to update after initialization
166 #[cfg(not(rtc_v2_f2))] 239 #[cfg(not(rtc_v2_f2))]
167 { 240 {
168 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); 241 let now = RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap();
169 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} 242 while now == RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap() {}
170 } 243 }
171 244
245 #[cfg(feature = "low-power")]
246 this.enable_wakeup_line();
247
172 this 248 this
173 } 249 }
174 250
@@ -177,11 +253,6 @@ impl Rtc {
177 freqs.rtc.to_hertz().unwrap() 253 freqs.rtc.to_hertz().unwrap()
178 } 254 }
179 255
180 /// Acquire a [`RtcTimeProvider`] instance.
181 pub const fn time_provider(&self) -> RtcTimeProvider {
182 RtcTimeProvider { _private: () }
183 }
184
185 /// Set the datetime to a new value. 256 /// Set the datetime to a new value.
186 /// 257 ///
187 /// # Errors 258 /// # Errors
@@ -225,15 +296,6 @@ impl Rtc {
225 Ok(()) 296 Ok(())
226 } 297 }
227 298
228 /// Return the current datetime.
229 ///
230 /// # Errors
231 ///
232 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
233 pub fn now(&self) -> Result<DateTime, RtcError> {
234 self.time_provider().now()
235 }
236
237 /// Check if daylight savings time is active. 299 /// Check if daylight savings time is active.
238 pub fn get_daylight_savings(&self) -> bool { 300 pub fn get_daylight_savings(&self) -> bool {
239 let cr = RTC::regs().cr().read(); 301 let cr = RTC::regs().cr().read();
@@ -315,3 +377,15 @@ trait SealedInstance {
315 377
316 // fn apply_config(&mut self, rtc_config: RtcConfig); 378 // fn apply_config(&mut self, rtc_config: RtcConfig);
317} 379}
380
381#[cfg(feature = "low-power")]
382pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig) {
383 #[cfg(feature = "_allow-disable-rtc")]
384 if config._disable_rtc {
385 return;
386 }
387
388 crate::time_driver::get_driver().set_rtc(cs, Rtc::new_inner(config));
389
390 trace!("low power: stop with rtc configured");
391}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c27d09ea7..abb80ed26 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -125,26 +125,69 @@ impl Config {
125 ) 125 )
126 } 126 }
127} 127}
128
129/// SPI communication mode
130pub mod mode {
131 use stm32_metapac::spi::vals;
132
133 trait SealedMode {}
134
135 /// Trait for SPI communication mode operations.
136 #[allow(private_bounds)]
137 pub trait CommunicationMode: SealedMode {
138 /// Spi communication mode
139 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
140 const MASTER: vals::Mstr;
141 /// Spi communication mode
142 #[cfg(any(spi_v4, spi_v5, spi_v6))]
143 const MASTER: vals::Master;
144 }
145
146 /// Mode allowing for SPI master operations.
147 pub struct Master;
148 /// Mode allowing for SPI slave operations.
149 pub struct Slave;
150
151 impl SealedMode for Master {}
152 impl CommunicationMode for Master {
153 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
154 const MASTER: vals::Mstr = vals::Mstr::MASTER;
155 #[cfg(any(spi_v4, spi_v5, spi_v6))]
156 const MASTER: vals::Master = vals::Master::MASTER;
157 }
158
159 impl SealedMode for Slave {}
160 impl CommunicationMode for Slave {
161 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
162 const MASTER: vals::Mstr = vals::Mstr::SLAVE;
163 #[cfg(any(spi_v4, spi_v5, spi_v6))]
164 const MASTER: vals::Master = vals::Master::SLAVE;
165 }
166}
167use mode::{CommunicationMode, Master, Slave};
168
128/// SPI driver. 169/// SPI driver.
129pub struct Spi<'d, M: PeriMode> { 170pub struct Spi<'d, M: PeriMode, CM: CommunicationMode> {
130 pub(crate) info: &'static Info, 171 pub(crate) info: &'static Info,
131 kernel_clock: Hertz, 172 kernel_clock: Hertz,
132 sck: Option<Peri<'d, AnyPin>>, 173 sck: Option<Peri<'d, AnyPin>>,
133 mosi: Option<Peri<'d, AnyPin>>, 174 mosi: Option<Peri<'d, AnyPin>>,
134 miso: Option<Peri<'d, AnyPin>>, 175 miso: Option<Peri<'d, AnyPin>>,
176 nss: Option<Peri<'d, AnyPin>>,
135 tx_dma: Option<ChannelAndRequest<'d>>, 177 tx_dma: Option<ChannelAndRequest<'d>>,
136 rx_dma: Option<ChannelAndRequest<'d>>, 178 rx_dma: Option<ChannelAndRequest<'d>>,
137 _phantom: PhantomData<M>, 179 _phantom: PhantomData<(M, CM)>,
138 current_word_size: word_impl::Config, 180 current_word_size: word_impl::Config,
139 gpio_speed: Speed, 181 gpio_speed: Speed,
140} 182}
141 183
142impl<'d, M: PeriMode> Spi<'d, M> { 184impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
143 fn new_inner<T: Instance>( 185 fn new_inner<T: Instance>(
144 _peri: Peri<'d, T>, 186 _peri: Peri<'d, T>,
145 sck: Option<Peri<'d, AnyPin>>, 187 sck: Option<Peri<'d, AnyPin>>,
146 mosi: Option<Peri<'d, AnyPin>>, 188 mosi: Option<Peri<'d, AnyPin>>,
147 miso: Option<Peri<'d, AnyPin>>, 189 miso: Option<Peri<'d, AnyPin>>,
190 nss: Option<Peri<'d, AnyPin>>,
148 tx_dma: Option<ChannelAndRequest<'d>>, 191 tx_dma: Option<ChannelAndRequest<'d>>,
149 rx_dma: Option<ChannelAndRequest<'d>>, 192 rx_dma: Option<ChannelAndRequest<'d>>,
150 config: Config, 193 config: Config,
@@ -155,6 +198,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
155 sck, 198 sck,
156 mosi, 199 mosi,
157 miso, 200 miso,
201 nss,
158 tx_dma, 202 tx_dma,
159 rx_dma, 203 rx_dma,
160 current_word_size: <u8 as SealedWord>::CONFIG, 204 current_word_size: <u8 as SealedWord>::CONFIG,
@@ -183,12 +227,12 @@ impl<'d, M: PeriMode> Spi<'d, M> {
183 w.set_cpha(cpha); 227 w.set_cpha(cpha);
184 w.set_cpol(cpol); 228 w.set_cpol(cpol);
185 229
186 w.set_mstr(vals::Mstr::MASTER); 230 w.set_mstr(CM::MASTER);
187 w.set_br(br); 231 w.set_br(br);
188 w.set_spe(true); 232 w.set_spe(true);
189 w.set_lsbfirst(lsbfirst); 233 w.set_lsbfirst(lsbfirst);
190 w.set_ssi(true); 234 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
191 w.set_ssm(true); 235 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
192 w.set_crcen(false); 236 w.set_crcen(false);
193 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 237 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
194 // we're doing "fake rxonly", by actually writing one 238 // we're doing "fake rxonly", by actually writing one
@@ -210,11 +254,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
210 w.set_cpha(cpha); 254 w.set_cpha(cpha);
211 w.set_cpol(cpol); 255 w.set_cpol(cpol);
212 256
213 w.set_mstr(vals::Mstr::MASTER); 257 w.set_mstr(CM::MASTER);
214 w.set_br(br); 258 w.set_br(br);
215 w.set_lsbfirst(lsbfirst); 259 w.set_lsbfirst(lsbfirst);
216 w.set_ssi(true); 260 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
217 w.set_ssm(true); 261 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
218 w.set_crcen(false); 262 w.set_crcen(false);
219 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 263 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
220 w.set_spe(true); 264 w.set_spe(true);
@@ -229,8 +273,8 @@ impl<'d, M: PeriMode> Spi<'d, M> {
229 w.set_cpha(cpha); 273 w.set_cpha(cpha);
230 w.set_cpol(cpol); 274 w.set_cpol(cpol);
231 w.set_lsbfirst(lsbfirst); 275 w.set_lsbfirst(lsbfirst);
232 w.set_ssm(true); 276 w.set_ssm(CM::MASTER == vals::Master::MASTER);
233 w.set_master(vals::Master::MASTER); 277 w.set_master(CM::MASTER);
234 w.set_comm(vals::Comm::FULL_DUPLEX); 278 w.set_comm(vals::Comm::FULL_DUPLEX);
235 w.set_ssom(vals::Ssom::ASSERTED); 279 w.set_ssom(vals::Ssom::ASSERTED);
236 w.set_midi(0); 280 w.set_midi(0);
@@ -469,7 +513,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
469 } 513 }
470} 514}
471 515
472impl<'d> Spi<'d, Blocking> { 516impl<'d> Spi<'d, Blocking, Slave> {
517 /// Create a new blocking SPI slave driver.
518 pub fn new_blocking_slave<T: Instance, #[cfg(afio)] A>(
519 peri: Peri<'d, T>,
520 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
521 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
522 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
523 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
524 config: Config,
525 ) -> Self {
526 Self::new_inner(
527 peri,
528 new_pin!(sck, config.sck_af()),
529 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
530 new_pin!(miso, AfType::input(config.miso_pull)),
531 new_pin!(cs, AfType::input(Pull::None)),
532 None,
533 None,
534 config,
535 )
536 }
537}
538
539impl<'d> Spi<'d, Blocking, Master> {
473 /// Create a new blocking SPI driver. 540 /// Create a new blocking SPI driver.
474 pub fn new_blocking<T: Instance, #[cfg(afio)] A>( 541 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
475 peri: Peri<'d, T>, 542 peri: Peri<'d, T>,
@@ -485,6 +552,7 @@ impl<'d> Spi<'d, Blocking> {
485 new_pin!(miso, AfType::input(config.miso_pull)), 552 new_pin!(miso, AfType::input(config.miso_pull)),
486 None, 553 None,
487 None, 554 None,
555 None,
488 config, 556 config,
489 ) 557 )
490 } 558 }
@@ -503,6 +571,7 @@ impl<'d> Spi<'d, Blocking> {
503 new_pin!(miso, AfType::input(config.miso_pull)), 571 new_pin!(miso, AfType::input(config.miso_pull)),
504 None, 572 None,
505 None, 573 None,
574 None,
506 config, 575 config,
507 ) 576 )
508 } 577 }
@@ -521,6 +590,7 @@ impl<'d> Spi<'d, Blocking> {
521 None, 590 None,
522 None, 591 None,
523 None, 592 None,
593 None,
524 config, 594 config,
525 ) 595 )
526 } 596 }
@@ -540,12 +610,38 @@ impl<'d> Spi<'d, Blocking> {
540 None, 610 None,
541 None, 611 None,
542 None, 612 None,
613 None,
614 config,
615 )
616 }
617}
618
619impl<'d> Spi<'d, Async, Slave> {
620 /// Create a new SPI slave driver.
621 pub fn new_slave<T: Instance, #[cfg(afio)] A>(
622 peri: Peri<'d, T>,
623 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
624 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
625 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
626 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
627 tx_dma: Peri<'d, impl TxDma<T>>,
628 rx_dma: Peri<'d, impl RxDma<T>>,
629 config: Config,
630 ) -> Self {
631 Self::new_inner(
632 peri,
633 new_pin!(sck, config.sck_af()),
634 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
635 new_pin!(miso, AfType::input(config.miso_pull)),
636 new_pin!(cs, AfType::input(Pull::None)),
637 new_dma!(tx_dma),
638 new_dma!(rx_dma),
543 config, 639 config,
544 ) 640 )
545 } 641 }
546} 642}
547 643
548impl<'d> Spi<'d, Async> { 644impl<'d> Spi<'d, Async, Master> {
549 /// Create a new SPI driver. 645 /// Create a new SPI driver.
550 pub fn new<T: Instance, #[cfg(afio)] A>( 646 pub fn new<T: Instance, #[cfg(afio)] A>(
551 peri: Peri<'d, T>, 647 peri: Peri<'d, T>,
@@ -561,6 +657,7 @@ impl<'d> Spi<'d, Async> {
561 new_pin!(sck, config.sck_af()), 657 new_pin!(sck, config.sck_af()),
562 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 658 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
563 new_pin!(miso, AfType::input(config.miso_pull)), 659 new_pin!(miso, AfType::input(config.miso_pull)),
660 None,
564 new_dma!(tx_dma), 661 new_dma!(tx_dma),
565 new_dma!(rx_dma), 662 new_dma!(rx_dma),
566 config, 663 config,
@@ -581,6 +678,7 @@ impl<'d> Spi<'d, Async> {
581 new_pin!(sck, config.sck_af()), 678 new_pin!(sck, config.sck_af()),
582 None, 679 None,
583 new_pin!(miso, AfType::input(config.miso_pull)), 680 new_pin!(miso, AfType::input(config.miso_pull)),
681 None,
584 #[cfg(any(spi_v1, spi_v2, spi_v3))] 682 #[cfg(any(spi_v1, spi_v2, spi_v3))]
585 new_dma!(tx_dma), 683 new_dma!(tx_dma),
586 #[cfg(any(spi_v4, spi_v5, spi_v6))] 684 #[cfg(any(spi_v4, spi_v5, spi_v6))]
@@ -603,6 +701,7 @@ impl<'d> Spi<'d, Async> {
603 new_pin!(sck, config.sck_af()), 701 new_pin!(sck, config.sck_af()),
604 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 702 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
605 None, 703 None,
704 None,
606 new_dma!(tx_dma), 705 new_dma!(tx_dma),
607 None, 706 None,
608 config, 707 config,
@@ -623,6 +722,7 @@ impl<'d> Spi<'d, Async> {
623 None, 722 None,
624 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 723 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
625 None, 724 None,
725 None,
626 new_dma!(tx_dma), 726 new_dma!(tx_dma),
627 None, 727 None,
628 config, 728 config,
@@ -646,7 +746,7 @@ impl<'d> Spi<'d, Async> {
646 config.bit_order = BitOrder::MsbFirst; 746 config.bit_order = BitOrder::MsbFirst;
647 config.frequency = freq; 747 config.frequency = freq;
648 748
649 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 749 Self::new_inner(peri, None, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
650 } 750 }
651 751
652 #[allow(dead_code)] 752 #[allow(dead_code)]
@@ -656,9 +756,11 @@ impl<'d> Spi<'d, Async> {
656 rx_dma: Option<ChannelAndRequest<'d>>, 756 rx_dma: Option<ChannelAndRequest<'d>>,
657 config: Config, 757 config: Config,
658 ) -> Self { 758 ) -> Self {
659 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config) 759 Self::new_inner(peri, None, None, None, None, tx_dma, rx_dma, config)
660 } 760 }
761}
661 762
763impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> {
662 /// SPI write, using DMA. 764 /// SPI write, using DMA.
663 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { 765 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
664 if data.is_empty() { 766 if data.is_empty() {
@@ -888,11 +990,12 @@ impl<'d> Spi<'d, Async> {
888 } 990 }
889} 991}
890 992
891impl<'d, M: PeriMode> Drop for Spi<'d, M> { 993impl<'d, M: PeriMode, CM: CommunicationMode> Drop for Spi<'d, M, CM> {
892 fn drop(&mut self) { 994 fn drop(&mut self) {
893 self.sck.as_ref().map(|x| x.set_as_disconnected()); 995 self.sck.as_ref().map(|x| x.set_as_disconnected());
894 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 996 self.mosi.as_ref().map(|x| x.set_as_disconnected());
895 self.miso.as_ref().map(|x| x.set_as_disconnected()); 997 self.miso.as_ref().map(|x| x.set_as_disconnected());
998 self.nss.as_ref().map(|x| x.set_as_disconnected());
896 999
897 self.info.rcc.disable(); 1000 self.info.rcc.disable();
898 } 1001 }
@@ -1127,7 +1230,7 @@ fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> {
1127// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 1230// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
1128macro_rules! impl_blocking { 1231macro_rules! impl_blocking {
1129 ($w:ident) => { 1232 ($w:ident) => {
1130 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> { 1233 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M, CM> {
1131 type Error = Error; 1234 type Error = Error;
1132 1235
1133 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 1236 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -1135,7 +1238,7 @@ macro_rules! impl_blocking {
1135 } 1238 }
1136 } 1239 }
1137 1240
1138 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> { 1241 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M, CM> {
1139 type Error = Error; 1242 type Error = Error;
1140 1243
1141 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 1244 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -1149,11 +1252,11 @@ macro_rules! impl_blocking {
1149impl_blocking!(u8); 1252impl_blocking!(u8);
1150impl_blocking!(u16); 1253impl_blocking!(u16);
1151 1254
1152impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { 1255impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::ErrorType for Spi<'d, M, CM> {
1153 type Error = Error; 1256 type Error = Error;
1154} 1257}
1155 1258
1156impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> { 1259impl<'d, W: Word, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M, CM> {
1157 fn flush(&mut self) -> Result<(), Self::Error> { 1260 fn flush(&mut self) -> Result<(), Self::Error> {
1158 Ok(()) 1261 Ok(())
1159 } 1262 }
@@ -1186,7 +1289,7 @@ impl embedded_hal_1::spi::Error for Error {
1186 } 1289 }
1187} 1290}
1188 1291
1189impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> { 1292impl<'d, W: Word, CM: CommunicationMode> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async, CM> {
1190 async fn flush(&mut self) -> Result<(), Self::Error> { 1293 async fn flush(&mut self) -> Result<(), Self::Error> {
1191 Ok(()) 1294 Ok(())
1192 } 1295 }
@@ -1328,7 +1431,7 @@ foreach_peripheral!(
1328 }; 1431 };
1329); 1432);
1330 1433
1331impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { 1434impl<'d, M: PeriMode, CM: CommunicationMode> SetConfig for Spi<'d, M, CM> {
1332 type Config = Config; 1435 type Config = Config;
1333 type ConfigError = (); 1436 type ConfigError = ();
1334 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1437 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 4956d1f68..7db51d72e 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -215,7 +215,10 @@ pub(crate) struct RtcDriver {
215 period: AtomicU32, 215 period: AtomicU32,
216 alarm: Mutex<CriticalSectionRawMutex, AlarmState>, 216 alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
217 #[cfg(feature = "low-power")] 217 #[cfg(feature = "low-power")]
218 rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>, 218 pub(crate) rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
219 #[cfg(feature = "low-power")]
220 /// The minimum pause time beyond which the executor will enter a low-power state.
221 min_stop_pause: Mutex<CriticalSectionRawMutex, Cell<embassy_time::Duration>>,
219 /// Saved count for the timer (its value is lost when entering STOP2) 222 /// Saved count for the timer (its value is lost when entering STOP2)
220 #[cfg(all(feature = "low-power", stm32wlex))] 223 #[cfg(all(feature = "low-power", stm32wlex))]
221 saved_count: AtomicU16, 224 saved_count: AtomicU16,
@@ -227,6 +230,8 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
227 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), 230 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
228 #[cfg(feature = "low-power")] 231 #[cfg(feature = "low-power")]
229 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)), 232 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)),
233 #[cfg(feature = "low-power")]
234 min_stop_pause: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(embassy_time::Duration::from_millis(0))),
230 #[cfg(all(feature = "low-power", stm32wlex))] 235 #[cfg(all(feature = "low-power", stm32wlex))]
231 saved_count: AtomicU16::new(0), 236 saved_count: AtomicU16::new(0),
232 queue: Mutex::new(RefCell::new(Queue::new())) 237 queue: Mutex::new(RefCell::new(Queue::new()))
@@ -400,27 +405,20 @@ impl RtcDriver {
400 } 405 }
401 406
402 /* 407 /*
403 Low-power public functions: all create a critical section 408 Low-power public functions: all create or require a critical section
404 */ 409 */
405 #[cfg(feature = "low-power")] 410 #[cfg(feature = "low-power")]
406 /// Set the rtc but panic if it's already been set 411 pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) {
407 pub(crate) fn set_rtc(&self, mut rtc: Rtc) { 412 self.min_stop_pause.borrow(cs).replace(min_stop_pause);
408 critical_section::with(|cs| {
409 rtc.stop_wakeup_alarm(cs);
410
411 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())
412 });
413 } 413 }
414 414
415 #[cfg(feature = "low-power")] 415 #[cfg(feature = "low-power")]
416 /// Set the rtc but panic if it's already been set 416 /// Set the rtc but panic if it's already been set
417 pub(crate) fn reconfigure_rtc(&self, f: impl FnOnce(&mut Rtc)) { 417 pub(crate) fn set_rtc(&self, cs: CriticalSection, mut rtc: Rtc) {
418 critical_section::with(|cs| f(self.rtc.borrow(cs).borrow_mut().as_mut().unwrap())); 418 rtc.stop_wakeup_alarm(cs);
419 }
420 419
421 #[cfg(feature = "low-power")] 420 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none());
422 /// The minimum pause time beyond which the executor will enter a low-power state. 421 }
423 pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250);
424 422
425 #[cfg(feature = "low-power")] 423 #[cfg(feature = "low-power")]
426 /// Pause the timer if ready; return err if not 424 /// Pause the timer if ready; return err if not
@@ -434,9 +432,9 @@ impl RtcDriver {
434 self.stop_wakeup_alarm(cs); 432 self.stop_wakeup_alarm(cs);
435 433
436 let time_until_next_alarm = self.time_until_next_alarm(cs); 434 let time_until_next_alarm = self.time_until_next_alarm(cs);
437 if time_until_next_alarm < Self::MIN_STOP_PAUSE { 435 if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() {
438 trace!( 436 trace!(
439 "time_until_next_alarm < Self::MIN_STOP_PAUSE ({})", 437 "time_until_next_alarm < self.min_stop_pause ({})",
440 time_until_next_alarm 438 time_until_next_alarm
441 ); 439 );
442 Err(()) 440 Err(())
@@ -460,18 +458,16 @@ impl RtcDriver {
460 458
461 #[cfg(feature = "low-power")] 459 #[cfg(feature = "low-power")]
462 /// Resume the timer with the given offset 460 /// Resume the timer with the given offset
463 pub(crate) fn resume_time(&self) { 461 pub(crate) fn resume_time(&self, cs: CriticalSection) {
464 if regs_gp16().cr1().read().cen() { 462 if regs_gp16().cr1().read().cen() {
465 // Time isn't currently stopped 463 // Time isn't currently stopped
466 464
467 return; 465 return;
468 } 466 }
469 467
470 critical_section::with(|cs| { 468 self.stop_wakeup_alarm(cs);
471 self.stop_wakeup_alarm(cs);
472 469
473 regs_gp16().cr1().modify(|w| w.set_cen(true)); 470 regs_gp16().cr1().modify(|w| w.set_cen(true));
474 })
475 } 471 }
476 472
477 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { 473 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
@@ -543,7 +539,7 @@ impl Driver for RtcDriver {
543} 539}
544 540
545#[cfg(feature = "low-power")] 541#[cfg(feature = "low-power")]
546pub(crate) fn get_driver() -> &'static RtcDriver { 542pub(crate) const fn get_driver() -> &'static RtcDriver {
547 &DRIVER 543 &DRIVER
548} 544}
549 545
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index b09bc7166..804d1ef37 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -399,7 +399,7 @@ pub struct UpdateInterruptHandler<T: CoreInstance> {
399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { 399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
400 unsafe fn on_interrupt() { 400 unsafe fn on_interrupt() {
401 #[cfg(feature = "low-power")] 401 #[cfg(feature = "low-power")]
402 crate::low_power::on_wakeup_irq(); 402 crate::low_power::Executor::on_wakeup_irq();
403 403
404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); 404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
405 405
@@ -429,7 +429,7 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare
429{ 429{
430 unsafe fn on_interrupt() { 430 unsafe fn on_interrupt() {
431 #[cfg(feature = "low-power")] 431 #[cfg(feature = "low-power")]
432 crate::low_power::on_wakeup_irq(); 432 crate::low_power::Executor::on_wakeup_irq();
433 433
434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); 434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
435 435
diff --git a/embassy-usb-logger/CHANGELOG.md b/embassy-usb-logger/CHANGELOG.md
index 4ea0e8871..3ba140b1f 100644
--- a/embassy-usb-logger/CHANGELOG.md
+++ b/embassy-usb-logger/CHANGELOG.md
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- Fixed panic in `UsbLogger` when usb is disconnected
12
11## 0.5.1 - 2025-08-26 13## 0.5.1 - 2025-08-26
12 14
13## 0.5.0 - 2025-07-22 15## 0.5.0 - 2025-07-22
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs
index de25abce1..7c3c5e709 100644
--- a/embassy-usb-logger/src/lib.rs
+++ b/embassy-usb-logger/src/lib.rs
@@ -8,7 +8,7 @@ use core::future::Future;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9use embassy_sync::pipe::Pipe; 9use embassy_sync::pipe::Pipe;
10use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State};
11use embassy_usb::driver::Driver; 11use embassy_usb::driver::{Driver, EndpointError};
12use embassy_usb::{Builder, Config}; 12use embassy_usb::{Builder, Config};
13use log::{Metadata, Record}; 13use log::{Metadata, Record};
14 14
@@ -133,17 +133,25 @@ impl<const N: usize, T: ReceiverHandler + Send + Sync> UsbLogger<N, T> {
133 sender.wait_connection().await; 133 sender.wait_connection().await;
134 loop { 134 loop {
135 let len = self.buffer.read(&mut rx[..]).await; 135 let len = self.buffer.read(&mut rx[..]).await;
136 let _ = sender.write_packet(&rx[..len]).await; 136 if Err(EndpointError::Disabled) == sender.write_packet(&rx[..len]).await
137 if len as u8 == MAX_PACKET_SIZE { 137 || len as u8 == MAX_PACKET_SIZE && Err(EndpointError::Disabled) == sender.write_packet(&[]).await
138 let _ = sender.write_packet(&[]).await; 138 {
139 } 139 sender.wait_connection().await;
140 };
140 } 141 }
141 }; 142 };
142 let reciever_fut = async { 143 let reciever_fut = async {
143 let mut reciever_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; 144 let mut reciever_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize];
144 receiver.wait_connection().await; 145 receiver.wait_connection().await;
145 loop { 146 loop {
146 let n = receiver.read_packet(&mut reciever_buf).await.unwrap(); 147 let n = match receiver.read_packet(&mut reciever_buf).await {
148 Err(EndpointError::Disabled) => {
149 receiver.wait_connection().await;
150 continue;
151 }
152 Err(_) => continue,
153 Ok(n) => n,
154 };
147 match &self.recieve_handler { 155 match &self.recieve_handler {
148 Some(handler) => { 156 Some(handler) => {
149 let data = &reciever_buf[..n]; 157 let data = &reciever_buf[..n];
diff --git a/examples/stm32c0/src/bin/rtc.rs b/examples/stm32c0/src/bin/rtc.rs
index feb27f6d9..5ff705ca2 100644
--- a/examples/stm32c0/src/bin/rtc.rs
+++ b/examples/stm32c0/src/bin/rtc.rs
@@ -21,12 +21,12 @@ async fn main(_spawner: Spawner) {
21 .and_hms_opt(10, 30, 15) 21 .and_hms_opt(10, 30, 15)
22 .unwrap(); 22 .unwrap();
23 23
24 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 24 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
25 25
26 rtc.set_datetime(now.into()).expect("datetime not set"); 26 rtc.set_datetime(now.into()).expect("datetime not set");
27 27
28 loop { 28 loop {
29 let now: NaiveDateTime = rtc.now().unwrap().into(); 29 let now: NaiveDateTime = time_provider.now().unwrap().into();
30 30
31 info!("{}", now.and_utc().timestamp()); 31 info!("{}", now.and_utc().timestamp());
32 32
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs
index cccf20949..0adcda614 100644
--- a/examples/stm32f4/src/bin/eth_w5500.rs
+++ b/examples/stm32f4/src/bin/eth_w5500.rs
@@ -12,6 +12,7 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_stm32::mode::Async; 12use embassy_stm32::mode::Async;
13use embassy_stm32::rng::Rng; 13use embassy_stm32::rng::Rng;
14use embassy_stm32::spi::Spi; 14use embassy_stm32::spi::Spi;
15use embassy_stm32::spi::mode::Master;
15use embassy_stm32::time::Hertz; 16use embassy_stm32::time::Hertz;
16use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi}; 17use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi};
17use embassy_time::{Delay, Timer}; 18use embassy_time::{Delay, Timer};
@@ -24,7 +25,7 @@ bind_interrupts!(struct Irqs {
24 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 25 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
25}); 26});
26 27
27type EthernetSPI = ExclusiveDevice<Spi<'static, Async>, Output<'static>, Delay>; 28type EthernetSPI = ExclusiveDevice<Spi<'static, Async, Master>, Output<'static>, Delay>;
28#[embassy_executor::task] 29#[embassy_executor::task]
29async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! { 30async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! {
30 runner.run().await 31 runner.run().await
diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs
index feb27f6d9..5ff705ca2 100644
--- a/examples/stm32f4/src/bin/rtc.rs
+++ b/examples/stm32f4/src/bin/rtc.rs
@@ -21,12 +21,12 @@ async fn main(_spawner: Spawner) {
21 .and_hms_opt(10, 30, 15) 21 .and_hms_opt(10, 30, 15)
22 .unwrap(); 22 .unwrap();
23 23
24 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 24 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
25 25
26 rtc.set_datetime(now.into()).expect("datetime not set"); 26 rtc.set_datetime(now.into()).expect("datetime not set");
27 27
28 loop { 28 loop {
29 let now: NaiveDateTime = rtc.now().unwrap().into(); 29 let now: NaiveDateTime = time_provider.now().unwrap().into();
30 30
31 info!("{}", now.and_utc().timestamp()); 31 info!("{}", now.and_utc().timestamp());
32 32
diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs
index 21da204cc..d8b58de22 100644
--- a/examples/stm32g0/src/bin/rtc.rs
+++ b/examples/stm32g0/src/bin/rtc.rs
@@ -17,12 +17,12 @@ async fn main(_spawner: Spawner) {
17 17
18 let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10, 0); 18 let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10, 0);
19 19
20 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 20 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
21 21
22 rtc.set_datetime(now.unwrap()).expect("datetime not set"); 22 rtc.set_datetime(now.unwrap()).expect("datetime not set");
23 23
24 loop { 24 loop {
25 let now: DateTime = rtc.now().unwrap().into(); 25 let now: DateTime = time_provider.now().unwrap().into();
26 26
27 info!("{}:{}:{}", now.hour(), now.minute(), now.second()); 27 info!("{}:{}:{}", now.hour(), now.minute(), now.second());
28 28
diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs
index 2026d8f99..caebc9daf 100644
--- a/examples/stm32h5/src/bin/stop.rs
+++ b/examples/stm32h5/src/bin/stop.rs
@@ -9,7 +9,6 @@ use embassy_executor::Spawner;
9use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; 9use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
10use embassy_stm32::low_power::Executor; 10use embassy_stm32::low_power::Executor;
11use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; 11use embassy_stm32::rcc::{HSIPrescaler, LsConfig};
12use embassy_stm32::rtc::{Rtc, RtcConfig};
13use embassy_stm32::{Config, Peri}; 12use embassy_stm32::{Config, Peri};
14use embassy_time::Timer; 13use embassy_time::Timer;
15use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
@@ -36,10 +35,6 @@ async fn async_main(spawner: Spawner) {
36 // config.enable_debug_during_sleep = false; 35 // config.enable_debug_during_sleep = false;
37 let p = embassy_stm32::init(config); 36 let p = embassy_stm32::init(config);
38 37
39 // give the RTC to the executor...
40 let rtc = Rtc::new(p.RTC, RtcConfig::default());
41 embassy_stm32::low_power::stop_with_rtc(rtc);
42
43 spawner.spawn(unwrap!(blinky(p.PB4.into()))); 38 spawner.spawn(unwrap!(blinky(p.PB4.into())));
44 spawner.spawn(unwrap!(timeout())); 39 spawner.spawn(unwrap!(timeout()));
45} 40}
diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs
index 1bd71637b..965716d23 100644
--- a/examples/stm32h7/src/bin/rtc.rs
+++ b/examples/stm32h7/src/bin/rtc.rs
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
23 .and_hms_opt(10, 30, 15) 23 .and_hms_opt(10, 30, 15)
24 .unwrap(); 24 .unwrap();
25 25
26 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 26 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
27 info!("Got RTC! {:?}", now.and_utc().timestamp()); 27 info!("Got RTC! {:?}", now.and_utc().timestamp());
28 28
29 rtc.set_datetime(now.into()).expect("datetime not set"); 29 rtc.set_datetime(now.into()).expect("datetime not set");
@@ -31,6 +31,6 @@ async fn main(_spawner: Spawner) {
31 // In reality the delay would be much longer 31 // In reality the delay would be much longer
32 Timer::after_millis(20000).await; 32 Timer::after_millis(20000).await;
33 33
34 let then: NaiveDateTime = rtc.now().unwrap().into(); 34 let then: NaiveDateTime = time_provider.now().unwrap().into();
35 info!("Got RTC! {:?}", then.and_utc().timestamp()); 35 info!("Got RTC! {:?}", then.and_utc().timestamp());
36} 36}
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index 61f31be24..f7ab20cdd 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -15,7 +15,7 @@ use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, Blocking>) { 18async fn main_task(mut spi: spi::Spi<'static, Blocking, spi::mode::Master>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
index be6a26d82..cd9d6c789 100644
--- a/examples/stm32h7/src/bin/spi_bdma.rs
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -20,7 +20,7 @@ use {defmt_rtt as _, panic_probe as _};
20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit(); 20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit();
21 21
22#[embassy_executor::task] 22#[embassy_executor::task]
23async fn main_task(mut spi: spi::Spi<'static, Async>) { 23async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) {
24 let (read_buffer, write_buffer) = unsafe { 24 let (read_buffer, write_buffer) = unsafe {
25 let ram = &mut *core::ptr::addr_of_mut!(RAM_D3); 25 let ram = &mut *core::ptr::addr_of_mut!(RAM_D3);
26 ram.initialize_all_copied(0); 26 ram.initialize_all_copied(0);
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 20cb67ba0..3d3c2f43e 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -15,7 +15,7 @@ use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, Async>) { 18async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 let mut read = [0; 128]; 21 let mut read = [0; 128];
diff --git a/examples/stm32h7rs/src/bin/rtc.rs b/examples/stm32h7rs/src/bin/rtc.rs
index 1bd71637b..965716d23 100644
--- a/examples/stm32h7rs/src/bin/rtc.rs
+++ b/examples/stm32h7rs/src/bin/rtc.rs
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
23 .and_hms_opt(10, 30, 15) 23 .and_hms_opt(10, 30, 15)
24 .unwrap(); 24 .unwrap();
25 25
26 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 26 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
27 info!("Got RTC! {:?}", now.and_utc().timestamp()); 27 info!("Got RTC! {:?}", now.and_utc().timestamp());
28 28
29 rtc.set_datetime(now.into()).expect("datetime not set"); 29 rtc.set_datetime(now.into()).expect("datetime not set");
@@ -31,6 +31,6 @@ async fn main(_spawner: Spawner) {
31 // In reality the delay would be much longer 31 // In reality the delay would be much longer
32 Timer::after_millis(20000).await; 32 Timer::after_millis(20000).await;
33 33
34 let then: NaiveDateTime = rtc.now().unwrap().into(); 34 let then: NaiveDateTime = time_provider.now().unwrap().into();
35 info!("Got RTC! {:?}", then.and_utc().timestamp()); 35 info!("Got RTC! {:?}", then.and_utc().timestamp());
36} 36}
diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs
index 8c280fdae..3253304eb 100644
--- a/examples/stm32h7rs/src/bin/spi.rs
+++ b/examples/stm32h7rs/src/bin/spi.rs
@@ -15,7 +15,7 @@ use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, Blocking>) { 18async fn main_task(mut spi: spi::Spi<'static, Blocking, spi::mode::Master>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs
index 3fa69fd15..ca644c6a8 100644
--- a/examples/stm32h7rs/src/bin/spi_dma.rs
+++ b/examples/stm32h7rs/src/bin/spi_dma.rs
@@ -15,7 +15,7 @@ use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, Async>) { 18async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 let mut read = [0; 128]; 21 let mut read = [0; 128];
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
index 1d26cd008..8b92075cc 100644
--- a/examples/stm32l4/src/bin/rtc.rs
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) {
39 .and_hms_opt(10, 30, 15) 39 .and_hms_opt(10, 30, 15)
40 .unwrap(); 40 .unwrap();
41 41
42 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 42 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
43 info!("Got RTC! {:?}", now.and_utc().timestamp()); 43 info!("Got RTC! {:?}", now.and_utc().timestamp());
44 44
45 rtc.set_datetime(now.into()).expect("datetime not set"); 45 rtc.set_datetime(now.into()).expect("datetime not set");
@@ -47,6 +47,6 @@ async fn main(_spawner: Spawner) {
47 // In reality the delay would be much longer 47 // In reality the delay would be much longer
48 Timer::after_millis(20000).await; 48 Timer::after_millis(20000).await;
49 49
50 let then: NaiveDateTime = rtc.now().unwrap().into(); 50 let then: NaiveDateTime = time_provider.now().unwrap().into();
51 info!("Got RTC! {:?}", then.and_utc().timestamp()); 51 info!("Got RTC! {:?}", then.and_utc().timestamp());
52} 52}
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 8e54938d1..0dbf515cf 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -28,6 +28,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
28use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; 28use embassy_stm32::i2c::{self, Config as I2C_Config, I2c};
29use embassy_stm32::mode::Async; 29use embassy_stm32::mode::Async;
30use embassy_stm32::rng::{self, Rng}; 30use embassy_stm32::rng::{self, Rng};
31use embassy_stm32::spi::mode::Master;
31use embassy_stm32::spi::{Config as SPI_Config, Spi}; 32use embassy_stm32::spi::{Config as SPI_Config, Spi};
32use embassy_stm32::time::Hertz; 33use embassy_stm32::time::Hertz;
33use embassy_stm32::{bind_interrupts, exti, pac, peripherals}; 34use embassy_stm32::{bind_interrupts, exti, pac, peripherals};
@@ -54,7 +55,7 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 5), 24)
54// Listen port for the webserver 55// Listen port for the webserver
55const HTTP_LISTEN_PORT: u16 = 80; 56const HTTP_LISTEN_PORT: u16 = 80;
56 57
57pub type SpeSpi = Spi<'static, Async>; 58pub type SpeSpi = Spi<'static, Async, Master>;
58pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; 59pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
59pub type SpeInt = exti::ExtiInput<'static>; 60pub type SpeInt = exti::ExtiInput<'static>;
60pub type SpeRst = Output<'static>; 61pub type SpeRst = Output<'static>;
diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs
index 7662dbfa8..3d119f90f 100644
--- a/examples/stm32l5/src/bin/stop.rs
+++ b/examples/stm32l5/src/bin/stop.rs
@@ -6,7 +6,6 @@ use embassy_executor::Spawner;
6use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; 6use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
7use embassy_stm32::low_power::Executor; 7use embassy_stm32::low_power::Executor;
8use embassy_stm32::rcc::LsConfig; 8use embassy_stm32::rcc::LsConfig;
9use embassy_stm32::rtc::{Rtc, RtcConfig};
10use embassy_stm32::{Config, Peri}; 9use embassy_stm32::{Config, Peri};
11use embassy_time::Timer; 10use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -27,10 +26,6 @@ async fn async_main(spawner: Spawner) {
27 // config.enable_debug_during_sleep = false; 26 // config.enable_debug_during_sleep = false;
28 let p = embassy_stm32::init(config); 27 let p = embassy_stm32::init(config);
29 28
30 // give the RTC to the executor...
31 let rtc = Rtc::new(p.RTC, RtcConfig::default());
32 embassy_stm32::low_power::stop_with_rtc(rtc);
33
34 spawner.spawn(unwrap!(blinky(p.PC7.into()))); 29 spawner.spawn(unwrap!(blinky(p.PC7.into())));
35 spawner.spawn(unwrap!(timeout())); 30 spawner.spawn(unwrap!(timeout()));
36} 31}
diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs
index d071cfbc7..56d16ccf7 100644
--- a/examples/stm32u0/src/bin/rtc.rs
+++ b/examples/stm32u0/src/bin/rtc.rs
@@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) {
36 .and_hms_opt(10, 30, 15) 36 .and_hms_opt(10, 30, 15)
37 .unwrap(); 37 .unwrap();
38 38
39 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 39 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
40 info!("Got RTC! {:?}", now.and_utc().timestamp()); 40 info!("Got RTC! {:?}", now.and_utc().timestamp());
41 41
42 rtc.set_datetime(now.into()).expect("datetime not set"); 42 rtc.set_datetime(now.into()).expect("datetime not set");
@@ -44,6 +44,6 @@ async fn main(_spawner: Spawner) {
44 // In reality the delay would be much longer 44 // In reality the delay would be much longer
45 Timer::after_millis(20000).await; 45 Timer::after_millis(20000).await;
46 46
47 let then: NaiveDateTime = rtc.now().unwrap().into(); 47 let then: NaiveDateTime = time_provider.now().unwrap().into();
48 info!("Got RTC! {:?}", then.and_utc().timestamp()); 48 info!("Got RTC! {:?}", then.and_utc().timestamp());
49} 49}
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
index d3709120f..2185142c9 100644
--- a/examples/stm32wl/src/bin/rtc.rs
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
44 .and_hms_opt(10, 30, 15) 44 .and_hms_opt(10, 30, 15)
45 .unwrap(); 45 .unwrap();
46 46
47 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 47 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
48 info!("Got RTC! {:?}", now.and_utc().timestamp()); 48 info!("Got RTC! {:?}", now.and_utc().timestamp());
49 49
50 rtc.set_datetime(now.into()).expect("datetime not set"); 50 rtc.set_datetime(now.into()).expect("datetime not set");
@@ -52,6 +52,6 @@ async fn main(_spawner: Spawner) {
52 // In reality the delay would be much longer 52 // In reality the delay would be much longer
53 Timer::after_millis(20000).await; 53 Timer::after_millis(20000).await;
54 54
55 let then: NaiveDateTime = rtc.now().unwrap().into(); 55 let then: NaiveDateTime = time_provider.now().unwrap().into();
56 info!("Got RTC! {:?}", then.and_utc().timestamp()); 56 info!("Got RTC! {:?}", then.and_utc().timestamp());
57} 57}
diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs
index ff1a5fa16..8b830a1e6 100644
--- a/examples/stm32wle5/src/bin/adc.rs
+++ b/examples/stm32wle5/src/bin/adc.rs
@@ -7,7 +7,6 @@ use defmt_rtt as _;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::adc::{Adc, SampleTime}; 8use embassy_stm32::adc::{Adc, SampleTime};
9use embassy_stm32::low_power::Executor; 9use embassy_stm32::low_power::Executor;
10use embassy_stm32::rtc::{Rtc, RtcConfig};
11use embassy_time::Timer; 10use embassy_time::Timer;
12use panic_probe as _; 11use panic_probe as _;
13use static_cell::StaticCell; 12use static_cell::StaticCell;
@@ -71,11 +70,6 @@ async fn async_main(_spawner: Spawner) {
71 defmt_serial::defmt_serial(SERIAL.init(uart)); 70 defmt_serial::defmt_serial(SERIAL.init(uart));
72 } 71 }
73 72
74 // give the RTC to the low_power executor...
75 let rtc_config = RtcConfig::default();
76 let rtc = Rtc::new(p.RTC, rtc_config);
77 embassy_stm32::low_power::stop_with_rtc(rtc);
78
79 info!("Hello World!"); 73 info!("Hello World!");
80 74
81 let mut adc = Adc::new(p.ADC1); 75 let mut adc = Adc::new(p.ADC1);
diff --git a/examples/stm32wle5/src/bin/blinky.rs b/examples/stm32wle5/src/bin/blinky.rs
index 1191a1157..b2745fdaf 100644
--- a/examples/stm32wle5/src/bin/blinky.rs
+++ b/examples/stm32wle5/src/bin/blinky.rs
@@ -7,7 +7,6 @@ use defmt_rtt as _;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::gpio::{Level, Output, Speed}; 8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::low_power::Executor; 9use embassy_stm32::low_power::Executor;
10use embassy_stm32::rtc::{Rtc, RtcConfig};
11use embassy_time::Timer; 10use embassy_time::Timer;
12use panic_probe as _; 11use panic_probe as _;
13use static_cell::StaticCell; 12use static_cell::StaticCell;
@@ -69,11 +68,6 @@ async fn async_main(_spawner: Spawner) {
69 defmt_serial::defmt_serial(SERIAL.init(uart)); 68 defmt_serial::defmt_serial(SERIAL.init(uart));
70 } 69 }
71 70
72 // give the RTC to the low_power executor...
73 let rtc_config = RtcConfig::default();
74 let rtc = Rtc::new(p.RTC, rtc_config);
75 embassy_stm32::low_power::stop_with_rtc(rtc);
76
77 info!("Hello World!"); 71 info!("Hello World!");
78 72
79 let mut led = Output::new(p.PB5, Level::High, Speed::Low); 73 let mut led = Output::new(p.PB5, Level::High, Speed::Low);
diff --git a/examples/stm32wle5/src/bin/button_exti.rs b/examples/stm32wle5/src/bin/button_exti.rs
index f07f9724d..db1bff0be 100644
--- a/examples/stm32wle5/src/bin/button_exti.rs
+++ b/examples/stm32wle5/src/bin/button_exti.rs
@@ -8,7 +8,6 @@ use embassy_executor::Spawner;
8use embassy_stm32::exti::ExtiInput; 8use embassy_stm32::exti::ExtiInput;
9use embassy_stm32::gpio::Pull; 9use embassy_stm32::gpio::Pull;
10use embassy_stm32::low_power::Executor; 10use embassy_stm32::low_power::Executor;
11use embassy_stm32::rtc::{Rtc, RtcConfig};
12use panic_probe as _; 11use panic_probe as _;
13use static_cell::StaticCell; 12use static_cell::StaticCell;
14 13
@@ -71,11 +70,6 @@ async fn async_main(_spawner: Spawner) {
71 defmt_serial::defmt_serial(SERIAL.init(uart)); 70 defmt_serial::defmt_serial(SERIAL.init(uart));
72 } 71 }
73 72
74 // give the RTC to the low_power executor...
75 let rtc_config = RtcConfig::default();
76 let rtc = Rtc::new(p.RTC, rtc_config);
77 embassy_stm32::low_power::stop_with_rtc(rtc);
78
79 info!("Hello World!"); 73 info!("Hello World!");
80 74
81 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); 75 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up);
diff --git a/examples/stm32wle5/src/bin/i2c.rs b/examples/stm32wle5/src/bin/i2c.rs
index af07f911e..c31c673c9 100644
--- a/examples/stm32wle5/src/bin/i2c.rs
+++ b/examples/stm32wle5/src/bin/i2c.rs
@@ -7,7 +7,6 @@ use defmt_rtt as _;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::i2c::I2c; 8use embassy_stm32::i2c::I2c;
9use embassy_stm32::low_power::Executor; 9use embassy_stm32::low_power::Executor;
10use embassy_stm32::rtc::{Rtc, RtcConfig};
11use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
12use embassy_stm32::{bind_interrupts, i2c, peripherals}; 11use embassy_stm32::{bind_interrupts, i2c, peripherals};
13use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
@@ -78,11 +77,6 @@ async fn async_main(_spawner: Spawner) {
78 defmt_serial::defmt_serial(SERIAL.init(uart)); 77 defmt_serial::defmt_serial(SERIAL.init(uart));
79 } 78 }
80 79
81 // give the RTC to the low_power executor...
82 let rtc_config = RtcConfig::default();
83 let rtc = Rtc::new(p.RTC, rtc_config);
84 embassy_stm32::low_power::stop_with_rtc(rtc);
85
86 info!("Hello World!"); 80 info!("Hello World!");
87 let en3v3 = embassy_stm32::gpio::Output::new( 81 let en3v3 = embassy_stm32::gpio::Output::new(
88 p.PA9, 82 p.PA9,
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 1161e827b..b92b47be2 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -73,7 +73,7 @@ teleprobe-meta = "1"
73embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 73embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
74embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 74embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
75embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } 75embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] }
76embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } 76embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any", "_allow-disable-rtc"] }
77embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } 77embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
78embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } 78embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] }
79embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } 79embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
@@ -94,6 +94,7 @@ rand_core = { version = "0.9.1", default-features = false }
94rand_chacha = { version = "0.9.0", default-features = false } 94rand_chacha = { version = "0.9.0", default-features = false }
95static_cell = "2" 95static_cell = "2"
96portable-atomic = { version = "1.5", features = [] } 96portable-atomic = { version = "1.5", features = [] }
97critical-section = "1.1"
97 98
98chrono = { version = "^0.4", default-features = false, optional = true} 99chrono = { version = "^0.4", default-features = false, optional = true}
99sha2 = { version = "0.10.8", default-features = false } 100sha2 = { version = "0.10.8", default-features = false }
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
index 5fe98d807..eb27af4ca 100644
--- a/tests/stm32/src/bin/rtc.rs
+++ b/tests/stm32/src/bin/rtc.rs
@@ -10,13 +10,19 @@ use common::*;
10use defmt::assert; 10use defmt::assert;
11use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_stm32::rcc::LsConfig; 12use embassy_stm32::rcc::LsConfig;
13#[cfg(feature = "stop")]
14use embassy_stm32::rtc::Rtc;
15#[cfg(not(feature = "stop"))]
13use embassy_stm32::rtc::{Rtc, RtcConfig}; 16use embassy_stm32::rtc::{Rtc, RtcConfig};
14use embassy_time::Timer; 17use embassy_time::Timer;
15
16#[embassy_executor::main] 18#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
18 let mut config = config(); 20 let mut config = config();
19 config.rcc.ls = LsConfig::default_lse(); 21 config.rcc.ls = LsConfig::default_lse();
22 #[cfg(feature = "stop")]
23 {
24 config.rtc._disable_rtc = false;
25 }
20 26
21 let p = init_with_config(config); 27 let p = init_with_config(config);
22 info!("Hello World!"); 28 info!("Hello World!");
@@ -26,14 +32,25 @@ async fn main(_spawner: Spawner) {
26 .and_hms_opt(10, 30, 15) 32 .and_hms_opt(10, 30, 15)
27 .unwrap(); 33 .unwrap();
28 34
29 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 35 #[cfg(not(feature = "stop"))]
36 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
37
38 #[cfg(feature = "stop")]
39 let (rtc, time_provider) = Rtc::new(p.RTC);
30 40
41 #[cfg(not(feature = "stop"))]
31 rtc.set_datetime(now.into()).expect("datetime not set"); 42 rtc.set_datetime(now.into()).expect("datetime not set");
32 43
44 #[cfg(feature = "stop")]
45 critical_section::with(|cs| {
46 rtc.borrow_mut(cs).set_datetime(now.into()).expect("datetime not set");
47 });
48
33 info!("Waiting 5 seconds"); 49 info!("Waiting 5 seconds");
34 Timer::after_millis(5000).await; 50 Timer::after_millis(5000).await;
35 51
36 let then: NaiveDateTime = rtc.now().unwrap().into(); 52 let then: NaiveDateTime = time_provider.now().unwrap().into();
53
37 let seconds = (then - now).num_seconds(); 54 let seconds = (then - now).num_seconds();
38 55
39 info!("measured = {}", seconds); 56 info!("measured = {}", seconds);
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index e8310866a..cedff772c 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -8,6 +8,7 @@ use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::mode::Blocking; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::spi::mode::Master;
11use embassy_stm32::spi::{self, Spi, Word}; 12use embassy_stm32::spi::{self, Spi, Word};
12use embassy_stm32::time::Hertz; 13use embassy_stm32::time::Hertz;
13 14
@@ -65,7 +66,7 @@ async fn main(_spawner: Spawner) {
65 cortex_m::asm::bkpt(); 66 cortex_m::asm::bkpt();
66} 67}
67 68
68fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>) 69fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>)
69where 70where
70 W: core::ops::Not<Output = W>, 71 W: core::ops::Not<Output = W>,
71{ 72{
@@ -109,7 +110,7 @@ where
109 spi.blocking_write::<u8>(&[]).unwrap(); 110 spi.blocking_write::<u8>(&[]).unwrap();
110} 111}
111 112
112fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>, mosi_out: &mut Output<'_>) 113fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>, mosi_out: &mut Output<'_>)
113where 114where
114 W: core::ops::Not<Output = W>, 115 W: core::ops::Not<Output = W>,
115{ 116{
@@ -125,7 +126,7 @@ where
125 spi.blocking_read::<u8>(&mut []).unwrap(); 126 spi.blocking_read::<u8>(&mut []).unwrap();
126} 127}
127 128
128fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>) 129fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>)
129where 130where
130 W: core::ops::Not<Output = W>, 131 W: core::ops::Not<Output = W>,
131{ 132{
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index b4fdb8faa..c8cd92401 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -8,6 +8,7 @@ use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::mode::Async; 10use embassy_stm32::mode::Async;
11use embassy_stm32::spi::mode::Master;
11use embassy_stm32::spi::{self, Spi, Word}; 12use embassy_stm32::spi::{self, Spi, Word};
12use embassy_stm32::time::Hertz; 13use embassy_stm32::time::Hertz;
13 14
@@ -78,7 +79,7 @@ async fn main(_spawner: Spawner) {
78 cortex_m::asm::bkpt(); 79 cortex_m::asm::bkpt();
79} 80}
80 81
81async fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>) 82async fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>)
82where 83where
83 W: core::ops::Not<Output = W>, 84 W: core::ops::Not<Output = W>,
84{ 85{
@@ -142,7 +143,7 @@ where
142 spi.write(&buf).await.unwrap(); 143 spi.write(&buf).await.unwrap();
143} 144}
144 145
145async fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>, mosi_out: &mut Output<'_>) 146async fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>, mosi_out: &mut Output<'_>)
146where 147where
147 W: core::ops::Not<Output = W>, 148 W: core::ops::Not<Output = W>,
148{ 149{
@@ -168,7 +169,7 @@ where
168 spi.blocking_read::<u8>(&mut []).unwrap(); 169 spi.blocking_read::<u8>(&mut []).unwrap();
169} 170}
170 171
171async fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>) 172async fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>)
172where 173where
173 W: core::ops::Not<Output = W>, 174 W: core::ops::Not<Output = W>,
174{ 175{
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs
index 73580f0f2..1fe65d867 100644
--- a/tests/stm32/src/bin/stop.rs
+++ b/tests/stm32/src/bin/stop.rs
@@ -10,9 +10,9 @@ use common::*;
10use cortex_m_rt::entry; 10use cortex_m_rt::entry;
11use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_stm32::Config; 12use embassy_stm32::Config;
13use embassy_stm32::low_power::{Executor, StopMode, stop_ready, stop_with_rtc}; 13use embassy_stm32::low_power::{Executor, StopMode, stop_ready};
14use embassy_stm32::rcc::LsConfig; 14use embassy_stm32::rcc::LsConfig;
15use embassy_stm32::rtc::{Rtc, RtcConfig}; 15use embassy_stm32::rtc::Rtc;
16use embassy_time::Timer; 16use embassy_time::Timer;
17 17
18#[entry] 18#[entry]
@@ -49,6 +49,7 @@ async fn async_main(spawner: Spawner) {
49 49
50 let mut config = Config::default(); 50 let mut config = Config::default();
51 config.rcc.ls = LsConfig::default_lse(); 51 config.rcc.ls = LsConfig::default_lse();
52 config.rtc._disable_rtc = false;
52 53
53 // System Clock seems cannot be greater than 16 MHz 54 // System Clock seems cannot be greater than 16 MHz
54 #[cfg(any(feature = "stm32h563zi", feature = "stm32h503rb"))] 55 #[cfg(any(feature = "stm32h563zi", feature = "stm32h503rb"))]
@@ -65,11 +66,11 @@ async fn async_main(spawner: Spawner) {
65 .and_hms_opt(10, 30, 15) 66 .and_hms_opt(10, 30, 15)
66 .unwrap(); 67 .unwrap();
67 68
68 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 69 let (rtc, _time_provider) = Rtc::new(p.RTC);
69 70
70 rtc.set_datetime(now.into()).expect("datetime not set"); 71 critical_section::with(|cs| {
71 72 rtc.borrow_mut(cs).set_datetime(now.into()).expect("datetime not set");
72 stop_with_rtc(rtc); 73 });
73 74
74 spawner.spawn(task_1().unwrap()); 75 spawner.spawn(task_1().unwrap());
75 spawner.spawn(task_2().unwrap()); 76 spawner.spawn(task_2().unwrap());
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 2bd934d6f..096cce947 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -468,6 +468,8 @@ pub fn config() -> Config {
468 config.rcc.apb3_pre = APBPrescaler::DIV1; 468 config.rcc.apb3_pre = APBPrescaler::DIV1;
469 config.rcc.sys = Sysclk::PLL1_P; 469 config.rcc.sys = Sysclk::PLL1_P;
470 config.rcc.voltage_scale = VoltageScale::Scale0; 470 config.rcc.voltage_scale = VoltageScale::Scale0;
471
472 config.rtc._disable_rtc = true;
471 } 473 }
472 474
473 #[cfg(feature = "stm32h503rb")] 475 #[cfg(feature = "stm32h503rb")]