diff options
| author | Jakob <[email protected]> | 2025-11-07 15:56:09 +0100 |
|---|---|---|
| committer | Jakob <[email protected]> | 2025-11-07 15:56:09 +0100 |
| commit | b5ec182235195eb55317d4fa6054e750c0d5e8b0 (patch) | |
| tree | ecc0dac5f71155efa54e6e1c98fb79c7931dc032 | |
| parent | 85a07311544eee72b6aef8cbae161fa18b62f18e (diff) | |
| parent | 1fd44118a7ba5329b256e3d45c04f606722eb3e9 (diff) | |
Merge branch 'into_ring_buffered_adc_for_g4' of https://github.com/WattStep/embassy into into_ring_buffered_adc_for_g4
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 | ||
| 77 | struct BitIter(u32); | 77 | struct 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; | |||
| 10 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; | 10 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; |
| 11 | use crate::rcc; | 11 | use crate::rcc; |
| 12 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | pub use crate::timer::simple_pwm::PwmPinConfig; | ||
| 13 | 14 | ||
| 14 | /// HRTIM burst controller instance. | 15 | /// HRTIM burst controller instance. |
| 15 | pub struct BurstController<T: Instance> { | 16 | pub struct BurstController<T: Instance> { |
| @@ -73,7 +74,7 @@ pub struct ComplementaryPwmPin<'d, T, C> { | |||
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | macro_rules! advanced_channel_impl { | 76 | macro_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 | ||
| 114 | advanced_channel_impl!(new_cha, ChA, 0, ChannelAPin, ChannelAComplementaryPin); | 145 | advanced_channel_impl!( |
| 115 | advanced_channel_impl!(new_chb, ChB, 1, ChannelBPin, ChannelBComplementaryPin); | 146 | new_cha, |
| 116 | advanced_channel_impl!(new_chc, ChC, 2, ChannelCPin, ChannelCComplementaryPin); | 147 | new_cha_with_config, |
| 117 | advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); | 148 | ChA, |
| 118 | advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); | 149 | 0, |
| 150 | ChannelAPin, | ||
| 151 | ChannelAComplementaryPin | ||
| 152 | ); | ||
| 153 | advanced_channel_impl!( | ||
| 154 | new_chb, | ||
| 155 | new_chb_with_config, | ||
| 156 | ChB, | ||
| 157 | 1, | ||
| 158 | ChannelBPin, | ||
| 159 | ChannelBComplementaryPin | ||
| 160 | ); | ||
| 161 | advanced_channel_impl!( | ||
| 162 | new_chc, | ||
| 163 | new_chc_with_config, | ||
| 164 | ChC, | ||
| 165 | 2, | ||
| 166 | ChannelCPin, | ||
| 167 | ChannelCComplementaryPin | ||
| 168 | ); | ||
| 169 | advanced_channel_impl!( | ||
| 170 | new_chd, | ||
| 171 | new_chd_with_config, | ||
| 172 | ChD, | ||
| 173 | 3, | ||
| 174 | ChannelDPin, | ||
| 175 | ChannelDComplementaryPin | ||
| 176 | ); | ||
| 177 | advanced_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)] |
| 120 | advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); | 186 | advanced_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 |
| 123 | pub struct AdvancedPwm<'d, T: Instance> { | 196 | pub 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; | |||
| 7 | use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer}; | 7 | use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer}; |
| 8 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; | 8 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; |
| 9 | use crate::mode::Async; | 9 | use crate::mode::Async; |
| 10 | use crate::spi::mode::Master; | ||
| 10 | use crate::spi::{Config as SpiConfig, RegsExt as _, *}; | 11 | use crate::spi::{Config as SpiConfig, RegsExt as _, *}; |
| 11 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 12 | 13 | ||
| @@ -225,7 +226,7 @@ impl<'s, 'd, W: Word> Reader<'s, 'd, W> { | |||
| 225 | pub struct I2S<'d, W: Word> { | 226 | pub 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; | |||
| 57 | use core::sync::atomic::{Ordering, compiler_fence}; | 53 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 58 | 54 | ||
| 59 | use cortex_m::peripheral::SCB; | 55 | use cortex_m::peripheral::SCB; |
| 56 | use critical_section::CriticalSection; | ||
| 60 | use embassy_executor::*; | 57 | use embassy_executor::*; |
| 61 | 58 | ||
| 62 | use crate::interrupt; | 59 | use crate::interrupt; |
| 63 | use crate::time_driver::{RtcDriver, get_driver}; | 60 | use crate::time_driver::get_driver; |
| 64 | 61 | ||
| 65 | const THREAD_PENDER: usize = usize::MAX; | 62 | const THREAD_PENDER: usize = usize::MAX; |
| 66 | 63 | ||
| 67 | use crate::rtc::Rtc; | ||
| 68 | |||
| 69 | static mut EXECUTOR: Option<Executor> = None; | 64 | static mut EXECUTOR: Option<Executor> = None; |
| 70 | 65 | ||
| 71 | #[cfg(stm32wlex)] | 66 | /// Prevent the device from going into the stop mode if held |
| 72 | pub(crate) use self::busy::DeviceBusy; | 67 | pub struct DeviceBusy(StopMode); |
| 73 | #[cfg(stm32wlex)] | ||
| 74 | mod busy { | ||
| 75 | use core::sync::atomic::{AtomicU32, Ordering}; | ||
| 76 | 68 | ||
| 77 | // Count of devices blocking STOP | 69 | impl 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 { | 97 | impl 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))] |
| 105 | foreach_interrupt! { | 113 | foreach_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)] | ||
| 127 | pub(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. | ||
| 135 | pub fn stop_with_rtc(rtc: Rtc) { | ||
| 136 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Reconfigure the RTC, if set. | ||
| 140 | pub 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. |
| 148 | pub fn stop_ready(stop_mode: StopMode) -> bool { | 138 | pub 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 | ||
| 199 | impl Executor { | 188 | impl 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}; | |||
| 4 | use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; | 4 | use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; |
| 5 | use crate::interrupt::typelevel::Interrupt; | 5 | use crate::interrupt::typelevel::Interrupt; |
| 6 | use crate::peripherals::RTC; | 6 | use crate::peripherals::RTC; |
| 7 | use crate::rtc::SealedInstance; | 7 | use 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 |
| 10 | pub(super) struct RtcInstant { | 10 | pub(super) struct RtcInstant { |
| @@ -117,7 +117,7 @@ impl WakeupPrescaler { | |||
| 117 | impl Rtc { | 117 | impl 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; | |||
| 5 | mod low_power; | 5 | mod low_power; |
| 6 | 6 | ||
| 7 | #[cfg(feature = "low-power")] | 7 | #[cfg(feature = "low-power")] |
| 8 | use core::cell::Cell; | 8 | use core::cell::{Cell, RefCell, RefMut}; |
| 9 | #[cfg(feature = "low-power")] | ||
| 10 | use core::ops; | ||
| 9 | 11 | ||
| 10 | #[cfg(feature = "low-power")] | 12 | #[cfg(feature = "low-power")] |
| 13 | use critical_section::CriticalSection; | ||
| 14 | #[cfg(feature = "low-power")] | ||
| 11 | use embassy_sync::blocking_mutex::Mutex; | 15 | use embassy_sync::blocking_mutex::Mutex; |
| 12 | #[cfg(feature = "low-power")] | 16 | #[cfg(feature = "low-power")] |
| 13 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 17 | use 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)] | ||
| 47 | pub struct RtcTimeProvider { | 52 | pub struct RtcTimeProvider { |
| 48 | _private: (), | 53 | _private: (), |
| 49 | } | 54 | } |
| 50 | 55 | ||
| 51 | impl RtcTimeProvider { | 56 | impl 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. | ||
| 121 | pub struct RtcContainer { | ||
| 122 | pub(self) mutex: &'static Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>, | ||
| 123 | } | ||
| 124 | |||
| 125 | #[cfg(feature = "low-power")] | ||
| 126 | impl 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. | ||
| 143 | pub struct RtcBorrow<'a> { | ||
| 144 | pub(self) ref_mut: RefMut<'a, Option<Rtc>>, | ||
| 145 | } | ||
| 146 | |||
| 147 | #[cfg(feature = "low-power")] | ||
| 148 | impl<'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")] | ||
| 157 | impl<'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. |
| 110 | pub struct Rtc { | 164 | pub 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 | ||
| 126 | impl Default for RtcConfig { | 184 | impl 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 | ||
| 147 | impl Rtc { | 209 | impl 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")] | ||
| 382 | pub(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 | ||
| 130 | pub 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 | } | ||
| 167 | use mode::{CommunicationMode, Master, Slave}; | ||
| 168 | |||
| 128 | /// SPI driver. | 169 | /// SPI driver. |
| 129 | pub struct Spi<'d, M: PeriMode> { | 170 | pub 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 | ||
| 142 | impl<'d, M: PeriMode> Spi<'d, M> { | 184 | impl<'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 | ||
| 472 | impl<'d> Spi<'d, Blocking> { | 516 | impl<'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 | |||
| 539 | impl<'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 | |||
| 619 | impl<'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 | ||
| 548 | impl<'d> Spi<'d, Async> { | 644 | impl<'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 | ||
| 763 | impl<'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 | ||
| 891 | impl<'d, M: PeriMode> Drop for Spi<'d, M> { | 993 | impl<'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 |
| 1128 | macro_rules! impl_blocking { | 1231 | macro_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 { | |||
| 1149 | impl_blocking!(u8); | 1252 | impl_blocking!(u8); |
| 1150 | impl_blocking!(u16); | 1253 | impl_blocking!(u16); |
| 1151 | 1254 | ||
| 1152 | impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { | 1255 | impl<'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 | ||
| 1156 | impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> { | 1259 | impl<'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 | ||
| 1189 | impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> { | 1292 | impl<'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 | ||
| 1331 | impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { | 1434 | impl<'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")] |
| 546 | pub(crate) fn get_driver() -> &'static RtcDriver { | 542 | pub(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> { | |||
| 399 | impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { | 399 | impl<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; | |||
| 8 | use embassy_futures::join::join; | 8 | use embassy_futures::join::join; |
| 9 | use embassy_sync::pipe::Pipe; | 9 | use embassy_sync::pipe::Pipe; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; |
| 11 | use embassy_usb::driver::Driver; | 11 | use embassy_usb::driver::{Driver, EndpointError}; |
| 12 | use embassy_usb::{Builder, Config}; | 12 | use embassy_usb::{Builder, Config}; |
| 13 | use log::{Metadata, Record}; | 13 | use 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}; | |||
| 12 | use embassy_stm32::mode::Async; | 12 | use embassy_stm32::mode::Async; |
| 13 | use embassy_stm32::rng::Rng; | 13 | use embassy_stm32::rng::Rng; |
| 14 | use embassy_stm32::spi::Spi; | 14 | use embassy_stm32::spi::Spi; |
| 15 | use embassy_stm32::spi::mode::Master; | ||
| 15 | use embassy_stm32::time::Hertz; | 16 | use embassy_stm32::time::Hertz; |
| 16 | use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi}; | 17 | use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi}; |
| 17 | use embassy_time::{Delay, Timer}; | 18 | use 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 | ||
| 27 | type EthernetSPI = ExclusiveDevice<Spi<'static, Async>, Output<'static>, Delay>; | 28 | type EthernetSPI = ExclusiveDevice<Spi<'static, Async, Master>, Output<'static>, Delay>; |
| 28 | #[embassy_executor::task] | 29 | #[embassy_executor::task] |
| 29 | async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! { | 30 | async 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; | |||
| 9 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; | 9 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; |
| 10 | use embassy_stm32::low_power::Executor; | 10 | use embassy_stm32::low_power::Executor; |
| 11 | use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; | 11 | use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; |
| 12 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 13 | use embassy_stm32::{Config, Peri}; | 12 | use embassy_stm32::{Config, Peri}; |
| 14 | use embassy_time::Timer; | 13 | use embassy_time::Timer; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {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; | |||
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
| 17 | #[embassy_executor::task] | 17 | #[embassy_executor::task] |
| 18 | async fn main_task(mut spi: spi::Spi<'static, Blocking>) { | 18 | async 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 _}; | |||
| 20 | static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit(); | 20 | static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit(); |
| 21 | 21 | ||
| 22 | #[embassy_executor::task] | 22 | #[embassy_executor::task] |
| 23 | async fn main_task(mut spi: spi::Spi<'static, Async>) { | 23 | async 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; | |||
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
| 17 | #[embassy_executor::task] | 17 | #[embassy_executor::task] |
| 18 | async fn main_task(mut spi: spi::Spi<'static, Async>) { | 18 | async 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; | |||
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
| 17 | #[embassy_executor::task] | 17 | #[embassy_executor::task] |
| 18 | async fn main_task(mut spi: spi::Spi<'static, Blocking>) { | 18 | async 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; | |||
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
| 17 | #[embassy_executor::task] | 17 | #[embassy_executor::task] |
| 18 | async fn main_task(mut spi: spi::Spi<'static, Async>) { | 18 | async 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}; | |||
| 28 | use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; | 28 | use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; |
| 29 | use embassy_stm32::mode::Async; | 29 | use embassy_stm32::mode::Async; |
| 30 | use embassy_stm32::rng::{self, Rng}; | 30 | use embassy_stm32::rng::{self, Rng}; |
| 31 | use embassy_stm32::spi::mode::Master; | ||
| 31 | use embassy_stm32::spi::{Config as SPI_Config, Spi}; | 32 | use embassy_stm32::spi::{Config as SPI_Config, Spi}; |
| 32 | use embassy_stm32::time::Hertz; | 33 | use embassy_stm32::time::Hertz; |
| 33 | use embassy_stm32::{bind_interrupts, exti, pac, peripherals}; | 34 | use 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 |
| 55 | const HTTP_LISTEN_PORT: u16 = 80; | 56 | const HTTP_LISTEN_PORT: u16 = 80; |
| 56 | 57 | ||
| 57 | pub type SpeSpi = Spi<'static, Async>; | 58 | pub type SpeSpi = Spi<'static, Async, Master>; |
| 58 | pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; | 59 | pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; |
| 59 | pub type SpeInt = exti::ExtiInput<'static>; | 60 | pub type SpeInt = exti::ExtiInput<'static>; |
| 60 | pub type SpeRst = Output<'static>; | 61 | pub 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; | |||
| 6 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; |
| 7 | use embassy_stm32::low_power::Executor; | 7 | use embassy_stm32::low_power::Executor; |
| 8 | use embassy_stm32::rcc::LsConfig; | 8 | use embassy_stm32::rcc::LsConfig; |
| 9 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 10 | use embassy_stm32::{Config, Peri}; | 9 | use embassy_stm32::{Config, Peri}; |
| 11 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {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 _; | |||
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::adc::{Adc, SampleTime}; | 8 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 9 | use embassy_stm32::low_power::Executor; | 9 | use embassy_stm32::low_power::Executor; |
| 10 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 11 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 12 | use panic_probe as _; | 11 | use panic_probe as _; |
| 13 | use static_cell::StaticCell; | 12 | use 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 _; | |||
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::gpio::{Level, Output, Speed}; | 8 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 9 | use embassy_stm32::low_power::Executor; | 9 | use embassy_stm32::low_power::Executor; |
| 10 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 11 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 12 | use panic_probe as _; | 11 | use panic_probe as _; |
| 13 | use static_cell::StaticCell; | 12 | use 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; | |||
| 8 | use embassy_stm32::exti::ExtiInput; | 8 | use embassy_stm32::exti::ExtiInput; |
| 9 | use embassy_stm32::gpio::Pull; | 9 | use embassy_stm32::gpio::Pull; |
| 10 | use embassy_stm32::low_power::Executor; | 10 | use embassy_stm32::low_power::Executor; |
| 11 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 12 | use panic_probe as _; | 11 | use panic_probe as _; |
| 13 | use static_cell::StaticCell; | 12 | use 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 _; | |||
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::i2c::I2c; | 8 | use embassy_stm32::i2c::I2c; |
| 9 | use embassy_stm32::low_power::Executor; | 9 | use embassy_stm32::low_power::Executor; |
| 10 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 11 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 12 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | 11 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; |
| 13 | use embassy_time::{Duration, Timer}; | 12 | use 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" | |||
| 73 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 73 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 74 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } | 74 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 75 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } | 75 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } |
| 76 | embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } | 76 | embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any", "_allow-disable-rtc"] } |
| 77 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | 77 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } |
| 78 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } | 78 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } |
| 79 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } | 79 | embassy-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 } | |||
| 94 | rand_chacha = { version = "0.9.0", default-features = false } | 94 | rand_chacha = { version = "0.9.0", default-features = false } |
| 95 | static_cell = "2" | 95 | static_cell = "2" |
| 96 | portable-atomic = { version = "1.5", features = [] } | 96 | portable-atomic = { version = "1.5", features = [] } |
| 97 | critical-section = "1.1" | ||
| 97 | 98 | ||
| 98 | chrono = { version = "^0.4", default-features = false, optional = true} | 99 | chrono = { version = "^0.4", default-features = false, optional = true} |
| 99 | sha2 = { version = "0.10.8", default-features = false } | 100 | sha2 = { 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::*; | |||
| 10 | use defmt::assert; | 10 | use defmt::assert; |
| 11 | use embassy_executor::Spawner; | 11 | use embassy_executor::Spawner; |
| 12 | use embassy_stm32::rcc::LsConfig; | 12 | use embassy_stm32::rcc::LsConfig; |
| 13 | #[cfg(feature = "stop")] | ||
| 14 | use embassy_stm32::rtc::Rtc; | ||
| 15 | #[cfg(not(feature = "stop"))] | ||
| 13 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | 16 | use embassy_stm32::rtc::{Rtc, RtcConfig}; |
| 14 | use embassy_time::Timer; | 17 | use embassy_time::Timer; |
| 15 | |||
| 16 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 19 | async 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; | |||
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::gpio::{Level, Output, Speed}; | 9 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 10 | use embassy_stm32::mode::Blocking; | 10 | use embassy_stm32::mode::Blocking; |
| 11 | use embassy_stm32::spi::mode::Master; | ||
| 11 | use embassy_stm32::spi::{self, Spi, Word}; | 12 | use embassy_stm32::spi::{self, Spi, Word}; |
| 12 | use embassy_stm32::time::Hertz; | 13 | use 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 | ||
| 68 | fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>) | 69 | fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>) |
| 69 | where | 70 | where |
| 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 | ||
| 112 | fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>, mosi_out: &mut Output<'_>) | 113 | fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>, mosi_out: &mut Output<'_>) |
| 113 | where | 114 | where |
| 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 | ||
| 128 | fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>) | 129 | fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>) |
| 129 | where | 130 | where |
| 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; | |||
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::gpio::{Level, Output, Speed}; | 9 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 10 | use embassy_stm32::mode::Async; | 10 | use embassy_stm32::mode::Async; |
| 11 | use embassy_stm32::spi::mode::Master; | ||
| 11 | use embassy_stm32::spi::{self, Spi, Word}; | 12 | use embassy_stm32::spi::{self, Spi, Word}; |
| 12 | use embassy_stm32::time::Hertz; | 13 | use 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 | ||
| 81 | async fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>) | 82 | async fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>) |
| 82 | where | 83 | where |
| 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 | ||
| 145 | async fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>, mosi_out: &mut Output<'_>) | 146 | async fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>, mosi_out: &mut Output<'_>) |
| 146 | where | 147 | where |
| 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 | ||
| 171 | async fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>) | 172 | async fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>) |
| 172 | where | 173 | where |
| 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::*; | |||
| 10 | use cortex_m_rt::entry; | 10 | use cortex_m_rt::entry; |
| 11 | use embassy_executor::Spawner; | 11 | use embassy_executor::Spawner; |
| 12 | use embassy_stm32::Config; | 12 | use embassy_stm32::Config; |
| 13 | use embassy_stm32::low_power::{Executor, StopMode, stop_ready, stop_with_rtc}; | 13 | use embassy_stm32::low_power::{Executor, StopMode, stop_ready}; |
| 14 | use embassy_stm32::rcc::LsConfig; | 14 | use embassy_stm32::rcc::LsConfig; |
| 15 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | 15 | use embassy_stm32::rtc::Rtc; |
| 16 | use embassy_time::Timer; | 16 | use 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")] |
