aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorRaul Alimbekov <[email protected]>2025-12-16 09:05:22 +0300
committerGitHub <[email protected]>2025-12-16 09:05:22 +0300
commitc9a04b4b732b7a3b696eb8223664c1a7942b1875 (patch)
tree6dbe5c02e66eed8d8762f13f95afd24f8db2b38c /embassy-stm32/src
parentcde24a3ef1117653ba5ed4184102b33f745782fb (diff)
parent5ae6e060ec1c90561719aabdc29d5b6e7b8b0a82 (diff)
Merge branch 'main' into main
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/adc/adc4.rs477
-rw-r--r--embassy-stm32/src/adc/c0.rs535
-rw-r--r--embassy-stm32/src/adc/f1.rs45
-rw-r--r--embassy-stm32/src/adc/f3.rs50
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs7
-rw-r--r--embassy-stm32/src/adc/g4.rs788
-rw-r--r--embassy-stm32/src/adc/injected.rs44
-rw-r--r--embassy-stm32/src/adc/mod.rs467
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs180
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs432
-rw-r--r--embassy-stm32/src/adc/v1.rs59
-rw-r--r--embassy-stm32/src/adc/v2.rs301
-rw-r--r--embassy-stm32/src/adc/v3.rs874
-rw-r--r--embassy-stm32/src/adc/v4.rs558
-rw-r--r--embassy-stm32/src/adc/watchdog_v1.rs6
-rw-r--r--embassy-stm32/src/backup_sram.rs28
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs12
-rw-r--r--embassy-stm32/src/can/enums.rs37
-rw-r--r--embassy-stm32/src/can/fd/config.rs15
-rw-r--r--embassy-stm32/src/can/fdcan.rs27
-rw-r--r--embassy-stm32/src/can/util.rs35
-rw-r--r--embassy-stm32/src/crc/v1.rs2
-rw-r--r--embassy-stm32/src/crc/v2v3.rs4
-rw-r--r--embassy-stm32/src/cryp/mod.rs10
-rw-r--r--embassy-stm32/src/dac/mod.rs2
-rw-r--r--embassy-stm32/src/dcmi.rs2
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs19
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs20
-rw-r--r--embassy-stm32/src/dma/gpdma/ringbuffered.rs13
-rw-r--r--embassy-stm32/src/dma/mod.rs34
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs2
-rw-r--r--embassy-stm32/src/dma/util.rs58
-rw-r--r--embassy-stm32/src/dma/word.rs4
-rw-r--r--embassy-stm32/src/dsihost.rs31
-rw-r--r--embassy-stm32/src/dts/mod.rs2
-rw-r--r--embassy-stm32/src/dts/tsel.rs17
-rw-r--r--embassy-stm32/src/eth/generic_phy.rs64
-rw-r--r--embassy-stm32/src/eth/mod.rs29
-rw-r--r--embassy-stm32/src/eth/sma/mod.rs42
-rw-r--r--embassy-stm32/src/eth/sma/v1.rs102
-rw-r--r--embassy-stm32/src/eth/sma/v2.rs94
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs265
-rw-r--r--embassy-stm32/src/eth/v1/rx_desc.rs2
-rw-r--r--embassy-stm32/src/eth/v1/tx_desc.rs2
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs2
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs201
-rw-r--r--embassy-stm32/src/exti.rs165
-rw-r--r--embassy-stm32/src/flash/asynch.rs8
-rw-r--r--embassy-stm32/src/flash/c.rs131
-rw-r--r--embassy-stm32/src/flash/common.rs16
-rw-r--r--embassy-stm32/src/flash/eeprom.rs2
-rw-r--r--embassy-stm32/src/flash/f0.rs2
-rw-r--r--embassy-stm32/src/flash/f1f3.rs2
-rw-r--r--embassy-stm32/src/flash/f2.rs4
-rw-r--r--embassy-stm32/src/flash/f4.rs24
-rw-r--r--embassy-stm32/src/flash/f7.rs12
-rw-r--r--embassy-stm32/src/flash/g.rs23
-rw-r--r--embassy-stm32/src/flash/h5.rs2
-rw-r--r--embassy-stm32/src/flash/h50.rs2
-rw-r--r--embassy-stm32/src/flash/h7.rs194
-rw-r--r--embassy-stm32/src/flash/l.rs30
-rw-r--r--embassy-stm32/src/flash/mod.rs7
-rw-r--r--embassy-stm32/src/flash/u0.rs2
-rw-r--r--embassy-stm32/src/flash/u5.rs2
-rw-r--r--embassy-stm32/src/fmc.rs38
-rw-r--r--embassy-stm32/src/fmt.rs10
-rw-r--r--embassy-stm32/src/gpio.rs73
-rw-r--r--embassy-stm32/src/hash/mod.rs8
-rw-r--r--embassy-stm32/src/hrtim/mod.rs87
-rw-r--r--embassy-stm32/src/hsem/mod.rs288
-rw-r--r--embassy-stm32/src/hspi/mod.rs95
-rw-r--r--embassy-stm32/src/i2c/config.rs8
-rw-r--r--embassy-stm32/src/i2c/mod.rs110
-rw-r--r--embassy-stm32/src/i2c/v1.rs1095
-rw-r--r--embassy-stm32/src/i2c/v2.rs825
-rw-r--r--embassy-stm32/src/i2s.rs7
-rw-r--r--embassy-stm32/src/ipcc.rs259
-rw-r--r--embassy-stm32/src/lcd.rs510
-rw-r--r--embassy-stm32/src/lib.rs65
-rw-r--r--embassy-stm32/src/low_power.rs305
-rw-r--r--embassy-stm32/src/lptim/pwm.rs6
-rw-r--r--embassy-stm32/src/ltdc.rs2
-rw-r--r--embassy-stm32/src/opamp.rs15
-rw-r--r--embassy-stm32/src/ospi/mod.rs66
-rw-r--r--embassy-stm32/src/qspi/mod.rs6
-rw-r--r--embassy-stm32/src/rcc/bd.rs140
-rw-r--r--embassy-stm32/src/rcc/f247.rs4
-rw-r--r--embassy-stm32/src/rcc/h.rs5
-rw-r--r--embassy-stm32/src/rcc/l.rs17
-rw-r--r--embassy-stm32/src/rcc/mco.rs37
-rw-r--r--embassy-stm32/src/rcc/mod.rs250
-rw-r--r--embassy-stm32/src/rcc/n6.rs1066
-rw-r--r--embassy-stm32/src/rcc/u5.rs19
-rw-r--r--embassy-stm32/src/rcc/wba.rs9
-rw-r--r--embassy-stm32/src/rng.rs27
-rw-r--r--embassy-stm32/src/rtc/low_power.rs82
-rw-r--r--embassy-stm32/src/rtc/mod.rs121
-rw-r--r--embassy-stm32/src/rtc/v2.rs2
-rw-r--r--embassy-stm32/src/rtc/v3.rs8
-rw-r--r--embassy-stm32/src/sai/mod.rs20
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs1389
-rw-r--r--embassy-stm32/src/sdmmc/sd.rs699
-rw-r--r--embassy-stm32/src/sdmmc/sdio.rs178
-rw-r--r--embassy-stm32/src/spdifrx/mod.rs2
-rw-r--r--embassy-stm32/src/spi/mod.rs298
-rw-r--r--embassy-stm32/src/time.rs2
-rw-r--r--embassy-stm32/src/time_driver.rs285
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs210
-rw-r--r--embassy-stm32/src/timer/input_capture.rs5
-rw-r--r--embassy-stm32/src/timer/low_level.rs430
-rw-r--r--embassy-stm32/src/timer/mod.rs35
-rw-r--r--embassy-stm32/src/timer/one_pulse.rs14
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs17
-rw-r--r--embassy-stm32/src/timer/qei.rs2
-rw-r--r--embassy-stm32/src/timer/ringbuffered.rs158
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs341
-rw-r--r--embassy-stm32/src/tsc/acquisition_banks.rs4
-rw-r--r--embassy-stm32/src/tsc/pin_groups.rs4
-rw-r--r--embassy-stm32/src/ucpd.rs7
-rw-r--r--embassy-stm32/src/uid.rs4
-rw-r--r--embassy-stm32/src/usart/buffered.rs75
-rw-r--r--embassy-stm32/src/usart/mod.rs93
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs161
-rw-r--r--embassy-stm32/src/usb/otg.rs10
-rw-r--r--embassy-stm32/src/usb/usb.rs4
-rw-r--r--embassy-stm32/src/vrefbuf/mod.rs11
-rw-r--r--embassy-stm32/src/wdg/mod.rs2
-rw-r--r--embassy-stm32/src/xspi/mod.rs104
128 files changed, 11069 insertions, 5788 deletions
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 255dc7956..491569c34 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -4,8 +4,8 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR
4#[cfg(stm32wba)] 4#[cfg(stm32wba)]
5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; 5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel};
6 6
7use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; 7use super::blocking_delay_us;
8use crate::dma::Transfer; 8use crate::adc::{AdcRegs, ConversionMode, Instance};
9#[cfg(stm32u5)] 9#[cfg(stm32u5)]
10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; 10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr;
11#[cfg(stm32wba)] 11#[cfg(stm32wba)]
@@ -15,7 +15,7 @@ pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4S
15#[cfg(stm32wba)] 15#[cfg(stm32wba)]
16pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime}; 16pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime};
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{pac, rcc, Peri}; 18use crate::{Peri, pac, rcc};
19 19
20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
21 21
@@ -24,56 +24,24 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
24/// VREF voltage used for factory calibration of VREFINTCAL register. 24/// VREF voltage used for factory calibration of VREFINTCAL register.
25pub const VREF_CALIB_MV: u32 = 3300; 25pub const VREF_CALIB_MV: u32 = 3300;
26 26
27const VREF_CHANNEL: u8 = 0; 27impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC4 {
28const VCORE_CHANNEL: u8 = 12; 28 const CHANNEL: u8 = 0;
29const TEMP_CHANNEL: u8 = 13;
30const VBAT_CHANNEL: u8 = 14;
31const DAC_CHANNEL: u8 = 21;
32
33// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
34/// Internal voltage reference channel.
35pub struct VrefInt;
36impl<T: Instance> AdcChannel<T> for VrefInt {}
37impl<T: Instance> SealedAdcChannel<T> for VrefInt {
38 fn channel(&self) -> u8 {
39 VREF_CHANNEL
40 }
41} 29}
42 30
43/// Internal temperature channel. 31impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC4 {
44pub struct Temperature; 32 const CHANNEL: u8 = 13;
45impl<T: Instance> AdcChannel<T> for Temperature {}
46impl<T: Instance> SealedAdcChannel<T> for Temperature {
47 fn channel(&self) -> u8 {
48 TEMP_CHANNEL
49 }
50} 33}
51 34
52/// Internal battery voltage channel. 35impl super::SealedSpecialConverter<super::Vcore> for crate::peripherals::ADC4 {
53pub struct Vbat; 36 const CHANNEL: u8 = 12;
54impl<T: Instance> AdcChannel<T> for Vbat {}
55impl<T: Instance> SealedAdcChannel<T> for Vbat {
56 fn channel(&self) -> u8 {
57 VBAT_CHANNEL
58 }
59} 37}
60 38
61/// Internal DAC channel. 39impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC4 {
62pub struct Dac; 40 const CHANNEL: u8 = 14;
63impl<T: Instance> AdcChannel<T> for Dac {}
64impl<T: Instance> SealedAdcChannel<T> for Dac {
65 fn channel(&self) -> u8 {
66 DAC_CHANNEL
67 }
68} 41}
69 42
70/// Internal Vcore channel. 43impl super::SealedSpecialConverter<super::Dac> for crate::peripherals::ADC4 {
71pub struct Vcore; 44 const CHANNEL: u8 = 21;
72impl<T: Instance> AdcChannel<T> for Vcore {}
73impl<T: Instance> SealedAdcChannel<T> for Vcore {
74 fn channel(&self) -> u8 {
75 VCORE_CHANNEL
76 }
77} 45}
78 46
79#[derive(Copy, Clone)] 47#[derive(Copy, Clone)]
@@ -108,123 +76,145 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 {
108 } 76 }
109} 77}
110 78
111// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 79fn from_ker_ck(frequency: Hertz) -> Presc {
112// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 80 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
113#[allow(unused)] 81 match raw_prescaler {
114enum Prescaler { 82 0 => Presc::DIV1,
115 NotDivided, 83 1 => Presc::DIV2,
116 DividedBy2, 84 2..=3 => Presc::DIV4,
117 DividedBy4, 85 4..=5 => Presc::DIV6,
118 DividedBy6, 86 6..=7 => Presc::DIV8,
119 DividedBy8, 87 8..=9 => Presc::DIV10,
120 DividedBy10, 88 10..=11 => Presc::DIV12,
121 DividedBy12, 89 _ => unimplemented!(),
122 DividedBy16, 90 }
123 DividedBy32,
124 DividedBy64,
125 DividedBy128,
126 DividedBy256,
127} 91}
128 92
129impl Prescaler { 93impl AdcRegs for crate::pac::adc::Adc4 {
130 fn from_ker_ck(frequency: Hertz) -> Self { 94 fn data(&self) -> *mut u16 {
131 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 95 crate::pac::adc::Adc4::dr(*self).as_ptr() as *mut u16
132 match raw_prescaler { 96 }
133 0 => Self::NotDivided, 97
134 1 => Self::DividedBy2, 98 fn enable(&self) {
135 2..=3 => Self::DividedBy4, 99 if !self.cr().read().aden() || !self.isr().read().adrdy() {
136 4..=5 => Self::DividedBy6, 100 self.isr().write(|w| w.set_adrdy(true));
137 6..=7 => Self::DividedBy8, 101 self.cr().modify(|w| w.set_aden(true));
138 8..=9 => Self::DividedBy10, 102 while !self.isr().read().adrdy() {}
139 10..=11 => Self::DividedBy12,
140 _ => unimplemented!(),
141 } 103 }
142 } 104 }
143 105
144 fn divisor(&self) -> u32 { 106 fn start(&self) {
145 match self { 107 // Start conversion
146 Prescaler::NotDivided => 1, 108 self.cr().modify(|reg| {
147 Prescaler::DividedBy2 => 2, 109 reg.set_adstart(true);
148 Prescaler::DividedBy4 => 4, 110 });
149 Prescaler::DividedBy6 => 6, 111 }
150 Prescaler::DividedBy8 => 8, 112
151 Prescaler::DividedBy10 => 10, 113 fn stop(&self) {
152 Prescaler::DividedBy12 => 12, 114 let cr = self.cr().read();
153 Prescaler::DividedBy16 => 16, 115 if cr.adstart() {
154 Prescaler::DividedBy32 => 32, 116 self.cr().modify(|w| w.set_adstp(true));
155 Prescaler::DividedBy64 => 64, 117 while self.cr().read().adstart() {}
156 Prescaler::DividedBy128 => 128, 118 }
157 Prescaler::DividedBy256 => 256, 119
120 if cr.aden() || cr.adstart() {
121 self.cr().modify(|w| w.set_addis(true));
122 while self.cr().read().aden() {}
158 } 123 }
124
125 // Reset configuration.
126 self.cfgr1().modify(|reg| {
127 reg.set_dmaen(false);
128 });
159 } 129 }
160 130
161 fn presc(&self) -> Presc { 131 fn configure_dma(&self, conversion_mode: ConversionMode) {
162 match self { 132 match conversion_mode {
163 Prescaler::NotDivided => Presc::DIV1, 133 ConversionMode::Singular => {
164 Prescaler::DividedBy2 => Presc::DIV2, 134 self.isr().modify(|reg| {
165 Prescaler::DividedBy4 => Presc::DIV4, 135 reg.set_ovr(true);
166 Prescaler::DividedBy6 => Presc::DIV6, 136 reg.set_eos(true);
167 Prescaler::DividedBy8 => Presc::DIV8, 137 reg.set_eoc(true);
168 Prescaler::DividedBy10 => Presc::DIV10, 138 });
169 Prescaler::DividedBy12 => Presc::DIV12, 139
170 Prescaler::DividedBy16 => Presc::DIV16, 140 self.cfgr1().modify(|reg| {
171 Prescaler::DividedBy32 => Presc::DIV32, 141 reg.set_dmaen(true);
172 Prescaler::DividedBy64 => Presc::DIV64, 142 reg.set_dmacfg(Dmacfg::ONE_SHOT);
173 Prescaler::DividedBy128 => Presc::DIV128, 143 #[cfg(stm32u5)]
174 Prescaler::DividedBy256 => Presc::DIV256, 144 reg.set_chselrmod(false);
145 #[cfg(stm32wba)]
146 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
147 });
148 }
149 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
150 _ => unreachable!(),
175 } 151 }
176 } 152 }
177}
178 153
179pub trait SealedInstance { 154 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
180 #[allow(unused)] 155 let mut prev_channel: i16 = -1;
181 fn regs() -> crate::pac::adc::Adc4; 156 #[cfg(stm32wba)]
182} 157 self.chselr().write_value(Chselr(0_u32));
158 #[cfg(stm32u5)]
159 self.chselrmod0().write_value(Chselr(0_u32));
160 for (_i, ((channel, _), sample_time)) in sequence.enumerate() {
161 self.smpr().modify(|w| {
162 w.set_smp(_i, sample_time);
163 });
183 164
184pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { 165 let channel_num = channel;
185 type Interrupt: crate::interrupt::typelevel::Interrupt; 166 if channel_num as i16 <= prev_channel {
186} 167 return;
168 };
169 prev_channel = channel_num as i16;
187 170
188pub struct Adc4<'d, T: Instance> { 171 #[cfg(stm32wba)]
189 #[allow(unused)] 172 self.chselr().modify(|w| {
190 adc: crate::Peri<'d, T>, 173 w.set_chsel0(channel as usize, true);
191} 174 });
175 #[cfg(stm32u5)]
176 self.chselrmod0().modify(|w| {
177 w.set_chsel(channel as usize, true);
178 });
179 }
180 }
192 181
193#[derive(Copy, Clone, Debug)] 182 fn convert(&self) {
194pub enum Adc4Error { 183 // Reset interrupts
195 InvalidSequence, 184 self.isr().modify(|reg| {
196 DMAError, 185 reg.set_eos(true);
186 reg.set_eoc(true);
187 });
188
189 // Start conversion
190 self.cr().modify(|reg| {
191 reg.set_adstart(true);
192 });
193
194 while !self.isr().read().eos() {
195 // spin
196 }
197 }
197} 198}
198 199
199impl<'d, T: Instance> Adc4<'d, T> { 200impl<'d, T: Instance<Regs = crate::pac::adc::Adc4>> super::Adc<'d, T> {
200 /// Create a new ADC driver. 201 /// Create a new ADC driver.
201 pub fn new(adc: Peri<'d, T>) -> Self { 202 pub fn new_adc4(adc: Peri<'d, T>) -> Self {
202 rcc::enable_and_reset::<T>(); 203 rcc::enable_and_reset::<T>();
203 let prescaler = Prescaler::from_ker_ck(T::frequency()); 204 let prescaler = from_ker_ck(T::frequency());
204 205
205 T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 206 T::regs().ccr().modify(|w| w.set_presc(prescaler));
206 207
207 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 208 let frequency = T::frequency() / prescaler;
208 info!("ADC4 frequency set to {}", frequency); 209 info!("ADC4 frequency set to {}", frequency);
209 210
210 if frequency > MAX_ADC_CLK_FREQ { 211 if frequency > MAX_ADC_CLK_FREQ {
211 panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 212 panic!(
213 "Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.",
214 MAX_ADC_CLK_FREQ.0 / 1_000_000
215 );
212 } 216 }
213 217
214 let mut s = Self { adc };
215
216 s.power_up();
217
218 s.calibrate();
219 blocking_delay_us(1);
220
221 s.enable();
222 s.configure();
223
224 s
225 }
226
227 fn power_up(&mut self) {
228 T::regs().isr().modify(|w| { 218 T::regs().isr().modify(|w| {
229 w.set_ldordy(true); 219 w.set_ldordy(true);
230 }); 220 });
@@ -236,22 +226,15 @@ impl<'d, T: Instance> Adc4<'d, T> {
236 T::regs().isr().modify(|w| { 226 T::regs().isr().modify(|w| {
237 w.set_ldordy(true); 227 w.set_ldordy(true);
238 }); 228 });
239 }
240 229
241 fn calibrate(&mut self) {
242 T::regs().cr().modify(|w| w.set_adcal(true)); 230 T::regs().cr().modify(|w| w.set_adcal(true));
243 while T::regs().cr().read().adcal() {} 231 while T::regs().cr().read().adcal() {}
244 T::regs().isr().modify(|w| w.set_eocal(true)); 232 T::regs().isr().modify(|w| w.set_eocal(true));
245 }
246 233
247 fn enable(&mut self) { 234 blocking_delay_us(1);
248 T::regs().isr().write(|w| w.set_adrdy(true)); 235
249 T::regs().cr().modify(|w| w.set_aden(true)); 236 T::regs().enable();
250 while !T::regs().isr().read().adrdy() {}
251 T::regs().isr().write(|w| w.set_adrdy(true));
252 }
253 237
254 fn configure(&mut self) {
255 // single conversion mode, software trigger 238 // single conversion mode, software trigger
256 T::regs().cfgr1().modify(|w| { 239 T::regs().cfgr1().modify(|w| {
257 #[cfg(stm32u5)] 240 #[cfg(stm32u5)]
@@ -277,73 +260,63 @@ impl<'d, T: Instance> Adc4<'d, T> {
277 w.set_smpsel(i, Smpsel::SMP1); 260 w.set_smpsel(i, Smpsel::SMP1);
278 } 261 }
279 }); 262 });
263
264 Self { adc }
280 } 265 }
281 266
282 /// Enable reading the voltage reference internal channel. 267 /// Enable reading the voltage reference internal channel.
283 pub fn enable_vrefint(&self) -> VrefInt { 268 pub fn enable_vrefint_adc4(&self) -> super::VrefInt {
284 T::regs().ccr().modify(|w| { 269 T::regs().ccr().modify(|w| {
285 w.set_vrefen(true); 270 w.set_vrefen(true);
286 }); 271 });
287 272
288 VrefInt {} 273 super::VrefInt {}
289 } 274 }
290 275
291 /// Enable reading the temperature internal channel. 276 /// Enable reading the temperature internal channel.
292 pub fn enable_temperature(&self) -> Temperature { 277 pub fn enable_temperature_adc4(&self) -> super::Temperature {
293 T::regs().ccr().modify(|w| { 278 T::regs().ccr().modify(|w| {
294 w.set_vsensesel(true); 279 w.set_vsensesel(true);
295 }); 280 });
296 281
297 Temperature {} 282 super::Temperature {}
298 } 283 }
299 284
300 /// Enable reading the vbat internal channel. 285 /// Enable reading the vbat internal channel.
301 #[cfg(stm32u5)] 286 #[cfg(stm32u5)]
302 pub fn enable_vbat(&self) -> Vbat { 287 pub fn enable_vbat_adc4(&self) -> super::Vbat {
303 T::regs().ccr().modify(|w| { 288 T::regs().ccr().modify(|w| {
304 w.set_vbaten(true); 289 w.set_vbaten(true);
305 }); 290 });
306 291
307 Vbat {} 292 super::Vbat {}
308 } 293 }
309 294
310 /// Enable reading the vbat internal channel. 295 /// Enable reading the vbat internal channel.
311 pub fn enable_vcore(&self) -> Vcore { 296 pub fn enable_vcore_adc4(&self) -> super::Vcore {
312 Vcore {} 297 super::Vcore {}
313 } 298 }
314 299
315 /// Enable reading the vbat internal channel. 300 /// Enable reading the vbat internal channel.
316 #[cfg(stm32u5)] 301 #[cfg(stm32u5)]
317 pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { 302 pub fn enable_dac_channel_adc4(&self, dac: DacChannel) -> super::Dac {
318 let mux; 303 let mux;
319 match dac { 304 match dac {
320 DacChannel::OUT1 => mux = false, 305 DacChannel::OUT1 => mux = false,
321 DacChannel::OUT2 => mux = true, 306 DacChannel::OUT2 => mux = true,
322 } 307 }
323 T::regs().or().modify(|w| w.set_chn21sel(mux)); 308 T::regs().or().modify(|w| w.set_chn21sel(mux));
324 Dac {} 309 super::Dac {}
325 }
326
327 /// Set the ADC sample time.
328 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
329 T::regs().smpr().modify(|w| {
330 w.set_smp(0, sample_time);
331 });
332 }
333
334 /// Get the ADC sample time.
335 pub fn sample_time(&self) -> SampleTime {
336 T::regs().smpr().read().smp(0)
337 } 310 }
338 311
339 /// Set the ADC resolution. 312 /// Set the ADC resolution.
340 pub fn set_resolution(&mut self, resolution: Resolution) { 313 pub fn set_resolution_adc4(&mut self, resolution: Resolution) {
341 T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); 314 T::regs().cfgr1().modify(|w| w.set_res(resolution.into()));
342 } 315 }
343 316
344 /// Set hardware averaging. 317 /// Set hardware averaging.
345 #[cfg(stm32u5)] 318 #[cfg(stm32u5)]
346 pub fn set_averaging(&mut self, averaging: Averaging) { 319 pub fn set_averaging_adc4(&mut self, averaging: Averaging) {
347 let (enable, samples, right_shift) = match averaging { 320 let (enable, samples, right_shift) = match averaging {
348 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0), 321 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0),
349 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1), 322 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1),
@@ -363,7 +336,7 @@ impl<'d, T: Instance> Adc4<'d, T> {
363 }) 336 })
364 } 337 }
365 #[cfg(stm32wba)] 338 #[cfg(stm32wba)]
366 pub fn set_averaging(&mut self, averaging: Averaging) { 339 pub fn set_averaging_adc4(&mut self, averaging: Averaging) {
367 let (enable, samples, right_shift) = match averaging { 340 let (enable, samples, right_shift) = match averaging {
368 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0), 341 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0),
369 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1), 342 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1),
@@ -382,164 +355,4 @@ impl<'d, T: Instance> Adc4<'d, T> {
382 w.set_ovse(enable) 355 w.set_ovse(enable)
383 }) 356 })
384 } 357 }
385
386 /// Read an ADC channel.
387 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
388 channel.setup();
389
390 // Select channel
391 #[cfg(stm32wba)]
392 {
393 T::regs().chselr().write_value(Chselr(0_u32));
394 T::regs().chselr().modify(|w| {
395 w.set_chsel0(channel.channel() as usize, true);
396 });
397 }
398 #[cfg(stm32u5)]
399 {
400 T::regs().chselrmod0().write_value(Chselr(0_u32));
401 T::regs().chselrmod0().modify(|w| {
402 w.set_chsel(channel.channel() as usize, true);
403 });
404 }
405
406 // Reset interrupts
407 T::regs().isr().modify(|reg| {
408 reg.set_eos(true);
409 reg.set_eoc(true);
410 });
411
412 // Start conversion
413 T::regs().cr().modify(|reg| {
414 reg.set_adstart(true);
415 });
416
417 while !T::regs().isr().read().eos() {
418 // spin
419 }
420
421 T::regs().dr().read().0 as u16
422 }
423
424 /// Read one or multiple ADC channels using DMA.
425 ///
426 /// `sequence` iterator and `readings` must have the same length.
427 /// The channels in `sequence` must be in ascending order.
428 ///
429 /// Example
430 /// ```rust,ignore
431 /// use embassy_stm32::adc::adc4;
432 /// use embassy_stm32::adc::AdcChannel;
433 ///
434 /// let mut adc4 = adc4::Adc4::new(p.ADC4);
435 /// let mut adc4_pin1 = p.PC1;
436 /// let mut adc4_pin2 = p.PC0;
437 /// let mut.into()d41 = adc4_pin1.into();
438 /// let mut.into()d42 = adc4_pin2.into();
439 /// let mut measurements = [0u16; 2];
440 /// // not that the channels must be in ascending order
441 /// adc4.read(
442 /// &mut p.GPDMA1_CH1,
443 /// [
444 /// &mut.into()d42,
445 /// &mut.into()d41,
446 /// ]
447 /// .into_iter(),
448 /// &mut measurements,
449 /// ).await.unwrap();
450 /// ```
451 pub async fn read(
452 &mut self,
453 rx_dma: Peri<'_, impl RxDma4<T>>,
454 sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
455 readings: &mut [u16],
456 ) -> Result<(), Adc4Error> {
457 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
458 assert!(
459 sequence.len() == readings.len(),
460 "Sequence length must be equal to readings length"
461 );
462
463 // Ensure no conversions are ongoing
464 Self::cancel_conversions();
465
466 T::regs().isr().modify(|reg| {
467 reg.set_ovr(true);
468 reg.set_eos(true);
469 reg.set_eoc(true);
470 });
471
472 T::regs().cfgr1().modify(|reg| {
473 reg.set_dmaen(true);
474 reg.set_dmacfg(Dmacfg::ONE_SHOT);
475 #[cfg(stm32u5)]
476 reg.set_chselrmod(false);
477 #[cfg(stm32wba)]
478 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
479 });
480
481 // Verify and activate sequence
482 let mut prev_channel: i16 = -1;
483 #[cfg(stm32wba)]
484 T::regs().chselr().write_value(Chselr(0_u32));
485 #[cfg(stm32u5)]
486 T::regs().chselrmod0().write_value(Chselr(0_u32));
487 for channel in sequence {
488 let channel_num = channel.channel;
489 if channel_num as i16 <= prev_channel {
490 return Err(Adc4Error::InvalidSequence);
491 };
492 prev_channel = channel_num as i16;
493
494 #[cfg(stm32wba)]
495 T::regs().chselr().modify(|w| {
496 w.set_chsel0(channel.channel as usize, true);
497 });
498 #[cfg(stm32u5)]
499 T::regs().chselrmod0().modify(|w| {
500 w.set_chsel(channel.channel as usize, true);
501 });
502 }
503
504 let request = rx_dma.request();
505 let transfer = unsafe {
506 Transfer::new_read(
507 rx_dma,
508 request,
509 T::regs().dr().as_ptr() as *mut u16,
510 readings,
511 Default::default(),
512 )
513 };
514
515 // Start conversion
516 T::regs().cr().modify(|reg| {
517 reg.set_adstart(true);
518 });
519
520 transfer.await;
521
522 // Ensure conversions are finished.
523 Self::cancel_conversions();
524
525 // Reset configuration.
526 T::regs().cfgr1().modify(|reg| {
527 reg.set_dmaen(false);
528 });
529
530 if T::regs().isr().read().ovr() {
531 Err(Adc4Error::DMAError)
532 } else {
533 Ok(())
534 }
535 }
536
537 fn cancel_conversions() {
538 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
539 T::regs().cr().modify(|reg| {
540 reg.set_adstp(true);
541 });
542 while T::regs().cr().read().adstart() {}
543 }
544 }
545} 358}
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index f2837a8f1..2f0f326af 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -1,14 +1,12 @@
1use pac::adc::vals::Scandir;
2#[allow(unused)] 1#[allow(unused)]
3use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; 2use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr};
4use pac::adccommon::vals::Presc; 3use pac::adccommon::vals::Presc;
4use stm32_metapac::adc::vals::{SampleTime, Scandir};
5 5
6use super::{ 6use super::{Adc, Instance, Resolution, blocking_delay_us};
7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 7use crate::adc::{AdcRegs, ConversionMode};
8};
9use crate::dma::Transfer;
10use crate::time::Hertz; 8use crate::time::Hertz;
11use crate::{pac, rcc, Peri}; 9use crate::{Peri, pac, rcc};
12 10
13/// Default VREF voltage used for sample conversion to millivolts. 11/// Default VREF voltage used for sample conversion to millivolts.
14pub const VREF_DEFAULT_MV: u32 = 3300; 12pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -19,189 +17,198 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25);
19 17
20const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; 18const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20;
21 19
22const TEMP_CHANNEL: u8 = 9;
23const VREF_CHANNEL: u8 = 10;
24
25const NUM_HW_CHANNELS: u8 = 22;
26const CHSELR_SQ_SIZE: usize = 8; 20const CHSELR_SQ_SIZE: usize = 8;
27const CHSELR_SQ_MAX_CHANNEL: u8 = 14; 21const CHSELR_SQ_MAX_CHANNEL: u8 = 14;
28const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; 22const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111;
29 23
30// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, 24impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
31// this currently cannot be modeled with stm32-data, 25 const CHANNEL: u8 = 10;
32// so these are available from the software on all ADCs.
33/// Internal voltage reference channel.
34pub struct VrefInt;
35impl<T: Instance> AdcChannel<T> for VrefInt {}
36impl<T: Instance> SealedAdcChannel<T> for VrefInt {
37 fn channel(&self) -> u8 {
38 VREF_CHANNEL
39 }
40} 26}
41 27
42/// Internal temperature channel. 28impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
43pub struct Temperature; 29 const CHANNEL: u8 = 9;
44impl<T: Instance> AdcChannel<T> for Temperature {}
45impl<T: Instance> SealedAdcChannel<T> for Temperature {
46 fn channel(&self) -> u8 {
47 TEMP_CHANNEL
48 }
49} 30}
50 31
51#[derive(Copy, Clone, Debug)] 32fn from_ker_ck(frequency: Hertz) -> Presc {
52pub enum Prescaler { 33 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
53 NotDivided, 34 match raw_prescaler {
54 DividedBy2, 35 0 => Presc::DIV1,
55 DividedBy4, 36 1 => Presc::DIV2,
56 DividedBy6, 37 2..=3 => Presc::DIV4,
57 DividedBy8, 38 4..=5 => Presc::DIV6,
58 DividedBy10, 39 6..=7 => Presc::DIV8,
59 DividedBy12, 40 8..=9 => Presc::DIV10,
60 DividedBy16, 41 10..=11 => Presc::DIV12,
61 DividedBy32, 42 _ => unimplemented!(),
62 DividedBy64, 43 }
63 DividedBy128,
64 DividedBy256,
65} 44}
66 45
67impl Prescaler { 46impl AdcRegs for crate::pac::adc::Adc {
68 fn from_ker_ck(frequency: Hertz) -> Self { 47 fn data(&self) -> *mut u16 {
69 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 48 crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
70 match raw_prescaler {
71 0 => Self::NotDivided,
72 1 => Self::DividedBy2,
73 2..=3 => Self::DividedBy4,
74 4..=5 => Self::DividedBy6,
75 6..=7 => Self::DividedBy8,
76 8..=9 => Self::DividedBy10,
77 10..=11 => Self::DividedBy12,
78 _ => unimplemented!(),
79 }
80 } 49 }
81 50
82 #[allow(unused)] 51 fn enable(&self) {
83 fn divisor(&self) -> u32 { 52 self.isr().modify(|w| w.set_adrdy(true));
84 match self { 53 self.cr().modify(|w| w.set_aden(true));
85 Prescaler::NotDivided => 1, 54 // ADRDY is "ADC ready". Wait until it will be True.
86 Prescaler::DividedBy2 => 2, 55 while !self.isr().read().adrdy() {}
87 Prescaler::DividedBy4 => 4, 56 }
88 Prescaler::DividedBy6 => 6, 57
89 Prescaler::DividedBy8 => 8, 58 fn start(&self) {
90 Prescaler::DividedBy10 => 10, 59 // Start conversion
91 Prescaler::DividedBy12 => 12, 60 self.cr().modify(|reg| {
92 Prescaler::DividedBy16 => 16, 61 reg.set_adstart(true);
93 Prescaler::DividedBy32 => 32, 62 });
94 Prescaler::DividedBy64 => 64,
95 Prescaler::DividedBy128 => 128,
96 Prescaler::DividedBy256 => 256,
97 }
98 } 63 }
99 64
100 fn presc(&self) -> Presc { 65 fn stop(&self) {
101 match self { 66 if self.cr().read().adstart() && !self.cr().read().addis() {
102 Prescaler::NotDivided => Presc::DIV1, 67 self.cr().modify(|reg| {
103 Prescaler::DividedBy2 => Presc::DIV2, 68 reg.set_adstp(Adstp::STOP);
104 Prescaler::DividedBy4 => Presc::DIV4, 69 });
105 Prescaler::DividedBy6 => Presc::DIV6, 70 while self.cr().read().adstart() {}
106 Prescaler::DividedBy8 => Presc::DIV8,
107 Prescaler::DividedBy10 => Presc::DIV10,
108 Prescaler::DividedBy12 => Presc::DIV12,
109 Prescaler::DividedBy16 => Presc::DIV16,
110 Prescaler::DividedBy32 => Presc::DIV32,
111 Prescaler::DividedBy64 => Presc::DIV64,
112 Prescaler::DividedBy128 => Presc::DIV128,
113 Prescaler::DividedBy256 => Presc::DIV256,
114 } 71 }
72
73 // Reset configuration.
74 self.cfgr1().modify(|reg| {
75 reg.set_cont(false);
76 reg.set_dmacfg(Dmacfg::from_bits(0));
77 reg.set_dmaen(false);
78 });
115 } 79 }
116}
117 80
118#[cfg(feature = "defmt")] 81 fn configure_dma(&self, conversion_mode: super::ConversionMode) {
119impl<'a> defmt::Format for Prescaler { 82 match conversion_mode {
120 fn format(&self, fmt: defmt::Formatter) { 83 ConversionMode::Singular => {
121 match self { 84 // Enable overrun control, so no new DMA requests will be generated until
122 Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), 85 // previous DR values is read.
123 Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), 86 self.isr().modify(|reg| {
124 Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), 87 reg.set_ovr(true);
125 Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), 88 });
126 Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), 89
127 Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), 90 // Set continuous mode with oneshot dma.
128 Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), 91 self.cfgr1().modify(|reg| {
129 Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), 92 reg.set_discen(false);
130 Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), 93 reg.set_cont(true);
131 Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), 94 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
132 Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), 95 reg.set_dmaen(true);
133 Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), 96 reg.set_ovrmod(Ovrmod::PRESERVE);
97 });
98 }
134 } 99 }
135 } 100 }
136}
137 101
138/// Number of samples used for averaging. 102 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>) {
139/// TODO: Implement hardware averaging setting. 103 let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE;
140#[allow(unused)] 104 let mut is_ordered_up = true;
141#[derive(Copy, Clone, Debug)] 105 let mut is_ordered_down = true;
142#[cfg_attr(feature = "defmt", derive(defmt::Format))]
143pub enum Averaging {
144 Disabled,
145 Samples2,
146 Samples4,
147 Samples8,
148 Samples16,
149 Samples32,
150 Samples64,
151 Samples128,
152 Samples256,
153 Samples512,
154 Samples1024,
155}
156 106
157impl<'d, T: Instance> Adc<'d, T> { 107 let sequence_len = sequence.len();
158 /// Create a new ADC driver. 108 let mut hw_channel_selection: u32 = 0;
159 pub fn new(adc: Peri<'d, T>, sample_time: SampleTime, resolution: Resolution) -> Self { 109 let mut last_channel: u8 = 0;
160 rcc::enable_and_reset::<T>(); 110 let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5;
161 111
162 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); 112 self.chselr_sq().write(|w| {
113 for (i, ((channel, _), _sample_time)) in sequence.enumerate() {
114 assert!(
115 sample_time == _sample_time || i == 0,
116 "C0 only supports one sample time for the sequence."
117 );
163 118
164 let prescaler = Prescaler::from_ker_ck(T::frequency()); 119 sample_time = _sample_time;
165 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 120 needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL;
121 is_ordered_up = is_ordered_up && (channel > last_channel || i == 0);
122 is_ordered_down = is_ordered_down && (channel < last_channel || i == 0);
123 hw_channel_selection += 1 << channel;
124 last_channel = channel;
166 125
167 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 126 if !needs_hw {
168 debug!("ADC frequency set to {}", frequency); 127 w.set_sq(i, channel);
128 }
129 }
169 130
170 if frequency > MAX_ADC_CLK_FREQ { 131 for i in sequence_len..CHSELR_SQ_SIZE {
171 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 132 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
133 }
134 });
135
136 if needs_hw {
137 assert!(
138 sequence_len <= CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down,
139 "Sequencer is required because of unordered channels, but read set cannot be more than {} in size.",
140 CHSELR_SQ_SIZE
141 );
142 assert!(
143 sequence_len > CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down,
144 "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.",
145 CHSELR_SQ_MAX_CHANNEL
146 );
147
148 // Set required channels for multi-convert.
149 unsafe { (self.chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
172 } 150 }
173 151
174 let mut s = Self { 152 self.smpr().modify(|w| {
175 adc, 153 w.smpsel(0);
176 sample_time: SampleTime::from_bits(0), 154 w.set_smp1(sample_time);
177 }; 155 });
178 156
179 s.power_up(); 157 self.cfgr1().modify(|reg| {
158 reg.set_chselrmod(!needs_hw);
159 reg.set_align(Align::RIGHT);
160 reg.set_scandir(if is_ordered_up { Scandir::UP } else { Scandir::BACK });
161 });
180 162
181 s.set_resolution(resolution); 163 // Trigger and wait for the channel selection procedure to complete.
164 self.isr().modify(|w| w.set_ccrdy(false));
165 while !self.isr().read().ccrdy() {}
166 }
182 167
183 s.calibrate(); 168 fn convert(&self) {
169 // Set single conversion mode.
170 self.cfgr1().modify(|w| w.set_cont(false));
184 171
185 s.enable(); 172 // Start conversion
173 self.cr().modify(|reg| {
174 reg.set_adstart(true);
175 });
186 176
187 s.configure_default(); 177 // Waiting for End Of Conversion (EOC).
178 while !self.isr().read().eoc() {}
179 }
180}
188 181
189 s.set_sample_time_all_channels(sample_time); 182impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
183 /// Create a new ADC driver.
184 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self {
185 rcc::enable_and_reset::<T>();
190 186
191 s 187 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
192 } 188
189 let prescaler = from_ker_ck(T::frequency());
190 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
191
192 let frequency = T::frequency() / prescaler;
193 debug!("ADC frequency set to {}", frequency);
194
195 if frequency > MAX_ADC_CLK_FREQ {
196 panic!(
197 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
198 MAX_ADC_CLK_FREQ.0 / 1_000_000
199 );
200 }
193 201
194 fn power_up(&mut self) {
195 T::regs().cr().modify(|reg| { 202 T::regs().cr().modify(|reg| {
196 reg.set_advregen(true); 203 reg.set_advregen(true);
197 }); 204 });
198 205
199 // "The software must wait for the ADC voltage regulator startup time." 206 // "The software must wait for the ADC voltage regulator startup time."
200 // See datasheet for the value. 207 // See datasheet for the value.
201 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); 208 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US as u64 + 1);
202 } 209
210 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
203 211
204 fn calibrate(&mut self) {
205 // We have to make sure AUTOFF is OFF, but keep its value after calibration. 212 // We have to make sure AUTOFF is OFF, but keep its value after calibration.
206 let autoff_value = T::regs().cfgr1().read().autoff(); 213 let autoff_value = T::regs().cfgr1().read().autoff();
207 T::regs().cfgr1().modify(|w| w.set_autoff(false)); 214 T::regs().cfgr1().modify(|w| w.set_autoff(false));
@@ -215,255 +222,35 @@ impl<'d, T: Instance> Adc<'d, T> {
215 debug!("ADC calibration value: {}.", T::regs().dr().read().data()); 222 debug!("ADC calibration value: {}.", T::regs().dr().read().data());
216 223
217 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); 224 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value));
218 }
219 225
220 fn enable(&mut self) { 226 T::regs().enable();
221 T::regs().isr().modify(|w| w.set_adrdy(true));
222 T::regs().cr().modify(|w| w.set_aden(true));
223 // ADRDY is "ADC ready". Wait until it will be True.
224 while !T::regs().isr().read().adrdy() {}
225 }
226 227
227 fn configure_default(&mut self) {
228 // single conversion mode, software trigger 228 // single conversion mode, software trigger
229 T::regs().cfgr1().modify(|w| { 229 T::regs().cfgr1().modify(|w| {
230 w.set_cont(false); 230 w.set_cont(false);
231 w.set_exten(Exten::DISABLED); 231 w.set_exten(Exten::DISABLED);
232 w.set_align(Align::RIGHT); 232 w.set_align(Align::RIGHT);
233 }); 233 });
234
235 Self { adc }
234 } 236 }
235 237
236 /// Enable reading the voltage reference internal channel. 238 /// Enable reading the voltage reference internal channel.
237 pub fn enable_vrefint(&self) -> VrefInt { 239 pub fn enable_vrefint(&self) -> super::VrefInt {
238 T::common_regs().ccr().modify(|reg| { 240 T::common_regs().ccr().modify(|reg| {
239 reg.set_vrefen(true); 241 reg.set_vrefen(true);
240 }); 242 });
241 243
242 VrefInt {} 244 super::VrefInt {}
243 } 245 }
244 246
245 /// Enable reading the temperature internal channel. 247 /// Enable reading the temperature internal channel.
246 pub fn enable_temperature(&self) -> Temperature { 248 pub fn enable_temperature(&self) -> super::Temperature {
247 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!"); 249 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!");
248 T::common_regs().ccr().modify(|reg| { 250 T::common_regs().ccr().modify(|reg| {
249 reg.set_tsen(true); 251 reg.set_tsen(true);
250 }); 252 });
251 253
252 Temperature {} 254 super::Temperature {}
253 }
254
255 /// Set the ADC sample time.
256 /// Shall only be called when ADC is not converting.
257 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
258 self.sample_time = sample_time;
259
260 // Set all channels to use SMP1 field as source.
261 T::regs().smpr().modify(|w| {
262 w.smpsel(0);
263 w.set_smp1(sample_time);
264 });
265 }
266
267 /// Set the ADC resolution.
268 pub fn set_resolution(&mut self, resolution: Resolution) {
269 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
270 }
271
272 /// Perform a single conversion.
273 fn convert(&mut self) -> u16 {
274 // Set single conversion mode.
275 T::regs().cfgr1().modify(|w| w.set_cont(false));
276
277 // Start conversion
278 T::regs().cr().modify(|reg| {
279 reg.set_adstart(true);
280 });
281
282 // Waiting for End Of Conversion (EOC).
283 while !T::regs().isr().read().eoc() {}
284
285 T::regs().dr().read().data() as u16
286 }
287
288 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
289 Self::configure_channel(channel);
290 T::regs().cfgr1().write(|reg| {
291 reg.set_chselrmod(false);
292 reg.set_align(Align::RIGHT);
293 });
294 self.convert()
295 }
296
297 fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) {
298 assert!(
299 channel_sequence.len() <= CHSELR_SQ_SIZE,
300 "Seqenced read set cannot be more than {} in size.",
301 CHSELR_SQ_SIZE
302 );
303 let mut last_sq_set: usize = 0;
304 T::regs().chselr_sq().write(|w| {
305 for (i, channel) in channel_sequence.enumerate() {
306 assert!(
307 channel.channel() <= CHSELR_SQ_MAX_CHANNEL,
308 "Sequencer only support HW channels smaller than {}.",
309 CHSELR_SQ_MAX_CHANNEL
310 );
311 w.set_sq(i, channel.channel());
312 last_sq_set = i;
313 }
314
315 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
316 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
317 }
318 });
319
320 Self::apply_channel_conf()
321 }
322
323 async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) {
324 // Enable overrun control, so no new DMA requests will be generated until
325 // previous DR values is read.
326 T::regs().isr().modify(|reg| {
327 reg.set_ovr(true);
328 });
329
330 // Set continuous mode with oneshot dma.
331 T::regs().cfgr1().modify(|reg| {
332 reg.set_discen(false);
333 reg.set_cont(true);
334 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
335 reg.set_dmaen(true);
336 reg.set_ovrmod(Ovrmod::PRESERVE);
337 });
338
339 let request = rx_dma.request();
340 let transfer = unsafe {
341 Transfer::new_read(
342 rx_dma,
343 request,
344 T::regs().dr().as_ptr() as *mut u16,
345 readings,
346 Default::default(),
347 )
348 };
349
350 // Start conversion.
351 T::regs().cr().modify(|reg| {
352 reg.set_adstart(true);
353 });
354
355 // Wait for conversion sequence to finish.
356 transfer.await;
357
358 // Ensure conversions are finished.
359 Self::cancel_conversions();
360
361 // Reset configuration.
362 T::regs().cfgr1().modify(|reg| {
363 reg.set_cont(false);
364 reg.set_dmacfg(Dmacfg::from_bits(0));
365 reg.set_dmaen(false);
366 });
367 }
368
369 /// Read one or multiple ADC channels using DMA in hardware order.
370 /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting.
371 /// Readings won't be in the same order as in the `set`!
372 ///
373 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
374 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
375 /// TODO(chudsaviet): externalize generic code and merge with read().
376 pub async fn read_in_hw_order(
377 &mut self,
378 rx_dma: Peri<'_, impl RxDma<T>>,
379 hw_channel_selection: u32,
380 scandir: Scandir,
381 readings: &mut [u16],
382 ) {
383 assert!(
384 hw_channel_selection != 0,
385 "Some bits in `hw_channel_selection` shall be set."
386 );
387 assert!(
388 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
389 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
390 NUM_HW_CHANNELS
391 );
392 // To check for correct readings slice size, we shall solve Hamming weight problem,
393 // which is either slow or memory consuming.
394 // Since we have limited resources, we don't do it here.
395 // Not doing this have a great potential for a bug through.
396
397 // Ensure no conversions are ongoing.
398 Self::cancel_conversions();
399
400 T::regs().cfgr1().modify(|reg| {
401 reg.set_chselrmod(false);
402 reg.set_scandir(scandir);
403 reg.set_align(Align::RIGHT);
404 });
405
406 // Set required channels for multi-convert.
407 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
408
409 Self::apply_channel_conf();
410
411 self.dma_convert(rx_dma, readings).await
412 }
413
414 // Read ADC channels in specified order using DMA (CHSELRMOD = 1).
415 // In STM32C0, only lower 14 ADC channels can be read this way.
416 // For other channels, use `read_in_hw_order()` or blocking read.
417 pub async fn read(
418 &mut self,
419 rx_dma: Peri<'_, impl RxDma<T>>,
420 channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
421 readings: &mut [u16],
422 ) {
423 assert!(
424 channel_sequence.len() != 0,
425 "Asynchronous read channel sequence cannot be empty."
426 );
427 assert!(
428 channel_sequence.len() == readings.len(),
429 "Channel sequence length must be equal to readings length."
430 );
431
432 // Ensure no conversions are ongoing.
433 Self::cancel_conversions();
434
435 T::regs().cfgr1().modify(|reg| {
436 reg.set_chselrmod(true);
437 reg.set_align(Align::RIGHT);
438 });
439
440 Self::setup_channel_sequencer(channel_sequence);
441
442 self.dma_convert(rx_dma, readings).await
443 }
444
445 fn configure_channel(channel: &mut impl AdcChannel<T>) {
446 channel.setup();
447 // write() because we want all other bits to be set to 0.
448 T::regs()
449 .chselr()
450 .write(|w| w.set_chsel(channel.channel().into(), true));
451
452 Self::apply_channel_conf();
453 }
454
455 fn apply_channel_conf() {
456 // Trigger and wait for the channel selection procedure to complete.
457 T::regs().isr().modify(|w| w.set_ccrdy(false));
458 while !T::regs().isr().read().ccrdy() {}
459 }
460
461 fn cancel_conversions() {
462 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
463 T::regs().cr().modify(|reg| {
464 reg.set_adstp(Adstp::STOP);
465 });
466 while T::regs().cr().read().adstart() {}
467 }
468 } 255 }
469} 256}
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 3cdc9d8fb..d6c6f480b 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -3,11 +3,11 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use super::blocking_delay_us; 5use super::blocking_delay_us;
6use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt};
7use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
8use crate::interrupt::{self}; 8use crate::interrupt::{self};
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{rcc, Peri}; 10use crate::{Peri, rcc};
11 11
12pub const VDDA_CALIB_MV: u32 = 3300; 12pub const VDDA_CALIB_MV: u32 = 3300;
13pub const ADC_MAX: u32 = (1 << 12) - 1; 13pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -28,20 +28,12 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
28 } 28 }
29} 29}
30 30
31pub struct Vref; 31impl<T: Instance> super::SealedSpecialConverter<VrefInt> for T {
32impl<T: Instance> AdcChannel<T> for Vref {} 32 const CHANNEL: u8 = 17;
33impl<T: Instance> super::SealedAdcChannel<T> for Vref {
34 fn channel(&self) -> u8 {
35 17
36 }
37} 33}
38 34
39pub struct Temperature; 35impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
40impl<T: Instance> AdcChannel<T> for Temperature {} 36 const CHANNEL: u8 = 16;
41impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
42 fn channel(&self) -> u8 {
43 16
44 }
45} 37}
46 38
47impl<'d, T: Instance> Adc<'d, T> { 39impl<'d, T: Instance> Adc<'d, T> {
@@ -51,7 +43,7 @@ impl<'d, T: Instance> Adc<'d, T> {
51 43
52 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) 44 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
53 // for at least two ADC clock cycles. 45 // for at least two ADC clock cycles.
54 blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1); 46 blocking_delay_us((1_000_000 * 2) / Self::freq().0 as u64 + 1);
55 47
56 // Reset calibration 48 // Reset calibration
57 T::regs().cr2().modify(|reg| reg.set_rstcal(true)); 49 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
@@ -66,15 +58,12 @@ impl<'d, T: Instance> Adc<'d, T> {
66 } 58 }
67 59
68 // One cycle after calibration 60 // One cycle after calibration
69 blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1); 61 blocking_delay_us((1_000_000 * 1) / Self::freq().0 as u64 + 1);
70 62
71 T::Interrupt::unpend(); 63 T::Interrupt::unpend();
72 unsafe { T::Interrupt::enable() }; 64 unsafe { T::Interrupt::enable() };
73 65
74 Self { 66 Self { adc }
75 adc,
76 sample_time: SampleTime::from_bits(0),
77 }
78 } 67 }
79 68
80 fn freq() -> Hertz { 69 fn freq() -> Hertz {
@@ -94,22 +83,18 @@ impl<'d, T: Instance> Adc<'d, T> {
94 } 83 }
95 } 84 }
96 85
97 pub fn enable_vref(&self) -> Vref { 86 pub fn enable_vref(&self) -> super::VrefInt {
98 T::regs().cr2().modify(|reg| { 87 T::regs().cr2().modify(|reg| {
99 reg.set_tsvrefe(true); 88 reg.set_tsvrefe(true);
100 }); 89 });
101 Vref {} 90 super::VrefInt {}
102 } 91 }
103 92
104 pub fn enable_temperature(&self) -> Temperature { 93 pub fn enable_temperature(&self) -> super::Temperature {
105 T::regs().cr2().modify(|reg| { 94 T::regs().cr2().modify(|reg| {
106 reg.set_tsvrefe(true); 95 reg.set_tsvrefe(true);
107 }); 96 });
108 Temperature {} 97 super::Temperature {}
109 }
110
111 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
112 self.sample_time = sample_time;
113 } 98 }
114 99
115 /// Perform a single conversion. 100 /// Perform a single conversion.
@@ -134,8 +119,8 @@ impl<'d, T: Instance> Adc<'d, T> {
134 T::regs().dr().read().0 as u16 119 T::regs().dr().read().0 as u16
135 } 120 }
136 121
137 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 122 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
138 Self::set_channel_sample_time(channel.channel(), self.sample_time); 123 Self::set_channel_sample_time(channel.channel(), sample_time);
139 T::regs().cr1().modify(|reg| { 124 T::regs().cr1().modify(|reg| {
140 reg.set_scan(false); 125 reg.set_scan(false);
141 reg.set_discen(false); 126 reg.set_discen(false);
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 3aeb6f2c7..29bfdac97 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -3,10 +3,10 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use super::blocking_delay_us; 5use super::blocking_delay_us;
6use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt};
7use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
8use crate::time::Hertz; 8use crate::time::Hertz;
9use crate::{interrupt, rcc, Peri}; 9use crate::{Peri, interrupt, rcc};
10 10
11pub const VDDA_CALIB_MV: u32 = 3300; 11pub const VDDA_CALIB_MV: u32 = 3300;
12pub const ADC_MAX: u32 = (1 << 12) - 1; 12pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -29,27 +29,12 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
29 } 29 }
30} 30}
31 31
32pub struct Vref; 32impl<T: Instance> super::SealedSpecialConverter<VrefInt> for T {
33impl<T: Instance> AdcChannel<T> for Vref {} 33 const CHANNEL: u8 = 18;
34impl<T: Instance> super::SealedAdcChannel<T> for Vref {
35 fn channel(&self) -> u8 {
36 18
37 }
38}
39
40impl Vref {
41 /// The value that vref would be if vdda was at 3300mv
42 pub fn value(&self) -> u16 {
43 crate::pac::VREFINTCAL.data().read()
44 }
45} 34}
46 35
47pub struct Temperature; 36impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
48impl<T: Instance> AdcChannel<T> for Temperature {} 37 const CHANNEL: u8 = 16;
49impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
50 fn channel(&self) -> u8 {
51 16
52 }
53} 38}
54 39
55impl<'d, T: Instance> Adc<'d, T> { 40impl<'d, T: Instance> Adc<'d, T> {
@@ -77,7 +62,7 @@ impl<'d, T: Instance> Adc<'d, T> {
77 while T::regs().cr().read().adcal() {} 62 while T::regs().cr().read().adcal() {}
78 63
79 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223). 64 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223).
80 blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1); 65 blocking_delay_us((1_000_000 * 4) / Self::freq().0 as u64 + 1);
81 66
82 // Enable the adc 67 // Enable the adc
83 T::regs().cr().modify(|w| w.set_aden(true)); 68 T::regs().cr().modify(|w| w.set_aden(true));
@@ -90,10 +75,7 @@ impl<'d, T: Instance> Adc<'d, T> {
90 T::Interrupt::enable(); 75 T::Interrupt::enable();
91 } 76 }
92 77
93 Self { 78 Self { adc }
94 adc,
95 sample_time: SampleTime::from_bits(0),
96 }
97 } 79 }
98 80
99 fn freq() -> Hertz { 81 fn freq() -> Hertz {
@@ -112,20 +94,16 @@ impl<'d, T: Instance> Adc<'d, T> {
112 } 94 }
113 } 95 }
114 96
115 pub fn enable_vref(&self) -> Vref { 97 pub fn enable_vref(&self) -> super::VrefInt {
116 T::common_regs().ccr().modify(|w| w.set_vrefen(true)); 98 T::common_regs().ccr().modify(|w| w.set_vrefen(true));
117 99
118 Vref {} 100 super::VrefInt {}
119 } 101 }
120 102
121 pub fn enable_temperature(&self) -> Temperature { 103 pub fn enable_temperature(&self) -> super::Temperature {
122 T::common_regs().ccr().modify(|w| w.set_tsen(true)); 104 T::common_regs().ccr().modify(|w| w.set_tsen(true));
123 105
124 Temperature {} 106 super::Temperature {}
125 }
126
127 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
128 self.sample_time = sample_time;
129 } 107 }
130 108
131 /// Perform a single conversion. 109 /// Perform a single conversion.
@@ -150,8 +128,8 @@ impl<'d, T: Instance> Adc<'d, T> {
150 T::regs().dr().read().rdata() 128 T::regs().dr().read().rdata()
151 } 129 }
152 130
153 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 131 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
154 Self::set_channel_sample_time(channel.channel(), self.sample_time); 132 Self::set_channel_sample_time(channel.channel(), sample_time);
155 133
156 // Configure the channel to sample 134 // Configure the channel to sample
157 T::regs().sqr1().write(|w| w.set_sq(0, channel.channel())); 135 T::regs().sqr1().write(|w| w.set_sq(0, channel.channel()));
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 84613078c..919ac3cc0 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -9,7 +9,7 @@ use super::Resolution;
9use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 9use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
10use crate::interrupt::typelevel::Interrupt; 10use crate::interrupt::typelevel::Interrupt;
11use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::{interrupt, rcc, Peri}; 12use crate::{Peri, interrupt, rcc};
13 13
14const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; 14const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
15 15
@@ -79,7 +79,7 @@ impl<T: Instance> Vref<T> {
79 } 79 }
80 80
81 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { 81 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration {
82 let vref_val = adc.read(self).await; 82 let vref_val = adc.read(self, SampleTime::from(0)).await;
83 Calibration { 83 Calibration {
84 vref_cal: self.calibrated_value(), 84 vref_cal: self.calibrated_value(),
85 vref_val, 85 vref_val,
@@ -270,7 +270,8 @@ impl<'d, T: Instance> Adc<'d, T> {
270 } 270 }
271 } 271 }
272 272
273 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 273 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
274 self.set_sample_time(channel, sample_time).await;
274 self.set_sample_sequence(&[channel.channel()]).await; 275 self.set_sample_sequence(&[channel.channel()]).await;
275 self.convert().await 276 self.convert().await
276 } 277 }
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 43498966f..e93ed945f 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,175 +1,275 @@
1#[cfg(stm32g4)]
2use pac::adc::regs::Difsel as DifselReg;
3#[allow(unused)]
4#[cfg(stm32g4)]
5pub use pac::adc::vals::{Adcaldif, Adstp, Difsel, Dmacfg, Dmaen, Exten, Rovsm, Trovs};
1#[allow(unused)] 6#[allow(unused)]
2#[cfg(stm32h7)] 7#[cfg(stm32h7)]
3use pac::adc::vals::{Adcaldif, Difsel, Exten}; 8use pac::adc::vals::{Adcaldif, Difsel, Exten};
4#[allow(unused)] 9pub use pac::adccommon::vals::{Dual, Presc};
5#[cfg(stm32g4)] 10
6use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; 11use super::{
7use pac::adccommon::vals::Presc; 12 Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime,
8use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; 13 blocking_delay_us,
9 14};
10use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; 15use crate::adc::{AdcRegs, BasicAdcRegs, SealedAdcChannel};
11use crate::adc::SealedAdcChannel; 16use crate::pac::adc::regs::{Smpr, Smpr2, Sqr1, Sqr2, Sqr3, Sqr4};
12use crate::dma::Transfer;
13use crate::time::Hertz; 17use crate::time::Hertz;
14use crate::{pac, rcc, Peri}; 18use crate::{Peri, pac, rcc};
19
20mod injected;
21pub use injected::InjectedAdc;
15 22
16/// Default VREF voltage used for sample conversion to millivolts. 23/// Default VREF voltage used for sample conversion to millivolts.
17pub const VREF_DEFAULT_MV: u32 = 3300; 24pub const VREF_DEFAULT_MV: u32 = 3300;
18/// VREF voltage used for factory calibration of VREFINTCAL register. 25/// VREF voltage used for factory calibration of VREFINTCAL register.
19pub const VREF_CALIB_MV: u32 = 3300; 26pub const VREF_CALIB_MV: u32 = 3300;
20 27
28const NR_INJECTED_RANKS: usize = 4;
29
21/// Max single ADC operation clock frequency 30/// Max single ADC operation clock frequency
22#[cfg(stm32g4)] 31#[cfg(stm32g4)]
23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); 32const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
24#[cfg(stm32h7)] 33#[cfg(stm32h7)]
25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 34const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
26 35
27// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 36fn from_ker_ck(frequency: Hertz) -> Presc {
28/// Internal voltage reference channel. 37 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
29pub struct VrefInt; 38 match raw_prescaler {
30impl<T: Instance + VrefChannel> AdcChannel<T> for VrefInt {} 39 0 => Presc::DIV1,
31impl<T: Instance + VrefChannel> super::SealedAdcChannel<T> for VrefInt { 40 1 => Presc::DIV2,
32 fn channel(&self) -> u8 { 41 2..=3 => Presc::DIV4,
33 T::CHANNEL 42 4..=5 => Presc::DIV6,
43 6..=7 => Presc::DIV8,
44 8..=9 => Presc::DIV10,
45 10..=11 => Presc::DIV12,
46 _ => unimplemented!(),
34 } 47 }
35} 48}
36 49
37/// Internal temperature channel. 50/// ADC configuration
38pub struct Temperature; 51#[derive(Default)]
39impl<T: Instance + TemperatureChannel> AdcChannel<T> for Temperature {} 52pub struct AdcConfig {
40impl<T: Instance + TemperatureChannel> super::SealedAdcChannel<T> for Temperature { 53 pub dual_mode: Option<Dual>,
41 fn channel(&self) -> u8 { 54 pub resolution: Option<Resolution>,
42 T::CHANNEL 55 #[cfg(stm32g4)]
43 } 56 pub oversampling_shift: Option<u8>,
57 #[cfg(stm32g4)]
58 pub oversampling_ratio: Option<u8>,
59 #[cfg(stm32g4)]
60 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
44} 61}
45 62
46/// Internal battery voltage channel. 63// Trigger source for ADC conversions¨
47pub struct Vbat; 64#[derive(Copy, Clone)]
48impl<T: Instance + VBatChannel> AdcChannel<T> for Vbat {} 65pub struct ConversionTrigger {
49impl<T: Instance + VBatChannel> super::SealedAdcChannel<T> for Vbat { 66 // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers
50 fn channel(&self) -> u8 { 67 // Note that Injected and Regular channels uses different mappings
51 T::CHANNEL 68 pub channel: u8,
52 } 69 pub edge: Exten,
53} 70}
54 71
55// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 72impl super::AdcRegs for crate::pac::adc::Adc {
56// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 73 fn data(&self) -> *mut u16 {
57#[allow(unused)] 74 crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
58enum Prescaler { 75 }
59 NotDivided, 76
60 DividedBy2, 77 fn enable(&self) {
61 DividedBy4, 78 // Make sure bits are off
62 DividedBy6, 79 while self.cr().read().addis() {
63 DividedBy8, 80 // spin
64 DividedBy10, 81 }
65 DividedBy12, 82
66 DividedBy16, 83 if !self.cr().read().aden() {
67 DividedBy32, 84 // Enable ADC
68 DividedBy64, 85 self.isr().modify(|reg| {
69 DividedBy128, 86 reg.set_adrdy(true);
70 DividedBy256, 87 });
71} 88 self.cr().modify(|reg| {
89 reg.set_aden(true);
90 });
72 91
73impl Prescaler { 92 while !self.isr().read().adrdy() {
74 fn from_ker_ck(frequency: Hertz) -> Self { 93 // spin
75 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 94 }
76 match raw_prescaler {
77 0 => Self::NotDivided,
78 1 => Self::DividedBy2,
79 2..=3 => Self::DividedBy4,
80 4..=5 => Self::DividedBy6,
81 6..=7 => Self::DividedBy8,
82 8..=9 => Self::DividedBy10,
83 10..=11 => Self::DividedBy12,
84 _ => unimplemented!(),
85 } 95 }
86 } 96 }
87 97
88 fn divisor(&self) -> u32 { 98 fn start(&self) {
89 match self { 99 self.cr().modify(|reg| {
90 Prescaler::NotDivided => 1, 100 reg.set_adstart(true);
91 Prescaler::DividedBy2 => 2, 101 });
92 Prescaler::DividedBy4 => 4, 102 }
93 Prescaler::DividedBy6 => 6, 103
94 Prescaler::DividedBy8 => 8, 104 fn stop(&self) {
95 Prescaler::DividedBy10 => 10, 105 if self.cr().read().adstart() && !self.cr().read().addis() {
96 Prescaler::DividedBy12 => 12, 106 self.cr().modify(|reg| {
97 Prescaler::DividedBy16 => 16, 107 reg.set_adstp(Adstp::STOP);
98 Prescaler::DividedBy32 => 32, 108 });
99 Prescaler::DividedBy64 => 64, 109 // The software must poll ADSTART until the bit is reset before assuming the
100 Prescaler::DividedBy128 => 128, 110 // ADC is completely stopped
101 Prescaler::DividedBy256 => 256, 111 while self.cr().read().adstart() {}
102 } 112 }
113
114 // Disable dma control and continuous conversion, if enabled
115 self.cfgr().modify(|reg| {
116 reg.set_cont(false);
117 reg.set_dmaen(Dmaen::DISABLE);
118 });
103 } 119 }
104 120
105 fn presc(&self) -> Presc { 121 fn convert(&self) {
106 match self { 122 self.isr().modify(|reg| {
107 Prescaler::NotDivided => Presc::DIV1, 123 reg.set_eos(true);
108 Prescaler::DividedBy2 => Presc::DIV2, 124 reg.set_eoc(true);
109 Prescaler::DividedBy4 => Presc::DIV4, 125 });
110 Prescaler::DividedBy6 => Presc::DIV6, 126
111 Prescaler::DividedBy8 => Presc::DIV8, 127 // Start conversion
112 Prescaler::DividedBy10 => Presc::DIV10, 128 self.cr().modify(|reg| {
113 Prescaler::DividedBy12 => Presc::DIV12, 129 reg.set_adstart(true);
114 Prescaler::DividedBy16 => Presc::DIV16, 130 });
115 Prescaler::DividedBy32 => Presc::DIV32, 131
116 Prescaler::DividedBy64 => Presc::DIV64, 132 while !self.isr().read().eos() {
117 Prescaler::DividedBy128 => Presc::DIV128, 133 // spin
118 Prescaler::DividedBy256 => Presc::DIV256,
119 } 134 }
120 } 135 }
121}
122 136
123impl<'d, T: Instance> Adc<'d, T> { 137 fn configure_dma(&self, conversion_mode: ConversionMode) {
124 /// Create a new ADC driver. 138 self.isr().modify(|reg| {
125 pub fn new(adc: Peri<'d, T>) -> Self { 139 reg.set_ovr(true);
126 rcc::enable_and_reset::<T>(); 140 });
127 141
128 let prescaler = Prescaler::from_ker_ck(T::frequency()); 142 self.cfgr().modify(|reg| {
143 reg.set_discen(false); // Convert all channels for each trigger
144 reg.set_dmacfg(match conversion_mode {
145 ConversionMode::Singular => Dmacfg::ONE_SHOT,
146 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
147 });
148 reg.set_dmaen(Dmaen::ENABLE);
149 });
129 150
130 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 151 if let ConversionMode::Repeated(mode) = conversion_mode {
152 match mode {
153 RegularConversionMode::Continuous => {
154 self.cfgr().modify(|reg| {
155 reg.set_cont(true);
156 });
157 }
158 RegularConversionMode::Triggered(trigger) => {
159 self.cfgr().modify(|r| {
160 r.set_cont(false); // New trigger is neede for each sample to be read
161 });
131 162
132 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 163 self.cfgr().modify(|r| {
133 trace!("ADC frequency set to {}", frequency); 164 r.set_extsel(trigger.channel);
165 r.set_exten(trigger.edge);
166 });
134 167
135 if frequency > MAX_ADC_CLK_FREQ { 168 // Regular conversions uses DMA so no need to generate interrupt
136 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 169 self.ier().modify(|r| r.set_eosie(false));
170 }
171 }
137 } 172 }
173 }
138 174
139 let mut s = Self { 175 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
140 adc, 176 self.cr().modify(|w| w.set_aden(false));
141 sample_time: SampleTime::from_bits(0),
142 };
143 s.power_up();
144 s.configure_differential_inputs();
145 177
146 s.calibrate(); 178 #[cfg(stm32g4)]
147 blocking_delay_us(1); 179 let mut difsel = DifselReg::default();
180 let mut smpr = Smpr::default();
181 let mut smpr2 = Smpr2::default();
182 let mut sqr1 = Sqr1::default();
183 let mut sqr2 = Sqr2::default();
184 let mut sqr3 = Sqr3::default();
185 let mut sqr4 = Sqr4::default();
186
187 // Set sequence length
188 sqr1.set_l(sequence.len() as u8 - 1);
189
190 // Configure channels and ranks
191 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() {
192 let sample_time = sample_time.into();
193 if ch <= 9 {
194 smpr.set_smp(ch as _, sample_time);
195 } else {
196 smpr2.set_smp((ch - 10) as _, sample_time);
197 }
198
199 match _i {
200 0..=3 => {
201 sqr1.set_sq(_i, ch);
202 }
203 4..=8 => {
204 sqr2.set_sq(_i - 4, ch);
205 }
206 9..=13 => {
207 sqr3.set_sq(_i - 9, ch);
208 }
209 14..=15 => {
210 sqr4.set_sq(_i - 14, ch);
211 }
212 _ => unreachable!(),
213 }
148 214
149 s.enable(); 215 #[cfg(stm32g4)]
150 s.configure(); 216 {
217 if ch < 18 {
218 difsel.set_difsel(
219 ch.into(),
220 if is_differential {
221 Difsel::DIFFERENTIAL
222 } else {
223 Difsel::SINGLE_ENDED
224 },
225 );
226 }
227 }
228 }
151 229
152 s 230 self.smpr().write_value(smpr);
231 self.smpr2().write_value(smpr2);
232 self.sqr1().write_value(sqr1);
233 self.sqr2().write_value(sqr2);
234 self.sqr3().write_value(sqr3);
235 self.sqr4().write_value(sqr4);
236 #[cfg(stm32g4)]
237 self.difsel().write_value(difsel);
153 } 238 }
239}
240
241impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
242 /// Create a new ADC driver.
243 pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self {
244 rcc::enable_and_reset::<T>();
245
246 let prescaler = from_ker_ck(T::frequency());
247
248 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
249
250 let frequency = T::frequency() / prescaler;
251 trace!("ADC frequency set to {}", frequency);
252
253 if frequency > MAX_ADC_CLK_FREQ {
254 panic!(
255 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
256 MAX_ADC_CLK_FREQ.0 / 1_000_000
257 );
258 }
154 259
155 fn power_up(&mut self) {
156 T::regs().cr().modify(|reg| { 260 T::regs().cr().modify(|reg| {
157 reg.set_deeppwd(false); 261 reg.set_deeppwd(false);
158 reg.set_advregen(true); 262 reg.set_advregen(true);
159 }); 263 });
160 264
161 blocking_delay_us(20); 265 blocking_delay_us(20);
162 }
163 266
164 fn configure_differential_inputs(&mut self) {
165 T::regs().difsel().modify(|w| { 267 T::regs().difsel().modify(|w| {
166 for n in 0..18 { 268 for n in 0..18 {
167 w.set_difsel(n, Difsel::SINGLE_ENDED); 269 w.set_difsel(n, Difsel::SINGLE_ENDED);
168 } 270 }
169 }); 271 });
170 }
171 272
172 fn calibrate(&mut self) {
173 T::regs().cr().modify(|w| { 273 T::regs().cr().modify(|w| {
174 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 274 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
175 }); 275 });
@@ -189,120 +289,79 @@ impl<'d, T: Instance> Adc<'d, T> {
189 while T::regs().cr().read().adcal() {} 289 while T::regs().cr().read().adcal() {}
190 290
191 blocking_delay_us(20); 291 blocking_delay_us(20);
192 }
193 292
194 fn enable(&mut self) { 293 T::regs().enable();
195 // Make sure bits are off
196 while T::regs().cr().read().addis() {
197 // spin
198 }
199
200 if !T::regs().cr().read().aden() {
201 // Enable ADC
202 T::regs().isr().modify(|reg| {
203 reg.set_adrdy(true);
204 });
205 T::regs().cr().modify(|reg| {
206 reg.set_aden(true);
207 });
208
209 while !T::regs().isr().read().adrdy() {
210 // spin
211 }
212 }
213 }
214 294
215 fn configure(&mut self) {
216 // single conversion mode, software trigger 295 // single conversion mode, software trigger
217 T::regs().cfgr().modify(|w| { 296 T::regs().cfgr().modify(|w| {
218 w.set_cont(false); 297 w.set_cont(false);
219 w.set_exten(Exten::DISABLED); 298 w.set_exten(Exten::DISABLED);
220 }); 299 });
300
301 if let Some(dual) = config.dual_mode {
302 T::common_regs().ccr().modify(|reg| {
303 reg.set_dual(dual);
304 })
305 }
306
307 if let Some(resolution) = config.resolution {
308 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
309 }
310
311 #[cfg(stm32g4)]
312 if let Some(shift) = config.oversampling_shift {
313 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
314 }
315
316 #[cfg(stm32g4)]
317 if let Some(ratio) = config.oversampling_ratio {
318 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
319 }
320
321 #[cfg(stm32g4)]
322 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
323 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
324 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
325 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
326 }
327
328 Self { adc }
221 } 329 }
222 330
223 /// Enable reading the voltage reference internal channel. 331 /// Enable reading the voltage reference internal channel.
224 pub fn enable_vrefint(&self) -> VrefInt 332 pub fn enable_vrefint(&self) -> super::VrefInt
225 where 333 where
226 T: VrefChannel, 334 T: super::SpecialConverter<super::VrefInt>,
227 { 335 {
228 T::common_regs().ccr().modify(|reg| { 336 T::common_regs().ccr().modify(|reg| {
229 reg.set_vrefen(true); 337 reg.set_vrefen(true);
230 }); 338 });
231 339
232 VrefInt {} 340 super::VrefInt {}
233 } 341 }
234 342
235 /// Enable reading the temperature internal channel. 343 /// Enable reading the temperature internal channel.
236 pub fn enable_temperature(&self) -> Temperature 344 pub fn enable_temperature(&self) -> super::Temperature
237 where 345 where
238 T: TemperatureChannel, 346 T: super::SpecialConverter<super::Temperature>,
239 { 347 {
240 T::common_regs().ccr().modify(|reg| { 348 T::common_regs().ccr().modify(|reg| {
241 reg.set_vsenseen(true); 349 reg.set_vsenseen(true);
242 }); 350 });
243 351
244 Temperature {} 352 super::Temperature {}
245 } 353 }
246 354
247 /// Enable reading the vbat internal channel. 355 /// Enable reading the vbat internal channel.
248 pub fn enable_vbat(&self) -> Vbat 356 pub fn enable_vbat(&self) -> super::Vbat
249 where 357 where
250 T: VBatChannel, 358 T: super::SpecialConverter<super::Vbat>,
251 { 359 {
252 T::common_regs().ccr().modify(|reg| { 360 T::common_regs().ccr().modify(|reg| {
253 reg.set_vbaten(true); 361 reg.set_vbaten(true);
254 }); 362 });
255 363
256 Vbat {} 364 super::Vbat {}
257 }
258
259 /// Enable differential channel.
260 /// Caution:
261 /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i]
262 /// is connected to another channel. As a consequence, this channel is no longer usable in
263 /// single-ended mode or in differential mode and must never be configured to be converted.
264 /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the
265 /// channel on the other ADC unusable. The only exception is when ADC master and the slave
266 /// operate in interleaved mode.
267 #[cfg(stm32g4)]
268 pub fn set_differential_channel(&mut self, ch: usize, enable: bool) {
269 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
270 T::regs().difsel().modify(|w| {
271 w.set_difsel(
272 ch,
273 if enable {
274 Difsel::DIFFERENTIAL
275 } else {
276 Difsel::SINGLE_ENDED
277 },
278 );
279 });
280 T::regs().cr().modify(|w| w.set_aden(true));
281 }
282
283 #[cfg(stm32g4)]
284 pub fn set_differential(&mut self, channel: &mut impl AdcChannel<T>, enable: bool) {
285 self.set_differential_channel(channel.channel() as usize, enable);
286 }
287
288 /// Set oversampling shift.
289 #[cfg(stm32g4)]
290 pub fn set_oversampling_shift(&mut self, shift: u8) {
291 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
292 }
293
294 /// Set oversampling ratio.
295 #[cfg(stm32g4)]
296 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
297 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
298 }
299
300 /// Enable oversampling in regular mode.
301 #[cfg(stm32g4)]
302 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
303 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
304 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
305 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
306 } 365 }
307 366
308 // Reads that are not implemented as INJECTED in "blocking_read" 367 // Reads that are not implemented as INJECTED in "blocking_read"
@@ -318,260 +377,215 @@ impl<'d, T: Instance> Adc<'d, T> {
318 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); 377 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
319 // } 378 // }
320 379
321 /// Set the ADC sample time. 380 /// Configures the ADC for injected conversions.
322 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
323 self.sample_time = sample_time;
324 }
325
326 /// Set the ADC resolution.
327 pub fn set_resolution(&mut self, resolution: Resolution) {
328 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
329 }
330
331 /// Perform a single conversion.
332 fn convert(&mut self) -> u16 {
333 T::regs().isr().modify(|reg| {
334 reg.set_eos(true);
335 reg.set_eoc(true);
336 });
337
338 // Start conversion
339 T::regs().cr().modify(|reg| {
340 reg.set_adstart(true);
341 });
342
343 while !T::regs().isr().read().eos() {
344 // spin
345 }
346
347 T::regs().dr().read().0 as u16
348 }
349
350 /// Read an ADC pin.
351 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
352 channel.setup();
353
354 self.read_channel(channel)
355 }
356
357 /// Read one or multiple ADC channels using DMA.
358 /// 381 ///
359 /// `sequence` iterator and `readings` must have the same length. 382 /// Injected conversions are separate from the regular conversion sequence and are typically
383 /// triggered by software or an external event. This method sets up a fixed-length sequence of
384 /// injected channels with specified sample times, the trigger source, and whether the end-of-sequence
385 /// interrupt should be enabled.
360 /// 386 ///
361 /// Example 387 /// # Parameters
362 /// ```rust,ignore 388 /// - `sequence`: An array of tuples containing the ADC channels and their sample times. The length
363 /// use embassy_stm32::adc::{Adc, AdcChannel} 389 /// `N` determines the number of injected ranks to configure (maximum 4 for STM32).
390 /// - `trigger`: The trigger source that starts the injected conversion sequence.
391 /// - `interrupt`: If `true`, enables the end-of-sequence (JEOS) interrupt for injected conversions.
364 /// 392 ///
365 /// let mut adc = Adc::new(p.ADC1); 393 /// # Returns
366 /// let mut adc_pin0 = p.PA0.into(); 394 /// An `InjectedAdc<T, N>` instance that represents the configured injected sequence. The returned
367 /// let mut adc_pin1 = p.PA1.into(); 395 /// type encodes the sequence length `N` in its type, ensuring that reads return exactly `N` samples.
368 /// let mut measurements = [0u16; 2];
369 /// 396 ///
370 /// adc.read( 397 /// # Panics
371 /// p.DMA1_CH2.reborrow(), 398 /// This function will panic if:
372 /// [ 399 /// - `sequence` is empty.
373 /// (&mut *adc_pin0, SampleTime::CYCLES160_5), 400 /// - `sequence` length exceeds the maximum number of injected ranks (`NR_INJECTED_RANKS`).
374 /// (&mut *adc_pin1, SampleTime::CYCLES160_5), 401 ///
375 /// ] 402 /// # Notes
376 /// .into_iter(), 403 /// - Injected conversions can run independently of regular ADC conversions.
377 /// &mut measurements, 404 /// - The order of channels in `sequence` determines the rank order in the injected sequence.
378 /// ) 405 /// - Accessing samples beyond `N` will result in a panic; use the returned type
379 /// .await; 406 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
380 /// defmt::info!("measurements: {}", measurements); 407 pub fn setup_injected_conversions<'a, const N: usize>(
381 /// ``` 408 self,
382 pub async fn read( 409 sequence: [(AnyAdcChannel<'a, T>, SampleTime); N],
383 &mut self, 410 trigger: ConversionTrigger,
384 rx_dma: Peri<'_, impl RxDma<T>>, 411 interrupt: bool,
385 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, 412 ) -> InjectedAdc<'a, T, N> {
386 readings: &mut [u16], 413 assert!(N != 0, "Read sequence cannot be empty");
387 ) {
388 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
389 assert!(
390 sequence.len() == readings.len(),
391 "Sequence length must be equal to readings length"
392 );
393 assert!( 414 assert!(
394 sequence.len() <= 16, 415 N <= NR_INJECTED_RANKS,
395 "Asynchronous read sequence cannot be more than 16 in length" 416 "Read sequence cannot be more than {} in length",
417 NR_INJECTED_RANKS
396 ); 418 );
397 419
398 // Ensure no conversions are ongoing and ADC is enabled. 420 T::regs().enable();
399 Self::cancel_conversions();
400 self.enable();
401 421
402 // Set sequence length 422 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
403 T::regs().sqr1().modify(|w| {
404 w.set_l(sequence.len() as u8 - 1);
405 });
406
407 // Configure channels and ranks
408 for (_i, (channel, sample_time)) in sequence.enumerate() {
409 Self::configure_channel(channel, sample_time);
410 423
411 match _i { 424 for (n, (channel, sample_time)) in sequence.iter().enumerate() {
412 0..=3 => { 425 let sample_time = sample_time.clone().into();
413 T::regs().sqr1().modify(|w| { 426 if channel.channel() <= 9 {
414 w.set_sq(_i, channel.channel()); 427 T::regs()
415 }); 428 .smpr()
416 } 429 .modify(|reg| reg.set_smp(channel.channel() as _, sample_time));
417 4..=8 => { 430 } else {
418 T::regs().sqr2().modify(|w| { 431 T::regs()
419 w.set_sq(_i - 4, channel.channel()); 432 .smpr2()
420 }); 433 .modify(|reg| reg.set_smp((channel.channel() - 10) as _, sample_time));
421 }
422 9..=13 => {
423 T::regs().sqr3().modify(|w| {
424 w.set_sq(_i - 9, channel.channel());
425 });
426 }
427 14..=15 => {
428 T::regs().sqr4().modify(|w| {
429 w.set_sq(_i - 14, channel.channel());
430 });
431 }
432 _ => unreachable!(),
433 } 434 }
434 }
435
436 // Set continuous mode with oneshot dma.
437 // Clear overrun flag before starting transfer.
438 T::regs().isr().modify(|reg| {
439 reg.set_ovr(true);
440 });
441 435
442 T::regs().cfgr().modify(|reg| { 436 let idx = match n {
443 reg.set_discen(false); 437 0..=3 => n,
444 reg.set_cont(true); 438 4..=8 => n - 4,
445 reg.set_dmacfg(Dmacfg::ONE_SHOT); 439 9..=13 => n - 9,
446 reg.set_dmaen(Dmaen::ENABLE); 440 14..=15 => n - 14,
447 }); 441 _ => unreachable!(),
448 442 };
449 let request = rx_dma.request();
450 let transfer = unsafe {
451 Transfer::new_read(
452 rx_dma,
453 request,
454 T::regs().dr().as_ptr() as *mut u16,
455 readings,
456 Default::default(),
457 )
458 };
459
460 // Start conversion
461 T::regs().cr().modify(|reg| {
462 reg.set_adstart(true);
463 });
464 443
465 // Wait for conversion sequence to finish. 444 T::regs().jsqr().modify(|w| w.set_jsq(idx, channel.channel()));
466 transfer.await; 445 }
467 446
468 // Ensure conversions are finished. 447 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
469 Self::cancel_conversions();
470 448
471 // Reset configuration. 449 // Set external trigger for injected conversion sequence
472 T::regs().cfgr().modify(|reg| { 450 // Possible trigger values are seen in Table 167 in RM0440 Rev 9
473 reg.set_cont(false); 451 T::regs().jsqr().modify(|r| {
452 r.set_jextsel(trigger.channel);
453 r.set_jexten(trigger.edge);
474 }); 454 });
475 }
476
477 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
478 // Configure channel
479 Self::set_channel_sample_time(channel.channel(), sample_time);
480 }
481 455
482 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 456 // Enable end of injected sequence interrupt
483 Self::configure_channel(channel, self.sample_time); 457 T::regs().ier().modify(|r| r.set_jeosie(interrupt));
484 #[cfg(stm32h7)]
485 {
486 T::regs().cfgr2().modify(|w| w.set_lshift(0));
487 T::regs()
488 .pcsel()
489 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
490 }
491 458
492 T::regs().sqr1().write(|reg| { 459 Self::start_injected_conversions();
493 reg.set_sq(0, channel.channel());
494 reg.set_l(0);
495 });
496 460
497 self.convert() 461 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
498 } 462 }
499 463
500 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 464 /// Configures ADC for both regular conversions with a ring-buffered DMA and injected conversions.
501 let sample_time = sample_time.into(); 465 ///
502 if ch <= 9 { 466 /// # Parameters
503 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); 467 /// - `dma`: The DMA peripheral to use for the ring-buffered ADC transfers.
504 } else { 468 /// - `dma_buf`: The buffer to store DMA-transferred samples for regular conversions.
505 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); 469 /// - `regular_sequence`: The sequence of channels and their sample times for regular conversions.
470 /// - `regular_conversion_mode`: The mode for regular conversions (e.g., continuous or triggered).
471 /// - `injected_sequence`: An array of channels and sample times for injected conversions (length `N`).
472 /// - `injected_trigger`: The trigger source for injected conversions.
473 /// - `injected_interrupt`: Whether to enable the end-of-sequence interrupt for injected conversions.
474 ///
475 /// Injected conversions are typically used with interrupts. If ADC1 and ADC2 are used in dual mode,
476 /// it is recommended to enable interrupts only for the ADC whose sequence takes the longest to complete.
477 ///
478 /// # Returns
479 /// A tuple containing:
480 /// 1. `RingBufferedAdc<'a, T>` — the configured ADC for regular conversions using DMA.
481 /// 2. `InjectedAdc<T, N>` — the configured ADC for injected conversions.
482 ///
483 /// # Safety
484 /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the
485 /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently.
486 /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way.
487 pub fn into_ring_buffered_and_injected<'a, 'b, const N: usize>(
488 self,
489 dma: Peri<'a, impl RxDma<T>>,
490 dma_buf: &'a mut [u16],
491 regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>,
492 regular_conversion_mode: RegularConversionMode,
493 injected_sequence: [(AnyAdcChannel<'b, T>, SampleTime); N],
494 injected_trigger: ConversionTrigger,
495 injected_interrupt: bool,
496 ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<'b, T, N>) {
497 unsafe {
498 (
499 Self {
500 adc: self.adc.clone_unchecked(),
501 }
502 .into_ring_buffered(dma, dma_buf, regular_sequence, regular_conversion_mode),
503 Self {
504 adc: self.adc.clone_unchecked(),
505 }
506 .setup_injected_conversions(injected_sequence, injected_trigger, injected_interrupt),
507 )
506 } 508 }
507 } 509 }
508 510
509 fn cancel_conversions() { 511 /// Stop injected conversions
512 pub(super) fn stop_injected_conversions() {
510 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 513 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
511 T::regs().cr().modify(|reg| { 514 T::regs().cr().modify(|reg| {
512 reg.set_adstp(Adstp::STOP); 515 reg.set_jadstp(Adstp::STOP);
513 }); 516 });
514 while T::regs().cr().read().adstart() {} 517 // The software must poll JADSTART until the bit is reset before assuming the
518 // ADC is completely stopped
519 while T::regs().cr().read().jadstart() {}
515 } 520 }
516 } 521 }
517}
518 522
519/// Implemented for ADCs that have a Temperature channel 523 /// Start injected ADC conversion
520pub trait TemperatureChannel { 524 pub(super) fn start_injected_conversions() {
521 const CHANNEL: u8; 525 T::regs().cr().modify(|reg| {
522} 526 reg.set_jadstart(true);
523/// Implemented for ADCs that have a Vref channel 527 });
524pub trait VrefChannel { 528 }
525 const CHANNEL: u8;
526} 529}
527/// Implemented for ADCs that have a VBat channel 530
528pub trait VBatChannel { 531impl<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> InjectedAdc<'a, T, N> {
529 const CHANNEL: u8; 532 /// Read sampled data from all injected ADC injected ranks
533 /// Clear the JEOS flag to allow a new injected sequence
534 pub(super) fn read_injected_data() -> [u16; N] {
535 let mut data = [0u16; N];
536 for i in 0..N {
537 data[i] = T::regs().jdr(i).read().jdata();
538 }
539
540 // Clear JEOS by writing 1
541 T::regs().isr().modify(|r| r.set_jeos(true));
542 data
543 }
530} 544}
531 545
532#[cfg(stm32g4)] 546#[cfg(stm32g4)]
533mod g4 { 547mod g4 {
534 pub use super::*; 548 use crate::adc::{SealedSpecialConverter, Temperature, Vbat, VrefInt};
535 549
536 impl TemperatureChannel for crate::peripherals::ADC1 { 550 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC1 {
537 const CHANNEL: u8 = 16; 551 const CHANNEL: u8 = 16;
538 } 552 }
539 553
540 impl VrefChannel for crate::peripherals::ADC1 { 554 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC1 {
541 const CHANNEL: u8 = 18; 555 const CHANNEL: u8 = 18;
542 } 556 }
543 557
544 impl VBatChannel for crate::peripherals::ADC1 { 558 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC1 {
545 const CHANNEL: u8 = 17; 559 const CHANNEL: u8 = 17;
546 } 560 }
547 561
548 #[cfg(peri_adc3_common)] 562 #[cfg(peri_adc3_common)]
549 impl VrefChannel for crate::peripherals::ADC3 { 563 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC3 {
550 const CHANNEL: u8 = 18; 564 const CHANNEL: u8 = 18;
551 } 565 }
552 566
553 #[cfg(peri_adc3_common)] 567 #[cfg(peri_adc3_common)]
554 impl VBatChannel for crate::peripherals::ADC3 { 568 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC3 {
555 const CHANNEL: u8 = 17; 569 const CHANNEL: u8 = 17;
556 } 570 }
557 571
558 #[cfg(not(stm32g4x1))] 572 #[cfg(not(stm32g4x1))]
559 impl VrefChannel for crate::peripherals::ADC4 { 573 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC4 {
560 const CHANNEL: u8 = 18; 574 const CHANNEL: u8 = 18;
561 } 575 }
562 576
563 #[cfg(not(stm32g4x1))] 577 #[cfg(not(stm32g4x1))]
564 impl TemperatureChannel for crate::peripherals::ADC5 { 578 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC5 {
565 const CHANNEL: u8 = 4; 579 const CHANNEL: u8 = 4;
566 } 580 }
567 581
568 #[cfg(not(stm32g4x1))] 582 #[cfg(not(stm32g4x1))]
569 impl VrefChannel for crate::peripherals::ADC5 { 583 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC5 {
570 const CHANNEL: u8 = 18; 584 const CHANNEL: u8 = 18;
571 } 585 }
572 586
573 #[cfg(not(stm32g4x1))] 587 #[cfg(not(stm32g4x1))]
574 impl VBatChannel for crate::peripherals::ADC5 { 588 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC5 {
575 const CHANNEL: u8 = 17; 589 const CHANNEL: u8 = 17;
576 } 590 }
577} 591}
@@ -579,13 +593,13 @@ mod g4 {
579// TODO this should look at each ADC individually and impl the correct channels 593// TODO this should look at each ADC individually and impl the correct channels
580#[cfg(stm32h7)] 594#[cfg(stm32h7)]
581mod h7 { 595mod h7 {
582 impl<T: Instance> TemperatureChannel for T { 596 impl<T: Instance> SealedSpecialConverter<Temperature> for T {
583 const CHANNEL: u8 = 18; 597 const CHANNEL: u8 = 18;
584 } 598 }
585 impl<T: Instance> VrefChannel for T { 599 impl<T: Instance> SealedSpecialConverter<VrefInt> for T {
586 const CHANNEL: u8 = 19; 600 const CHANNEL: u8 = 19;
587 } 601 }
588 impl<T: Instance> VBatChannel for T { 602 impl<T: Instance> SealedSpecialConverter<Vbat> for T {
589 // TODO this should be 14 for H7a/b/35 603 // TODO this should be 14 for H7a/b/35
590 const CHANNEL: u8 = 17; 604 const CHANNEL: u8 = 17;
591 } 605 }
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs
new file mode 100644
index 000000000..029722b84
--- /dev/null
+++ b/embassy-stm32/src/adc/injected.rs
@@ -0,0 +1,44 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use super::{AdcRegs, AnyAdcChannel, SampleTime};
8use crate::adc::Adc;
9#[allow(unused_imports)]
10use crate::adc::Instance;
11
12/// Injected ADC sequence with owned channels.
13pub struct InjectedAdc<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> {
14 _channels: [(AnyAdcChannel<'a, T>, SampleTime); N],
15 _phantom: PhantomData<T>,
16}
17
18impl<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> InjectedAdc<'a, T, N> {
19 pub(crate) fn new(channels: [(AnyAdcChannel<'a, T>, SampleTime); N]) -> Self {
20 Self {
21 _channels: channels,
22 _phantom: PhantomData,
23 }
24 }
25
26 pub fn stop_injected_conversions(&mut self) {
27 Adc::<T>::stop_injected_conversions()
28 }
29
30 pub fn start_injected_conversions(&mut self) {
31 Adc::<T>::start_injected_conversions()
32 }
33
34 pub fn read_injected_samples(&mut self) -> [u16; N] {
35 InjectedAdc::<T, N>::read_injected_data()
36 }
37}
38
39impl<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> Drop for InjectedAdc<'a, T, N> {
40 fn drop(&mut self) {
41 T::regs().stop();
42 compiler_fence(Ordering::SeqCst);
43 }
44}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index ea986f4cf..da432f6ce 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -17,38 +17,44 @@
17#[cfg_attr(adc_c0, path = "c0.rs")] 17#[cfg_attr(adc_c0, path = "c0.rs")]
18mod _version; 18mod _version;
19 19
20#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
21mod ringbuffered;
22
20use core::marker::PhantomData; 23use core::marker::PhantomData;
21 24
22#[allow(unused)] 25#[allow(unused)]
23#[cfg(not(any(adc_f3v3, adc_wba)))] 26#[cfg(not(any(adc_f3v3, adc_wba)))]
24pub use _version::*; 27pub use _version::*;
25use embassy_hal_internal::{impl_peripheral, PeripheralType}; 28#[allow(unused)]
29use embassy_hal_internal::PeripheralType;
26#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] 30#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))]
27use embassy_sync::waitqueue::AtomicWaker; 31use embassy_sync::waitqueue::AtomicWaker;
32#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
33pub use ringbuffered::RingBufferedAdc;
34
35#[cfg(adc_u5)]
36use crate::pac::adc::vals::Adc4SampleTime;
37#[cfg(adc_wba)]
38use crate::pac::adc::vals::SampleTime as Adc4SampleTime;
28 39
29#[cfg(any(adc_u5, adc_wba))] 40#[cfg(any(adc_u5, adc_wba))]
30#[path = "adc4.rs"] 41#[path = "adc4.rs"]
31pub mod adc4; 42pub mod adc4;
32 43
44#[allow(unused)]
45pub(self) use crate::block_for_us as blocking_delay_us;
33pub use crate::pac::adc::vals; 46pub use crate::pac::adc::vals;
34#[cfg(not(any(adc_f1, adc_f3v3)))] 47#[cfg(not(any(adc_f1, adc_f3v3)))]
35pub use crate::pac::adc::vals::Res as Resolution; 48pub use crate::pac::adc::vals::Res as Resolution;
36pub use crate::pac::adc::vals::SampleTime; 49pub use crate::pac::adc::vals::SampleTime;
37use crate::peripherals; 50use crate::peripherals;
38 51
39#[cfg(not(adc_wba))]
40dma_trait!(RxDma, Instance); 52dma_trait!(RxDma, Instance);
41#[cfg(adc_u5)]
42dma_trait!(RxDma4, adc4::Instance);
43#[cfg(adc_wba)]
44dma_trait!(RxDma4, adc4::Instance);
45 53
46/// Analog to Digital driver. 54/// Analog to Digital driver.
47pub struct Adc<'d, T: Instance> { 55pub struct Adc<'d, T: Instance> {
48 #[allow(unused)] 56 #[allow(unused)]
49 adc: crate::Peri<'d, T>, 57 adc: crate::Peri<'d, T>,
50 #[cfg(not(any(adc_f3v3, adc_f3v2, adc_wba)))]
51 sample_time: SampleTime,
52} 58}
53 59
54#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] 60#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))]
@@ -65,10 +71,53 @@ impl State {
65 } 71 }
66} 72}
67 73
68trait SealedInstance { 74#[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))]
69 #[cfg(not(adc_wba))] 75trait_set::trait_set! {
70 #[allow(unused)] 76 pub trait DefaultInstance = Instance;
77}
78
79#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_g4, adc_c0))]
80trait_set::trait_set! {
81 pub trait DefaultInstance = Instance<Regs = crate::pac::adc::Adc>;
82}
83
84#[cfg(adc_wba)]
85trait_set::trait_set! {
86 pub trait DefaultInstance = Instance<Regs = crate::pac::adc::Adc4>;
87}
88
89pub trait BasicAdcRegs {
90 type SampleTime;
91}
92
93#[cfg(any(
94 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
95))]
96trait AdcRegs: BasicAdcRegs {
97 fn enable(&self);
98 fn start(&self);
99 fn stop(&self);
100 fn convert(&self);
101 fn configure_dma(&self, conversion_mode: ConversionMode);
102 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>);
103 fn data(&self) -> *mut u16;
104}
105
106#[allow(private_bounds)]
107pub trait BasicInstance {
108 #[cfg(any(
109 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
110 ))]
111 type Regs: AdcRegs;
112}
113
114trait SealedInstance: BasicInstance {
115 #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))]
71 fn regs() -> crate::pac::adc::Adc; 116 fn regs() -> crate::pac::adc::Adc;
117 #[cfg(any(
118 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
119 ))]
120 fn regs() -> Self::Regs;
72 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))] 121 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))]
73 #[allow(unused)] 122 #[allow(unused)]
74 fn common_regs() -> crate::pac::adccommon::AdcCommon; 123 fn common_regs() -> crate::pac::adccommon::AdcCommon;
@@ -77,27 +126,278 @@ trait SealedInstance {
77} 126}
78 127
79pub(crate) trait SealedAdcChannel<T> { 128pub(crate) trait SealedAdcChannel<T> {
80 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 129 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
81 fn setup(&mut self) {} 130 fn setup(&mut self) {}
82 131
83 #[allow(unused)] 132 #[allow(unused)]
84 fn channel(&self) -> u8; 133 fn channel(&self) -> u8;
134
135 #[allow(unused)]
136 fn is_differential(&self) -> bool {
137 false
138 }
85} 139}
86 140
87/// Performs a busy-wait delay for a specified number of microseconds. 141#[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
88#[allow(unused)] 142/// Number of samples used for averaging.
89pub(crate) fn blocking_delay_us(us: u32) { 143#[derive(Copy, Clone, Debug)]
90 #[cfg(feature = "time")] 144#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91 embassy_time::block_for(embassy_time::Duration::from_micros(us as u64)); 145pub enum Averaging {
92 #[cfg(not(feature = "time"))] 146 Disabled,
93 { 147 Samples2,
94 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; 148 Samples4,
95 let us = us as u64; 149 Samples8,
96 let cycles = freq * us / 1_000_000; 150 Samples16,
97 cortex_m::asm::delay(cycles as u32); 151 Samples32,
152 Samples64,
153 Samples128,
154 Samples256,
155 #[cfg(any(adc_c0, adc_v4, adc_u5))]
156 Samples512,
157 #[cfg(any(adc_c0, adc_v4, adc_u5))]
158 Samples1024,
159}
160
161#[cfg(any(
162 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0
163))]
164pub(crate) enum ConversionMode {
165 // Should match the cfg on "read" below
166 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
167 Singular,
168 // Should match the cfg on "into_ring_buffered" below
169 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
170 Repeated(RegularConversionMode),
171}
172
173// Should match the cfg on "into_ring_buffered" below
174#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
175// Conversion mode for regular ADC channels
176#[derive(Copy, Clone)]
177pub enum RegularConversionMode {
178 // Samples as fast as possible
179 Continuous,
180 #[cfg(adc_g4)]
181 // Sample at rate determined by external trigger
182 Triggered(ConversionTrigger),
183}
184
185impl<'d, T: Instance> Adc<'d, T> {
186 #[cfg(any(
187 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v3, adc_v4, adc_wba, adc_c0
188 ))]
189 /// Read an ADC pin.
190 pub fn blocking_read(
191 &mut self,
192 channel: &mut impl AdcChannel<T>,
193 sample_time: <T::Regs as BasicAdcRegs>::SampleTime,
194 ) -> u16 {
195 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
196 channel.setup();
197
198 // Ensure no conversions are ongoing
199 T::regs().stop();
200 #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))]
201 T::regs().enable();
202 T::regs().configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
203
204 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
205 //
206 // TODO: If hardware allows, enable after configure_sequence on all chips
207 #[cfg(any(adc_g4, adc_h5))]
208 T::regs().enable();
209 T::regs().convert();
210
211 unsafe { core::ptr::read_volatile(T::regs().data()) }
212 }
213
214 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
215 /// Read one or multiple ADC regular channels using DMA.
216 ///
217 /// `sequence` iterator and `readings` must have the same length.
218 ///
219 /// Example
220 /// ```rust,ignore
221 /// use embassy_stm32::adc::{Adc, AdcChannel}
222 ///
223 /// let mut adc = Adc::new(p.ADC1);
224 /// let mut adc_pin0 = p.PA0.into();
225 /// let mut adc_pin1 = p.PA1.into();
226 /// let mut measurements = [0u16; 2];
227 ///
228 /// adc.read(
229 /// p.DMA1_CH2.reborrow(),
230 /// [
231 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
232 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
233 /// ]
234 /// .into_iter(),
235 /// &mut measurements,
236 /// )
237 /// .await;
238 /// defmt::info!("measurements: {}", measurements);
239 /// ```
240 ///
241 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
242 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
243 ///
244 /// Note: Depending on hardware limitations, this method may require channels to be passed
245 /// in order or require the sequence to have the same sample time for all channnels, depending
246 /// on the number and properties of the channels in the sequence. This method will panic if
247 /// the hardware cannot deliver the requested configuration.
248 pub async fn read<'a, 'b: 'a>(
249 &mut self,
250 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
251 sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>,
252 readings: &mut [u16],
253 ) {
254 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
255 assert!(
256 sequence.len() == readings.len(),
257 "Sequence length must be equal to readings length"
258 );
259 assert!(
260 sequence.len() <= 16,
261 "Asynchronous read sequence cannot be more than 16 in length"
262 );
263
264 // Ensure no conversions are ongoing
265 T::regs().stop();
266 #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
267 T::regs().enable();
268
269 T::regs().configure_sequence(
270 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
271 );
272
273 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
274 //
275 // TODO: If hardware allows, enable after configure_sequence on all chips
276 #[cfg(any(adc_g4, adc_h5))]
277 T::regs().enable();
278 T::regs().configure_dma(ConversionMode::Singular);
279
280 let request = rx_dma.request();
281 let transfer =
282 unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::regs().data(), readings, Default::default()) };
283
284 T::regs().start();
285
286 // Wait for conversion sequence to finish.
287 transfer.await;
288
289 // Ensure conversions are finished.
290 T::regs().stop();
291 }
292
293 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
294 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
295 ///
296 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
297 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
298 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
299 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
300 /// defines the period at which the buffer should be read.
301 ///
302 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
303 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
304 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
305 /// the buffer length should be `3 * 40 = 120`.
306 ///
307 /// # Parameters
308 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
309 /// - `dma_buf`: The buffer where DMA stores ADC samples.
310 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
311 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
312 ///
313 /// # Returns
314 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
315 ///
316 /// Note: Depending on hardware limitations, this method may require channels to be passed
317 /// in order or require the sequence to have the same sample time for all channnels, depending
318 /// on the number and properties of the channels in the sequence. This method will panic if
319 /// the hardware cannot deliver the requested configuration.
320 pub fn into_ring_buffered<'a, 'b>(
321 self,
322 dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>,
323 dma_buf: &'a mut [u16],
324 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>,
325 mode: RegularConversionMode,
326 ) -> RingBufferedAdc<'a, T> {
327 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
328 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
329 assert!(
330 sequence.len() <= 16,
331 "Asynchronous read sequence cannot be more than 16 in length"
332 );
333 // Ensure no conversions are ongoing
334 T::regs().stop();
335 #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
336 T::regs().enable();
337
338 T::regs().configure_sequence(
339 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
340 );
341
342 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
343 //
344 // TODO: If hardware allows, enable after configure_sequence on all chips
345 #[cfg(any(adc_g4, adc_h5))]
346 T::regs().enable();
347 T::regs().configure_dma(ConversionMode::Repeated(mode));
348
349 core::mem::forget(self);
350
351 RingBufferedAdc::new(dma, dma_buf)
352 }
353}
354
355pub(self) trait SpecialChannel {}
356
357/// Implemented for ADCs that have a special channel
358trait SealedSpecialConverter<T: SpecialChannel + Sized> {
359 const CHANNEL: u8;
360}
361
362#[allow(private_bounds)]
363pub trait SpecialConverter<T: SpecialChannel + Sized>: SealedSpecialConverter<T> {}
364
365impl<C: SpecialChannel + Sized, T: SealedSpecialConverter<C>> SpecialConverter<C> for T {}
366
367impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> AdcChannel<T> for C {}
368impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> SealedAdcChannel<T> for C {
369 fn channel(&self) -> u8 {
370 T::CHANNEL
98 } 371 }
99} 372}
100 373
374pub struct VrefInt;
375impl SpecialChannel for VrefInt {}
376
377impl VrefInt {
378 #[cfg(any(adc_f3v1, adc_f3v2))]
379 /// The value that vref would be if vdda was at 3300mv
380 pub fn calibrated_value(&self) -> u16 {
381 crate::pac::VREFINTCAL.data().read()
382 }
383}
384
385/// Internal temperature channel.
386pub struct Temperature;
387impl SpecialChannel for Temperature {}
388
389/// Internal battery voltage channel.
390pub struct Vbat;
391impl SpecialChannel for Vbat {}
392
393/// Vcore channel.
394pub struct Vcore;
395impl SpecialChannel for Vcore {}
396
397/// Internal dac channel.
398pub struct Dac;
399impl SpecialChannel for Dac {}
400
101/// ADC instance. 401/// ADC instance.
102#[cfg(not(any( 402#[cfg(not(any(
103 adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, 403 adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs,
@@ -121,12 +421,16 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri
121#[allow(private_bounds)] 421#[allow(private_bounds)]
122pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { 422pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
123 #[allow(unused_mut)] 423 #[allow(unused_mut)]
124 fn degrade_adc(mut self) -> AnyAdcChannel<T> { 424 fn degrade_adc<'a>(mut self) -> AnyAdcChannel<'a, T>
125 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 425 where
426 Self: 'a,
427 {
428 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
126 self.setup(); 429 self.setup();
127 430
128 AnyAdcChannel { 431 AnyAdcChannel {
129 channel: self.channel(), 432 channel: self.channel(),
433 is_differential: self.is_differential(),
130 _phantom: PhantomData, 434 _phantom: PhantomData,
131 } 435 }
132 } 436 }
@@ -136,34 +440,57 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
136/// 440///
137/// This is useful in scenarios where you need the ADC channels to have the same type, such as 441/// This is useful in scenarios where you need the ADC channels to have the same type, such as
138/// storing them in an array. 442/// storing them in an array.
139pub struct AnyAdcChannel<T> { 443pub struct AnyAdcChannel<'a, T> {
140 channel: u8, 444 channel: u8,
141 _phantom: PhantomData<T>, 445 is_differential: bool,
446 _phantom: PhantomData<&'a mut T>,
142} 447}
143impl_peripheral!(AnyAdcChannel<T: Instance>); 448impl<T: Instance> AdcChannel<T> for AnyAdcChannel<'_, T> {}
144impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {} 449impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<'_, T> {
145impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
146 fn channel(&self) -> u8 { 450 fn channel(&self) -> u8 {
147 self.channel 451 self.channel
148 } 452 }
453
454 fn is_differential(&self) -> bool {
455 self.is_differential
456 }
149} 457}
150 458
151impl<T> AnyAdcChannel<T> { 459impl<T> AnyAdcChannel<'_, T> {
152 #[allow(unused)] 460 #[allow(unused)]
153 pub fn get_hw_channel(&self) -> u8 { 461 pub fn get_hw_channel(&self) -> u8 {
154 self.channel 462 self.channel
155 } 463 }
156} 464}
465
466#[cfg(not(adc_wba))]
467impl BasicAdcRegs for crate::pac::adc::Adc {
468 type SampleTime = SampleTime;
469}
470
471#[cfg(any(adc_wba, adc_u5))]
472impl BasicAdcRegs for crate::pac::adc::Adc4 {
473 type SampleTime = Adc4SampleTime;
474}
475
157#[cfg(adc_wba)] 476#[cfg(adc_wba)]
158foreach_adc!( 477foreach_adc!(
159 (ADC4, $common_inst:ident, $clock:ident) => { 478 (ADC4, $common_inst:ident, $clock:ident) => {
160 impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { 479 impl crate::adc::BasicInstance for peripherals::ADC4 {
161 fn regs() -> crate::pac::adc::Adc4 { 480 type Regs = crate::pac::adc::Adc4;
481 }
482
483 impl crate::adc::SealedInstance for peripherals::ADC4 {
484 fn regs() -> Self::Regs {
162 crate::pac::ADC4 485 crate::pac::ADC4
163 } 486 }
487
488 fn common_regs() -> crate::pac::adccommon::AdcCommon {
489 return crate::pac::$common_inst
490 }
164 } 491 }
165 492
166 impl crate::adc::adc4::Instance for peripherals::ADC4 { 493 impl crate::adc::Instance for peripherals::ADC4 {
167 type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; 494 type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL;
168 } 495 }
169 }; 496 };
@@ -188,20 +515,32 @@ foreach_adc!(
188#[cfg(adc_u5)] 515#[cfg(adc_u5)]
189foreach_adc!( 516foreach_adc!(
190 (ADC4, $common_inst:ident, $clock:ident) => { 517 (ADC4, $common_inst:ident, $clock:ident) => {
191 impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { 518 impl crate::adc::BasicInstance for peripherals::ADC4 {
192 fn regs() -> crate::pac::adc::Adc4 { 519 type Regs = crate::pac::adc::Adc4;
520 }
521
522 impl crate::adc::SealedInstance for peripherals::ADC4 {
523 fn regs() -> Self::Regs {
193 crate::pac::ADC4 524 crate::pac::ADC4
194 } 525 }
526
527 fn common_regs() -> crate::pac::adccommon::AdcCommon {
528 return crate::pac::$common_inst
529 }
195 } 530 }
196 531
197 impl crate::adc::adc4::Instance for peripherals::ADC4 { 532 impl crate::adc::Instance for peripherals::ADC4 {
198 type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; 533 type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL;
199 } 534 }
200 }; 535 };
201 536
202 ($inst:ident, $common_inst:ident, $clock:ident) => { 537 ($inst:ident, $common_inst:ident, $clock:ident) => {
538 impl crate::adc::BasicInstance for peripherals::$inst {
539 type Regs = crate::pac::adc::Adc;
540 }
541
203 impl crate::adc::SealedInstance for peripherals::$inst { 542 impl crate::adc::SealedInstance for peripherals::$inst {
204 fn regs() -> crate::pac::adc::Adc { 543 fn regs() -> Self::Regs {
205 crate::pac::$inst 544 crate::pac::$inst
206 } 545 }
207 546
@@ -219,14 +558,23 @@ foreach_adc!(
219#[cfg(not(any(adc_u5, adc_wba)))] 558#[cfg(not(any(adc_u5, adc_wba)))]
220foreach_adc!( 559foreach_adc!(
221 ($inst:ident, $common_inst:ident, $clock:ident) => { 560 ($inst:ident, $common_inst:ident, $clock:ident) => {
561 impl crate::adc::BasicInstance for peripherals::$inst {
562 #[cfg(any(
563 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
564 ))]
565 type Regs = crate::pac::adc::Adc;
566 }
567
222 impl crate::adc::SealedInstance for peripherals::$inst { 568 impl crate::adc::SealedInstance for peripherals::$inst {
223 #[cfg(not(adc_wba))] 569 #[cfg(any(
224 fn regs() -> crate::pac::adc::Adc { 570 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
571 ))]
572 fn regs() -> Self::Regs {
225 crate::pac::$inst 573 crate::pac::$inst
226 } 574 }
227 575
228 #[cfg(adc_wba)] 576 #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))]
229 fn regs() -> crate::pac::adc::Adc4 { 577 fn regs() -> crate::pac::adc::Adc {
230 crate::pac::$inst 578 crate::pac::$inst
231 } 579 }
232 580
@@ -252,7 +600,7 @@ macro_rules! impl_adc_pin {
252 ($inst:ident, $pin:ident, $ch:expr) => { 600 ($inst:ident, $pin:ident, $ch:expr) => {
253 impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {} 601 impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {}
254 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> { 602 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {
255 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 603 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
256 fn setup(&mut self) { 604 fn setup(&mut self) {
257 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self); 605 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self);
258 } 606 }
@@ -264,6 +612,39 @@ macro_rules! impl_adc_pin {
264 }; 612 };
265} 613}
266 614
615#[allow(unused_macros)]
616macro_rules! impl_adc_pair {
617 ($inst:ident, $pin:ident, $npin:ident, $ch:expr) => {
618 impl crate::adc::AdcChannel<peripherals::$inst>
619 for (
620 crate::Peri<'_, crate::peripherals::$pin>,
621 crate::Peri<'_, crate::peripherals::$npin>,
622 )
623 {
624 }
625 impl crate::adc::SealedAdcChannel<peripherals::$inst>
626 for (
627 crate::Peri<'_, crate::peripherals::$pin>,
628 crate::Peri<'_, crate::peripherals::$npin>,
629 )
630 {
631 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
632 fn setup(&mut self) {
633 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0);
634 <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1);
635 }
636
637 fn channel(&self) -> u8 {
638 $ch
639 }
640
641 fn is_differential(&self) -> bool {
642 true
643 }
644 }
645 };
646}
647
267/// Get the maximum reading value for this resolution. 648/// Get the maximum reading value for this resolution.
268/// 649///
269/// This is `2**n - 1`. 650/// This is `2**n - 1`.
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs
new file mode 100644
index 000000000..242a1a89c
--- /dev/null
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -0,0 +1,180 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use super::AdcRegs;
8#[allow(unused_imports)]
9use crate::adc::{Instance, RxDma};
10#[allow(unused_imports)]
11use crate::dma::{ReadableRingBuffer, TransferOptions};
12use crate::rcc;
13
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub struct OverrunError;
16
17pub struct RingBufferedAdc<'d, T: Instance> {
18 _phantom: PhantomData<T>,
19 ring_buf: ReadableRingBuffer<'d, u16>,
20}
21
22impl<'d, T: Instance> RingBufferedAdc<'d, T> {
23 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self {
24 //dma side setup
25 let opts = TransferOptions {
26 half_transfer_ir: true,
27 circular: true,
28 ..Default::default()
29 };
30
31 // Safety: we forget the struct before this function returns.
32 let request = dma.request();
33
34 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, T::regs().data(), dma_buf, opts) };
35
36 Self {
37 _phantom: PhantomData,
38 ring_buf,
39 }
40 }
41
42 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
43 pub fn start(&mut self) {
44 compiler_fence(Ordering::SeqCst);
45 self.ring_buf.start();
46
47 T::regs().start();
48 }
49
50 pub fn stop(&mut self) {
51 self.ring_buf.request_pause();
52
53 compiler_fence(Ordering::SeqCst);
54 }
55
56 pub fn clear(&mut self) {
57 self.ring_buf.clear();
58 }
59
60 /// Reads measurements from the DMA ring buffer.
61 ///
62 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
63 /// The length of the `measurements` array should be exactly half of the DMA buffer length.
64 /// Because interrupts are only generated if half or full DMA transfer completes.
65 ///
66 /// Each call to `read` will populate the `measurements` array in the same order as the channels
67 /// defined with `sequence`. There will be many sequences worth of measurements in this array
68 /// because it only returns if at least half of the DMA buffer is filled. For example if 2
69 /// channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`.
70 ///
71 /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly
72 /// running tasks. Otherwise, you'll see constant Overrun errors occurring, this means that
73 /// you're sampling too quickly for the task to handle, and you may need to increase the buffer size.
74 /// Example:
75 /// ```rust,ignore
76 /// const DMA_BUF_LEN: usize = 120;
77 /// use embassy_stm32::adc::{Adc, AdcChannel}
78 ///
79 /// let mut adc = Adc::new(p.ADC1);
80 /// let mut adc_pin0 = p.PA0.degrade_adc();
81 /// let mut adc_pin1 = p.PA1.degrade_adc();
82 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
83 ///
84 /// let mut ring_buffered_adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
85 /// p.DMA2_CH0,
86 /// adc_dma_buf, [
87 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
88 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
89 /// ].into_iter());
90 ///
91 ///
92 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
93 /// loop {
94 /// match ring_buffered_adc.read(&mut measurements).await {
95 /// Ok(_) => {
96 /// defmt::info!("adc1: {}", measurements);
97 /// }
98 /// Err(e) => {
99 /// defmt::warn!("Error: {:?}", e);
100 /// }
101 /// }
102 /// }
103 /// ```
104 ///
105 ///
106 /// [`teardown_adc`]: #method.teardown_adc
107 /// [`start_continuous_sampling`]: #method.start_continuous_sampling
108 pub async fn read(&mut self, measurements: &mut [u16]) -> Result<usize, OverrunError> {
109 assert_eq!(
110 self.ring_buf.capacity() / 2,
111 measurements.len(),
112 "Buffer size must be half the size of the ring buffer"
113 );
114
115 if !self.ring_buf.is_running() {
116 self.start();
117 }
118
119 // #[cfg(adc_v2)]
120 // {
121 // // Clear overrun flag if set.
122 // if T::regs().sr().read().ovr() {
123 // self.stop();
124 //
125 // return Err(OverrunError);
126 // }
127 // }
128
129 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
130 }
131
132 /// Read bytes that are readily available in the ring buffer.
133 /// If no bytes are currently available in the buffer the call waits until the some
134 /// bytes are available (at least one byte and at most half the buffer size)
135 ///
136 /// Background receive is started if `start_continuous_sampling()` has not been previously called.
137 ///
138 /// Receive in the background is terminated if an error is returned.
139 /// It must then manually be started again by calling `start_continuous_sampling()` or by re-calling `blocking_read()`.
140 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
141 if !self.ring_buf.is_running() {
142 self.start();
143 }
144
145 // #[cfg(adc_v2)]
146 // {
147 // // Clear overrun flag if set.
148 // if T::regs().sr().read().ovr() {
149 // self.stop();
150 //
151 // return Err(OverrunError);
152 // }
153 // }
154
155 loop {
156 match self.ring_buf.read(buf) {
157 Ok((0, _)) => {}
158 Ok((len, _)) => {
159 return Ok(len);
160 }
161 Err(_) => {
162 self.ring_buf.request_pause();
163
164 return Err(OverrunError);
165 }
166 }
167 }
168 }
169}
170
171impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
172 fn drop(&mut self) {
173 T::regs().stop();
174
175 compiler_fence(Ordering::SeqCst);
176
177 self.ring_buf.request_pause();
178 rcc::disable::<T>();
179 }
180}
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
deleted file mode 100644
index 6f69e8486..000000000
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ /dev/null
@@ -1,432 +0,0 @@
1use core::marker::PhantomData;
2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering};
4
5use stm32_metapac::adc::vals::SampleTime;
6
7use crate::adc::{Adc, AdcChannel, Instance, RxDma};
8use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
9use crate::pac::adc::vals;
10use crate::{rcc, Peri};
11
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct OverrunError;
14
15fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
16 r.sr().modify(|regs| {
17 regs.set_eoc(false);
18 regs.set_ovr(false);
19 });
20}
21
22#[derive(PartialOrd, PartialEq, Debug, Clone, Copy)]
23pub enum Sequence {
24 One,
25 Two,
26 Three,
27 Four,
28 Five,
29 Six,
30 Seven,
31 Eight,
32 Nine,
33 Ten,
34 Eleven,
35 Twelve,
36 Thirteen,
37 Fourteen,
38 Fifteen,
39 Sixteen,
40}
41
42impl From<Sequence> for u8 {
43 fn from(s: Sequence) -> u8 {
44 match s {
45 Sequence::One => 0,
46 Sequence::Two => 1,
47 Sequence::Three => 2,
48 Sequence::Four => 3,
49 Sequence::Five => 4,
50 Sequence::Six => 5,
51 Sequence::Seven => 6,
52 Sequence::Eight => 7,
53 Sequence::Nine => 8,
54 Sequence::Ten => 9,
55 Sequence::Eleven => 10,
56 Sequence::Twelve => 11,
57 Sequence::Thirteen => 12,
58 Sequence::Fourteen => 13,
59 Sequence::Fifteen => 14,
60 Sequence::Sixteen => 15,
61 }
62 }
63}
64
65impl From<u8> for Sequence {
66 fn from(val: u8) -> Self {
67 match val {
68 0 => Sequence::One,
69 1 => Sequence::Two,
70 2 => Sequence::Three,
71 3 => Sequence::Four,
72 4 => Sequence::Five,
73 5 => Sequence::Six,
74 6 => Sequence::Seven,
75 7 => Sequence::Eight,
76 8 => Sequence::Nine,
77 9 => Sequence::Ten,
78 10 => Sequence::Eleven,
79 11 => Sequence::Twelve,
80 12 => Sequence::Thirteen,
81 13 => Sequence::Fourteen,
82 14 => Sequence::Fifteen,
83 15 => Sequence::Sixteen,
84 _ => panic!("Invalid sequence number"),
85 }
86 }
87}
88
89pub struct RingBufferedAdc<'d, T: Instance> {
90 _phantom: PhantomData<T>,
91 ring_buf: ReadableRingBuffer<'d, u16>,
92}
93
94impl<'d, T: Instance> Adc<'d, T> {
95 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
96 ///
97 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
98 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
99 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
100 ///
101 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
102 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
103 ///
104 /// [`read`]: #method.read
105 pub fn into_ring_buffered(self, dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> RingBufferedAdc<'d, T> {
106 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
107
108 let opts: crate::dma::TransferOptions = TransferOptions {
109 half_transfer_ir: true,
110 priority: Priority::VeryHigh,
111 ..Default::default()
112 };
113
114 // Safety: we forget the struct before this function returns.
115 let rx_src = T::regs().dr().as_ptr() as *mut u16;
116 let request = dma.request();
117
118 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) };
119
120 // Don't disable the clock
121 mem::forget(self);
122
123 RingBufferedAdc {
124 _phantom: PhantomData,
125 ring_buf,
126 }
127 }
128}
129
130impl<'d, T: Instance> RingBufferedAdc<'d, T> {
131 fn is_on() -> bool {
132 T::regs().cr2().read().adon()
133 }
134
135 fn stop_adc() {
136 T::regs().cr2().modify(|reg| {
137 reg.set_adon(false);
138 });
139 }
140
141 fn start_adc() {
142 T::regs().cr2().modify(|reg| {
143 reg.set_adon(true);
144 });
145 }
146
147 /// Sets the channel sample time
148 ///
149 /// ## SAFETY:
150 /// - ADON == 0 i.e ADC must not be enabled when this is called.
151 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
152 if ch <= 9 {
153 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
154 } else {
155 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
156 }
157 }
158
159 fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) {
160 let ch_iter = ch.iter();
161 for idx in ch_iter {
162 unsafe {
163 Self::set_channel_sample_time(*idx, sample_time);
164 }
165 }
166 }
167
168 pub fn set_sample_sequence(
169 &mut self,
170 sequence: Sequence,
171 channel: &mut impl AdcChannel<T>,
172 sample_time: SampleTime,
173 ) {
174 let was_on = Self::is_on();
175 if !was_on {
176 Self::start_adc();
177 }
178
179 // Check the sequence is long enough
180 T::regs().sqr1().modify(|r| {
181 let prev: Sequence = r.l().into();
182 if prev < sequence {
183 let new_l: Sequence = sequence;
184 trace!("Setting sequence length from {:?} to {:?}", prev as u8, new_l as u8);
185 r.set_l(sequence.into())
186 } else {
187 r.set_l(prev.into())
188 }
189 });
190
191 // Set this GPIO as an analog input.
192 channel.setup();
193
194 // Set the channel in the right sequence field.
195 match sequence {
196 Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())),
197 Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())),
198 Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())),
199 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
200 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
201 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
202 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())),
203 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())),
204 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())),
205 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())),
206 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())),
207 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())),
208 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())),
209 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())),
210 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())),
211 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())),
212 };
213
214 if !was_on {
215 Self::stop_adc();
216 }
217
218 self.set_channels_sample_time(&[channel.channel()], sample_time);
219
220 Self::start_adc();
221 }
222
223 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
224 pub fn start(&mut self) -> Result<(), OverrunError> {
225 self.setup_adc();
226 self.ring_buf.clear();
227
228 Ok(())
229 }
230
231 fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> {
232 self.teardown_adc();
233 Err(err)
234 }
235
236 /// Stops DMA transfer.
237 /// It does not turn off ADC.
238 /// Calling `start` restarts continuous DMA transfer.
239 ///
240 /// [`start`]: #method.start
241 pub fn teardown_adc(&mut self) {
242 // Stop the DMA transfer
243 self.ring_buf.request_pause();
244
245 let r = T::regs();
246
247 // Stop ADC
248 r.cr2().modify(|reg| {
249 // Stop ADC
250 reg.set_swstart(false);
251 // Stop DMA
252 reg.set_dma(false);
253 });
254
255 r.cr1().modify(|w| {
256 // Disable interrupt for end of conversion
257 w.set_eocie(false);
258 // Disable interrupt for overrun
259 w.set_ovrie(false);
260 });
261
262 clear_interrupt_flags(r);
263
264 compiler_fence(Ordering::SeqCst);
265 }
266
267 fn setup_adc(&mut self) {
268 compiler_fence(Ordering::SeqCst);
269
270 self.ring_buf.start();
271
272 let r = T::regs();
273
274 // Enable ADC
275 let was_on = Self::is_on();
276 if !was_on {
277 r.cr2().modify(|reg| {
278 reg.set_adon(false);
279 reg.set_swstart(false);
280 });
281 }
282
283 // Clear all interrupts
284 r.sr().modify(|regs| {
285 regs.set_eoc(false);
286 regs.set_ovr(false);
287 regs.set_strt(false);
288 });
289
290 r.cr1().modify(|w| {
291 // Enable interrupt for end of conversion
292 w.set_eocie(true);
293 // Enable interrupt for overrun
294 w.set_ovrie(true);
295 // Scanning converisons of multiple channels
296 w.set_scan(true);
297 // Continuous conversion mode
298 w.set_discen(false);
299 });
300
301 r.cr2().modify(|w| {
302 // Enable DMA mode
303 w.set_dma(true);
304 // Enable continuous conversions
305 w.set_cont(true);
306 // DMA requests are issues as long as DMA=1 and data are converted.
307 w.set_dds(vals::Dds::CONTINUOUS);
308 // EOC flag is set at the end of each conversion.
309 w.set_eocs(vals::Eocs::EACH_CONVERSION);
310 });
311
312 // Begin ADC conversions
313 T::regs().cr2().modify(|reg| {
314 reg.set_adon(true);
315 reg.set_swstart(true);
316 });
317
318 super::blocking_delay_us(3);
319 }
320
321 /// Read bytes that are readily available in the ring buffer.
322 /// If no bytes are currently available in the buffer the call waits until the some
323 /// bytes are available (at least one byte and at most half the buffer size)
324 ///
325 /// Background receive is started if `start()` has not been previously called.
326 ///
327 /// Receive in the background is terminated if an error is returned.
328 /// It must then manually be started again by calling `start()` or by re-calling `read()`.
329 pub fn blocking_read<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> {
330 let r = T::regs();
331
332 // Start background receive if it was not already started
333 if !r.cr2().read().dma() {
334 self.start()?;
335 }
336
337 // Clear overrun flag if set.
338 if r.sr().read().ovr() {
339 return self.stop(OverrunError);
340 }
341
342 loop {
343 match self.ring_buf.read(buf) {
344 Ok((0, _)) => {}
345 Ok((len, _)) => {
346 return Ok(len);
347 }
348 Err(_) => {
349 return self.stop(OverrunError);
350 }
351 }
352 }
353 }
354
355 /// Reads measurements from the DMA ring buffer.
356 ///
357 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
358 /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes.
359 ///
360 /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `set_sample_sequence`.
361 /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled.
362 /// For example if 3 channels are sampled `measurements` contain: `[sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3..]`.
363 ///
364 /// If an error is returned, it indicates a DMA overrun, and the process must be restarted by calling `start` or `read` again.
365 ///
366 /// By default, the ADC fills the DMA buffer as quickly as possible. To control the sample rate, call `teardown_adc` after each readout, and then start the DMA again at the desired interval.
367 /// Note that even if using `teardown_adc` to control the sample rate, with each call to `read`, measurements equivalent to half the size of the DMA buffer are still collected.
368 ///
369 /// Example:
370 /// ```rust,ignore
371 /// const DMA_BUF_LEN: usize = 120;
372 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
373 /// let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_dma_buf);
374 ///
375 /// adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
376 /// adc.set_sample_sequence(Sequence::Two, &mut p.PA1, SampleTime::CYCLES112);
377 /// adc.set_sample_sequence(Sequence::Three, &mut p.PA2, SampleTime::CYCLES112);
378 ///
379 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
380 /// loop {
381 /// match adc.read(&mut measurements).await {
382 /// Ok(_) => {
383 /// defmt::info!("adc1: {}", measurements);
384 /// // Only needed to manually control sample rate.
385 /// adc.teardown_adc();
386 /// }
387 /// Err(e) => {
388 /// defmt::warn!("Error: {:?}", e);
389 /// // DMA overrun, next call to `read` restarts ADC.
390 /// }
391 /// }
392 ///
393 /// // Manually control sample rate.
394 /// Timer::after_millis(100).await;
395 /// }
396 /// ```
397 ///
398 ///
399 /// [`set_sample_sequence`]: #method.set_sample_sequence
400 /// [`teardown_adc`]: #method.teardown_adc
401 /// [`start`]: #method.start
402 pub async fn read<const N: usize>(&mut self, measurements: &mut [u16; N]) -> Result<usize, OverrunError> {
403 assert_eq!(
404 self.ring_buf.capacity() / 2,
405 N,
406 "Buffer size must be half the size of the ring buffer"
407 );
408
409 let r = T::regs();
410
411 // Start background receive if it was not already started
412 if !r.cr2().read().dma() {
413 self.start()?;
414 }
415
416 // Clear overrun flag if set.
417 if r.sr().read().ovr() {
418 return self.stop(OverrunError);
419 }
420 match self.ring_buf.read_exact(measurements).await {
421 Ok(len) => Ok(len),
422 Err(_) => self.stop(OverrunError),
423 }
424 }
425}
426
427impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
428 fn drop(&mut self) {
429 self.teardown_adc();
430 rcc::disable::<T>();
431 }
432}
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index d09374876..58c30935f 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -5,11 +5,12 @@ use core::task::Poll;
5#[cfg(adc_l0)] 5#[cfg(adc_l0)]
6use stm32_metapac::adc::vals::Ckmode; 6use stm32_metapac::adc::vals::Ckmode;
7 7
8use super::blocking_delay_us; 8#[cfg(not(adc_l0))]
9use super::Vbat;
10use super::{Temperature, VrefInt, blocking_delay_us};
9use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 11use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
10use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
11use crate::peripherals::ADC1; 13use crate::{Peri, interrupt, rcc};
12use crate::{interrupt, rcc, Peri};
13 14
14mod watchdog_v1; 15mod watchdog_v1;
15pub use watchdog_v1::WatchdogChannels; 16pub use watchdog_v1::WatchdogChannels;
@@ -42,36 +43,23 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
42} 43}
43 44
44#[cfg(not(adc_l0))] 45#[cfg(not(adc_l0))]
45pub struct Vbat; 46impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC1 {
46 47 const CHANNEL: u8 = 18;
47#[cfg(not(adc_l0))] 48}
48impl AdcChannel<ADC1> for Vbat {}
49 49
50#[cfg(not(adc_l0))] 50#[cfg(not(adc_l0))]
51impl super::SealedAdcChannel<ADC1> for Vbat { 51impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
52 fn channel(&self) -> u8 { 52 const CHANNEL: u8 = 17;
53 18
54 }
55} 53}
56 54
57pub struct Vref; 55#[cfg(adc_l0)]
58impl AdcChannel<ADC1> for Vref {} 56impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
59impl super::SealedAdcChannel<ADC1> for Vref { 57 const CHANNEL: u8 = 18;
60 fn channel(&self) -> u8 {
61 17
62 }
63} 58}
64 59
65pub struct Temperature; 60#[cfg(not(adc_l0))]
66impl AdcChannel<ADC1> for Temperature {} 61impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
67impl super::SealedAdcChannel<ADC1> for Temperature { 62 const CHANNEL: u8 = 16;
68 fn channel(&self) -> u8 {
69 if cfg!(adc_l0) {
70 18
71 } else {
72 16
73 }
74 }
75} 63}
76 64
77impl<'d, T: Instance> Adc<'d, T> { 65impl<'d, T: Instance> Adc<'d, T> {
@@ -118,10 +106,7 @@ impl<'d, T: Instance> Adc<'d, T> {
118 T::Interrupt::enable(); 106 T::Interrupt::enable();
119 } 107 }
120 108
121 Self { 109 Self { adc }
122 adc,
123 sample_time: SampleTime::from_bits(0),
124 }
125 } 110 }
126 111
127 #[cfg(not(adc_l0))] 112 #[cfg(not(adc_l0))]
@@ -134,12 +119,12 @@ impl<'d, T: Instance> Adc<'d, T> {
134 Vbat 119 Vbat
135 } 120 }
136 121
137 pub fn enable_vref(&self) -> Vref { 122 pub fn enable_vref(&self) -> VrefInt {
138 // Table 28. Embedded internal reference voltage 123 // Table 28. Embedded internal reference voltage
139 // tstart = 10μs 124 // tstart = 10μs
140 T::regs().ccr().modify(|reg| reg.set_vrefen(true)); 125 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
141 blocking_delay_us(10); 126 blocking_delay_us(10);
142 Vref 127 VrefInt
143 } 128 }
144 129
145 pub fn enable_temperature(&self) -> Temperature { 130 pub fn enable_temperature(&self) -> Temperature {
@@ -153,10 +138,6 @@ impl<'d, T: Instance> Adc<'d, T> {
153 Temperature 138 Temperature
154 } 139 }
155 140
156 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
157 self.sample_time = sample_time;
158 }
159
160 pub fn set_resolution(&mut self, resolution: Resolution) { 141 pub fn set_resolution(&mut self, resolution: Resolution) {
161 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 142 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
162 } 143 }
@@ -167,12 +148,13 @@ impl<'d, T: Instance> Adc<'d, T> {
167 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode)); 148 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode));
168 } 149 }
169 150
170 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 151 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
171 let ch_num = channel.channel(); 152 let ch_num = channel.channel();
172 channel.setup(); 153 channel.setup();
173 154
174 // A.7.5 Single conversion sequence code example - Software trigger 155 // A.7.5 Single conversion sequence code example - Software trigger
175 T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true)); 156 T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true));
157 T::regs().smpr().modify(|reg| reg.set_smp(sample_time.into()));
176 158
177 self.convert().await 159 self.convert().await
178 } 160 }
@@ -183,7 +165,6 @@ impl<'d, T: Instance> Adc<'d, T> {
183 reg.set_eosmp(true); 165 reg.set_eosmp(true);
184 }); 166 });
185 167
186 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
187 T::regs().ier().modify(|w| w.set_eocie(true)); 168 T::regs().ier().modify(|w| w.set_eocie(true));
188 T::regs().cr().modify(|reg| reg.set_adstart(true)); 169 T::regs().cr().modify(|reg| reg.set_adstart(true));
189 170
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index e94a25b24..b026383d5 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,23 +1,40 @@
1use super::blocking_delay_us; 1use core::sync::atomic::{Ordering, compiler_fence};
2use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 2
3use crate::peripherals::ADC1; 3use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us};
4use crate::adc::{Adc, AdcRegs, Instance, Resolution, SampleTime};
5use crate::pac::adc::vals;
6pub use crate::pac::adccommon::vals::Adcpre;
4use crate::time::Hertz; 7use crate::time::Hertz;
5use crate::{rcc, Peri}; 8use crate::{Peri, rcc};
6 9
7mod ringbuffered_v2; 10fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
8pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; 11 r.sr().modify(|regs| {
12 regs.set_eoc(false);
13 regs.set_ovr(false);
14 });
15}
9 16
10/// Default VREF voltage used for sample conversion to millivolts. 17/// Default VREF voltage used for sample conversion to millivolts.
11pub const VREF_DEFAULT_MV: u32 = 3300; 18pub const VREF_DEFAULT_MV: u32 = 3300;
12/// VREF voltage used for factory calibration of VREFINTCAL register. 19/// VREF voltage used for factory calibration of VREFINTCAL register.
13pub const VREF_CALIB_MV: u32 = 3300; 20pub const VREF_CALIB_MV: u32 = 3300;
14 21
15pub struct VrefInt; 22impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
16impl AdcChannel<ADC1> for VrefInt {} 23 const CHANNEL: u8 = 17;
17impl super::SealedAdcChannel<ADC1> for VrefInt { 24}
18 fn channel(&self) -> u8 { 25
19 17 26#[cfg(any(stm32f2, stm32f40x, stm32f41x))]
20 } 27impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
28 const CHANNEL: u8 = 16;
29}
30
31#[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))]
32impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
33 const CHANNEL: u8 = 18;
34}
35
36impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC1 {
37 const CHANNEL: u8 = 18;
21} 38}
22 39
23impl VrefInt { 40impl VrefInt {
@@ -27,20 +44,6 @@ impl VrefInt {
27 } 44 }
28} 45}
29 46
30pub struct Temperature;
31impl AdcChannel<ADC1> for Temperature {}
32impl super::SealedAdcChannel<ADC1> for Temperature {
33 fn channel(&self) -> u8 {
34 cfg_if::cfg_if! {
35 if #[cfg(any(stm32f2, stm32f40x, stm32f41x))] {
36 16
37 } else {
38 18
39 }
40 }
41 }
42}
43
44impl Temperature { 47impl Temperature {
45 /// Time needed for temperature sensor readings to stabilize 48 /// Time needed for temperature sensor readings to stabilize
46 pub fn start_time_us() -> u32 { 49 pub fn start_time_us() -> u32 {
@@ -48,76 +51,174 @@ impl Temperature {
48 } 51 }
49} 52}
50 53
51pub struct Vbat; 54fn from_pclk2(freq: Hertz) -> Adcpre {
52impl AdcChannel<ADC1> for Vbat {} 55 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V).
53impl super::SealedAdcChannel<ADC1> for Vbat { 56 #[cfg(stm32f2)]
54 fn channel(&self) -> u8 { 57 const MAX_FREQUENCY: Hertz = Hertz(30_000_000);
55 18 58 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
59 #[cfg(not(stm32f2))]
60 const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
61 let raw_div = rcc::raw_prescaler(freq.0, MAX_FREQUENCY.0);
62 match raw_div {
63 0..=1 => Adcpre::DIV2,
64 2..=3 => Adcpre::DIV4,
65 4..=5 => Adcpre::DIV6,
66 6..=7 => Adcpre::DIV8,
67 _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."),
56 } 68 }
57} 69}
58 70
59enum Prescaler { 71/// ADC configuration
60 Div2, 72#[derive(Default)]
61 Div4, 73pub struct AdcConfig {
62 Div6, 74 pub resolution: Option<Resolution>,
63 Div8,
64} 75}
65 76
66impl Prescaler { 77impl super::AdcRegs for crate::pac::adc::Adc {
67 fn from_pclk2(freq: Hertz) -> Self { 78 fn data(&self) -> *mut u16 {
68 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). 79 crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
69 #[cfg(stm32f2)] 80 }
70 const MAX_FREQUENCY: Hertz = Hertz(30_000_000); 81
71 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. 82 fn enable(&self) {
72 #[cfg(not(stm32f2))] 83 self.cr2().modify(|reg| {
73 const MAX_FREQUENCY: Hertz = Hertz(36_000_000); 84 reg.set_adon(true);
74 let raw_div = freq.0 / MAX_FREQUENCY.0; 85 });
75 match raw_div { 86
76 0..=1 => Self::Div2, 87 blocking_delay_us(3);
77 2..=3 => Self::Div4, 88 }
78 4..=5 => Self::Div6, 89
79 6..=7 => Self::Div8, 90 fn start(&self) {
80 _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), 91 // Begin ADC conversions
92 self.cr2().modify(|reg| {
93 reg.set_swstart(true);
94 });
95 }
96
97 fn stop(&self) {
98 let r = self;
99
100 // Stop ADC
101 r.cr2().modify(|reg| {
102 // Stop ADC
103 reg.set_swstart(false);
104 // Stop ADC
105 reg.set_adon(false);
106 // Stop DMA
107 reg.set_dma(false);
108 });
109
110 r.cr1().modify(|w| {
111 // Disable interrupt for end of conversion
112 w.set_eocie(false);
113 // Disable interrupt for overrun
114 w.set_ovrie(false);
115 });
116
117 clear_interrupt_flags(*r);
118
119 compiler_fence(Ordering::SeqCst);
120 }
121
122 fn convert(&self) {
123 // clear end of conversion flag
124 self.sr().modify(|reg| {
125 reg.set_eoc(false);
126 });
127
128 // Start conversion
129 self.cr2().modify(|reg| {
130 reg.set_swstart(true);
131 });
132
133 while self.sr().read().strt() == false {
134 // spin //wait for actual start
135 }
136 while self.sr().read().eoc() == false {
137 // spin //wait for finish
138 }
139 }
140
141 fn configure_dma(&self, conversion_mode: ConversionMode) {
142 match conversion_mode {
143 ConversionMode::Repeated(_) => {
144 let r = self;
145
146 // Clear all interrupts
147 r.sr().modify(|regs| {
148 regs.set_eoc(false);
149 regs.set_ovr(false);
150 regs.set_strt(false);
151 });
152
153 r.cr1().modify(|w| {
154 // Enable interrupt for end of conversion
155 w.set_eocie(true);
156 // Enable interrupt for overrun
157 w.set_ovrie(true);
158 // Scanning converisons of multiple channels
159 w.set_scan(true);
160 // Continuous conversion mode
161 w.set_discen(false);
162 });
163
164 r.cr2().modify(|w| {
165 // Enable DMA mode
166 w.set_dma(true);
167 // Enable continuous conversions
168 w.set_cont(true);
169 // DMA requests are issues as long as DMA=1 and data are converted.
170 w.set_dds(vals::Dds::CONTINUOUS);
171 // EOC flag is set at the end of each conversion.
172 w.set_eocs(vals::Eocs::EACH_CONVERSION);
173 });
174 }
81 } 175 }
82 } 176 }
83 177
84 fn adcpre(&self) -> crate::pac::adccommon::vals::Adcpre { 178 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
85 match self { 179 self.cr2().modify(|reg| {
86 Prescaler::Div2 => crate::pac::adccommon::vals::Adcpre::DIV2, 180 reg.set_adon(true);
87 Prescaler::Div4 => crate::pac::adccommon::vals::Adcpre::DIV4, 181 });
88 Prescaler::Div6 => crate::pac::adccommon::vals::Adcpre::DIV6, 182
89 Prescaler::Div8 => crate::pac::adccommon::vals::Adcpre::DIV8, 183 // Check the sequence is long enough
184 self.sqr1().modify(|r| {
185 r.set_l((sequence.len() - 1).try_into().unwrap());
186 });
187
188 for (i, ((ch, _), sample_time)) in sequence.enumerate() {
189 // Set the channel in the right sequence field.
190 self.sqr3().modify(|w| w.set_sq(i, ch));
191
192 let sample_time = sample_time.into();
193 if ch <= 9 {
194 self.smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
195 } else {
196 self.smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
197 }
90 } 198 }
91 } 199 }
92} 200}
93 201
94impl<'d, T> Adc<'d, T> 202impl<'d, T> Adc<'d, T>
95where 203where
96 T: Instance, 204 T: Instance<Regs = crate::pac::adc::Adc>,
97{ 205{
98 pub fn new(adc: Peri<'d, T>) -> Self { 206 pub fn new(adc: Peri<'d, T>) -> Self {
99 rcc::enable_and_reset::<T>(); 207 Self::new_with_config(adc, Default::default())
208 }
100 209
101 let presc = Prescaler::from_pclk2(T::frequency()); 210 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
102 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); 211 rcc::enable_and_reset::<T>();
103 T::regs().cr2().modify(|reg| {
104 reg.set_adon(true);
105 });
106 212
107 blocking_delay_us(3); 213 let presc = from_pclk2(T::frequency());
214 T::common_regs().ccr().modify(|w| w.set_adcpre(presc));
215 T::regs().enable();
108 216
109 Self { 217 if let Some(resolution) = config.resolution {
110 adc, 218 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
111 sample_time: SampleTime::from_bits(0),
112 } 219 }
113 }
114
115 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
116 self.sample_time = sample_time;
117 }
118 220
119 pub fn set_resolution(&mut self, resolution: Resolution) { 221 Self { adc }
120 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
121 } 222 }
122 223
123 /// Enables internal voltage reference and returns [VrefInt], which can be used in 224 /// Enables internal voltage reference and returns [VrefInt], which can be used in
@@ -152,59 +253,11 @@ where
152 253
153 Vbat {} 254 Vbat {}
154 } 255 }
155
156 /// Perform a single conversion.
157 fn convert(&mut self) -> u16 {
158 // clear end of conversion flag
159 T::regs().sr().modify(|reg| {
160 reg.set_eoc(false);
161 });
162
163 // Start conversion
164 T::regs().cr2().modify(|reg| {
165 reg.set_swstart(true);
166 });
167
168 while T::regs().sr().read().strt() == false {
169 // spin //wait for actual start
170 }
171 while T::regs().sr().read().eoc() == false {
172 // spin //wait for finish
173 }
174
175 T::regs().dr().read().0 as u16
176 }
177
178 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
179 channel.setup();
180
181 // Configure ADC
182 let channel = channel.channel();
183
184 // Select channel
185 T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
186
187 // Configure channel
188 Self::set_channel_sample_time(channel, self.sample_time);
189
190 self.convert()
191 }
192
193 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
194 let sample_time = sample_time.into();
195 if ch <= 9 {
196 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
197 } else {
198 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
199 }
200 }
201} 256}
202 257
203impl<'d, T: Instance> Drop for Adc<'d, T> { 258impl<'d, T: Instance> Drop for Adc<'d, T> {
204 fn drop(&mut self) { 259 fn drop(&mut self) {
205 T::regs().cr2().modify(|reg| { 260 T::regs().stop();
206 reg.set_adon(false);
207 });
208 261
209 rcc::disable::<T>(); 262 rcc::disable::<T>();
210 } 263 }
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 16063ce4d..9cc44aa9a 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,19 +1,19 @@
1use cfg_if::cfg_if; 1use cfg_if::cfg_if;
2#[cfg(adc_g0)] 2#[cfg(adc_g0)]
3use heapless::Vec; 3use heapless::Vec;
4use pac::adc::vals::Dmacfg;
5#[cfg(adc_g0)] 4#[cfg(adc_g0)]
6use pac::adc::vals::{Ckmode, Smpsel}; 5use pac::adc::vals::Ckmode;
6use pac::adc::vals::Dmacfg;
7#[cfg(adc_v3)] 7#[cfg(adc_v3)]
8use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; 8use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs};
9#[cfg(adc_g0)] 9#[cfg(adc_g0)]
10pub use pac::adc::vals::{Ovsr, Ovss, Presc}; 10pub use pac::adc::vals::{Ovsr, Ovss, Presc};
11 11
12use super::{ 12#[allow(unused_imports)]
13 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 13use super::SealedAdcChannel;
14}; 14use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
15use crate::dma::Transfer; 15use crate::adc::ConversionMode;
16use crate::{pac, rcc, Peri}; 16use crate::{Peri, pac, rcc};
17 17
18/// Default VREF voltage used for sample conversion to millivolts. 18/// Default VREF voltage used for sample conversion to millivolts.
19pub const VREF_DEFAULT_MV: u32 = 3300; 19pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -25,70 +25,64 @@ pub const VREF_CALIB_MV: u32 = 3000;
25// TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable 25// TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable
26const SAMPLE_TIMES_CAPACITY: usize = 2; 26const SAMPLE_TIMES_CAPACITY: usize = 2;
27 27
28pub struct VrefInt; 28#[cfg(adc_g0)]
29impl<T: Instance> AdcChannel<T> for VrefInt {} 29impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
30impl<T: Instance> SealedAdcChannel<T> for VrefInt { 30 const CHANNEL: u8 = 13;
31 fn channel(&self) -> u8 { 31}
32 cfg_if! { 32#[cfg(any(adc_h5, adc_h7rs))]
33 if #[cfg(adc_g0)] { 33impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
34 let val = 13; 34 const CHANNEL: u8 = 17;
35 } else if #[cfg(any(adc_h5, adc_h7rs))] { 35}
36 let val = 17; 36#[cfg(adc_u0)]
37 } else if #[cfg(adc_u0)] { 37impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
38 let val = 12; 38 const CHANNEL: u8 = 12;
39 } else { 39}
40 let val = 0; 40#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
41 } 41impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
42 } 42 const CHANNEL: u8 = 0;
43 val
44 }
45} 43}
46 44
47pub struct Temperature; 45#[cfg(adc_g0)]
48impl<T: Instance> AdcChannel<T> for Temperature {} 46impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
49impl<T: Instance> SealedAdcChannel<T> for Temperature { 47 const CHANNEL: u8 = 12;
50 fn channel(&self) -> u8 { 48}
51 cfg_if! { 49#[cfg(any(adc_h5, adc_h7rs))]
52 if #[cfg(adc_g0)] { 50impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
53 let val = 12; 51 const CHANNEL: u8 = 16;
54 } else if #[cfg(any(adc_h5, adc_h7rs))] { 52}
55 let val = 16; 53#[cfg(adc_u0)]
56 } else if #[cfg(adc_u0)] { 54impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
57 let val = 11; 55 const CHANNEL: u8 = 11;
58 } else { 56}
59 let val = 17; 57#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
60 } 58impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
61 } 59 const CHANNEL: u8 = 17;
62 val
63 }
64} 60}
65 61
66pub struct Vbat; 62#[cfg(adc_g0)]
67impl<T: Instance> AdcChannel<T> for Vbat {} 63impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
68impl<T: Instance> SealedAdcChannel<T> for Vbat { 64 const CHANNEL: u8 = 14;
69 fn channel(&self) -> u8 { 65}
70 cfg_if! { 66#[cfg(any(adc_h5, adc_h7rs))]
71 if #[cfg(adc_g0)] { 67impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
72 let val = 14; 68 const CHANNEL: u8 = 16;
73 } else if #[cfg(any(adc_h5, adc_h7rs))] { 69}
74 let val = 2; 70#[cfg(adc_u0)]
75 } else if #[cfg(any(adc_h5, adc_h7rs))] { 71impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
76 let val = 13; 72 const CHANNEL: u8 = 13;
77 } else { 73}
78 let val = 18; 74#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
79 } 75impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
80 } 76 const CHANNEL: u8 = 18;
81 val
82 }
83} 77}
84 78
85cfg_if! { 79cfg_if! {
86 if #[cfg(any(adc_h5, adc_h7rs))] { 80 if #[cfg(any(adc_h5, adc_h7rs))] {
87 pub struct VddCore; 81 pub struct VddCore;
88 impl<T: Instance> AdcChannel<T> for VddCore {} 82 impl<T: Instance> super::AdcChannel<T> for VddCore {}
89 impl<T: Instance> super::SealedAdcChannel<T> for VddCore { 83 impl<T: Instance> super::SealedAdcChannel<T> for VddCore {
90 fn channel(&self) -> u8 { 84 fn channel(&self) -> u8 {
91 6 85 17
92 } 86 }
93 } 87 }
94 } 88 }
@@ -97,7 +91,7 @@ cfg_if! {
97cfg_if! { 91cfg_if! {
98 if #[cfg(adc_u0)] { 92 if #[cfg(adc_u0)] {
99 pub struct DacOut; 93 pub struct DacOut;
100 impl<T: Instance> AdcChannel<T> for DacOut {} 94 impl<T: Instance> super::AdcChannel<T> for DacOut {}
101 impl<T: Instance> super::SealedAdcChannel<T> for DacOut { 95 impl<T: Instance> super::SealedAdcChannel<T> for DacOut {
102 fn channel(&self) -> u8 { 96 fn channel(&self) -> u8 {
103 19 97 19
@@ -106,21 +100,6 @@ cfg_if! {
106 } 100 }
107} 101}
108 102
109/// Number of samples used for averaging.
110#[derive(Copy, Clone, Debug)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub enum Averaging {
113 Disabled,
114 Samples2,
115 Samples4,
116 Samples8,
117 Samples16,
118 Samples32,
119 Samples64,
120 Samples128,
121 Samples256,
122}
123
124cfg_if! { if #[cfg(adc_g0)] { 103cfg_if! { if #[cfg(adc_g0)] {
125 104
126/// Synchronous PCLK prescaler 105/// Synchronous PCLK prescaler
@@ -141,295 +120,150 @@ pub enum Clock {
141 120
142}} 121}}
143 122
144impl<'d, T: Instance> Adc<'d, T> { 123#[cfg(adc_u0)]
145 /// Enable the voltage regulator 124type Ovss = u8;
146 fn init_regulator() { 125#[cfg(adc_u0)]
147 rcc::enable_and_reset::<T>(); 126type Ovsr = u8;
148 T::regs().cr().modify(|reg| { 127#[cfg(adc_v3)]
149 #[cfg(not(any(adc_g0, adc_u0)))] 128type Ovss = OversamplingShift;
150 reg.set_deeppwd(false); 129#[cfg(adc_v3)]
151 reg.set_advregen(true); 130type Ovsr = OversamplingRatio;
152 }); 131
153 132/// Adc configuration
154 // If this is false then each ADC_CHSELR bit enables an input channel. 133#[derive(Default)]
155 // This is the reset value, so has no effect. 134pub struct AdcConfig {
156 #[cfg(any(adc_g0, adc_u0))] 135 #[cfg(any(adc_u0, adc_g0, adc_v3))]
157 T::regs().cfgr1().modify(|reg| { 136 pub oversampling_shift: Option<Ovss>,
158 reg.set_chselrmod(false); 137 #[cfg(any(adc_u0, adc_g0, adc_v3))]
159 }); 138 pub oversampling_ratio: Option<Ovsr>,
160 139 #[cfg(any(adc_u0, adc_g0))]
161 blocking_delay_us(20); 140 pub oversampling_enable: Option<bool>,
162 } 141 #[cfg(adc_v3)]
163 142 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
164 /// Calibrate to remove conversion offset
165 fn init_calibrate() {
166 T::regs().cr().modify(|reg| {
167 reg.set_adcal(true);
168 });
169
170 while T::regs().cr().read().adcal() {
171 // spin
172 }
173
174 blocking_delay_us(1);
175 }
176
177 /// Initialize the ADC leaving any analog clock at reset value.
178 /// For G0 and WL, this is the async clock without prescaler.
179 pub fn new(adc: Peri<'d, T>) -> Self {
180 Self::init_regulator();
181 Self::init_calibrate();
182 Self {
183 adc,
184 sample_time: SampleTime::from_bits(0),
185 }
186 }
187
188 #[cfg(adc_g0)] 143 #[cfg(adc_g0)]
189 /// Initialize ADC with explicit clock for the analog ADC 144 pub clock: Option<Clock>,
190 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { 145 pub resolution: Option<Resolution>,
191 Self::init_regulator(); 146 pub averaging: Option<Averaging>,
192 147}
193 #[cfg(any(stm32wl5x))]
194 {
195 // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual
196 let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0;
197 match clock {
198 Clock::Async { div: _ } => {
199 assert!(async_clock_available);
200 }
201 Clock::Sync { div: _ } => {
202 if async_clock_available {
203 warn!("Not using configured ADC clock");
204 }
205 }
206 }
207 }
208 match clock {
209 Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)),
210 Clock::Sync { div } => T::regs().cfgr2().modify(|reg| {
211 reg.set_ckmode(match div {
212 CkModePclk::DIV1 => Ckmode::PCLK,
213 CkModePclk::DIV2 => Ckmode::PCLK_DIV2,
214 CkModePclk::DIV4 => Ckmode::PCLK_DIV4,
215 })
216 }),
217 }
218
219 Self::init_calibrate();
220 148
221 Self { 149impl super::AdcRegs for crate::pac::adc::Adc {
222 adc, 150 fn data(&self) -> *mut u16 {
223 sample_time: SampleTime::from_bits(0), 151 crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
224 }
225 } 152 }
226 153
227 // Enable ADC only when it is not already running. 154 // Enable ADC only when it is not already running.
228 fn enable(&mut self) { 155 fn enable(&self) {
229 // Make sure bits are off 156 // Make sure bits are off
230 while T::regs().cr().read().addis() { 157 while self.cr().read().addis() {
231 // spin 158 // spin
232 } 159 }
233 160
234 if !T::regs().cr().read().aden() { 161 if !self.cr().read().aden() {
235 // Enable ADC 162 // Enable ADC
236 T::regs().isr().modify(|reg| { 163 self.isr().modify(|reg| {
237 reg.set_adrdy(true); 164 reg.set_adrdy(true);
238 }); 165 });
239 T::regs().cr().modify(|reg| { 166 self.cr().modify(|reg| {
240 reg.set_aden(true); 167 reg.set_aden(true);
241 }); 168 });
242 169
243 while !T::regs().isr().read().adrdy() { 170 while !self.isr().read().adrdy() {
244 // spin 171 // spin
245 } 172 }
246 } 173 }
247 } 174 }
248 175
249 pub fn enable_vrefint(&self) -> VrefInt { 176 fn start(&self) {
177 self.cr().modify(|reg| {
178 reg.set_adstart(true);
179 });
180 }
181
182 fn stop(&self) {
183 // Ensure conversions are finished.
184 if self.cr().read().adstart() && !self.cr().read().addis() {
185 self.cr().modify(|reg| {
186 reg.set_adstp(true);
187 });
188 while self.cr().read().adstart() {}
189 }
190
191 // Reset configuration.
250 #[cfg(not(any(adc_g0, adc_u0)))] 192 #[cfg(not(any(adc_g0, adc_u0)))]
251 T::common_regs().ccr().modify(|reg| { 193 self.cfgr().modify(|reg| {
252 reg.set_vrefen(true); 194 reg.set_cont(false);
195 reg.set_dmaen(false);
253 }); 196 });
254 #[cfg(any(adc_g0, adc_u0))] 197 #[cfg(any(adc_g0, adc_u0))]
255 T::regs().ccr().modify(|reg| { 198 self.cfgr1().modify(|reg| {
256 reg.set_vrefen(true); 199 reg.set_cont(false);
200 reg.set_dmaen(false);
257 }); 201 });
202 }
258 203
259 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us 204 /// Perform a single conversion.
260 // to stabilize the internal voltage reference. 205 fn convert(&self) {
261 blocking_delay_us(15); 206 // Some models are affected by an erratum:
207 // If we perform conversions slower than 1 kHz, the first read ADC value can be
208 // corrupted, so we discard it and measure again.
209 //
210 // STM32L471xx: Section 2.7.3
211 // STM32G4: Section 2.7.3
212 #[cfg(any(rcc_l4, rcc_g4))]
213 let len = 2;
262 214
263 VrefInt {} 215 #[cfg(not(any(rcc_l4, rcc_g4)))]
264 } 216 let len = 1;
265 217
266 pub fn enable_temperature(&self) -> Temperature { 218 for _ in 0..len {
267 cfg_if! { 219 self.isr().modify(|reg| {
268 if #[cfg(any(adc_g0, adc_u0))] { 220 reg.set_eos(true);
269 T::regs().ccr().modify(|reg| { 221 reg.set_eoc(true);
270 reg.set_tsen(true); 222 });
271 });
272 } else if #[cfg(any(adc_h5, adc_h7rs))] {
273 T::common_regs().ccr().modify(|reg| {
274 reg.set_tsen(true);
275 });
276 } else {
277 T::common_regs().ccr().modify(|reg| {
278 reg.set_ch17sel(true);
279 });
280 }
281 }
282 223
283 Temperature {} 224 // Start conversion
284 } 225 self.cr().modify(|reg| {
226 reg.set_adstart(true);
227 });
285 228
286 pub fn enable_vbat(&self) -> Vbat { 229 while !self.isr().read().eos() {
287 cfg_if! { 230 // spin
288 if #[cfg(any(adc_g0, adc_u0))] {
289 T::regs().ccr().modify(|reg| {
290 reg.set_vbaten(true);
291 });
292 } else if #[cfg(any(adc_h5, adc_h7rs))] {
293 T::common_regs().ccr().modify(|reg| {
294 reg.set_vbaten(true);
295 });
296 } else {
297 T::common_regs().ccr().modify(|reg| {
298 reg.set_ch18sel(true);
299 });
300 } 231 }
301 } 232 }
302
303 Vbat {}
304 } 233 }
305 234
306 /// Set the ADC sample time. 235 fn configure_dma(&self, conversion_mode: ConversionMode) {
307 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 236 // Set continuous mode with oneshot dma.
308 self.sample_time = sample_time; 237 // Clear overrun flag before starting transfer.
309 } 238 self.isr().modify(|reg| {
310 239 reg.set_ovr(true);
311 /// Get the ADC sample time. 240 });
312 pub fn sample_time(&self) -> SampleTime {
313 self.sample_time
314 }
315 241
316 /// Set the ADC resolution.
317 pub fn set_resolution(&mut self, resolution: Resolution) {
318 #[cfg(not(any(adc_g0, adc_u0)))] 242 #[cfg(not(any(adc_g0, adc_u0)))]
319 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 243 let regs = self.cfgr();
320 #[cfg(any(adc_g0, adc_u0))]
321 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
322 }
323 244
324 pub fn set_averaging(&mut self, averaging: Averaging) { 245 #[cfg(any(adc_g0, adc_u0))]
325 let (enable, samples, right_shift) = match averaging { 246 let regs = self.cfgr1();
326 Averaging::Disabled => (false, 0, 0),
327 Averaging::Samples2 => (true, 0, 1),
328 Averaging::Samples4 => (true, 1, 2),
329 Averaging::Samples8 => (true, 2, 3),
330 Averaging::Samples16 => (true, 3, 4),
331 Averaging::Samples32 => (true, 4, 5),
332 Averaging::Samples64 => (true, 5, 6),
333 Averaging::Samples128 => (true, 6, 7),
334 Averaging::Samples256 => (true, 7, 8),
335 };
336 T::regs().cfgr2().modify(|reg| {
337 #[cfg(not(any(adc_g0, adc_u0)))]
338 reg.set_rovse(enable);
339 #[cfg(any(adc_g0, adc_u0))]
340 reg.set_ovse(enable);
341 #[cfg(any(adc_h5, adc_h7rs))]
342 reg.set_ovsr(samples.into());
343 #[cfg(not(any(adc_h5, adc_h7rs)))]
344 reg.set_ovsr(samples.into());
345 reg.set_ovss(right_shift.into());
346 })
347 }
348 /*
349 /// Convert a raw sample from the `Temperature` to deg C
350 pub fn to_degrees_centigrade(sample: u16) -> f32 {
351 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
352 * (sample as f32 - VtempCal30::get().read() as f32)
353 + 30.0
354 }
355 */
356
357 /// Perform a single conversion.
358 fn convert(&mut self) -> u16 {
359 T::regs().isr().modify(|reg| {
360 reg.set_eos(true);
361 reg.set_eoc(true);
362 });
363 247
364 // Start conversion 248 regs.modify(|reg| {
365 T::regs().cr().modify(|reg| { 249 reg.set_discen(false);
366 reg.set_adstart(true); 250 reg.set_cont(true);
251 reg.set_dmacfg(match conversion_mode {
252 ConversionMode::Singular => Dmacfg::ONE_SHOT,
253 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
254 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
255 });
256 reg.set_dmaen(true);
367 }); 257 });
368
369 while !T::regs().isr().read().eos() {
370 // spin
371 }
372
373 T::regs().dr().read().0 as u16
374 } 258 }
375 259
376 /// Read an ADC channel. 260 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
377 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 261 #[cfg(adc_h5)]
378 self.read_channel(channel) 262 self.cr().modify(|w| w.set_aden(false));
379 }
380
381 /// Read one or multiple ADC channels using DMA.
382 ///
383 /// `readings` must have a length that is a multiple of the length of the
384 /// `sequence` iterator.
385 ///
386 /// Note: The order of values in `readings` is defined by the pin ADC
387 /// channel number and not the pin order in `sequence`.
388 ///
389 /// Example
390 /// ```rust,ignore
391 /// use embassy_stm32::adc::{Adc, AdcChannel}
392 ///
393 /// let mut adc = Adc::new(p.ADC1);
394 /// let mut adc_pin0 = p.PA0.degrade_adc();
395 /// let mut adc_pin1 = p.PA1.degrade_adc();
396 /// let mut measurements = [0u16; 2];
397 ///
398 /// adc.read(
399 /// p.DMA1_CH2.reborrow(),
400 /// [
401 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
402 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
403 /// ]
404 /// .into_iter(),
405 /// &mut measurements,
406 /// )
407 /// .await;
408 /// defmt::info!("measurements: {}", measurements);
409 /// ```
410 pub async fn read(
411 &mut self,
412 rx_dma: Peri<'_, impl RxDma<T>>,
413 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
414 readings: &mut [u16],
415 ) {
416 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
417 assert!(
418 readings.len() % sequence.len() == 0,
419 "Readings length must be a multiple of sequence length"
420 );
421 assert!(
422 sequence.len() <= 16,
423 "Asynchronous read sequence cannot be more than 16 in length"
424 );
425
426 // Ensure no conversions are ongoing and ADC is enabled.
427 Self::cancel_conversions();
428 self.enable();
429 263
430 // Set sequence length 264 // Set sequence length
431 #[cfg(not(any(adc_g0, adc_u0)))] 265 #[cfg(not(any(adc_g0, adc_u0)))]
432 T::regs().sqr1().modify(|w| { 266 self.sqr1().modify(|w| {
433 w.set_l(sequence.len() as u8 - 1); 267 w.set_l(sequence.len() as u8 - 1);
434 }); 268 });
435 269
@@ -437,12 +271,12 @@ impl<'d, T: Instance> Adc<'d, T> {
437 { 271 {
438 let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new(); 272 let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new();
439 273
440 T::regs().chselr().write(|chselr| { 274 self.chselr().write(|chselr| {
441 T::regs().smpr().write(|smpr| { 275 self.smpr().write(|smpr| {
442 for (channel, sample_time) in sequence { 276 for ((channel, _), sample_time) in sequence {
443 chselr.set_chsel(channel.channel.into(), true); 277 chselr.set_chsel(channel.into(), true);
444 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { 278 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
445 smpr.set_smpsel(channel.channel.into(), (i as u8).into()); 279 smpr.set_smpsel(channel.into(), (i as u8).into());
446 } else { 280 } else {
447 smpr.set_sample_time(sample_times.len(), sample_time); 281 smpr.set_sample_time(sample_times.len(), sample_time);
448 if let Err(_) = sample_times.push(sample_time) { 282 if let Err(_) = sample_times.push(sample_time) {
@@ -461,225 +295,321 @@ impl<'d, T: Instance> Adc<'d, T> {
461 #[cfg(adc_u0)] 295 #[cfg(adc_u0)]
462 let mut channel_mask = 0; 296 let mut channel_mask = 0;
463 297
298 #[cfg(adc_h5)]
299 let mut difsel = 0u32;
300
464 // Configure channels and ranks 301 // Configure channels and ranks
465 for (_i, (channel, sample_time)) in sequence.enumerate() { 302 for (_i, ((channel, _is_differential), sample_time)) in sequence.enumerate() {
466 Self::configure_channel(channel, sample_time); 303 // RM0492, RM0481, etc.
304 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
305 #[cfg(any(adc_h5, adc_h7rs))]
306 if channel == 0 {
307 self.or().modify(|reg| reg.set_op0(true));
308 }
309
310 // Configure channel
311 cfg_if! {
312 if #[cfg(adc_u0)] {
313 // On G0 and U6 all channels use the same sampling time.
314 self.smpr().modify(|reg| reg.set_smp1(sample_time.into()));
315 } else if #[cfg(any(adc_h5, adc_h7rs))] {
316 match channel {
317 0..=9 => self.smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
318 _ => self.smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
319 }
320 } else {
321 let sample_time = sample_time.into();
322 self
323 .smpr(channel as usize / 10)
324 .modify(|reg| reg.set_smp(channel as usize % 10, sample_time));
325 }
326 }
327
328 #[cfg(stm32h7)]
329 {
330 use crate::pac::adc::vals::Pcsel;
331
332 self.cfgr2().modify(|w| w.set_lshift(0));
333 self.pcsel()
334 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
335 }
467 336
468 // Each channel is sampled according to sequence 337 // Each channel is sampled according to sequence
469 #[cfg(not(any(adc_g0, adc_u0)))] 338 #[cfg(not(any(adc_g0, adc_u0)))]
470 match _i { 339 match _i {
471 0..=3 => { 340 0..=3 => {
472 T::regs().sqr1().modify(|w| { 341 self.sqr1().modify(|w| {
473 w.set_sq(_i, channel.channel()); 342 w.set_sq(_i, channel);
474 }); 343 });
475 } 344 }
476 4..=8 => { 345 4..=8 => {
477 T::regs().sqr2().modify(|w| { 346 self.sqr2().modify(|w| {
478 w.set_sq(_i - 4, channel.channel()); 347 w.set_sq(_i - 4, channel);
479 }); 348 });
480 } 349 }
481 9..=13 => { 350 9..=13 => {
482 T::regs().sqr3().modify(|w| { 351 self.sqr3().modify(|w| {
483 w.set_sq(_i - 9, channel.channel()); 352 w.set_sq(_i - 9, channel);
484 }); 353 });
485 } 354 }
486 14..=15 => { 355 14..=15 => {
487 T::regs().sqr4().modify(|w| { 356 self.sqr4().modify(|w| {
488 w.set_sq(_i - 14, channel.channel()); 357 w.set_sq(_i - 14, channel);
489 }); 358 });
490 } 359 }
491 _ => unreachable!(), 360 _ => unreachable!(),
492 } 361 }
493 362
363 #[cfg(adc_h5)]
364 {
365 difsel |= (_is_differential as u32) << channel;
366 }
367
494 #[cfg(adc_u0)] 368 #[cfg(adc_u0)]
495 { 369 {
496 channel_mask |= 1 << channel.channel(); 370 channel_mask |= 1 << channel;
497 } 371 }
498 } 372 }
499 373
374 #[cfg(adc_h5)]
375 self.difsel().write(|w| w.set_difsel(difsel));
376
500 // On G0 and U0 enabled channels are sampled from 0 to last channel. 377 // On G0 and U0 enabled channels are sampled from 0 to last channel.
501 // It is possible to add up to 8 sequences if CHSELRMOD = 1. 378 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
502 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. 379 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
503 #[cfg(adc_u0)] 380 #[cfg(adc_u0)]
504 T::regs().chselr().modify(|reg| { 381 self.chselr().modify(|reg| {
505 reg.set_chsel(channel_mask); 382 reg.set_chsel(channel_mask);
506 }); 383 });
507 } 384 }
508 // Set continuous mode with oneshot dma. 385 }
509 // Clear overrun flag before starting transfer. 386}
510 T::regs().isr().modify(|reg| {
511 reg.set_ovr(true);
512 });
513 387
514 #[cfg(not(any(adc_g0, adc_u0)))] 388impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
515 T::regs().cfgr().modify(|reg| { 389 /// Enable the voltage regulator
516 reg.set_discen(false); 390 fn init_regulator() {
517 reg.set_cont(true); 391 rcc::enable_and_reset::<T>();
518 reg.set_dmacfg(Dmacfg::ONE_SHOT); 392 T::regs().cr().modify(|reg| {
519 reg.set_dmaen(true); 393 #[cfg(not(any(adc_g0, adc_u0)))]
394 reg.set_deeppwd(false);
395 reg.set_advregen(true);
520 }); 396 });
397
398 // If this is false then each ADC_CHSELR bit enables an input channel.
399 // This is the reset value, so has no effect.
521 #[cfg(any(adc_g0, adc_u0))] 400 #[cfg(any(adc_g0, adc_u0))]
522 T::regs().cfgr1().modify(|reg| { 401 T::regs().cfgr1().modify(|reg| {
523 reg.set_discen(false); 402 reg.set_chselrmod(false);
524 reg.set_cont(true);
525 reg.set_dmacfg(Dmacfg::ONE_SHOT);
526 reg.set_dmaen(true);
527 }); 403 });
528 404
529 let request = rx_dma.request(); 405 blocking_delay_us(20);
530 let transfer = unsafe { 406 }
531 Transfer::new_read(
532 rx_dma,
533 request,
534 T::regs().dr().as_ptr() as *mut u16,
535 readings,
536 Default::default(),
537 )
538 };
539 407
540 // Start conversion 408 /// Calibrate to remove conversion offset
409 fn init_calibrate() {
541 T::regs().cr().modify(|reg| { 410 T::regs().cr().modify(|reg| {
542 reg.set_adstart(true); 411 reg.set_adcal(true);
543 }); 412 });
544 413
545 // Wait for conversion sequence to finish. 414 while T::regs().cr().read().adcal() {
546 transfer.await; 415 // spin
547 416 }
548 // Ensure conversions are finished.
549 Self::cancel_conversions();
550 417
551 // Reset configuration. 418 blocking_delay_us(1);
552 #[cfg(not(any(adc_g0, adc_u0)))]
553 T::regs().cfgr().modify(|reg| {
554 reg.set_cont(false);
555 });
556 #[cfg(any(adc_g0, adc_u0))]
557 T::regs().cfgr1().modify(|reg| {
558 reg.set_cont(false);
559 });
560 } 419 }
561 420
562 #[cfg(not(adc_g0))] 421 /// Initialize the ADC leaving any analog clock at reset value.
563 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 422 /// For G0 and WL, this is the async clock without prescaler.
564 // RM0492, RM0481, etc. 423 pub fn new(adc: Peri<'d, T>) -> Self {
565 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 424 Self::init_regulator();
566 #[cfg(any(adc_h5, adc_h7rs))] 425 Self::init_calibrate();
567 if channel.channel() == 0 { 426 Self { adc }
568 T::regs().or().modify(|reg| reg.set_op0(true));
569 }
570
571 // Configure channel
572 Self::set_channel_sample_time(channel.channel(), sample_time);
573 } 427 }
574 428
575 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 429 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
576 self.enable();
577 #[cfg(not(adc_g0))] 430 #[cfg(not(adc_g0))]
578 Self::configure_channel(channel, self.sample_time); 431 let s = Self::new(adc);
432
579 #[cfg(adc_g0)] 433 #[cfg(adc_g0)]
580 T::regs().smpr().write(|reg| { 434 let s = match config.clock {
581 reg.set_sample_time(0, self.sample_time); 435 Some(clock) => Self::new_with_clock(adc, clock),
582 reg.set_smpsel(channel.channel().into(), Smpsel::SMP1); 436 None => Self::new(adc),
583 }); 437 };
584 // Select channel 438
585 #[cfg(not(any(adc_g0, adc_u0)))] 439 #[cfg(any(adc_g0, adc_u0, adc_v3))]
586 T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel())); 440 if let Some(shift) = config.oversampling_shift {
441 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
442 }
443
444 #[cfg(any(adc_g0, adc_u0, adc_v3))]
445 if let Some(ratio) = config.oversampling_ratio {
446 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
447 }
448
587 #[cfg(any(adc_g0, adc_u0))] 449 #[cfg(any(adc_g0, adc_u0))]
588 T::regs().chselr().write(|reg| { 450 if let Some(enable) = config.oversampling_enable {
589 #[cfg(adc_g0)] 451 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
590 reg.set_chsel(channel.channel().into(), true); 452 }
591 #[cfg(adc_u0)]
592 reg.set_chsel(1 << channel.channel());
593 });
594 453
595 // Some models are affected by an erratum: 454 #[cfg(adc_v3)]
596 // If we perform conversions slower than 1 kHz, the first read ADC value can be 455 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
597 // corrupted, so we discard it and measure again. 456 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
598 // 457 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
599 // STM32L471xx: Section 2.7.3 458 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
600 // STM32G4: Section 2.7.3 459 }
601 #[cfg(any(rcc_l4, rcc_g4))]
602 let _ = self.convert();
603 let val = self.convert();
604 460
605 T::regs().cr().modify(|reg| reg.set_addis(true)); 461 if let Some(resolution) = config.resolution {
462 #[cfg(not(any(adc_g0, adc_u0)))]
463 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
464 #[cfg(any(adc_g0, adc_u0))]
465 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
466 }
606 467
607 // RM0492, RM0481, etc. 468 if let Some(averaging) = config.averaging {
608 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 469 let (enable, samples, right_shift) = match averaging {
609 #[cfg(any(adc_h5, adc_h7rs))] 470 Averaging::Disabled => (false, 0, 0),
610 if channel.channel() == 0 { 471 Averaging::Samples2 => (true, 0, 1),
611 T::regs().or().modify(|reg| reg.set_op0(false)); 472 Averaging::Samples4 => (true, 1, 2),
473 Averaging::Samples8 => (true, 2, 3),
474 Averaging::Samples16 => (true, 3, 4),
475 Averaging::Samples32 => (true, 4, 5),
476 Averaging::Samples64 => (true, 5, 6),
477 Averaging::Samples128 => (true, 6, 7),
478 Averaging::Samples256 => (true, 7, 8),
479 };
480 T::regs().cfgr2().modify(|reg| {
481 #[cfg(not(any(adc_g0, adc_u0)))]
482 reg.set_rovse(enable);
483 #[cfg(any(adc_g0, adc_u0))]
484 reg.set_ovse(enable);
485 #[cfg(any(adc_h5, adc_h7rs))]
486 reg.set_ovsr(samples.into());
487 #[cfg(not(any(adc_h5, adc_h7rs)))]
488 reg.set_ovsr(samples.into());
489 reg.set_ovss(right_shift.into());
490 })
612 } 491 }
613 492
614 val 493 s
615 } 494 }
616 495
617 #[cfg(adc_g0)] 496 #[cfg(adc_g0)]
618 pub fn set_oversampling_shift(&mut self, shift: Ovss) { 497 /// Initialize ADC with explicit clock for the analog ADC
619 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); 498 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self {
620 } 499 Self::init_regulator();
621 #[cfg(adc_u0)]
622 pub fn set_oversampling_shift(&mut self, shift: u8) {
623 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
624 }
625 500
626 #[cfg(adc_g0)] 501 #[cfg(any(stm32wl5x))]
627 pub fn set_oversampling_ratio(&mut self, ratio: Ovsr) { 502 {
628 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); 503 // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual
629 } 504 let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0;
630 #[cfg(adc_u0)] 505 match clock {
631 pub fn set_oversampling_ratio(&mut self, ratio: u8) { 506 Clock::Async { div: _ } => {
632 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); 507 assert!(async_clock_available);
633 } 508 }
509 Clock::Sync { div: _ } => {
510 if async_clock_available {
511 warn!("Not using configured ADC clock");
512 }
513 }
514 }
515 }
516 match clock {
517 Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)),
518 Clock::Sync { div } => T::regs().cfgr2().modify(|reg| {
519 reg.set_ckmode(match div {
520 CkModePclk::DIV1 => Ckmode::PCLK,
521 CkModePclk::DIV2 => Ckmode::PCLK_DIV2,
522 CkModePclk::DIV4 => Ckmode::PCLK_DIV4,
523 })
524 }),
525 }
634 526
635 #[cfg(any(adc_g0, adc_u0))] 527 Self::init_calibrate();
636 pub fn oversampling_enable(&mut self, enable: bool) {
637 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
638 }
639 528
640 #[cfg(adc_v3)] 529 Self { adc }
641 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
642 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
643 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
644 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
645 } 530 }
646 531
647 #[cfg(adc_v3)] 532 pub fn enable_vrefint(&self) -> VrefInt {
648 pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) { 533 #[cfg(not(any(adc_g0, adc_u0)))]
649 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); 534 T::common_regs().ccr().modify(|reg| {
535 reg.set_vrefen(true);
536 });
537 #[cfg(any(adc_g0, adc_u0))]
538 T::regs().ccr().modify(|reg| {
539 reg.set_vrefen(true);
540 });
541
542 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
543 // to stabilize the internal voltage reference.
544 blocking_delay_us(15);
545
546 VrefInt {}
650 } 547 }
651 548
652 #[cfg(adc_v3)] 549 pub fn enable_temperature(&self) -> Temperature {
653 pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) { 550 cfg_if! {
654 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); 551 if #[cfg(any(adc_g0, adc_u0))] {
552 T::regs().ccr().modify(|reg| {
553 reg.set_tsen(true);
554 });
555 } else if #[cfg(any(adc_h5, adc_h7rs))] {
556 T::common_regs().ccr().modify(|reg| {
557 reg.set_tsen(true);
558 });
559 } else {
560 T::common_regs().ccr().modify(|reg| {
561 reg.set_ch17sel(true);
562 });
563 }
564 }
565
566 Temperature {}
655 } 567 }
656 568
657 #[cfg(not(adc_g0))] 569 pub fn enable_vbat(&self) -> Vbat {
658 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
659 cfg_if! { 570 cfg_if! {
660 if #[cfg(adc_u0)] { 571 if #[cfg(any(adc_g0, adc_u0))] {
661 // On G0 and U6 all channels use the same sampling time. 572 T::regs().ccr().modify(|reg| {
662 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 573 reg.set_vbaten(true);
574 });
663 } else if #[cfg(any(adc_h5, adc_h7rs))] { 575 } else if #[cfg(any(adc_h5, adc_h7rs))] {
664 match _ch { 576 T::common_regs().ccr().modify(|reg| {
665 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 577 reg.set_vbaten(true);
666 _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 578 });
667 }
668 } else { 579 } else {
669 let sample_time = sample_time.into(); 580 T::common_regs().ccr().modify(|reg| {
670 T::regs() 581 reg.set_ch18sel(true);
671 .smpr(_ch as usize / 10) 582 });
672 .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time));
673 } 583 }
674 } 584 }
585
586 Vbat {}
675 } 587 }
676 588
677 fn cancel_conversions() { 589 pub fn disable_vbat(&self) {
678 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 590 cfg_if! {
679 T::regs().cr().modify(|reg| { 591 if #[cfg(any(adc_g0, adc_u0))] {
680 reg.set_adstp(true); 592 T::regs().ccr().modify(|reg| {
681 }); 593 reg.set_vbaten(false);
682 while T::regs().cr().read().adstart() {} 594 });
595 } else if #[cfg(any(adc_h5, adc_h7rs))] {
596 T::common_regs().ccr().modify(|reg| {
597 reg.set_vbaten(false);
598 });
599 } else {
600 T::common_regs().ccr().modify(|reg| {
601 reg.set_ch18sel(false);
602 });
603 }
683 } 604 }
684 } 605 }
606
607 /*
608 /// Convert a raw sample from the `Temperature` to deg C
609 pub fn to_degrees_centigrade(sample: u16) -> f32 {
610 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
611 * (sample as f32 - VtempCal30::get().read() as f32)
612 + 30.0
613 }
614 */
685} 615}
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index b66437e6e..962816194 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -4,12 +4,12 @@ use pac::adc::vals::{Adcaldif, Boost};
4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; 4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 5use pac::adccommon::vals::Presc;
6 6
7use super::{ 7use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
8 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 8#[cfg(stm32u5)]
9}; 9use crate::adc::DefaultInstance;
10use crate::dma::Transfer; 10use crate::adc::{AdcRegs, ConversionMode};
11use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::{pac, rcc, Peri}; 12use crate::{Peri, pac, rcc};
13 13
14/// Default VREF voltage used for sample conversion to millivolts. 14/// Default VREF voltage used for sample conversion to millivolts.
15pub const VREF_DEFAULT_MV: u32 = 3300; 15pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -25,153 +25,228 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
26 26
27#[cfg(stm32g4)] 27#[cfg(stm32g4)]
28const VREF_CHANNEL: u8 = 18; 28impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
29 const CHANNEL: u8 = 18;
30}
29#[cfg(stm32g4)] 31#[cfg(stm32g4)]
30const TEMP_CHANNEL: u8 = 16; 32impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
33 const CHANNEL: u8 = 16;
34}
31 35
32#[cfg(stm32h7)] 36#[cfg(stm32h7)]
33const VREF_CHANNEL: u8 = 19; 37impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
38 const CHANNEL: u8 = 19;
39}
34#[cfg(stm32h7)] 40#[cfg(stm32h7)]
35const TEMP_CHANNEL: u8 = 18; 41impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
42 const CHANNEL: u8 = 18;
43}
36 44
37// TODO this should be 14 for H7a/b/35 45// TODO this should be 14 for H7a/b/35
38#[cfg(not(stm32u5))] 46#[cfg(not(stm32u5))]
39const VBAT_CHANNEL: u8 = 17; 47impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
48 const CHANNEL: u8 = 17;
49}
40 50
41#[cfg(stm32u5)] 51#[cfg(stm32u5)]
42const VREF_CHANNEL: u8 = 0; 52impl<T: DefaultInstance> super::SealedSpecialConverter<super::VrefInt> for T {
53 const CHANNEL: u8 = 0;
54}
43#[cfg(stm32u5)] 55#[cfg(stm32u5)]
44const TEMP_CHANNEL: u8 = 19; 56impl<T: DefaultInstance> super::SealedSpecialConverter<super::Temperature> for T {
57 const CHANNEL: u8 = 19;
58}
45#[cfg(stm32u5)] 59#[cfg(stm32u5)]
46const VBAT_CHANNEL: u8 = 18; 60impl<T: DefaultInstance> super::SealedSpecialConverter<super::Vbat> for T {
47 61 const CHANNEL: u8 = 18;
48// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
49/// Internal voltage reference channel.
50pub struct VrefInt;
51impl<T: Instance> AdcChannel<T> for VrefInt {}
52impl<T: Instance> SealedAdcChannel<T> for VrefInt {
53 fn channel(&self) -> u8 {
54 VREF_CHANNEL
55 }
56} 62}
57 63
58/// Internal temperature channel. 64fn from_ker_ck(frequency: Hertz) -> Presc {
59pub struct Temperature; 65 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
60impl<T: Instance> AdcChannel<T> for Temperature {} 66 match raw_prescaler {
61impl<T: Instance> SealedAdcChannel<T> for Temperature { 67 0 => Presc::DIV1,
62 fn channel(&self) -> u8 { 68 1 => Presc::DIV2,
63 TEMP_CHANNEL 69 2..=3 => Presc::DIV4,
70 4..=5 => Presc::DIV6,
71 6..=7 => Presc::DIV8,
72 8..=9 => Presc::DIV10,
73 10..=11 => Presc::DIV12,
74 _ => unimplemented!(),
64 } 75 }
65} 76}
66 77
67/// Internal battery voltage channel. 78/// Adc configuration
68pub struct Vbat; 79#[derive(Default)]
69impl<T: Instance> AdcChannel<T> for Vbat {} 80pub struct AdcConfig {
70impl<T: Instance> SealedAdcChannel<T> for Vbat { 81 pub resolution: Option<Resolution>,
71 fn channel(&self) -> u8 { 82 pub averaging: Option<Averaging>,
72 VBAT_CHANNEL
73 }
74} 83}
75 84
76// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 85impl AdcRegs for crate::pac::adc::Adc {
77// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 86 fn data(&self) -> *mut u16 {
78#[allow(unused)] 87 crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
79enum Prescaler { 88 }
80 NotDivided, 89
81 DividedBy2, 90 fn enable(&self) {
82 DividedBy4, 91 self.isr().write(|w| w.set_adrdy(true));
83 DividedBy6, 92 self.cr().modify(|w| w.set_aden(true));
84 DividedBy8, 93 while !self.isr().read().adrdy() {}
85 DividedBy10, 94 self.isr().write(|w| w.set_adrdy(true));
86 DividedBy12, 95 }
87 DividedBy16,
88 DividedBy32,
89 DividedBy64,
90 DividedBy128,
91 DividedBy256,
92}
93 96
94impl Prescaler { 97 fn start(&self) {
95 fn from_ker_ck(frequency: Hertz) -> Self { 98 // Start conversion
96 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 99 self.cr().modify(|reg| {
97 match raw_prescaler { 100 reg.set_adstart(true);
98 0 => Self::NotDivided, 101 });
99 1 => Self::DividedBy2, 102 }
100 2..=3 => Self::DividedBy4, 103
101 4..=5 => Self::DividedBy6, 104 fn stop(&self) {
102 6..=7 => Self::DividedBy8, 105 if self.cr().read().adstart() && !self.cr().read().addis() {
103 8..=9 => Self::DividedBy10, 106 self.cr().modify(|reg| {
104 10..=11 => Self::DividedBy12, 107 reg.set_adstp(Adstp::STOP);
105 _ => unimplemented!(), 108 });
109 while self.cr().read().adstart() {}
106 } 110 }
111
112 // Reset configuration.
113 self.cfgr().modify(|reg| {
114 reg.set_cont(false);
115 reg.set_dmngt(Dmngt::from_bits(0));
116 });
107 } 117 }
108 118
109 fn divisor(&self) -> u32 { 119 fn convert(&self) {
110 match self { 120 self.isr().modify(|reg| {
111 Prescaler::NotDivided => 1, 121 reg.set_eos(true);
112 Prescaler::DividedBy2 => 2, 122 reg.set_eoc(true);
113 Prescaler::DividedBy4 => 4, 123 });
114 Prescaler::DividedBy6 => 6, 124
115 Prescaler::DividedBy8 => 8, 125 // Start conversion
116 Prescaler::DividedBy10 => 10, 126 self.cr().modify(|reg| {
117 Prescaler::DividedBy12 => 12, 127 reg.set_adstart(true);
118 Prescaler::DividedBy16 => 16, 128 });
119 Prescaler::DividedBy32 => 32, 129
120 Prescaler::DividedBy64 => 64, 130 while !self.isr().read().eos() {
121 Prescaler::DividedBy128 => 128, 131 // spin
122 Prescaler::DividedBy256 => 256,
123 } 132 }
124 } 133 }
125 134
126 fn presc(&self) -> Presc { 135 fn configure_dma(&self, conversion_mode: ConversionMode) {
127 match self { 136 match conversion_mode {
128 Prescaler::NotDivided => Presc::DIV1, 137 ConversionMode::Singular => {
129 Prescaler::DividedBy2 => Presc::DIV2, 138 self.isr().modify(|reg| {
130 Prescaler::DividedBy4 => Presc::DIV4, 139 reg.set_ovr(true);
131 Prescaler::DividedBy6 => Presc::DIV6, 140 });
132 Prescaler::DividedBy8 => Presc::DIV8, 141 self.cfgr().modify(|reg| {
133 Prescaler::DividedBy10 => Presc::DIV10, 142 reg.set_cont(true);
134 Prescaler::DividedBy12 => Presc::DIV12, 143 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
135 Prescaler::DividedBy16 => Presc::DIV16, 144 });
136 Prescaler::DividedBy32 => Presc::DIV32, 145 }
137 Prescaler::DividedBy64 => Presc::DIV64, 146 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
138 Prescaler::DividedBy128 => Presc::DIV128, 147 _ => unreachable!(),
139 Prescaler::DividedBy256 => Presc::DIV256,
140 } 148 }
141 } 149 }
142}
143 150
144/// Number of samples used for averaging. 151 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
145#[derive(Copy, Clone, Debug)] 152 // Set sequence length
146#[cfg_attr(feature = "defmt", derive(defmt::Format))] 153 self.sqr1().modify(|w| {
147pub enum Averaging { 154 w.set_l(sequence.len() as u8 - 1);
148 Disabled, 155 });
149 Samples2, 156
150 Samples4, 157 // Configure channels and ranks
151 Samples8, 158 for (i, ((channel, _), sample_time)) in sequence.enumerate() {
152 Samples16, 159 let sample_time = sample_time.into();
153 Samples32, 160 if channel <= 9 {
154 Samples64, 161 self.smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time));
155 Samples128, 162 } else {
156 Samples256, 163 self.smpr(1).modify(|reg| reg.set_smp((channel - 10) as _, sample_time));
157 Samples512, 164 }
158 Samples1024, 165
166 #[cfg(any(stm32h7, stm32u5))]
167 {
168 self.cfgr2().modify(|w| w.set_lshift(0));
169 self.pcsel().modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
170 }
171
172 match i {
173 0..=3 => {
174 self.sqr1().modify(|w| {
175 w.set_sq(i, channel);
176 });
177 }
178 4..=8 => {
179 self.sqr2().modify(|w| {
180 w.set_sq(i - 4, channel);
181 });
182 }
183 9..=13 => {
184 self.sqr3().modify(|w| {
185 w.set_sq(i - 9, channel);
186 });
187 }
188 14..=15 => {
189 self.sqr4().modify(|w| {
190 w.set_sq(i - 14, channel);
191 });
192 }
193 _ => unreachable!(),
194 }
195 }
196 }
159} 197}
160 198
161impl<'d, T: Instance> Adc<'d, T> { 199impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
200 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
201 let s = Self::new(adc);
202
203 // Set the ADC resolution.
204 if let Some(resolution) = config.resolution {
205 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
206 }
207
208 // Set hardware averaging.
209 if let Some(averaging) = config.averaging {
210 let (enable, samples, right_shift) = match averaging {
211 Averaging::Disabled => (false, 0, 0),
212 Averaging::Samples2 => (true, 1, 1),
213 Averaging::Samples4 => (true, 3, 2),
214 Averaging::Samples8 => (true, 7, 3),
215 Averaging::Samples16 => (true, 15, 4),
216 Averaging::Samples32 => (true, 31, 5),
217 Averaging::Samples64 => (true, 63, 6),
218 Averaging::Samples128 => (true, 127, 7),
219 Averaging::Samples256 => (true, 255, 8),
220 Averaging::Samples512 => (true, 511, 9),
221 Averaging::Samples1024 => (true, 1023, 10),
222 };
223
224 T::regs().cfgr2().modify(|reg| {
225 reg.set_rovse(enable);
226 reg.set_ovsr(samples);
227 reg.set_ovss(right_shift);
228 })
229 }
230
231 s
232 }
233
162 /// Create a new ADC driver. 234 /// Create a new ADC driver.
163 pub fn new(adc: Peri<'d, T>) -> Self { 235 pub fn new(adc: Peri<'d, T>) -> Self {
164 rcc::enable_and_reset::<T>(); 236 rcc::enable_and_reset::<T>();
165 237
166 let prescaler = Prescaler::from_ker_ck(T::frequency()); 238 let prescaler = from_ker_ck(T::frequency());
167 239
168 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 240 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
169 241
170 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 242 let frequency = T::frequency() / prescaler;
171 info!("ADC frequency set to {}", frequency); 243 info!("ADC frequency set to {}", frequency);
172 244
173 if frequency > MAX_ADC_CLK_FREQ { 245 if frequency > MAX_ADC_CLK_FREQ {
174 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 246 panic!(
247 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
248 MAX_ADC_CLK_FREQ.0 / 1_000_000
249 );
175 } 250 }
176 251
177 #[cfg(stm32h7)] 252 #[cfg(stm32h7)]
@@ -187,40 +262,20 @@ impl<'d, T: Instance> Adc<'d, T> {
187 }; 262 };
188 T::regs().cr().modify(|w| w.set_boost(boost)); 263 T::regs().cr().modify(|w| w.set_boost(boost));
189 } 264 }
190 let mut s = Self {
191 adc,
192 sample_time: SampleTime::from_bits(0),
193 };
194 s.power_up();
195 s.configure_differential_inputs();
196
197 s.calibrate();
198 blocking_delay_us(1);
199 265
200 s.enable();
201 s.configure();
202
203 s
204 }
205
206 fn power_up(&mut self) {
207 T::regs().cr().modify(|reg| { 266 T::regs().cr().modify(|reg| {
208 reg.set_deeppwd(false); 267 reg.set_deeppwd(false);
209 reg.set_advregen(true); 268 reg.set_advregen(true);
210 }); 269 });
211 270
212 blocking_delay_us(10); 271 blocking_delay_us(10);
213 }
214 272
215 fn configure_differential_inputs(&mut self) {
216 T::regs().difsel().modify(|w| { 273 T::regs().difsel().modify(|w| {
217 for n in 0..20 { 274 for n in 0..20 {
218 w.set_difsel(n, Difsel::SINGLE_ENDED); 275 w.set_difsel(n, Difsel::SINGLE_ENDED);
219 } 276 }
220 }); 277 });
221 }
222 278
223 fn calibrate(&mut self) {
224 T::regs().cr().modify(|w| { 279 T::regs().cr().modify(|w| {
225 #[cfg(not(adc_u5))] 280 #[cfg(not(adc_u5))]
226 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 281 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
@@ -230,21 +285,18 @@ impl<'d, T: Instance> Adc<'d, T> {
230 T::regs().cr().modify(|w| w.set_adcal(true)); 285 T::regs().cr().modify(|w| w.set_adcal(true));
231 286
232 while T::regs().cr().read().adcal() {} 287 while T::regs().cr().read().adcal() {}
233 }
234 288
235 fn enable(&mut self) { 289 blocking_delay_us(1);
236 T::regs().isr().write(|w| w.set_adrdy(true)); 290
237 T::regs().cr().modify(|w| w.set_aden(true)); 291 T::regs().enable();
238 while !T::regs().isr().read().adrdy() {}
239 T::regs().isr().write(|w| w.set_adrdy(true));
240 }
241 292
242 fn configure(&mut self) {
243 // single conversion mode, software trigger 293 // single conversion mode, software trigger
244 T::regs().cfgr().modify(|w| { 294 T::regs().cfgr().modify(|w| {
245 w.set_cont(false); 295 w.set_cont(false);
246 w.set_exten(Exten::DISABLED); 296 w.set_exten(Exten::DISABLED);
247 }); 297 });
298
299 Self { adc }
248 } 300 }
249 301
250 /// Enable reading the voltage reference internal channel. 302 /// Enable reading the voltage reference internal channel.
@@ -273,228 +325,4 @@ impl<'d, T: Instance> Adc<'d, T> {
273 325
274 Vbat {} 326 Vbat {}
275 } 327 }
276
277 /// Set the ADC sample time.
278 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
279 self.sample_time = sample_time;
280 }
281
282 /// Get the ADC sample time.
283 pub fn sample_time(&self) -> SampleTime {
284 self.sample_time
285 }
286
287 /// Set the ADC resolution.
288 pub fn set_resolution(&mut self, resolution: Resolution) {
289 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
290 }
291
292 /// Set hardware averaging.
293 pub fn set_averaging(&mut self, averaging: Averaging) {
294 let (enable, samples, right_shift) = match averaging {
295 Averaging::Disabled => (false, 0, 0),
296 Averaging::Samples2 => (true, 1, 1),
297 Averaging::Samples4 => (true, 3, 2),
298 Averaging::Samples8 => (true, 7, 3),
299 Averaging::Samples16 => (true, 15, 4),
300 Averaging::Samples32 => (true, 31, 5),
301 Averaging::Samples64 => (true, 63, 6),
302 Averaging::Samples128 => (true, 127, 7),
303 Averaging::Samples256 => (true, 255, 8),
304 Averaging::Samples512 => (true, 511, 9),
305 Averaging::Samples1024 => (true, 1023, 10),
306 };
307
308 T::regs().cfgr2().modify(|reg| {
309 reg.set_rovse(enable);
310 reg.set_ovsr(samples);
311 reg.set_ovss(right_shift);
312 })
313 }
314
315 /// Perform a single conversion.
316 fn convert(&mut self) -> u16 {
317 T::regs().isr().modify(|reg| {
318 reg.set_eos(true);
319 reg.set_eoc(true);
320 });
321
322 // Start conversion
323 T::regs().cr().modify(|reg| {
324 reg.set_adstart(true);
325 });
326
327 while !T::regs().isr().read().eos() {
328 // spin
329 }
330
331 T::regs().dr().read().0 as u16
332 }
333
334 /// Read an ADC channel.
335 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
336 self.read_channel(channel)
337 }
338
339 /// Read one or multiple ADC channels using DMA.
340 ///
341 /// `sequence` iterator and `readings` must have the same length.
342 ///
343 /// Example
344 /// ```rust,ignore
345 /// use embassy_stm32::adc::{Adc, AdcChannel}
346 ///
347 /// let mut adc = Adc::new(p.ADC1);
348 /// let mut adc_pin0 = p.PA0.into();
349 /// let mut adc_pin2 = p.PA2.into();
350 /// let mut measurements = [0u16; 2];
351 ///
352 /// adc.read(
353 /// p.DMA2_CH0.reborrow(),
354 /// [
355 /// (&mut *adc_pin0, SampleTime::CYCLES112),
356 /// (&mut *adc_pin2, SampleTime::CYCLES112),
357 /// ]
358 /// .into_iter(),
359 /// &mut measurements,
360 /// )
361 /// .await;
362 /// defmt::info!("measurements: {}", measurements);
363 /// ```
364 pub async fn read(
365 &mut self,
366 rx_dma: Peri<'_, impl RxDma<T>>,
367 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
368 readings: &mut [u16],
369 ) {
370 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
371 assert!(
372 sequence.len() == readings.len(),
373 "Sequence length must be equal to readings length"
374 );
375 assert!(
376 sequence.len() <= 16,
377 "Asynchronous read sequence cannot be more than 16 in length"
378 );
379
380 // Ensure no conversions are ongoing
381 Self::cancel_conversions();
382
383 // Set sequence length
384 T::regs().sqr1().modify(|w| {
385 w.set_l(sequence.len() as u8 - 1);
386 });
387
388 // Configure channels and ranks
389 for (i, (channel, sample_time)) in sequence.enumerate() {
390 Self::configure_channel(channel, sample_time);
391 match i {
392 0..=3 => {
393 T::regs().sqr1().modify(|w| {
394 w.set_sq(i, channel.channel());
395 });
396 }
397 4..=8 => {
398 T::regs().sqr2().modify(|w| {
399 w.set_sq(i - 4, channel.channel());
400 });
401 }
402 9..=13 => {
403 T::regs().sqr3().modify(|w| {
404 w.set_sq(i - 9, channel.channel());
405 });
406 }
407 14..=15 => {
408 T::regs().sqr4().modify(|w| {
409 w.set_sq(i - 14, channel.channel());
410 });
411 }
412 _ => unreachable!(),
413 }
414 }
415
416 // Set continuous mode with oneshot dma.
417 // Clear overrun flag before starting transfer.
418
419 T::regs().isr().modify(|reg| {
420 reg.set_ovr(true);
421 });
422 T::regs().cfgr().modify(|reg| {
423 reg.set_cont(true);
424 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
425 });
426
427 let request = rx_dma.request();
428 let transfer = unsafe {
429 Transfer::new_read(
430 rx_dma,
431 request,
432 T::regs().dr().as_ptr() as *mut u16,
433 readings,
434 Default::default(),
435 )
436 };
437
438 // Start conversion
439 T::regs().cr().modify(|reg| {
440 reg.set_adstart(true);
441 });
442
443 // Wait for conversion sequence to finish.
444 transfer.await;
445
446 // Ensure conversions are finished.
447 Self::cancel_conversions();
448
449 // Reset configuration.
450 T::regs().cfgr().modify(|reg| {
451 reg.set_cont(false);
452 reg.set_dmngt(Dmngt::from_bits(0));
453 });
454 }
455
456 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
457 channel.setup();
458
459 let channel = channel.channel();
460
461 Self::set_channel_sample_time(channel, sample_time);
462
463 #[cfg(any(stm32h7, stm32u5))]
464 {
465 T::regs().cfgr2().modify(|w| w.set_lshift(0));
466 T::regs()
467 .pcsel()
468 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
469 }
470 }
471
472 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
473 Self::configure_channel(channel, self.sample_time);
474
475 T::regs().sqr1().modify(|reg| {
476 reg.set_sq(0, channel.channel());
477 reg.set_l(0);
478 });
479
480 self.convert()
481 }
482
483 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
484 let sample_time = sample_time.into();
485 if ch <= 9 {
486 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
487 } else {
488 T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
489 }
490 }
491
492 fn cancel_conversions() {
493 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
494 T::regs().cr().modify(|reg| {
495 reg.set_adstp(Adstp::STOP);
496 });
497 while T::regs().cr().read().adstart() {}
498 }
499 }
500} 328}
diff --git a/embassy-stm32/src/adc/watchdog_v1.rs b/embassy-stm32/src/adc/watchdog_v1.rs
index bbe8e1971..b12e0d333 100644
--- a/embassy-stm32/src/adc/watchdog_v1.rs
+++ b/embassy-stm32/src/adc/watchdog_v1.rs
@@ -1,7 +1,7 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::task::Poll; 2use core::task::Poll;
3 3
4use stm32_metapac::adc::vals::{Align, Awdsgl, Res}; 4use stm32_metapac::adc::vals::{Align, Awdsgl, Res, SampleTime};
5 5
6use crate::adc::{Adc, AdcChannel, Instance}; 6use crate::adc::{Adc, AdcChannel, Instance};
7 7
@@ -67,7 +67,7 @@ impl<'d, T: Instance> Adc<'d, T> {
67 /// let v_high = adc.monitor_watchdog().await; 67 /// let v_high = adc.monitor_watchdog().await;
68 /// info!("ADC sample is high {}", v_high); 68 /// info!("ADC sample is high {}", v_high);
69 /// ``` 69 /// ```
70 pub async fn monitor_watchdog(&mut self) -> u16 { 70 pub async fn monitor_watchdog(&mut self, sample_time: SampleTime) -> u16 {
71 assert!( 71 assert!(
72 match T::regs().cfgr1().read().awdsgl() { 72 match T::regs().cfgr1().read().awdsgl() {
73 Awdsgl::SINGLE_CHANNEL => T::regs().cfgr1().read().awdch() != 0, 73 Awdsgl::SINGLE_CHANNEL => T::regs().cfgr1().read().awdch() != 0,
@@ -76,7 +76,7 @@ impl<'d, T: Instance> Adc<'d, T> {
76 "`set_channel` should be called before `monitor`", 76 "`set_channel` should be called before `monitor`",
77 ); 77 );
78 assert!(T::regs().chselr().read().0 != 0); 78 assert!(T::regs().chselr().read().0 != 0);
79 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); 79 T::regs().smpr().modify(|reg| reg.set_smp(sample_time.into()));
80 Self::start_awd(); 80 Self::start_awd();
81 81
82 let sample = poll_fn(|cx| { 82 let sample = poll_fn(|cx| {
diff --git a/embassy-stm32/src/backup_sram.rs b/embassy-stm32/src/backup_sram.rs
new file mode 100644
index 000000000..31b373c6c
--- /dev/null
+++ b/embassy-stm32/src/backup_sram.rs
@@ -0,0 +1,28 @@
1//! Battary backed SRAM
2
3use core::slice;
4
5use embassy_hal_internal::Peri;
6
7use crate::_generated::{BKPSRAM_BASE, BKPSRAM_SIZE};
8use crate::peripherals::BKPSRAM;
9
10/// Struct used to initilize backup sram
11pub struct BackupMemory {}
12
13impl BackupMemory {
14 /// Setup battery backed sram
15 ///
16 /// Returns slice to sram and whether the sram was retained
17 pub fn new(_backup_sram: Peri<'static, BKPSRAM>) -> (&'static mut [u8], bool) {
18 // Assert bksram has been enabled in rcc
19 assert!(crate::pac::PWR.bdcr().read().bren() == crate::pac::pwr::vals::Retention::PRESERVED);
20
21 unsafe {
22 (
23 slice::from_raw_parts_mut(BKPSRAM_BASE as *mut u8, BKPSRAM_SIZE),
24 critical_section::with(|_| crate::rcc::BKSRAM_RETAINED),
25 )
26 }
27 }
28}
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index 8eb188560..507350c42 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -5,8 +5,8 @@ use core::future::poll_fn;
5use core::marker::PhantomData; 5use core::marker::PhantomData;
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_hal_internal::interrupt::InterruptExt;
9use embassy_hal_internal::PeripheralType; 8use embassy_hal_internal::PeripheralType;
9use embassy_hal_internal::interrupt::InterruptExt;
10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
11use embassy_sync::channel::Channel; 11use embassy_sync::channel::Channel;
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
@@ -22,7 +22,7 @@ use crate::can::enums::{BusError, RefCountOp, TryReadError};
22use crate::gpio::{AfType, OutputType, Pull, Speed}; 22use crate::gpio::{AfType, OutputType, Pull, Speed};
23use crate::interrupt::typelevel::Interrupt; 23use crate::interrupt::typelevel::Interrupt;
24use crate::rcc::{self, RccPeripheral}; 24use crate::rcc::{self, RccPeripheral};
25use crate::{interrupt, peripherals, Peri}; 25use crate::{Peri, interrupt, peripherals};
26 26
27/// Interrupt handler. 27/// Interrupt handler.
28pub struct TxInterruptHandler<T: Instance> { 28pub struct TxInterruptHandler<T: Instance> {
@@ -186,10 +186,10 @@ impl<'d> Can<'d> {
186 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>, 186 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
187 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>, 187 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
188 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> 188 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
189 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> 189 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
190 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> 190 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
191 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> 191 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
192 + 'd, 192 + 'd,
193 ) -> Self { 193 ) -> Self {
194 let info = T::info(); 194 let info = T::info();
195 let regs = &T::info().regs; 195 let regs = &T::info().regs;
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs
index 6d91020fc..c5900cadc 100644
--- a/embassy-stm32/src/can/enums.rs
+++ b/embassy-stm32/src/can/enums.rs
@@ -82,3 +82,40 @@ pub enum RefCountOp {
82 /// Notify sender destroyed 82 /// Notify sender destroyed
83 NotifySenderDestroyed, 83 NotifySenderDestroyed,
84} 84}
85
86/// Error returned when calculating the can timing fails
87#[derive(Debug)]
88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89pub enum TimingCalcError {
90 /// Bitrate is lower than 1000
91 BitrateTooLow {
92 /// The set bitrate
93 bitrate: u32,
94 },
95 /// No solution possible
96 NoSolution {
97 /// The sum of BS1 and BS2
98 bs1_bs2_sum: u8,
99 },
100 /// Prescaler is not 1 < prescaler < 1024
101 InvalidPrescaler {
102 /// The calculated prescaler value
103 prescaler: u32,
104 },
105 /// BS1 or BS2 are not in the range 0 < BSx < BSx_MAX
106 BSNotInRange {
107 /// The value of BS1
108 bs1: u8,
109 /// The value of BS2
110 bs2: u8,
111 },
112 /// Final bitrate doesn't match the requested bitrate
113 NoMatch {
114 /// The requested bitrate
115 requested: u32,
116 /// The calculated bitrate
117 final_calculated: u32,
118 },
119 /// core::num::NonZeroUxx::new error
120 CoreNumNew,
121}
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
index c6a66b469..4fe634ce4 100644
--- a/embassy-stm32/src/can/fd/config.rs
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -1,7 +1,7 @@
1//! Configuration for FDCAN Module 1//! Configuration for FDCAN Module
2// Note: This file is copied and modified from fdcan crate by Richard Meadows 2// Note: This file is copied and modified from fdcan crate by Richard Meadows
3 3
4use core::num::{NonZeroU16, NonZeroU8}; 4use core::num::{NonZeroU8, NonZeroU16};
5 5
6/// Configures the bit timings. 6/// Configures the bit timings.
7/// 7///
@@ -360,6 +360,8 @@ pub struct FdCanConfig {
360 pub global_filter: GlobalFilter, 360 pub global_filter: GlobalFilter,
361 /// TX buffer mode (FIFO or priority queue) 361 /// TX buffer mode (FIFO or priority queue)
362 pub tx_buffer_mode: TxBufferMode, 362 pub tx_buffer_mode: TxBufferMode,
363 /// Automatic recovery from bus off state
364 pub automatic_bus_off_recovery: bool,
363} 365}
364 366
365impl FdCanConfig { 367impl FdCanConfig {
@@ -456,6 +458,16 @@ impl FdCanConfig {
456 self.tx_buffer_mode = txbm; 458 self.tx_buffer_mode = txbm;
457 self 459 self
458 } 460 }
461
462 /// Enables or disables automatic recovery from bus off state
463 ///
464 /// Automatic recovery is performed by clearing the INIT bit in the CCCR register if
465 /// the BO bit is active in the IR register in the IT0 interrupt.
466 #[inline]
467 pub const fn set_automatic_bus_off_recovery(mut self, enabled: bool) -> Self {
468 self.automatic_bus_off_recovery = enabled;
469 self
470 }
459} 471}
460 472
461impl Default for FdCanConfig { 473impl Default for FdCanConfig {
@@ -474,6 +486,7 @@ impl Default for FdCanConfig {
474 timestamp_source: TimestampSource::None, 486 timestamp_source: TimestampSource::None,
475 global_filter: GlobalFilter::default(), 487 global_filter: GlobalFilter::default(),
476 tx_buffer_mode: TxBufferMode::Priority, 488 tx_buffer_mode: TxBufferMode::Priority,
489 automatic_bus_off_recovery: true,
477 } 490 }
478 } 491 }
479} 492}
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index d8f71e03e..9883aff57 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -3,8 +3,8 @@ use core::future::poll_fn;
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_hal_internal::interrupt::InterruptExt;
7use embassy_hal_internal::PeripheralType; 6use embassy_hal_internal::PeripheralType;
7use embassy_hal_internal::interrupt::InterruptExt;
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_sync::channel::Channel; 9use embassy_sync::channel::Channel;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
@@ -13,7 +13,7 @@ use crate::can::fd::peripheral::Registers;
13use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed};
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::rcc::{self, RccPeripheral}; 15use crate::rcc::{self, RccPeripheral};
16use crate::{interrupt, peripherals, Peri}; 16use crate::{Peri, interrupt, peripherals};
17 17
18pub(crate) mod fd; 18pub(crate) mod fd;
19 19
@@ -53,7 +53,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
53 regs.ir().write(|w| w.set_tefn(true)); 53 regs.ir().write(|w| w.set_tefn(true));
54 } 54 }
55 55
56 T::info().state.lock(|s| { 56 let recover_from_bo = T::info().state.lock(|s| {
57 let state = s.borrow_mut(); 57 let state = s.borrow_mut();
58 match &state.tx_mode { 58 match &state.tx_mode {
59 TxMode::NonBuffered(waker) => waker.wake(), 59 TxMode::NonBuffered(waker) => waker.wake(),
@@ -85,11 +85,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
85 if ir.rfn(1) { 85 if ir.rfn(1) {
86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick); 86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick);
87 } 87 }
88
89 state.automatic_bus_off_recovery
88 }); 90 });
89 91
90 if ir.bo() { 92 if ir.bo() {
91 regs.ir().write(|w| w.set_bo(true)); 93 regs.ir().write(|w| w.set_bo(true));
92 if regs.psr().read().bo() { 94 if let Some(true) = recover_from_bo
95 && regs.psr().read().bo()
96 {
93 // Initiate bus-off recovery sequence by resetting CCCR.INIT 97 // Initiate bus-off recovery sequence by resetting CCCR.INIT
94 regs.cccr().modify(|w| w.set_init(false)); 98 regs.cccr().modify(|w| w.set_init(false));
95 } 99 }
@@ -182,8 +186,8 @@ impl<'d> CanConfigurator<'d> {
182 rx: Peri<'d, impl RxPin<T>>, 186 rx: Peri<'d, impl RxPin<T>>,
183 tx: Peri<'d, impl TxPin<T>>, 187 tx: Peri<'d, impl TxPin<T>>,
184 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> 188 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
185 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> 189 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
186 + 'd, 190 + 'd,
187 ) -> CanConfigurator<'d> { 191 ) -> CanConfigurator<'d> {
188 set_as_af!(rx, AfType::input(Pull::None)); 192 set_as_af!(rx, AfType::input(Pull::None));
189 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 193 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
@@ -263,7 +267,9 @@ impl<'d> CanConfigurator<'d> {
263 pub fn start(self, mode: OperatingMode) -> Can<'d> { 267 pub fn start(self, mode: OperatingMode) -> Can<'d> {
264 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit); 268 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit);
265 self.info.state.lock(|s| { 269 self.info.state.lock(|s| {
266 s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; 270 let mut state = s.borrow_mut();
271 state.ns_per_timer_tick = ns_per_timer_tick;
272 state.automatic_bus_off_recovery = Some(self.config.automatic_bus_off_recovery);
267 }); 273 });
268 self.info.regs.into_mode(self.config, mode); 274 self.info.regs.into_mode(self.config, mode);
269 Can { 275 Can {
@@ -459,7 +465,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d,
459 pub async fn write(&mut self, frame: Frame) { 465 pub async fn write(&mut self, frame: Frame) {
460 self.tx_buf.send(frame).await; 466 self.tx_buf.send(frame).await;
461 self.info.interrupt0.pend(); // Wake for Tx 467 self.info.interrupt0.pend(); // Wake for Tx
462 //T::IT0Interrupt::pend(); // Wake for Tx 468 //T::IT0Interrupt::pend(); // Wake for Tx
463 } 469 }
464 470
465 /// Async read frame from RX buffer. 471 /// Async read frame from RX buffer.
@@ -548,7 +554,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
548 pub async fn write(&mut self, frame: FdFrame) { 554 pub async fn write(&mut self, frame: FdFrame) {
549 self.tx_buf.send(frame).await; 555 self.tx_buf.send(frame).await;
550 self.info.interrupt0.pend(); // Wake for Tx 556 self.info.interrupt0.pend(); // Wake for Tx
551 //T::IT0Interrupt::pend(); // Wake for Tx 557 //T::IT0Interrupt::pend(); // Wake for Tx
552 } 558 }
553 559
554 /// Async read frame from RX buffer. 560 /// Async read frame from RX buffer.
@@ -861,7 +867,7 @@ struct State {
861 sender_instance_count: usize, 867 sender_instance_count: usize,
862 tx_pin_port: Option<u8>, 868 tx_pin_port: Option<u8>,
863 rx_pin_port: Option<u8>, 869 rx_pin_port: Option<u8>,
864 870 automatic_bus_off_recovery: Option<bool>, // controlled by CanConfigurator::start()
865 pub err_waker: AtomicWaker, 871 pub err_waker: AtomicWaker,
866} 872}
867 873
@@ -876,6 +882,7 @@ impl State {
876 sender_instance_count: 0, 882 sender_instance_count: 0,
877 tx_pin_port: None, 883 tx_pin_port: None,
878 rx_pin_port: None, 884 rx_pin_port: None,
885 automatic_bus_off_recovery: None,
879 } 886 }
880 } 887 }
881} 888}
diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs
index fcdbbad62..beca4c34e 100644
--- a/embassy-stm32/src/can/util.rs
+++ b/embassy-stm32/src/can/util.rs
@@ -1,6 +1,8 @@
1//! Utility functions shared between CAN controller types. 1//! Utility functions shared between CAN controller types.
2 2
3use core::num::{NonZeroU16, NonZeroU8}; 3use core::num::{NonZeroU8, NonZeroU16};
4
5use crate::can::enums::TimingCalcError;
4 6
5/// Shared struct to represent bit timings used by calc_can_timings. 7/// Shared struct to represent bit timings used by calc_can_timings.
6#[derive(Clone, Copy, Debug)] 8#[derive(Clone, Copy, Debug)]
@@ -17,7 +19,10 @@ pub struct NominalBitTiming {
17} 19}
18 20
19/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency 21/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency
20pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> { 22pub fn calc_can_timings(
23 periph_clock: crate::time::Hertz,
24 can_bitrate: u32,
25) -> Result<NominalBitTiming, TimingCalcError> {
21 const BS1_MAX: u8 = 16; 26 const BS1_MAX: u8 = 16;
22 const BS2_MAX: u8 = 8; 27 const BS2_MAX: u8 = 8;
23 const MAX_SAMPLE_POINT_PERMILL: u16 = 900; 28 const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
@@ -25,7 +30,7 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O
25 let periph_clock = periph_clock.0; 30 let periph_clock = periph_clock.0;
26 31
27 if can_bitrate < 1000 { 32 if can_bitrate < 1000 {
28 return None; 33 return Err(TimingCalcError::BitrateTooLow { bitrate: can_bitrate });
29 } 34 }
30 35
31 // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG 36 // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
@@ -53,14 +58,14 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O
53 let mut bs1_bs2_sum = max_quanta_per_bit - 1; 58 let mut bs1_bs2_sum = max_quanta_per_bit - 1;
54 while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { 59 while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
55 if bs1_bs2_sum <= 2 { 60 if bs1_bs2_sum <= 2 {
56 return None; // No solution 61 return Err(TimingCalcError::NoSolution { bs1_bs2_sum }); // No solution
57 } 62 }
58 bs1_bs2_sum -= 1; 63 bs1_bs2_sum -= 1;
59 } 64 }
60 65
61 let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; 66 let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
62 if (prescaler < 1) || (prescaler > 1024) { 67 if (prescaler < 1) || (prescaler > 1024) {
63 return None; // No solution 68 return Err(TimingCalcError::InvalidPrescaler { prescaler }); // No solution
64 } 69 }
65 70
66 // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. 71 // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
@@ -93,22 +98,26 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O
93 98
94 // Check is BS1 and BS2 are in range 99 // Check is BS1 and BS2 are in range
95 if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { 100 if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
96 return None; 101 return Err(TimingCalcError::BSNotInRange { bs1, bs2 });
97 } 102 }
98 103
104 let calculated = periph_clock / (prescaler * (1 + bs1 + bs2) as u32);
99 // Check if final bitrate matches the requested 105 // Check if final bitrate matches the requested
100 if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { 106 if can_bitrate != calculated {
101 return None; 107 return Err(TimingCalcError::NoMatch {
108 requested: can_bitrate,
109 final_calculated: calculated,
110 });
102 } 111 }
103 112
104 // One is recommended by DS-015, CANOpen, and DeviceNet 113 // One is recommended by DS-015, CANOpen, and DeviceNet
105 let sync_jump_width = core::num::NonZeroU8::new(1)?; 114 let sync_jump_width = core::num::NonZeroU8::new(1).ok_or(TimingCalcError::CoreNumNew)?;
106 115
107 let seg1 = core::num::NonZeroU8::new(bs1)?; 116 let seg1 = core::num::NonZeroU8::new(bs1).ok_or(TimingCalcError::CoreNumNew)?;
108 let seg2 = core::num::NonZeroU8::new(bs2)?; 117 let seg2 = core::num::NonZeroU8::new(bs2).ok_or(TimingCalcError::CoreNumNew)?;
109 let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?; 118 let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16).ok_or(TimingCalcError::CoreNumNew)?;
110 119
111 Some(NominalBitTiming { 120 Ok(NominalBitTiming {
112 sync_jump_width, 121 sync_jump_width,
113 prescaler: nz_prescaler, 122 prescaler: nz_prescaler,
114 seg1, 123 seg1,
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index 13e5263de..836228599 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -1,6 +1,6 @@
1use crate::pac::CRC as PAC_CRC; 1use crate::pac::CRC as PAC_CRC;
2use crate::peripherals::CRC; 2use crate::peripherals::CRC;
3use crate::{rcc, Peri}; 3use crate::{Peri, rcc};
4 4
5/// CRC driver. 5/// CRC driver.
6pub struct Crc<'d> { 6pub struct Crc<'d> {
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index d834d0971..a566a2e04 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -1,7 +1,7 @@
1use crate::pac::crc::vals;
2use crate::pac::CRC as PAC_CRC; 1use crate::pac::CRC as PAC_CRC;
2use crate::pac::crc::vals;
3use crate::peripherals::CRC; 3use crate::peripherals::CRC;
4use crate::{rcc, Peri}; 4use crate::{Peri, rcc};
5 5
6/// CRC driver. 6/// CRC driver.
7pub struct Crc<'d> { 7pub struct Crc<'d> {
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 0173b2b5d..4f1115fb7 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1236,7 +1236,10 @@ impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> {
1236 } 1236 }
1237 if C::REQUIRES_PADDING { 1237 if C::REQUIRES_PADDING {
1238 if last_block_remainder != 0 { 1238 if last_block_remainder != 0 {
1239 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); 1239 panic!(
1240 "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.",
1241 C::BLOCK_SIZE
1242 );
1240 } 1243 }
1241 } 1244 }
1242 if last_block { 1245 if last_block {
@@ -1703,7 +1706,10 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
1703 } 1706 }
1704 if C::REQUIRES_PADDING { 1707 if C::REQUIRES_PADDING {
1705 if last_block_remainder != 0 { 1708 if last_block_remainder != 0 {
1706 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); 1709 panic!(
1710 "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.",
1711 C::BLOCK_SIZE
1712 );
1707 } 1713 }
1708 } 1714 }
1709 if last_block { 1715 if last_block {
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 08e001337..d74d4a4be 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -8,7 +8,7 @@ use crate::mode::{Async, Blocking, Mode as PeriMode};
8#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] 8#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
9use crate::pac::dac; 9use crate::pac::dac;
10use crate::rcc::{self, RccPeripheral}; 10use crate::rcc::{self, RccPeripheral};
11use crate::{peripherals, Peri}; 11use crate::{Peri, peripherals};
12 12
13mod tsel; 13mod tsel;
14use embassy_hal_internal::PeripheralType; 14use embassy_hal_internal::PeripheralType;
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index bd03f1e00..dcae9f298 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
9use crate::dma::Transfer; 9use crate::dma::Transfer;
10use crate::gpio::{AfType, Pull}; 10use crate::gpio::{AfType, Pull};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, rcc, Peri}; 12use crate::{Peri, interrupt, rcc};
13 13
14/// Interrupt handler. 14/// Interrupt handler.
15pub struct InterruptHandler<T: Instance> { 15pub struct InterruptHandler<T: Instance> {
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
index 73ecab070..adc084474 100644
--- a/embassy-stm32/src/dma/dma_bdma.rs
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -1,6 +1,6 @@
1use core::future::{poll_fn, Future}; 1use core::future::{Future, poll_fn};
2use core::pin::Pin; 2use core::pin::Pin;
3use core::sync::atomic::{fence, AtomicUsize, Ordering}; 3use core::sync::atomic::{AtomicUsize, Ordering, fence};
4use core::task::{Context, Poll, Waker}; 4use core::task::{Context, Poll, Waker};
5 5
6use embassy_hal_internal::Peri; 6use embassy_hal_internal::Peri;
@@ -10,6 +10,7 @@ use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBu
10use super::word::{Word, WordSize}; 10use super::word::{Word, WordSize};
11use super::{AnyChannel, Channel, Dir, Request, STATE}; 11use super::{AnyChannel, Channel, Dir, Request, STATE};
12use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
13use crate::rcc::BusyPeripheral;
13use crate::{interrupt, pac}; 14use crate::{interrupt, pac};
14 15
15pub(crate) struct ChannelInfo { 16pub(crate) struct ChannelInfo {
@@ -602,7 +603,7 @@ impl AnyChannel {
602/// DMA transfer. 603/// DMA transfer.
603#[must_use = "futures do nothing unless you `.await` or poll them"] 604#[must_use = "futures do nothing unless you `.await` or poll them"]
604pub struct Transfer<'a> { 605pub struct Transfer<'a> {
605 channel: Peri<'a, AnyChannel>, 606 channel: BusyPeripheral<Peri<'a, AnyChannel>>,
606} 607}
607 608
608impl<'a> Transfer<'a> { 609impl<'a> Transfer<'a> {
@@ -713,7 +714,9 @@ impl<'a> Transfer<'a> {
713 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options, 714 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options,
714 ); 715 );
715 channel.start(); 716 channel.start();
716 Self { channel } 717 Self {
718 channel: BusyPeripheral::new(channel),
719 }
717 } 720 }
718 721
719 /// Request the transfer to pause, keeping the existing configuration for this channel. 722 /// Request the transfer to pause, keeping the existing configuration for this channel.
@@ -816,7 +819,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
816 819
817/// Ringbuffer for receiving data using DMA circular mode. 820/// Ringbuffer for receiving data using DMA circular mode.
818pub struct ReadableRingBuffer<'a, W: Word> { 821pub struct ReadableRingBuffer<'a, W: Word> {
819 channel: Peri<'a, AnyChannel>, 822 channel: BusyPeripheral<Peri<'a, AnyChannel>>,
820 ringbuf: ReadableDmaRingBuffer<'a, W>, 823 ringbuf: ReadableDmaRingBuffer<'a, W>,
821} 824}
822 825
@@ -853,7 +856,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
853 ); 856 );
854 857
855 Self { 858 Self {
856 channel, 859 channel: BusyPeripheral::new(channel),
857 ringbuf: ReadableDmaRingBuffer::new(buffer), 860 ringbuf: ReadableDmaRingBuffer::new(buffer),
858 } 861 }
859 } 862 }
@@ -972,7 +975,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
972 975
973/// Ringbuffer for writing data using DMA circular mode. 976/// Ringbuffer for writing data using DMA circular mode.
974pub struct WritableRingBuffer<'a, W: Word> { 977pub struct WritableRingBuffer<'a, W: Word> {
975 channel: Peri<'a, AnyChannel>, 978 channel: BusyPeripheral<Peri<'a, AnyChannel>>,
976 ringbuf: WritableDmaRingBuffer<'a, W>, 979 ringbuf: WritableDmaRingBuffer<'a, W>,
977} 980}
978 981
@@ -1009,7 +1012,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
1009 ); 1012 );
1010 1013
1011 Self { 1014 Self {
1012 channel, 1015 channel: BusyPeripheral::new(channel),
1013 ringbuf: WritableDmaRingBuffer::new(buffer), 1016 ringbuf: WritableDmaRingBuffer::new(buffer),
1014 } 1017 }
1015 } 1018 }
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs
index 4a14c2a8e..afb18ec1a 100644
--- a/embassy-stm32/src/dma/gpdma/mod.rs
+++ b/embassy-stm32/src/dma/gpdma/mod.rs
@@ -2,7 +2,7 @@
2 2
3use core::future::Future; 3use core::future::Future;
4use core::pin::Pin; 4use core::pin::Pin;
5use core::sync::atomic::{fence, AtomicUsize, Ordering}; 5use core::sync::atomic::{AtomicUsize, Ordering, fence};
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
@@ -14,6 +14,7 @@ use super::{AnyChannel, Channel, Dir, Request, STATE};
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::pac; 15use crate::pac;
16use crate::pac::gpdma::vals; 16use crate::pac::gpdma::vals;
17use crate::rcc::BusyPeripheral;
17 18
18pub mod linked_list; 19pub mod linked_list;
19pub mod ringbuffered; 20pub mod ringbuffered;
@@ -236,6 +237,11 @@ impl AnyChannel {
236 // "Preceding reads and writes cannot be moved past subsequent writes." 237 // "Preceding reads and writes cannot be moved past subsequent writes."
237 fence(Ordering::SeqCst); 238 fence(Ordering::SeqCst);
238 239
240 if ch.cr().read().en() {
241 ch.cr().modify(|w| w.set_susp(true));
242 while !ch.sr().read().suspf() {}
243 }
244
239 ch.cr().write(|w| w.set_reset(true)); 245 ch.cr().write(|w| w.set_reset(true));
240 ch.fcr().write(|w| { 246 ch.fcr().write(|w| {
241 // Clear all irqs 247 // Clear all irqs
@@ -407,7 +413,7 @@ impl AnyChannel {
407/// Linked-list DMA transfer. 413/// Linked-list DMA transfer.
408#[must_use = "futures do nothing unless you `.await` or poll them"] 414#[must_use = "futures do nothing unless you `.await` or poll them"]
409pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { 415pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> {
410 channel: Peri<'a, AnyChannel>, 416 channel: BusyPeripheral<Peri<'a, AnyChannel>>,
411} 417}
412 418
413impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { 419impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> {
@@ -428,7 +434,9 @@ impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> {
428 channel.configure_linked_list(&table, options); 434 channel.configure_linked_list(&table, options);
429 channel.start(); 435 channel.start();
430 436
431 Self { channel } 437 Self {
438 channel: BusyPeripheral::new(channel),
439 }
432 } 440 }
433 441
434 /// Request the transfer to pause, keeping the existing configuration for this channel. 442 /// Request the transfer to pause, keeping the existing configuration for this channel.
@@ -504,7 +512,7 @@ impl<'a, const ITEM_COUNT: usize> Future for LinkedListTransfer<'a, ITEM_COUNT>
504/// DMA transfer. 512/// DMA transfer.
505#[must_use = "futures do nothing unless you `.await` or poll them"] 513#[must_use = "futures do nothing unless you `.await` or poll them"]
506pub struct Transfer<'a> { 514pub struct Transfer<'a> {
507 channel: Peri<'a, AnyChannel>, 515 channel: BusyPeripheral<Peri<'a, AnyChannel>>,
508} 516}
509 517
510impl<'a> Transfer<'a> { 518impl<'a> Transfer<'a> {
@@ -624,7 +632,9 @@ impl<'a> Transfer<'a> {
624 ); 632 );
625 channel.start(); 633 channel.start();
626 634
627 Self { channel } 635 Self {
636 channel: BusyPeripheral::new(channel),
637 }
628 } 638 }
629 639
630 /// Request the transfer to pause, keeping the existing configuration for this channel. 640 /// Request the transfer to pause, keeping the existing configuration for this channel.
diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
index 9ee52193b..c150d0b95 100644
--- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs
+++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
@@ -3,16 +3,17 @@
3//! FIXME: Add request_pause functionality? 3//! FIXME: Add request_pause functionality?
4//! FIXME: Stop the DMA, if a user does not queue new transfers (chain of linked-list items ends automatically). 4//! FIXME: Stop the DMA, if a user does not queue new transfers (chain of linked-list items ends automatically).
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::sync::atomic::{fence, Ordering}; 6use core::sync::atomic::{Ordering, fence};
7use core::task::Waker; 7use core::task::Waker;
8 8
9use embassy_hal_internal::Peri; 9use embassy_hal_internal::Peri;
10 10
11use super::{AnyChannel, TransferOptions, STATE}; 11use super::{AnyChannel, STATE, TransferOptions};
12use crate::dma::gpdma::linked_list::{RunMode, Table}; 12use crate::dma::gpdma::linked_list::{RunMode, Table};
13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
14use crate::dma::word::Word; 14use crate::dma::word::Word;
15use crate::dma::{Channel, Dir, Request}; 15use crate::dma::{Channel, Dir, Request};
16use crate::rcc::BusyPeripheral;
16 17
17struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); 18struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>);
18 19
@@ -49,7 +50,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
49 50
50/// Ringbuffer for receiving data using GPDMA linked-list mode. 51/// Ringbuffer for receiving data using GPDMA linked-list mode.
51pub struct ReadableRingBuffer<'a, W: Word> { 52pub struct ReadableRingBuffer<'a, W: Word> {
52 channel: Peri<'a, AnyChannel>, 53 channel: BusyPeripheral<Peri<'a, AnyChannel>>,
53 ringbuf: ReadableDmaRingBuffer<'a, W>, 54 ringbuf: ReadableDmaRingBuffer<'a, W>,
54 table: Table<2>, 55 table: Table<2>,
55 options: TransferOptions, 56 options: TransferOptions,
@@ -70,7 +71,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
70 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory); 71 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory);
71 72
72 Self { 73 Self {
73 channel, 74 channel: BusyPeripheral::new(channel),
74 ringbuf: ReadableDmaRingBuffer::new(buffer), 75 ringbuf: ReadableDmaRingBuffer::new(buffer),
75 table, 76 table,
76 options, 77 options,
@@ -189,7 +190,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
189 190
190/// Ringbuffer for writing data using GPDMA linked-list mode. 191/// Ringbuffer for writing data using GPDMA linked-list mode.
191pub struct WritableRingBuffer<'a, W: Word> { 192pub struct WritableRingBuffer<'a, W: Word> {
192 channel: Peri<'a, AnyChannel>, 193 channel: BusyPeripheral<Peri<'a, AnyChannel>>,
193 ringbuf: WritableDmaRingBuffer<'a, W>, 194 ringbuf: WritableDmaRingBuffer<'a, W>,
194 table: Table<2>, 195 table: Table<2>,
195 options: TransferOptions, 196 options: TransferOptions,
@@ -210,7 +211,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
210 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral); 211 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral);
211 212
212 Self { 213 Self {
213 channel, 214 channel: BusyPeripheral::new(channel),
214 ringbuf: WritableDmaRingBuffer::new(buffer), 215 ringbuf: WritableDmaRingBuffer::new(buffer),
215 table, 216 table,
216 options, 217 options,
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 5989bfd7c..05d9c2e51 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -3,6 +3,7 @@
3 3
4#[cfg(any(bdma, dma))] 4#[cfg(any(bdma, dma))]
5mod dma_bdma; 5mod dma_bdma;
6
6#[cfg(any(bdma, dma))] 7#[cfg(any(bdma, dma))]
7pub use dma_bdma::*; 8pub use dma_bdma::*;
8 9
@@ -24,9 +25,10 @@ pub(crate) use util::*;
24pub(crate) mod ringbuffer; 25pub(crate) mod ringbuffer;
25pub mod word; 26pub mod word;
26 27
27use embassy_hal_internal::{impl_peripheral, PeripheralType}; 28use embassy_hal_internal::{PeripheralType, impl_peripheral};
28 29
29use crate::interrupt; 30use crate::interrupt;
31use crate::rcc::StoppablePeripheral;
30 32
31/// The direction of a DMA transfer. 33/// The direction of a DMA transfer.
32#[derive(Debug, Copy, Clone, PartialEq, Eq)] 34#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -45,7 +47,7 @@ pub type Request = u8;
45#[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] 47#[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))]
46pub type Request = (); 48pub type Request = ();
47 49
48pub(crate) trait SealedChannel { 50pub(crate) trait SealedChannel: StoppablePeripheral {
49 fn id(&self) -> u8; 51 fn id(&self) -> u8;
50} 52}
51 53
@@ -59,15 +61,28 @@ pub(crate) trait ChannelInterrupt {
59pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {} 61pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {}
60 62
61macro_rules! dma_channel_impl { 63macro_rules! dma_channel_impl {
62 ($channel_peri:ident, $index:expr) => { 64 ($channel_peri:ident, $index:expr, $stop_mode:ident) => {
65 impl crate::rcc::StoppablePeripheral for crate::peripherals::$channel_peri {
66 #[cfg(feature = "low-power")]
67 fn stop_mode(&self) -> crate::rcc::StopMode {
68 crate::rcc::StopMode::$stop_mode
69 }
70 }
71
63 impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { 72 impl crate::dma::SealedChannel for crate::peripherals::$channel_peri {
64 fn id(&self) -> u8 { 73 fn id(&self) -> u8 {
65 $index 74 $index
66 } 75 }
67 } 76 }
77
68 impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri { 78 impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri {
69 unsafe fn on_irq() { 79 unsafe fn on_irq() {
70 crate::dma::AnyChannel { id: $index }.on_irq(); 80 crate::dma::AnyChannel {
81 id: $index,
82 #[cfg(feature = "low-power")]
83 stop_mode: crate::rcc::StopMode::$stop_mode,
84 }
85 .on_irq();
71 } 86 }
72 } 87 }
73 88
@@ -77,6 +92,8 @@ macro_rules! dma_channel_impl {
77 fn from(val: crate::peripherals::$channel_peri) -> Self { 92 fn from(val: crate::peripherals::$channel_peri) -> Self {
78 Self { 93 Self {
79 id: crate::dma::SealedChannel::id(&val), 94 id: crate::dma::SealedChannel::id(&val),
95 #[cfg(feature = "low-power")]
96 stop_mode: crate::rcc::StoppablePeripheral::stop_mode(&val),
80 } 97 }
81 } 98 }
82 } 99 }
@@ -86,6 +103,8 @@ macro_rules! dma_channel_impl {
86/// Type-erased DMA channel. 103/// Type-erased DMA channel.
87pub struct AnyChannel { 104pub struct AnyChannel {
88 pub(crate) id: u8, 105 pub(crate) id: u8,
106 #[cfg(feature = "low-power")]
107 pub(crate) stop_mode: crate::rcc::StopMode,
89} 108}
90impl_peripheral!(AnyChannel); 109impl_peripheral!(AnyChannel);
91 110
@@ -95,6 +114,13 @@ impl AnyChannel {
95 } 114 }
96} 115}
97 116
117impl StoppablePeripheral for AnyChannel {
118 #[cfg(feature = "low-power")]
119 fn stop_mode(&self) -> crate::rcc::StopMode {
120 self.stop_mode
121 }
122}
123
98impl SealedChannel for AnyChannel { 124impl SealedChannel for AnyChannel {
99 fn id(&self) -> u8 { 125 fn id(&self) -> u8 {
100 self.id 126 self.id
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
index 661fb1728..eff5b4058 100644
--- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
+++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
@@ -2,7 +2,7 @@ use std::task::Waker;
2 2
3use proptest::prop_oneof; 3use proptest::prop_oneof;
4use proptest::strategy::{self, BoxedStrategy, Strategy as _}; 4use proptest::strategy::{self, BoxedStrategy, Strategy as _};
5use proptest_state_machine::{prop_state_machine, ReferenceStateMachine, StateMachineTest}; 5use proptest_state_machine::{ReferenceStateMachine, StateMachineTest, prop_state_machine};
6 6
7use super::*; 7use super::*;
8 8
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs
index 3245887c1..304268963 100644
--- a/embassy-stm32/src/dma/util.rs
+++ b/embassy-stm32/src/dma/util.rs
@@ -20,6 +20,16 @@ impl<'d> ChannelAndRequest<'d> {
20 Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options) 20 Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options)
21 } 21 }
22 22
23 #[allow(dead_code)]
24 pub unsafe fn read_unchecked<'a, W: Word>(
25 &'a self,
26 peri_addr: *mut W,
27 buf: &'a mut [W],
28 options: TransferOptions,
29 ) -> Transfer<'a> {
30 Transfer::new_read(self.channel.clone_unchecked(), self.request, peri_addr, buf, options)
31 }
32
23 pub unsafe fn read_raw<'a, MW: Word, PW: Word>( 33 pub unsafe fn read_raw<'a, MW: Word, PW: Word>(
24 &'a mut self, 34 &'a mut self,
25 peri_addr: *mut PW, 35 peri_addr: *mut PW,
@@ -29,6 +39,16 @@ impl<'d> ChannelAndRequest<'d> {
29 Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) 39 Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options)
30 } 40 }
31 41
42 #[allow(dead_code)]
43 pub unsafe fn read_raw_unchecked<'a, MW: Word, PW: Word>(
44 &'a self,
45 peri_addr: *mut PW,
46 buf: *mut [MW],
47 options: TransferOptions,
48 ) -> Transfer<'a> {
49 Transfer::new_read_raw(self.channel.clone_unchecked(), self.request, peri_addr, buf, options)
50 }
51
32 pub unsafe fn write<'a, W: Word>( 52 pub unsafe fn write<'a, W: Word>(
33 &'a mut self, 53 &'a mut self,
34 buf: &'a [W], 54 buf: &'a [W],
@@ -38,6 +58,16 @@ impl<'d> ChannelAndRequest<'d> {
38 Transfer::new_write(self.channel.reborrow(), self.request, buf, peri_addr, options) 58 Transfer::new_write(self.channel.reborrow(), self.request, buf, peri_addr, options)
39 } 59 }
40 60
61 #[allow(dead_code)]
62 pub unsafe fn write_unchecked<'a, W: Word>(
63 &'a self,
64 buf: &'a [W],
65 peri_addr: *mut W,
66 options: TransferOptions,
67 ) -> Transfer<'a> {
68 Transfer::new_write(self.channel.clone_unchecked(), self.request, buf, peri_addr, options)
69 }
70
41 pub unsafe fn write_raw<'a, MW: Word, PW: Word>( 71 pub unsafe fn write_raw<'a, MW: Word, PW: Word>(
42 &'a mut self, 72 &'a mut self,
43 buf: *const [MW], 73 buf: *const [MW],
@@ -48,6 +78,16 @@ impl<'d> ChannelAndRequest<'d> {
48 } 78 }
49 79
50 #[allow(dead_code)] 80 #[allow(dead_code)]
81 pub unsafe fn write_raw_unchecked<'a, MW: Word, PW: Word>(
82 &'a self,
83 buf: *const [MW],
84 peri_addr: *mut PW,
85 options: TransferOptions,
86 ) -> Transfer<'a> {
87 Transfer::new_write_raw(self.channel.clone_unchecked(), self.request, buf, peri_addr, options)
88 }
89
90 #[allow(dead_code)]
51 pub unsafe fn write_repeated<'a, W: Word>( 91 pub unsafe fn write_repeated<'a, W: Word>(
52 &'a mut self, 92 &'a mut self,
53 repeated: &'a W, 93 repeated: &'a W,
@@ -64,4 +104,22 @@ impl<'d> ChannelAndRequest<'d> {
64 options, 104 options,
65 ) 105 )
66 } 106 }
107
108 #[allow(dead_code)]
109 pub unsafe fn write_repeated_unchecked<'a, W: Word>(
110 &'a self,
111 repeated: &'a W,
112 count: usize,
113 peri_addr: *mut W,
114 options: TransferOptions,
115 ) -> Transfer<'a> {
116 Transfer::new_write_repeated(
117 self.channel.clone_unchecked(),
118 self.request,
119 repeated,
120 count,
121 peri_addr,
122 options,
123 )
124 }
67} 125}
diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs
index fb1bde860..5c3bb8f7f 100644
--- a/embassy-stm32/src/dma/word.rs
+++ b/embassy-stm32/src/dma/word.rs
@@ -31,6 +31,10 @@ pub trait Word: SealedWord + Default + Copy + 'static {
31 fn size() -> WordSize; 31 fn size() -> WordSize;
32 /// Amount of bits of this word size. 32 /// Amount of bits of this word size.
33 fn bits() -> usize; 33 fn bits() -> usize;
34 /// Maximum value of this type.
35 fn max() -> usize {
36 (1 << Self::bits()) - 1
37 }
34} 38}
35 39
36macro_rules! impl_word { 40macro_rules! impl_word {
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index deda956af..b8945820c 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -5,17 +5,10 @@ use core::marker::PhantomData;
5use embassy_hal_internal::PeripheralType; 5use embassy_hal_internal::PeripheralType;
6 6
7//use crate::gpio::{AnyPin, SealedPin}; 7//use crate::gpio::{AnyPin, SealedPin};
8use crate::block_for_us;
8use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 9use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9use crate::rcc::{self, RccPeripheral}; 10use crate::rcc::{self, RccPeripheral};
10use crate::{peripherals, Peri}; 11use crate::{Peri, peripherals};
11
12/// Performs a busy-wait delay for a specified number of microseconds.
13pub fn blocking_delay_ms(ms: u32) {
14 #[cfg(feature = "time")]
15 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
16 #[cfg(not(feature = "time"))]
17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms);
18}
19 12
20/// PacketTypes extracted from CubeMX 13/// PacketTypes extracted from CubeMX
21#[repr(u8)] 14#[repr(u8)]
@@ -121,17 +114,15 @@ impl<'d, T: Instance> DsiHost<'d, T> {
121 114
122 /// DCS or Generic short/long write command 115 /// DCS or Generic short/long write command
123 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> { 116 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> {
124 assert!(data.len() > 0); 117 match data.len() {
125 118 0 => self.short_write(channel_id, PacketType::DcsShortPktWriteP0, address, 0),
126 if data.len() == 1 { 119 1 => self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]),
127 self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]) 120 _ => self.long_write(
128 } else {
129 self.long_write(
130 channel_id, 121 channel_id,
131 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well... 122 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well...
132 address, 123 address,
133 data, 124 data,
134 ) 125 ),
135 } 126 }
136 } 127 }
137 128
@@ -336,7 +327,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
336 if T::regs().gpsr().read().cmdfe() { 327 if T::regs().gpsr().read().cmdfe() {
337 return Ok(()); 328 return Ok(());
338 } 329 }
339 blocking_delay_ms(1); 330 block_for_us(1_000);
340 } 331 }
341 Err(Error::FifoTimeout) 332 Err(Error::FifoTimeout)
342 } 333 }
@@ -347,7 +338,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
347 if !T::regs().gpsr().read().cmdff() { 338 if !T::regs().gpsr().read().cmdff() {
348 return Ok(()); 339 return Ok(());
349 } 340 }
350 blocking_delay_ms(1); 341 block_for_us(1_000);
351 } 342 }
352 Err(Error::FifoTimeout) 343 Err(Error::FifoTimeout)
353 } 344 }
@@ -358,7 +349,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
358 if !self.read_busy() { 349 if !self.read_busy() {
359 return Ok(()); 350 return Ok(());
360 } 351 }
361 blocking_delay_ms(1); 352 block_for_us(1_000);
362 } 353 }
363 Err(Error::ReadTimeout) 354 Err(Error::ReadTimeout)
364 } 355 }
@@ -369,7 +360,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
369 if !T::regs().gpsr().read().prdfe() { 360 if !T::regs().gpsr().read().prdfe() {
370 return Ok(()); 361 return Ok(());
371 } 362 }
372 blocking_delay_ms(1); 363 block_for_us(1_000);
373 } 364 }
374 Err(Error::FifoTimeout) 365 Err(Error::FifoTimeout)
375 } 366 }
diff --git a/embassy-stm32/src/dts/mod.rs b/embassy-stm32/src/dts/mod.rs
index 1f39c8db5..a75ae0560 100644
--- a/embassy-stm32/src/dts/mod.rs
+++ b/embassy-stm32/src/dts/mod.rs
@@ -1,7 +1,7 @@
1//! Digital Temperature Sensor (DTS) 1//! Digital Temperature Sensor (DTS)
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{Ordering, compiler_fence};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_hal_internal::Peri; 7use embassy_hal_internal::Peri;
diff --git a/embassy-stm32/src/dts/tsel.rs b/embassy-stm32/src/dts/tsel.rs
index 99eab6dd8..79c697c8d 100644
--- a/embassy-stm32/src/dts/tsel.rs
+++ b/embassy-stm32/src/dts/tsel.rs
@@ -49,3 +49,20 @@ pub enum TriggerSel {
49 /// EXTI13 49 /// EXTI13
50 Exti13 = 4, 50 Exti13 = 4,
51} 51}
52
53/// Trigger selection for N6
54#[cfg(stm32n6)]
55#[derive(Debug, Copy, Clone, Eq, PartialEq)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
57pub enum TriggerSel {
58 /// Software triggering. Performs continuous measurements.
59 Software = 0,
60 /// LPTIM4 OUT
61 Lptim4 = 1,
62 /// LPTIM2 CH1
63 Lptim2 = 2,
64 /// LPTIM3 CH1
65 Lptim3 = 3,
66 /// EXTI13
67 Exti13 = 4,
68}
diff --git a/embassy-stm32/src/eth/generic_phy.rs b/embassy-stm32/src/eth/generic_phy.rs
index 774beef80..0a5f41de0 100644
--- a/embassy-stm32/src/eth/generic_phy.rs
+++ b/embassy-stm32/src/eth/generic_phy.rs
@@ -8,6 +8,7 @@ use embassy_time::{Duration, Timer};
8use futures_util::FutureExt; 8use futures_util::FutureExt;
9 9
10use super::{Phy, StationManagement}; 10use super::{Phy, StationManagement};
11use crate::block_for_us as blocking_delay_us;
11 12
12#[allow(dead_code)] 13#[allow(dead_code)]
13mod phy_consts { 14mod phy_consts {
@@ -43,21 +44,23 @@ mod phy_consts {
43use self::phy_consts::*; 44use self::phy_consts::*;
44 45
45/// Generic SMI Ethernet PHY implementation 46/// Generic SMI Ethernet PHY implementation
46pub struct GenericPhy { 47pub struct GenericPhy<SM: StationManagement> {
47 phy_addr: u8, 48 phy_addr: u8,
49 sm: SM,
48 #[cfg(feature = "time")] 50 #[cfg(feature = "time")]
49 poll_interval: Duration, 51 poll_interval: Duration,
50} 52}
51 53
52impl GenericPhy { 54impl<SM: StationManagement> GenericPhy<SM> {
53 /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication 55 /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication
54 /// 56 ///
55 /// # Panics 57 /// # Panics
56 /// `phy_addr` must be in range `0..32` 58 /// `phy_addr` must be in range `0..32`
57 pub fn new(phy_addr: u8) -> Self { 59 pub fn new(sm: SM, phy_addr: u8) -> Self {
58 assert!(phy_addr < 32); 60 assert!(phy_addr < 32);
59 Self { 61 Self {
60 phy_addr, 62 phy_addr,
63 sm,
61 #[cfg(feature = "time")] 64 #[cfg(feature = "time")]
62 poll_interval: Duration::from_millis(500), 65 poll_interval: Duration::from_millis(500),
63 } 66 }
@@ -67,8 +70,9 @@ impl GenericPhy {
67 /// 70 ///
68 /// # Panics 71 /// # Panics
69 /// Initialization panics if PHY didn't respond on any address 72 /// Initialization panics if PHY didn't respond on any address
70 pub fn new_auto() -> Self { 73 pub fn new_auto(sm: SM) -> Self {
71 Self { 74 Self {
75 sm,
72 phy_addr: 0xFF, 76 phy_addr: 0xFF,
73 #[cfg(feature = "time")] 77 #[cfg(feature = "time")]
74 poll_interval: Duration::from_millis(500), 78 poll_interval: Duration::from_millis(500),
@@ -76,27 +80,14 @@ impl GenericPhy {
76 } 80 }
77} 81}
78 82
79// TODO: Factor out to shared functionality 83impl<SM: StationManagement> Phy for GenericPhy<SM> {
80fn blocking_delay_us(us: u32) { 84 fn phy_reset(&mut self) {
81 #[cfg(feature = "time")]
82 embassy_time::block_for(Duration::from_micros(us as u64));
83 #[cfg(not(feature = "time"))]
84 {
85 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64;
86 let us = us as u64;
87 let cycles = freq * us / 1_000_000;
88 cortex_m::asm::delay(cycles as u32);
89 }
90}
91
92impl Phy for GenericPhy {
93 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
94 // Detect SMI address 85 // Detect SMI address
95 if self.phy_addr == 0xFF { 86 if self.phy_addr == 0xFF {
96 for addr in 0..32 { 87 for addr in 0..32 {
97 sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET); 88 self.sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
98 for _ in 0..10 { 89 for _ in 0..10 {
99 if sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET { 90 if self.sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET {
100 trace!("Found ETH PHY on address {}", addr); 91 trace!("Found ETH PHY on address {}", addr);
101 self.phy_addr = addr; 92 self.phy_addr = addr;
102 return; 93 return;
@@ -108,30 +99,30 @@ impl Phy for GenericPhy {
108 panic!("PHY did not respond"); 99 panic!("PHY did not respond");
109 } 100 }
110 101
111 sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); 102 self.sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
112 while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} 103 while self.sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
113 } 104 }
114 105
115 fn phy_init<S: StationManagement>(&mut self, sm: &mut S) { 106 fn phy_init(&mut self) {
116 // Clear WU CSR 107 // Clear WU CSR
117 self.smi_write_ext(sm, PHY_REG_WUCSR, 0); 108 self.smi_write_ext(PHY_REG_WUCSR, 0);
118 109
119 // Enable auto-negotiation 110 // Enable auto-negotiation
120 sm.smi_write( 111 self.sm.smi_write(
121 self.phy_addr, 112 self.phy_addr,
122 PHY_REG_BCR, 113 PHY_REG_BCR,
123 PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M, 114 PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M,
124 ); 115 );
125 } 116 }
126 117
127 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool { 118 fn poll_link(&mut self, cx: &mut Context) -> bool {
128 #[cfg(not(feature = "time"))] 119 #[cfg(not(feature = "time"))]
129 cx.waker().wake_by_ref(); 120 cx.waker().wake_by_ref();
130 121
131 #[cfg(feature = "time")] 122 #[cfg(feature = "time")]
132 let _ = Timer::after(self.poll_interval).poll_unpin(cx); 123 let _ = Timer::after(self.poll_interval).poll_unpin(cx);
133 124
134 let bsr = sm.smi_read(self.phy_addr, PHY_REG_BSR); 125 let bsr = self.sm.smi_read(self.phy_addr, PHY_REG_BSR);
135 126
136 // No link without autonegotiate 127 // No link without autonegotiate
137 if bsr & PHY_REG_BSR_ANDONE == 0 { 128 if bsr & PHY_REG_BSR_ANDONE == 0 {
@@ -148,7 +139,7 @@ impl Phy for GenericPhy {
148} 139}
149 140
150/// Public functions for the PHY 141/// Public functions for the PHY
151impl GenericPhy { 142impl<SM: StationManagement> GenericPhy<SM> {
152 /// Set the SMI polling interval. 143 /// Set the SMI polling interval.
153 #[cfg(feature = "time")] 144 #[cfg(feature = "time")]
154 pub fn set_poll_interval(&mut self, poll_interval: Duration) { 145 pub fn set_poll_interval(&mut self, poll_interval: Duration) {
@@ -156,10 +147,15 @@ impl GenericPhy {
156 } 147 }
157 148
158 // Writes a value to an extended PHY register in MMD address space 149 // Writes a value to an extended PHY register in MMD address space
159 fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) { 150 fn smi_write_ext(&mut self, reg_addr: u16, reg_data: u16) {
160 sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address 151 self.sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address
161 sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr); 152 self.sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr);
162 sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data 153 self.sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data
163 sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data); 154 self.sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data);
155 }
156
157 /// Access the underlying station management.
158 pub fn station_management(&mut self) -> &mut SM {
159 &mut self.sm
164 } 160 }
165} 161}
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 10b3a0517..c8bce0e8a 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -5,6 +5,7 @@
5#[cfg_attr(eth_v2, path = "v2/mod.rs")] 5#[cfg_attr(eth_v2, path = "v2/mod.rs")]
6mod _version; 6mod _version;
7mod generic_phy; 7mod generic_phy;
8mod sma;
8 9
9use core::mem::MaybeUninit; 10use core::mem::MaybeUninit;
10use core::task::Context; 11use core::task::Context;
@@ -15,6 +16,7 @@ use embassy_sync::waitqueue::AtomicWaker;
15 16
16pub use self::_version::{InterruptHandler, *}; 17pub use self::_version::{InterruptHandler, *};
17pub use self::generic_phy::*; 18pub use self::generic_phy::*;
19pub use self::sma::{Sma, StationManagement};
18use crate::rcc::RccPeripheral; 20use crate::rcc::RccPeripheral;
19 21
20#[allow(unused)] 22#[allow(unused)]
@@ -109,7 +111,7 @@ impl<'d, T: Instance, P: Phy> embassy_net_driver::Driver for Ethernet<'d, T, P>
109 } 111 }
110 112
111 fn link_state(&mut self, cx: &mut Context) -> LinkState { 113 fn link_state(&mut self, cx: &mut Context) -> LinkState {
112 if self.phy.poll_link(&mut self.station_management, cx) { 114 if self.phy.poll_link(cx) {
113 LinkState::Up 115 LinkState::Up
114 } else { 116 } else {
115 LinkState::Down 117 LinkState::Down
@@ -157,32 +159,17 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
157 } 159 }
158} 160}
159 161
160/// Station Management Interface (SMI) on an ethernet PHY
161pub trait StationManagement {
162 /// Read a register over SMI.
163 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16;
164 /// Write a register over SMI.
165 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16);
166}
167
168/// Trait for an Ethernet PHY 162/// Trait for an Ethernet PHY
169pub trait Phy { 163pub trait Phy {
170 /// Reset PHY and wait for it to come out of reset. 164 /// Reset PHY and wait for it to come out of reset.
171 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S); 165 fn phy_reset(&mut self);
172 /// PHY initialisation. 166 /// PHY initialisation.
173 fn phy_init<S: StationManagement>(&mut self, sm: &mut S); 167 fn phy_init(&mut self);
174 /// Poll link to see if it is up and FD with 100Mbps 168 /// Poll link to see if it is up and FD with 100Mbps
175 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool; 169 fn poll_link(&mut self, cx: &mut Context) -> bool;
176} 170}
177 171
178impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { 172impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
179 /// Directly expose the SMI interface used by the Ethernet driver.
180 ///
181 /// This can be used to for example configure special PHY registers for compliance testing.
182 pub fn station_management(&mut self) -> &mut impl StationManagement {
183 &mut self.station_management
184 }
185
186 /// Access the user-supplied `Phy`. 173 /// Access the user-supplied `Phy`.
187 pub fn phy(&self) -> &P { 174 pub fn phy(&self) -> &P {
188 &self.phy 175 &self.phy
@@ -212,8 +199,8 @@ impl Instance for crate::peripherals::ETH {}
212pin_trait!(RXClkPin, Instance, @A); 199pin_trait!(RXClkPin, Instance, @A);
213pin_trait!(TXClkPin, Instance, @A); 200pin_trait!(TXClkPin, Instance, @A);
214pin_trait!(RefClkPin, Instance, @A); 201pin_trait!(RefClkPin, Instance, @A);
215pin_trait!(MDIOPin, Instance, @A); 202pin_trait!(MDIOPin, sma::Instance, @A);
216pin_trait!(MDCPin, Instance, @A); 203pin_trait!(MDCPin, sma::Instance, @A);
217pin_trait!(RXDVPin, Instance, @A); 204pin_trait!(RXDVPin, Instance, @A);
218pin_trait!(CRSPin, Instance, @A); 205pin_trait!(CRSPin, Instance, @A);
219pin_trait!(RXD0Pin, Instance, @A); 206pin_trait!(RXD0Pin, Instance, @A);
diff --git a/embassy-stm32/src/eth/sma/mod.rs b/embassy-stm32/src/eth/sma/mod.rs
new file mode 100644
index 000000000..6c851911d
--- /dev/null
+++ b/embassy-stm32/src/eth/sma/mod.rs
@@ -0,0 +1,42 @@
1//! Station Management Agent (also known as MDIO or SMI).
2
3#![macro_use]
4
5#[cfg_attr(eth_v2, path = "v2.rs")]
6#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1.rs")]
7mod _version;
8
9use embassy_hal_internal::PeripheralType;
10use stm32_metapac::common::{RW, Reg};
11
12pub use self::_version::*;
13
14/// Station Management Interface (SMI).
15pub trait StationManagement {
16 /// Read a register over SMI.
17 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16;
18 /// Write a register over SMI.
19 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16);
20}
21
22trait SealedInstance {
23 fn regs() -> (Reg<AddressRegister, RW>, Reg<DataRegister, RW>);
24}
25
26/// MDIO instance.
27#[allow(private_bounds)]
28pub trait Instance: SealedInstance + PeripheralType + Send + 'static {}
29
30impl SealedInstance for crate::peripherals::ETH_SMA {
31 fn regs() -> (Reg<AddressRegister, RW>, Reg<DataRegister, RW>) {
32 let mac = crate::pac::ETH.ethernet_mac();
33
34 #[cfg(any(eth_v1a, eth_v1b, eth_v1c))]
35 return (mac.macmiiar(), mac.macmiidr());
36
37 #[cfg(eth_v2)]
38 return (mac.macmdioar(), mac.macmdiodr());
39 }
40}
41
42impl Instance for crate::peripherals::ETH_SMA {}
diff --git a/embassy-stm32/src/eth/sma/v1.rs b/embassy-stm32/src/eth/sma/v1.rs
new file mode 100644
index 000000000..db64a6c78
--- /dev/null
+++ b/embassy-stm32/src/eth/sma/v1.rs
@@ -0,0 +1,102 @@
1use embassy_hal_internal::Peri;
2pub(crate) use regs::{Macmiiar as AddressRegister, Macmiidr as DataRegister};
3use stm32_metapac::eth::regs;
4use stm32_metapac::eth::vals::{Cr, MbProgress, Mw};
5
6use super::{Instance, StationManagement};
7use crate::eth::{MDCPin, MDIOPin};
8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
9
10/// Station Management Agent.
11///
12/// This peripheral is used for SMI reads and writes to the connected
13/// ethernet PHY/device(s).
14pub struct Sma<'d, T: Instance> {
15 _peri: Peri<'d, T>,
16 clock_range: Cr,
17 pins: [Peri<'d, AnyPin>; 2],
18}
19
20impl<'d, T: Instance> Sma<'d, T> {
21 /// Create a new instance of this peripheral.
22 pub fn new<#[cfg(afio)] A>(
23 peri: Peri<'d, T>,
24 mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
25 mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
26 ) -> Self {
27 set_as_af!(mdio, AfType::output(OutputType::PushPull, Speed::VeryHigh));
28 set_as_af!(mdc, AfType::output(OutputType::PushPull, Speed::VeryHigh));
29
30 // Enable necessary clocks.
31 critical_section::with(|_| {
32 #[cfg(eth_v1a)]
33 let reg = crate::pac::RCC.ahbenr();
34
35 #[cfg(any(eth_v1b, eth_v1c))]
36 let reg = crate::pac::RCC.ahb1enr();
37
38 reg.modify(|w| {
39 w.set_ethen(true);
40 })
41 });
42
43 let hclk = unsafe { crate::rcc::get_freqs().hclk1.to_hertz() };
44 let hclk = unwrap!(hclk, "SMA requires HCLK to be enabled, but it was not.");
45 let hclk_mhz = hclk.0 / 1_000_000;
46
47 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
48 let clock_range = match hclk_mhz {
49 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
50 25..=34 => Cr::CR_20_35, // Divide by 16
51 35..=59 => Cr::CR_35_60, // Divide by 26
52 60..=99 => Cr::CR_60_100, // Divide by 42
53 100..=149 => Cr::CR_100_150, // Divide by 62
54 150..=216 => Cr::CR_150_168, // Divide by 102
55 _ => {
56 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
57 }
58 };
59
60 Self {
61 _peri: peri,
62 clock_range,
63 pins: [mdio.into(), mdc.into()],
64 }
65 }
66}
67
68impl<T: Instance> StationManagement for Sma<'_, T> {
69 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
70 let (macmiiar, macmiidr) = T::regs();
71
72 macmiiar.modify(|w| {
73 w.set_pa(phy_addr);
74 w.set_mr(reg);
75 w.set_mw(Mw::READ); // read operation
76 w.set_cr(self.clock_range);
77 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
78 });
79 while macmiiar.read().mb() == MbProgress::BUSY {}
80 macmiidr.read().md()
81 }
82
83 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
84 let (macmiiar, macmiidr) = T::regs();
85
86 macmiidr.write(|w| w.set_md(val));
87 macmiiar.modify(|w| {
88 w.set_pa(phy_addr);
89 w.set_mr(reg);
90 w.set_mw(Mw::WRITE); // write
91 w.set_cr(self.clock_range);
92 w.set_mb(MbProgress::BUSY);
93 });
94 while macmiiar.read().mb() == MbProgress::BUSY {}
95 }
96}
97
98impl<T: Instance> Drop for Sma<'_, T> {
99 fn drop(&mut self) {
100 self.pins.iter_mut().for_each(|p| p.set_as_disconnected());
101 }
102}
diff --git a/embassy-stm32/src/eth/sma/v2.rs b/embassy-stm32/src/eth/sma/v2.rs
new file mode 100644
index 000000000..6bc5230b5
--- /dev/null
+++ b/embassy-stm32/src/eth/sma/v2.rs
@@ -0,0 +1,94 @@
1use embassy_hal_internal::Peri;
2pub(crate) use regs::{Macmdioar as AddressRegister, Macmdiodr as DataRegister};
3use stm32_metapac::eth::regs;
4
5use super::{Instance, StationManagement};
6use crate::eth::{MDCPin, MDIOPin};
7use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
8
9/// Station Management Agent.
10///
11/// This peripheral is used for SMI reads and writes to the connected
12/// ethernet PHY/device(s).
13pub struct Sma<'d, T: Instance> {
14 _peri: Peri<'d, T>,
15 pins: [Peri<'d, AnyPin>; 2],
16 clock_range: u8,
17}
18
19impl<'d, T: Instance> Sma<'d, T> {
20 /// Create a new instance of this peripheral.
21 pub fn new(peri: Peri<'d, T>, mdio: Peri<'d, impl MDIOPin<T>>, mdc: Peri<'d, impl MDCPin<T>>) -> Self {
22 set_as_af!(mdio, AfType::output(OutputType::PushPull, Speed::VeryHigh));
23 set_as_af!(mdc, AfType::output(OutputType::PushPull, Speed::VeryHigh));
24
25 // Enable necessary clocks.
26 critical_section::with(|_| {
27 crate::pac::RCC.ahb1enr().modify(|w| {
28 w.set_ethen(true);
29 })
30 });
31
32 let hclk = unsafe { crate::rcc::get_freqs().hclk1.to_hertz() };
33 let hclk = unwrap!(hclk, "SMA requires HCLK to be enabled, but it was not.");
34 let hclk_mhz = hclk.0 / 1_000_000;
35
36 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
37 let clock_range = match hclk_mhz {
38 0..=34 => 2, // Divide by 16
39 35..=59 => 3, // Divide by 26
40 60..=99 => 0, // Divide by 42
41 100..=149 => 1, // Divide by 62
42 150..=249 => 4, // Divide by 102
43 250..=310 => 5, // Divide by 124
44 _ => {
45 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
46 }
47 };
48
49 Self {
50 _peri: peri,
51 clock_range,
52 pins: [mdio.into(), mdc.into()],
53 }
54 }
55}
56
57impl<T: Instance> StationManagement for Sma<'_, T> {
58 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
59 let (macmdioar, macmdiodr) = T::regs();
60
61 macmdioar.modify(|w| {
62 w.set_pa(phy_addr);
63 w.set_rda(reg);
64 w.set_goc(0b11); // read
65 w.set_cr(self.clock_range);
66 w.set_mb(true);
67 });
68
69 while macmdioar.read().mb() {}
70
71 macmdiodr.read().md()
72 }
73
74 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
75 let (macmdioar, macmdiodr) = T::regs();
76
77 macmdiodr.write(|w| w.set_md(val));
78 macmdioar.modify(|w| {
79 w.set_pa(phy_addr);
80 w.set_rda(reg);
81 w.set_goc(0b01); // write
82 w.set_cr(self.clock_range);
83 w.set_mb(true);
84 });
85
86 while macmdioar.read().mb() {}
87 }
88}
89
90impl<T: Instance> Drop for Sma<'_, T> {
91 fn drop(&mut self) {
92 self.pins.iter_mut().for_each(|p| p.set_as_disconnected());
93 }
94}
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 5be1c9739..8de26ce9d 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -3,11 +3,10 @@
3mod rx_desc; 3mod rx_desc;
4mod tx_desc; 4mod tx_desc;
5 5
6use core::marker::PhantomData; 6use core::sync::atomic::{Ordering, fence};
7use core::sync::atomic::{fence, Ordering};
8 7
9use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; 9use stm32_metapac::eth::vals::{Apcs, Dm, DmaomrSr, Fes, Ftf, Ifg, Pbl, Rsf, St, Tsf};
11 10
12pub(crate) use self::rx_desc::{RDes, RDesRing}; 11pub(crate) use self::rx_desc::{RDes, RDesRing};
13pub(crate) use self::tx_desc::{TDes, TDesRing}; 12pub(crate) use self::tx_desc::{TDes, TDesRing};
@@ -22,7 +21,6 @@ use crate::pac::AFIO;
22#[cfg(any(eth_v1b, eth_v1c))] 21#[cfg(any(eth_v1b, eth_v1c))]
23use crate::pac::SYSCFG; 22use crate::pac::SYSCFG;
24use crate::pac::{ETH, RCC}; 23use crate::pac::{ETH, RCC};
25use crate::rcc::SealedRccPeripheral;
26 24
27/// Interrupt handler. 25/// Interrupt handler.
28pub struct InterruptHandler {} 26pub struct InterruptHandler {}
@@ -53,14 +51,13 @@ pub struct Ethernet<'d, T: Instance, P: Phy> {
53 51
54 pins: Pins<'d>, 52 pins: Pins<'d>,
55 pub(crate) phy: P, 53 pub(crate) phy: P,
56 pub(crate) station_management: EthernetStationManagement<T>,
57 pub(crate) mac_addr: [u8; 6], 54 pub(crate) mac_addr: [u8; 6],
58} 55}
59 56
60/// Pins of ethernet driver. 57/// Pins of ethernet driver.
61enum Pins<'d> { 58enum Pins<'d> {
62 Rmii([Peri<'d, AnyPin>; 9]), 59 Rmii([Peri<'d, AnyPin>; 7]),
63 Mii([Peri<'d, AnyPin>; 14]), 60 Mii([Peri<'d, AnyPin>; 12]),
64} 61}
65 62
66#[cfg(eth_v1a)] 63#[cfg(eth_v1a)]
@@ -97,68 +94,105 @@ macro_rules! config_pins {
97 }; 94 };
98} 95}
99 96
100impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { 97impl<'d, T: Instance, SMA: sma::Instance> Ethernet<'d, T, GenericPhy<Sma<'d, SMA>>> {
98 /// Create a new RMII ethernet driver using 7 pins.
99 ///
100 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
101 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
102 ///
103 /// See [`Ethernet::new_with_phy`] for creating an RMII ethernet
104 /// river with a non-standard PHY.
105 ///
101 /// safety: the returned instance is not leak-safe 106 /// safety: the returned instance is not leak-safe
102 pub fn new<const TX: usize, const RX: usize, #[cfg(afio)] A>( 107 pub fn new<const TX: usize, const RX: usize, #[cfg(afio)] A>(
103 queue: &'d mut PacketQueue<TX, RX>, 108 queue: &'d mut PacketQueue<TX, RX>,
104 peri: Peri<'d, T>, 109 peri: Peri<'d, T>,
105 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 110 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
106 ref_clk: Peri<'d, if_afio!(impl RefClkPin<T, A>)>, 111 ref_clk: Peri<'d, if_afio!(impl RefClkPin<T, A>)>,
107 mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
108 mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
109 crs: Peri<'d, if_afio!(impl CRSPin<T, A>)>, 112 crs: Peri<'d, if_afio!(impl CRSPin<T, A>)>,
110 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>, 113 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
111 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>, 114 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
112 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>, 115 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
113 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>, 116 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
114 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>, 117 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
115 phy: P,
116 mac_addr: [u8; 6], 118 mac_addr: [u8; 6],
119 sma: Peri<'d, SMA>,
120 mdio: Peri<'d, if_afio!(impl MDIOPin<SMA, A>)>,
121 mdc: Peri<'d, if_afio!(impl MDCPin<SMA, A>)>,
117 ) -> Self { 122 ) -> Self {
118 // Enable the necessary Clocks 123 let sma = Sma::new(sma, mdio, mdc);
119 #[cfg(eth_v1a)] 124 let phy = GenericPhy::new_auto(sma);
120 critical_section::with(|_| {
121 RCC.apb2enr().modify(|w| w.set_afioen(true));
122
123 // Select RMII (Reduced Media Independent Interface)
124 // Must be done prior to enabling peripheral clock
125 AFIO.mapr().modify(|w| {
126 w.set_mii_rmii_sel(true);
127 w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
128 });
129 125
130 RCC.ahbenr().modify(|w| { 126 Self::new_with_phy(
131 w.set_ethen(true); 127 queue, peri, irq, ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en, mac_addr, phy,
132 w.set_ethtxen(true); 128 )
133 w.set_ethrxen(true); 129 }
134 });
135 });
136 130
137 #[cfg(any(eth_v1b, eth_v1c))] 131 /// Create a new MII ethernet driver using 14 pins.
138 critical_section::with(|_| { 132 ///
139 RCC.ahb1enr().modify(|w| { 133 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
140 w.set_ethen(true); 134 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
141 w.set_ethtxen(true); 135 ///
142 w.set_ethrxen(true); 136 /// See [`Ethernet::new_mii_with_phy`] for creating an RMII ethernet
143 }); 137 /// river with a non-standard PHY.
138 pub fn new_mii<const TX: usize, const RX: usize, #[cfg(afio)] A>(
139 queue: &'d mut PacketQueue<TX, RX>,
140 peri: Peri<'d, T>,
141 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
142 rx_clk: Peri<'d, if_afio!(impl RXClkPin<T, A>)>,
143 tx_clk: Peri<'d, if_afio!(impl TXClkPin<T, A>)>,
144 rxdv: Peri<'d, if_afio!(impl RXDVPin<T, A>)>,
145 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
146 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
147 rx_d2: Peri<'d, if_afio!(impl RXD2Pin<T, A>)>,
148 rx_d3: Peri<'d, if_afio!(impl RXD3Pin<T, A>)>,
149 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
150 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
151 tx_d2: Peri<'d, if_afio!(impl TXD2Pin<T, A>)>,
152 tx_d3: Peri<'d, if_afio!(impl TXD3Pin<T, A>)>,
153 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
154 mac_addr: [u8; 6],
155 sma: Peri<'d, SMA>,
156 mdio: Peri<'d, if_afio!(impl MDIOPin<SMA, A>)>,
157 mdc: Peri<'d, if_afio!(impl MDCPin<SMA, A>)>,
158 ) -> Self {
159 let sma = Sma::new(sma, mdio, mdc);
160 let phy = GenericPhy::new_auto(sma);
144 161
145 // RMII (Reduced Media Independent Interface) 162 Self::new_mii_with_phy(
146 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true)); 163 queue, peri, irq, rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en,
147 }); 164 mac_addr, phy,
165 )
166 }
167}
148 168
169impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
170 /// safety: the returned instance is not leak-safe
171 pub fn new_with_phy<const TX: usize, const RX: usize, #[cfg(afio)] A>(
172 queue: &'d mut PacketQueue<TX, RX>,
173 peri: Peri<'d, T>,
174 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
175 ref_clk: Peri<'d, if_afio!(impl RefClkPin<T, A>)>,
176 crs: Peri<'d, if_afio!(impl CRSPin<T, A>)>,
177 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
178 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
179 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
180 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
181 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
182 mac_addr: [u8; 6],
183 phy: P,
184 ) -> Self {
149 #[cfg(eth_v1a)] 185 #[cfg(eth_v1a)]
150 { 186 {
151 config_in_pins!(ref_clk, rx_d0, rx_d1); 187 config_in_pins!(ref_clk, rx_d0, rx_d1);
152 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); 188 config_af_pins!(tx_d0, tx_d1, tx_en);
153 } 189 }
154 190
155 #[cfg(any(eth_v1b, eth_v1c))] 191 #[cfg(any(eth_v1b, eth_v1c))]
156 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 192 config_pins!(ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
157 193
158 let pins = Pins::Rmii([ 194 let pins = Pins::Rmii([
159 ref_clk.into(), 195 ref_clk.into(),
160 mdio.into(),
161 mdc.into(),
162 crs.into(), 196 crs.into(),
163 rx_d0.into(), 197 rx_d0.into(),
164 rx_d1.into(), 198 rx_d1.into(),
@@ -167,7 +201,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
167 tx_en.into(), 201 tx_en.into(),
168 ]); 202 ]);
169 203
170 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 204 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, true)
171 } 205 }
172 206
173 fn new_inner<const TX: usize, const RX: usize>( 207 fn new_inner<const TX: usize, const RX: usize>(
@@ -177,7 +211,39 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
177 pins: Pins<'d>, 211 pins: Pins<'d>,
178 phy: P, 212 phy: P,
179 mac_addr: [u8; 6], 213 mac_addr: [u8; 6],
214 rmii_mii_sel: bool,
180 ) -> Self { 215 ) -> Self {
216 // Enable the necessary Clocks
217 #[cfg(eth_v1a)]
218 critical_section::with(|_| {
219 RCC.apb2enr().modify(|w| w.set_afioen(true));
220
221 // Select (R)MII (Reduced Media Independent Interface)
222 // Must be done prior to enabling peripheral clock
223 AFIO.mapr().modify(|w| {
224 w.set_mii_rmii_sel(rmii_mii_sel);
225 w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
226 });
227
228 RCC.ahbenr().modify(|w| {
229 w.set_ethen(true);
230 w.set_ethtxen(true);
231 w.set_ethrxen(true);
232 });
233 });
234
235 #[cfg(any(eth_v1b, eth_v1c))]
236 critical_section::with(|_| {
237 RCC.ahb1enr().modify(|w| {
238 w.set_ethen(true);
239 w.set_ethtxen(true);
240 w.set_ethrxen(true);
241 });
242
243 // (R)MII ((Reduced) Media Independent Interface)
244 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(rmii_mii_sel));
245 });
246
181 let dma = T::regs().ethernet_dma(); 247 let dma = T::regs().ethernet_dma();
182 let mac = T::regs().ethernet_mac(); 248 let mac = T::regs().ethernet_mac();
183 249
@@ -190,7 +256,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
190 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping 256 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
191 w.set_fes(Fes::FES100); // fast ethernet speed 257 w.set_fes(Fes::FES100); // fast ethernet speed
192 w.set_dm(Dm::FULL_DUPLEX); // full duplex 258 w.set_dm(Dm::FULL_DUPLEX); // full duplex
193 // TODO: Carrier sense ? ECRSFD 259 // TODO: Carrier sense ? ECRSFD
194 }); 260 });
195 261
196 // Set the mac to pass all multicast packets 262 // Set the mac to pass all multicast packets
@@ -226,30 +292,10 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
226 292
227 // TODO MTU size setting not found for v1 ethernet, check if correct 293 // TODO MTU size setting not found for v1 ethernet, check if correct
228 294
229 let hclk = <T as SealedRccPeripheral>::frequency();
230 let hclk_mhz = hclk.0 / 1_000_000;
231
232 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
233 let clock_range = match hclk_mhz {
234 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
235 25..=34 => Cr::CR_20_35, // Divide by 16
236 35..=59 => Cr::CR_35_60, // Divide by 26
237 60..=99 => Cr::CR_60_100, // Divide by 42
238 100..=149 => Cr::CR_100_150, // Divide by 62
239 150..=216 => Cr::CR_150_168, // Divide by 102
240 _ => {
241 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
242 }
243 };
244
245 let mut this = Self { 295 let mut this = Self {
246 _peri: peri, 296 _peri: peri,
247 pins, 297 pins,
248 phy: phy, 298 phy: phy,
249 station_management: EthernetStationManagement {
250 peri: PhantomData,
251 clock_range: clock_range,
252 },
253 mac_addr, 299 mac_addr,
254 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 300 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
255 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 301 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
@@ -279,8 +325,8 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
279 w.set_tie(true); 325 w.set_tie(true);
280 }); 326 });
281 327
282 this.phy.phy_reset(&mut this.station_management); 328 this.phy.phy_reset();
283 this.phy.phy_init(&mut this.station_management); 329 this.phy.phy_init();
284 330
285 interrupt::ETH.unpend(); 331 interrupt::ETH.unpend();
286 unsafe { interrupt::ETH.enable() }; 332 unsafe { interrupt::ETH.enable() };
@@ -288,15 +334,13 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
288 this 334 this
289 } 335 }
290 336
291 /// Create a new MII ethernet driver using 14 pins. 337 /// Create a new MII ethernet driver using 12 pins.
292 pub fn new_mii<const TX: usize, const RX: usize, #[cfg(afio)] A>( 338 pub fn new_mii_with_phy<const TX: usize, const RX: usize, #[cfg(afio)] A>(
293 queue: &'d mut PacketQueue<TX, RX>, 339 queue: &'d mut PacketQueue<TX, RX>,
294 peri: Peri<'d, T>, 340 peri: Peri<'d, T>,
295 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 341 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
296 rx_clk: Peri<'d, if_afio!(impl RXClkPin<T, A>)>, 342 rx_clk: Peri<'d, if_afio!(impl RXClkPin<T, A>)>,
297 tx_clk: Peri<'d, if_afio!(impl TXClkPin<T, A>)>, 343 tx_clk: Peri<'d, if_afio!(impl TXClkPin<T, A>)>,
298 mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
299 mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
300 rxdv: Peri<'d, if_afio!(impl RXDVPin<T, A>)>, 344 rxdv: Peri<'d, if_afio!(impl RXDVPin<T, A>)>,
301 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>, 345 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
302 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>, 346 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
@@ -307,56 +351,23 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
307 tx_d2: Peri<'d, if_afio!(impl TXD2Pin<T, A>)>, 351 tx_d2: Peri<'d, if_afio!(impl TXD2Pin<T, A>)>,
308 tx_d3: Peri<'d, if_afio!(impl TXD3Pin<T, A>)>, 352 tx_d3: Peri<'d, if_afio!(impl TXD3Pin<T, A>)>,
309 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>, 353 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
310 phy: P,
311 mac_addr: [u8; 6], 354 mac_addr: [u8; 6],
355 phy: P,
312 ) -> Self { 356 ) -> Self {
313 // TODO: Handle optional signals like CRS, MII_COL, RX_ER?
314
315 // Enable the necessary Clocks
316 #[cfg(eth_v1a)]
317 critical_section::with(|_| {
318 RCC.apb2enr().modify(|w| w.set_afioen(true));
319
320 // Select MII (Media Independent Interface)
321 // Must be done prior to enabling peripheral clock
322 AFIO.mapr().modify(|w| {
323 w.set_mii_rmii_sel(false);
324 w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
325 });
326
327 RCC.ahbenr().modify(|w| {
328 w.set_ethen(true);
329 w.set_ethtxen(true);
330 w.set_ethrxen(true);
331 });
332 });
333
334 #[cfg(any(eth_v1b, eth_v1c))]
335 critical_section::with(|_| {
336 RCC.ahb1enr().modify(|w| {
337 w.set_ethen(true);
338 w.set_ethtxen(true);
339 w.set_ethrxen(true);
340 });
341
342 // MII (Media Independent Interface)
343 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(false));
344 });
345
346 #[cfg(eth_v1a)] 357 #[cfg(eth_v1a)]
347 { 358 {
348 config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv); 359 config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv);
349 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); 360 config_af_pins!(tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
350 } 361 }
351 362
352 #[cfg(any(eth_v1b, eth_v1c))] 363 #[cfg(any(eth_v1b, eth_v1c))]
353 config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); 364 config_pins!(
365 rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
366 );
354 367
355 let pins = Pins::Mii([ 368 let pins = Pins::Mii([
356 rx_clk.into(), 369 rx_clk.into(),
357 tx_clk.into(), 370 tx_clk.into(),
358 mdio.into(),
359 mdc.into(),
360 rxdv.into(), 371 rxdv.into(),
361 rx_d0.into(), 372 rx_d0.into(),
362 rx_d1.into(), 373 rx_d1.into(),
@@ -369,43 +380,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
369 tx_en.into(), 380 tx_en.into(),
370 ]); 381 ]);
371 382
372 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 383 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, false)
373 }
374}
375
376/// Ethernet station management interface.
377pub(crate) struct EthernetStationManagement<T: Instance> {
378 peri: PhantomData<T>,
379 clock_range: Cr,
380}
381
382impl<T: Instance> StationManagement for EthernetStationManagement<T> {
383 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
384 let mac = T::regs().ethernet_mac();
385
386 mac.macmiiar().modify(|w| {
387 w.set_pa(phy_addr);
388 w.set_mr(reg);
389 w.set_mw(Mw::READ); // read operation
390 w.set_cr(self.clock_range);
391 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
392 });
393 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
394 mac.macmiidr().read().md()
395 }
396
397 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
398 let mac = T::regs().ethernet_mac();
399
400 mac.macmiidr().write(|w| w.set_md(val));
401 mac.macmiiar().modify(|w| {
402 w.set_pa(phy_addr);
403 w.set_mr(reg);
404 w.set_mw(Mw::WRITE); // write
405 w.set_cr(self.clock_range);
406 w.set_mb(MbProgress::BUSY);
407 });
408 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
409 } 384 }
410} 385}
411 386
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs
index 2a46c1895..6ade1f29c 100644
--- a/embassy-stm32/src/eth/v1/rx_desc.rs
+++ b/embassy-stm32/src/eth/v1/rx_desc.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{compiler_fence, fence, Ordering}; 1use core::sync::atomic::{Ordering, compiler_fence, fence};
2 2
3use stm32_metapac::eth::vals::{Rpd, Rps}; 3use stm32_metapac::eth::vals::{Rpd, Rps};
4use vcell::VolatileCell; 4use vcell::VolatileCell;
diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs
index 1317d20f4..ba99b66cb 100644
--- a/embassy-stm32/src/eth/v1/tx_desc.rs
+++ b/embassy-stm32/src/eth/v1/tx_desc.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{compiler_fence, fence, Ordering}; 1use core::sync::atomic::{Ordering, compiler_fence, fence};
2 2
3use vcell::VolatileCell; 3use vcell::VolatileCell;
4 4
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index 645bfdb14..e335ed8f3 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{fence, Ordering}; 1use core::sync::atomic::{Ordering, fence};
2 2
3use vcell::VolatileCell; 3use vcell::VolatileCell;
4 4
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index cf7a9901b..7f92e351c 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,7 +1,6 @@
1mod descriptors; 1mod descriptors;
2 2
3use core::marker::PhantomData; 3use core::sync::atomic::{Ordering, fence};
4use core::sync::atomic::{fence, Ordering};
5 4
6use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
7use stm32_metapac::syscfg::vals::EthSelPhy; 6use stm32_metapac::syscfg::vals::EthSelPhy;
@@ -12,7 +11,6 @@ use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed};
12use crate::interrupt; 11use crate::interrupt;
13use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
14use crate::pac::ETH; 13use crate::pac::ETH;
15use crate::rcc::SealedRccPeripheral;
16 14
17/// Interrupt handler. 15/// Interrupt handler.
18pub struct InterruptHandler {} 16pub struct InterruptHandler {}
@@ -42,14 +40,13 @@ pub struct Ethernet<'d, T: Instance, P: Phy> {
42 pub(crate) rx: RDesRing<'d>, 40 pub(crate) rx: RDesRing<'d>,
43 pins: Pins<'d>, 41 pins: Pins<'d>,
44 pub(crate) phy: P, 42 pub(crate) phy: P,
45 pub(crate) station_management: EthernetStationManagement<T>,
46 pub(crate) mac_addr: [u8; 6], 43 pub(crate) mac_addr: [u8; 6],
47} 44}
48 45
49/// Pins of ethernet driver. 46/// Pins of ethernet driver.
50enum Pins<'d> { 47enum Pins<'d> {
51 Rmii([Peri<'d, AnyPin>; 9]), 48 Rmii([Peri<'d, AnyPin>; 7]),
52 Mii([Peri<'d, AnyPin>; 14]), 49 Mii([Peri<'d, AnyPin>; 12]),
53} 50}
54 51
55macro_rules! config_pins { 52macro_rules! config_pins {
@@ -63,41 +60,96 @@ macro_rules! config_pins {
63 }; 60 };
64} 61}
65 62
66impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { 63impl<'d, T: Instance, SMA: sma::Instance> Ethernet<'d, T, GenericPhy<Sma<'d, SMA>>> {
67 /// Create a new RMII ethernet driver using 9 pins. 64 /// Create a new RMII ethernet driver using 7 pins.
65 ///
66 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
67 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
68 ///
69 /// See [`Ethernet::new_with_phy`] for creating an RMII ethernet
70 /// river with a non-standard PHY.
68 pub fn new<const TX: usize, const RX: usize>( 71 pub fn new<const TX: usize, const RX: usize>(
69 queue: &'d mut PacketQueue<TX, RX>, 72 queue: &'d mut PacketQueue<TX, RX>,
70 peri: Peri<'d, T>, 73 peri: Peri<'d, T>,
71 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 74 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
72 ref_clk: Peri<'d, impl RefClkPin<T>>, 75 ref_clk: Peri<'d, impl RefClkPin<T>>,
73 mdio: Peri<'d, impl MDIOPin<T>>,
74 mdc: Peri<'d, impl MDCPin<T>>,
75 crs: Peri<'d, impl CRSPin<T>>, 76 crs: Peri<'d, impl CRSPin<T>>,
76 rx_d0: Peri<'d, impl RXD0Pin<T>>, 77 rx_d0: Peri<'d, impl RXD0Pin<T>>,
77 rx_d1: Peri<'d, impl RXD1Pin<T>>, 78 rx_d1: Peri<'d, impl RXD1Pin<T>>,
78 tx_d0: Peri<'d, impl TXD0Pin<T>>, 79 tx_d0: Peri<'d, impl TXD0Pin<T>>,
79 tx_d1: Peri<'d, impl TXD1Pin<T>>, 80 tx_d1: Peri<'d, impl TXD1Pin<T>>,
80 tx_en: Peri<'d, impl TXEnPin<T>>, 81 tx_en: Peri<'d, impl TXEnPin<T>>,
81 phy: P,
82 mac_addr: [u8; 6], 82 mac_addr: [u8; 6],
83 sma: Peri<'d, SMA>,
84 mdio: Peri<'d, impl MDIOPin<SMA>>,
85 mdc: Peri<'d, impl MDCPin<SMA>>,
83 ) -> Self { 86 ) -> Self {
84 // Enable the necessary clocks 87 let sma = Sma::new(sma, mdio, mdc);
85 critical_section::with(|_| { 88 let phy = GenericPhy::new_auto(sma);
86 crate::pac::RCC.ahb1enr().modify(|w| {
87 w.set_ethen(true);
88 w.set_ethtxen(true);
89 w.set_ethrxen(true);
90 });
91 89
92 crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII)); 90 Self::new_with_phy(
93 }); 91 queue, peri, irq, ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en, mac_addr, phy,
92 )
93 }
94
95 /// Create a new MII ethernet driver using 14 pins.
96 ///
97 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
98 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
99 ///
100 /// See [`Ethernet::new_mii_with_phy`] for creating an RMII ethernet
101 /// river with a non-standard PHY.
102 pub fn new_mii<const TX: usize, const RX: usize>(
103 queue: &'d mut PacketQueue<TX, RX>,
104 peri: Peri<'d, T>,
105 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
106 rx_clk: Peri<'d, impl RXClkPin<T>>,
107 tx_clk: Peri<'d, impl TXClkPin<T>>,
108 rxdv: Peri<'d, impl RXDVPin<T>>,
109 rx_d0: Peri<'d, impl RXD0Pin<T>>,
110 rx_d1: Peri<'d, impl RXD1Pin<T>>,
111 rx_d2: Peri<'d, impl RXD2Pin<T>>,
112 rx_d3: Peri<'d, impl RXD3Pin<T>>,
113 tx_d0: Peri<'d, impl TXD0Pin<T>>,
114 tx_d1: Peri<'d, impl TXD1Pin<T>>,
115 tx_d2: Peri<'d, impl TXD2Pin<T>>,
116 tx_d3: Peri<'d, impl TXD3Pin<T>>,
117 tx_en: Peri<'d, impl TXEnPin<T>>,
118 mac_addr: [u8; 6],
119 sma: Peri<'d, SMA>,
120 mdio: Peri<'d, impl MDIOPin<SMA>>,
121 mdc: Peri<'d, impl MDCPin<SMA>>,
122 ) -> Self {
123 let sma = Sma::new(sma, mdio, mdc);
124 let phy = GenericPhy::new_auto(sma);
125
126 Self::new_mii_with_phy(
127 queue, peri, irq, rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en,
128 mac_addr, phy,
129 )
130 }
131}
94 132
95 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 133impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
134 /// Create a new RMII ethernet driver using 7 pins.
135 pub fn new_with_phy<const TX: usize, const RX: usize>(
136 queue: &'d mut PacketQueue<TX, RX>,
137 peri: Peri<'d, T>,
138 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
139 ref_clk: Peri<'d, impl RefClkPin<T>>,
140 crs: Peri<'d, impl CRSPin<T>>,
141 rx_d0: Peri<'d, impl RXD0Pin<T>>,
142 rx_d1: Peri<'d, impl RXD1Pin<T>>,
143 tx_d0: Peri<'d, impl TXD0Pin<T>>,
144 tx_d1: Peri<'d, impl TXD1Pin<T>>,
145 tx_en: Peri<'d, impl TXEnPin<T>>,
146 mac_addr: [u8; 6],
147 phy: P,
148 ) -> Self {
149 config_pins!(ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
96 150
97 let pins = Pins::Rmii([ 151 let pins = Pins::Rmii([
98 ref_clk.into(), 152 ref_clk.into(),
99 mdio.into(),
100 mdc.into(),
101 crs.into(), 153 crs.into(),
102 rx_d0.into(), 154 rx_d0.into(),
103 rx_d1.into(), 155 rx_d1.into(),
@@ -106,18 +158,16 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
106 tx_en.into(), 158 tx_en.into(),
107 ]); 159 ]);
108 160
109 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 161 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, EthSelPhy::RMII)
110 } 162 }
111 163
112 /// Create a new MII ethernet driver using 14 pins. 164 /// Create a new MII ethernet driver using 12 pins.
113 pub fn new_mii<const TX: usize, const RX: usize>( 165 pub fn new_mii_with_phy<const TX: usize, const RX: usize>(
114 queue: &'d mut PacketQueue<TX, RX>, 166 queue: &'d mut PacketQueue<TX, RX>,
115 peri: Peri<'d, T>, 167 peri: Peri<'d, T>,
116 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 168 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
117 rx_clk: Peri<'d, impl RXClkPin<T>>, 169 rx_clk: Peri<'d, impl RXClkPin<T>>,
118 tx_clk: Peri<'d, impl TXClkPin<T>>, 170 tx_clk: Peri<'d, impl TXClkPin<T>>,
119 mdio: Peri<'d, impl MDIOPin<T>>,
120 mdc: Peri<'d, impl MDCPin<T>>,
121 rxdv: Peri<'d, impl RXDVPin<T>>, 171 rxdv: Peri<'d, impl RXDVPin<T>>,
122 rx_d0: Peri<'d, impl RXD0Pin<T>>, 172 rx_d0: Peri<'d, impl RXD0Pin<T>>,
123 rx_d1: Peri<'d, impl RXD1Pin<T>>, 173 rx_d1: Peri<'d, impl RXD1Pin<T>>,
@@ -128,29 +178,16 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
128 tx_d2: Peri<'d, impl TXD2Pin<T>>, 178 tx_d2: Peri<'d, impl TXD2Pin<T>>,
129 tx_d3: Peri<'d, impl TXD3Pin<T>>, 179 tx_d3: Peri<'d, impl TXD3Pin<T>>,
130 tx_en: Peri<'d, impl TXEnPin<T>>, 180 tx_en: Peri<'d, impl TXEnPin<T>>,
131 phy: P,
132 mac_addr: [u8; 6], 181 mac_addr: [u8; 6],
182 phy: P,
133 ) -> Self { 183 ) -> Self {
134 // Enable the necessary clocks 184 config_pins!(
135 critical_section::with(|_| { 185 rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
136 crate::pac::RCC.ahb1enr().modify(|w| { 186 );
137 w.set_ethen(true);
138 w.set_ethtxen(true);
139 w.set_ethrxen(true);
140 });
141
142 crate::pac::SYSCFG
143 .pmcr()
144 .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII));
145 });
146
147 config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
148 187
149 let pins = Pins::Mii([ 188 let pins = Pins::Mii([
150 rx_clk.into(), 189 rx_clk.into(),
151 tx_clk.into(), 190 tx_clk.into(),
152 mdio.into(),
153 mdc.into(),
154 rxdv.into(), 191 rxdv.into(),
155 rx_d0.into(), 192 rx_d0.into(),
156 rx_d1.into(), 193 rx_d1.into(),
@@ -163,7 +200,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
163 tx_en.into(), 200 tx_en.into(),
164 ]); 201 ]);
165 202
166 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 203 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, EthSelPhy::MII_GMII)
167 } 204 }
168 205
169 fn new_inner<const TX: usize, const RX: usize>( 206 fn new_inner<const TX: usize, const RX: usize>(
@@ -173,7 +210,19 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
173 pins: Pins<'d>, 210 pins: Pins<'d>,
174 phy: P, 211 phy: P,
175 mac_addr: [u8; 6], 212 mac_addr: [u8; 6],
213 eth_sel_phy: EthSelPhy,
176 ) -> Self { 214 ) -> Self {
215 // Enable the necessary clocks
216 critical_section::with(|_| {
217 crate::pac::RCC.ahb1enr().modify(|w| {
218 w.set_ethen(true);
219 w.set_ethtxen(true);
220 w.set_ethrxen(true);
221 });
222
223 crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(eth_sel_phy));
224 });
225
177 let dma = T::regs().ethernet_dma(); 226 let dma = T::regs().ethernet_dma();
178 let mac = T::regs().ethernet_mac(); 227 let mac = T::regs().ethernet_mac();
179 let mtl = T::regs().ethernet_mtl(); 228 let mtl = T::regs().ethernet_mtl();
@@ -235,32 +284,12 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
235 w.set_rbsz(RX_BUFFER_SIZE as u16); 284 w.set_rbsz(RX_BUFFER_SIZE as u16);
236 }); 285 });
237 286
238 let hclk = <T as SealedRccPeripheral>::frequency();
239 let hclk_mhz = hclk.0 / 1_000_000;
240
241 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
242 let clock_range = match hclk_mhz {
243 0..=34 => 2, // Divide by 16
244 35..=59 => 3, // Divide by 26
245 60..=99 => 0, // Divide by 42
246 100..=149 => 1, // Divide by 62
247 150..=249 => 4, // Divide by 102
248 250..=310 => 5, // Divide by 124
249 _ => {
250 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
251 }
252 };
253
254 let mut this = Self { 287 let mut this = Self {
255 _peri: peri, 288 _peri: peri,
256 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 289 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
257 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 290 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
258 pins, 291 pins,
259 phy, 292 phy,
260 station_management: EthernetStationManagement {
261 peri: PhantomData,
262 clock_range: clock_range,
263 },
264 mac_addr, 293 mac_addr,
265 }; 294 };
266 295
@@ -286,8 +315,8 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
286 w.set_tie(true); 315 w.set_tie(true);
287 }); 316 });
288 317
289 this.phy.phy_reset(&mut this.station_management); 318 this.phy.phy_reset();
290 this.phy.phy_init(&mut this.station_management); 319 this.phy.phy_init();
291 320
292 interrupt::ETH.unpend(); 321 interrupt::ETH.unpend();
293 unsafe { interrupt::ETH.enable() }; 322 unsafe { interrupt::ETH.enable() };
@@ -296,42 +325,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
296 } 325 }
297} 326}
298 327
299/// Ethernet SMI driver.
300pub struct EthernetStationManagement<T: Instance> {
301 peri: PhantomData<T>,
302 clock_range: u8,
303}
304
305impl<T: Instance> StationManagement for EthernetStationManagement<T> {
306 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
307 let mac = T::regs().ethernet_mac();
308
309 mac.macmdioar().modify(|w| {
310 w.set_pa(phy_addr);
311 w.set_rda(reg);
312 w.set_goc(0b11); // read
313 w.set_cr(self.clock_range);
314 w.set_mb(true);
315 });
316 while mac.macmdioar().read().mb() {}
317 mac.macmdiodr().read().md()
318 }
319
320 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
321 let mac = T::regs().ethernet_mac();
322
323 mac.macmdiodr().write(|w| w.set_md(val));
324 mac.macmdioar().modify(|w| {
325 w.set_pa(phy_addr);
326 w.set_rda(reg);
327 w.set_goc(0b01); // write
328 w.set_cr(self.clock_range);
329 w.set_mb(true);
330 });
331 while mac.macmdioar().read().mb() {}
332 }
333}
334
335impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { 328impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> {
336 fn drop(&mut self) { 329 fn drop(&mut self) {
337 let dma = T::regs().ethernet_dma(); 330 let dma = T::regs().ethernet_dma();
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 9fce78f95..458174b5d 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -5,13 +5,16 @@ use core::marker::PhantomData;
5use core::pin::Pin; 5use core::pin::Pin;
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::{impl_peripheral, PeripheralType}; 8use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use futures_util::FutureExt;
10 11
11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; 12use crate::gpio::{AnyPin, ExtiPin, Input, Level, Pin as GpioPin, PinNumber, Pull};
12use crate::pac::exti::regs::Lines; 13use crate::interrupt::Interrupt as InterruptEnum;
14use crate::interrupt::typelevel::{Binding, Handler, Interrupt as InterruptType};
13use crate::pac::EXTI; 15use crate::pac::EXTI;
14use crate::{interrupt, pac, peripherals, Peri}; 16use crate::pac::exti::regs::Lines;
17use crate::{Peri, pac};
15 18
16const EXTI_COUNT: usize = 16; 19const EXTI_COUNT: usize = 16;
17static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; 20static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT];
@@ -31,11 +34,11 @@ fn cpu_regs() -> pac::exti::Exti {
31 EXTI 34 EXTI
32} 35}
33 36
34#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] 37#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50, exti_n6)))]
35fn exticr_regs() -> pac::syscfg::Syscfg { 38fn exticr_regs() -> pac::syscfg::Syscfg {
36 pac::SYSCFG 39 pac::SYSCFG
37} 40}
38#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 41#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
39fn exticr_regs() -> pac::exti::Exti { 42fn exticr_regs() -> pac::exti::Exti {
40 EXTI 43 EXTI
41} 44}
@@ -45,9 +48,9 @@ fn exticr_regs() -> pac::afio::Afio {
45} 48}
46 49
47unsafe fn on_irq() { 50unsafe fn on_irq() {
48 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 51 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
49 let bits = EXTI.pr(0).read().0; 52 let bits = EXTI.pr(0).read().0;
50 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 53 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
51 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; 54 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
52 55
53 // We don't handle or change any EXTI lines above 16. 56 // We don't handle or change any EXTI lines above 16.
@@ -62,16 +65,16 @@ unsafe fn on_irq() {
62 } 65 }
63 66
64 // Clear pending 67 // Clear pending
65 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 68 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
66 EXTI.pr(0).write_value(Lines(bits)); 69 EXTI.pr(0).write_value(Lines(bits));
67 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 70 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
68 { 71 {
69 EXTI.rpr(0).write_value(Lines(bits)); 72 EXTI.rpr(0).write_value(Lines(bits));
70 EXTI.fpr(0).write_value(Lines(bits)); 73 EXTI.fpr(0).write_value(Lines(bits));
71 } 74 }
72 75
73 #[cfg(feature = "low-power")] 76 #[cfg(feature = "low-power")]
74 crate::low_power::on_wakeup_irq(); 77 crate::low_power::Executor::on_wakeup_irq_or_event();
75} 78}
76 79
77struct BitIter(u32); 80struct BitIter(u32);
@@ -105,10 +108,17 @@ impl<'d> Unpin for ExtiInput<'d> {}
105 108
106impl<'d> ExtiInput<'d> { 109impl<'d> ExtiInput<'d> {
107 /// Create an EXTI input. 110 /// Create an EXTI input.
108 pub fn new<T: GpioPin>(pin: Peri<'d, T>, ch: Peri<'d, T::ExtiChannel>, pull: Pull) -> Self { 111 ///
109 // Needed if using AnyPin+AnyChannel. 112 /// The Binding must bind the Channel's IRQ to [InterruptHandler].
110 assert_eq!(pin.pin(), ch.number()); 113 pub fn new<T: ExtiPin + GpioPin>(
111 114 pin: Peri<'d, T>,
115 _ch: Peri<'d, T::ExtiChannel>,
116 pull: Pull,
117 _irq: impl Binding<
118 <<T as ExtiPin>::ExtiChannel as Channel>::IRQ,
119 InterruptHandler<<<T as ExtiPin>::ExtiChannel as Channel>::IRQ>,
120 >,
121 ) -> Self {
112 Self { 122 Self {
113 pin: Input::new(pin, pull), 123 pin: Input::new(pin, pull),
114 } 124 }
@@ -133,7 +143,7 @@ impl<'d> ExtiInput<'d> {
133 /// 143 ///
134 /// This returns immediately if the pin is already high. 144 /// This returns immediately if the pin is already high.
135 pub async fn wait_for_high(&mut self) { 145 pub async fn wait_for_high(&mut self) {
136 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); 146 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, true);
137 if self.is_high() { 147 if self.is_high() {
138 return; 148 return;
139 } 149 }
@@ -144,7 +154,7 @@ impl<'d> ExtiInput<'d> {
144 /// 154 ///
145 /// This returns immediately if the pin is already low. 155 /// This returns immediately if the pin is already low.
146 pub async fn wait_for_low(&mut self) { 156 pub async fn wait_for_low(&mut self) {
147 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); 157 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, true);
148 if self.is_low() { 158 if self.is_low() {
149 return; 159 return;
150 } 160 }
@@ -155,19 +165,40 @@ impl<'d> ExtiInput<'d> {
155 /// 165 ///
156 /// If the pin is already high, it will wait for it to go low then back high. 166 /// If the pin is already high, it will wait for it to go low then back high.
157 pub async fn wait_for_rising_edge(&mut self) { 167 pub async fn wait_for_rising_edge(&mut self) {
158 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await 168 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, true).await
169 }
170
171 /// Asynchronously wait until the pin sees a rising edge.
172 ///
173 /// If the pin is already high, it will wait for it to go low then back high.
174 pub fn poll_for_rising_edge<'a>(&mut self, cx: &mut Context<'a>) {
175 let _ =
176 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, false).poll_unpin(cx);
159 } 177 }
160 178
161 /// Asynchronously wait until the pin sees a falling edge. 179 /// Asynchronously wait until the pin sees a falling edge.
162 /// 180 ///
163 /// If the pin is already low, it will wait for it to go high then back low. 181 /// If the pin is already low, it will wait for it to go high then back low.
164 pub async fn wait_for_falling_edge(&mut self) { 182 pub async fn wait_for_falling_edge(&mut self) {
165 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await 183 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, true).await
184 }
185
186 /// Asynchronously wait until the pin sees a falling edge.
187 ///
188 /// If the pin is already low, it will wait for it to go high then back low.
189 pub fn poll_for_falling_edge<'a>(&mut self, cx: &mut Context<'a>) {
190 let _ =
191 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, false).poll_unpin(cx);
166 } 192 }
167 193
168 /// Asynchronously wait until the pin sees any edge (either rising or falling). 194 /// Asynchronously wait until the pin sees any edge (either rising or falling).
169 pub async fn wait_for_any_edge(&mut self) { 195 pub async fn wait_for_any_edge(&mut self) {
170 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await 196 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true, true).await
197 }
198
199 /// Asynchronously wait until the pin sees any edge (either rising or falling).
200 pub fn poll_for_any_edge<'a>(&mut self, cx: &mut Context<'a>) {
201 let _ = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true, false).poll_unpin(cx);
171 } 202 }
172} 203}
173 204
@@ -226,12 +257,13 @@ impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> {
226 257
227#[must_use = "futures do nothing unless you `.await` or poll them"] 258#[must_use = "futures do nothing unless you `.await` or poll them"]
228struct ExtiInputFuture<'a> { 259struct ExtiInputFuture<'a> {
229 pin: u8, 260 pin: PinNumber,
261 drop: bool,
230 phantom: PhantomData<&'a mut AnyPin>, 262 phantom: PhantomData<&'a mut AnyPin>,
231} 263}
232 264
233impl<'a> ExtiInputFuture<'a> { 265impl<'a> ExtiInputFuture<'a> {
234 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { 266 fn new(pin: PinNumber, port: PinNumber, rising: bool, falling: bool, drop: bool) -> Self {
235 critical_section::with(|_| { 267 critical_section::with(|_| {
236 let pin = pin as usize; 268 let pin = pin as usize;
237 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); 269 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
@@ -239,9 +271,9 @@ impl<'a> ExtiInputFuture<'a> {
239 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); 271 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
240 272
241 // clear pending bit 273 // clear pending bit
242 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 274 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
243 EXTI.pr(0).write(|w| w.set_line(pin, true)); 275 EXTI.pr(0).write(|w| w.set_line(pin, true));
244 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 276 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
245 { 277 {
246 EXTI.rpr(0).write(|w| w.set_line(pin, true)); 278 EXTI.rpr(0).write(|w| w.set_line(pin, true));
247 EXTI.fpr(0).write(|w| w.set_line(pin, true)); 279 EXTI.fpr(0).write(|w| w.set_line(pin, true));
@@ -252,6 +284,7 @@ impl<'a> ExtiInputFuture<'a> {
252 284
253 Self { 285 Self {
254 pin, 286 pin,
287 drop,
255 phantom: PhantomData, 288 phantom: PhantomData,
256 } 289 }
257 } 290 }
@@ -259,10 +292,12 @@ impl<'a> ExtiInputFuture<'a> {
259 292
260impl<'a> Drop for ExtiInputFuture<'a> { 293impl<'a> Drop for ExtiInputFuture<'a> {
261 fn drop(&mut self) { 294 fn drop(&mut self) {
262 critical_section::with(|_| { 295 if self.drop {
263 let pin = self.pin as _; 296 critical_section::with(|_| {
264 cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); 297 let pin = self.pin as _;
265 }); 298 cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
299 });
300 }
266 } 301 }
267} 302}
268 303
@@ -302,7 +337,7 @@ macro_rules! foreach_exti_irq {
302 (EXTI15) => { $action!(EXTI15); }; 337 (EXTI15) => { $action!(EXTI15); };
303 338
304 // plus the weird ones 339 // plus the weird ones
305 (EXTI0_1) => { $action!( EXTI0_1 ); }; 340 (EXTI0_1) => { $action!(EXTI0_1); };
306 (EXTI15_10) => { $action!(EXTI15_10); }; 341 (EXTI15_10) => { $action!(EXTI15_10); };
307 (EXTI15_4) => { $action!(EXTI15_4); }; 342 (EXTI15_4) => { $action!(EXTI15_4); };
308 (EXTI1_0) => { $action!(EXTI1_0); }; 343 (EXTI1_0) => { $action!(EXTI1_0); };
@@ -315,57 +350,67 @@ macro_rules! foreach_exti_irq {
315 }; 350 };
316} 351}
317 352
318macro_rules! impl_irq { 353///EXTI interrupt handler. All EXTI interrupt vectors should be bound to this handler.
319 ($e:ident) => { 354///
320 #[allow(non_snake_case)] 355/// It is generic over the [Interrupt](InterruptType) rather
321 #[cfg(feature = "rt")] 356/// than the [Channel] because it should not be bound multiple
322 #[interrupt] 357/// times to the same vector on chips which multiplex multiple EXTI interrupts into one vector.
323 unsafe fn $e() { 358//
324 on_irq() 359// It technically doesn't need to be generic at all, except to satisfy the generic argument
325 } 360// of [Handler]. All EXTI interrupts eventually land in the same on_irq() function.
326 }; 361pub struct InterruptHandler<T: crate::interrupt::typelevel::Interrupt> {
362 _phantom: PhantomData<T>,
327} 363}
328 364
329foreach_exti_irq!(impl_irq); 365impl<T: InterruptType> Handler<T> for InterruptHandler<T> {
366 unsafe fn on_interrupt() {
367 on_irq()
368 }
369}
330 370
331trait SealedChannel {} 371trait SealedChannel {}
332 372
333/// EXTI channel trait. 373/// EXTI channel trait.
334#[allow(private_bounds)] 374#[allow(private_bounds)]
335pub trait Channel: PeripheralType + SealedChannel + Sized { 375pub trait Channel: PeripheralType + SealedChannel + Sized {
336 /// Get the EXTI channel number. 376 /// EXTI channel number.
337 fn number(&self) -> u8; 377 fn number(&self) -> PinNumber;
378 /// [Enum-level Interrupt](InterruptEnum), which may be the same for multiple channels.
379 fn irq(&self) -> InterruptEnum;
380 /// [Type-level Interrupt](InterruptType), which may be the same for multiple channels.
381 type IRQ: InterruptType;
338} 382}
339 383
340/// Type-erased EXTI channel. 384//Doc isn't hidden in order to surface the explanation to users, even though it's completely inoperable, not just deprecated.
385//Entire type along with doc can probably be removed after deprecation has appeared in a release once.
386/// Deprecated type-erased EXTI channel.
341/// 387///
342/// This represents ownership over any EXTI channel, known at runtime. 388/// Support for AnyChannel was removed in order to support manually bindable EXTI interrupts via bind_interrupts; [ExtiInput::new()]
389/// must know the required IRQ at compile time, and therefore cannot support type-erased channels.
390#[deprecated = "type-erased EXTI channels are no longer supported, in order to support manually bindable EXTI interrupts (more info: https://github.com/embassy-rs/embassy/pull/4922)"]
343pub struct AnyChannel { 391pub struct AnyChannel {
344 number: u8, 392 #[allow(unused)]
345} 393 number: PinNumber,
346
347impl_peripheral!(AnyChannel);
348impl SealedChannel for AnyChannel {}
349impl Channel for AnyChannel {
350 fn number(&self) -> u8 {
351 self.number
352 }
353} 394}
354 395
355macro_rules! impl_exti { 396macro_rules! impl_exti {
356 ($type:ident, $number:expr) => { 397 ($type:ident, $number:expr) => {
357 impl SealedChannel for peripherals::$type {} 398 impl SealedChannel for crate::peripherals::$type {}
358 impl Channel for peripherals::$type { 399 impl Channel for crate::peripherals::$type {
359 fn number(&self) -> u8 { 400 fn number(&self) -> PinNumber {
360 $number 401 $number
361 } 402 }
403 fn irq(&self) -> InterruptEnum {
404 crate::_generated::peripheral_interrupts::EXTI::$type::IRQ
405 }
406 type IRQ = crate::_generated::peripheral_interrupts::EXTI::$type;
362 } 407 }
363 408
364 impl From<peripherals::$type> for AnyChannel { 409 //Still here to surface deprecation messages to the user - remove when removing AnyChannel
365 fn from(val: peripherals::$type) -> Self { 410 #[allow(deprecated)]
366 Self { 411 impl From<crate::peripherals::$type> for AnyChannel {
367 number: val.number() as u8, 412 fn from(_val: crate::peripherals::$type) -> Self {
368 } 413 Self { number: $number }
369 } 414 }
370 } 415 }
371 }; 416 };
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 006dcddeb..a131217b7 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -1,17 +1,17 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::mutex::Mutex; 6use embassy_sync::mutex::Mutex;
7 7
8use super::{ 8use super::{
9 blocking_read, ensure_sector_aligned, family, get_flash_regions, get_sector, Async, Error, Flash, FlashLayout, 9 Async, Error, FLASH_BASE, FLASH_SIZE, Flash, FlashLayout, WRITE_SIZE, blocking_read, ensure_sector_aligned, family,
10 FLASH_BASE, FLASH_SIZE, WRITE_SIZE, 10 get_flash_regions, get_sector,
11}; 11};
12use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
13use crate::peripherals::FLASH; 13use crate::peripherals::FLASH;
14use crate::{interrupt, Peri}; 14use crate::{Peri, interrupt};
15 15
16pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); 16pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
17 17
diff --git a/embassy-stm32/src/flash/c.rs b/embassy-stm32/src/flash/c.rs
new file mode 100644
index 000000000..0ad1002b0
--- /dev/null
+++ b/embassy-stm32/src/flash/c.rs
@@ -0,0 +1,131 @@
1use core::ptr::write_volatile;
2use core::sync::atomic::{Ordering, fence};
3
4use cortex_m::interrupt;
5
6use super::{FlashSector, WRITE_SIZE};
7use crate::flash::Error;
8use crate::pac;
9
10pub(crate) unsafe fn lock() {
11 pac::FLASH.cr().modify(|w| w.set_lock(true));
12}
13pub(crate) unsafe fn unlock() {
14 // Wait, while the memory interface is busy.
15 wait_busy();
16
17 // Unlock flash
18 if pac::FLASH.cr().read().lock() {
19 pac::FLASH.keyr().write_value(0x4567_0123);
20 pac::FLASH.keyr().write_value(0xCDEF_89AB);
21 }
22}
23
24pub(crate) unsafe fn enable_blocking_write() {
25 assert_eq!(0, WRITE_SIZE % 4);
26 pac::FLASH.cr().write(|w| w.set_pg(true));
27}
28
29pub(crate) unsafe fn disable_blocking_write() {
30 pac::FLASH.cr().write(|w| w.set_pg(false));
31}
32
33pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
34 let mut address = start_address;
35 for val in buf.chunks(4) {
36 write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into())));
37 address += val.len() as u32;
38
39 // prevents parallelism errors
40 fence(Ordering::SeqCst);
41 }
42
43 wait_ready_blocking()
44}
45
46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
47 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
48
49 #[cfg(feature = "defmt")]
50 defmt::trace!(
51 "STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}",
52 sector.start,
53 idx,
54 super::BANK1_REGION.erase_size
55 );
56
57 wait_busy();
58 clear_all_err();
59
60 // Explicitly unlock before erase
61 unlock();
62
63 interrupt::free(|_| {
64 #[cfg(feature = "defmt")]
65 {
66 let cr_before = pac::FLASH.cr().read();
67 defmt::trace!("FLASH_CR before: 0x{:08x}", cr_before.0);
68 }
69
70 pac::FLASH.cr().modify(|w| {
71 w.set_per(true);
72 w.set_pnb(idx as u8);
73 w.set_strt(true);
74 });
75
76 #[cfg(feature = "defmt")]
77 {
78 let cr_after = pac::FLASH.cr().read();
79 defmt::trace!(
80 "FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}",
81 cr_after.0,
82 cr_after.per(),
83 cr_after.pnb(),
84 cr_after.strt()
85 );
86 }
87 });
88
89 let ret: Result<(), Error> = wait_ready_blocking();
90
91 // Clear erase bit
92 pac::FLASH.cr().modify(|w| w.set_per(false));
93
94 // Explicitly lock after erase
95 lock();
96
97 // Extra wait to ensure operation completes
98 wait_busy();
99
100 ret
101}
102
103pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
104 while pac::FLASH.sr().read().bsy() {}
105
106 let sr = pac::FLASH.sr().read();
107
108 if sr.progerr() {
109 return Err(Error::Prog);
110 }
111
112 if sr.wrperr() {
113 return Err(Error::Protected);
114 }
115
116 if sr.pgaerr() {
117 return Err(Error::Unaligned);
118 }
119
120 Ok(())
121}
122
123pub(crate) unsafe fn clear_all_err() {
124 // read and write back the same value.
125 // This clears all "write 1 to clear" bits.
126 pac::FLASH.sr().modify(|_| {});
127}
128
129fn wait_busy() {
130 while pac::FLASH.sr().read().bsy() {}
131}
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 10023e637..60d00e766 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -1,14 +1,14 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5 5
6use super::{ 6use super::{
7 family, get_flash_regions, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, 7 Async, Blocking, Error, FLASH_SIZE, FlashBank, FlashLayout, FlashRegion, FlashSector, MAX_ERASE_SIZE, READ_SIZE,
8 MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, 8 WRITE_SIZE, family, get_flash_regions,
9}; 9};
10use crate::Peri;
11use crate::_generated::FLASH_BASE; 10use crate::_generated::FLASH_BASE;
11use crate::Peri;
12use crate::peripherals::FLASH; 12use crate::peripherals::FLASH;
13 13
14/// Internal flash memory driver. 14/// Internal flash memory driver.
@@ -102,7 +102,13 @@ pub(super) unsafe fn blocking_write(
102 } 102 }
103 103
104 let mut address = base + offset; 104 let mut address = base + offset;
105 trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); 105 trace!(
106 "Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})",
107 bytes.len(),
108 address,
109 base,
110 offset
111 );
106 112
107 for chunk in bytes.chunks(WRITE_SIZE) { 113 for chunk in bytes.chunks(WRITE_SIZE) {
108 write_chunk(address, chunk)?; 114 write_chunk(address, chunk)?;
diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs
index cc3529eb9..39c497e3f 100644
--- a/embassy-stm32/src/flash/eeprom.rs
+++ b/embassy-stm32/src/flash/eeprom.rs
@@ -1,6 +1,6 @@
1use embassy_hal_internal::drop::OnDrop; 1use embassy_hal_internal::drop::OnDrop;
2 2
3use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE}; 3use super::{Blocking, EEPROM_BASE, EEPROM_SIZE, Error, Flash, family};
4 4
5#[cfg(eeprom)] 5#[cfg(eeprom)]
6impl<'d> Flash<'d, Blocking> { 6impl<'d> Flash<'d, Blocking> {
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index 3f9dbe945..5c01fce9c 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs
index bf9ad2893..9e469ffbc 100644
--- a/embassy-stm32/src/flash/f1f3.rs
+++ b/embassy-stm32/src/flash/f1f3.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs
index 67e380619..b48ab3b76 100644
--- a/embassy-stm32/src/flash/f2.rs
+++ b/embassy-stm32/src/flash/f2.rs
@@ -1,9 +1,9 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering, fence};
3 3
4use pac::flash::regs::Sr; 4use pac::flash::regs::Sr;
5 5
6use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; 6use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions};
7use crate::flash::Error; 7use crate::flash::Error;
8use crate::pac; 8use crate::pac;
9 9
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 62e0492b5..9c5051492 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -1,10 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering, fence};
3 3
4use embassy_sync::waitqueue::AtomicWaker; 4use embassy_sync::waitqueue::AtomicWaker;
5use pac::flash::regs::Sr; 5use pac::flash::regs::Sr;
6 6
7use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; 7use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions};
8use crate::_generated::FLASH_SIZE; 8use crate::_generated::FLASH_SIZE;
9use crate::flash::Error; 9use crate::flash::Error;
10use crate::pac; 10use crate::pac;
@@ -246,7 +246,9 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
246 feature = "stm32f439zi", 246 feature = "stm32f439zi",
247 ))] 247 ))]
248 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { 248 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
249 panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); 249 panic!(
250 "Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"
251 );
250 } 252 }
251 253
252 #[cfg(any( 254 #[cfg(any(
@@ -270,14 +272,16 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
270 feature = "stm32f439zg", 272 feature = "stm32f439zg",
271 ))] 273 ))]
272 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { 274 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
273 panic!("Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"); 275 panic!(
276 "Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"
277 );
274 } 278 }
275} 279}
276 280
277#[allow(unused)] 281#[allow(unused)]
278fn pa12_is_output_pull_low() -> bool { 282fn pa12_is_output_pull_low() -> bool {
279 use pac::gpio::vals;
280 use pac::GPIOA; 283 use pac::GPIOA;
284 use pac::gpio::vals;
281 const PIN: usize = 12; 285 const PIN: usize = 12;
282 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT 286 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
283 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN 287 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN
@@ -287,7 +291,7 @@ fn pa12_is_output_pull_low() -> bool {
287#[cfg(test)] 291#[cfg(test)]
288mod tests { 292mod tests {
289 use super::*; 293 use super::*;
290 use crate::flash::{get_sector, FlashBank}; 294 use crate::flash::{FlashBank, get_sector};
291 295
292 #[test] 296 #[test]
293 #[cfg(stm32f429)] 297 #[cfg(stm32f429)]
@@ -370,9 +374,13 @@ mod tests {
370#[cfg(all(bank_setup_configurable))] 374#[cfg(all(bank_setup_configurable))]
371pub(crate) fn check_bank_setup() { 375pub(crate) fn check_bank_setup() {
372 if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() { 376 if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() {
373 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"); 377 panic!(
378 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"
379 );
374 } 380 }
375 if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() { 381 if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() {
376 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"); 382 panic!(
383 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"
384 );
377 } 385 }
378} 386}
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index 0547c747a..09389c417 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
@@ -99,7 +99,7 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> {
99#[cfg(test)] 99#[cfg(test)]
100mod tests { 100mod tests {
101 use super::*; 101 use super::*;
102 use crate::flash::{get_sector, FlashBank}; 102 use crate::flash::{FlashBank, get_sector};
103 103
104 #[test] 104 #[test]
105 #[cfg(stm32f732)] 105 #[cfg(stm32f732)]
@@ -218,9 +218,13 @@ mod tests {
218#[cfg(all(bank_setup_configurable))] 218#[cfg(all(bank_setup_configurable))]
219pub(crate) fn check_bank_setup() { 219pub(crate) fn check_bank_setup() {
220 if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() { 220 if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() {
221 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"); 221 panic!(
222 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"
223 );
222 } 224 }
223 if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() { 225 if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() {
224 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"); 226 panic!(
227 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"
228 );
225 } 229 }
226} 230}
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs
index bc1fd360c..d7ba2f571 100644
--- a/embassy-stm32/src/flash/g.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
@@ -44,7 +44,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
44} 44}
45 45
46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
47 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
48 wait_busy(); 47 wait_busy();
49 clear_all_err(); 48 clear_all_err();
50 49
@@ -54,9 +53,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
54 #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))] 53 #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))]
55 w.set_bker(sector.bank == crate::flash::FlashBank::Bank2); 54 w.set_bker(sector.bank == crate::flash::FlashBank::Bank2);
56 #[cfg(flash_g0x0)] 55 #[cfg(flash_g0x0)]
57 w.set_pnb(idx as u16); 56 w.set_pnb(sector.index_in_bank as u16);
58 #[cfg(not(flash_g0x0))] 57 #[cfg(not(flash_g0x0))]
59 w.set_pnb(idx as u8); 58 w.set_pnb(sector.index_in_bank as u8);
60 w.set_strt(true); 59 w.set_strt(true);
61 }); 60 });
62 }); 61 });
@@ -105,19 +104,27 @@ fn wait_busy() {
105#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))] 104#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))]
106pub(crate) fn check_bank_setup() { 105pub(crate) fn check_bank_setup() {
107 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { 106 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
108 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); 107 panic!(
108 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"
109 );
109 } 110 }
110 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { 111 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
111 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); 112 panic!(
113 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"
114 );
112 } 115 }
113} 116}
114 117
115#[cfg(all(bank_setup_configurable, flash_g0x1))] 118#[cfg(all(bank_setup_configurable, flash_g0x1))]
116pub(crate) fn check_bank_setup() { 119pub(crate) fn check_bank_setup() {
117 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() { 120 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() {
118 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"); 121 panic!(
122 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"
123 );
119 } 124 }
120 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() { 125 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() {
121 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"); 126 panic!(
127 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"
128 );
122 } 129 }
123} 130}
diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs
index fd9bfcc75..88f247879 100644
--- a/embassy-stm32/src/flash/h5.rs
+++ b/embassy-stm32/src/flash/h5.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index f8e210556..91d5da4d6 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -1,7 +1,7 @@
1/// STM32H50 series flash impl. See RM0492 1/// STM32H50 series flash impl. See RM0492
2use core::{ 2use core::{
3 ptr::write_volatile, 3 ptr::write_volatile,
4 sync::atomic::{fence, Ordering}, 4 sync::atomic::{Ordering, fence},
5}; 5};
6 6
7use cortex_m::interrupt; 7use cortex_m::interrupt;
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index f1d84101c..b342f4a83 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -1,10 +1,31 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; 4use embassy_sync::waitqueue::AtomicWaker;
5use pac::flash::regs::Sr;
6
7use super::{BANK1_REGION, FLASH_REGIONS, FlashSector, WRITE_SIZE};
5use crate::flash::Error; 8use crate::flash::Error;
6use crate::pac; 9use crate::pac;
7 10
11static WAKER: AtomicWaker = AtomicWaker::new();
12
13pub(crate) unsafe fn on_interrupt() {
14 // Clear IRQ flags
15 pac::FLASH.bank(0).ccr().write(|w| {
16 w.set_clr_eop(true);
17 w.set_clr_operr(true);
18 });
19 if is_dual_bank() {
20 pac::FLASH.bank(1).ccr().write(|w| {
21 w.set_clr_eop(true);
22 w.set_clr_operr(true);
23 });
24 }
25
26 WAKER.wake();
27}
28
8const fn is_dual_bank() -> bool { 29const fn is_dual_bank() -> bool {
9 FLASH_REGIONS.len() >= 2 30 FLASH_REGIONS.len() >= 2
10} 31}
@@ -29,12 +50,68 @@ pub(crate) unsafe fn unlock() {
29 } 50 }
30} 51}
31 52
53pub(crate) unsafe fn enable_write() {
54 enable_blocking_write();
55}
56
57pub(crate) unsafe fn disable_write() {
58 disable_blocking_write();
59}
60
32pub(crate) unsafe fn enable_blocking_write() { 61pub(crate) unsafe fn enable_blocking_write() {
33 assert_eq!(0, WRITE_SIZE % 4); 62 assert_eq!(0, WRITE_SIZE % 4);
34} 63}
35 64
36pub(crate) unsafe fn disable_blocking_write() {} 65pub(crate) unsafe fn disable_blocking_write() {}
37 66
67pub(crate) async unsafe fn write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
68 // We cannot have the write setup sequence in begin_write as it depends on the address
69 let bank = if start_address < BANK1_REGION.end() {
70 pac::FLASH.bank(0)
71 } else {
72 pac::FLASH.bank(1)
73 };
74 bank.cr().write(|w| {
75 w.set_pg(true);
76 #[cfg(flash_h7)]
77 w.set_psize(2); // 32 bits at once
78 w.set_eopie(true);
79 w.set_operrie(true);
80 });
81 cortex_m::asm::isb();
82 cortex_m::asm::dsb();
83 fence(Ordering::SeqCst);
84
85 let mut res = None;
86 let mut address = start_address;
87 for val in buf.chunks(4) {
88 write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into())));
89 address += val.len() as u32;
90
91 res = Some(wait_ready(bank).await);
92 bank.sr().modify(|w| {
93 if w.eop() {
94 w.set_eop(true);
95 }
96 });
97 if unwrap!(res).is_err() {
98 break;
99 }
100 }
101
102 cortex_m::asm::isb();
103 cortex_m::asm::dsb();
104 fence(Ordering::SeqCst);
105
106 bank.cr().write(|w| {
107 w.set_pg(false);
108 w.set_eopie(false);
109 w.set_operrie(false);
110 });
111
112 unwrap!(res)
113}
114
38pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 115pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
39 // We cannot have the write setup sequence in begin_write as it depends on the address 116 // We cannot have the write setup sequence in begin_write as it depends on the address
40 let bank = if start_address < BANK1_REGION.end() { 117 let bank = if start_address < BANK1_REGION.end() {
@@ -77,6 +154,36 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
77 unwrap!(res) 154 unwrap!(res)
78} 155}
79 156
157pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> {
158 let bank = pac::FLASH.bank(sector.bank as usize);
159 bank.cr().modify(|w| {
160 w.set_ser(true);
161 #[cfg(flash_h7)]
162 w.set_snb(sector.index_in_bank);
163 #[cfg(flash_h7ab)]
164 w.set_ssn(sector.index_in_bank);
165 w.set_eopie(true);
166 w.set_operrie(true);
167 });
168
169 bank.cr().modify(|w| {
170 w.set_start(true);
171 });
172
173 cortex_m::asm::isb();
174 cortex_m::asm::dsb();
175 fence(Ordering::SeqCst);
176
177 let ret: Result<(), Error> = wait_ready(bank).await;
178 bank.cr().modify(|w| {
179 w.set_ser(false);
180 w.set_eopie(false);
181 w.set_operrie(false);
182 });
183 bank_clear_all_err(bank);
184 ret
185}
186
80pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 187pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
81 let bank = pac::FLASH.bank(sector.bank as usize); 188 let bank = pac::FLASH.bank(sector.bank as usize);
82 bank.cr().modify(|w| { 189 bank.cr().modify(|w| {
@@ -112,46 +219,59 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) {
112 bank.sr().modify(|_| {}); 219 bank.sr().modify(|_| {});
113} 220}
114 221
222async fn wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
223 use core::future::poll_fn;
224 use core::task::Poll;
225
226 poll_fn(|cx| {
227 WAKER.register(cx.waker());
228
229 let sr = bank.sr().read();
230 if !sr.bsy() && !sr.qw() {
231 Poll::Ready(get_result(sr))
232 } else {
233 return Poll::Pending;
234 }
235 })
236 .await
237}
238
115unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { 239unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
116 loop { 240 loop {
117 let sr = bank.sr().read(); 241 let sr = bank.sr().read();
118 242
119 if !sr.bsy() && !sr.qw() { 243 if !sr.bsy() && !sr.qw() {
120 if sr.wrperr() { 244 return get_result(sr);
121 return Err(Error::Protected);
122 }
123 if sr.pgserr() {
124 error!("pgserr");
125 return Err(Error::Seq);
126 }
127 if sr.incerr() {
128 // writing to a different address when programming 256 bit word was not finished
129 error!("incerr");
130 return Err(Error::Seq);
131 }
132 if sr.crcrderr() {
133 error!("crcrderr");
134 return Err(Error::Seq);
135 }
136 if sr.operr() {
137 return Err(Error::Prog);
138 }
139 if sr.sneccerr1() {
140 // single ECC error
141 return Err(Error::Prog);
142 }
143 if sr.dbeccerr() {
144 // double ECC error
145 return Err(Error::Prog);
146 }
147 if sr.rdperr() {
148 return Err(Error::Protected);
149 }
150 if sr.rdserr() {
151 return Err(Error::Protected);
152 }
153
154 return Ok(());
155 } 245 }
156 } 246 }
157} 247}
248
249fn get_result(sr: Sr) -> Result<(), Error> {
250 if sr.wrperr() {
251 Err(Error::Protected)
252 } else if sr.pgserr() {
253 error!("pgserr");
254 Err(Error::Seq)
255 } else if sr.incerr() {
256 // writing to a different address when programming 256 bit word was not finished
257 error!("incerr");
258 Err(Error::Seq)
259 } else if sr.crcrderr() {
260 error!("crcrderr");
261 Err(Error::Seq)
262 } else if sr.operr() {
263 Err(Error::Prog)
264 } else if sr.sneccerr1() {
265 // single ECC error
266 Err(Error::Prog)
267 } else if sr.dbeccerr() {
268 // double ECC error
269 Err(Error::Prog)
270 } else if sr.rdperr() {
271 Err(Error::Protected)
272 } else if sr.rdserr() {
273 Err(Error::Protected)
274 } else {
275 Ok(())
276 }
277}
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 1b82704ec..b3281f2d5 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
@@ -96,14 +96,20 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] 96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))]
97 { 97 {
98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; 98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
99 #[cfg(any(flash_l4, flash_l5))]
100 let pgn = super::BANK1_REGION.size as u32 / super::BANK1_REGION.erase_size as u32;
99 101
100 #[cfg(flash_l4)] 102 #[cfg(flash_l4)]
101 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; 103 let (idx, bank) = if idx > (pgn - 1) {
104 (idx - pgn, true)
105 } else {
106 (idx, false)
107 };
102 108
103 #[cfg(flash_l5)] 109 #[cfg(flash_l5)]
104 let (idx, bank) = if pac::FLASH.optr().read().dbank() { 110 let (idx, bank) = if pac::FLASH.optr().read().dbank() {
105 if idx > 255 { 111 if idx > (pgn - 1) {
106 (idx - 256, Some(true)) 112 (idx - pgn, Some(true))
107 } else { 113 } else {
108 (idx, Some(false)) 114 (idx, Some(false))
109 } 115 }
@@ -234,19 +240,27 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
234#[cfg(all(bank_setup_configurable, flash_l5))] 240#[cfg(all(bank_setup_configurable, flash_l5))]
235pub(crate) fn check_bank_setup() { 241pub(crate) fn check_bank_setup() {
236 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { 242 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
237 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); 243 panic!(
244 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"
245 );
238 } 246 }
239 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { 247 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
240 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); 248 panic!(
249 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"
250 );
241 } 251 }
242} 252}
243 253
244#[cfg(all(bank_setup_configurable, flash_l4))] 254#[cfg(all(bank_setup_configurable, flash_l4))]
245pub(crate) fn check_bank_setup() { 255pub(crate) fn check_bank_setup() {
246 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() { 256 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() {
247 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"); 257 panic!(
258 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"
259 );
248 } 260 }
249 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() { 261 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() {
250 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"); 262 panic!(
263 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"
264 );
251 } 265 }
252} 266}
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 3e74d857a..6211a37b7 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -1,14 +1,14 @@
1//! Flash memory (FLASH) 1//! Flash memory (FLASH)
2use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; 2use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
3 3
4#[cfg(flash_f4)] 4#[cfg(any(flash_f4, flash_h7, flash_h7ab))]
5mod asynch; 5mod asynch;
6#[cfg(flash)] 6#[cfg(flash)]
7mod common; 7mod common;
8#[cfg(eeprom)] 8#[cfg(eeprom)]
9mod eeprom; 9mod eeprom;
10 10
11#[cfg(flash_f4)] 11#[cfg(any(flash_f4, flash_h7, flash_h7ab))]
12pub use asynch::InterruptHandler; 12pub use asynch::InterruptHandler;
13#[cfg(flash)] 13#[cfg(flash)]
14pub use common::*; 14pub use common::*;
@@ -99,6 +99,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is
99#[cfg_attr(flash_f4, path = "f4.rs")] 99#[cfg_attr(flash_f4, path = "f4.rs")]
100#[cfg_attr(flash_f7, path = "f7.rs")] 100#[cfg_attr(flash_f7, path = "f7.rs")]
101#[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] 101#[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")]
102#[cfg_attr(flash_c0, path = "c.rs")]
102#[cfg_attr(flash_h7, path = "h7.rs")] 103#[cfg_attr(flash_h7, path = "h7.rs")]
103#[cfg_attr(flash_h7ab, path = "h7.rs")] 104#[cfg_attr(flash_h7ab, path = "h7.rs")]
104#[cfg_attr(any(flash_u5, flash_wba), path = "u5.rs")] 105#[cfg_attr(any(flash_u5, flash_wba), path = "u5.rs")]
@@ -108,7 +109,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is
108#[cfg_attr( 109#[cfg_attr(
109 not(any( 110 not(any(
110 flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, 111 flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4,
111 flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, 112 flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_c0, flash_h7, flash_h7ab, flash_u5,
112 flash_wba, flash_h50, flash_u0, flash_h5, 113 flash_wba, flash_h50, flash_u0, flash_h5,
113 )), 114 )),
114 path = "other.rs" 115 path = "other.rs"
diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs
index 68d847eca..a64f6c492 100644
--- a/embassy-stm32/src/flash/u0.rs
+++ b/embassy-stm32/src/flash/u0.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
index 6c3d4b422..5f1f562c0 100644
--- a/embassy-stm32/src/flash/u5.rs
+++ b/embassy-stm32/src/flash/u5.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashBank, FlashSector, WRITE_SIZE}; 4use super::{FlashBank, FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index ff18a8bee..a7c6c90bb 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::gpio::{AfType, OutputType, Pull, Speed}; 6use crate::gpio::{AfType, OutputType, Pull, Speed};
7use crate::{rcc, Peri}; 7use crate::{Peri, rcc};
8 8
9/// FMC driver 9/// FMC driver
10pub struct Fmc<'d, T: Instance> { 10pub struct Fmc<'d, T: Instance> {
@@ -236,6 +236,42 @@ impl<'d, T: Instance> Fmc<'d, T> {
236 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) 236 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
237 ] 237 ]
238 )); 238 ));
239
240 fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank1: (
241 bank: stm32_fmc::SdramTargetBank::Bank1,
242 addr: [
243 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
244 ],
245 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
246 d: [
247 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
248 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
249 ],
250 nbl: [
251 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
252 ],
253 ctrl: [
254 (sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
255 ]
256 ));
257
258 fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank2: (
259 bank: stm32_fmc::SdramTargetBank::Bank2,
260 addr: [
261 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
262 ],
263 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
264 d: [
265 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
266 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
267 ],
268 nbl: [
269 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
270 ],
271 ctrl: [
272 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
273 ]
274 ));
239} 275}
240 276
241trait SealedInstance: crate::rcc::RccPeripheral { 277trait SealedInstance: crate::rcc::RccPeripheral {
diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs
index b6ae24ee8..b731796f0 100644
--- a/embassy-stm32/src/fmt.rs
+++ b/embassy-stm32/src/fmt.rs
@@ -207,6 +207,16 @@ macro_rules! error {
207} 207}
208 208
209#[cfg(feature = "defmt")] 209#[cfg(feature = "defmt")]
210trait_set::trait_set! {
211 pub trait Debuggable = Debug + defmt::Format;
212}
213
214#[cfg(not(feature = "defmt"))]
215trait_set::trait_set! {
216 pub trait Debuggable = Debug;
217}
218
219#[cfg(feature = "defmt")]
210#[collapse_debuginfo(yes)] 220#[collapse_debuginfo(yes)]
211macro_rules! unwrap { 221macro_rules! unwrap {
212 ($($x:tt)*) => { 222 ($($x:tt)*) => {
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index 5a8d23183..5de8bad2c 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -4,7 +4,7 @@
4use core::convert::Infallible; 4use core::convert::Infallible;
5 5
6use critical_section::CriticalSection; 6use critical_section::CriticalSection;
7use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; 7use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral};
8 8
9use crate::pac::gpio::{self, vals}; 9use crate::pac::gpio::{self, vals};
10use crate::peripherals; 10use crate::peripherals;
@@ -592,7 +592,7 @@ impl AfType {
592 592
593#[inline(never)] 593#[inline(never)]
594#[cfg(gpio_v1)] 594#[cfg(gpio_v1)]
595fn set_as_af(pin_port: u8, af_type: AfType) { 595fn set_as_af(pin_port: PinNumber, af_type: AfType) {
596 let pin = unsafe { AnyPin::steal(pin_port) }; 596 let pin = unsafe { AnyPin::steal(pin_port) };
597 let r = pin.block(); 597 let r = pin.block();
598 let n = pin._pin() as usize; 598 let n = pin._pin() as usize;
@@ -649,7 +649,7 @@ impl AfType {
649 649
650#[inline(never)] 650#[inline(never)]
651#[cfg(gpio_v2)] 651#[cfg(gpio_v2)]
652fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { 652fn set_as_af(pin_port: PinNumber, af_num: u8, af_type: AfType) {
653 let pin = unsafe { AnyPin::steal(pin_port) }; 653 let pin = unsafe { AnyPin::steal(pin_port) };
654 let r = pin.block(); 654 let r = pin.block();
655 let n = pin._pin() as usize; 655 let n = pin._pin() as usize;
@@ -663,7 +663,7 @@ fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) {
663 663
664#[inline(never)] 664#[inline(never)]
665#[cfg(gpio_v2)] 665#[cfg(gpio_v2)]
666fn set_speed(pin_port: u8, speed: Speed) { 666fn set_speed(pin_port: PinNumber, speed: Speed) {
667 let pin = unsafe { AnyPin::steal(pin_port) }; 667 let pin = unsafe { AnyPin::steal(pin_port) };
668 let r = pin.block(); 668 let r = pin.block();
669 let n = pin._pin() as usize; 669 let n = pin._pin() as usize;
@@ -672,7 +672,7 @@ fn set_speed(pin_port: u8, speed: Speed) {
672} 672}
673 673
674#[inline(never)] 674#[inline(never)]
675fn set_as_analog(pin_port: u8) { 675fn set_as_analog(pin_port: PinNumber) {
676 let pin = unsafe { AnyPin::steal(pin_port) }; 676 let pin = unsafe { AnyPin::steal(pin_port) };
677 let r = pin.block(); 677 let r = pin.block();
678 let n = pin._pin() as usize; 678 let n = pin._pin() as usize;
@@ -684,11 +684,15 @@ fn set_as_analog(pin_port: u8) {
684 }); 684 });
685 685
686 #[cfg(gpio_v2)] 686 #[cfg(gpio_v2)]
687 r.moder().modify(|w| w.set_moder(n, vals::Moder::ANALOG)); 687 {
688 #[cfg(any(stm32l47x, stm32l48x))]
689 r.ascr().modify(|w| w.set_asc(n, true));
690 r.moder().modify(|w| w.set_moder(n, vals::Moder::ANALOG));
691 }
688} 692}
689 693
690#[inline(never)] 694#[inline(never)]
691fn get_pull(pin_port: u8) -> Pull { 695fn get_pull(pin_port: PinNumber) -> Pull {
692 let pin = unsafe { AnyPin::steal(pin_port) }; 696 let pin = unsafe { AnyPin::steal(pin_port) };
693 let r = pin.block(); 697 let r = pin.block();
694 let n = pin._pin() as usize; 698 let n = pin._pin() as usize;
@@ -727,15 +731,15 @@ pub struct AfioRemapBool<const V: bool>;
727pub struct AfioRemapNotApplicable; 731pub struct AfioRemapNotApplicable;
728 732
729pub(crate) trait SealedPin { 733pub(crate) trait SealedPin {
730 fn pin_port(&self) -> u8; 734 fn pin_port(&self) -> PinNumber;
731 735
732 #[inline] 736 #[inline]
733 fn _pin(&self) -> u8 { 737 fn _pin(&self) -> PinNumber {
734 self.pin_port() % 16 738 self.pin_port() % 16
735 } 739 }
736 740
737 #[inline] 741 #[inline]
738 fn _port(&self) -> u8 { 742 fn _port(&self) -> PinNumber {
739 self.pin_port() / 16 743 self.pin_port() / 16
740 } 744 }
741 745
@@ -798,31 +802,49 @@ pub(crate) trait SealedPin {
798 } 802 }
799} 803}
800 804
801/// GPIO pin trait. 805/// GPIO pin number type.
806///
807/// Some chips have a total number of ports that exceeds 8, a larger integer
808/// is needed to hold the total pin number `(ports * number)`.
809#[cfg(not(stm32n6))]
810pub type PinNumber = u8;
811
812/// GPIO pin number type.
813///
814/// Some chips have a total number of ports that exceeds 8, a larger integer
815/// is needed to hold the total pin number `(ports * number)`.
816#[cfg(stm32n6)]
817pub type PinNumber = u16;
818
819/// Pin that can be used to configure an [ExtiInput](crate::exti::ExtiInput). This trait is lost when converting to [AnyPin].
820#[cfg(feature = "exti")]
802#[allow(private_bounds)] 821#[allow(private_bounds)]
803pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static { 822pub trait ExtiPin: PeripheralType + SealedPin {
804 /// EXTI channel assigned to this pin. 823 /// EXTI channel assigned to this pin.
805 /// 824 ///
806 /// For example, PC4 uses EXTI4. 825 /// For example, PC4 uses EXTI4.
807 #[cfg(feature = "exti")]
808 type ExtiChannel: crate::exti::Channel; 826 type ExtiChannel: crate::exti::Channel;
827}
809 828
829/// GPIO pin trait.
830#[allow(private_bounds)]
831pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
810 /// Number of the pin within the port (0..31) 832 /// Number of the pin within the port (0..31)
811 #[inline] 833 #[inline]
812 fn pin(&self) -> u8 { 834 fn pin(&self) -> PinNumber {
813 self._pin() 835 self._pin()
814 } 836 }
815 837
816 /// Port of the pin 838 /// Port of the pin
817 #[inline] 839 #[inline]
818 fn port(&self) -> u8 { 840 fn port(&self) -> PinNumber {
819 self._port() 841 self._port()
820 } 842 }
821} 843}
822 844
823/// Type-erased GPIO pin 845/// Type-erased GPIO pin.
824pub struct AnyPin { 846pub struct AnyPin {
825 pin_port: u8, 847 pin_port: PinNumber,
826} 848}
827 849
828impl AnyPin { 850impl AnyPin {
@@ -830,12 +852,12 @@ impl AnyPin {
830 /// 852 ///
831 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... 853 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
832 #[inline] 854 #[inline]
833 pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> { 855 pub unsafe fn steal(pin_port: PinNumber) -> Peri<'static, Self> {
834 Peri::new_unchecked(Self { pin_port }) 856 Peri::new_unchecked(Self { pin_port })
835 } 857 }
836 858
837 #[inline] 859 #[inline]
838 fn _port(&self) -> u8 { 860 fn _port(&self) -> PinNumber {
839 self.pin_port / 16 861 self.pin_port / 16
840 } 862 }
841 863
@@ -848,13 +870,10 @@ impl AnyPin {
848} 870}
849 871
850impl_peripheral!(AnyPin); 872impl_peripheral!(AnyPin);
851impl Pin for AnyPin { 873impl Pin for AnyPin {}
852 #[cfg(feature = "exti")]
853 type ExtiChannel = crate::exti::AnyChannel;
854}
855impl SealedPin for AnyPin { 874impl SealedPin for AnyPin {
856 #[inline] 875 #[inline]
857 fn pin_port(&self) -> u8 { 876 fn pin_port(&self) -> PinNumber {
858 self.pin_port 877 self.pin_port
859 } 878 }
860} 879}
@@ -864,12 +883,14 @@ impl SealedPin for AnyPin {
864foreach_pin!( 883foreach_pin!(
865 ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => { 884 ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => {
866 impl Pin for peripherals::$pin_name { 885 impl Pin for peripherals::$pin_name {
867 #[cfg(feature = "exti")] 886 }
887 #[cfg(feature = "exti")]
888 impl ExtiPin for peripherals::$pin_name {
868 type ExtiChannel = peripherals::$exti_ch; 889 type ExtiChannel = peripherals::$exti_ch;
869 } 890 }
870 impl SealedPin for peripherals::$pin_name { 891 impl SealedPin for peripherals::$pin_name {
871 #[inline] 892 #[inline]
872 fn pin_port(&self) -> u8 { 893 fn pin_port(&self) -> PinNumber {
873 $port_num * 16 + $pin_num 894 $port_num * 16 + $pin_num
874 } 895 }
875 } 896 }
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs
index 90c06c0d8..ba573267c 100644
--- a/embassy-stm32/src/hash/mod.rs
+++ b/embassy-stm32/src/hash/mod.rs
@@ -19,7 +19,7 @@ use crate::interrupt::typelevel::Interrupt;
19use crate::mode::Async; 19use crate::mode::Async;
20use crate::mode::{Blocking, Mode}; 20use crate::mode::{Blocking, Mode};
21use crate::peripherals::HASH; 21use crate::peripherals::HASH;
22use crate::{interrupt, pac, peripherals, rcc, Peri}; 22use crate::{Peri, interrupt, pac, peripherals, rcc};
23 23
24#[cfg(hash_v1)] 24#[cfg(hash_v1)]
25const NUM_CONTEXT_REGS: usize = 51; 25const NUM_CONTEXT_REGS: usize = 51;
@@ -514,11 +514,7 @@ impl<'d, T: Instance> Hash<'d, T, Async> {
514 T::regs().imr().modify(|reg| reg.set_dcie(true)); 514 T::regs().imr().modify(|reg| reg.set_dcie(true));
515 // Check for completion. 515 // Check for completion.
516 let bits = T::regs().sr().read(); 516 let bits = T::regs().sr().read();
517 if bits.dcis() { 517 if bits.dcis() { Poll::Ready(()) } else { Poll::Pending }
518 Poll::Ready(())
519 } else {
520 Poll::Pending
521 }
522 }) 518 })
523 .await; 519 .await;
524 520
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 6fece5eb2..6c6807479 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -10,6 +10,7 @@ pub use traits::Instance;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::rcc; 11use crate::rcc;
12use crate::time::Hertz; 12use crate::time::Hertz;
13pub use crate::timer::simple_pwm::PwmPinConfig;
13 14
14/// HRTIM burst controller instance. 15/// HRTIM burst controller instance.
15pub struct BurstController<T: Instance> { 16pub struct BurstController<T: Instance> {
@@ -73,7 +74,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
73} 74}
74 75
75macro_rules! advanced_channel_impl { 76macro_rules! advanced_channel_impl {
76 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 77 ($new_chx:ident, $new_chx_with_config:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
77 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> { 78 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
78 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 79 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
79 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { 80 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
@@ -86,6 +87,21 @@ macro_rules! advanced_channel_impl {
86 phantom: PhantomData, 87 phantom: PhantomData,
87 } 88 }
88 } 89 }
90
91 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with a specific configuration.")]
92 pub fn $new_chx_with_config(
93 pin: Peri<'d, impl $pin_trait<T>>,
94 pin_config: PwmPinConfig,
95 ) -> Self {
96 critical_section::with(|_| {
97 pin.set_low();
98 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
99 });
100 PwmPin {
101 _pin: pin.into(),
102 phantom: PhantomData,
103 }
104 }
89 } 105 }
90 106
91 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> { 107 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
@@ -100,6 +116,21 @@ macro_rules! advanced_channel_impl {
100 phantom: PhantomData, 116 phantom: PhantomData,
101 } 117 }
102 } 118 }
119
120 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance with a specific configuration.")]
121 pub fn $new_chx_with_config(
122 pin: Peri<'d, impl $complementary_pin_trait<T>>,
123 pin_config: PwmPinConfig,
124 ) -> Self {
125 critical_section::with(|_| {
126 pin.set_low();
127 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
128 });
129 ComplementaryPwmPin {
130 _pin: pin.into(),
131 phantom: PhantomData,
132 }
133 }
103 } 134 }
104 135
105 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> { 136 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> {
@@ -111,13 +142,55 @@ macro_rules! advanced_channel_impl {
111 }; 142 };
112} 143}
113 144
114advanced_channel_impl!(new_cha, ChA, 0, ChannelAPin, ChannelAComplementaryPin); 145advanced_channel_impl!(
115advanced_channel_impl!(new_chb, ChB, 1, ChannelBPin, ChannelBComplementaryPin); 146 new_cha,
116advanced_channel_impl!(new_chc, ChC, 2, ChannelCPin, ChannelCComplementaryPin); 147 new_cha_with_config,
117advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); 148 ChA,
118advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); 149 0,
150 ChannelAPin,
151 ChannelAComplementaryPin
152);
153advanced_channel_impl!(
154 new_chb,
155 new_chb_with_config,
156 ChB,
157 1,
158 ChannelBPin,
159 ChannelBComplementaryPin
160);
161advanced_channel_impl!(
162 new_chc,
163 new_chc_with_config,
164 ChC,
165 2,
166 ChannelCPin,
167 ChannelCComplementaryPin
168);
169advanced_channel_impl!(
170 new_chd,
171 new_chd_with_config,
172 ChD,
173 3,
174 ChannelDPin,
175 ChannelDComplementaryPin
176);
177advanced_channel_impl!(
178 new_che,
179 new_che_with_config,
180 ChE,
181 4,
182 ChannelEPin,
183 ChannelEComplementaryPin
184);
119#[cfg(hrtim_v2)] 185#[cfg(hrtim_v2)]
120advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); 186advanced_channel_impl!(
187 new_chf,
188 new_chf_with_config,
189 ChF,
190 5,
191 ChannelFPin,
192 ChannelFComplementaryPin
193);
121 194
122/// Struct used to divide a high resolution timer into multiple channels 195/// Struct used to divide a high resolution timer into multiple channels
123pub struct AdvancedPwm<'d, T: Instance> { 196pub struct AdvancedPwm<'d, T: Instance> {
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index 573a1851d..b5fa3c897 100644
--- a/embassy-stm32/src/hsem/mod.rs
+++ b/embassy-stm32/src/hsem/mod.rs
@@ -1,14 +1,22 @@
1//! Hardware Semaphore (HSEM) 1//! Hardware Semaphore (HSEM)
2 2
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::sync::atomic::{Ordering, compiler_fence};
6use core::task::Poll;
7
8#[cfg(all(stm32wb, feature = "low-power"))]
9use critical_section::CriticalSection;
3use embassy_hal_internal::PeripheralType; 10use embassy_hal_internal::PeripheralType;
11use embassy_sync::waitqueue::AtomicWaker;
4 12
5use crate::pac;
6use crate::rcc::{self, RccPeripheral};
7// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. 13// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs.
8// Those MCUs have a different HSEM implementation (Secure semaphore lock support, 14// Those MCUs have a different HSEM implementation (Secure semaphore lock support,
9// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), 15// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute),
10// which is not yet supported by this code. 16// which is not yet supported by this code.
11use crate::Peri; 17use crate::Peri;
18use crate::rcc::{self, RccPeripheral};
19use crate::{interrupt, pac};
12 20
13/// HSEM error. 21/// HSEM error.
14#[derive(Debug)] 22#[derive(Debug)]
@@ -41,63 +49,153 @@ pub enum CoreId {
41 Core1 = 0x8, 49 Core1 = 0x8,
42} 50}
43 51
44/// Get the current core id 52impl CoreId {
45/// This code assume that it is only executed on a Cortex-M M0+, M4 or M7 core. 53 /// Get the current core id
46#[inline(always)] 54 /// This code assume that it is only executed on a Cortex-M M0+, M4 or M7 core.
47pub fn get_current_coreid() -> CoreId { 55 pub fn current() -> Self {
48 let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() }; 56 let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() };
49 match (cpuid & 0x000000F0) >> 4 { 57 match (cpuid & 0x000000F0) >> 4 {
50 #[cfg(any(stm32wb, stm32wl))] 58 #[cfg(any(stm32wb, stm32wl))]
51 0x0 => CoreId::Core1, 59 0x0 => CoreId::Core1,
52 60
53 #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))] 61 #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))]
54 0x4 => CoreId::Core0, 62 0x4 => CoreId::Core0,
55 63
56 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] 64 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
57 0x4 => CoreId::Core1, 65 0x4 => CoreId::Core1,
58 66
59 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] 67 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
60 0x7 => CoreId::Core0, 68 0x7 => CoreId::Core0,
61 _ => panic!("Unknown Cortex-M core"), 69 _ => panic!("Unknown Cortex-M core"),
70 }
71 }
72
73 /// Translates the core ID to an index into the interrupt registers.
74 pub fn to_index(&self) -> usize {
75 match &self {
76 CoreId::Core0 => 0,
77 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))]
78 CoreId::Core1 => 1,
79 }
62 } 80 }
63} 81}
64 82
65/// Translates the core ID to an index into the interrupt registers. 83#[cfg(not(all(stm32wb, feature = "low-power")))]
66#[inline(always)] 84const PUB_CHANNELS: usize = 6;
67fn core_id_to_index(core: CoreId) -> usize { 85
68 match core { 86#[cfg(all(stm32wb, feature = "low-power"))]
69 CoreId::Core0 => 0, 87const PUB_CHANNELS: usize = 4;
70 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))] 88
71 CoreId::Core1 => 1, 89/// TX interrupt handler.
90pub struct HardwareSemaphoreInterruptHandler<T: Instance> {
91 _phantom: PhantomData<T>,
92}
93
94impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for HardwareSemaphoreInterruptHandler<T> {
95 unsafe fn on_interrupt() {
96 let core_id = CoreId::current();
97
98 for number in 0..5 {
99 if T::regs().isr(core_id.to_index()).read().isf(number as usize) {
100 T::regs()
101 .icr(core_id.to_index())
102 .write(|w| w.set_isc(number as usize, true));
103
104 T::regs()
105 .ier(core_id.to_index())
106 .modify(|w| w.set_ise(number as usize, false));
107
108 T::state().waker_for(number).wake();
109 }
110 }
72 } 111 }
73} 112}
74 113
75/// HSEM driver 114/// Hardware semaphore mutex
76pub struct HardwareSemaphore<'d, T: Instance> { 115pub struct HardwareSemaphoreMutex<'a, T: Instance> {
77 _peri: Peri<'d, T>, 116 index: u8,
117 process_id: u8,
118 _lifetime: PhantomData<&'a mut T>,
78} 119}
79 120
80impl<'d, T: Instance> HardwareSemaphore<'d, T> { 121impl<'a, T: Instance> Drop for HardwareSemaphoreMutex<'a, T> {
81 /// Creates a new HardwareSemaphore instance. 122 fn drop(&mut self) {
82 pub fn new(peripheral: Peri<'d, T>) -> Self { 123 HardwareSemaphoreChannel::<'a, T> {
83 rcc::enable_and_reset::<T>(); 124 index: self.index,
125 _lifetime: PhantomData,
126 }
127 .unlock(self.process_id);
128 }
129}
130
131/// Hardware semaphore channel
132pub struct HardwareSemaphoreChannel<'a, T: Instance> {
133 index: u8,
134 _lifetime: PhantomData<&'a mut T>,
135}
136
137impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> {
138 pub(crate) const fn new(number: u8) -> Self {
139 core::assert!(number > 0 && number <= 6);
140
141 Self {
142 index: number - 1,
143 _lifetime: PhantomData,
144 }
145 }
146
147 /// Locks the semaphore.
148 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
149 /// check if the lock has been successful, carried out from the HSEM_Rx register.
150 pub async fn lock(&mut self, process_id: u8) -> HardwareSemaphoreMutex<'a, T> {
151 let _scoped_block_stop = T::RCC_INFO.block_stop();
152 let core_id = CoreId::current();
153
154 poll_fn(|cx| {
155 T::state().waker_for(self.index).register(cx.waker());
156
157 compiler_fence(Ordering::SeqCst);
158
159 T::regs()
160 .ier(core_id.to_index())
161 .modify(|w| w.set_ise(self.index as usize, true));
84 162
85 HardwareSemaphore { _peri: peripheral } 163 match self.try_lock(process_id) {
164 Some(mutex) => Poll::Ready(mutex),
165 None => Poll::Pending,
166 }
167 })
168 .await
169 }
170
171 /// Try to lock the semaphor
172 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
173 /// check if the lock has been successful, carried out from the HSEM_Rx register.
174 pub fn try_lock(&mut self, process_id: u8) -> Option<HardwareSemaphoreMutex<'a, T>> {
175 if self.two_step_lock(process_id).is_ok() {
176 Some(HardwareSemaphoreMutex {
177 index: self.index,
178 process_id: process_id,
179 _lifetime: PhantomData,
180 })
181 } else {
182 None
183 }
86 } 184 }
87 185
88 /// Locks the semaphore. 186 /// Locks the semaphore.
89 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to 187 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
90 /// check if the lock has been successful, carried out from the HSEM_Rx register. 188 /// check if the lock has been successful, carried out from the HSEM_Rx register.
91 pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemError> { 189 pub fn two_step_lock(&mut self, process_id: u8) -> Result<(), HsemError> {
92 T::regs().r(sem_id as usize).write(|w| { 190 T::regs().r(self.index as usize).write(|w| {
93 w.set_procid(process_id); 191 w.set_procid(process_id);
94 w.set_coreid(get_current_coreid() as u8); 192 w.set_coreid(CoreId::current() as u8);
95 w.set_lock(true); 193 w.set_lock(true);
96 }); 194 });
97 let reg = T::regs().r(sem_id as usize).read(); 195 let reg = T::regs().r(self.index as usize).read();
98 match ( 196 match (
99 reg.lock(), 197 reg.lock(),
100 reg.coreid() == get_current_coreid() as u8, 198 reg.coreid() == CoreId::current() as u8,
101 reg.procid() == process_id, 199 reg.procid() == process_id,
102 ) { 200 ) {
103 (true, true, true) => Ok(()), 201 (true, true, true) => Ok(()),
@@ -108,9 +206,9 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
108 /// Locks the semaphore. 206 /// Locks the semaphore.
109 /// The 1-step procedure consists in a read to lock and check the semaphore in a single step, 207 /// The 1-step procedure consists in a read to lock and check the semaphore in a single step,
110 /// carried out from the HSEM_RLRx register. 208 /// carried out from the HSEM_RLRx register.
111 pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemError> { 209 pub fn one_step_lock(&mut self) -> Result<(), HsemError> {
112 let reg = T::regs().rlr(sem_id as usize).read(); 210 let reg = T::regs().rlr(self.index as usize).read();
113 match (reg.lock(), reg.coreid() == get_current_coreid() as u8, reg.procid()) { 211 match (reg.lock(), reg.coreid() == CoreId::current() as u8, reg.procid()) {
114 (false, true, 0) => Ok(()), 212 (false, true, 0) => Ok(()),
115 _ => Err(HsemError::LockFailed), 213 _ => Err(HsemError::LockFailed),
116 } 214 }
@@ -119,14 +217,60 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
119 /// Unlocks the semaphore. 217 /// Unlocks the semaphore.
120 /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus 218 /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus
121 /// core ID or by a process not having the semaphore lock right. 219 /// core ID or by a process not having the semaphore lock right.
122 pub fn unlock(&mut self, sem_id: u8, process_id: u8) { 220 pub fn unlock(&mut self, process_id: u8) {
123 T::regs().r(sem_id as usize).write(|w| { 221 T::regs().r(self.index as usize).write(|w| {
124 w.set_procid(process_id); 222 w.set_procid(process_id);
125 w.set_coreid(get_current_coreid() as u8); 223 w.set_coreid(CoreId::current() as u8);
126 w.set_lock(false); 224 w.set_lock(false);
127 }); 225 });
128 } 226 }
129 227
228 /// Return the channel number
229 pub const fn channel(&self) -> u8 {
230 self.index + 1
231 }
232}
233
234/// HSEM driver
235pub struct HardwareSemaphore<T: Instance> {
236 _type: PhantomData<T>,
237}
238
239impl<T: Instance> HardwareSemaphore<T> {
240 /// Creates a new HardwareSemaphore instance.
241 pub fn new<'d>(
242 _peripheral: Peri<'d, T>,
243 _irq: impl interrupt::typelevel::Binding<T::Interrupt, HardwareSemaphoreInterruptHandler<T>> + 'd,
244 ) -> Self {
245 rcc::enable_and_reset_without_stop::<T>();
246
247 HardwareSemaphore { _type: PhantomData }
248 }
249
250 /// Get a single channel, and keep the global struct
251 pub const fn channel_for<'a>(&'a mut self, number: u8) -> HardwareSemaphoreChannel<'a, T> {
252 #[cfg(all(stm32wb, feature = "low-power"))]
253 core::assert!(number != 3 && number != 4);
254
255 HardwareSemaphoreChannel::new(number)
256 }
257
258 /// Split the global struct into channels
259 ///
260 /// If using low-power mode, channels 3 and 4 will not be returned
261 pub const fn split<'a>(self) -> [HardwareSemaphoreChannel<'a, T>; PUB_CHANNELS] {
262 [
263 HardwareSemaphoreChannel::new(1),
264 HardwareSemaphoreChannel::new(2),
265 #[cfg(not(all(stm32wb, feature = "low-power")))]
266 HardwareSemaphoreChannel::new(3),
267 #[cfg(not(all(stm32wb, feature = "low-power")))]
268 HardwareSemaphoreChannel::new(4),
269 HardwareSemaphoreChannel::new(5),
270 HardwareSemaphoreChannel::new(6),
271 ]
272 }
273
130 /// Unlocks all semaphores. 274 /// Unlocks all semaphores.
131 /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR 275 /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR
132 /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a 276 /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a
@@ -138,11 +282,6 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
138 }); 282 });
139 } 283 }
140 284
141 /// Checks if the semaphore is locked.
142 pub fn is_semaphore_locked(&self, sem_id: u8) -> bool {
143 T::regs().r(sem_id as usize).read().lock()
144 }
145
146 /// Sets the clear (unlock) key 285 /// Sets the clear (unlock) key
147 pub fn set_clear_key(&mut self, key: u16) { 286 pub fn set_clear_key(&mut self, key: u16) {
148 T::regs().keyr().modify(|w| w.set_key(key)); 287 T::regs().keyr().modify(|w| w.set_key(key));
@@ -152,38 +291,61 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
152 pub fn get_clear_key(&mut self) -> u16 { 291 pub fn get_clear_key(&mut self) -> u16 {
153 T::regs().keyr().read().key() 292 T::regs().keyr().read().key()
154 } 293 }
294}
155 295
156 /// Sets the interrupt enable bit for the semaphore. 296#[cfg(all(stm32wb, feature = "low-power"))]
157 pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) { 297pub(crate) fn init_hsem(cs: CriticalSection) {
158 T::regs() 298 rcc::enable_and_reset_with_cs::<crate::peripherals::HSEM>(cs);
159 .ier(core_id_to_index(core_id)) 299
160 .modify(|w| w.set_ise(sem_x, enable)); 300 unsafe {
301 crate::rcc::REFCOUNT_STOP1 = 0;
302 crate::rcc::REFCOUNT_STOP2 = 0;
161 } 303 }
304}
162 305
163 /// Gets the interrupt flag for the semaphore. 306struct State {
164 pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool { 307 wakers: [AtomicWaker; 6],
165 T::regs().isr(core_id_to_index(core_id)).read().isf(sem_x) 308}
309
310impl State {
311 const fn new() -> Self {
312 Self {
313 wakers: [const { AtomicWaker::new() }; 6],
314 }
166 } 315 }
167 316
168 /// Clears the interrupt flag for the semaphore. 317 const fn waker_for(&self, index: u8) -> &AtomicWaker {
169 pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) { 318 &self.wakers[index as usize]
170 T::regs()
171 .icr(core_id_to_index(core_id))
172 .write(|w| w.set_isc(sem_x, false));
173 } 319 }
174} 320}
175 321
176trait SealedInstance { 322trait SealedInstance {
177 fn regs() -> pac::hsem::Hsem; 323 fn regs() -> pac::hsem::Hsem;
324 fn state() -> &'static State;
178} 325}
179 326
180/// HSEM instance trait. 327/// HSEM instance trait.
181#[allow(private_bounds)] 328#[allow(private_bounds)]
182pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {} 329pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {
330 /// Interrupt for this peripheral.
331 type Interrupt: interrupt::typelevel::Interrupt;
332}
183 333
184impl SealedInstance for crate::peripherals::HSEM { 334impl SealedInstance for crate::peripherals::HSEM {
185 fn regs() -> crate::pac::hsem::Hsem { 335 fn regs() -> crate::pac::hsem::Hsem {
186 crate::pac::HSEM 336 crate::pac::HSEM
187 } 337 }
338
339 fn state() -> &'static State {
340 static STATE: State = State::new();
341 &STATE
342 }
188} 343}
189impl Instance for crate::peripherals::HSEM {} 344
345foreach_interrupt!(
346 ($inst:ident, hsem, $block:ident, $signal_name:ident, $irq:ident) => {
347 impl Instance for crate::peripherals::$inst {
348 type Interrupt = crate::interrupt::typelevel::$irq;
349 }
350 };
351);
diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs
index 95d9e5099..1d3560678 100644
--- a/embassy-stm32/src/hspi/mod.rs
+++ b/embassy-stm32/src/hspi/mod.rs
@@ -16,7 +16,7 @@ use embassy_embedded_hal::{GetConfig, SetConfig};
16use embassy_hal_internal::{Peri, PeripheralType}; 16use embassy_hal_internal::{Peri, PeripheralType};
17pub use enums::*; 17pub use enums::*;
18 18
19use crate::dma::{word, ChannelAndRequest}; 19use crate::dma::{ChannelAndRequest, word};
20use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 20use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
21use crate::mode::{Async, Blocking, Mode as PeriMode}; 21use crate::mode::{Async, Blocking, Mode as PeriMode};
22use crate::pac::hspi::Hspi as Regs; 22use crate::pac::hspi::Hspi as Regs;
@@ -391,7 +391,7 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
391 while T::REGS.sr().read().busy() {} 391 while T::REGS.sr().read().busy() {}
392 392
393 T::REGS.cr().modify(|w| { 393 T::REGS.cr().modify(|w| {
394 w.set_fmode(0.into()); 394 w.set_fmode(FunctionalMode::IndirectWrite.into());
395 }); 395 });
396 396
397 // Configure alternate bytes 397 // Configure alternate bytes
@@ -498,7 +498,8 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
498 w.set_dmaen(false); 498 w.set_dmaen(false);
499 }); 499 });
500 500
501 self.configure_command(&transaction, Some(buf.len()))?; 501 let transfer_size_bytes = buf.len() * W::size().bytes();
502 self.configure_command(&transaction, Some(transfer_size_bytes))?;
502 503
503 let current_address = T::REGS.ar().read().address(); 504 let current_address = T::REGS.ar().read().address();
504 let current_instruction = T::REGS.ir().read().instruction(); 505 let current_instruction = T::REGS.ir().read().instruction();
@@ -537,7 +538,8 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
537 w.set_dmaen(false); 538 w.set_dmaen(false);
538 }); 539 });
539 540
540 self.configure_command(&transaction, Some(buf.len()))?; 541 let transfer_size_bytes = buf.len() * W::size().bytes();
542 self.configure_command(&transaction, Some(transfer_size_bytes))?;
541 543
542 T::REGS 544 T::REGS
543 .cr() 545 .cr()
@@ -767,7 +769,8 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
767 // Wait for peripheral to be free 769 // Wait for peripheral to be free
768 while T::REGS.sr().read().busy() {} 770 while T::REGS.sr().read().busy() {}
769 771
770 self.configure_command(&transaction, Some(buf.len()))?; 772 let transfer_size_bytes = buf.len() * W::size().bytes();
773 self.configure_command(&transaction, Some(transfer_size_bytes))?;
771 774
772 let current_address = T::REGS.ar().read().address(); 775 let current_address = T::REGS.ar().read().address();
773 let current_instruction = T::REGS.ir().read().instruction(); 776 let current_instruction = T::REGS.ir().read().instruction();
@@ -782,16 +785,18 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
782 T::REGS.ar().write(|v| v.set_address(current_address)); 785 T::REGS.ar().write(|v| v.set_address(current_address));
783 } 786 }
784 787
785 let transfer = unsafe { 788 for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
786 self.dma 789 let transfer = unsafe {
787 .as_mut() 790 self.dma
788 .unwrap() 791 .as_mut()
789 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) 792 .unwrap()
790 }; 793 .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
794 };
791 795
792 T::REGS.cr().modify(|w| w.set_dmaen(true)); 796 T::REGS.cr().modify(|w| w.set_dmaen(true));
793 797
794 transfer.blocking_wait(); 798 transfer.blocking_wait();
799 }
795 800
796 finish_dma(T::REGS); 801 finish_dma(T::REGS);
797 802
@@ -807,21 +812,24 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
807 // Wait for peripheral to be free 812 // Wait for peripheral to be free
808 while T::REGS.sr().read().busy() {} 813 while T::REGS.sr().read().busy() {}
809 814
810 self.configure_command(&transaction, Some(buf.len()))?; 815 let transfer_size_bytes = buf.len() * W::size().bytes();
816 self.configure_command(&transaction, Some(transfer_size_bytes))?;
811 T::REGS 817 T::REGS
812 .cr() 818 .cr()
813 .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); 819 .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into()));
814 820
815 let transfer = unsafe { 821 for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
816 self.dma 822 let transfer = unsafe {
817 .as_mut() 823 self.dma
818 .unwrap() 824 .as_mut()
819 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) 825 .unwrap()
820 }; 826 .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
827 };
821 828
822 T::REGS.cr().modify(|w| w.set_dmaen(true)); 829 T::REGS.cr().modify(|w| w.set_dmaen(true));
823 830
824 transfer.blocking_wait(); 831 transfer.blocking_wait();
832 }
825 833
826 finish_dma(T::REGS); 834 finish_dma(T::REGS);
827 835
@@ -837,7 +845,8 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
837 // Wait for peripheral to be free 845 // Wait for peripheral to be free
838 while T::REGS.sr().read().busy() {} 846 while T::REGS.sr().read().busy() {}
839 847
840 self.configure_command(&transaction, Some(buf.len()))?; 848 let transfer_size_bytes = buf.len() * W::size().bytes();
849 self.configure_command(&transaction, Some(transfer_size_bytes))?;
841 850
842 let current_address = T::REGS.ar().read().address(); 851 let current_address = T::REGS.ar().read().address();
843 let current_instruction = T::REGS.ir().read().instruction(); 852 let current_instruction = T::REGS.ir().read().instruction();
@@ -852,16 +861,18 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
852 T::REGS.ar().write(|v| v.set_address(current_address)); 861 T::REGS.ar().write(|v| v.set_address(current_address));
853 } 862 }
854 863
855 let transfer = unsafe { 864 for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
856 self.dma 865 let transfer = unsafe {
857 .as_mut() 866 self.dma
858 .unwrap() 867 .as_mut()
859 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) 868 .unwrap()
860 }; 869 .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
870 };
861 871
862 T::REGS.cr().modify(|w| w.set_dmaen(true)); 872 T::REGS.cr().modify(|w| w.set_dmaen(true));
863 873
864 transfer.await; 874 transfer.await;
875 }
865 876
866 finish_dma(T::REGS); 877 finish_dma(T::REGS);
867 878
@@ -877,21 +888,25 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
877 // Wait for peripheral to be free 888 // Wait for peripheral to be free
878 while T::REGS.sr().read().busy() {} 889 while T::REGS.sr().read().busy() {}
879 890
880 self.configure_command(&transaction, Some(buf.len()))?; 891 let transfer_size_bytes = buf.len() * W::size().bytes();
892 self.configure_command(&transaction, Some(transfer_size_bytes))?;
881 T::REGS 893 T::REGS
882 .cr() 894 .cr()
883 .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); 895 .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into()));
884 896
885 let transfer = unsafe { 897 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
886 self.dma 898 for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
887 .as_mut() 899 let transfer = unsafe {
888 .unwrap() 900 self.dma
889 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) 901 .as_mut()
890 }; 902 .unwrap()
903 .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
904 };
891 905
892 T::REGS.cr().modify(|w| w.set_dmaen(true)); 906 T::REGS.cr().modify(|w| w.set_dmaen(true));
893 907
894 transfer.await; 908 transfer.await;
909 }
895 910
896 finish_dma(T::REGS); 911 finish_dma(T::REGS);
897 912
diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs
index 4e3b736c7..74fac14b2 100644
--- a/embassy-stm32/src/i2c/config.rs
+++ b/embassy-stm32/src/i2c/config.rs
@@ -4,7 +4,7 @@ use crate::gpio::{AfType, OutputType, Speed};
4use crate::time::Hertz; 4use crate::time::Hertz;
5 5
6#[repr(u8)] 6#[repr(u8)]
7#[derive(Copy, Clone)] 7#[derive(Debug, Copy, Clone)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))] 8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9/// Bits of the I2C OA2 register to mask out. 9/// Bits of the I2C OA2 register to mask out.
10pub enum AddrMask { 10pub enum AddrMask {
@@ -60,7 +60,7 @@ impl Address {
60 } 60 }
61} 61}
62 62
63#[derive(Copy, Clone)] 63#[derive(Debug, Copy, Clone)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))] 64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65/// The second Own Address register. 65/// The second Own Address register.
66pub struct OA2 { 66pub struct OA2 {
@@ -70,7 +70,7 @@ pub struct OA2 {
70 pub mask: AddrMask, 70 pub mask: AddrMask,
71} 71}
72 72
73#[derive(Copy, Clone)] 73#[derive(Debug, Copy, Clone)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))] 74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75/// The Own Address(es) of the I2C peripheral. 75/// The Own Address(es) of the I2C peripheral.
76pub enum OwnAddresses { 76pub enum OwnAddresses {
@@ -88,7 +88,7 @@ pub enum OwnAddresses {
88} 88}
89 89
90/// Slave Configuration 90/// Slave Configuration
91#[derive(Copy, Clone)] 91#[derive(Debug, Copy, Clone)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))] 92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93pub struct SlaveAddrConfig { 93pub struct SlaveAddrConfig {
94 /// Target Address(es) 94 /// Target Address(es)
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 249bac41c..0aa2d1da9 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -129,7 +129,7 @@ impl<'d> Drop for I2CDropGuard<'d> {
129 x.set_as_disconnected() 129 x.set_as_disconnected()
130 } 130 }
131 131
132 self.info.rcc.disable(); 132 self.info.rcc.disable_without_stop();
133 } 133 }
134} 134}
135 135
@@ -154,8 +154,8 @@ impl<'d> I2c<'d, Async, Master> {
154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>, 154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>, 155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> 156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> 157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
158 + 'd, 158 + 'd,
159 tx_dma: Peri<'d, impl TxDma<T>>, 159 tx_dma: Peri<'d, impl TxDma<T>>,
160 rx_dma: Peri<'d, impl RxDma<T>>, 160 rx_dma: Peri<'d, impl RxDma<T>>,
161 config: Config, 161 config: Config,
@@ -219,13 +219,14 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
219 sda, 219 sda,
220 }, 220 },
221 }; 221 };
222
222 this.enable_and_init(config); 223 this.enable_and_init(config);
223 224
224 this 225 this
225 } 226 }
226 227
227 fn enable_and_init(&mut self, config: Config) { 228 fn enable_and_init(&mut self, config: Config) {
228 self.info.rcc.enable_and_reset(); 229 self.info.rcc.enable_and_reset_without_stop();
229 self.init(config); 230 self.init(config);
230 } 231 }
231} 232}
@@ -437,15 +438,15 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> {
437 438
438/// Frame type in I2C transaction. 439/// Frame type in I2C transaction.
439/// 440///
440/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST 441/// This tells each method what kind of frame to use, to generate a (repeated) start condition (ST
441/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an 442/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
442/// ACK or NACK after the last byte received. 443/// ACK or NACK after the last byte received.
443/// 444///
444/// For write operations, the following options are identical because they differ only in the (N)ACK 445/// For write operations, the following options are identical because they differ only in the (N)ACK
445/// treatment relevant for read operations: 446/// treatment relevant for read operations:
446/// 447///
447/// - `FirstFrame` and `FirstAndNextFrame` 448/// - `FirstFrame` and `FirstAndNextFrame` behave identically for writes
448/// - `NextFrame` and `LastFrameNoStop` 449/// - `NextFrame` and `LastFrameNoStop` behave identically for writes
449/// 450///
450/// Abbreviations used below: 451/// Abbreviations used below:
451/// 452///
@@ -474,7 +475,7 @@ enum FrameOptions {
474 475
475#[allow(dead_code)] 476#[allow(dead_code)]
476impl FrameOptions { 477impl FrameOptions {
477 /// Sends start or repeated start condition before transfer. 478 /// Returns true if a start or repeated start condition should be generated before this operation.
478 fn send_start(self) -> bool { 479 fn send_start(self) -> bool {
479 match self { 480 match self {
480 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, 481 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
@@ -482,7 +483,7 @@ impl FrameOptions {
482 } 483 }
483 } 484 }
484 485
485 /// Sends stop condition after transfer. 486 /// Returns true if a stop condition should be generated after this operation.
486 fn send_stop(self) -> bool { 487 fn send_stop(self) -> bool {
487 match self { 488 match self {
488 Self::FirstAndLastFrame | Self::LastFrame => true, 489 Self::FirstAndLastFrame | Self::LastFrame => true,
@@ -490,7 +491,10 @@ impl FrameOptions {
490 } 491 }
491 } 492 }
492 493
493 /// Sends NACK after last byte received, indicating end of read operation. 494 /// Returns true if NACK should be sent after the last byte received in a read operation.
495 ///
496 /// This signals the end of a read sequence and releases the bus for the master's
497 /// next transmission (or stop condition).
494 fn send_nack(self) -> bool { 498 fn send_nack(self) -> bool {
495 match self { 499 match self {
496 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, 500 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
@@ -499,24 +503,44 @@ impl FrameOptions {
499 } 503 }
500} 504}
501 505
502/// Iterates over operations in transaction. 506/// Analyzes I2C transaction operations and assigns appropriate frame to each.
507///
508/// This function processes a sequence of I2C operations and determines the correct
509/// frame configuration for each operation to ensure proper I2C protocol compliance.
510/// It handles the complex logic of:
511///
512/// - Generating start conditions for the first operation of each type (read/write)
513/// - Generating stop conditions for the final operation in the entire transaction
514/// - Managing ACK/NACK behavior for read operations, including merging consecutive reads
515/// - Ensuring proper bus handoff between different operation types
516///
517/// **Transaction Contract Compliance:**
518/// The frame assignments ensure compliance with the embedded-hal I2C transaction contract,
519/// where consecutive operations of the same type are logically merged while maintaining
520/// proper protocol boundaries.
503/// 521///
504/// Returns necessary frame options for each operation to uphold the [transaction contract] and have 522/// **Error Handling:**
505/// the right start/stop/(N)ACK conditions on the wire. 523/// Returns an error if any read operation has an empty buffer, as this would create
524/// an invalid I2C transaction that could halt mid-execution.
525///
526/// # Arguments
527/// * `operations` - Mutable slice of I2C operations from embedded-hal
528///
529/// # Returns
530/// An iterator over (operation, frame) pairs, or an error if the transaction is invalid
506/// 531///
507/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
508#[allow(dead_code)] 532#[allow(dead_code)]
509fn operation_frames<'a, 'b: 'a>( 533fn operation_frames<'a, 'b: 'a>(
510 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], 534 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
511) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> { 535) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
512 use embedded_hal_1::i2c::Operation::{Read, Write}; 536 use embedded_hal_1::i2c::Operation::{Read, Write};
513 537
514 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an 538 // Validate that no read operations have empty buffers before starting the transaction.
515 // error in the middle of the transaction. 539 // Empty read operations would risk halting with an error mid-transaction.
516 // 540 //
517 // In principle, we could allow empty read frames within consecutive read operations, as long as 541 // Note: We could theoretically allow empty read operations within consecutive read
518 // at least one byte remains in the final (merged) read operation, but that makes the logic more 542 // sequences as long as the final merged read has at least one byte, but this would
519 // complicated and error-prone. 543 // complicate the logic significantly and create error-prone edge cases.
520 if operations.iter().any(|op| match op { 544 if operations.iter().any(|op| match op {
521 Read(read) => read.is_empty(), 545 Read(read) => read.is_empty(),
522 Write(_) => false, 546 Write(_) => false,
@@ -525,46 +549,52 @@ fn operation_frames<'a, 'b: 'a>(
525 } 549 }
526 550
527 let mut operations = operations.iter_mut().peekable(); 551 let mut operations = operations.iter_mut().peekable();
528 552 let mut next_first_operation = true;
529 let mut next_first_frame = true;
530 553
531 Ok(iter::from_fn(move || { 554 Ok(iter::from_fn(move || {
532 let op = operations.next()?; 555 let current_op = operations.next()?;
533 556
534 // Is `op` first frame of its type? 557 // Determine if this is the first operation of its type (read or write)
535 let first_frame = next_first_frame; 558 let is_first_of_type = next_first_operation;
536 let next_op = operations.peek(); 559 let next_op = operations.peek();
537 560
538 // Get appropriate frame options as combination of the following properties: 561 // Compute the appropriate frame based on three key properties:
539 // 562 //
540 // - For each first operation of its type, generate a (repeated) start condition. 563 // 1. **Start Condition**: Generate (repeated) start for first operation of each type
541 // - For the last operation overall in the entire transaction, generate a stop condition. 564 // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction
542 // - For read operations, check the next operation: if it is also a read operation, we merge 565 // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the
543 // these and send ACK for all bytes in the current operation; send NACK only for the final 566 // sequence, or NACK for the final read in a sequence (before write or transaction end)
544 // read operation's last byte (before write or end of entire transaction) to indicate last
545 // byte read and release the bus for transmission of the bus master's next byte (or stop).
546 // 567 //
547 // We check the third property unconditionally, i.e. even for write opeartions. This is okay 568 // The third property is checked for all operations since the resulting frame
548 // because the resulting frame options are identical for write operations. 569 // configurations are identical for write operations regardless of ACK/NACK treatment.
549 let frame = match (first_frame, next_op) { 570 let frame = match (is_first_of_type, next_op) {
571 // First operation of type, and it's also the final operation overall
550 (true, None) => FrameOptions::FirstAndLastFrame, 572 (true, None) => FrameOptions::FirstAndLastFrame,
573 // First operation of type, next operation is also a read (continue read sequence)
551 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, 574 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
575 // First operation of type, next operation is write (end current sequence)
552 (true, Some(Write(_))) => FrameOptions::FirstFrame, 576 (true, Some(Write(_))) => FrameOptions::FirstFrame,
553 // 577
578 // Continuation operation, and it's the final operation overall
554 (false, None) => FrameOptions::LastFrame, 579 (false, None) => FrameOptions::LastFrame,
580 // Continuation operation, next operation is also a read (continue read sequence)
555 (false, Some(Read(_))) => FrameOptions::NextFrame, 581 (false, Some(Read(_))) => FrameOptions::NextFrame,
582 // Continuation operation, next operation is write (end current sequence, no stop)
556 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, 583 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
557 }; 584 };
558 585
559 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at 586 // Pre-calculate whether the next operation will be the first of its type.
560 // the beginning of the loop because we hand out `op` as iterator value and cannot access it 587 // This is done here because we consume `current_op` as the iterator value
561 // anymore in the next iteration. 588 // and cannot access it in the next iteration.
562 next_first_frame = match (&op, next_op) { 589 next_first_operation = match (&current_op, next_op) {
590 // No next operation
563 (_, None) => false, 591 (_, None) => false,
592 // Operation type changes: next will be first of its type
564 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, 593 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
594 // Operation type continues: next will not be first of its type
565 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, 595 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
566 }; 596 };
567 597
568 Some((op, frame)) 598 Some((current_op, frame))
569 })) 599 }))
570} 600}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 081eb1191..81a6d74c1 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -8,7 +8,7 @@ use core::future::poll_fn;
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{Either, select};
12use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
13use embedded_hal_1::i2c::Operation; 13use embedded_hal_1::i2c::Operation;
14use mode::Master; 14use mode::Master;
@@ -30,6 +30,7 @@ use crate::pac::i2c;
30// hit a case like this! 30// hit a case like this!
31pub unsafe fn on_interrupt<T: Instance>() { 31pub unsafe fn on_interrupt<T: Instance>() {
32 let regs = T::info().regs; 32 let regs = T::info().regs;
33 trace!("I2C interrupt triggered");
33 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 34 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
34 // other stuff, so we wake the task on every interrupt. 35 // other stuff, so we wake the task on every interrupt.
35 T::state().waker.wake(); 36 T::state().waker.wake();
@@ -92,6 +93,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
92 self.info.regs.cr1().modify(|reg| { 93 self.info.regs.cr1().modify(|reg| {
93 reg.set_pe(true); 94 reg.set_pe(true);
94 }); 95 });
96 trace!("i2c v1 init complete");
95 } 97 }
96 98
97 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> { 99 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
@@ -151,7 +153,13 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
151 Ok(sr1) 153 Ok(sr1)
152 } 154 }
153 155
154 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { 156 fn write_bytes(
157 &mut self,
158 address: u8,
159 write_buffer: &[u8],
160 timeout: Timeout,
161 frame: FrameOptions,
162 ) -> Result<(), Error> {
155 if frame.send_start() { 163 if frame.send_start() {
156 // Send a START condition 164 // Send a START condition
157 165
@@ -170,7 +178,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
170 } 178 }
171 179
172 // Set up current address we're trying to talk to 180 // Set up current address we're trying to talk to
173 self.info.regs.dr().write(|reg| reg.set_dr(addr << 1)); 181 self.info.regs.dr().write(|reg| reg.set_dr(address << 1));
174 182
175 // Wait until address was sent 183 // Wait until address was sent
176 // Wait for the address to be acknowledged 184 // Wait for the address to be acknowledged
@@ -184,7 +192,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
184 } 192 }
185 193
186 // Send bytes 194 // Send bytes
187 for c in bytes { 195 for c in write_buffer {
188 self.send_byte(*c, timeout)?; 196 self.send_byte(*c, timeout)?;
189 } 197 }
190 198
@@ -236,12 +244,12 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
236 244
237 fn blocking_read_timeout( 245 fn blocking_read_timeout(
238 &mut self, 246 &mut self,
239 addr: u8, 247 address: u8,
240 buffer: &mut [u8], 248 read_buffer: &mut [u8],
241 timeout: Timeout, 249 timeout: Timeout,
242 frame: FrameOptions, 250 frame: FrameOptions,
243 ) -> Result<(), Error> { 251 ) -> Result<(), Error> {
244 let Some((last, buffer)) = buffer.split_last_mut() else { 252 let Some((last_byte, read_buffer)) = read_buffer.split_last_mut() else {
245 return Err(Error::Overrun); 253 return Err(Error::Overrun);
246 }; 254 };
247 255
@@ -263,7 +271,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
263 } 271 }
264 272
265 // Set up current address we're trying to talk to 273 // Set up current address we're trying to talk to
266 self.info.regs.dr().write(|reg| reg.set_dr((addr << 1) + 1)); 274 self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1));
267 275
268 // Wait until address was sent 276 // Wait until address was sent
269 // Wait for the address to be acknowledged 277 // Wait for the address to be acknowledged
@@ -276,7 +284,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
276 } 284 }
277 285
278 // Receive bytes into buffer 286 // Receive bytes into buffer
279 for c in buffer { 287 for c in read_buffer {
280 *c = self.recv_byte(timeout)?; 288 *c = self.recv_byte(timeout)?;
281 } 289 }
282 290
@@ -291,37 +299,42 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
291 }); 299 });
292 300
293 // Receive last byte 301 // Receive last byte
294 *last = self.recv_byte(timeout)?; 302 *last_byte = self.recv_byte(timeout)?;
295 303
296 // Fallthrough is success 304 // Fallthrough is success
297 Ok(()) 305 Ok(())
298 } 306 }
299 307
300 /// Blocking read. 308 /// Blocking read.
301 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 309 pub fn blocking_read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
302 self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) 310 self.blocking_read_timeout(address, read_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)
303 } 311 }
304 312
305 /// Blocking write. 313 /// Blocking write.
306 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 314 pub fn blocking_write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
307 self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; 315 self.write_bytes(address, write_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)?;
308 316
309 // Fallthrough is success 317 // Fallthrough is success
310 Ok(()) 318 Ok(())
311 } 319 }
312 320
313 /// Blocking write, restart, read. 321 /// Blocking write, restart, read.
314 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 322 pub fn blocking_write_read(
323 &mut self,
324 address: u8,
325 write_buffer: &[u8],
326 read_buffer: &mut [u8],
327 ) -> Result<(), Error> {
315 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 328 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
316 // stop condition below. 329 // stop condition below.
317 if read.is_empty() { 330 if read_buffer.is_empty() {
318 return Err(Error::Overrun); 331 return Err(Error::Overrun);
319 } 332 }
320 333
321 let timeout = self.timeout(); 334 let timeout = self.timeout();
322 335
323 self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; 336 self.write_bytes(address, write_buffer, timeout, FrameOptions::FirstFrame)?;
324 self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; 337 self.blocking_read_timeout(address, read_buffer, timeout, FrameOptions::FirstAndLastFrame)?;
325 338
326 Ok(()) 339 Ok(())
327 } 340 }
@@ -331,32 +344,43 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
331 /// Consecutive operations of same type are merged. See [transaction contract] for details. 344 /// Consecutive operations of same type are merged. See [transaction contract] for details.
332 /// 345 ///
333 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 346 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
334 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 347 pub fn blocking_transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
335 let timeout = self.timeout(); 348 let timeout = self.timeout();
336 349
337 for (op, frame) in operation_frames(operations)? { 350 for (op, frame) in operation_frames(operations)? {
338 match op { 351 match op {
339 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, 352 Operation::Read(read_buffer) => self.blocking_read_timeout(address, read_buffer, timeout, frame)?,
340 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, 353 Operation::Write(write_buffer) => self.write_bytes(address, write_buffer, timeout, frame)?,
341 } 354 }
342 } 355 }
343 356
344 Ok(()) 357 Ok(())
345 } 358 }
346 359
347 // Async 360 /// Can be used by both blocking and async implementations
348
349 #[inline] // pretty sure this should always be inlined 361 #[inline] // pretty sure this should always be inlined
350 fn enable_interrupts(info: &'static Info) -> () { 362 fn enable_interrupts(info: &'static Info) {
351 info.regs.cr2().modify(|w| { 363 // The interrupt handler disables interrupts globally, so we need to re-enable them
352 w.set_iterren(true); 364 // This must be done in a critical section to avoid races
353 w.set_itevten(true); 365 critical_section::with(|_| {
366 info.regs.cr2().modify(|w| {
367 w.set_iterren(true);
368 w.set_itevten(true);
369 });
354 }); 370 });
355 } 371 }
372
373 /// Can be used by both blocking and async implementations
374 fn clear_stop_flag(info: &'static Info) {
375 trace!("I2C slave: clearing STOPF flag (v1 sequence)");
376 // v1 requires: READ SR1 then WRITE CR1 to clear STOPF
377 let _ = info.regs.sr1().read();
378 info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF
379 }
356} 380}
357 381
358impl<'d, IM: MasterMode> I2c<'d, Async, IM> { 382impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
359 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { 383 async fn write_frame(&mut self, address: u8, write_buffer: &[u8], frame: FrameOptions) -> Result<(), Error> {
360 self.info.regs.cr2().modify(|w| { 384 self.info.regs.cr2().modify(|w| {
361 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 385 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
362 // reception. 386 // reception.
@@ -439,7 +463,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
439 // this address from the memory after each TxE event. 463 // this address from the memory after each TxE event.
440 let dst = self.info.regs.dr().as_ptr() as *mut u8; 464 let dst = self.info.regs.dr().as_ptr() as *mut u8;
441 465
442 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) 466 self.tx_dma
467 .as_mut()
468 .unwrap()
469 .write(write_buffer, dst, Default::default())
443 }; 470 };
444 471
445 // Wait for bytes to be sent, or an error to occur. 472 // Wait for bytes to be sent, or an error to occur.
@@ -501,28 +528,30 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
501 } 528 }
502 529
503 /// Write. 530 /// Write.
504 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 531 pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
505 self.write_frame(address, write, FrameOptions::FirstAndLastFrame) 532 let _scoped_block_stop = self.info.rcc.block_stop();
533 self.write_frame(address, write_buffer, FrameOptions::FirstAndLastFrame)
506 .await?; 534 .await?;
507 535
508 Ok(()) 536 Ok(())
509 } 537 }
510 538
511 /// Read. 539 /// Read.
512 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 540 pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
513 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) 541 let _scoped_block_stop = self.info.rcc.block_stop();
542 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
514 .await?; 543 .await?;
515 544
516 Ok(()) 545 Ok(())
517 } 546 }
518 547
519 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> { 548 async fn read_frame(&mut self, address: u8, read_buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> {
520 if buffer.is_empty() { 549 if read_buffer.is_empty() {
521 return Err(Error::Overrun); 550 return Err(Error::Overrun);
522 } 551 }
523 552
524 // Some branches below depend on whether the buffer contains only a single byte. 553 // Some branches below depend on whether the buffer contains only a single byte.
525 let single_byte = buffer.len() == 1; 554 let single_byte = read_buffer.len() == 1;
526 555
527 self.info.regs.cr2().modify(|w| { 556 self.info.regs.cr2().modify(|w| {
528 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 557 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
@@ -612,7 +641,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
612 self.info.regs.sr2().read(); 641 self.info.regs.sr2().read();
613 } else { 642 } else {
614 // Before starting reception of single byte (but without START condition, i.e. in case 643 // Before starting reception of single byte (but without START condition, i.e. in case
615 // of continued frame), program NACK to emit at end of this byte. 644 // of merged operations), program NACK to emit at end of this byte.
616 if frame.send_nack() && single_byte { 645 if frame.send_nack() && single_byte {
617 self.info.regs.cr1().modify(|w| { 646 self.info.regs.cr1().modify(|w| {
618 w.set_ack(false); 647 w.set_ack(false);
@@ -634,7 +663,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
634 // from this address from the memory after each RxE event. 663 // from this address from the memory after each RxE event.
635 let src = self.info.regs.dr().as_ptr() as *mut u8; 664 let src = self.info.regs.dr().as_ptr() as *mut u8;
636 665
637 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) 666 self.rx_dma.as_mut().unwrap().read(src, read_buffer, Default::default())
638 }; 667 };
639 668
640 // Wait for bytes to be received, or an error to occur. 669 // Wait for bytes to be received, or an error to occur.
@@ -673,15 +702,18 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
673 } 702 }
674 703
675 /// Write, restart, read. 704 /// Write, restart, read.
676 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 705 pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> {
706 let _scoped_block_stop = self.info.rcc.block_stop();
677 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 707 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
678 // stop condition below. 708 // stop condition below.
679 if read.is_empty() { 709 if read_buffer.is_empty() {
680 return Err(Error::Overrun); 710 return Err(Error::Overrun);
681 } 711 }
682 712
683 self.write_frame(address, write, FrameOptions::FirstFrame).await?; 713 self.write_frame(address, write_buffer, FrameOptions::FirstFrame)
684 self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await 714 .await?;
715 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
716 .await
685 } 717 }
686 718
687 /// Transaction with operations. 719 /// Transaction with operations.
@@ -689,11 +721,12 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
689 /// Consecutive operations of same type are merged. See [transaction contract] for details. 721 /// Consecutive operations of same type are merged. See [transaction contract] for details.
690 /// 722 ///
691 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 723 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
692 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 724 pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
725 let _scoped_block_stop = self.info.rcc.block_stop();
693 for (op, frame) in operation_frames(operations)? { 726 for (op, frame) in operation_frames(operations)? {
694 match op { 727 match op {
695 Operation::Read(read) => self.read_frame(addr, read, frame).await?, 728 Operation::Read(read_buffer) => self.read_frame(address, read_buffer, frame).await?,
696 Operation::Write(write) => self.write_frame(addr, write, frame).await?, 729 Operation::Write(write_buffer) => self.write_frame(address, write_buffer, frame).await?,
697 } 730 }
698 } 731 }
699 732
@@ -729,12 +762,959 @@ impl Duty {
729 } 762 }
730} 763}
731 764
765/// Result of attempting to send a byte in slave transmitter mode
766#[derive(Debug, PartialEq)]
767enum TransmitResult {
768 /// Byte sent and ACKed by master - continue transmission
769 Acknowledged,
770 /// Byte sent but NACKed by master - normal end of read transaction
771 NotAcknowledged,
772 /// STOP condition detected - master terminated transaction
773 Stopped,
774 /// RESTART condition detected - master starting new transaction
775 Restarted,
776}
777
778/// Result of attempting to receive a byte in slave receiver mode
779#[derive(Debug, PartialEq)]
780enum ReceiveResult {
781 /// Data byte successfully received
782 Data(u8),
783 /// STOP condition detected - end of write transaction
784 Stopped,
785 /// RESTART condition detected - master starting new transaction
786 Restarted,
787}
788
789/// Enumeration of slave transaction termination conditions
790#[derive(Debug, Clone, Copy, PartialEq)]
791#[cfg_attr(feature = "defmt", derive(defmt::Format))]
792enum SlaveTermination {
793 /// STOP condition received - normal end of transaction
794 Stop,
795 /// RESTART condition received - master starting new transaction
796 Restart,
797 /// NACK received - normal end of read transaction
798 Nack,
799}
800
801impl<'d, M: PeriMode> I2c<'d, M, Master> {
802 /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster)
803 pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> {
804 let mut slave = I2c {
805 info: self.info,
806 state: self.state,
807 kernel_clock: self.kernel_clock,
808 tx_dma: self.tx_dma.take(), // Use take() to move ownership
809 rx_dma: self.rx_dma.take(), // Use take() to move ownership
810 #[cfg(feature = "time")]
811 timeout: self.timeout,
812 _phantom: PhantomData,
813 _phantom2: PhantomData,
814 _drop_guard: self._drop_guard, // Move the drop guard
815 };
816 slave.init_slave(slave_addr_config);
817 slave
818 }
819}
820
821// Address configuration methods
822impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
823 /// Initialize slave mode with address configuration
824 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) {
825 trace!("I2C slave: initializing with config={:?}", config);
826
827 // Disable peripheral for configuration
828 self.info.regs.cr1().modify(|reg| reg.set_pe(false));
829
830 // Configure slave addresses
831 self.apply_address_configuration(config);
832
833 // Enable peripheral with slave settings
834 self.info.regs.cr1().modify(|reg| {
835 reg.set_pe(true);
836 reg.set_ack(true); // Enable acknowledgment for slave mode
837 reg.set_nostretch(false); // Allow clock stretching for processing time
838 });
839
840 trace!("I2C slave: initialization complete");
841 }
842
843 /// Apply the complete address configuration for slave mode
844 fn apply_address_configuration(&mut self, config: SlaveAddrConfig) {
845 match config.addr {
846 OwnAddresses::OA1(addr) => {
847 self.configure_primary_address(addr);
848 self.disable_secondary_address();
849 }
850 OwnAddresses::OA2(oa2) => {
851 self.configure_default_primary_address();
852 self.configure_secondary_address(oa2.addr); // v1 ignores mask
853 }
854 OwnAddresses::Both { oa1, oa2 } => {
855 self.configure_primary_address(oa1);
856 self.configure_secondary_address(oa2.addr); // v1 ignores mask
857 }
858 }
859
860 // Configure general call detection
861 if config.general_call {
862 self.info.regs.cr1().modify(|w| w.set_engc(true));
863 }
864 }
865
866 /// Configure the primary address (OA1) register
867 fn configure_primary_address(&mut self, addr: Address) {
868 match addr {
869 Address::SevenBit(addr) => {
870 self.info.regs.oar1().write(|reg| {
871 let hw_addr = (addr as u16) << 1; // Address in bits [7:1]
872 reg.set_add(hw_addr);
873 reg.set_addmode(i2c::vals::Addmode::BIT7);
874 });
875 }
876 Address::TenBit(addr) => {
877 self.info.regs.oar1().write(|reg| {
878 reg.set_add(addr);
879 reg.set_addmode(i2c::vals::Addmode::BIT10);
880 });
881 }
882 }
883
884 // Set required bit 14 as per reference manual
885 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
886 }
887
888 /// Configure the secondary address (OA2) register
889 fn configure_secondary_address(&mut self, addr: u8) {
890 self.info.regs.oar2().write(|reg| {
891 reg.set_add2(addr);
892 reg.set_endual(i2c::vals::Endual::DUAL);
893 });
894 }
895
896 /// Set a default primary address when using OA2-only mode
897 fn configure_default_primary_address(&mut self) {
898 self.info.regs.oar1().write(|reg| {
899 reg.set_add(0); // Reserved address, safe to use
900 reg.set_addmode(i2c::vals::Addmode::BIT7);
901 });
902 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
903 }
904
905 /// Disable secondary address when not needed
906 fn disable_secondary_address(&mut self) {
907 self.info.regs.oar2().write(|reg| {
908 reg.set_endual(i2c::vals::Endual::SINGLE);
909 });
910 }
911}
912
913impl<'d, M: PeriMode> I2c<'d, M, MultiMaster> {
914 /// Listen for incoming I2C address match and return the command type
915 ///
916 /// This method blocks until the slave address is matched by a master.
917 /// Returns the command type (Read/Write) and the matched address.
918 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
919 trace!("I2C slave: starting blocking listen for address match");
920 let result = self.blocking_listen_with_timeout(self.timeout());
921 trace!("I2C slave: blocking listen complete, result={:?}", result);
922 result
923 }
924
925 /// Respond to a master read request by transmitting data
926 ///
927 /// Sends the provided data to the master. If the master requests more bytes
928 /// than available, padding bytes (0x00) are sent until the master terminates
929 /// the transaction with NACK.
930 ///
931 /// Returns the total number of bytes transmitted (including padding).
932 pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
933 trace!("I2C slave: starting blocking respond_to_read, data_len={}", data.len());
934
935 if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? {
936 trace!("I2C slave: zero-length read detected");
937 return Ok(zero_length_result);
938 }
939
940 let result = self.transmit_to_master(data, self.timeout());
941 trace!("I2C slave: blocking respond_to_read complete, result={:?}", result);
942 result
943 }
944
945 /// Respond to a master write request by receiving data
946 ///
947 /// Receives data from the master into the provided buffer. If the master
948 /// sends more bytes than the buffer can hold, excess bytes are acknowledged
949 /// but discarded.
950 ///
951 /// Returns the number of bytes stored in the buffer (not total received).
952 pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
953 trace!(
954 "I2C slave: starting blocking respond_to_write, buffer_len={}",
955 buffer.len()
956 );
957 let result = self.receive_from_master(buffer, self.timeout());
958 trace!("I2C slave: blocking respond_to_write complete, result={:?}", result);
959 result
960 }
961
962 // Private implementation methods
963
964 /// Wait for address match and determine transaction type
965 fn blocking_listen_with_timeout(&mut self, timeout: Timeout) -> Result<SlaveCommand, Error> {
966 // Ensure interrupts are disabled for blocking operation
967 self.disable_i2c_interrupts();
968
969 // Wait for address match (ADDR flag)
970 loop {
971 let sr1 = Self::read_status_and_handle_errors(self.info)?;
972
973 if sr1.addr() {
974 // Address matched - read SR2 to get direction and clear ADDR flag
975 let sr2 = self.info.regs.sr2().read();
976 let direction = if sr2.tra() {
977 SlaveCommandKind::Read
978 } else {
979 SlaveCommandKind::Write
980 };
981
982 // Use the static method instead of the instance method
983 let matched_address = Self::decode_matched_address(sr2, self.info)?;
984 trace!(
985 "I2C slave: address matched, direction={:?}, addr={:?}",
986 direction, matched_address
987 );
988
989 return Ok(SlaveCommand {
990 kind: direction,
991 address: matched_address,
992 });
993 }
994
995 timeout.check()?;
996 }
997 }
998
999 /// Transmit data to master in response to read request
1000 fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> {
1001 let mut bytes_transmitted = 0;
1002 let mut padding_count = 0;
1003
1004 loop {
1005 let byte_to_send = if bytes_transmitted < data.len() {
1006 data[bytes_transmitted]
1007 } else {
1008 padding_count += 1;
1009 0x00 // Send padding bytes when data is exhausted
1010 };
1011
1012 match self.transmit_byte(byte_to_send, timeout)? {
1013 TransmitResult::Acknowledged => {
1014 bytes_transmitted += 1;
1015 }
1016 TransmitResult::NotAcknowledged => {
1017 bytes_transmitted += 1; // Count the NACKed byte
1018 break;
1019 }
1020 TransmitResult::Stopped | TransmitResult::Restarted => {
1021 break;
1022 }
1023 }
1024 }
1025
1026 if padding_count > 0 {
1027 trace!(
1028 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1029 data.len(),
1030 padding_count,
1031 bytes_transmitted
1032 );
1033 }
1034
1035 Ok(bytes_transmitted)
1036 }
1037
1038 /// Receive data from master during write request
1039 fn receive_from_master(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
1040 let mut bytes_stored = 0;
1041
1042 // Receive bytes that fit in buffer
1043 while bytes_stored < buffer.len() {
1044 match self.receive_byte(timeout)? {
1045 ReceiveResult::Data(byte) => {
1046 buffer[bytes_stored] = byte;
1047 bytes_stored += 1;
1048 }
1049 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1050 return Ok(bytes_stored);
1051 }
1052 }
1053 }
1054
1055 // Handle buffer overflow by discarding excess bytes
1056 if bytes_stored == buffer.len() {
1057 trace!("I2C slave: buffer full, discarding excess bytes");
1058 self.discard_excess_bytes(timeout)?;
1059 }
1060
1061 Ok(bytes_stored)
1062 }
1063
1064 /// Detect zero-length read pattern early
1065 ///
1066 /// Zero-length reads occur when a master sends START+ADDR+R followed immediately
1067 /// by NACK+STOP without wanting any data. This must be detected before attempting
1068 /// to transmit any bytes to avoid SDA line issues.
1069 fn detect_zero_length_read(&mut self, _timeout: Timeout) -> Result<Option<usize>, Error> {
1070 // Quick check for immediate termination signals
1071 let sr1 = self.info.regs.sr1().read();
1072
1073 // Check for immediate NACK (fastest zero-length pattern)
1074 if sr1.af() {
1075 self.clear_acknowledge_failure();
1076 return Ok(Some(0));
1077 }
1078
1079 // Check for immediate STOP (alternative zero-length pattern)
1080 if sr1.stopf() {
1081 Self::clear_stop_flag(self.info);
1082 return Ok(Some(0));
1083 }
1084
1085 // Give a brief window for master to send termination signals
1086 // This handles masters that have slight delays between address ACK and NACK
1087 const ZERO_LENGTH_DETECTION_CYCLES: u32 = 20; // ~5-10µs window
1088
1089 for _ in 0..ZERO_LENGTH_DETECTION_CYCLES {
1090 let sr1 = self.info.regs.sr1().read();
1091
1092 // Immediate NACK indicates zero-length read
1093 if sr1.af() {
1094 self.clear_acknowledge_failure();
1095 return Ok(Some(0));
1096 }
1097
1098 // Immediate STOP indicates zero-length read
1099 if sr1.stopf() {
1100 Self::clear_stop_flag(self.info);
1101 return Ok(Some(0));
1102 }
1103
1104 // If TXE becomes ready, master is waiting for data - not zero-length
1105 if sr1.txe() {
1106 return Ok(None); // Proceed with normal transmission
1107 }
1108
1109 // If RESTART detected, handle as zero-length
1110 if sr1.addr() {
1111 return Ok(Some(0));
1112 }
1113 }
1114
1115 // No zero-length pattern detected within the window
1116 Ok(None)
1117 }
1118
1119 /// Discard excess bytes when buffer is full
1120 fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> {
1121 let mut discarded_count = 0;
1122
1123 loop {
1124 match self.receive_byte(timeout)? {
1125 ReceiveResult::Data(_) => {
1126 discarded_count += 1;
1127 continue;
1128 }
1129 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1130 if discarded_count > 0 {
1131 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1132 }
1133 break;
1134 }
1135 }
1136 }
1137 Ok(())
1138 }
1139
1140 /// Send a single byte and wait for master's response
1141 fn transmit_byte(&mut self, byte: u8, timeout: Timeout) -> Result<TransmitResult, Error> {
1142 // Wait for transmit buffer ready
1143 self.wait_for_transmit_ready(timeout)?;
1144
1145 // Send the byte
1146 self.info.regs.dr().write(|w| w.set_dr(byte));
1147
1148 // Wait for transmission completion or master response
1149 self.wait_for_transmit_completion(timeout)
1150 }
1151
1152 /// Wait until transmit buffer is ready (TXE flag set)
1153 fn wait_for_transmit_ready(&mut self, timeout: Timeout) -> Result<(), Error> {
1154 loop {
1155 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1156
1157 // Check for early termination conditions
1158 if let Some(result) = Self::check_early_termination(sr1) {
1159 return Err(self.handle_early_termination(result));
1160 }
1161
1162 if sr1.txe() {
1163 return Ok(()); // Ready to transmit
1164 }
1165
1166 timeout.check()?;
1167 }
1168 }
1169
1170 /// Wait for byte transmission completion or master response
1171 fn wait_for_transmit_completion(&mut self, timeout: Timeout) -> Result<TransmitResult, Error> {
1172 loop {
1173 let sr1 = self.info.regs.sr1().read();
1174
1175 // Check flags in priority order
1176 if sr1.af() {
1177 self.clear_acknowledge_failure();
1178 return Ok(TransmitResult::NotAcknowledged);
1179 }
1180
1181 if sr1.btf() {
1182 return Ok(TransmitResult::Acknowledged);
1183 }
1184
1185 if sr1.stopf() {
1186 Self::clear_stop_flag(self.info);
1187 return Ok(TransmitResult::Stopped);
1188 }
1189
1190 if sr1.addr() {
1191 return Ok(TransmitResult::Restarted);
1192 }
1193
1194 // Check for other error conditions
1195 self.check_for_hardware_errors(sr1)?;
1196
1197 timeout.check()?;
1198 }
1199 }
1200
1201 /// Receive a single byte or detect transaction termination
1202 fn receive_byte(&mut self, timeout: Timeout) -> Result<ReceiveResult, Error> {
1203 loop {
1204 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1205
1206 // Check for received data first (prioritize data over control signals)
1207 if sr1.rxne() {
1208 let byte = self.info.regs.dr().read().dr();
1209 return Ok(ReceiveResult::Data(byte));
1210 }
1211
1212 // Check for transaction termination
1213 if sr1.addr() {
1214 return Ok(ReceiveResult::Restarted);
1215 }
1216
1217 if sr1.stopf() {
1218 Self::clear_stop_flag(self.info);
1219 return Ok(ReceiveResult::Stopped);
1220 }
1221
1222 timeout.check()?;
1223 }
1224 }
1225
1226 /// Determine which slave address was matched based on SR2 flags
1227 fn decode_matched_address(sr2: i2c::regs::Sr2, info: &'static Info) -> Result<Address, Error> {
1228 if sr2.gencall() {
1229 Ok(Address::SevenBit(0x00)) // General call address
1230 } else if sr2.dualf() {
1231 // OA2 (secondary address) was matched
1232 let oar2 = info.regs.oar2().read();
1233 if oar2.endual() != i2c::vals::Endual::DUAL {
1234 return Err(Error::Bus); // Hardware inconsistency
1235 }
1236 Ok(Address::SevenBit(oar2.add2()))
1237 } else {
1238 // OA1 (primary address) was matched
1239 let oar1 = info.regs.oar1().read();
1240 match oar1.addmode() {
1241 i2c::vals::Addmode::BIT7 => {
1242 let addr = (oar1.add() >> 1) as u8;
1243 Ok(Address::SevenBit(addr))
1244 }
1245 i2c::vals::Addmode::BIT10 => Ok(Address::TenBit(oar1.add())),
1246 }
1247 }
1248 }
1249
1250 // Helper methods for hardware interaction
1251
1252 /// Read status register and handle I2C errors (except NACK in slave mode)
1253 fn read_status_and_handle_errors(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
1254 match Self::check_and_clear_error_flags(info) {
1255 Ok(sr1) => Ok(sr1),
1256 Err(Error::Nack) => {
1257 // In slave mode, NACK is normal protocol behavior, not an error
1258 Ok(info.regs.sr1().read())
1259 }
1260 Err(other_error) => Err(other_error),
1261 }
1262 }
1263
1264 /// Check for conditions that cause early termination of operations
1265 fn check_early_termination(sr1: i2c::regs::Sr1) -> Option<TransmitResult> {
1266 if sr1.stopf() {
1267 Some(TransmitResult::Stopped)
1268 } else if sr1.addr() {
1269 Some(TransmitResult::Restarted)
1270 } else if sr1.af() {
1271 Some(TransmitResult::NotAcknowledged)
1272 } else {
1273 None
1274 }
1275 }
1276
1277 /// Convert early termination to appropriate error
1278 fn handle_early_termination(&mut self, result: TransmitResult) -> Error {
1279 match result {
1280 TransmitResult::Stopped => {
1281 Self::clear_stop_flag(self.info);
1282 Error::Bus // Unexpected STOP during setup
1283 }
1284 TransmitResult::Restarted => {
1285 Error::Bus // Unexpected RESTART during setup
1286 }
1287 TransmitResult::NotAcknowledged => {
1288 self.clear_acknowledge_failure();
1289 Error::Bus // Unexpected NACK during setup
1290 }
1291 TransmitResult::Acknowledged => {
1292 unreachable!() // This should never be passed to this function
1293 }
1294 }
1295 }
1296
1297 /// Check for hardware-level I2C errors during transmission
1298 fn check_for_hardware_errors(&self, sr1: i2c::regs::Sr1) -> Result<(), Error> {
1299 if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() {
1300 // Delegate to existing error handling
1301 Self::check_and_clear_error_flags(self.info)?;
1302 }
1303 Ok(())
1304 }
1305
1306 /// Disable I2C event and error interrupts for blocking operations
1307 fn disable_i2c_interrupts(&mut self) {
1308 self.info.regs.cr2().modify(|w| {
1309 w.set_itevten(false);
1310 w.set_iterren(false);
1311 });
1312 }
1313
1314 /// Clear the acknowledge failure flag
1315 fn clear_acknowledge_failure(&mut self) {
1316 self.info.regs.sr1().write(|reg| {
1317 reg.0 = !0;
1318 reg.set_af(false);
1319 });
1320 }
1321
1322 /// Configure DMA settings for slave operations (shared between read/write)
1323 fn setup_slave_dma_base(&mut self) {
1324 self.info.regs.cr2().modify(|w| {
1325 w.set_itbufen(false); // Always disable buffer interrupts when using DMA
1326 w.set_dmaen(true); // Enable DMA requests
1327 w.set_last(false); // LAST bit not used in slave mode for v1 hardware
1328 });
1329 }
1330
1331 /// Disable DMA and interrupts in a critical section
1332 fn disable_dma_and_interrupts(info: &'static Info) {
1333 critical_section::with(|_| {
1334 info.regs.cr2().modify(|w| {
1335 w.set_dmaen(false);
1336 w.set_iterren(false);
1337 w.set_itevten(false);
1338 });
1339 });
1340 }
1341
1342 /// Check for early termination conditions during slave operations
1343 /// Returns Some(result) if termination detected, None to continue
1344 fn check_slave_termination_conditions(sr1: i2c::regs::Sr1) -> Option<SlaveTermination> {
1345 if sr1.stopf() {
1346 Some(SlaveTermination::Stop)
1347 } else if sr1.addr() {
1348 Some(SlaveTermination::Restart)
1349 } else if sr1.af() {
1350 Some(SlaveTermination::Nack)
1351 } else {
1352 None
1353 }
1354 }
1355}
1356
1357impl<'d> I2c<'d, Async, MultiMaster> {
1358 /// Async listen for incoming I2C messages using interrupts
1359 ///
1360 /// Waits for a master to address this slave and returns the command type
1361 /// (Read/Write) and the matched address. This method will suspend until
1362 /// an address match occurs.
1363 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
1364 let _scoped_block_stop = self.info.rcc.block_stop();
1365 trace!("I2C slave: starting async listen for address match");
1366 let state = self.state;
1367 let info = self.info;
1368
1369 Self::enable_interrupts(info);
1370
1371 let on_drop = OnDrop::new(|| {
1372 Self::disable_dma_and_interrupts(info);
1373 });
1374
1375 let result = poll_fn(|cx| {
1376 state.waker.register(cx.waker());
1377
1378 match Self::check_and_clear_error_flags(info) {
1379 Err(e) => {
1380 error!("I2C slave: error during listen: {:?}", e);
1381 Poll::Ready(Err(e))
1382 }
1383 Ok(sr1) => {
1384 if sr1.addr() {
1385 let sr2 = info.regs.sr2().read();
1386 let direction = if sr2.tra() {
1387 SlaveCommandKind::Read
1388 } else {
1389 SlaveCommandKind::Write
1390 };
1391
1392 let matched_address = match Self::decode_matched_address(sr2, info) {
1393 Ok(addr) => {
1394 trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, addr);
1395 addr
1396 }
1397 Err(e) => {
1398 error!("I2C slave: failed to decode matched address: {:?}", e);
1399 return Poll::Ready(Err(e));
1400 }
1401 };
1402
1403 Poll::Ready(Ok(SlaveCommand {
1404 kind: direction,
1405 address: matched_address,
1406 }))
1407 } else {
1408 Self::enable_interrupts(info);
1409 Poll::Pending
1410 }
1411 }
1412 }
1413 })
1414 .await;
1415
1416 drop(on_drop);
1417 trace!("I2C slave: listen complete, result={:?}", result);
1418 result
1419 }
1420
1421 /// Async respond to write command using RX DMA
1422 ///
1423 /// Receives data from the master into the provided buffer using DMA.
1424 /// If the master sends more bytes than the buffer can hold, excess bytes
1425 /// are acknowledged but discarded to prevent interrupt flooding.
1426 ///
1427 /// Returns the number of bytes stored in the buffer (not total received).
1428 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1429 let _scoped_block_stop = self.info.rcc.block_stop();
1430 trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len());
1431
1432 if buffer.is_empty() {
1433 warn!("I2C slave: respond_to_write called with empty buffer");
1434 return Err(Error::Overrun);
1435 }
1436
1437 let state = self.state;
1438 let info = self.info;
1439
1440 self.setup_slave_dma_base();
1441
1442 let on_drop = OnDrop::new(|| {
1443 Self::disable_dma_and_interrupts(info);
1444 });
1445
1446 info.regs.sr2().read();
1447
1448 let result = self.execute_slave_receive_transfer(buffer, state, info).await;
1449
1450 drop(on_drop);
1451 trace!("I2C slave: respond_to_write complete, result={:?}", result);
1452 result
1453 }
1454
1455 /// Async respond to read command using TX DMA
1456 ///
1457 /// Transmits data to the master using DMA. If the master requests more bytes
1458 /// than available in the data buffer, padding bytes (0x00) are sent until
1459 /// the master terminates the transaction with NACK, STOP, or RESTART.
1460 ///
1461 /// Returns the total number of bytes transmitted (data + padding).
1462 pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
1463 let _scoped_block_stop = self.info.rcc.block_stop();
1464 trace!("I2C slave: starting respond_to_read, data_len={}", data.len());
1465
1466 if data.is_empty() {
1467 warn!("I2C slave: respond_to_read called with empty data");
1468 return Err(Error::Overrun);
1469 }
1470
1471 let state = self.state;
1472 let info = self.info;
1473
1474 self.setup_slave_dma_base();
1475
1476 let on_drop = OnDrop::new(|| {
1477 Self::disable_dma_and_interrupts(info);
1478 });
1479
1480 info.regs.sr2().read();
1481
1482 let result = self.execute_slave_transmit_transfer(data, state, info).await;
1483
1484 drop(on_drop);
1485 trace!("I2C slave: respond_to_read complete, result={:?}", result);
1486 result
1487 }
1488
1489 // === Private Transfer Execution Methods ===
1490
1491 /// Execute complete slave receive transfer with excess byte handling
1492 async fn execute_slave_receive_transfer(
1493 &mut self,
1494 buffer: &mut [u8],
1495 state: &'static State,
1496 info: &'static Info,
1497 ) -> Result<usize, Error> {
1498 let dma_transfer = unsafe {
1499 let src = info.regs.dr().as_ptr() as *mut u8;
1500 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1501 };
1502
1503 let i2c_monitor =
1504 Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]);
1505
1506 match select(dma_transfer, i2c_monitor).await {
1507 Either::Second(Err(e)) => {
1508 error!("I2C slave: error during receive transfer: {:?}", e);
1509 Self::disable_dma_and_interrupts(info);
1510 Err(e)
1511 }
1512 Either::First(_) => {
1513 trace!("I2C slave: DMA receive completed, handling excess bytes");
1514 Self::disable_dma_and_interrupts(info);
1515 self.handle_excess_bytes(state, info).await?;
1516 Ok(buffer.len())
1517 }
1518 Either::Second(Ok(termination)) => {
1519 trace!("I2C slave: receive terminated by I2C event: {:?}", termination);
1520 Self::disable_dma_and_interrupts(info);
1521 Ok(buffer.len())
1522 }
1523 }
1524 }
1525
1526 /// Execute complete slave transmit transfer with padding byte handling
1527 async fn execute_slave_transmit_transfer(
1528 &mut self,
1529 data: &[u8],
1530 state: &'static State,
1531 info: &'static Info,
1532 ) -> Result<usize, Error> {
1533 let dma_transfer = unsafe {
1534 let dst = info.regs.dr().as_ptr() as *mut u8;
1535 self.tx_dma.as_mut().unwrap().write(data, dst, Default::default())
1536 };
1537
1538 let i2c_monitor = Self::create_termination_monitor(
1539 state,
1540 info,
1541 &[
1542 SlaveTermination::Stop,
1543 SlaveTermination::Restart,
1544 SlaveTermination::Nack,
1545 ],
1546 );
1547
1548 match select(dma_transfer, i2c_monitor).await {
1549 Either::Second(Err(e)) => {
1550 error!("I2C slave: error during transmit transfer: {:?}", e);
1551 Self::disable_dma_and_interrupts(info);
1552 Err(e)
1553 }
1554 Either::First(_) => {
1555 trace!("I2C slave: DMA transmit completed, handling padding bytes");
1556 Self::disable_dma_and_interrupts(info);
1557 let padding_count = self.handle_padding_bytes(state, info).await?;
1558 let total_bytes = data.len() + padding_count;
1559 trace!(
1560 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1561 data.len(),
1562 padding_count,
1563 total_bytes
1564 );
1565 Ok(total_bytes)
1566 }
1567 Either::Second(Ok(termination)) => {
1568 trace!("I2C slave: transmit terminated by I2C event: {:?}", termination);
1569 Self::disable_dma_and_interrupts(info);
1570 Ok(data.len())
1571 }
1572 }
1573 }
1574
1575 /// Create a future that monitors for specific slave termination conditions
1576 fn create_termination_monitor(
1577 state: &'static State,
1578 info: &'static Info,
1579 allowed_terminations: &'static [SlaveTermination],
1580 ) -> impl Future<Output = Result<SlaveTermination, Error>> {
1581 poll_fn(move |cx| {
1582 state.waker.register(cx.waker());
1583
1584 match Self::check_and_clear_error_flags(info) {
1585 Err(Error::Nack) if allowed_terminations.contains(&SlaveTermination::Nack) => {
1586 Poll::Ready(Ok(SlaveTermination::Nack))
1587 }
1588 Err(e) => Poll::Ready(Err(e)),
1589 Ok(sr1) => {
1590 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1591 if allowed_terminations.contains(&termination) {
1592 // Handle the specific termination condition
1593 match termination {
1594 SlaveTermination::Stop => Self::clear_stop_flag(info),
1595 SlaveTermination::Nack => {
1596 info.regs.sr1().write(|reg| {
1597 reg.0 = !0;
1598 reg.set_af(false);
1599 });
1600 }
1601 SlaveTermination::Restart => {
1602 // ADDR flag will be handled by next listen() call
1603 }
1604 }
1605 Poll::Ready(Ok(termination))
1606 } else {
1607 // Unexpected termination condition
1608 Poll::Ready(Err(Error::Bus))
1609 }
1610 } else {
1611 Self::enable_interrupts(info);
1612 Poll::Pending
1613 }
1614 }
1615 }
1616 })
1617 }
1618
1619 /// Handle excess bytes after DMA buffer is full
1620 ///
1621 /// Reads and discards bytes until transaction termination to prevent interrupt flooding
1622 async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> {
1623 let mut discarded_count = 0;
1624
1625 poll_fn(|cx| {
1626 state.waker.register(cx.waker());
1627
1628 match Self::check_and_clear_error_flags(info) {
1629 Err(e) => {
1630 error!("I2C slave: error while discarding excess bytes: {:?}", e);
1631 Poll::Ready(Err(e))
1632 }
1633 Ok(sr1) => {
1634 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1635 match termination {
1636 SlaveTermination::Stop => Self::clear_stop_flag(info),
1637 SlaveTermination::Restart => {}
1638 SlaveTermination::Nack => unreachable!("NACK not expected during receive"),
1639 }
1640 if discarded_count > 0 {
1641 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1642 }
1643 return Poll::Ready(Ok(()));
1644 }
1645
1646 if sr1.rxne() {
1647 let _discarded_byte = info.regs.dr().read().dr();
1648 discarded_count += 1;
1649 Self::enable_interrupts(info);
1650 return Poll::Pending;
1651 }
1652
1653 Self::enable_interrupts(info);
1654 Poll::Pending
1655 }
1656 }
1657 })
1658 .await
1659 }
1660
1661 /// Handle padding bytes after DMA data is exhausted
1662 ///
1663 /// Sends 0x00 bytes until transaction termination to prevent interrupt flooding
1664 async fn handle_padding_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<usize, Error> {
1665 let mut padding_count = 0;
1666
1667 poll_fn(|cx| {
1668 state.waker.register(cx.waker());
1669
1670 match Self::check_and_clear_error_flags(info) {
1671 Err(Error::Nack) => Poll::Ready(Ok(padding_count)),
1672 Err(e) => {
1673 error!("I2C slave: error while sending padding bytes: {:?}", e);
1674 Poll::Ready(Err(e))
1675 }
1676 Ok(sr1) => {
1677 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1678 match termination {
1679 SlaveTermination::Stop => Self::clear_stop_flag(info),
1680 SlaveTermination::Restart => {}
1681 SlaveTermination::Nack => {
1682 info.regs.sr1().write(|reg| {
1683 reg.0 = !0;
1684 reg.set_af(false);
1685 });
1686 }
1687 }
1688 return Poll::Ready(Ok(padding_count));
1689 }
1690
1691 if sr1.txe() {
1692 info.regs.dr().write(|w| w.set_dr(0x00));
1693 padding_count += 1;
1694 Self::enable_interrupts(info);
1695 return Poll::Pending;
1696 }
1697
1698 Self::enable_interrupts(info);
1699 Poll::Pending
1700 }
1701 }
1702 })
1703 .await
1704 }
1705}
1706
1707/// Timing configuration for I2C v1 hardware
1708///
1709/// This struct encapsulates the complex timing calculations required for STM32 I2C v1
1710/// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of
1711/// the unified TIMINGR register found in v2 hardware.
732struct Timings { 1712struct Timings {
733 freq: u8, 1713 freq: u8, // APB frequency in MHz for CR2.FREQ register
734 mode: Mode, 1714 mode: Mode, // Standard or Fast mode selection
735 trise: u8, 1715 trise: u8, // Rise time compensation value
736 ccr: u16, 1716 ccr: u16, // Clock control register value
737 duty: Duty, 1717 duty: Duty, // Fast mode duty cycle selection
738} 1718}
739 1719
740impl Timings { 1720impl Timings {
@@ -762,11 +1742,7 @@ impl Timings {
762 mode = Mode::Standard; 1742 mode = Mode::Standard;
763 ccr = { 1743 ccr = {
764 let ccr = clock / (frequency * 2); 1744 let ccr = clock / (frequency * 2);
765 if ccr < 4 { 1745 if ccr < 4 { 4 } else { ccr }
766 4
767 } else {
768 ccr
769 }
770 }; 1746 };
771 } else { 1747 } else {
772 const DUTYCYCLE: u8 = 0; 1748 const DUTYCYCLE: u8 = 0;
@@ -775,14 +1751,10 @@ impl Timings {
775 duty = Duty::Duty2_1; 1751 duty = Duty::Duty2_1;
776 ccr = clock / (frequency * 3); 1752 ccr = clock / (frequency * 3);
777 ccr = if ccr < 1 { 1 } else { ccr }; 1753 ccr = if ccr < 1 { 1 } else { ccr };
778
779 // Set clock to fast mode with appropriate parameters for selected speed (2:1 duty cycle)
780 } else { 1754 } else {
781 duty = Duty::Duty16_9; 1755 duty = Duty::Duty16_9;
782 ccr = clock / (frequency * 25); 1756 ccr = clock / (frequency * 25);
783 ccr = if ccr < 1 { 1 } else { ccr }; 1757 ccr = if ccr < 1 { 1 } else { ccr };
784
785 // Set clock to fast mode with appropriate parameters for selected speed (16:9 duty cycle)
786 } 1758 }
787 } 1759 }
788 1760
@@ -792,11 +1764,6 @@ impl Timings {
792 ccr: ccr as u16, 1764 ccr: ccr as u16,
793 duty, 1765 duty,
794 mode, 1766 mode,
795 //prescale: presc_reg,
796 //scll,
797 //sclh,
798 //sdadel,
799 //scldel,
800 } 1767 }
801 } 1768 }
802} 1769}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 0bfc795ac..fe7782a7c 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -2,7 +2,7 @@ use core::cmp;
2use core::future::poll_fn; 2use core::future::poll_fn;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use config::{Address, OwnAddresses, OA2}; 5use config::{Address, OA2, OwnAddresses};
6use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::drop::OnDrop; 7use embassy_hal_internal::drop::OnDrop;
8use embedded_hal_1::i2c::Operation; 8use embedded_hal_1::i2c::Operation;
@@ -70,6 +70,11 @@ fn debug_print_interrupts(isr: stm32_metapac::i2c::regs::Isr) {
70} 70}
71 71
72pub(crate) unsafe fn on_interrupt<T: Instance>() { 72pub(crate) unsafe fn on_interrupt<T: Instance>() {
73 // restore the clocks to their last configured state as
74 // much is lost in STOP modes
75 #[cfg(all(feature = "low-power", stm32wlex))]
76 crate::low_power::Executor::on_wakeup_irq_or_event();
77
73 let regs = T::info().regs; 78 let regs = T::info().regs;
74 let isr = regs.isr().read(); 79 let isr = regs.isr().read();
75 80
@@ -93,6 +98,27 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
93} 98}
94 99
95impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { 100impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
101 #[inline]
102 fn to_reload(reload: bool) -> i2c::vals::Reload {
103 if reload {
104 i2c::vals::Reload::NOT_COMPLETED
105 } else {
106 i2c::vals::Reload::COMPLETED
107 }
108 }
109
110 /// Calculate total bytes in a group of operations
111 #[inline]
112 fn total_operation_bytes(operations: &[Operation<'_>]) -> usize {
113 operations
114 .iter()
115 .map(|op| match op {
116 Operation::Write(buf) => buf.len(),
117 Operation::Read(buf) => buf.len(),
118 })
119 .sum()
120 }
121
96 pub(crate) fn init(&mut self, config: Config) { 122 pub(crate) fn init(&mut self, config: Config) {
97 self.info.regs.cr1().modify(|reg| { 123 self.info.regs.cr1().modify(|reg| {
98 reg.set_pe(false); 124 reg.set_pe(false);
@@ -142,12 +168,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
142 // `buffer`. The START bit can be set even if the bus 168 // `buffer`. The START bit can be set even if the bus
143 // is BUSY or I2C is in slave mode. 169 // is BUSY or I2C is in slave mode.
144 170
145 let reload = if reload {
146 i2c::vals::Reload::NOT_COMPLETED
147 } else {
148 i2c::vals::Reload::COMPLETED
149 };
150
151 info.regs.cr2().modify(|w| { 171 info.regs.cr2().modify(|w| {
152 w.set_sadd(address.addr() << 1); 172 w.set_sadd(address.addr() << 1);
153 w.set_add10(address.add_mode()); 173 w.set_add10(address.add_mode());
@@ -155,7 +175,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
155 w.set_nbytes(length as u8); 175 w.set_nbytes(length as u8);
156 w.set_start(true); 176 w.set_start(true);
157 w.set_autoend(stop.autoend()); 177 w.set_autoend(stop.autoend());
158 w.set_reload(reload); 178 w.set_reload(Self::to_reload(reload));
159 }); 179 });
160 180
161 Ok(()) 181 Ok(())
@@ -167,28 +187,25 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
167 length: usize, 187 length: usize,
168 stop: Stop, 188 stop: Stop,
169 reload: bool, 189 reload: bool,
190 restart: bool,
170 timeout: Timeout, 191 timeout: Timeout,
171 ) -> Result<(), Error> { 192 ) -> Result<(), Error> {
172 assert!(length < 256); 193 assert!(length < 256);
173 194
174 // Wait for any previous address sequence to end 195 if !restart {
175 // automatically. This could be up to 50% of a bus 196 // Wait for any previous address sequence to end
176 // cycle (ie. up to 0.5/freq) 197 // automatically. This could be up to 50% of a bus
177 while info.regs.cr2().read().start() { 198 // cycle (ie. up to 0.5/freq)
178 timeout.check()?; 199 while info.regs.cr2().read().start() {
179 } 200 timeout.check()?;
201 }
180 202
181 // Wait for the bus to be free 203 // Wait for the bus to be free
182 while info.regs.isr().read().busy() { 204 while info.regs.isr().read().busy() {
183 timeout.check()?; 205 timeout.check()?;
206 }
184 } 207 }
185 208
186 let reload = if reload {
187 i2c::vals::Reload::NOT_COMPLETED
188 } else {
189 i2c::vals::Reload::COMPLETED
190 };
191
192 // Set START and prepare to send `bytes`. The 209 // Set START and prepare to send `bytes`. The
193 // START bit can be set even if the bus is BUSY or 210 // START bit can be set even if the bus is BUSY or
194 // I2C is in slave mode. 211 // I2C is in slave mode.
@@ -199,28 +216,36 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
199 w.set_nbytes(length as u8); 216 w.set_nbytes(length as u8);
200 w.set_start(true); 217 w.set_start(true);
201 w.set_autoend(stop.autoend()); 218 w.set_autoend(stop.autoend());
202 w.set_reload(reload); 219 w.set_reload(Self::to_reload(reload));
203 }); 220 });
204 221
205 Ok(()) 222 Ok(())
206 } 223 }
207 224
208 fn reload(info: &'static Info, length: usize, will_reload: bool, timeout: Timeout) -> Result<(), Error> { 225 fn reload(
226 info: &'static Info,
227 length: usize,
228 will_reload: bool,
229 stop: Stop,
230 timeout: Timeout,
231 ) -> Result<(), Error> {
209 assert!(length < 256 && length > 0); 232 assert!(length < 256 && length > 0);
210 233
211 while !info.regs.isr().read().tcr() { 234 // Wait for either TCR (Transfer Complete Reload) or TC (Transfer Complete)
235 // TCR occurs when RELOAD=1, TC occurs when RELOAD=0
236 // Both indicate the peripheral is ready for the next transfer
237 loop {
238 let isr = info.regs.isr().read();
239 if isr.tcr() || isr.tc() {
240 break;
241 }
212 timeout.check()?; 242 timeout.check()?;
213 } 243 }
214 244
215 let will_reload = if will_reload {
216 i2c::vals::Reload::NOT_COMPLETED
217 } else {
218 i2c::vals::Reload::COMPLETED
219 };
220
221 info.regs.cr2().modify(|w| { 245 info.regs.cr2().modify(|w| {
222 w.set_nbytes(length as u8); 246 w.set_nbytes(length as u8);
223 w.set_reload(will_reload); 247 w.set_reload(Self::to_reload(will_reload));
248 w.set_autoend(stop.autoend());
224 }); 249 });
225 250
226 Ok(()) 251 Ok(())
@@ -364,7 +389,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
364 loop { 389 loop {
365 let isr = self.info.regs.isr().read(); 390 let isr = self.info.regs.isr().read();
366 self.error_occurred(&isr, timeout)?; 391 self.error_occurred(&isr, timeout)?;
367 if isr.tc() { 392 // Wait for either TC or TCR - both indicate transfer completion
393 // TCR occurs when RELOAD=1, TC occurs when RELOAD=0
394 if isr.tc() || isr.tcr() {
368 return Ok(()); 395 return Ok(());
369 } 396 }
370 timeout.check()?; 397 timeout.check()?;
@@ -391,14 +418,20 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
391 address, 418 address,
392 read.len().min(255), 419 read.len().min(255),
393 Stop::Automatic, 420 Stop::Automatic,
394 last_chunk_idx != 0, 421 last_chunk_idx != 0, // reload
395 restart, 422 restart,
396 timeout, 423 timeout,
397 )?; 424 )?;
398 425
399 for (number, chunk) in read.chunks_mut(255).enumerate() { 426 for (number, chunk) in read.chunks_mut(255).enumerate() {
400 if number != 0 { 427 if number != 0 {
401 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 428 Self::reload(
429 self.info,
430 chunk.len(),
431 number != last_chunk_idx,
432 Stop::Automatic,
433 timeout,
434 )?;
402 } 435 }
403 436
404 for byte in chunk { 437 for byte in chunk {
@@ -436,6 +469,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
436 write.len().min(255), 469 write.len().min(255),
437 Stop::Software, 470 Stop::Software,
438 last_chunk_idx != 0, 471 last_chunk_idx != 0,
472 false, // restart
439 timeout, 473 timeout,
440 ) { 474 ) {
441 if send_stop { 475 if send_stop {
@@ -446,7 +480,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
446 480
447 for (number, chunk) in write.chunks(255).enumerate() { 481 for (number, chunk) in write.chunks(255).enumerate() {
448 if number != 0 { 482 if number != 0 {
449 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 483 Self::reload(
484 self.info,
485 chunk.len(),
486 number != last_chunk_idx,
487 Stop::Software,
488 timeout,
489 )?;
450 } 490 }
451 491
452 for byte in chunk { 492 for byte in chunk {
@@ -502,9 +542,215 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
502 /// 542 ///
503 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 543 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
504 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 544 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
505 let _ = addr; 545 if operations.is_empty() {
506 let _ = operations; 546 return Err(Error::ZeroLengthTransfer);
507 todo!() 547 }
548
549 let address = addr.into();
550 let timeout = self.timeout();
551
552 // Group consecutive operations of the same type
553 let mut op_idx = 0;
554 let mut is_first_group = true;
555
556 while op_idx < operations.len() {
557 // Determine the type of current group and find all consecutive operations of same type
558 let is_read = matches!(operations[op_idx], Operation::Read(_));
559 let group_start = op_idx;
560
561 // Find end of this group (consecutive operations of same type)
562 while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read {
563 op_idx += 1;
564 }
565 let group_end = op_idx;
566 let is_last_group = op_idx >= operations.len();
567
568 // Execute this group of operations
569 if is_read {
570 self.execute_read_group(
571 address,
572 &mut operations[group_start..group_end],
573 is_first_group,
574 is_last_group,
575 timeout,
576 )?;
577 } else {
578 self.execute_write_group(
579 address,
580 &operations[group_start..group_end],
581 is_first_group,
582 is_last_group,
583 timeout,
584 )?;
585 }
586
587 is_first_group = false;
588 }
589
590 Ok(())
591 }
592
593 fn execute_write_group(
594 &mut self,
595 address: Address,
596 operations: &[Operation<'_>],
597 is_first_group: bool,
598 is_last_group: bool,
599 timeout: Timeout,
600 ) -> Result<(), Error> {
601 // Calculate total bytes across all operations in this group
602 let total_bytes = Self::total_operation_bytes(operations);
603
604 if total_bytes == 0 {
605 // Handle empty write group - just send address
606 if is_first_group {
607 Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?;
608 }
609 if is_last_group {
610 self.master_stop();
611 }
612 return Ok(());
613 }
614
615 let mut total_remaining = total_bytes;
616 let mut first_chunk = true;
617
618 for operation in operations {
619 if let Operation::Write(buffer) = operation {
620 for chunk in buffer.chunks(255) {
621 let chunk_len = chunk.len();
622 total_remaining -= chunk_len;
623 let is_last_chunk = total_remaining == 0;
624 let will_reload = !is_last_chunk;
625
626 if first_chunk {
627 // First chunk: initiate transfer
628 // If not first group, use RESTART instead of START
629 Self::master_write(
630 self.info,
631 address,
632 chunk_len,
633 Stop::Software,
634 will_reload,
635 !is_first_group,
636 timeout,
637 )?;
638 first_chunk = false;
639 } else {
640 // Subsequent chunks: use reload
641 // Always use Software stop for writes
642 Self::reload(self.info, chunk_len, will_reload, Stop::Software, timeout)?;
643 }
644
645 // Send data bytes
646 for byte in chunk {
647 self.wait_txis(timeout)?;
648 self.info.regs.txdr().write(|w| w.set_txdata(*byte));
649 }
650 }
651 }
652 }
653
654 // Wait for transfer to complete
655 if is_last_group {
656 self.wait_tc(timeout)?;
657 self.master_stop();
658 self.wait_stop(timeout)?;
659 } else {
660 // Wait for TC before next group (enables RESTART)
661 self.wait_tc(timeout)?;
662 }
663
664 Ok(())
665 }
666
667 fn execute_read_group(
668 &mut self,
669 address: Address,
670 operations: &mut [Operation<'_>],
671 is_first_group: bool,
672 is_last_group: bool,
673 timeout: Timeout,
674 ) -> Result<(), Error> {
675 // Calculate total bytes across all operations in this group
676 let total_bytes = Self::total_operation_bytes(operations);
677
678 if total_bytes == 0 {
679 // Handle empty read group
680 if is_first_group {
681 Self::master_read(
682 self.info,
683 address,
684 0,
685 if is_last_group { Stop::Automatic } else { Stop::Software },
686 false, // reload
687 !is_first_group,
688 timeout,
689 )?;
690 }
691 if is_last_group {
692 self.wait_stop(timeout)?;
693 }
694 return Ok(());
695 }
696
697 let mut total_remaining = total_bytes;
698 let mut first_chunk = true;
699
700 for operation in operations {
701 if let Operation::Read(buffer) = operation {
702 for chunk in buffer.chunks_mut(255) {
703 let chunk_len = chunk.len();
704 total_remaining -= chunk_len;
705 let is_last_chunk = total_remaining == 0;
706 let will_reload = !is_last_chunk;
707
708 if first_chunk {
709 // First chunk: initiate transfer
710 let stop = if is_last_group && is_last_chunk {
711 Stop::Automatic
712 } else {
713 Stop::Software
714 };
715
716 Self::master_read(
717 self.info,
718 address,
719 chunk_len,
720 stop,
721 will_reload,
722 !is_first_group, // restart if not first group
723 timeout,
724 )?;
725 first_chunk = false;
726 } else {
727 // Subsequent chunks: use reload
728 let stop = if is_last_group && is_last_chunk {
729 Stop::Automatic
730 } else {
731 Stop::Software
732 };
733 Self::reload(self.info, chunk_len, will_reload, stop, timeout)?;
734 }
735
736 // Receive data bytes
737 for byte in chunk {
738 self.wait_rxne(timeout)?;
739 *byte = self.info.regs.rxdr().read().rxdata();
740 }
741 }
742 }
743 }
744
745 // Wait for transfer to complete
746 if is_last_group {
747 self.wait_stop(timeout)?;
748 }
749 // For non-last read groups, don't wait for TC - the peripheral may hold SCL low
750 // in Software AUTOEND mode until the next START is issued. Just proceed directly
751 // to the next group which will issue RESTART and release the clock.
752
753 Ok(())
508 } 754 }
509 755
510 /// Blocking write multiple buffers. 756 /// Blocking write multiple buffers.
@@ -526,6 +772,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
526 first_length.min(255), 772 first_length.min(255),
527 Stop::Software, 773 Stop::Software,
528 (first_length > 255) || (last_slice_index != 0), 774 (first_length > 255) || (last_slice_index != 0),
775 false, // restart
529 timeout, 776 timeout,
530 ) { 777 ) {
531 self.master_stop(); 778 self.master_stop();
@@ -547,6 +794,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
547 self.info, 794 self.info,
548 slice_len.min(255), 795 slice_len.min(255),
549 (idx != last_slice_index) || (slice_len > 255), 796 (idx != last_slice_index) || (slice_len > 255),
797 Stop::Software,
550 timeout, 798 timeout,
551 ) { 799 ) {
552 if err != Error::Nack { 800 if err != Error::Nack {
@@ -562,6 +810,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
562 self.info, 810 self.info,
563 chunk.len(), 811 chunk.len(),
564 (number != last_chunk_idx) || (idx != last_slice_index), 812 (number != last_chunk_idx) || (idx != last_slice_index),
813 Stop::Software,
565 timeout, 814 timeout,
566 ) { 815 ) {
567 if err != Error::Nack { 816 if err != Error::Nack {
@@ -605,6 +854,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
605 first_slice: bool, 854 first_slice: bool,
606 last_slice: bool, 855 last_slice: bool,
607 send_stop: bool, 856 send_stop: bool,
857 restart: bool,
608 timeout: Timeout, 858 timeout: Timeout,
609 ) -> Result<(), Error> { 859 ) -> Result<(), Error> {
610 let total_len = write.len(); 860 let total_len = write.len();
@@ -671,10 +921,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
671 total_len.min(255), 921 total_len.min(255),
672 Stop::Software, 922 Stop::Software,
673 (total_len > 255) || !last_slice, 923 (total_len > 255) || !last_slice,
924 restart,
674 timeout, 925 timeout,
675 )?; 926 )?;
676 } else { 927 } else {
677 Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; 928 Self::reload(
929 self.info,
930 total_len.min(255),
931 (total_len > 255) || !last_slice,
932 Stop::Software,
933 timeout,
934 )?;
678 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 935 self.info.regs.cr1().modify(|w| w.set_tcie(true));
679 } 936 }
680 } else if !(isr.tcr() || isr.tc()) { 937 } else if !(isr.tcr() || isr.tc()) {
@@ -683,9 +940,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
683 } else if remaining_len == 0 { 940 } else if remaining_len == 0 {
684 return Poll::Ready(Ok(())); 941 return Poll::Ready(Ok(()));
685 } else { 942 } else {
686 let last_piece = (remaining_len <= 255) && last_slice; 943 if let Err(e) = Self::reload(
687 944 self.info,
688 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { 945 remaining_len.min(255),
946 (remaining_len > 255) || !last_slice,
947 Stop::Software,
948 timeout,
949 ) {
689 return Poll::Ready(Err(e)); 950 return Poll::Ready(Err(e));
690 } 951 }
691 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 952 self.info.regs.cr1().modify(|w| w.set_tcie(true));
@@ -697,10 +958,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
697 .await?; 958 .await?;
698 959
699 dma_transfer.await; 960 dma_transfer.await;
700 if last_slice { 961
701 // This should be done already 962 // Always wait for TC after DMA completes - needed for consecutive buffers
702 self.wait_tc(timeout)?; 963 self.wait_tc(timeout)?;
703 }
704 964
705 if last_slice & send_stop { 965 if last_slice & send_stop {
706 self.master_stop(); 966 self.master_stop();
@@ -775,7 +1035,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
775 address, 1035 address,
776 total_len.min(255), 1036 total_len.min(255),
777 Stop::Automatic, 1037 Stop::Automatic,
778 total_len > 255, 1038 total_len > 255, // reload
779 restart, 1039 restart,
780 timeout, 1040 timeout,
781 )?; 1041 )?;
@@ -783,12 +1043,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
783 return Poll::Ready(Ok(())); 1043 return Poll::Ready(Ok(()));
784 } 1044 }
785 } else if isr.tcr() { 1045 } else if isr.tcr() {
786 // poll_fn was woken without an interrupt present 1046 // Transfer Complete Reload - need to set up next chunk
787 return Poll::Pending;
788 } else {
789 let last_piece = remaining_len <= 255; 1047 let last_piece = remaining_len <= 255;
790 1048
791 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { 1049 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Automatic, timeout) {
792 return Poll::Ready(Err(e)); 1050 return Poll::Ready(Err(e));
793 } 1051 }
794 // Return here if we are on last chunk, 1052 // Return here if we are on last chunk,
@@ -797,6 +1055,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
797 return Poll::Ready(Ok(())); 1055 return Poll::Ready(Ok(()));
798 } 1056 }
799 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 1057 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1058 } else {
1059 // poll_fn was woken without TCR interrupt
1060 return Poll::Pending;
800 } 1061 }
801 1062
802 remaining_len = remaining_len.saturating_sub(255); 1063 remaining_len = remaining_len.saturating_sub(255);
@@ -814,12 +1075,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
814 1075
815 /// Write. 1076 /// Write.
816 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 1077 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
1078 let _scoped_block_stop = self.info.rcc.block_stop();
817 let timeout = self.timeout(); 1079 let timeout = self.timeout();
818 if write.is_empty() { 1080 if write.is_empty() {
819 self.write_internal(address.into(), write, true, timeout) 1081 self.write_internal(address.into(), write, true, timeout)
820 } else { 1082 } else {
821 timeout 1083 timeout
822 .with(self.write_dma_internal(address.into(), write, true, true, true, timeout)) 1084 .with(self.write_dma_internal(address.into(), write, true, true, true, false, timeout))
823 .await 1085 .await
824 } 1086 }
825 } 1087 }
@@ -828,21 +1090,30 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
828 /// 1090 ///
829 /// The buffers are concatenated in a single write transaction. 1091 /// The buffers are concatenated in a single write transaction.
830 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { 1092 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> {
1093 let _scoped_block_stop = self.info.rcc.block_stop();
831 let timeout = self.timeout(); 1094 let timeout = self.timeout();
832 1095
833 if write.is_empty() { 1096 if write.is_empty() {
834 return Err(Error::ZeroLengthTransfer); 1097 return Err(Error::ZeroLengthTransfer);
835 } 1098 }
836 let mut iter = write.iter();
837 1099
1100 let mut iter = write.iter();
838 let mut first = true; 1101 let mut first = true;
839 let mut current = iter.next(); 1102 let mut current = iter.next();
1103
840 while let Some(c) = current { 1104 while let Some(c) = current {
841 let next = iter.next(); 1105 let next = iter.next();
842 let is_last = next.is_none(); 1106 let is_last = next.is_none();
843 1107
844 let fut = self.write_dma_internal(address, c, first, is_last, is_last, timeout); 1108 let fut = self.write_dma_internal(
1109 address, c, first, // first_slice
1110 is_last, // last_slice
1111 is_last, // send_stop (only on last buffer)
1112 false, // restart (false for all - they're one continuous write)
1113 timeout,
1114 );
845 timeout.with(fut).await?; 1115 timeout.with(fut).await?;
1116
846 first = false; 1117 first = false;
847 current = next; 1118 current = next;
848 } 1119 }
@@ -851,6 +1122,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
851 1122
852 /// Read. 1123 /// Read.
853 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 1124 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
1125 let _scoped_block_stop = self.info.rcc.block_stop();
854 let timeout = self.timeout(); 1126 let timeout = self.timeout();
855 1127
856 if buffer.is_empty() { 1128 if buffer.is_empty() {
@@ -863,12 +1135,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
863 1135
864 /// Write, restart, read. 1136 /// Write, restart, read.
865 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 1137 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
1138 let _scoped_block_stop = self.info.rcc.block_stop();
866 let timeout = self.timeout(); 1139 let timeout = self.timeout();
867 1140
868 if write.is_empty() { 1141 if write.is_empty() {
869 self.write_internal(address.into(), write, false, timeout)?; 1142 self.write_internal(address.into(), write, false, timeout)?;
870 } else { 1143 } else {
871 let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout); 1144 let fut = self.write_dma_internal(address.into(), write, true, true, false, false, timeout);
872 timeout.with(fut).await?; 1145 timeout.with(fut).await?;
873 } 1146 }
874 1147
@@ -888,9 +1161,299 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
888 /// 1161 ///
889 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 1162 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
890 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 1163 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
891 let _ = addr; 1164 let _scoped_block_stop = self.info.rcc.block_stop();
892 let _ = operations; 1165 if operations.is_empty() {
893 todo!() 1166 return Err(Error::ZeroLengthTransfer);
1167 }
1168
1169 let address = addr.into();
1170 let timeout = self.timeout();
1171
1172 // Group consecutive operations of the same type
1173 let mut op_idx = 0;
1174 let mut is_first_group = true;
1175
1176 while op_idx < operations.len() {
1177 // Determine the type of current group and find all consecutive operations of same type
1178 let is_read = matches!(operations[op_idx], Operation::Read(_));
1179 let group_start = op_idx;
1180
1181 // Find end of this group (consecutive operations of same type)
1182 while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read {
1183 op_idx += 1;
1184 }
1185 let group_end = op_idx;
1186 let is_last_group = op_idx >= operations.len();
1187
1188 // Execute this group of operations
1189 if is_read {
1190 self.execute_read_group_async(
1191 address,
1192 &mut operations[group_start..group_end],
1193 is_first_group,
1194 is_last_group,
1195 timeout,
1196 )
1197 .await?;
1198 } else {
1199 self.execute_write_group_async(
1200 address,
1201 &operations[group_start..group_end],
1202 is_first_group,
1203 is_last_group,
1204 timeout,
1205 )
1206 .await?;
1207 }
1208
1209 is_first_group = false;
1210 }
1211
1212 Ok(())
1213 }
1214
1215 async fn execute_write_group_async(
1216 &mut self,
1217 address: Address,
1218 operations: &[Operation<'_>],
1219 is_first_group: bool,
1220 is_last_group: bool,
1221 timeout: Timeout,
1222 ) -> Result<(), Error> {
1223 // Calculate total bytes across all operations in this group
1224 let total_bytes = Self::total_operation_bytes(operations);
1225
1226 if total_bytes == 0 {
1227 // Handle empty write group using blocking call
1228 if is_first_group {
1229 Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?;
1230 }
1231 if is_last_group {
1232 self.master_stop();
1233 }
1234 return Ok(());
1235 }
1236
1237 // Collect all write buffers
1238 let mut write_buffers: heapless::Vec<&[u8], 16> = heapless::Vec::new();
1239 for operation in operations {
1240 if let Operation::Write(buffer) = operation {
1241 if !buffer.is_empty() {
1242 let _ = write_buffers.push(buffer);
1243 }
1244 }
1245 }
1246
1247 if write_buffers.is_empty() {
1248 return Ok(());
1249 }
1250
1251 // Send each buffer using DMA
1252 let num_buffers = write_buffers.len();
1253 for (idx, buffer) in write_buffers.iter().enumerate() {
1254 let is_first_buffer = idx == 0;
1255 let is_last_buffer = idx == num_buffers - 1;
1256
1257 let fut = self.write_dma_internal(
1258 address,
1259 buffer,
1260 is_first_buffer, // first_slice
1261 is_last_buffer, // last_slice
1262 is_last_buffer && is_last_group, // send_stop
1263 is_first_buffer && !is_first_group, // restart (only for first buffer if not first group)
1264 timeout,
1265 );
1266 timeout.with(fut).await?;
1267 }
1268
1269 Ok(())
1270 }
1271
1272 async fn execute_read_group_async(
1273 &mut self,
1274 address: Address,
1275 operations: &mut [Operation<'_>],
1276 is_first_group: bool,
1277 is_last_group: bool,
1278 timeout: Timeout,
1279 ) -> Result<(), Error> {
1280 // Calculate total bytes across all operations in this group
1281 let total_bytes = Self::total_operation_bytes(operations);
1282
1283 if total_bytes == 0 {
1284 // Handle empty read group using blocking call
1285 if is_first_group {
1286 Self::master_read(
1287 self.info,
1288 address,
1289 0,
1290 if is_last_group { Stop::Automatic } else { Stop::Software },
1291 false, // reload
1292 !is_first_group,
1293 timeout,
1294 )?;
1295 }
1296 if is_last_group {
1297 self.wait_stop(timeout)?;
1298 }
1299 return Ok(());
1300 }
1301
1302 // Use DMA for read operations - need to handle multiple buffers
1303 let restart = !is_first_group;
1304 let mut total_remaining = total_bytes;
1305 let mut is_first_in_group = true;
1306
1307 for operation in operations {
1308 if let Operation::Read(buffer) = operation {
1309 if buffer.is_empty() {
1310 // Skip empty buffers
1311 continue;
1312 }
1313
1314 let buf_len = buffer.len();
1315 total_remaining -= buf_len;
1316 let is_last_in_group = total_remaining == 0;
1317
1318 // Perform DMA read
1319 if is_first_in_group {
1320 // First buffer: use read_dma_internal which handles restart properly
1321 // Only use Automatic stop if this is the last buffer in the last group
1322 let stop_mode = if is_last_group && is_last_in_group {
1323 Stop::Automatic
1324 } else {
1325 Stop::Software
1326 };
1327
1328 // We need a custom DMA read that respects our stop mode
1329 self.read_dma_group_internal(address, buffer, restart, stop_mode, timeout)
1330 .await?;
1331 is_first_in_group = false;
1332 } else {
1333 // Subsequent buffers: need to reload and continue
1334 let stop_mode = if is_last_group && is_last_in_group {
1335 Stop::Automatic
1336 } else {
1337 Stop::Software
1338 };
1339
1340 self.read_dma_group_internal(
1341 address, buffer, false, // no restart for subsequent buffers in same group
1342 stop_mode, timeout,
1343 )
1344 .await?;
1345 }
1346 }
1347 }
1348
1349 // Wait for transfer to complete
1350 if is_last_group {
1351 self.wait_stop(timeout)?;
1352 }
1353
1354 Ok(())
1355 }
1356
1357 /// Internal DMA read helper for transaction groups
1358 async fn read_dma_group_internal(
1359 &mut self,
1360 address: Address,
1361 buffer: &mut [u8],
1362 restart: bool,
1363 stop_mode: Stop,
1364 timeout: Timeout,
1365 ) -> Result<(), Error> {
1366 let total_len = buffer.len();
1367
1368 let dma_transfer = unsafe {
1369 let regs = self.info.regs;
1370 regs.cr1().modify(|w| {
1371 w.set_rxdmaen(true);
1372 w.set_tcie(true);
1373 w.set_nackie(true);
1374 w.set_errie(true);
1375 });
1376 let src = regs.rxdr().as_ptr() as *mut u8;
1377
1378 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1379 };
1380
1381 let mut remaining_len = total_len;
1382
1383 let on_drop = OnDrop::new(|| {
1384 let regs = self.info.regs;
1385 regs.cr1().modify(|w| {
1386 w.set_rxdmaen(false);
1387 w.set_tcie(false);
1388 w.set_nackie(false);
1389 w.set_errie(false);
1390 });
1391 regs.icr().write(|w| {
1392 w.set_nackcf(true);
1393 w.set_berrcf(true);
1394 w.set_arlocf(true);
1395 w.set_ovrcf(true);
1396 });
1397 });
1398
1399 poll_fn(|cx| {
1400 self.state.waker.register(cx.waker());
1401
1402 let isr = self.info.regs.isr().read();
1403
1404 if isr.nackf() {
1405 return Poll::Ready(Err(Error::Nack));
1406 }
1407 if isr.arlo() {
1408 return Poll::Ready(Err(Error::Arbitration));
1409 }
1410 if isr.berr() {
1411 return Poll::Ready(Err(Error::Bus));
1412 }
1413 if isr.ovr() {
1414 return Poll::Ready(Err(Error::Overrun));
1415 }
1416
1417 if remaining_len == total_len {
1418 Self::master_read(
1419 self.info,
1420 address,
1421 total_len.min(255),
1422 stop_mode,
1423 total_len > 255, // reload
1424 restart,
1425 timeout,
1426 )?;
1427 if total_len <= 255 {
1428 return Poll::Ready(Ok(()));
1429 }
1430 } else if isr.tcr() {
1431 // Transfer Complete Reload - need to set up next chunk
1432 let last_piece = remaining_len <= 255;
1433
1434 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, stop_mode, timeout) {
1435 return Poll::Ready(Err(e));
1436 }
1437 // Return here if we are on last chunk,
1438 // end of transfer will be awaited with the DMA below
1439 if last_piece {
1440 return Poll::Ready(Ok(()));
1441 }
1442 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1443 } else {
1444 // poll_fn was woken without TCR interrupt
1445 return Poll::Pending;
1446 }
1447
1448 remaining_len = remaining_len.saturating_sub(255);
1449 Poll::Pending
1450 })
1451 .await?;
1452
1453 dma_transfer.await;
1454 drop(on_drop);
1455
1456 Ok(())
894 } 1457 }
895} 1458}
896 1459
@@ -1028,7 +1591,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1028 if number == 0 { 1591 if number == 0 {
1029 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1592 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1030 } else { 1593 } else {
1031 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1594 Self::reload(
1595 self.info,
1596 chunk.len(),
1597 number != last_chunk_idx,
1598 Stop::Software,
1599 timeout,
1600 )?;
1032 } 1601 }
1033 1602
1034 let mut index = 0; 1603 let mut index = 0;
@@ -1036,7 +1605,8 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1036 for byte in chunk { 1605 for byte in chunk {
1037 // Wait until we have received something 1606 // Wait until we have received something
1038 match self.wait_rxne(timeout) { 1607 match self.wait_rxne(timeout) {
1039 Ok(ReceiveResult::StopReceived) | Ok(ReceiveResult::NewStart) => { 1608 Ok(ReceiveResult::StopReceived) => {}
1609 Ok(ReceiveResult::NewStart) => {
1040 trace!("--- Slave RX transmission end (early)"); 1610 trace!("--- Slave RX transmission end (early)");
1041 return Ok(total_len - remaining_len); // Return N bytes read 1611 return Ok(total_len - remaining_len); // Return N bytes read
1042 } 1612 }
@@ -1077,7 +1647,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1077 if number == 0 { 1647 if number == 0 {
1078 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1648 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1079 } else { 1649 } else {
1080 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1650 Self::reload(
1651 self.info,
1652 chunk.len(),
1653 number != last_chunk_idx,
1654 Stop::Software,
1655 timeout,
1656 )?;
1081 } 1657 }
1082 1658
1083 let mut index = 0; 1659 let mut index = 0;
@@ -1104,42 +1680,50 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1104 1680
1105 /// Listen for incoming I2C messages. 1681 /// Listen for incoming I2C messages.
1106 /// 1682 ///
1107 /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. 1683 /// This method blocks until the slave address is matched by a master.
1108 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { 1684 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
1109 let state = self.state; 1685 let timeout = self.timeout();
1686
1110 self.info.regs.cr1().modify(|reg| { 1687 self.info.regs.cr1().modify(|reg| {
1111 reg.set_addrie(true); 1688 reg.set_addrie(true);
1112 trace!("Enable ADDRIE"); 1689 trace!("Enable ADDRIE");
1113 }); 1690 });
1114 1691
1115 poll_fn(|cx| { 1692 loop {
1116 state.waker.register(cx.waker());
1117 let isr = self.info.regs.isr().read(); 1693 let isr = self.info.regs.isr().read();
1118 if !isr.addr() { 1694 if isr.addr() {
1119 Poll::Pending 1695 break;
1120 } else {
1121 trace!("ADDR triggered (address match)");
1122 // we do not clear the address flag here as it will be cleared by the dma read/write
1123 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
1124 match isr.dir() {
1125 i2c::vals::Dir::WRITE => {
1126 trace!("DIR: write");
1127 Poll::Ready(Ok(SlaveCommand {
1128 kind: SlaveCommandKind::Write,
1129 address: self.determine_matched_address()?,
1130 }))
1131 }
1132 i2c::vals::Dir::READ => {
1133 trace!("DIR: read");
1134 Poll::Ready(Ok(SlaveCommand {
1135 kind: SlaveCommandKind::Read,
1136 address: self.determine_matched_address()?,
1137 }))
1138 }
1139 }
1140 } 1696 }
1141 }) 1697 timeout.check()?;
1142 .await 1698 }
1699
1700 trace!("ADDR triggered (address match)");
1701
1702 // we do not clear the address flag here as it will be cleared by the dma read/write
1703 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
1704 self.slave_command()
1705 }
1706
1707 /// Determine the received slave command.
1708 fn slave_command(&self) -> Result<SlaveCommand, Error> {
1709 let isr = self.info.regs.isr().read();
1710
1711 match isr.dir() {
1712 i2c::vals::Dir::WRITE => {
1713 trace!("DIR: write");
1714 Ok(SlaveCommand {
1715 kind: SlaveCommandKind::Write,
1716 address: self.determine_matched_address()?,
1717 })
1718 }
1719 i2c::vals::Dir::READ => {
1720 trace!("DIR: read");
1721 Ok(SlaveCommand {
1722 kind: SlaveCommandKind::Read,
1723 address: self.determine_matched_address()?,
1724 })
1725 }
1726 }
1143 } 1727 }
1144 1728
1145 /// Respond to a write command. 1729 /// Respond to a write command.
@@ -1158,16 +1742,44 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1158} 1742}
1159 1743
1160impl<'d> I2c<'d, Async, MultiMaster> { 1744impl<'d> I2c<'d, Async, MultiMaster> {
1745 /// Listen for incoming I2C messages.
1746 ///
1747 /// The listen method is an asynchronous method but it does not require DMA to be asynchronous.
1748 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
1749 let _scoped_block_stop = self.info.rcc.block_stop();
1750 let state = self.state;
1751 self.info.regs.cr1().modify(|reg| {
1752 reg.set_addrie(true);
1753 trace!("Enable ADDRIE");
1754 });
1755
1756 poll_fn(|cx| {
1757 state.waker.register(cx.waker());
1758 let isr = self.info.regs.isr().read();
1759 if !isr.addr() {
1760 Poll::Pending
1761 } else {
1762 trace!("ADDR triggered (address match)");
1763 // we do not clear the address flag here as it will be cleared by the dma read/write
1764 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
1765 Poll::Ready(self.slave_command())
1766 }
1767 })
1768 .await
1769 }
1770
1161 /// Respond to a write command. 1771 /// Respond to a write command.
1162 /// 1772 ///
1163 /// Returns the total number of bytes received. 1773 /// Returns the total number of bytes received.
1164 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 1774 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1775 let _scoped_block_stop = self.info.rcc.block_stop();
1165 let timeout = self.timeout(); 1776 let timeout = self.timeout();
1166 timeout.with(self.read_dma_internal_slave(buffer, timeout)).await 1777 timeout.with(self.read_dma_internal_slave(buffer, timeout)).await
1167 } 1778 }
1168 1779
1169 /// Respond to a read request from an I2C master. 1780 /// Respond to a read request from an I2C master.
1170 pub async fn respond_to_read(&mut self, write: &[u8]) -> Result<SendStatus, Error> { 1781 pub async fn respond_to_read(&mut self, write: &[u8]) -> Result<SendStatus, Error> {
1782 let _scoped_block_stop = self.info.rcc.block_stop();
1171 let timeout = self.timeout(); 1783 let timeout = self.timeout();
1172 timeout.with(self.write_dma_internal_slave(write, timeout)).await 1784 timeout.with(self.write_dma_internal_slave(write, timeout)).await
1173 } 1785 }
@@ -1181,7 +1793,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1181 1793
1182 let regs = self.info.regs; 1794 let regs = self.info.regs;
1183 1795
1184 let dma_transfer = unsafe { 1796 let mut dma_transfer = unsafe {
1185 regs.cr1().modify(|w| { 1797 regs.cr1().modify(|w| {
1186 w.set_rxdmaen(true); 1798 w.set_rxdmaen(true);
1187 w.set_stopie(true); 1799 w.set_stopie(true);
@@ -1213,13 +1825,20 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1213 Poll::Pending 1825 Poll::Pending
1214 } else if isr.tcr() { 1826 } else if isr.tcr() {
1215 let is_last_slice = remaining_len <= 255; 1827 let is_last_slice = remaining_len <= 255;
1216 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { 1828 if let Err(e) = Self::reload(
1829 self.info,
1830 remaining_len.min(255),
1831 !is_last_slice,
1832 Stop::Software,
1833 timeout,
1834 ) {
1217 return Poll::Ready(Err(e)); 1835 return Poll::Ready(Err(e));
1218 } 1836 }
1219 remaining_len = remaining_len.saturating_sub(255); 1837 remaining_len = remaining_len.saturating_sub(255);
1220 regs.cr1().modify(|w| w.set_tcie(true)); 1838 regs.cr1().modify(|w| w.set_tcie(true));
1221 Poll::Pending 1839 Poll::Pending
1222 } else if isr.stopf() { 1840 } else if isr.stopf() {
1841 remaining_len = remaining_len.saturating_add(dma_transfer.get_remaining_transfers() as usize);
1223 regs.icr().write(|reg| reg.set_stopcf(true)); 1842 regs.icr().write(|reg| reg.set_stopcf(true));
1224 let poll = Poll::Ready(Ok(total_len - remaining_len)); 1843 let poll = Poll::Ready(Ok(total_len - remaining_len));
1225 poll 1844 poll
@@ -1229,6 +1848,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1229 }) 1848 })
1230 .await?; 1849 .await?;
1231 1850
1851 dma_transfer.request_pause();
1232 dma_transfer.await; 1852 dma_transfer.await;
1233 1853
1234 drop(on_drop); 1854 drop(on_drop);
@@ -1258,7 +1878,8 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1258 w.set_txdmaen(false); 1878 w.set_txdmaen(false);
1259 w.set_stopie(false); 1879 w.set_stopie(false);
1260 w.set_tcie(false); 1880 w.set_tcie(false);
1261 }) 1881 });
1882 regs.isr().write(|w| w.set_txe(true));
1262 }); 1883 });
1263 1884
1264 let state = self.state; 1885 let state = self.state;
@@ -1274,13 +1895,24 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1274 Poll::Pending 1895 Poll::Pending
1275 } else if isr.tcr() { 1896 } else if isr.tcr() {
1276 let is_last_slice = remaining_len <= 255; 1897 let is_last_slice = remaining_len <= 255;
1277 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { 1898 if let Err(e) = Self::reload(
1899 self.info,
1900 remaining_len.min(255),
1901 !is_last_slice,
1902 Stop::Software,
1903 timeout,
1904 ) {
1278 return Poll::Ready(Err(e)); 1905 return Poll::Ready(Err(e));
1279 } 1906 }
1280 remaining_len = remaining_len.saturating_sub(255); 1907 remaining_len = remaining_len.saturating_sub(255);
1281 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 1908 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1282 Poll::Pending 1909 Poll::Pending
1283 } else if isr.stopf() { 1910 } else if isr.stopf() {
1911 let mut leftover_bytes = dma_transfer.get_remaining_transfers();
1912 if !self.info.regs.isr().read().txe() {
1913 leftover_bytes = leftover_bytes.saturating_add(1);
1914 }
1915 remaining_len = remaining_len.saturating_add(leftover_bytes as usize);
1284 self.info.regs.icr().write(|reg| reg.set_stopcf(true)); 1916 self.info.regs.icr().write(|reg| reg.set_stopcf(true));
1285 if remaining_len > 0 { 1917 if remaining_len > 0 {
1286 dma_transfer.request_pause(); 1918 dma_transfer.request_pause();
@@ -1294,6 +1926,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1294 }) 1926 })
1295 .await?; 1927 .await?;
1296 1928
1929 dma_transfer.request_pause();
1297 dma_transfer.await; 1930 dma_transfer.await;
1298 1931
1299 drop(on_drop); 1932 drop(on_drop);
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index b6d3daf54..df077a3ae 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -3,12 +3,13 @@
3use embassy_futures::join::join; 3use embassy_futures::join::join;
4use stm32_metapac::spi::vals; 4use stm32_metapac::spi::vals;
5 5
6use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; 6use crate::Peri;
7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer};
7use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
8use crate::mode::Async; 9use crate::mode::Async;
10use crate::spi::mode::Master;
9use crate::spi::{Config as SpiConfig, RegsExt as _, *}; 11use crate::spi::{Config as SpiConfig, RegsExt as _, *};
10use crate::time::Hertz; 12use crate::time::Hertz;
11use crate::Peri;
12 13
13/// I2S mode 14/// I2S mode
14#[derive(Copy, Clone)] 15#[derive(Copy, Clone)]
@@ -225,7 +226,7 @@ impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
225pub struct I2S<'d, W: Word> { 226pub struct I2S<'d, W: Word> {
226 #[allow(dead_code)] 227 #[allow(dead_code)]
227 mode: Mode, 228 mode: Mode,
228 spi: Spi<'d, Async>, 229 spi: Spi<'d, Async, Master>,
229 txsd: Option<Peri<'d, AnyPin>>, 230 txsd: Option<Peri<'d, AnyPin>>,
230 rxsd: Option<Peri<'d, AnyPin>>, 231 rxsd: Option<Peri<'d, AnyPin>>,
231 ws: Option<Peri<'d, AnyPin>>, 232 ws: Option<Peri<'d, AnyPin>>,
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 670d8332c..74ce0b29e 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,13 +1,16 @@
1//! Inter-Process Communication Controller (IPCC) 1//! Inter-Process Communication Controller (IPCC)
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::marker::PhantomData;
5use core::sync::atomic::{Ordering, compiler_fence};
5use core::task::Poll; 6use core::task::Poll;
6 7
8use embassy_hal_internal::Peri;
7use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
8 10
9use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
10use crate::peripherals::IPCC; 12use crate::peripherals::IPCC;
13use crate::rcc::SealedRccPeripheral;
11use crate::{interrupt, rcc}; 14use crate::{interrupt, rcc};
12 15
13/// Interrupt handler. 16/// Interrupt handler.
@@ -17,25 +20,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive
17 unsafe fn on_interrupt() { 20 unsafe fn on_interrupt() {
18 let regs = IPCC::regs(); 21 let regs = IPCC::regs();
19 22
20 let channels = [
21 IpccChannel::Channel1,
22 IpccChannel::Channel2,
23 IpccChannel::Channel3,
24 IpccChannel::Channel4,
25 IpccChannel::Channel5,
26 IpccChannel::Channel6,
27 ];
28
29 // Status register gives channel occupied status. For rx, use cpu1. 23 // Status register gives channel occupied status. For rx, use cpu1.
30 let sr = regs.cpu(1).sr().read(); 24 let sr = regs.cpu(1).sr().read();
31 regs.cpu(0).mr().modify(|w| { 25 regs.cpu(0).mr().modify(|w| {
32 for channel in channels { 26 for index in 0..5 {
33 if sr.chf(channel as usize) { 27 if sr.chf(index as usize) {
34 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 28 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
35 w.set_chom(channel as usize, true); 29 w.set_chom(index as usize, true);
36 30
37 // There shouldn't be a race because the channel is masked only if the interrupt has fired 31 // There shouldn't be a race because the channel is masked only if the interrupt has fired
38 IPCC::state().rx_waker_for(channel).wake(); 32 IPCC::state().rx_waker_for(index).wake();
39 } 33 }
40 } 34 }
41 }) 35 })
@@ -49,25 +43,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi
49 unsafe fn on_interrupt() { 43 unsafe fn on_interrupt() {
50 let regs = IPCC::regs(); 44 let regs = IPCC::regs();
51 45
52 let channels = [
53 IpccChannel::Channel1,
54 IpccChannel::Channel2,
55 IpccChannel::Channel3,
56 IpccChannel::Channel4,
57 IpccChannel::Channel5,
58 IpccChannel::Channel6,
59 ];
60
61 // Status register gives channel occupied status. For tx, use cpu0. 46 // Status register gives channel occupied status. For tx, use cpu0.
62 let sr = regs.cpu(0).sr().read(); 47 let sr = regs.cpu(0).sr().read();
63 regs.cpu(0).mr().modify(|w| { 48 regs.cpu(0).mr().modify(|w| {
64 for channel in channels { 49 for index in 0..5 {
65 if !sr.chf(channel as usize) { 50 if !sr.chf(index as usize) {
66 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 51 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
67 w.set_chfm(channel as usize, true); 52 w.set_chfm(index as usize, true);
68 53
69 // There shouldn't be a race because the channel is masked only if the interrupt has fired 54 // There shouldn't be a race because the channel is masked only if the interrupt has fired
70 IPCC::state().tx_waker_for(channel).wake(); 55 IPCC::state().tx_waker_for(index).wake();
71 } 56 }
72 } 57 }
73 }); 58 });
@@ -82,76 +67,57 @@ pub struct Config {
82 // reserved for future use 67 // reserved for future use
83} 68}
84 69
85/// Channel. 70/// IPCC TX Channel
86#[allow(missing_docs)] 71pub struct IpccTxChannel<'a> {
87#[derive(Debug, Clone, Copy)] 72 index: u8,
88#[repr(C)] 73 _lifetime: PhantomData<&'a mut usize>,
89pub enum IpccChannel {
90 Channel1 = 0,
91 Channel2 = 1,
92 Channel3 = 2,
93 Channel4 = 3,
94 Channel5 = 4,
95 Channel6 = 5,
96} 74}
97 75
98/// IPCC driver. 76impl<'a> IpccTxChannel<'a> {
99pub struct Ipcc; 77 pub(crate) const fn new(index: u8) -> Self {
100 78 core::assert!(index < 6);
101impl Ipcc {
102 /// Enable IPCC.
103 pub fn enable(_config: Config) {
104 rcc::enable_and_reset::<IPCC>();
105 IPCC::set_cpu2(true);
106
107 let regs = IPCC::regs();
108 79
109 regs.cpu(0).cr().modify(|w| { 80 Self {
110 w.set_rxoie(true); 81 index: index,
111 w.set_txfie(true); 82 _lifetime: PhantomData,
112 }); 83 }
113
114 // enable interrupts
115 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
116 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
117
118 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
119 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
120 } 84 }
121 85
122 /// Send data to an IPCC channel. The closure is called to write the data when appropriate. 86 /// Send data to an IPCC channel. The closure is called to write the data when appropriate.
123 pub async fn send(channel: IpccChannel, f: impl FnOnce()) { 87 pub async fn send(&mut self, f: impl FnOnce()) {
88 let _scoped_block_stop = IPCC::RCC_INFO.block_stop();
124 let regs = IPCC::regs(); 89 let regs = IPCC::regs();
125 90
126 Self::flush(channel).await; 91 self.flush().await;
127 92
128 f(); 93 f();
129 94
130 compiler_fence(Ordering::SeqCst); 95 compiler_fence(Ordering::SeqCst);
131 96
132 trace!("ipcc: ch {}: send data", channel as u8); 97 trace!("ipcc: ch {}: send data", self.index as u8);
133 regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)); 98 regs.cpu(0).scr().write(|w| w.set_chs(self.index as usize, true));
134 } 99 }
135 100
136 /// Wait for the tx channel to become clear 101 /// Wait for the tx channel to become clear
137 pub async fn flush(channel: IpccChannel) { 102 pub async fn flush(&mut self) {
103 let _scoped_block_stop = IPCC::RCC_INFO.block_stop();
138 let regs = IPCC::regs(); 104 let regs = IPCC::regs();
139 105
140 // This is a race, but is nice for debugging 106 // This is a race, but is nice for debugging
141 if regs.cpu(0).sr().read().chf(channel as usize) { 107 if regs.cpu(0).sr().read().chf(self.index as usize) {
142 trace!("ipcc: ch {}: wait for tx free", channel as u8); 108 trace!("ipcc: ch {}: wait for tx free", self.index as u8);
143 } 109 }
144 110
145 poll_fn(|cx| { 111 poll_fn(|cx| {
146 IPCC::state().tx_waker_for(channel).register(cx.waker()); 112 IPCC::state().tx_waker_for(self.index).register(cx.waker());
147 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt 113 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
148 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false)); 114 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, false));
149 115
150 compiler_fence(Ordering::SeqCst); 116 compiler_fence(Ordering::SeqCst);
151 117
152 if !regs.cpu(0).sr().read().chf(channel as usize) { 118 if !regs.cpu(0).sr().read().chf(self.index as usize) {
153 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 119 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
154 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); 120 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, true));
155 121
156 Poll::Ready(()) 122 Poll::Ready(())
157 } else { 123 } else {
@@ -160,27 +126,45 @@ impl Ipcc {
160 }) 126 })
161 .await; 127 .await;
162 } 128 }
129}
130
131/// IPCC RX Channel
132pub struct IpccRxChannel<'a> {
133 index: u8,
134 _lifetime: PhantomData<&'a mut usize>,
135}
136
137impl<'a> IpccRxChannel<'a> {
138 pub(crate) const fn new(index: u8) -> Self {
139 core::assert!(index < 6);
140
141 Self {
142 index: index,
143 _lifetime: PhantomData,
144 }
145 }
163 146
164 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate. 147 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
165 pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R { 148 pub async fn receive<R>(&mut self, mut f: impl FnMut() -> Option<R>) -> R {
149 let _scoped_block_stop = IPCC::RCC_INFO.block_stop();
166 let regs = IPCC::regs(); 150 let regs = IPCC::regs();
167 151
168 loop { 152 loop {
169 // This is a race, but is nice for debugging 153 // This is a race, but is nice for debugging
170 if !regs.cpu(1).sr().read().chf(channel as usize) { 154 if !regs.cpu(1).sr().read().chf(self.index as usize) {
171 trace!("ipcc: ch {}: wait for rx occupied", channel as u8); 155 trace!("ipcc: ch {}: wait for rx occupied", self.index as u8);
172 } 156 }
173 157
174 poll_fn(|cx| { 158 poll_fn(|cx| {
175 IPCC::state().rx_waker_for(channel).register(cx.waker()); 159 IPCC::state().rx_waker_for(self.index).register(cx.waker());
176 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt 160 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
177 regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false)); 161 regs.cpu(0).mr().modify(|w| w.set_chom(self.index as usize, false));
178 162
179 compiler_fence(Ordering::SeqCst); 163 compiler_fence(Ordering::SeqCst);
180 164
181 if regs.cpu(1).sr().read().chf(channel as usize) { 165 if regs.cpu(1).sr().read().chf(self.index as usize) {
182 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 166 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
183 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); 167 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, true));
184 168
185 Poll::Ready(()) 169 Poll::Ready(())
186 } else { 170 } else {
@@ -189,21 +173,114 @@ impl Ipcc {
189 }) 173 })
190 .await; 174 .await;
191 175
192 trace!("ipcc: ch {}: read data", channel as u8); 176 trace!("ipcc: ch {}: read data", self.index as u8);
193 177
194 match f() { 178 match f() {
195 Some(ret) => return ret, 179 Some(ret) => return ret,
196 None => {} 180 None => {}
197 } 181 }
198 182
199 trace!("ipcc: ch {}: clear rx", channel as u8); 183 trace!("ipcc: ch {}: clear rx", self.index as u8);
200 compiler_fence(Ordering::SeqCst); 184 compiler_fence(Ordering::SeqCst);
201 // If the channel is clear and the read function returns none, fetch more data 185 // If the channel is clear and the read function returns none, fetch more data
202 regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)); 186 regs.cpu(0).scr().write(|w| w.set_chc(self.index as usize, true));
203 } 187 }
204 } 188 }
205} 189}
206 190
191/// IPCC Channel
192pub struct IpccChannel<'a> {
193 index: u8,
194 _lifetime: PhantomData<&'a mut usize>,
195}
196
197impl<'a> IpccChannel<'a> {
198 pub(crate) const fn new(number: u8) -> Self {
199 core::assert!(number > 0 && number <= 6);
200
201 Self {
202 index: number - 1,
203 _lifetime: PhantomData,
204 }
205 }
206
207 /// Split into a tx and rx channel
208 pub const fn split(self) -> (IpccTxChannel<'a>, IpccRxChannel<'a>) {
209 (IpccTxChannel::new(self.index), IpccRxChannel::new(self.index))
210 }
211}
212
213/// IPCC driver.
214pub struct Ipcc {
215 _private: (),
216}
217
218impl Ipcc {
219 /// Creates a new HardwareSemaphore instance.
220 pub fn new<'d>(
221 _peripheral: Peri<'d, crate::peripherals::IPCC>,
222 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
223 + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>
224 + 'd,
225 _config: Config,
226 ) -> Self {
227 rcc::enable_and_reset_without_stop::<IPCC>();
228 IPCC::set_cpu2(true);
229
230 // Verify rfwkpsel is set
231 let _ = IPCC::frequency();
232
233 let regs = IPCC::regs();
234
235 regs.cpu(0).cr().modify(|w| {
236 w.set_rxoie(true);
237 w.set_txfie(true);
238 });
239
240 // enable interrupts
241 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
242 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
243
244 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
245 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
246
247 Self { _private: () }
248 }
249
250 /// Split into a tx and rx channel
251 pub const fn split<'a>(self) -> [(IpccTxChannel<'a>, IpccRxChannel<'a>); 6] {
252 [
253 IpccChannel::new(1).split(),
254 IpccChannel::new(2).split(),
255 IpccChannel::new(3).split(),
256 IpccChannel::new(4).split(),
257 IpccChannel::new(5).split(),
258 IpccChannel::new(6).split(),
259 ]
260 }
261
262 /// Receive from a channel number
263 pub async unsafe fn receive<R>(number: u8, f: impl FnMut() -> Option<R>) -> R {
264 core::assert!(number > 0 && number <= 6);
265
266 IpccRxChannel::new(number - 1).receive(f).await
267 }
268
269 /// Send to a channel number
270 pub async unsafe fn send(number: u8, f: impl FnOnce()) {
271 core::assert!(number > 0 && number <= 6);
272
273 IpccTxChannel::new(number - 1).send(f).await
274 }
275
276 /// Send to a channel number
277 pub async unsafe fn flush(number: u8) {
278 core::assert!(number > 0 && number <= 6);
279
280 IpccTxChannel::new(number - 1).flush().await
281 }
282}
283
207impl SealedInstance for crate::peripherals::IPCC { 284impl SealedInstance for crate::peripherals::IPCC {
208 fn regs() -> crate::pac::ipcc::Ipcc { 285 fn regs() -> crate::pac::ipcc::Ipcc {
209 crate::pac::IPCC 286 crate::pac::IPCC
@@ -232,26 +309,12 @@ impl State {
232 } 309 }
233 } 310 }
234 311
235 const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { 312 const fn rx_waker_for(&self, index: u8) -> &AtomicWaker {
236 match channel { 313 &self.rx_wakers[index as usize]
237 IpccChannel::Channel1 => &self.rx_wakers[0],
238 IpccChannel::Channel2 => &self.rx_wakers[1],
239 IpccChannel::Channel3 => &self.rx_wakers[2],
240 IpccChannel::Channel4 => &self.rx_wakers[3],
241 IpccChannel::Channel5 => &self.rx_wakers[4],
242 IpccChannel::Channel6 => &self.rx_wakers[5],
243 }
244 } 314 }
245 315
246 const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { 316 const fn tx_waker_for(&self, index: u8) -> &AtomicWaker {
247 match channel { 317 &self.tx_wakers[index as usize]
248 IpccChannel::Channel1 => &self.tx_wakers[0],
249 IpccChannel::Channel2 => &self.tx_wakers[1],
250 IpccChannel::Channel3 => &self.tx_wakers[2],
251 IpccChannel::Channel4 => &self.tx_wakers[3],
252 IpccChannel::Channel5 => &self.tx_wakers[4],
253 IpccChannel::Channel6 => &self.tx_wakers[5],
254 }
255 } 318 }
256} 319}
257 320
diff --git a/embassy-stm32/src/lcd.rs b/embassy-stm32/src/lcd.rs
new file mode 100644
index 000000000..ea29f1398
--- /dev/null
+++ b/embassy-stm32/src/lcd.rs
@@ -0,0 +1,510 @@
1//! LCD
2use core::marker::PhantomData;
3
4use embassy_hal_internal::{Peri, PeripheralType};
5
6use crate::gpio::{AfType, AnyPin, SealedPin};
7use crate::peripherals;
8use crate::rcc::{self, RccPeripheral};
9use crate::time::Hertz;
10
11#[cfg(any(stm32u0, stm32l073, stm32l083))]
12const NUM_SEGMENTS: u8 = 52;
13#[cfg(any(stm32wb, stm32l4x6, stm32l15x, stm32l162, stm32l4x3, stm32l4x6))]
14const NUM_SEGMENTS: u8 = 44;
15#[cfg(any(stm32l053, stm32l063, stm32l100))]
16const NUM_SEGMENTS: u8 = 32;
17
18/// LCD configuration struct
19#[non_exhaustive]
20#[derive(Debug, Clone, Copy)]
21pub struct Config {
22 #[cfg(lcd_v2)]
23 /// Enable the voltage output buffer for higher driving capability.
24 ///
25 /// The LCD driving capability is improved as buffers prevent the LCD capacitive loads from loading the resistor
26 /// bridge unacceptably and interfering with its voltage generation.
27 pub use_voltage_output_buffer: bool,
28 /// Enable SEG pin remapping. SEG[31:28] multiplexed with SEG[43:40]
29 pub use_segment_muxing: bool,
30 /// Bias selector
31 pub bias: Bias,
32 /// Duty selector
33 pub duty: Duty,
34 /// Internal or external voltage source
35 pub voltage_source: VoltageSource,
36 /// The frequency used to update the LCD with.
37 /// Should be between ~30 and ~100. Lower is better for power consumption, but has lower visual fidelity.
38 pub target_fps: Hertz,
39 /// LCD driver selector
40 pub drive: Drive,
41}
42
43impl Default for Config {
44 fn default() -> Self {
45 Self {
46 #[cfg(lcd_v2)]
47 use_voltage_output_buffer: false,
48 use_segment_muxing: false,
49 bias: Default::default(),
50 duty: Default::default(),
51 voltage_source: Default::default(),
52 target_fps: Hertz(60),
53 drive: Drive::Medium,
54 }
55 }
56}
57
58/// The number of voltage levels used when driving an LCD.
59/// Your LCD datasheet should tell you what to use.
60#[repr(u8)]
61#[derive(Debug, Default, Clone, Copy)]
62pub enum Bias {
63 /// 1/4 bias
64 #[default]
65 Quarter = 0b00,
66 /// 1/2 bias
67 Half = 0b01,
68 /// 1/3 bias
69 Third = 0b10,
70}
71
72/// The duty used by the LCD driver.
73///
74/// This is essentially how many COM pins you're using.
75#[repr(u8)]
76#[derive(Debug, Default, Clone, Copy)]
77pub enum Duty {
78 #[default]
79 /// Use a single COM pin
80 Static = 0b000,
81 /// Use two COM pins
82 Half = 0b001,
83 /// Use three COM pins
84 Third = 0b010,
85 /// Use four COM pins
86 Quarter = 0b011,
87 /// Use eight COM pins.
88 ///
89 /// In this mode, `COM[7:4]` outputs are available on `SEG[51:48]`.
90 /// This allows reducing the number of available segments.
91 Eigth = 0b100,
92}
93
94impl Duty {
95 fn num_com_pins(&self) -> u8 {
96 match self {
97 Duty::Static => 1,
98 Duty::Half => 2,
99 Duty::Third => 3,
100 Duty::Quarter => 4,
101 Duty::Eigth => 8,
102 }
103 }
104}
105
106/// Whether to use the internal or external voltage source to drive the LCD
107#[repr(u8)]
108#[derive(Debug, Default, Clone, Copy)]
109pub enum VoltageSource {
110 #[default]
111 /// Voltage stepup converter
112 Internal,
113 /// VLCD pin
114 External,
115}
116
117/// Defines the pulse duration in terms of ck_ps pulses.
118///
119/// A short pulse leads to lower power consumption, but displays with high internal resistance
120/// may need a longer pulse to achieve satisfactory contrast.
121/// Note that the pulse is never longer than one half prescaled LCD clock period.
122///
123/// Displays with high internal resistance may need a longer drive time to achieve satisfactory contrast.
124/// `PermanentHighDrive` is useful in this case if some additional power consumption can be tolerated.
125///
126/// Basically, for power usage, you want this as low as possible while still being able to use the LCD
127/// with a good enough contrast.
128#[repr(u8)]
129#[derive(Debug, Clone, Copy)]
130pub enum Drive {
131 /// Zero clock pulse on duration
132 Lowest = 0x00,
133 /// One clock pulse on duration
134 VeryLow = 0x01,
135 /// Two clock pulse on duration
136 Low = 0x02,
137 /// Three clock pulse on duration
138 Medium = 0x03,
139 /// Four clock pulse on duration
140 MediumHigh = 0x04,
141 /// Five clock pulse on duration
142 High = 0x05,
143 /// Six clock pulse on duration
144 VeryHigh = 0x06,
145 /// Seven clock pulse on duration
146 Highest = 0x07,
147 /// Enables the highdrive bit of the hardware
148 PermanentHighDrive = 0x09,
149}
150
151/// LCD driver.
152pub struct Lcd<'d, T: Instance> {
153 _peri: PhantomData<&'d mut T>,
154 duty: Duty,
155 ck_div: u32,
156}
157
158impl<'d, T: Instance> Lcd<'d, T> {
159 /// Initialize the lcd driver.
160 ///
161 /// The `pins` parameter must contain *all* segment and com pins that are connected to the LCD.
162 /// This is not further checked by this driver. Pins not routed to the LCD can be used for other purposes.
163 pub fn new<const N: usize>(
164 _peripheral: Peri<'d, T>,
165 config: Config,
166 vlcd_pin: Peri<'_, impl VlcdPin<T>>,
167 pins: [LcdPin<'d, T>; N],
168 ) -> Self {
169 rcc::enable_and_reset::<T>();
170
171 vlcd_pin.set_as_af(
172 vlcd_pin.af_num(),
173 AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh),
174 );
175
176 assert_eq!(
177 pins.iter().filter(|pin| !pin.is_seg).count(),
178 config.duty.num_com_pins() as usize,
179 "The number of provided COM pins is not the same as the duty configures"
180 );
181
182 // Set the pins
183 for pin in pins {
184 pin.pin.set_as_af(
185 pin.af_num,
186 AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh),
187 );
188 }
189
190 // Initialize the display ram to 0
191 for i in 0..8 {
192 T::regs().ram_com(i).low().write_value(0);
193 T::regs().ram_com(i).high().write_value(0);
194 }
195
196 // Calculate the clock dividers
197 let Some(lcd_clk) = (unsafe { rcc::get_freqs().rtc.to_hertz() }) else {
198 panic!("The LCD driver needs the RTC/LCD clock to be running");
199 };
200 let duty_divider = match config.duty {
201 Duty::Static => 1,
202 Duty::Half => 2,
203 Duty::Third => 3,
204 Duty::Quarter => 4,
205 Duty::Eigth => 8,
206 };
207 let target_clock = config.target_fps.0 * duty_divider;
208 let target_division = lcd_clk.0 / target_clock;
209
210 let mut ps = 0;
211 let mut div = 0;
212 let mut best_fps_match = u32::MAX;
213
214 for trial_div in 0..0xF {
215 let trial_ps = (target_division / (trial_div + 16))
216 .next_power_of_two()
217 .trailing_zeros();
218 let fps = lcd_clk.0 / ((1 << trial_ps) * (trial_div + 16)) / duty_divider;
219
220 if fps < config.target_fps.0 {
221 continue;
222 }
223
224 if fps < best_fps_match {
225 ps = trial_ps;
226 div = trial_div;
227 best_fps_match = fps;
228 }
229 }
230
231 let ck_div = lcd_clk.0 / ((1 << ps) * (div + 16));
232
233 trace!(
234 "lcd_clk: {}, fps: {}, ps: {}, div: {}, ck_div: {}",
235 lcd_clk, best_fps_match, ps, div, ck_div
236 );
237
238 if best_fps_match == u32::MAX || ps > 0xF {
239 panic!("Lcd clock error");
240 }
241
242 // Set the frame control
243 T::regs().fcr().modify(|w| {
244 w.set_ps(ps as u8);
245 w.set_div(div as u8);
246 w.set_cc(0b100); // Init in the middle-ish
247 w.set_dead(0b000);
248 w.set_pon(config.drive as u8 & 0x07);
249 w.set_hd((config.drive as u8 & !0x07) != 0);
250 });
251
252 // Wait for the frame control to synchronize
253 while !T::regs().sr().read().fcrsf() {}
254
255 // Set the control register values
256 T::regs().cr().modify(|w| {
257 #[cfg(lcd_v2)]
258 w.set_bufen(config.use_voltage_output_buffer);
259 w.set_mux_seg(config.use_segment_muxing);
260 w.set_bias(config.bias as u8);
261 w.set_duty(config.duty as u8);
262 w.set_vsel(matches!(config.voltage_source, VoltageSource::External));
263 });
264
265 // Enable the lcd
266 T::regs().cr().modify(|w| w.set_lcden(true));
267
268 // Wait for the lcd to be enabled
269 while !T::regs().sr().read().ens() {}
270
271 // Wait for the stepup converter to be ready
272 while !T::regs().sr().read().rdy() {}
273
274 Self {
275 _peri: PhantomData,
276 duty: config.duty,
277 ck_div,
278 }
279 }
280
281 /// Change the contrast by changing the voltage being used.
282 ///
283 /// This is from low at 0 to high at 7.
284 pub fn set_contrast_control(&mut self, value: u8) {
285 assert!((0..=7).contains(&value));
286 T::regs().fcr().modify(|w| w.set_cc(value));
287 }
288
289 /// Change the contrast by introducing a deadtime to the signals
290 /// where the voltages are held at 0V.
291 ///
292 /// This is from no dead time at 0 to high dead time at 7.
293 pub fn set_dead_time(&mut self, value: u8) {
294 assert!((0..=7).contains(&value));
295 T::regs()
296 .fcr()
297 .modify(|w: &mut stm32_metapac::lcd::regs::Fcr| w.set_dead(value));
298 }
299
300 /// Write data into the display RAM. This overwrites the data already in it for the specified com index.
301 ///
302 /// The `com_index` value determines which part of the RAM is written to.
303 /// The `segments` value is a bitmap where each bit represents whether a pixel is turned on or off.
304 ///
305 /// This function waits last update request to be finished, but does not submit the buffer to the LCD with a new request.
306 /// Submission has to be done manually using [Self::submit_frame].
307 pub fn write_com_segments(&mut self, com_index: u8, segments: u64) {
308 while T::regs().sr().read().udr() {}
309
310 assert!(
311 com_index < self.duty.num_com_pins(),
312 "Com index cannot be higher than number of configured com pins (through the Duty setting in the config)"
313 );
314
315 assert!(
316 segments.leading_zeros() >= 64 - self.num_segments() as u32,
317 "Invalid segment pixel set",
318 );
319
320 T::regs()
321 .ram_com(com_index as usize)
322 .low()
323 .write_value((segments & 0xFFFF_FFFF) as u32);
324 T::regs()
325 .ram_com(com_index as usize)
326 .high()
327 .write_value(((segments >> 32) & 0xFFFF_FFFF) as u32);
328 }
329
330 /// Read the data from the display RAM.
331 ///
332 /// The `com_index` value determines which part of the RAM is read from.
333 ///
334 /// This function waits for the last update request to be finished.
335 pub fn read_com_segments(&self, com_index: u8) -> u64 {
336 while T::regs().sr().read().udr() {}
337
338 assert!(
339 com_index < self.duty.num_com_pins(),
340 "Com index cannot be higher than number of configured com pins (through the Duty setting in the config)"
341 );
342
343 let low = T::regs().ram_com(com_index as usize).low().read();
344 let high = T::regs().ram_com(com_index as usize).high().read();
345
346 ((high as u64) << 32) | low as u64
347 }
348
349 /// Submit the current RAM data to the LCD.
350 ///
351 /// This function waits until the RAM is writable, but does not wait for the frame to be drawn.
352 pub fn submit_frame(&mut self) {
353 while T::regs().sr().read().udr() {}
354 // Clear the update done flag
355 T::regs().sr().write(|w| w.set_udd(true));
356 // Set the update request flag
357 T::regs().sr().write(|w| w.set_udr(true));
358 }
359
360 /// Get the number of segments that are supported on this LCD
361 pub fn num_segments(&self) -> u8 {
362 match self.duty {
363 Duty::Eigth => NUM_SEGMENTS - 4, // With 8 coms, 4 of the segment pins turn into com pins
364 _ => NUM_SEGMENTS,
365 }
366 }
367
368 /// Get the pixel mask for the current LCD setup.
369 /// This is a mask of all bits that are allowed to be set in the [Self::write_com_segments] function.
370 pub fn segment_pixel_mask(&self) -> u64 {
371 (1 << self.num_segments()) - 1
372 }
373
374 /// Get the number of COM pins that were configured through the Drive config
375 pub fn num_com_pins(&self) -> u8 {
376 self.duty.num_com_pins()
377 }
378
379 /// Set the blink behavior on some pixels.
380 ///
381 /// The blink frequency is an approximation. It's divided from the clock selected by the FPS.
382 /// Play with the FPS value if you want the blink frequency to be more accurate.
383 ///
384 /// If a blink frequency cannot be attained, this function will panic.
385 pub fn set_blink(&mut self, selector: BlinkSelector, freq: BlinkFreq) {
386 // Freq * 100 to be able to do integer math
387 let scaled_blink_freq = match freq {
388 BlinkFreq::Hz0_25 => 25,
389 BlinkFreq::Hz0_5 => 50,
390 BlinkFreq::Hz1 => 100,
391 BlinkFreq::Hz2 => 200,
392 BlinkFreq::Hz4 => 400,
393 };
394
395 let desired_divider = self.ck_div * 100 / scaled_blink_freq;
396 let target_divider = desired_divider.next_power_of_two();
397 let power_divisions = target_divider.trailing_zeros();
398
399 trace!(
400 "Setting LCD blink frequency -> desired_divider: {}, target_divider: {}",
401 desired_divider, target_divider
402 );
403
404 assert!(
405 (8..=1024).contains(&target_divider),
406 "LCD blink frequency cannot be attained"
407 );
408
409 T::regs().fcr().modify(|reg| {
410 reg.set_blinkf((power_divisions - 3) as u8);
411 reg.set_blink(selector as u8);
412 })
413 }
414}
415
416impl<'d, T: Instance> Drop for Lcd<'d, T> {
417 fn drop(&mut self) {
418 // Disable the lcd
419 T::regs().cr().modify(|w| w.set_lcden(false));
420 rcc::disable::<T>();
421 }
422}
423
424/// Blink frequency
425#[derive(Debug, Clone, Copy, PartialEq, Eq)]
426pub enum BlinkFreq {
427 /// 0.25 hz
428 Hz0_25,
429 /// 0.5 hz
430 Hz0_5,
431 /// 1 hz
432 Hz1,
433 /// 2 hz
434 Hz2,
435 /// 4 hz
436 Hz4,
437}
438
439/// Blink pixel selector
440#[derive(Debug, Clone, Copy, PartialEq, Eq)]
441#[repr(u8)]
442pub enum BlinkSelector {
443 /// No pixels blink
444 None = 0b00,
445 /// The SEG0, COM0 pixel blinks if the pixel is set
446 Seg0Com0 = 0b01,
447 /// The SEG0 pixel of all COMs blinks if the pixel is set
448 Seg0ComAll = 0b10,
449 /// All pixels blink if the pixel is set
450 All = 0b11,
451}
452
453/// A type-erased pin that can be configured as an LCD pin.
454/// This is used for passing pins to the new function in the array.
455pub struct LcdPin<'d, T: Instance> {
456 pin: Peri<'d, AnyPin>,
457 af_num: u8,
458 is_seg: bool,
459 _phantom: PhantomData<T>,
460}
461
462impl<'d, T: Instance> LcdPin<'d, T> {
463 /// Construct an LCD pin from any pin that supports it
464 pub fn new_seg(pin: Peri<'d, impl SegPin<T>>) -> Self {
465 let af = pin.af_num();
466
467 Self {
468 pin: pin.into(),
469 af_num: af,
470 is_seg: true,
471 _phantom: PhantomData,
472 }
473 }
474
475 /// Construct an LCD pin from any pin that supports it
476 pub fn new_com(pin: Peri<'d, impl ComPin<T>>) -> Self {
477 let af = pin.af_num();
478
479 Self {
480 pin: pin.into(),
481 af_num: af,
482 is_seg: false,
483 _phantom: PhantomData,
484 }
485 }
486}
487
488trait SealedInstance: crate::rcc::SealedRccPeripheral + PeripheralType {
489 fn regs() -> crate::pac::lcd::Lcd;
490}
491
492/// DSI instance trait.
493#[allow(private_bounds)]
494pub trait Instance: SealedInstance + RccPeripheral + 'static {}
495
496pin_trait!(SegPin, Instance);
497pin_trait!(ComPin, Instance);
498pin_trait!(VlcdPin, Instance);
499
500foreach_peripheral!(
501 (lcd, $inst:ident) => {
502 impl crate::lcd::SealedInstance for peripherals::$inst {
503 fn regs() -> crate::pac::lcd::Lcd {
504 crate::pac::$inst
505 }
506 }
507
508 impl crate::lcd::Instance for peripherals::$inst {}
509 };
510);
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 7e0f7884e..2f783bf64 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -1,5 +1,6 @@
1#![cfg_attr(not(test), no_std)] 1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![allow(unsafe_op_in_unsafe_fn)]
3#![cfg_attr( 4#![cfg_attr(
4 docsrs, 5 docsrs,
5 doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-stm32'>browse the `embassy-stm32` documentation on the Embassy website</a> instead.</p><p>The documentation here on `docs.rs` is built for a single chip only (stm32h7, stm32h7rs55 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.</p></div>\n\n" 6 doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-stm32'>browse the `embassy-stm32` documentation on the Embassy website</a> instead.</p><p>The documentation here on `docs.rs` is built for a single chip only (stm32h7, stm32h7rs55 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.</p></div>\n\n"
@@ -53,6 +54,8 @@ pub mod timer;
53 54
54#[cfg(adc)] 55#[cfg(adc)]
55pub mod adc; 56pub mod adc;
57#[cfg(backup_sram)]
58pub mod backup_sram;
56#[cfg(can)] 59#[cfg(can)]
57pub mod can; 60pub mod can;
58// FIXME: Cordic driver cause stm32u5a5zj crash 61// FIXME: Cordic driver cause stm32u5a5zj crash
@@ -74,6 +77,7 @@ pub mod dts;
74pub mod eth; 77pub mod eth;
75#[cfg(feature = "exti")] 78#[cfg(feature = "exti")]
76pub mod exti; 79pub mod exti;
80#[cfg(flash)]
77pub mod flash; 81pub mod flash;
78#[cfg(fmc)] 82#[cfg(fmc)]
79pub mod fmc; 83pub mod fmc;
@@ -91,6 +95,8 @@ pub mod i2c;
91pub mod i2s; 95pub mod i2s;
92#[cfg(stm32wb)] 96#[cfg(stm32wb)]
93pub mod ipcc; 97pub mod ipcc;
98#[cfg(lcd)]
99pub mod lcd;
94#[cfg(feature = "low-power")] 100#[cfg(feature = "low-power")]
95pub mod low_power; 101pub mod low_power;
96#[cfg(lptim)] 102#[cfg(lptim)]
@@ -147,7 +153,7 @@ pub use crate::_generated::interrupt;
147/// Macro to bind interrupts to handlers. 153/// Macro to bind interrupts to handlers.
148/// 154///
149/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) 155/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
150/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to 156/// and implements the right [`Binding`](crate::interrupt::typelevel::Binding)s for it. You can pass this struct to drivers to
151/// prove at compile-time that the right interrupts have been bound. 157/// prove at compile-time that the right interrupts have been bound.
152/// 158///
153/// Example of how to bind one interrupt: 159/// Example of how to bind one interrupt:
@@ -174,7 +180,10 @@ pub use crate::_generated::interrupt;
174/// } 180/// }
175/// ); 181/// );
176/// ``` 182/// ```
177 183///
184/// Some chips collate multiple interrupt signals into a single interrupt vector. In the above example, I2C2_3 is a
185/// single vector which is activated by events and errors on both peripherals I2C2 and I2C3. Check your chip's list
186/// of interrupt vectors if you get an unexpected compile error trying to bind the standard name.
178// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. 187// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
179#[macro_export] 188#[macro_export]
180macro_rules! bind_interrupts { 189macro_rules! bind_interrupts {
@@ -194,7 +203,7 @@ macro_rules! bind_interrupts {
194 203
195 $( 204 $(
196 #[allow(non_snake_case)] 205 #[allow(non_snake_case)]
197 #[no_mangle] 206 #[unsafe(no_mangle)]
198 $(#[cfg($cond_irq)])? 207 $(#[cfg($cond_irq)])?
199 $(#[doc = $doc])* 208 $(#[doc = $doc])*
200 unsafe extern "C" fn $irq() { 209 unsafe extern "C" fn $irq() {
@@ -222,7 +231,7 @@ macro_rules! bind_interrupts {
222} 231}
223 232
224// Reexports 233// Reexports
225pub use _generated::{peripherals, Peripherals}; 234pub use _generated::{Peripherals, peripherals};
226pub use embassy_hal_internal::{Peri, PeripheralType}; 235pub use embassy_hal_internal::{Peri, PeripheralType};
227#[cfg(feature = "unstable-pac")] 236#[cfg(feature = "unstable-pac")]
228pub use stm32_metapac as pac; 237pub use stm32_metapac as pac;
@@ -240,6 +249,14 @@ pub struct Config {
240 /// RCC config. 249 /// RCC config.
241 pub rcc: rcc::Config, 250 pub rcc: rcc::Config,
242 251
252 #[cfg(feature = "low-power")]
253 /// RTC config
254 pub rtc: rtc::RtcConfig,
255
256 #[cfg(feature = "low-power")]
257 /// Minimum time to stop
258 pub min_stop_pause: embassy_time::Duration,
259
243 /// Enable debug during sleep and stop. 260 /// Enable debug during sleep and stop.
244 /// 261 ///
245 /// May increase power consumption. Defaults to true. 262 /// May increase power consumption. Defaults to true.
@@ -293,6 +310,10 @@ impl Default for Config {
293 fn default() -> Self { 310 fn default() -> Self {
294 Self { 311 Self {
295 rcc: Default::default(), 312 rcc: Default::default(),
313 #[cfg(feature = "low-power")]
314 rtc: Default::default(),
315 #[cfg(feature = "low-power")]
316 min_stop_pause: embassy_time::Duration::from_millis(250),
296 #[cfg(dbgmcu)] 317 #[cfg(dbgmcu)]
297 enable_debug_during_sleep: true, 318 enable_debug_during_sleep: true,
298 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] 319 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
@@ -495,6 +516,16 @@ fn init_hw(config: Config) -> Peripherals {
495 critical_section::with(|cs| { 516 critical_section::with(|cs| {
496 let p = Peripherals::take_with_cs(cs); 517 let p = Peripherals::take_with_cs(cs);
497 518
519 #[cfg(dbgmcu_n6)]
520 {
521 crate::pac::RCC.miscensr().write(|w| w.set_dbgens(true));
522 crate::pac::RCC.miscenr().read(); // volatile read
523 crate::pac::DBGMCU
524 .cr()
525 .modify(|w| w.set_dbgclken(stm32_metapac::dbgmcu::vals::Dbgclken::B_0X1));
526 crate::pac::DBGMCU.cr().read();
527 }
528
498 #[cfg(dbgmcu)] 529 #[cfg(dbgmcu)]
499 crate::pac::DBGMCU.cr().modify(|cr| { 530 crate::pac::DBGMCU.cr().modify(|cr| {
500 #[cfg(dbgmcu_h5)] 531 #[cfg(dbgmcu_h5)]
@@ -509,7 +540,7 @@ fn init_hw(config: Config) -> Peripherals {
509 } 540 }
510 #[cfg(any( 541 #[cfg(any(
511 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, 542 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
512 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl 543 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl, dbgmcu_n6
513 ))] 544 ))]
514 { 545 {
515 cr.set_dbg_sleep(config.enable_debug_during_sleep); 546 cr.set_dbg_sleep(config.enable_debug_during_sleep);
@@ -530,7 +561,7 @@ fn init_hw(config: Config) -> Peripherals {
530 rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs); 561 rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
531 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))] 562 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
532 rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs); 563 rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
533 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))] 564 #[cfg(all(flash, not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs))))]
534 rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs); 565 rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
535 566
536 // Enable the VDDIO2 power supply on chips that have it. 567 // Enable the VDDIO2 power supply on chips that have it.
@@ -590,7 +621,7 @@ fn init_hw(config: Config) -> Peripherals {
590 #[cfg(ucpd)] 621 #[cfg(ucpd)]
591 ucpd::init( 622 ucpd::init(
592 cs, 623 cs,
593 #[cfg(peri_ucpd1)] 624 #[cfg(all(peri_ucpd1, not(stm32n6)))]
594 config.enable_ucpd1_dead_battery, 625 config.enable_ucpd1_dead_battery,
595 #[cfg(peri_ucpd2)] 626 #[cfg(peri_ucpd2)]
596 config.enable_ucpd2_dead_battery, 627 config.enable_ucpd2_dead_battery,
@@ -622,8 +653,28 @@ fn init_hw(config: Config) -> Peripherals {
622 exti::init(cs); 653 exti::init(cs);
623 654
624 rcc::init_rcc(cs, config.rcc); 655 rcc::init_rcc(cs, config.rcc);
656
657 #[cfg(feature = "low-power")]
658 rtc::init_rtc(cs, config.rtc, config.min_stop_pause);
659
660 #[cfg(all(stm32wb, feature = "low-power"))]
661 hsem::init_hsem(cs);
625 } 662 }
626 663
627 p 664 p
628 }) 665 })
629} 666}
667
668/// Performs a busy-wait delay for a specified number of microseconds.
669#[allow(unused)]
670pub(crate) fn block_for_us(us: u64) {
671 cfg_if::cfg_if! {
672 // this does strange things on stm32wlx in low power mode depending on exactly when it's called
673 // as in sometimes 15 us (1 tick) would take > 20 seconds.
674 if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] {
675 embassy_time::block_for(embassy_time::Duration::from_micros(us));
676 } else {
677 cortex_m::asm::delay(unsafe { rcc::get_freqs().sys.to_hertz().unwrap().0 as u64 * us / 1_000_000 } as u32);
678 }
679 }
680}
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 342f73bc8..2388abe3c 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -14,7 +14,7 @@
14//! 14//!
15//! Since entering and leaving low-power modes typically incurs a significant latency, the 15//! Since entering and leaving low-power modes typically incurs a significant latency, the
16//! low-power executor will only attempt to enter when the next timer event is at least 16//! low-power executor will only attempt to enter when the next timer event is at least
17//! [`time_driver::MIN_STOP_PAUSE`] in the future. 17//! [`time_driver::min_stop_pause`] in the future.
18//! 18//!
19//! Currently there is no macro analogous to `embassy_executor::main` for this executor; 19//! Currently there is no macro analogous to `embassy_executor::main` for this executor;
20//! consequently one must define their entrypoint manually. Moreover, you must relinquish control 20//! consequently one must define their entrypoint manually. Moreover, you must relinquish control
@@ -22,53 +22,65 @@
22//! 22//!
23//! ```rust,no_run 23//! ```rust,no_run
24//! use embassy_executor::Spawner; 24//! use embassy_executor::Spawner;
25//! use embassy_stm32::low_power::Executor; 25//! use embassy_stm32::low_power;
26//! use embassy_stm32::rtc::{Rtc, RtcConfig}; 26//! use embassy_stm32::rtc::{Rtc, RtcConfig};
27//! use static_cell::StaticCell; 27//! use embassy_time::Duration;
28//! 28//!
29//! #[cortex_m_rt::entry] 29//! #[embassy_executor::main(executor = "low_power::Executor")]
30//! fn main() -> ! {
31//! Executor::take().run(|spawner| {
32//! spawner.spawn(unwrap!(async_main(spawner)));
33//! });
34//! }
35//!
36//! #[embassy_executor::task]
37//! async fn async_main(spawner: Spawner) { 30//! async fn async_main(spawner: Spawner) {
38//! // initialize the platform... 31//! // initialize the platform...
39//! let mut config = embassy_stm32::Config::default(); 32//! let mut config = embassy_stm32::Config::default();
33//! // the default value, but can be adjusted
34//! config.min_stop_pause = Duration::from_millis(250);
40//! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working 35//! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working
41//! config.enable_debug_during_sleep = false; 36//! config.enable_debug_during_sleep = false;
42//! let p = embassy_stm32::init(config); 37//! let p = embassy_stm32::init(config);
43//! 38//!
44//! // give the RTC to the executor...
45//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
46//! static RTC: StaticCell<Rtc> = StaticCell::new();
47//! let rtc = RTC.init(rtc);
48//! embassy_stm32::low_power::stop_with_rtc(rtc);
49//!
50//! // your application here... 39//! // your application here...
51//! } 40//! }
52//! ``` 41//! ```
53 42
54// TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.`
55#![allow(static_mut_refs)]
56
57use core::arch::asm; 43use core::arch::asm;
58use core::marker::PhantomData; 44use core::marker::PhantomData;
59use core::sync::atomic::{compiler_fence, Ordering}; 45use core::mem;
46use core::sync::atomic::{Ordering, compiler_fence};
60 47
61use cortex_m::peripheral::SCB; 48use cortex_m::peripheral::SCB;
49use critical_section::CriticalSection;
62use embassy_executor::*; 50use embassy_executor::*;
63 51
64use crate::interrupt; 52use crate::interrupt;
65use crate::time_driver::{get_driver, RtcDriver}; 53pub use crate::rcc::StopMode;
54use crate::rcc::{BusyPeripheral, RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2};
55use crate::time_driver::get_driver;
66 56
67const THREAD_PENDER: usize = usize::MAX; 57const THREAD_PENDER: usize = usize::MAX;
68 58
69use crate::rtc::Rtc; 59static mut EXECUTOR_TAKEN: bool = false;
70 60
71static mut EXECUTOR: Option<Executor> = None; 61/// Prevent the device from going into the stop mode if held
62pub struct DeviceBusy {
63 _stop_mode: BusyPeripheral<StopMode>,
64}
65
66impl DeviceBusy {
67 /// Create a new DeviceBusy with stop1.
68 pub fn new_stop1() -> Self {
69 Self::new(StopMode::Stop1)
70 }
71
72 /// Create a new DeviceBusy with stop2.
73 pub fn new_stop2() -> Self {
74 Self::new(StopMode::Stop2)
75 }
76
77 /// Create a new DeviceBusy.
78 pub fn new(stop_mode: StopMode) -> Self {
79 Self {
80 _stop_mode: BusyPeripheral::new(stop_mode),
81 }
82 }
83}
72 84
73#[cfg(not(stm32u0))] 85#[cfg(not(stm32u0))]
74foreach_interrupt! { 86foreach_interrupt! {
@@ -76,7 +88,7 @@ foreach_interrupt! {
76 #[interrupt] 88 #[interrupt]
77 #[allow(non_snake_case)] 89 #[allow(non_snake_case)]
78 unsafe fn $irq() { 90 unsafe fn $irq() {
79 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 91 Executor::on_wakeup_irq_or_event();
80 } 92 }
81 }; 93 };
82} 94}
@@ -87,55 +99,35 @@ foreach_interrupt! {
87 #[interrupt] 99 #[interrupt]
88 #[allow(non_snake_case)] 100 #[allow(non_snake_case)]
89 unsafe fn $irq() { 101 unsafe fn $irq() {
90 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 102 Executor::on_wakeup_irq_or_event();
91 } 103 }
92 }; 104 };
93} 105}
94 106
95#[allow(dead_code)]
96pub(crate) unsafe fn on_wakeup_irq() {
97 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
98}
99
100/// Configure STOP mode with RTC.
101pub fn stop_with_rtc(rtc: &'static Rtc) {
102 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
103}
104
105/// Get whether the core is ready to enter the given stop mode. 107/// Get whether the core is ready to enter the given stop mode.
106/// 108///
107/// This will return false if some peripheral driver is in use that 109/// This will return false if some peripheral driver is in use that
108/// prevents entering the given stop mode. 110/// prevents entering the given stop mode.
109pub fn stop_ready(stop_mode: StopMode) -> bool { 111pub fn stop_ready(stop_mode: StopMode) -> bool {
110 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { 112 critical_section::with(|cs| match Executor::stop_mode(cs) {
111 Some(StopMode::Stop2) => true, 113 Some(StopMode::Standby | StopMode::Stop2) => true,
112 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, 114 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1,
113 None => false, 115 None => false,
114 } 116 })
115}
116
117/// Available Stop modes.
118#[non_exhaustive]
119#[derive(PartialEq)]
120pub enum StopMode {
121 /// STOP 1
122 Stop1,
123 /// STOP 2
124 Stop2,
125} 117}
126 118
127#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] 119#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))]
128use stm32_metapac::pwr::vals::Lpms; 120use crate::pac::pwr::vals::Lpms;
129 121
130#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] 122#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))]
131impl Into<Lpms> for StopMode { 123impl Into<Lpms> for StopMode {
132 fn into(self) -> Lpms { 124 fn into(self) -> Lpms {
133 match self { 125 match self {
134 StopMode::Stop1 => Lpms::STOP1, 126 StopMode::Stop1 => Lpms::STOP1,
135 #[cfg(not(stm32wba))] 127 #[cfg(not(any(stm32wb, stm32wba)))]
136 StopMode::Stop2 => Lpms::STOP2, 128 StopMode::Standby | StopMode::Stop2 => Lpms::STOP2,
137 #[cfg(stm32wba)] 129 #[cfg(any(stm32wb, stm32wba))]
138 StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2? 130 StopMode::Standby | StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2?
139 } 131 }
140 } 132 }
141} 133}
@@ -153,55 +145,146 @@ impl Into<Lpms> for StopMode {
153pub struct Executor { 145pub struct Executor {
154 inner: raw::Executor, 146 inner: raw::Executor,
155 not_send: PhantomData<*mut ()>, 147 not_send: PhantomData<*mut ()>,
156 scb: SCB,
157 time_driver: &'static RtcDriver,
158} 148}
159 149
160impl Executor { 150impl Executor {
161 /// Create a new Executor. 151 /// Create a new Executor.
162 pub fn take() -> &'static mut Self { 152 pub fn new() -> Self {
163 critical_section::with(|_| unsafe { 153 unsafe {
164 assert!(EXECUTOR.is_none()); 154 if EXECUTOR_TAKEN {
165 155 panic!("Low power executor can only be taken once.");
166 EXECUTOR = Some(Self { 156 } else {
167 inner: raw::Executor::new(THREAD_PENDER as *mut ()), 157 EXECUTOR_TAKEN = true;
168 not_send: PhantomData, 158 }
169 scb: cortex_m::Peripherals::steal().SCB, 159 }
170 time_driver: get_driver(),
171 });
172
173 let executor = EXECUTOR.as_mut().unwrap();
174
175 executor
176 })
177 }
178 160
179 unsafe fn on_wakeup_irq(&mut self) { 161 Self {
180 self.time_driver.resume_time(); 162 inner: raw::Executor::new(THREAD_PENDER as *mut ()),
181 trace!("low power: resume"); 163 not_send: PhantomData,
164 }
182 } 165 }
183 166
184 pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { 167 pub(crate) unsafe fn on_wakeup_irq_or_event() {
185 self.time_driver.set_rtc(rtc); 168 if !get_driver().is_stopped() {
169 return;
170 }
186 171
187 rtc.enable_wakeup_line(); 172 critical_section::with(|cs| {
173 #[cfg(stm32wlex)]
174 {
175 let es = crate::pac::PWR.extscr().read();
176 match (es.c1stopf(), es.c1stop2f()) {
177 (true, false) => debug!("low power: wake from STOP1"),
178 (false, true) => debug!("low power: wake from STOP2"),
179 (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"),
180 (false, false) => trace!("low power: stop mode not entered"),
181 };
182 crate::pac::PWR.extscr().modify(|w| {
183 w.set_c1cssf(false);
184 });
185
186 if es.c1stop2f() || es.c1stopf() {
187 // when we wake from any stop mode we need to re-initialize the rcc
188 crate::rcc::init(RCC_CONFIG.unwrap());
189
190 if es.c1stop2f() {
191 // when we wake from STOP2, we need to re-initialize the time driver
192 get_driver().init_timer(cs);
193 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
194 // and given that we just woke from STOP2, we can reset them
195 REFCOUNT_STOP2 = 0;
196 REFCOUNT_STOP1 = 0;
197 }
198 }
199 }
200 get_driver().resume_time(cs);
201
202 trace!("low power: resume time");
203 });
204 }
188 205
189 trace!("low power: stop with rtc configured"); 206 const fn get_scb() -> SCB {
207 unsafe { mem::transmute(()) }
190 } 208 }
191 209
192 fn stop_mode(&self) -> Option<StopMode> { 210 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> {
193 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 211 // We cannot enter standby because we will lose program state.
212 if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } {
194 Some(StopMode::Stop2) 213 Some(StopMode::Stop2)
195 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 214 } else if unsafe { REFCOUNT_STOP1 == 0 } {
196 Some(StopMode::Stop1) 215 Some(StopMode::Stop1)
197 } else { 216 } else {
217 trace!("low power: not ready to stop (refcount_stop1: {})", unsafe {
218 REFCOUNT_STOP1
219 });
198 None 220 None
199 } 221 }
200 } 222 }
201 223
224 #[cfg(all(stm32wb, feature = "low-power"))]
225 fn configure_stop_stm32wb(&self, _cs: CriticalSection) -> Result<(), ()> {
226 use core::task::Poll;
227
228 use embassy_futures::poll_once;
229
230 use crate::hsem::HardwareSemaphoreChannel;
231 use crate::pac::rcc::vals::{Smps, Sw};
232 use crate::pac::{PWR, RCC};
233
234 trace!("low power: trying to get sem3");
235
236 let sem3_mutex = match poll_once(HardwareSemaphoreChannel::<crate::peripherals::HSEM>::new(3).lock(0)) {
237 Poll::Pending => None,
238 Poll::Ready(mutex) => Some(mutex),
239 }
240 .ok_or(())?;
241
242 trace!("low power: got sem3");
243
244 let sem4_mutex = HardwareSemaphoreChannel::<crate::peripherals::HSEM>::new(4).try_lock(0);
245 if let Some(sem4_mutex) = sem4_mutex {
246 trace!("low power: got sem4");
247
248 if PWR.extscr().read().c2ds() {
249 drop(sem4_mutex);
250 } else {
251 return Ok(());
252 }
253 }
254
255 // Sem4 not granted
256 // Set HSION
257 RCC.cr().modify(|w| {
258 w.set_hsion(true);
259 });
260
261 // Wait for HSIRDY
262 while !RCC.cr().read().hsirdy() {}
263
264 // Set SW to HSI
265 RCC.cfgr().modify(|w| {
266 w.set_sw(Sw::HSI);
267 });
268
269 // Wait for SWS to report HSI
270 while !RCC.cfgr().read().sws().eq(&Sw::HSI) {}
271
272 // Set SMPSSEL to HSI
273 RCC.smpscr().modify(|w| {
274 w.set_smpssel(Smps::HSI);
275 });
276
277 drop(sem3_mutex);
278
279 Ok(())
280 }
281
202 #[allow(unused_variables)] 282 #[allow(unused_variables)]
203 fn configure_stop(&mut self, stop_mode: StopMode) { 283 fn configure_stop(&self, _cs: CriticalSection, stop_mode: StopMode) -> Result<(), ()> {
204 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba))] 284 #[cfg(all(stm32wb, feature = "low-power"))]
285 self.configure_stop_stm32wb(_cs)?;
286
287 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wlex))]
205 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 288 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
206 #[cfg(stm32h5)] 289 #[cfg(stm32h5)]
207 crate::pac::PWR.pmcr().modify(|v| { 290 crate::pac::PWR.pmcr().modify(|v| {
@@ -209,34 +292,34 @@ impl Executor {
209 v.set_lpms(vals::Lpms::STOP); 292 v.set_lpms(vals::Lpms::STOP);
210 v.set_svos(vals::Svos::SCALE3); 293 v.set_svos(vals::Svos::SCALE3);
211 }); 294 });
295
296 Ok(())
212 } 297 }
213 298
214 fn configure_pwr(&mut self) { 299 fn configure_pwr(&self) {
215 self.scb.clear_sleepdeep(); 300 Self::get_scb().clear_sleepdeep();
301 // Clear any previous stop flags
302 #[cfg(stm32wlex)]
303 crate::pac::PWR.extscr().modify(|w| {
304 w.set_c1cssf(true);
305 });
216 306
217 compiler_fence(Ordering::SeqCst); 307 compiler_fence(Ordering::SeqCst);
218 308
219 let stop_mode = self.stop_mode(); 309 critical_section::with(|cs| {
220 310 let _ = unsafe { RCC_CONFIG }?;
221 if stop_mode.is_none() { 311 let stop_mode = Self::stop_mode(cs)?;
222 trace!("low power: not ready to stop"); 312 get_driver().pause_time(cs).ok()?;
223 return; 313 self.configure_stop(cs, stop_mode).ok()?;
224 }
225
226 if self.time_driver.pause_time().is_err() {
227 trace!("low power: failed to pause time");
228 return;
229 }
230 314
231 let stop_mode = stop_mode.unwrap(); 315 Some(stop_mode)
232 match stop_mode { 316 })
233 StopMode::Stop1 => trace!("low power: stop 1"), 317 .map(|stop_mode| {
234 StopMode::Stop2 => trace!("low power: stop 2"), 318 trace!("low power: enter stop: {}", stop_mode);
235 }
236 self.configure_stop(stop_mode);
237 319
238 #[cfg(not(feature = "low-power-debug-with-sleep"))] 320 #[cfg(not(feature = "low-power-debug-with-sleep"))]
239 self.scb.set_sleepdeep(); 321 Self::get_scb().set_sleepdeep();
322 });
240 } 323 }
241 324
242 /// Run the executor. 325 /// Run the executor.
@@ -258,14 +341,16 @@ impl Executor {
258 /// 341 ///
259 /// This function never returns. 342 /// This function never returns.
260 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 343 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
261 let executor = unsafe { EXECUTOR.as_mut().unwrap() }; 344 init(self.inner.spawner());
262 init(executor.inner.spawner());
263 345
264 loop { 346 loop {
265 unsafe { 347 unsafe {
266 executor.inner.poll(); 348 self.inner.poll();
267 self.configure_pwr(); 349 self.configure_pwr();
350 #[cfg(feature = "defmt")]
351 defmt::flush();
268 asm!("wfe"); 352 asm!("wfe");
353 Self::on_wakeup_irq_or_event();
269 }; 354 };
270 } 355 }
271 } 356 }
diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs
index 96af9f4d9..a69db3caf 100644
--- a/embassy-stm32/src/lptim/pwm.rs
+++ b/embassy-stm32/src/lptim/pwm.rs
@@ -4,12 +4,12 @@ use core::marker::PhantomData;
4 4
5use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
6 6
7use super::timer::Timer;
8#[cfg(not(any(lptim_v2a, lptim_v2b)))] 7#[cfg(not(any(lptim_v2a, lptim_v2b)))]
9use super::OutputPin; 8use super::OutputPin;
10#[cfg(any(lptim_v2a, lptim_v2b))] 9use super::timer::Timer;
11use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin};
12use super::{BasicInstance, Instance}; 10use super::{BasicInstance, Instance};
11#[cfg(any(lptim_v2a, lptim_v2b))]
12use super::{Channel1Pin, Channel2Pin, channel::Channel, timer::ChannelDirection};
13#[cfg(gpio_v2)] 13#[cfg(gpio_v2)]
14use crate::gpio::Pull; 14use crate::gpio::Pull;
15use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 15use crate::gpio::{AfType, AnyPin, OutputType, Speed};
diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs
index 0f6ef569c..de2db9872 100644
--- a/embassy-stm32/src/ltdc.rs
+++ b/embassy-stm32/src/ltdc.rs
@@ -14,7 +14,7 @@ use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr};
14use crate::gpio::{AfType, OutputType, Speed}; 14use crate::gpio::{AfType, OutputType, Speed};
15use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
16use crate::interrupt::{self}; 16use crate::interrupt::{self};
17use crate::{peripherals, rcc, Peri}; 17use crate::{Peri, peripherals, rcc};
18 18
19static LTDC_WAKER: AtomicWaker = AtomicWaker::new(); 19static LTDC_WAKER: AtomicWaker = AtomicWaker::new();
20 20
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index e36719ef3..4a55f5bd3 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -3,19 +3,12 @@
3 3
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::Peri;
7#[cfg(opamp_v5)]
8use crate::block_for_us;
6use crate::pac::opamp::vals::*; 9use crate::pac::opamp::vals::*;
7#[cfg(not(any(stm32g4, stm32f3)))] 10#[cfg(not(any(stm32g4, stm32f3)))]
8use crate::rcc::RccInfo; 11use crate::rcc::RccInfo;
9use crate::Peri;
10
11/// Performs a busy-wait delay for a specified number of microseconds.
12#[cfg(opamp_v5)]
13fn blocking_delay_ms(ms: u32) {
14 #[cfg(feature = "time")]
15 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
16 #[cfg(not(feature = "time"))]
17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms);
18}
19 12
20/// Gain 13/// Gain
21#[allow(missing_docs)] 14#[allow(missing_docs)]
@@ -439,7 +432,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
439 432
440 // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize 433 // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize
441 // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 434 // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7
442 blocking_delay_ms(2); 435 block_for_us(2_000);
443 436
444 if !T::regs().csr().read().calout() { 437 if !T::regs().csr().read().calout() {
445 if mid == 0 { 438 if mid == 0 {
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index d93cecb69..2d5dbd95a 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -12,14 +12,14 @@ use embassy_hal_internal::PeripheralType;
12pub use enums::*; 12pub use enums::*;
13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; 13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits};
14 14
15use crate::dma::{word, ChannelAndRequest}; 15use crate::dma::{ChannelAndRequest, word};
16use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 16use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
17use crate::mode::{Async, Blocking, Mode as PeriMode}; 17use crate::mode::{Async, Blocking, Mode as PeriMode};
18use crate::pac::octospi::{vals, Octospi as Regs}; 18use crate::pac::octospi::{Octospi as Regs, vals};
19#[cfg(octospim_v1)] 19#[cfg(octospim_v1)]
20use crate::pac::octospim::Octospim; 20use crate::pac::octospim::Octospim;
21use crate::rcc::{self, RccPeripheral}; 21use crate::rcc::{self, RccPeripheral};
22use crate::{peripherals, Peri}; 22use crate::{Peri, peripherals};
23 23
24/// OPSI driver config. 24/// OPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
@@ -451,7 +451,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
451 } 451 }
452 452
453 T::REGS.cr().modify(|w| { 453 T::REGS.cr().modify(|w| {
454 w.set_fmode(0.into()); 454 w.set_fmode(vals::FunctionalMode::INDIRECT_WRITE);
455 }); 455 });
456 456
457 // Configure alternate bytes 457 // Configure alternate bytes
@@ -577,7 +577,8 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
577 w.set_dmaen(false); 577 w.set_dmaen(false);
578 }); 578 });
579 579
580 self.configure_command(&transaction, Some(buf.len()))?; 580 let transfer_size_bytes = buf.len() * W::size().bytes();
581 self.configure_command(&transaction, Some(transfer_size_bytes))?;
581 582
582 let current_address = T::REGS.ar().read().address(); 583 let current_address = T::REGS.ar().read().address();
583 let current_instruction = T::REGS.ir().read().instruction(); 584 let current_instruction = T::REGS.ir().read().instruction();
@@ -616,7 +617,8 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
616 w.set_dmaen(false); 617 w.set_dmaen(false);
617 }); 618 });
618 619
619 self.configure_command(&transaction, Some(buf.len()))?; 620 let transfer_size_bytes = buf.len() * W::size().bytes();
621 self.configure_command(&transaction, Some(transfer_size_bytes))?;
620 622
621 T::REGS 623 T::REGS
622 .cr() 624 .cr()
@@ -1153,7 +1155,8 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1153 // Wait for peripheral to be free 1155 // Wait for peripheral to be free
1154 while T::REGS.sr().read().busy() {} 1156 while T::REGS.sr().read().busy() {}
1155 1157
1156 self.configure_command(&transaction, Some(buf.len()))?; 1158 let transfer_size_bytes = buf.len() * W::size().bytes();
1159 self.configure_command(&transaction, Some(transfer_size_bytes))?;
1157 1160
1158 let current_address = T::REGS.ar().read().address(); 1161 let current_address = T::REGS.ar().read().address();
1159 let current_instruction = T::REGS.ir().read().instruction(); 1162 let current_instruction = T::REGS.ir().read().instruction();
@@ -1168,16 +1171,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1168 T::REGS.ar().write(|v| v.set_address(current_address)); 1171 T::REGS.ar().write(|v| v.set_address(current_address));
1169 } 1172 }
1170 1173
1171 let transfer = unsafe { 1174 for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
1172 self.dma 1175 let transfer = unsafe {
1173 .as_mut() 1176 self.dma
1174 .unwrap() 1177 .as_mut()
1175 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) 1178 .unwrap()
1176 }; 1179 .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
1180 };
1177 1181
1178 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1182 T::REGS.cr().modify(|w| w.set_dmaen(true));
1179 1183
1180 transfer.blocking_wait(); 1184 transfer.blocking_wait();
1185 }
1181 1186
1182 finish_dma(T::REGS); 1187 finish_dma(T::REGS);
1183 1188
@@ -1193,13 +1198,14 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1193 // Wait for peripheral to be free 1198 // Wait for peripheral to be free
1194 while T::REGS.sr().read().busy() {} 1199 while T::REGS.sr().read().busy() {}
1195 1200
1196 self.configure_command(&transaction, Some(buf.len()))?; 1201 let transfer_size_bytes = buf.len() * W::size().bytes();
1202 self.configure_command(&transaction, Some(transfer_size_bytes))?;
1197 T::REGS 1203 T::REGS
1198 .cr() 1204 .cr()
1199 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); 1205 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
1200 1206
1201 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU. 1207 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
1202 for chunk in buf.chunks(0xFFFF) { 1208 for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
1203 let transfer = unsafe { 1209 let transfer = unsafe {
1204 self.dma 1210 self.dma
1205 .as_mut() 1211 .as_mut()
@@ -1226,7 +1232,8 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1226 // Wait for peripheral to be free 1232 // Wait for peripheral to be free
1227 while T::REGS.sr().read().busy() {} 1233 while T::REGS.sr().read().busy() {}
1228 1234
1229 self.configure_command(&transaction, Some(buf.len()))?; 1235 let transfer_size_bytes = buf.len() * W::size().bytes();
1236 self.configure_command(&transaction, Some(transfer_size_bytes))?;
1230 1237
1231 let current_address = T::REGS.ar().read().address(); 1238 let current_address = T::REGS.ar().read().address();
1232 let current_instruction = T::REGS.ir().read().instruction(); 1239 let current_instruction = T::REGS.ir().read().instruction();
@@ -1241,16 +1248,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1241 T::REGS.ar().write(|v| v.set_address(current_address)); 1248 T::REGS.ar().write(|v| v.set_address(current_address));
1242 } 1249 }
1243 1250
1244 let transfer = unsafe { 1251 for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
1245 self.dma 1252 let transfer = unsafe {
1246 .as_mut() 1253 self.dma
1247 .unwrap() 1254 .as_mut()
1248 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) 1255 .unwrap()
1249 }; 1256 .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
1257 };
1250 1258
1251 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1259 T::REGS.cr().modify(|w| w.set_dmaen(true));
1252 1260
1253 transfer.await; 1261 transfer.await;
1262 }
1254 1263
1255 finish_dma(T::REGS); 1264 finish_dma(T::REGS);
1256 1265
@@ -1266,13 +1275,14 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1266 // Wait for peripheral to be free 1275 // Wait for peripheral to be free
1267 while T::REGS.sr().read().busy() {} 1276 while T::REGS.sr().read().busy() {}
1268 1277
1269 self.configure_command(&transaction, Some(buf.len()))?; 1278 let transfer_size_bytes = buf.len() * W::size().bytes();
1279 self.configure_command(&transaction, Some(transfer_size_bytes))?;
1270 T::REGS 1280 T::REGS
1271 .cr() 1281 .cr()
1272 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); 1282 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
1273 1283
1274 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU. 1284 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
1275 for chunk in buf.chunks(0xFFFF) { 1285 for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
1276 let transfer = unsafe { 1286 let transfer = unsafe {
1277 self.dma 1287 self.dma
1278 .as_mut() 1288 .as_mut()
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index b03cd9009..1f47f4845 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -14,7 +14,7 @@ use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::quadspi::Quadspi as Regs; 15use crate::pac::quadspi::Quadspi as Regs;
16use crate::rcc::{self, RccPeripheral}; 16use crate::rcc::{self, RccPeripheral};
17use crate::{peripherals, Peri}; 17use crate::{Peri, peripherals};
18 18
19/// QSPI transfer configuration. 19/// QSPI transfer configuration.
20#[derive(Clone, Copy)] 20#[derive(Clone, Copy)]
@@ -111,7 +111,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
111 config: Config, 111 config: Config,
112 fsel: FlashSelection, 112 fsel: FlashSelection,
113 ) -> Self { 113 ) -> Self {
114 rcc::enable_and_reset::<T>(); 114 rcc::enable_and_reset_without_stop::<T>();
115 115
116 while T::REGS.sr().read().busy() {} 116 while T::REGS.sr().read().busy() {}
117 117
@@ -403,6 +403,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
403 403
404 /// Async read data, using DMA. 404 /// Async read data, using DMA.
405 pub async fn read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { 405 pub async fn read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) {
406 let _scoped_block_stop = T::RCC_INFO.block_stop();
406 let transfer = self.start_read_transfer(transaction, buf); 407 let transfer = self.start_read_transfer(transaction, buf);
407 transfer.await; 408 transfer.await;
408 } 409 }
@@ -443,6 +444,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
443 444
444 /// Async write data, using DMA. 445 /// Async write data, using DMA.
445 pub async fn write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { 446 pub async fn write_dma(&mut self, buf: &[u8], transaction: TransferConfig) {
447 let _scoped_block_stop = T::RCC_INFO.block_stop();
446 let transfer = self.start_write_transfer(transaction, buf); 448 let transfer = self.start_write_transfer(transaction, buf);
447 transfer.await; 449 transfer.await;
448 } 450 }
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index 63fc195dd..219be208f 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -1,6 +1,10 @@
1use core::sync::atomic::{compiler_fence, Ordering}; 1#[cfg(not(stm32n6))]
2use core::sync::atomic::{Ordering, compiler_fence};
2 3
3use crate::pac::common::{Reg, RW}; 4#[cfg(not(stm32n6))]
5use crate::pac::common::{RW, Reg};
6#[cfg(backup_sram)]
7use crate::pac::pwr::vals::Retention;
4pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; 8pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
5use crate::time::Hertz; 9use crate::time::Hertz;
6 10
@@ -52,7 +56,7 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
52 } 56 }
53} 57}
54 58
55#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))] 59#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0, stm32n6)))]
56type Bdcr = crate::pac::rcc::regs::Bdcr; 60type Bdcr = crate::pac::rcc::regs::Bdcr;
57#[cfg(any(rtc_v2_l0, rtc_v2_l1))] 61#[cfg(any(rtc_v2_l0, rtc_v2_l1))]
58type Bdcr = crate::pac::rcc::regs::Csr; 62type Bdcr = crate::pac::rcc::regs::Csr;
@@ -62,19 +66,22 @@ type Bdcr = crate::pac::rcc::regs::Csr1;
62#[cfg(any(stm32c0))] 66#[cfg(any(stm32c0))]
63fn unlock() {} 67fn unlock() {}
64 68
65#[cfg(not(any(stm32c0)))] 69#[cfg(not(any(stm32c0, stm32n6)))]
66fn unlock() { 70fn unlock() {
67 #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] 71 #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))]
68 let cr = crate::pac::PWR.cr(); 72 let cr = crate::pac::PWR.cr();
69 #[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))] 73 #[cfg(not(any(
74 stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba, stm32n6
75 )))]
70 let cr = crate::pac::PWR.cr1(); 76 let cr = crate::pac::PWR.cr1();
71 #[cfg(any(stm32u5, stm32h5, stm32wba))] 77 #[cfg(any(stm32u5, stm32h5, stm32wba, stm32n6))]
72 let cr = crate::pac::PWR.dbpcr(); 78 let cr = crate::pac::PWR.dbpcr();
73 79
74 cr.modify(|w| w.set_dbp(true)); 80 cr.modify(|w| w.set_dbp(true));
75 while !cr.read().dbp() {} 81 while !cr.read().dbp() {}
76} 82}
77 83
84#[cfg(not(stm32n6))]
78fn bdcr() -> Reg<Bdcr, RW> { 85fn bdcr() -> Reg<Bdcr, RW> {
79 #[cfg(any(rtc_v2_l0, rtc_v2_l1))] 86 #[cfg(any(rtc_v2_l0, rtc_v2_l1))]
80 return crate::pac::RCC.csr(); 87 return crate::pac::RCC.csr();
@@ -89,6 +96,8 @@ pub struct LsConfig {
89 pub rtc: RtcClockSource, 96 pub rtc: RtcClockSource,
90 pub lsi: bool, 97 pub lsi: bool,
91 pub lse: Option<LseConfig>, 98 pub lse: Option<LseConfig>,
99 #[cfg(backup_sram)]
100 pub enable_backup_sram: bool,
92} 101}
93 102
94impl LsConfig { 103impl LsConfig {
@@ -113,6 +122,8 @@ impl LsConfig {
113 peripherals_clocked: false, 122 peripherals_clocked: false,
114 }), 123 }),
115 lsi: false, 124 lsi: false,
125 #[cfg(backup_sram)]
126 enable_backup_sram: false,
116 } 127 }
117 } 128 }
118 129
@@ -121,6 +132,8 @@ impl LsConfig {
121 rtc: RtcClockSource::LSI, 132 rtc: RtcClockSource::LSI,
122 lsi: true, 133 lsi: true,
123 lse: None, 134 lse: None,
135 #[cfg(backup_sram)]
136 enable_backup_sram: false,
124 } 137 }
125 } 138 }
126 139
@@ -129,6 +142,8 @@ impl LsConfig {
129 rtc: RtcClockSource::DISABLE, 142 rtc: RtcClockSource::DISABLE,
130 lsi: false, 143 lsi: false,
131 lse: None, 144 lse: None,
145 #[cfg(backup_sram)]
146 enable_backup_sram: false,
132 } 147 }
133 } 148 }
134} 149}
@@ -140,6 +155,7 @@ impl Default for LsConfig {
140} 155}
141 156
142impl LsConfig { 157impl LsConfig {
158 #[cfg(not(stm32n6))]
143 pub(crate) fn init(&self) -> Option<Hertz> { 159 pub(crate) fn init(&self) -> Option<Hertz> {
144 let rtc_clk = match self.rtc { 160 let rtc_clk = match self.rtc {
145 RtcClockSource::LSI => { 161 RtcClockSource::LSI => {
@@ -175,14 +191,19 @@ impl LsConfig {
175 if self.lsi { 191 if self.lsi {
176 #[cfg(any(stm32u5, stm32h5, stm32wba))] 192 #[cfg(any(stm32u5, stm32h5, stm32wba))]
177 let csr = crate::pac::RCC.bdcr(); 193 let csr = crate::pac::RCC.bdcr();
178 #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))] 194 #[cfg(stm32n6)]
195 let csr = crate::pac::RCC.sr();
196 #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0, stm32n6)))]
179 let csr = crate::pac::RCC.csr(); 197 let csr = crate::pac::RCC.csr();
180 #[cfg(any(stm32c0))] 198 #[cfg(stm32c0)]
181 let csr = crate::pac::RCC.csr2(); 199 let csr = crate::pac::RCC.csr2();
182 200
183 #[cfg(not(any(rcc_wb, rcc_wba)))] 201 #[cfg(not(any(rcc_wb, rcc_wba, rcc_n6)))]
184 csr.modify(|w| w.set_lsion(true)); 202 csr.modify(|w| w.set_lsion(true));
185 203
204 #[cfg(rcc_n6)]
205 crate::pac::RCC.cr().modify(|w| w.set_lsion(true));
206
186 #[cfg(any(rcc_wb, rcc_wba))] 207 #[cfg(any(rcc_wb, rcc_wba))]
187 csr.modify(|w| w.set_lsi1on(true)); 208 csr.modify(|w| w.set_lsi1on(true));
188 209
@@ -193,28 +214,77 @@ impl LsConfig {
193 while !csr.read().lsi1rdy() {} 214 while !csr.read().lsi1rdy() {}
194 } 215 }
195 216
217 // Enable backup regulator for peristent battery backed sram
218 #[cfg(backup_sram)]
219 {
220 unsafe { super::BKSRAM_RETAINED = crate::pac::PWR.bdcr().read().bren() == Retention::PRESERVED };
221
222 crate::pac::PWR.bdcr().modify(|w| {
223 w.set_bren(match self.enable_backup_sram {
224 true => Retention::PRESERVED,
225 false => Retention::LOST,
226 });
227 });
228
229 // Wait for backup regulator voltage to stabilize
230 while self.enable_backup_sram && !crate::pac::PWR.bdsr().read().brrdy() {}
231 }
232
196 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. 233 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets.
197 // once set, changing it requires a backup domain reset. 234 // once set, changing it requires a backup domain reset.
198 // first check if the configuration matches what we want. 235 // first check if the configuration matches what we want.
236 // N6 has all the fields spread across multiple registers under RCC.
199 237
200 // check if it's already enabled and in the source we want. 238 // check if it's already enabled and in the source we want.
239 #[cfg(not(rcc_n6))]
201 let reg = bdcr().read(); 240 let reg = bdcr().read();
241 #[cfg(rcc_n6)]
242 let reg = crate::pac::RCC.cr().read();
243 #[cfg(rcc_n6)]
244 let apb4lenr = crate::pac::RCC.apb4lenr().read();
245 #[cfg(rcc_n6)]
246 let ccipr7 = crate::pac::RCC.ccipr7().read();
247 #[cfg(rcc_n6)]
248 let lsecfgr = crate::pac::RCC.lsecfgr().read();
249
202 let mut ok = true; 250 let mut ok = true;
203 ok &= reg.rtcsel() == self.rtc; 251 #[cfg(not(rcc_n6))]
204 #[cfg(not(rcc_wba))] 252 {
253 ok &= reg.rtcsel() == self.rtc;
254 }
255 #[cfg(rcc_n6)]
256 {
257 ok &= ccipr7.rtcsel() == self.rtc;
258 }
259 #[cfg(not(any(rcc_wba, rcc_n6)))]
205 { 260 {
206 ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE); 261 ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE);
207 } 262 }
263 #[cfg(rcc_n6)]
264 {
265 ok &= apb4lenr.rtcen() == (self.rtc != RtcClockSource::DISABLE);
266 }
208 ok &= reg.lseon() == lse_en; 267 ok &= reg.lseon() == lse_en;
209 ok &= reg.lsebyp() == lse_byp; 268 #[cfg(not(rcc_n6))]
269 {
270 ok &= reg.lsebyp() == lse_byp;
271 }
272 #[cfg(rcc_n6)]
273 {
274 ok &= lsecfgr.lsebyp() == lse_byp;
275 }
210 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] 276 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))]
211 if let Some(lse_sysen) = lse_sysen { 277 if let Some(lse_sysen) = lse_sysen {
212 ok &= reg.lsesysen() == lse_sysen; 278 ok &= reg.lsesysen() == lse_sysen;
213 } 279 }
214 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] 280 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1, rcc_n6)))]
215 if let Some(lse_drv) = lse_drv { 281 if let Some(lse_drv) = lse_drv {
216 ok &= reg.lsedrv() == lse_drv.into(); 282 ok &= reg.lsedrv() == lse_drv.into();
217 } 283 }
284 #[cfg(rcc_n6)]
285 if let Some(lse_drv) = lse_drv {
286 ok &= lsecfgr.lsedrv() == lse_drv.into();
287 }
218 288
219 // if configuration is OK, we're done. 289 // if configuration is OK, we're done.
220 if ok { 290 if ok {
@@ -223,7 +293,7 @@ impl LsConfig {
223 } 293 }
224 294
225 // If not OK, reset backup domain and configure it. 295 // If not OK, reset backup domain and configure it.
226 #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0)))] 296 #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0, stm32n6)))]
227 { 297 {
228 bdcr().modify(|w| w.set_bdrst(true)); 298 bdcr().modify(|w| w.set_bdrst(true));
229 bdcr().modify(|w| w.set_bdrst(false)); 299 bdcr().modify(|w| w.set_bdrst(false));
@@ -236,7 +306,7 @@ impl LsConfig {
236 // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset 306 // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset
237 // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset 307 // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset
238 //#[cfg(any(stm32h5, stm32h7rs))] 308 //#[cfg(any(stm32h5, stm32h7rs))]
239 #[cfg(any(stm32h7rs))] 309 #[cfg(any(stm32h7rs, stm32n6))]
240 { 310 {
241 bdcr().modify(|w| w.set_vswrst(true)); 311 bdcr().modify(|w| w.set_vswrst(true));
242 bdcr().modify(|w| w.set_vswrst(false)); 312 bdcr().modify(|w| w.set_vswrst(false));
@@ -248,16 +318,31 @@ impl LsConfig {
248 } 318 }
249 319
250 if lse_en { 320 if lse_en {
251 bdcr().modify(|w| { 321 #[cfg(not(rcc_n6))]
252 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] 322 {
253 if let Some(lse_drv) = lse_drv { 323 bdcr().modify(|w| {
254 w.set_lsedrv(lse_drv.into()); 324 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
255 } 325 if let Some(lse_drv) = lse_drv {
256 w.set_lsebyp(lse_byp); 326 w.set_lsedrv(lse_drv.into());
257 w.set_lseon(true); 327 }
258 }); 328 w.set_lsebyp(lse_byp);
329 w.set_lseon(true);
330 });
331
332 while !bdcr().read().lserdy() {}
333 }
334 #[cfg(rcc_n6)]
335 {
336 crate::pac::RCC.lsecfgr().modify(|w| {
337 if let Some(lse_drv) = lse_drv {
338 w.set_lsedrv(lse_drv.into());
339 }
340 w.set_lsebyp(lse_byp);
341 });
342 crate::pac::RCC.cr().modify(|w| w.set_lseon(true));
259 343
260 while !bdcr().read().lserdy() {} 344 while !crate::pac::RCC.sr().read().lserdy() {}
345 }
261 346
262 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] 347 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))]
263 if let Some(lse_sysen) = lse_sysen { 348 if let Some(lse_sysen) = lse_sysen {
@@ -272,6 +357,7 @@ impl LsConfig {
272 } 357 }
273 358
274 if self.rtc != RtcClockSource::DISABLE { 359 if self.rtc != RtcClockSource::DISABLE {
360 #[cfg(not(rcc_n6))]
275 bdcr().modify(|w| { 361 bdcr().modify(|w| {
276 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))] 362 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))]
277 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 363 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
@@ -280,6 +366,12 @@ impl LsConfig {
280 w.set_rtcen(true); 366 w.set_rtcen(true);
281 w.set_rtcsel(self.rtc); 367 w.set_rtcsel(self.rtc);
282 }); 368 });
369
370 #[cfg(rcc_n6)]
371 {
372 crate::pac::RCC.ccipr7().modify(|w| w.set_rtcsel(self.rtc));
373 crate::pac::RCC.apb4lenr().modify(|w| w.set_rtcen(true))
374 }
283 } 375 }
284 376
285 trace!("BDCR configured: {:08x}", bdcr().read().0); 377 trace!("BDCR configured: {:08x}", bdcr().read().0);
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 8f2e8db5f..d941054cd 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -1,13 +1,13 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2 2
3#[cfg(any(stm32f4, stm32f7))]
4use crate::pac::PWR;
3#[cfg(any(stm32f413, stm32f423, stm32f412))] 5#[cfg(any(stm32f413, stm32f423, stm32f412))]
4pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; 6pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource;
5pub use crate::pac::rcc::vals::{ 7pub use crate::pac::rcc::vals::{
6 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, 8 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
7 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 9 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
8}; 10};
9#[cfg(any(stm32f4, stm32f7))]
10use crate::pac::PWR;
11use crate::pac::{FLASH, RCC}; 11use crate::pac::{FLASH, RCC};
12use crate::time::Hertz; 12use crate::time::Hertz;
13 13
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 331bab7a0..485edd390 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -597,7 +597,10 @@ pub(crate) unsafe fn init(config: Config) {
597 Hertz(24_000_000) => Usbrefcksel::MHZ24, 597 Hertz(24_000_000) => Usbrefcksel::MHZ24,
598 Hertz(26_000_000) => Usbrefcksel::MHZ26, 598 Hertz(26_000_000) => Usbrefcksel::MHZ26,
599 Hertz(32_000_000) => Usbrefcksel::MHZ32, 599 Hertz(32_000_000) => Usbrefcksel::MHZ32,
600 _ => panic!("cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 600 _ => panic!(
601 "cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
602 clk_val
603 ),
601 }, 604 },
602 None => Usbrefcksel::MHZ24, 605 None => Usbrefcksel::MHZ24,
603 }; 606 };
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 81b89046e..0d668103c 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -135,7 +135,14 @@ pub const WPAN_DEFAULT: Config = Config {
135 apb1_pre: APBPrescaler::DIV1, 135 apb1_pre: APBPrescaler::DIV1,
136 apb2_pre: APBPrescaler::DIV1, 136 apb2_pre: APBPrescaler::DIV1,
137 137
138 mux: super::mux::ClockMux::default(), 138 mux: {
139 use crate::pac::rcc::vals::Rfwkpsel;
140
141 let mut mux = super::mux::ClockMux::default();
142
143 mux.rfwkpsel = Rfwkpsel::LSE;
144 mux
145 },
139}; 146};
140 147
141fn msi_enable(range: MSIRange) { 148fn msi_enable(range: MSIRange) {
@@ -499,9 +506,9 @@ pub use pll::*;
499 506
500#[cfg(any(stm32l0, stm32l1))] 507#[cfg(any(stm32l0, stm32l1))]
501mod pll { 508mod pll {
502 use super::{pll_enable, PllInstance}; 509 use super::{PllInstance, pll_enable};
503 pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource};
504 use crate::pac::RCC; 510 use crate::pac::RCC;
511 pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource};
505 use crate::time::Hertz; 512 use crate::time::Hertz;
506 513
507 #[derive(Clone, Copy)] 514 #[derive(Clone, Copy)]
@@ -563,11 +570,11 @@ mod pll {
563 570
564#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] 571#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
565mod pll { 572mod pll {
566 use super::{pll_enable, PllInstance}; 573 use super::{PllInstance, pll_enable};
574 use crate::pac::RCC;
567 pub use crate::pac::rcc::vals::{ 575 pub use crate::pac::rcc::vals::{
568 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, 576 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource,
569 }; 577 };
570 use crate::pac::RCC;
571 use crate::time::Hertz; 578 use crate::time::Hertz;
572 579
573 #[derive(Clone, Copy)] 580 #[derive(Clone, Copy)]
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index 59ccc8cb5..0624fdf26 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -3,6 +3,7 @@ use core::marker::PhantomData;
3use embassy_hal_internal::PeripheralType; 3use embassy_hal_internal::PeripheralType;
4 4
5use crate::gpio::{AfType, OutputType, Speed}; 5use crate::gpio::{AfType, OutputType, Speed};
6use crate::pac::RCC;
6#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] 7#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))]
7pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; 8pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
8#[cfg(not(any( 9#[cfg(not(any(
@@ -15,7 +16,8 @@ pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
15 rcc_h7ab, 16 rcc_h7ab,
16 rcc_h7rm0433, 17 rcc_h7rm0433,
17 rcc_h7, 18 rcc_h7,
18 rcc_h7rs 19 rcc_h7rs,
20 rcc_n6
19)))] 21)))]
20pub use crate::pac::rcc::vals::Mcosel as McoSource; 22pub use crate::pac::rcc::vals::Mcosel as McoSource;
21#[cfg(any( 23#[cfg(any(
@@ -28,11 +30,11 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource;
28 rcc_h7ab, 30 rcc_h7ab,
29 rcc_h7rm0433, 31 rcc_h7rm0433,
30 rcc_h7, 32 rcc_h7,
31 rcc_h7rs 33 rcc_h7rs,
34 rcc_n6
32))] 35))]
33pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; 36pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
34use crate::pac::RCC; 37use crate::{Peri, peripherals};
35use crate::{peripherals, Peri};
36 38
37#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] 39#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))]
38#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] 40#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
@@ -59,10 +61,12 @@ macro_rules! impl_peri {
59 type Source = $source; 61 type Source = $source;
60 62
61 unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { 63 unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) {
62 #[cfg(not(any(stm32u5, stm32wba)))] 64 #[cfg(not(any(stm32u5, stm32wba, stm32n6)))]
63 let r = RCC.cfgr(); 65 let r = RCC.cfgr();
64 #[cfg(any(stm32u5, stm32wba))] 66 #[cfg(any(stm32u5, stm32wba))]
65 let r = RCC.cfgr1(); 67 let r = RCC.cfgr1();
68 #[cfg(any(stm32n6))]
69 let r = RCC.ccipr5();
66 70
67 r.modify(|w| { 71 r.modify(|w| {
68 w.$set_source(source); 72 w.$set_source(source);
@@ -91,12 +95,29 @@ pub struct Mco<'d, T: McoInstance> {
91 95
92impl<'d, T: McoInstance> Mco<'d, T> { 96impl<'d, T: McoInstance> Mco<'d, T> {
93 /// Create a new MCO instance. 97 /// Create a new MCO instance.
94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self { 98 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, config: McoConfig) -> Self {
95 critical_section::with(|_| unsafe { 99 critical_section::with(|_| unsafe {
96 T::_apply_clock_settings(source, prescaler); 100 T::_apply_clock_settings(source, config.prescaler);
97 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 101 set_as_af!(pin, AfType::output(OutputType::PushPull, config.speed));
98 }); 102 });
99 103
100 Self { phantom: PhantomData } 104 Self { phantom: PhantomData }
101 } 105 }
102} 106}
107
108#[non_exhaustive]
109pub struct McoConfig {
110 /// Master Clock Out prescaler
111 pub prescaler: McoPrescaler,
112 /// IO Drive Strength
113 pub speed: Speed,
114}
115
116impl Default for McoConfig {
117 fn default() -> Self {
118 Self {
119 prescaler: McoPrescaler::DIV1,
120 speed: Speed::VeryHigh,
121 }
122 }
123}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c41f81816..d25c922d8 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -4,6 +4,7 @@
4#![allow(missing_docs)] // TODO 4#![allow(missing_docs)] // TODO
5 5
6use core::mem::MaybeUninit; 6use core::mem::MaybeUninit;
7use core::ops;
7 8
8mod bd; 9mod bd;
9pub use bd::*; 10pub use bd::*;
@@ -11,6 +12,7 @@ pub use bd::*;
11#[cfg(any(mco, mco1, mco2))] 12#[cfg(any(mco, mco1, mco2))]
12mod mco; 13mod mco;
13use critical_section::CriticalSection; 14use critical_section::CriticalSection;
15use embassy_hal_internal::{Peri, PeripheralType};
14#[cfg(any(mco, mco1, mco2))] 16#[cfg(any(mco, mco1, mco2))]
15pub use mco::*; 17pub use mco::*;
16 18
@@ -28,12 +30,13 @@ pub use hsi48::*;
28#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")] 30#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")]
29#[cfg_attr(stm32u5, path = "u5.rs")] 31#[cfg_attr(stm32u5, path = "u5.rs")]
30#[cfg_attr(stm32wba, path = "wba.rs")] 32#[cfg_attr(stm32wba, path = "wba.rs")]
33#[cfg_attr(stm32n6, path = "n6.rs")]
31mod _version; 34mod _version;
32 35
33pub use _version::*; 36pub use _version::*;
34use stm32_metapac::RCC; 37use stm32_metapac::RCC;
35 38
36pub use crate::_generated::{mux, Clocks}; 39pub use crate::_generated::{Clocks, mux};
37use crate::time::Hertz; 40use crate::time::Hertz;
38 41
39#[cfg(feature = "low-power")] 42#[cfg(feature = "low-power")]
@@ -48,6 +51,12 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
48/// May be read without a critical section 51/// May be read without a critical section
49pub(crate) static mut REFCOUNT_STOP2: u32 = 0; 52pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
50 53
54#[cfg(feature = "low-power")]
55pub(crate) static mut RCC_CONFIG: Option<Config> = None;
56
57#[cfg(backup_sram)]
58pub(crate) static mut BKSRAM_RETAINED: bool = false;
59
51#[cfg(not(feature = "_dual-core"))] 60#[cfg(not(feature = "_dual-core"))]
52/// Frozen clock frequencies 61/// Frozen clock frequencies
53/// 62///
@@ -104,6 +113,32 @@ pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clo
104 unsafe { get_freqs() } 113 unsafe { get_freqs() }
105} 114}
106 115
116#[cfg(feature = "low-power")]
117fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
118 match stop_mode {
119 StopMode::Standby => {}
120 StopMode::Stop2 => unsafe {
121 REFCOUNT_STOP2 += 1;
122 },
123 StopMode::Stop1 => unsafe {
124 REFCOUNT_STOP1 += 1;
125 },
126 }
127}
128
129#[cfg(feature = "low-power")]
130fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
131 match stop_mode {
132 StopMode::Standby => {}
133 StopMode::Stop2 => unsafe {
134 REFCOUNT_STOP2 -= 1;
135 },
136 StopMode::Stop1 => unsafe {
137 REFCOUNT_STOP1 -= 1;
138 },
139 }
140}
141
107pub(crate) trait SealedRccPeripheral { 142pub(crate) trait SealedRccPeripheral {
108 fn frequency() -> Hertz; 143 fn frequency() -> Hertz;
109 #[allow(dead_code)] 144 #[allow(dead_code)]
@@ -134,14 +169,27 @@ pub(crate) struct RccInfo {
134 stop_mode: StopMode, 169 stop_mode: StopMode,
135} 170}
136 171
172/// Specifies a limit for the stop mode of the peripheral or the stop mode to be entered.
173/// E.g. if `StopMode::Stop1` is selected, the peripheral prevents the chip from entering Stop1 mode.
137#[cfg(feature = "low-power")] 174#[cfg(feature = "low-power")]
138#[allow(dead_code)] 175#[allow(dead_code)]
139pub(crate) enum StopMode { 176#[derive(Debug, Clone, Copy, PartialEq, Default, defmt::Format)]
140 Standby, 177pub enum StopMode {
141 Stop2, 178 #[default]
179 /// Peripheral prevents chip from entering Stop1 or executor will enter Stop1
142 Stop1, 180 Stop1,
181 /// Peripheral prevents chip from entering Stop2 or executor will enter Stop2
182 Stop2,
183 /// Peripheral does not prevent chip from entering Stop
184 Standby,
143} 185}
144 186
187#[cfg(feature = "low-power")]
188type BusyRccPeripheral = BusyPeripheral<StopMode>;
189
190#[cfg(not(feature = "low-power"))]
191type BusyRccPeripheral = ();
192
145impl RccInfo { 193impl RccInfo {
146 /// Safety: 194 /// Safety:
147 /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit 195 /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit
@@ -194,17 +242,6 @@ impl RccInfo {
194 } 242 }
195 } 243 }
196 244
197 #[cfg(feature = "low-power")]
198 match self.stop_mode {
199 StopMode::Standby => {}
200 StopMode::Stop2 => unsafe {
201 REFCOUNT_STOP2 += 1;
202 },
203 StopMode::Stop1 => unsafe {
204 REFCOUNT_STOP1 += 1;
205 },
206 }
207
208 // set the xxxRST bit 245 // set the xxxRST bit
209 let reset_ptr = self.reset_ptr(); 246 let reset_ptr = self.reset_ptr();
210 if let Some(reset_ptr) = reset_ptr { 247 if let Some(reset_ptr) = reset_ptr {
@@ -260,17 +297,6 @@ impl RccInfo {
260 } 297 }
261 } 298 }
262 299
263 #[cfg(feature = "low-power")]
264 match self.stop_mode {
265 StopMode::Standby => {}
266 StopMode::Stop2 => unsafe {
267 REFCOUNT_STOP2 -= 1;
268 },
269 StopMode::Stop1 => unsafe {
270 REFCOUNT_STOP1 -= 1;
271 },
272 }
273
274 // clear the xxxEN bit 300 // clear the xxxEN bit
275 let enable_ptr = self.enable_ptr(); 301 let enable_ptr = self.enable_ptr();
276 unsafe { 302 unsafe {
@@ -279,14 +305,85 @@ impl RccInfo {
279 } 305 }
280 } 306 }
281 307
308 #[allow(dead_code)]
309 pub(crate) fn increment_stop_refcount_with_cs(&self, _cs: CriticalSection) {
310 #[cfg(feature = "low-power")]
311 increment_stop_refcount(_cs, self.stop_mode);
312 }
313
314 #[allow(dead_code)]
315 fn increment_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) {
316 #[cfg(all(stm32wlex, feature = "low-power"))]
317 match self.stop_mode {
318 StopMode::Stop1 | StopMode::Stop2 => increment_stop_refcount(_cs, StopMode::Stop2),
319 _ => {}
320 }
321 }
322
323 #[allow(dead_code)]
324 pub(crate) fn increment_stop_refcount(&self) {
325 #[cfg(feature = "low-power")]
326 critical_section::with(|cs| self.increment_stop_refcount_with_cs(cs))
327 }
328
329 #[allow(dead_code)]
330 pub(crate) fn decrement_stop_refcount_with_cs(&self, _cs: CriticalSection) {
331 #[cfg(feature = "low-power")]
332 decrement_stop_refcount(_cs, self.stop_mode);
333 }
334
335 #[allow(dead_code)]
336 fn decrement_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) {
337 #[cfg(all(stm32wlex, feature = "low-power"))]
338 match self.stop_mode {
339 StopMode::Stop1 | StopMode::Stop2 => decrement_stop_refcount(_cs, StopMode::Stop2),
340 _ => {}
341 }
342 }
343
344 #[allow(dead_code)]
345 pub(crate) fn decrement_stop_refcount(&self) {
346 #[cfg(feature = "low-power")]
347 critical_section::with(|cs| self.decrement_stop_refcount_with_cs(cs))
348 }
349
282 // TODO: should this be `unsafe`? 350 // TODO: should this be `unsafe`?
283 pub(crate) fn enable_and_reset(&self) { 351 pub(crate) fn enable_and_reset(&self) {
284 critical_section::with(|cs| self.enable_and_reset_with_cs(cs)) 352 critical_section::with(|cs| {
353 self.enable_and_reset_with_cs(cs);
354 self.increment_stop_refcount_with_cs(cs);
355 })
356 }
357
358 #[allow(dead_code)]
359 pub(crate) fn enable_and_reset_without_stop(&self) {
360 critical_section::with(|cs| {
361 self.enable_and_reset_with_cs(cs);
362 self.increment_minimum_stop_refcount_with_cs(cs);
363 })
285 } 364 }
286 365
287 // TODO: should this be `unsafe`? 366 // TODO: should this be `unsafe`?
288 pub(crate) fn disable(&self) { 367 pub(crate) fn disable(&self) {
289 critical_section::with(|cs| self.disable_with_cs(cs)) 368 critical_section::with(|cs| {
369 self.disable_with_cs(cs);
370 self.decrement_stop_refcount_with_cs(cs);
371 })
372 }
373
374 // TODO: should this be `unsafe`?
375 #[allow(dead_code)]
376 pub(crate) fn disable_without_stop(&self) {
377 critical_section::with(|cs| {
378 self.disable_with_cs(cs);
379 self.decrement_minimum_stop_refcount_with_cs(cs);
380 })
381 }
382
383 #[allow(dead_code)]
384 pub(crate) fn block_stop(&self) -> BusyRccPeripheral {
385 #[cfg(feature = "low-power")]
386 BusyPeripheral::new(self.stop_mode)
290 } 387 }
291 388
292 fn reset_ptr(&self) -> Option<*mut u32> { 389 fn reset_ptr(&self) -> Option<*mut u32> {
@@ -302,6 +399,60 @@ impl RccInfo {
302 } 399 }
303} 400}
304 401
402pub(crate) trait StoppablePeripheral {
403 #[cfg(feature = "low-power")]
404 #[allow(dead_code)]
405 fn stop_mode(&self) -> StopMode;
406}
407
408#[cfg(feature = "low-power")]
409impl StoppablePeripheral for StopMode {
410 fn stop_mode(&self) -> StopMode {
411 *self
412 }
413}
414
415impl<'a, T: StoppablePeripheral + PeripheralType> StoppablePeripheral for Peri<'a, T> {
416 #[cfg(feature = "low-power")]
417 fn stop_mode(&self) -> StopMode {
418 T::stop_mode(&self)
419 }
420}
421
422pub(crate) struct BusyPeripheral<T: StoppablePeripheral> {
423 peripheral: T,
424}
425
426impl<T: StoppablePeripheral> BusyPeripheral<T> {
427 pub fn new(peripheral: T) -> Self {
428 #[cfg(feature = "low-power")]
429 critical_section::with(|cs| increment_stop_refcount(cs, peripheral.stop_mode()));
430
431 Self { peripheral }
432 }
433}
434
435impl<T: StoppablePeripheral> Drop for BusyPeripheral<T> {
436 fn drop(&mut self) {
437 #[cfg(feature = "low-power")]
438 critical_section::with(|cs| decrement_stop_refcount(cs, self.peripheral.stop_mode()));
439 }
440}
441
442impl<T: StoppablePeripheral> ops::Deref for BusyPeripheral<T> {
443 type Target = T;
444
445 fn deref(&self) -> &Self::Target {
446 &self.peripheral
447 }
448}
449
450impl<T: StoppablePeripheral> ops::DerefMut for BusyPeripheral<T> {
451 fn deref_mut(&mut self) -> &mut Self::Target {
452 &mut self.peripheral
453 }
454}
455
305#[allow(unused)] 456#[allow(unused)]
306mod util { 457mod util {
307 use crate::time::Hertz; 458 use crate::time::Hertz;
@@ -371,6 +522,16 @@ pub fn enable_and_reset<T: RccPeripheral>() {
371 T::RCC_INFO.enable_and_reset(); 522 T::RCC_INFO.enable_and_reset();
372} 523}
373 524
525/// Enables and resets peripheral `T` without incrementing the stop refcount.
526///
527/// # Safety
528///
529/// Peripheral must not be in use.
530// TODO: should this be `unsafe`?
531pub fn enable_and_reset_without_stop<T: RccPeripheral>() {
532 T::RCC_INFO.enable_and_reset_without_stop();
533}
534
374/// Disables peripheral `T`. 535/// Disables peripheral `T`.
375/// 536///
376/// # Safety 537/// # Safety
@@ -390,7 +551,7 @@ pub fn disable<T: RccPeripheral>() {
390/// 551///
391/// This should only be called after `init`. 552/// This should only be called after `init`.
392#[cfg(not(feature = "_dual-core"))] 553#[cfg(not(feature = "_dual-core"))]
393pub fn reinit<'a>(config: Config, _rcc: &'a mut crate::Peri<'a, crate::peripherals::RCC>) { 554pub fn reinit(config: Config, _rcc: &'_ mut crate::Peri<'_, crate::peripherals::RCC>) {
394 critical_section::with(|cs| init_rcc(cs, config)) 555 critical_section::with(|cs| init_rcc(cs, config))
395} 556}
396 557
@@ -404,8 +565,39 @@ pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) {
404 565
405 #[cfg(feature = "low-power")] 566 #[cfg(feature = "low-power")]
406 { 567 {
568 RCC_CONFIG = Some(config);
407 REFCOUNT_STOP2 = 0; 569 REFCOUNT_STOP2 = 0;
408 REFCOUNT_STOP1 = 0; 570 REFCOUNT_STOP1 = 0;
409 } 571 }
410 } 572 }
411} 573}
574
575/// Calculate intermediate prescaler number used to calculate peripheral prescalers
576///
577/// This function is intended to calculate a number indicating a minimum division
578/// necessary to result in a frequency lower than the provided `freq_max`.
579///
580/// The returned value indicates the `val + 1` divider is necessary to result in
581/// the output frequency that is below the maximum provided.
582///
583/// For example:
584/// 0 = divider of 1 => no division necessary as the input frequency is below max
585/// 1 = divider of 2 => division by 2 necessary
586/// ...
587///
588/// The provided max frequency is inclusive. So if `freq_in == freq_max` the result
589/// will be 0, indicating that no division is necessary. To accomplish that we subtract
590/// 1 from the input frequency so that the integer rounding plays in our favor.
591///
592/// For example:
593/// Let the input frequency be 110 and the max frequency be 55.
594/// If we naiively do `110/55 = 2` the renult will indicate that we need a divider by 3
595/// which in reality will be rounded up to 4 as usually a 3 division is not available.
596/// In either case the resulting frequency will be either 36 or 27 which is lower than
597/// what we would want. The result should be 1.
598/// If we do the following instead `109/55 = 1` indicating that we need a divide by 2
599/// which will result in the correct 55.
600#[allow(unused)]
601pub(crate) fn raw_prescaler(freq_in: u32, freq_max: u32) -> u32 {
602 freq_in.saturating_sub(1) / freq_max
603}
diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs
new file mode 100644
index 000000000..178ec57d4
--- /dev/null
+++ b/embassy-stm32/src/rcc/n6.rs
@@ -0,0 +1,1066 @@
1use stm32_metapac::rcc::vals::{
2 Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws,
3 Timpre,
4};
5pub use stm32_metapac::rcc::vals::{
6 Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler,
7};
8
9use crate::pac::{PWR, RCC, SYSCFG};
10use crate::time::Hertz;
11
12pub const HSI_FREQ: Hertz = Hertz(64_000_000);
13pub const LSE_FREQ: Hertz = Hertz(32_768);
14
15#[derive(Clone, Copy, Eq, PartialEq)]
16pub enum HseMode {
17 /// crystal/ceramic oscillator
18 Oscillator,
19 /// oscillator bypassed with external clock (analog)
20 Bypass,
21 /// oscillator bypassed with external digital clock
22 BypassDigital,
23}
24
25#[derive(Clone, Copy, Eq, PartialEq)]
26pub struct Hse {
27 /// HSE frequency.
28 pub freq: Hertz,
29 /// HSE oscillator mode.
30 pub mode: HseMode,
31}
32
33#[derive(Clone, Copy, Eq, PartialEq)]
34pub struct Hsi {
35 pub pre: HsiPrescaler,
36 pub trim: Hsitrim,
37}
38
39#[derive(Clone, Copy, PartialEq)]
40pub enum SupplyConfig {
41 Smps,
42 External,
43}
44
45#[derive(Clone, Copy, PartialEq)]
46pub enum CpuClk {
47 Hse,
48 Ic1 { source: Icsel, divider: Icint },
49 Msi,
50 Hsi,
51}
52
53impl CpuClk {
54 const fn to_bits(self) -> u8 {
55 match self {
56 Self::Hsi => 0x0,
57 Self::Msi => 0x1,
58 Self::Hse => 0x2,
59 Self::Ic1 { .. } => 0x3,
60 }
61 }
62}
63
64#[derive(Clone, Copy, PartialEq)]
65pub struct IcConfig {
66 source: Icsel,
67 divider: Icint,
68}
69
70#[derive(Clone, Copy, PartialEq)]
71pub enum SysClk {
72 Hse,
73 Ic2 {
74 ic2: IcConfig,
75 ic6: IcConfig,
76 ic11: IcConfig,
77 },
78 Msi,
79 Hsi,
80}
81
82impl SysClk {
83 const fn to_bits(self) -> u8 {
84 match self {
85 Self::Hsi => 0x0,
86 Self::Msi => 0x1,
87 Self::Hse => 0x2,
88 Self::Ic2 { .. } => 0x3,
89 }
90 }
91}
92
93#[derive(Clone, Copy, PartialEq)]
94pub struct Msi {
95 pub freq: Msifreqsel,
96 pub trim: u8,
97}
98
99#[derive(Clone, Copy, PartialEq)]
100pub enum Pll {
101 Oscillator {
102 source: Pllsel,
103 divm: Plldivm,
104 fractional: u32,
105 divn: u16,
106 divp1: Pllpdiv,
107 divp2: Pllpdiv,
108 },
109 Bypass {
110 source: Pllsel,
111 },
112}
113
114/// Configuration of the core clocks
115#[non_exhaustive]
116#[derive(Clone, Copy)]
117pub struct Config {
118 pub hsi: Option<Hsi>,
119 pub hse: Option<Hse>,
120 pub msi: Option<Msi>,
121 pub lsi: bool,
122 pub lse: bool,
123
124 pub sys: SysClk,
125 pub cpu: CpuClk,
126
127 pub pll1: Option<Pll>,
128 pub pll2: Option<Pll>,
129 pub pll3: Option<Pll>,
130 pub pll4: Option<Pll>,
131
132 pub ahb: AhbPrescaler,
133 pub apb1: ApbPrescaler,
134 pub apb2: ApbPrescaler,
135 pub apb4: ApbPrescaler,
136 pub apb5: ApbPrescaler,
137
138 pub supply_config: SupplyConfig,
139}
140
141impl Config {
142 pub const fn new() -> Self {
143 Self {
144 hsi: Some(Hsi {
145 pre: HsiPrescaler::DIV1,
146 trim: HsiCalibration::from_bits(32),
147 }),
148 hse: None,
149 msi: None,
150 lsi: true,
151 lse: false,
152 sys: SysClk::Hsi,
153 cpu: CpuClk::Hsi,
154 pll1: Some(Pll::Bypass { source: Pllsel::HSI }),
155 pll2: Some(Pll::Bypass { source: Pllsel::HSI }),
156 pll3: Some(Pll::Bypass { source: Pllsel::HSI }),
157 pll4: Some(Pll::Bypass { source: Pllsel::HSI }),
158
159 ahb: AhbPrescaler::DIV2,
160 apb1: ApbPrescaler::DIV1,
161 apb2: ApbPrescaler::DIV1,
162 apb4: ApbPrescaler::DIV1,
163 apb5: ApbPrescaler::DIV1,
164
165 supply_config: SupplyConfig::Smps,
166 }
167 }
168}
169
170#[allow(dead_code)]
171struct ClocksOutput {
172 cpuclk: Hertz,
173 sysclk: Hertz,
174 pclk_tim: Hertz,
175 ahb: Hertz,
176 apb1: Hertz,
177 apb2: Hertz,
178 apb4: Hertz,
179 apb5: Hertz,
180}
181
182struct ClocksInput {
183 hsi: Option<Hertz>,
184 msi: Option<Hertz>,
185 hse: Option<Hertz>,
186}
187
188fn init_clocks(config: Config, input: &ClocksInput) -> ClocksOutput {
189 // handle increasing dividers
190 debug!("configuring increasing pclk dividers");
191 RCC.cfgr2().modify(|w| {
192 if config.apb1 > w.ppre1() {
193 debug!(" - APB1");
194 w.set_ppre1(config.apb1);
195 }
196 if config.apb2 > w.ppre2() {
197 debug!(" - APB2");
198 w.set_ppre2(config.apb2);
199 }
200 if config.apb4 > w.ppre4() {
201 debug!(" - APB4");
202 w.set_ppre4(config.apb4);
203 }
204 if config.apb5 > w.ppre5() {
205 debug!(" - APB5");
206 w.set_ppre5(config.apb5);
207 }
208 if config.ahb > w.hpre() {
209 debug!(" - AHB");
210 w.set_hpre(config.ahb);
211 }
212 });
213 // cpuclk
214 debug!("configuring cpuclk");
215 match config.cpu {
216 CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"),
217 CpuClk::Ic1 { source, divider } => {
218 if !pll_sources_ready(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) {
219 panic!("ICx clock switch requires both origin and destination clock source to be active")
220 }
221
222 RCC.iccfgr(0).write(|w| {
223 w.set_icsel(source);
224 w.set_icint(divider);
225 });
226 RCC.divensr().modify(|w| w.set_ic1ens(true));
227 }
228 CpuClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"),
229 CpuClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"),
230 _ => {}
231 }
232 // set source
233 let cpusw = Cpusw::from_bits(config.cpu.to_bits());
234 RCC.cfgr().modify(|w| w.set_cpusw(cpusw));
235 // wait for changes to take effect
236 while RCC.cfgr().read().cpusws() != Cpusws::from_bits(config.cpu.to_bits()) {}
237
238 // sysclk
239 debug!("configuring sysclk");
240 match config.sys {
241 SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"),
242 SysClk::Ic2 { ic2, ic6, ic11 } => {
243 if !pll_sources_ready(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) {
244 panic!("IC2 clock switch requires both origin and destination clock source to be active")
245 }
246 if !pll_sources_ready(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) {
247 panic!("IC6 clock switch requires both origin and destination clock source to be active")
248 }
249 if !pll_sources_ready(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) {
250 panic!("IC11 clock switch requires both origin and destination clock source to be active")
251 }
252
253 RCC.iccfgr(1).write(|w| {
254 w.set_icsel(ic2.source);
255 w.set_icint(ic2.divider);
256 });
257 RCC.iccfgr(5).write(|w| {
258 w.set_icsel(ic6.source);
259 w.set_icint(ic6.divider);
260 });
261 RCC.iccfgr(10).write(|w| {
262 w.set_icsel(ic11.source);
263 w.set_icint(ic11.divider);
264 });
265 RCC.divensr().modify(|w| {
266 w.set_ic2ens(true);
267 w.set_ic6ens(true);
268 w.set_ic11ens(true);
269 });
270 }
271 SysClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"),
272 SysClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"),
273 _ => {}
274 }
275 // switch the system bus clock
276 let syssw = Syssw::from_bits(config.sys.to_bits());
277 RCC.cfgr().modify(|w| w.set_syssw(syssw));
278 // wait for changes to be applied
279 while RCC.cfgr().read().syssws() != Syssws::from_bits(config.sys.to_bits()) {}
280
281 // decreasing dividers
282 debug!("configuring decreasing pclk dividers");
283 RCC.cfgr2().modify(|w| {
284 if config.ahb < w.hpre() {
285 debug!(" - AHB");
286 w.set_hpre(config.ahb);
287 }
288 if config.apb1 < w.ppre1() {
289 debug!(" - APB1");
290 w.set_ppre1(config.apb1);
291 }
292 if config.apb2 < w.ppre2() {
293 debug!(" - APB2");
294 w.set_ppre2(config.apb2);
295 }
296 if config.apb4 < w.ppre4() {
297 debug!(" - APB4");
298 w.set_ppre4(config.apb4);
299 }
300 if config.apb5 < w.ppre5() {
301 debug!(" - APB5");
302 w.set_ppre5(config.apb5);
303 }
304 });
305
306 let cpuclk = match config.cpu {
307 CpuClk::Hsi => unwrap!(input.hsi),
308 CpuClk::Msi => unwrap!(input.msi),
309 CpuClk::Hse => unwrap!(input.hse),
310 CpuClk::Ic1 { .. } => todo!(),
311 };
312
313 let sysclk = match config.sys {
314 SysClk::Hsi => unwrap!(input.hsi),
315 SysClk::Msi => unwrap!(input.msi),
316 SysClk::Hse => unwrap!(input.hse),
317 SysClk::Ic2 { .. } => todo!(),
318 };
319
320 let timpre: u32 = match RCC.cfgr2().read().timpre() {
321 Timpre::DIV1 => 1,
322 Timpre::DIV2 => 2,
323 Timpre::DIV4 => 4,
324 Timpre::_RESERVED_3 => 8,
325 };
326
327 let hpre = periph_prescaler_to_value(config.ahb.to_bits());
328 let ppre1 = periph_prescaler_to_value(config.apb1.to_bits());
329 let ppre2 = periph_prescaler_to_value(config.apb2.to_bits());
330 let ppre4 = periph_prescaler_to_value(config.apb4.to_bits());
331 let ppre5 = periph_prescaler_to_value(config.apb5.to_bits());
332
333 // enable all peripherals in sleep mode
334 enable_low_power_peripherals();
335
336 // enable interrupts
337 unsafe {
338 core::arch::asm!("cpsie i");
339 }
340
341 ClocksOutput {
342 sysclk,
343 cpuclk,
344 pclk_tim: sysclk / timpre,
345 ahb: Hertz(sysclk.0 / hpre as u32),
346 apb1: sysclk / hpre / ppre1,
347 apb2: sysclk / hpre / ppre2,
348 apb4: sysclk / hpre / ppre4,
349 apb5: sysclk / hpre / ppre5,
350 }
351}
352
353fn enable_low_power_peripherals() {
354 // AHB1-5
355 RCC.ahb1lpenr().modify(|w| {
356 w.set_adc12lpen(true);
357 w.set_gpdma1lpen(true);
358 });
359 RCC.ahb2lpenr().modify(|w| {
360 w.set_adf1lpen(true);
361 w.set_mdf1lpen(true);
362 w.set_ramcfglpen(true);
363 });
364 RCC.ahb3lpenr().modify(|w| {
365 w.set_risaflpen(true);
366 w.set_iaclpen(true);
367 w.set_rifsclpen(true);
368 w.set_pkalpen(true);
369 w.set_saeslpen(true);
370 w.set_cryplpen(true);
371 w.set_hashlpen(true);
372 w.set_rnglpen(true);
373 });
374 RCC.ahb4lpenr().modify(|w| {
375 w.set_crclpen(true);
376 w.set_pwrlpen(true);
377 w.set_gpioqlpen(true);
378 w.set_gpioplpen(true);
379 w.set_gpioolpen(true);
380 w.set_gpionlpen(true);
381 w.set_gpiohlpen(true);
382 w.set_gpioglpen(true);
383 w.set_gpioflpen(true);
384 w.set_gpioelpen(true);
385 w.set_gpiodlpen(true);
386 w.set_gpioclpen(true);
387 w.set_gpioblpen(true);
388 w.set_gpioalpen(true);
389 });
390 RCC.ahb5lpenr().modify(|w| {
391 w.set_npulpen(true);
392 w.set_npucachelpen(true);
393 w.set_otg2lpen(true);
394 w.set_otgphy2lpen(true);
395 w.set_otgphy1lpen(true);
396 w.set_otg1lpen(true);
397 w.set_eth1lpen(true);
398 w.set_eth1rxlpen(true);
399 w.set_eth1txlpen(true);
400 w.set_eth1maclpen(true);
401 w.set_gpulpen(true);
402 w.set_gfxmmulpen(true);
403 w.set_mce4lpen(true);
404 w.set_xspi3lpen(true);
405 w.set_mce3lpen(true);
406 w.set_mce2lpen(true);
407 w.set_mce1lpen(true);
408 w.set_xspimlpen(true);
409 w.set_xspi2lpen(true);
410 w.set_sdmmc1lpen(true);
411 w.set_sdmmc2lpen(true);
412 w.set_pssilpen(true);
413 w.set_xspi1lpen(true);
414 w.set_fmclpen(true);
415 w.set_jpeglpen(true);
416 w.set_dma2dlpen(true);
417 w.set_hpdma1lpen(true);
418 });
419
420 // APB1-5
421 RCC.apb1llpenr().modify(|w| {
422 w.set_uart8lpen(true);
423 w.set_uart7lpen(true);
424 w.set_i3c2lpen(true);
425 w.set_i3c1lpen(true);
426 w.set_i2c3lpen(true);
427 w.set_i2c2lpen(true);
428 w.set_i2c1lpen(true);
429 w.set_uart5lpen(true);
430 w.set_uart4lpen(true);
431 w.set_usart3lpen(true);
432 w.set_usart2lpen(true);
433 w.set_spdifrx1lpen(true);
434 w.set_spi3lpen(true);
435 w.set_spi2lpen(true);
436 w.set_tim11lpen(true);
437 w.set_tim10lpen(true);
438 w.set_wwdglpen(true);
439 w.set_lptim1lpen(true);
440 w.set_tim14lpen(true);
441 w.set_tim13lpen(true);
442 w.set_tim12lpen(true);
443 w.set_tim7lpen(true);
444 w.set_tim6lpen(true);
445 w.set_tim5lpen(true);
446 w.set_tim4lpen(true);
447 w.set_tim3lpen(true);
448 w.set_tim2lpen(true);
449 });
450 RCC.apb1hlpenr().modify(|w| {
451 w.set_ucpd1lpen(true);
452 w.set_fdcanlpen(true);
453 w.set_mdioslpen(true);
454 });
455 RCC.apb2lpenr().modify(|w| {
456 w.set_sai2lpen(true);
457 w.set_sai1lpen(true);
458 w.set_spi5lpen(true);
459 w.set_tim9lpen(true);
460 w.set_tim17lpen(true);
461 w.set_tim16lpen(true);
462 w.set_tim15lpen(true);
463 w.set_tim18lpen(true);
464 w.set_spi4lpen(true);
465 w.set_spi1lpen(true);
466 w.set_usart10lpen(true);
467 w.set_uart9lpen(true);
468 w.set_usart6lpen(true);
469 w.set_usart1lpen(true);
470 w.set_tim8lpen(true);
471 w.set_tim1lpen(true);
472 });
473 RCC.apb3lpenr().modify(|w| {
474 w.set_dftlpen(true);
475 });
476 RCC.apb4llpenr().modify(|w| {
477 w.set_rtcapblpen(true);
478 w.set_rtclpen(true);
479 w.set_vrefbuflpen(true);
480 w.set_lptim5lpen(true);
481 w.set_lptim4lpen(true);
482 w.set_lptim3lpen(true);
483 w.set_lptim2lpen(true);
484 w.set_i2c4lpen(true);
485 w.set_spi6lpen(true);
486 w.set_lpuart1lpen(true);
487 w.set_hdplpen(true);
488 });
489 RCC.apb4hlpenr().modify(|w| {
490 w.set_dtslpen(true);
491 w.set_bseclpen(true);
492 w.set_syscfglpen(true);
493 });
494 RCC.apb5lpenr().modify(|w| {
495 w.set_csilpen(true);
496 w.set_venclpen(true);
497 w.set_gfxtimlpen(true);
498 w.set_dcmilpen(true);
499 w.set_ltdclpen(true);
500 });
501
502 RCC.buslpenr().modify(|w| {
503 w.set_aclknclpen(true);
504 w.set_aclknlpen(true);
505 });
506
507 RCC.memlpenr().modify(|w| {
508 w.set_bootromlpen(true);
509 w.set_vencramlpen(true);
510 w.set_npucacheramlpen(true);
511 w.set_flexramlpen(true);
512 w.set_axisram2lpen(true);
513 w.set_axisram1lpen(true);
514 w.set_bkpsramlpen(true);
515 w.set_ahbsram2lpen(true);
516 w.set_ahbsram1lpen(true);
517 w.set_axisram6lpen(true);
518 w.set_axisram5lpen(true);
519 w.set_axisram4lpen(true);
520 w.set_axisram3lpen(true);
521 });
522
523 RCC.misclpenr().modify(|w| {
524 w.set_perlpen(true);
525 w.set_xspiphycomplpen(true);
526 w.set_dbglpen(true);
527 });
528}
529
530const fn periph_prescaler_to_value(bits: u8) -> u8 {
531 match bits {
532 0 => 1,
533 1 => 2,
534 2 => 4,
535 3 => 8,
536 4 => 16,
537 5 => 32,
538 6 => 64,
539 7.. => 128,
540 }
541}
542
543fn pll_source_ready(source: u8) -> bool {
544 match source {
545 0x0 if !RCC.sr().read().pllrdy(0) && !RCC.pllcfgr1(0).read().pllbyp() => false,
546 0x1 if !RCC.sr().read().pllrdy(1) && !RCC.pllcfgr1(1).read().pllbyp() => false,
547 0x2 if !RCC.sr().read().pllrdy(2) && !RCC.pllcfgr1(2).read().pllbyp() => false,
548 0x3 if !RCC.sr().read().pllrdy(3) && !RCC.pllcfgr1(3).read().pllbyp() => false,
549 _ => true,
550 }
551}
552
553fn pll_sources_ready(source1: u8, source2: u8) -> bool {
554 pll_source_ready(source1) && pll_source_ready(source2)
555}
556
557impl Default for Config {
558 fn default() -> Self {
559 Self::new()
560 }
561}
562
563fn power_supply_config(supply_config: SupplyConfig) {
564 // power supply config
565 PWR.cr1().modify(|w| {
566 w.set_sden(match supply_config {
567 SupplyConfig::External => false,
568 SupplyConfig::Smps => true,
569 });
570 });
571
572 // Validate supply configuration
573 while !PWR.voscr().read().actvosrdy() {}
574}
575
576struct PllInput {
577 hsi: Option<Hertz>,
578 msi: Option<Hertz>,
579 hse: Option<Hertz>,
580 i2s_ckin: Option<Hertz>,
581}
582
583#[derive(Clone, Copy, Default)]
584#[allow(dead_code)]
585struct PllOutput {
586 divm: Option<Hertz>,
587 divn: Option<Hertz>,
588 divp1: Option<Hertz>,
589 divp2: Option<Hertz>,
590 output: Option<Hertz>,
591}
592
593fn init_pll(pll_config: Option<Pll>, pll_index: usize, input: &PllInput) -> PllOutput {
594 let cfgr1 = RCC.pllcfgr1(pll_index);
595 let cfgr2 = RCC.pllcfgr2(pll_index);
596 let cfgr3 = RCC.pllcfgr3(pll_index);
597
598 match pll_config {
599 Some(Pll::Oscillator {
600 source,
601 divm,
602 fractional,
603 divn,
604 divp1,
605 divp2,
606 }) => {
607 // ensure pll is disabled
608 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
609 while RCC.sr().read().pllrdy(pll_index) {}
610
611 // ensure PLLxMODSSDIS=1 to work in fractional mode
612 cfgr3.modify(|w| w.set_pllmodssdis(Pllmodssdis::FRACTIONAL_DIVIDE));
613 // clear bypass mode
614 cfgr1.modify(|w| w.set_pllbyp(false));
615 // configure the pll clock source, mul and div factors
616 cfgr1.modify(|w| {
617 w.set_pllsel(source);
618 w.set_plldivm(divm);
619 w.set_plldivn(divn);
620 });
621
622 let in_clk = match source {
623 Pllsel::HSI => unwrap!(input.hsi),
624 Pllsel::MSI => unwrap!(input.msi),
625 Pllsel::HSE => unwrap!(input.hse),
626 Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin),
627 _ => panic!("reserved PLL source not allowed"),
628 };
629
630 let m = divm.to_bits() as u32;
631 let n = divn as u32;
632
633 cfgr3.modify(|w| {
634 w.set_pllpdiv1(divp1);
635 w.set_pllpdiv2(divp2);
636 });
637
638 let p1 = divp1.to_bits() as u32;
639 let p2 = divp2.to_bits() as u32;
640
641 // configure pll divnfrac
642 cfgr2.modify(|w| w.set_plldivnfrac(fractional));
643 // clear pllxmoddsen
644 cfgr3.modify(|w| w.set_pllmoddsen(false));
645 // fractional mode
646 if fractional != 0 {
647 cfgr3.modify(|w| {
648 w.set_pllmoddsen(true);
649 w.set_plldacen(true);
650 })
651 }
652 // enable pll post divider output
653 cfgr3.modify(|w| {
654 w.set_pllmodssrst(true);
655 w.set_pllpdiven(true);
656 });
657 // enable the pll
658 RCC.csr().write(|w| w.pllons(pll_index));
659 // wait until ready
660 while RCC.sr().read().pllrdy(pll_index) {}
661
662 PllOutput {
663 divm: Some(Hertz(m)),
664 divn: Some(Hertz(n)),
665 divp1: Some(Hertz(p1)),
666 divp2: Some(Hertz(p2)),
667 output: Some(Hertz(in_clk.0 / m / n / p1 / p2)),
668 }
669 }
670 Some(Pll::Bypass { source }) => {
671 // check if source is ready
672 if !pll_source_ready(source.to_bits()) {
673 panic!("PLL source is not ready")
674 }
675
676 // ensure pll is disabled
677 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
678 while RCC.sr().read().pllrdy(pll_index) {}
679
680 cfgr1.modify(|w| {
681 w.set_pllbyp(true);
682 w.set_pllsel(source);
683 });
684
685 let in_clk = match source {
686 Pllsel::HSI => unwrap!(input.hsi),
687 Pllsel::MSI => unwrap!(input.msi),
688 Pllsel::HSE => unwrap!(input.hse),
689 Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin),
690 _ => panic!("reserved PLL source not allowed"),
691 };
692
693 PllOutput {
694 output: Some(in_clk),
695 ..Default::default()
696 }
697 }
698 None => {
699 cfgr3.modify(|w| w.set_pllpdiven(false));
700 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
701 // wait till disabled
702 while RCC.sr().read().pllrdy(pll_index) {}
703
704 // clear bypass mode
705 cfgr1.modify(|w| w.set_pllbyp(false));
706
707 PllOutput::default()
708 }
709 }
710}
711
712#[allow(dead_code)]
713struct OscOutput {
714 hsi: Option<Hertz>,
715 hse: Option<Hertz>,
716 msi: Option<Hertz>,
717 lsi: Option<Hertz>,
718 lse: Option<Hertz>,
719 pll1: Option<Hertz>,
720 pll2: Option<Hertz>,
721 pll3: Option<Hertz>,
722 pll4: Option<Hertz>,
723 ic1sel: Icsel,
724 ic2sel: Icsel,
725 ic6sel: Icsel,
726 ic11sel: Icsel,
727}
728
729fn init_osc(config: Config) -> OscOutput {
730 let (cpu_src, sys_src) = {
731 let reg = RCC.cfgr().read();
732 (reg.cpusws(), reg.syssws())
733 };
734 let pll1_src = RCC.pllcfgr1(0).read().pllsel();
735 let pll2_src = RCC.pllcfgr1(1).read().pllsel();
736 let pll3_src = RCC.pllcfgr1(2).read().pllsel();
737 let pll4_src = RCC.pllcfgr1(3).read().pllsel();
738 let rcc_sr = RCC.sr().read();
739
740 debug!("configuring HSE");
741
742 // hse configuration
743 let hse = if let Some(hse) = config.hse {
744 match hse.mode {
745 HseMode::Oscillator => {
746 debug!("HSE in oscillator mode");
747 }
748 HseMode::Bypass => {
749 debug!("HSE in bypass mode");
750 RCC.hsecfgr().modify(|w| {
751 w.set_hsebyp(true);
752 w.set_hseext(Hseext::ANALOG);
753 });
754 }
755 HseMode::BypassDigital => {
756 debug!("HSE in bypass digital mode");
757 RCC.hsecfgr().modify(|w| {
758 w.set_hsebyp(true);
759 w.set_hseext(Hseext::DIGITAL);
760 });
761 }
762 }
763 RCC.csr().write(|w| w.set_hseons(true));
764
765 // wait until the hse is ready
766 while !RCC.sr().read().hserdy() {}
767
768 Some(hse.freq)
769 } else if cpu_src == Cpusws::HSE
770 || sys_src == Syssws::HSE
771 || (pll1_src == Pllsel::HSE && rcc_sr.pllrdy(0))
772 || (pll2_src == Pllsel::HSE && rcc_sr.pllrdy(1))
773 || (pll3_src == Pllsel::HSE && rcc_sr.pllrdy(2))
774 || (pll4_src == Pllsel::HSE && rcc_sr.pllrdy(3))
775 {
776 panic!(
777 "When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
778 );
779 } else {
780 debug!("HSE off");
781
782 RCC.ccr().write(|w| w.set_hseonc(true));
783 RCC.hsecfgr().modify(|w| {
784 w.set_hseext(Hseext::ANALOG);
785 w.set_hsebyp(false);
786 });
787
788 // wait until the hse is disabled
789 while RCC.sr().read().hserdy() {}
790
791 None
792 };
793
794 // hsi configuration
795 debug!("configuring HSI");
796 let hsi = if let Some(hsi) = config.hsi {
797 RCC.csr().write(|w| w.set_hsions(true));
798 while !RCC.sr().read().hsirdy() {}
799
800 // set divider and calibration
801 RCC.hsicfgr().modify(|w| {
802 w.set_hsidiv(hsi.pre);
803 w.set_hsitrim(hsi.trim);
804 });
805
806 Some(HSI_FREQ / hsi.pre)
807 } else if cpu_src == Cpusws::HSI
808 || sys_src == Syssws::HSI
809 || (pll1_src == Pllsel::HSI && rcc_sr.pllrdy(0))
810 || (pll2_src == Pllsel::HSI && rcc_sr.pllrdy(1))
811 || (pll3_src == Pllsel::HSI && rcc_sr.pllrdy(2))
812 || (pll4_src == Pllsel::HSI && rcc_sr.pllrdy(3))
813 {
814 panic!(
815 "When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
816 );
817 } else {
818 debug!("HSI off");
819
820 RCC.ccr().write(|w| w.set_hsionc(true));
821 while RCC.sr().read().hsirdy() {}
822
823 None
824 };
825
826 // msi configuration
827 debug!("configuring MSI");
828 let msi = if let Some(msi) = config.msi {
829 RCC.msicfgr().modify(|w| w.set_msifreqsel(msi.freq));
830 RCC.csr().write(|w| w.set_msions(true));
831 while !RCC.sr().read().msirdy() {}
832 RCC.msicfgr().modify(|w| w.set_msitrim(msi.trim));
833
834 Some(match msi.freq {
835 Msifreqsel::_4MHZ => Hertz::mhz(4),
836 Msifreqsel::_16MHZ => Hertz::mhz(16),
837 })
838 } else if cpu_src == Cpusws::MSI
839 || sys_src == Syssws::MSI
840 || (pll1_src == Pllsel::MSI && rcc_sr.pllrdy(0))
841 || (pll2_src == Pllsel::MSI && rcc_sr.pllrdy(1))
842 || (pll3_src == Pllsel::MSI && rcc_sr.pllrdy(2))
843 || (pll4_src == Pllsel::MSI && rcc_sr.pllrdy(3))
844 {
845 panic!(
846 "When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
847 );
848 } else {
849 RCC.ccr().write(|w| w.set_msionc(true));
850 while RCC.sr().read().msirdy() {}
851
852 None
853 };
854
855 // lsi configuration
856 debug!("configuring LSI");
857 let lsi = if config.lsi {
858 RCC.csr().write(|w| w.set_lsions(true));
859 while !RCC.sr().read().lsirdy() {}
860 Some(super::LSI_FREQ)
861 } else {
862 RCC.ccr().write(|w| w.set_lsionc(true));
863 while RCC.sr().read().lsirdy() {}
864 None
865 };
866
867 // lse configuration
868 debug!("configuring LSE");
869 let lse = if config.lse {
870 RCC.csr().write(|w| w.set_lseons(true));
871 while !RCC.sr().read().lserdy() {}
872 Some(LSE_FREQ)
873 } else {
874 RCC.ccr().write(|w| w.set_lseonc(true));
875 while RCC.sr().read().lserdy() {}
876 None
877 };
878
879 let pll_input = PllInput {
880 hse,
881 msi,
882 hsi,
883 i2s_ckin: None,
884 };
885
886 // pll1,2,3,4 config
887 let pll_configs = [config.pll1, config.pll2, config.pll3, config.pll4];
888 let mut pll_outputs: [PllOutput; 4] = [PllOutput::default(); 4];
889
890 let ic1_src = RCC.iccfgr(0).read().icsel();
891 let ic2_src = RCC.iccfgr(1).read().icsel();
892 let ic6_src = RCC.iccfgr(5).read().icsel();
893 let ic11_src = RCC.iccfgr(10).read().icsel();
894
895 for (n, (&pll, out)) in pll_configs.iter().zip(pll_outputs.iter_mut()).enumerate() {
896 debug!("configuring PLL{}", n + 1);
897 let pll_ready = RCC.sr().read().pllrdy(n);
898
899 if is_new_pll_config(pll, 0) {
900 let this_pll = Icsel::from_bits(n as u8);
901
902 if cpu_src == Cpusws::IC1 && ic1_src == this_pll {
903 panic!("PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)")
904 }
905
906 if sys_src == Syssws::IC2 && (ic2_src == this_pll || ic6_src == this_pll || ic11_src == this_pll) {
907 panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)")
908 }
909
910 *out = init_pll(pll, 0, &pll_input);
911 } else if pll.is_some() && !pll_ready {
912 RCC.csr().write(|w| w.pllons(n));
913 while !RCC.sr().read().pllrdy(n) {}
914 }
915 }
916
917 OscOutput {
918 hsi,
919 hse,
920 msi,
921 lsi,
922 lse,
923 pll1: pll_outputs[0].output,
924 pll2: pll_outputs[1].output,
925 pll3: pll_outputs[2].output,
926 pll4: pll_outputs[3].output,
927 ic1sel: ic1_src,
928 ic2sel: ic2_src,
929 ic6sel: ic6_src,
930 ic11sel: ic11_src,
931 }
932}
933
934fn is_new_pll_config(pll: Option<Pll>, pll_index: usize) -> bool {
935 let cfgr1 = RCC.pllcfgr1(pll_index).read();
936 let cfgr2 = RCC.pllcfgr2(pll_index).read();
937 let cfgr3 = RCC.pllcfgr3(pll_index).read();
938
939 let ready = RCC.sr().read().pllrdy(pll_index);
940 let bypass = cfgr1.pllbyp();
941
942 match (pll, ready, bypass) {
943 (None, true, _) => return true,
944 (Some(_), false, _) => return true,
945 (Some(conf), true, bypass) => match (conf, bypass) {
946 (Pll::Bypass { .. }, false) => return true,
947 (Pll::Oscillator { .. }, true) => return true,
948 _ => {}
949 },
950 _ => {}
951 }
952
953 match pll {
954 Some(Pll::Bypass { source }) => cfgr1.pllsel() != source,
955 Some(Pll::Oscillator {
956 source,
957 divm: m,
958 fractional,
959 divn: n,
960 divp1: p1,
961 divp2: p2,
962 }) => {
963 cfgr1.pllsel() != source
964 || cfgr1.plldivm() != m
965 || cfgr1.plldivn() != n
966 || cfgr2.plldivnfrac() != fractional
967 || cfgr3.pllpdiv1() != p1
968 || cfgr3.pllpdiv2() != p2
969 }
970 None => false,
971 }
972}
973
974pub(crate) unsafe fn init(config: Config) {
975 debug!("enabling SYSCFG");
976 // system configuration setup
977 RCC.apb4hensr().write(|w| w.set_syscfgens(true));
978 // delay after RCC peripheral clock enabling
979 RCC.apb4hensr().read();
980
981 debug!("setting VTOR");
982
983 let vtor = unsafe {
984 let p = cortex_m::Peripherals::steal();
985 p.SCB.vtor.read()
986 };
987
988 // set default vector table location after reset or standby
989 SYSCFG.initsvtorcr().write(|w| w.set_svtor_addr(vtor));
990 // read back the value to ensure it is written before deactivating SYSCFG
991 SYSCFG.initsvtorcr().read();
992
993 debug!("deactivating SYSCFG");
994
995 // deactivate SYSCFG
996 RCC.apb4hensr().write(|w| w.set_syscfgens(false));
997
998 debug!("enabling FPU");
999
1000 // enable fpu
1001 unsafe {
1002 let p = cortex_m::Peripherals::steal();
1003 p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22));
1004 }
1005
1006 // TODO: ugly workaround for DMA accesses until RIF is properly implemented
1007 debug!("deactivating RIF");
1008 const RISAF3_BASE_NS: *mut u32 = stm32_metapac::RNG.wrapping_byte_offset(0x8000) as _; // AHB3PERIPH_BASE_NS + 0x8000UL
1009 const RISAF3_REG0_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x40);
1010 const RISAF3_REG0_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x48);
1011 const RISAF3_REG0_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x4C);
1012 const RISAF3_REG1_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x80);
1013 const RISAF3_REG1_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x88);
1014 const RISAF3_REG1_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x8C);
1015 unsafe {
1016 *RISAF3_REG0_CIDCFGR = 0x000F000F; /* RW for everyone */
1017 *RISAF3_REG0_ENDR = 0xFFFFFFFF; /* all-encompassing */
1018 *RISAF3_REG0_CFGR = 0x00000101; /* enabled, secure, unprivileged for everyone */
1019 *RISAF3_REG1_CIDCFGR = 0x00FF00FF; /* RW for everyone */
1020 *RISAF3_REG1_ENDR = 0xFFFFFFFF; /* all-encompassing */
1021 *RISAF3_REG1_CFGR = 0x00000001; /* enabled, non-secure, unprivileged*/
1022 }
1023
1024 debug!("setting power supply config");
1025
1026 power_supply_config(config.supply_config);
1027
1028 let osc = init_osc(config);
1029 let clock_inputs = ClocksInput {
1030 hsi: osc.hsi,
1031 msi: osc.msi,
1032 hse: osc.hse,
1033 };
1034 let clocks = init_clocks(config, &clock_inputs);
1035
1036 // TODO: sysb, sysc, sysd must have the same clock source
1037
1038 set_clocks!(
1039 sys: Some(clocks.sysclk),
1040 hsi: osc.hsi,
1041 hsi_div: None,
1042 hse: osc.hse,
1043 msi: osc.msi,
1044 hclk1: Some(clocks.ahb),
1045 hclk2: Some(clocks.ahb),
1046 hclk3: Some(clocks.ahb),
1047 hclk4: Some(clocks.ahb),
1048 hclk5: Some(clocks.ahb),
1049 pclk1: Some(clocks.apb1),
1050 pclk2: Some(clocks.apb2),
1051 pclk1_tim: Some(clocks.pclk_tim),
1052 pclk2_tim: Some(clocks.pclk_tim),
1053 pclk4: Some(clocks.apb4),
1054 pclk5: Some(clocks.apb5),
1055 per: None,
1056 rtc: None,
1057 i2s_ckin: None,
1058 ic8: None,
1059 ic9: None,
1060 ic10: None,
1061 ic14: None,
1062 ic15: None,
1063 ic17: None,
1064 ic20: None,
1065 );
1066}
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 06895a99a..47cc29c6f 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -6,9 +6,9 @@ pub use crate::pac::rcc::vals::{
6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
7}; 7};
8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge}; 8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge};
9#[cfg(all(peri_usb_otg_hs))]
10pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
11use crate::pac::{FLASH, PWR, RCC}; 9use crate::pac::{FLASH, PWR, RCC};
10#[cfg(all(peri_usb_otg_hs))]
11pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel};
12use crate::rcc::LSI_FREQ; 12use crate::rcc::LSI_FREQ;
13use crate::time::Hertz; 13use crate::time::Hertz;
14 14
@@ -343,6 +343,16 @@ pub(crate) unsafe fn init(config: Config) {
343 343
344 let hsi48 = config.hsi48.map(super::init_hsi48); 344 let hsi48 = config.hsi48.map(super::init_hsi48);
345 345
346 // There's a possibility that a bootloader that ran before us has configured the system clock
347 // source to be PLL1_R. In that case we'd get forever stuck on (de)configuring PLL1 as the chip
348 // prohibits disabling PLL1 when it's used as a source for system clock. Change the system
349 // clock source to MSIS which doesn't suffer from this conflict. The correct source per the
350 // provided config is then set further down.
351 // See https://github.com/embassy-rs/embassy/issues/5072
352 let default_system_clock_source = Config::default().sys;
353 RCC.cfgr1().modify(|w| w.set_sw(default_system_clock_source));
354 while RCC.cfgr1().read().sws() != default_system_clock_source {}
355
346 let pll_input = PllInput { hse, hsi, msi: msis }; 356 let pll_input = PllInput { hse, hsi, msi: msis };
347 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range); 357 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range);
348 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); 358 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range);
@@ -442,7 +452,10 @@ pub(crate) unsafe fn init(config: Config) {
442 Hertz(24_000_000) => Usbrefcksel::MHZ24, 452 Hertz(24_000_000) => Usbrefcksel::MHZ24,
443 Hertz(26_000_000) => Usbrefcksel::MHZ26, 453 Hertz(26_000_000) => Usbrefcksel::MHZ26,
444 Hertz(32_000_000) => Usbrefcksel::MHZ32, 454 Hertz(32_000_000) => Usbrefcksel::MHZ32,
445 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 455 _ => panic!(
456 "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
457 clk_val
458 ),
446 }, 459 },
447 None => Usbrefcksel::MHZ24, 460 None => Usbrefcksel::MHZ24,
448 }; 461 };
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 481437939..2528996d5 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -7,9 +7,9 @@ pub use crate::pac::rcc::vals::{
7 Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, 7 Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv,
8 Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk, 8 Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk,
9}; 9};
10#[cfg(all(peri_usb_otg_hs))]
11pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
12use crate::pac::{FLASH, RCC}; 10use crate::pac::{FLASH, RCC};
11#[cfg(all(peri_usb_otg_hs))]
12pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel};
13use crate::rcc::LSI_FREQ; 13use crate::rcc::LSI_FREQ;
14use crate::time::Hertz; 14use crate::time::Hertz;
15 15
@@ -245,7 +245,10 @@ pub(crate) unsafe fn init(config: Config) {
245 Hertz(24_000_000) => Usbrefcksel::MHZ24, 245 Hertz(24_000_000) => Usbrefcksel::MHZ24,
246 Hertz(26_000_000) => Usbrefcksel::MHZ26, 246 Hertz(26_000_000) => Usbrefcksel::MHZ26,
247 Hertz(32_000_000) => Usbrefcksel::MHZ32, 247 Hertz(32_000_000) => Usbrefcksel::MHZ32,
248 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 248 _ => panic!(
249 "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
250 clk_val
251 ),
249 }, 252 },
250 None => Usbrefcksel::MHZ24, 253 None => Usbrefcksel::MHZ24,
251 }; 254 };
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 63654639e..b8dfc7ecf 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -9,10 +9,27 @@ use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, pac, peripherals, rcc, Peri}; 12use crate::{Peri, interrupt, pac, peripherals, rcc};
13 13
14static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 14static RNG_WAKER: AtomicWaker = AtomicWaker::new();
15 15
16/// WBA-specific health test configuration values for RNG
17#[derive(Clone, Copy)]
18#[allow(dead_code)]
19enum Htcfg {
20 /// WBA-specific health test configuration (0x0000AAC7)
21 /// Corresponds to configuration A, B, and C thresholds as recommended in the reference manual
22 WbaRecommended = 0x0000_AAC7,
23}
24
25impl Htcfg {
26 /// Convert to the raw u32 value for register access
27 #[allow(dead_code)]
28 fn value(self) -> u32 {
29 self as u32
30 }
31}
32
16/// RNG error 33/// RNG error
17#[derive(Debug, PartialEq, Eq, Clone, Copy)] 34#[derive(Debug, PartialEq, Eq, Clone, Copy)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))] 35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -100,7 +117,7 @@ impl<'d, T: Instance> Rng<'d, T> {
100 // wait for CONDRST to be set 117 // wait for CONDRST to be set
101 while !T::regs().cr().read().condrst() {} 118 while !T::regs().cr().read().condrst() {}
102 119
103 // TODO for WBA6, the HTCR reg is different 120 // Set health test configuration values
104 #[cfg(not(rng_wba6))] 121 #[cfg(not(rng_wba6))]
105 { 122 {
106 // magic number must be written immediately before every read or write access to HTCR 123 // magic number must be written immediately before every read or write access to HTCR
@@ -111,6 +128,12 @@ impl<'d, T: Instance> Rng<'d, T> {
111 .htcr() 128 .htcr()
112 .write(|w| w.set_htcfg(pac::rng::vals::Htcfg::RECOMMENDED)); 129 .write(|w| w.set_htcfg(pac::rng::vals::Htcfg::RECOMMENDED));
113 } 130 }
131 #[cfg(rng_wba6)]
132 {
133 // For WBA6, set RNG_HTCR0 to the recommended value for configurations A, B, and C
134 // This value corresponds to the health test thresholds specified in the reference manual
135 T::regs().htcr(0).write(|w| w.0 = Htcfg::WbaRecommended.value());
136 }
114 137
115 // finish conditioning 138 // finish conditioning
116 T::regs().cr().modify(|reg| { 139 T::regs().cr().modify(|reg| {
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index a81ac6746..f049d6b12 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -1,10 +1,11 @@
1#[cfg(feature = "time")] 1#[cfg(feature = "time")]
2use embassy_time::{Duration, TICK_HZ}; 2use embassy_time::{Duration, TICK_HZ};
3 3
4use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; 4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte};
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::pac::rtc::vals::Wucksel;
6use crate::peripherals::RTC; 7use crate::peripherals::RTC;
7use crate::rtc::SealedInstance; 8use crate::rtc::{RtcTimeProvider, SealedInstance};
8 9
9/// Represents an instant in time that can be substracted to compute a duration 10/// Represents an instant in time that can be substracted to compute a duration
10pub(super) struct RtcInstant { 11pub(super) struct RtcInstant {
@@ -58,66 +59,22 @@ impl core::ops::Sub for RtcInstant {
58 } 59 }
59} 60}
60 61
61#[repr(u8)] 62fn wucksel_compute_min(val: u32) -> (Wucksel, u32) {
62#[derive(Clone, Copy, Debug)] 63 *[
63pub(crate) enum WakeupPrescaler { 64 (Wucksel::DIV2, 2),
64 Div2 = 2, 65 (Wucksel::DIV4, 4),
65 Div4 = 4, 66 (Wucksel::DIV8, 8),
66 Div8 = 8, 67 (Wucksel::DIV16, 16),
67 Div16 = 16, 68 ]
68} 69 .iter()
69 70 .find(|(_, psc)| *psc as u32 > val)
70#[cfg(any( 71 .unwrap_or(&(Wucksel::DIV16, 16))
71 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba
72))]
73impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
74 fn from(val: WakeupPrescaler) -> Self {
75 use crate::pac::rtc::vals::Wucksel;
76
77 match val {
78 WakeupPrescaler::Div2 => Wucksel::DIV2,
79 WakeupPrescaler::Div4 => Wucksel::DIV4,
80 WakeupPrescaler::Div8 => Wucksel::DIV8,
81 WakeupPrescaler::Div16 => Wucksel::DIV16,
82 }
83 }
84}
85
86#[cfg(any(
87 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba
88))]
89impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
90 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
91 use crate::pac::rtc::vals::Wucksel;
92
93 match val {
94 Wucksel::DIV2 => WakeupPrescaler::Div2,
95 Wucksel::DIV4 => WakeupPrescaler::Div4,
96 Wucksel::DIV8 => WakeupPrescaler::Div8,
97 Wucksel::DIV16 => WakeupPrescaler::Div16,
98 _ => unreachable!(),
99 }
100 }
101}
102
103impl WakeupPrescaler {
104 pub fn compute_min(val: u32) -> Self {
105 *[
106 WakeupPrescaler::Div2,
107 WakeupPrescaler::Div4,
108 WakeupPrescaler::Div8,
109 WakeupPrescaler::Div16,
110 ]
111 .iter()
112 .find(|psc| **psc as u32 > val)
113 .unwrap_or(&WakeupPrescaler::Div16)
114 }
115} 72}
116 73
117impl Rtc { 74impl Rtc {
118 /// Return the current instant. 75 /// Return the current instant.
119 fn instant(&self) -> Result<RtcInstant, RtcError> { 76 fn instant(&self) -> Result<RtcInstant, RtcError> {
120 self.time_provider().read(|_, tr, ss| { 77 RtcTimeProvider::new().read(|_, tr, ss| {
121 let second = bcd2_to_byte((tr.st(), tr.su())); 78 let second = bcd2_to_byte((tr.st(), tr.su()));
122 79
123 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) 80 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
@@ -127,7 +84,7 @@ impl Rtc {
127 /// start the wakeup alarm and with a duration that is as close to but less than 84 /// start the wakeup alarm and with a duration that is as close to but less than
128 /// the requested duration, and record the instant the wakeup alarm was started 85 /// the requested duration, and record the instant the wakeup alarm was started
129 pub(crate) fn start_wakeup_alarm( 86 pub(crate) fn start_wakeup_alarm(
130 &self, 87 &mut self,
131 requested_duration: embassy_time::Duration, 88 requested_duration: embassy_time::Duration,
132 cs: critical_section::CriticalSection, 89 cs: critical_section::CriticalSection,
133 ) { 90 ) {
@@ -138,7 +95,7 @@ impl Rtc {
138 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); 95 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
139 let rtc_hz = Self::frequency().0 as u64; 96 let rtc_hz = Self::frequency().0 as u64;
140 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; 97 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
141 let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); 98 let (wucksel, prescaler) = wucksel_compute_min((rtc_ticks / u16::MAX as u64) as u32);
142 99
143 // adjust the rtc ticks to the prescaler and subtract one rtc tick 100 // adjust the rtc ticks to the prescaler and subtract one rtc tick
144 let rtc_ticks = rtc_ticks / prescaler as u64; 101 let rtc_ticks = rtc_ticks / prescaler as u64;
@@ -159,7 +116,7 @@ impl Rtc {
159 while !regs.icsr().read().wutwf() {} 116 while !regs.icsr().read().wutwf() {}
160 } 117 }
161 118
162 regs.cr().modify(|w| w.set_wucksel(prescaler.into())); 119 regs.cr().modify(|w| w.set_wucksel(wucksel));
163 regs.wutr().write(|w| w.set_wut(rtc_ticks)); 120 regs.wutr().write(|w| w.set_wut(rtc_ticks));
164 regs.cr().modify(|w| w.set_wute(true)); 121 regs.cr().modify(|w| w.set_wute(true));
165 regs.cr().modify(|w| w.set_wutie(true)); 122 regs.cr().modify(|w| w.set_wutie(true));
@@ -179,7 +136,10 @@ impl Rtc {
179 136
180 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` 137 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
181 /// was called, otherwise none 138 /// was called, otherwise none
182 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 139 pub(crate) fn stop_wakeup_alarm(
140 &mut self,
141 cs: critical_section::CriticalSection,
142 ) -> Option<embassy_time::Duration> {
183 let instant = self.instant().unwrap(); 143 let instant = self.instant().unwrap();
184 if RTC::regs().cr().read().wute() { 144 if RTC::regs().cr().read().wute() {
185 trace!("rtc: stop wakeup alarm at {}", instant); 145 trace!("rtc: stop wakeup alarm at {}", instant);
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 92dec0960..e88bd7ab2 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -5,15 +5,19 @@ mod datetime;
5mod low_power; 5mod low_power;
6 6
7#[cfg(feature = "low-power")] 7#[cfg(feature = "low-power")]
8use core::cell::Cell; 8use core::cell::{Cell, RefCell, RefMut};
9#[cfg(feature = "low-power")]
10use core::ops;
9 11
10#[cfg(feature = "low-power")] 12#[cfg(feature = "low-power")]
11use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 13use critical_section::CriticalSection;
12#[cfg(feature = "low-power")] 14#[cfg(feature = "low-power")]
13use embassy_sync::blocking_mutex::Mutex; 15use embassy_sync::blocking_mutex::Mutex;
16#[cfg(feature = "low-power")]
17use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
14 18
15use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
16pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; 19pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
20use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
17use crate::pac::rtc::regs::{Dr, Tr}; 21use crate::pac::rtc::regs::{Dr, Tr};
18use crate::time::Hertz; 22use crate::time::Hertz;
19 23
@@ -25,8 +29,8 @@ mod _version;
25#[allow(unused_imports)] 29#[allow(unused_imports)]
26pub use _version::*; 30pub use _version::*;
27 31
28use crate::peripherals::RTC;
29use crate::Peri; 32use crate::Peri;
33use crate::peripherals::RTC;
30 34
31/// Errors that can occur on methods on [RtcClock] 35/// Errors that can occur on methods on [RtcClock]
32#[non_exhaustive] 36#[non_exhaustive]
@@ -44,11 +48,17 @@ pub enum RtcError {
44} 48}
45 49
46/// Provides immutable access to the current time of the RTC. 50/// Provides immutable access to the current time of the RTC.
51#[derive(Clone)]
47pub struct RtcTimeProvider { 52pub struct RtcTimeProvider {
48 _private: (), 53 _private: (),
49} 54}
50 55
51impl RtcTimeProvider { 56impl RtcTimeProvider {
57 /// Create a new RTC time provider instance.
58 pub(self) const fn new() -> Self {
59 Self { _private: () }
60 }
61
52 /// Return the current datetime. 62 /// Return the current datetime.
53 /// 63 ///
54 /// # Errors 64 /// # Errors
@@ -106,6 +116,50 @@ impl RtcTimeProvider {
106 } 116 }
107} 117}
108 118
119#[cfg(feature = "low-power")]
120/// Contains an RTC driver.
121pub struct RtcContainer {
122 pub(self) mutex: &'static Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
123}
124
125#[cfg(feature = "low-power")]
126impl RtcContainer {
127 pub(self) const fn new() -> Self {
128 Self {
129 mutex: &crate::time_driver::get_driver().rtc,
130 }
131 }
132
133 /// Acquire an RTC borrow.
134 pub fn borrow_mut<'a>(&self, cs: CriticalSection<'a>) -> RtcBorrow<'a> {
135 RtcBorrow {
136 ref_mut: self.mutex.borrow(cs).borrow_mut(),
137 }
138 }
139}
140
141#[cfg(feature = "low-power")]
142/// Contains an RTC borrow.
143pub struct RtcBorrow<'a> {
144 pub(self) ref_mut: RefMut<'a, Option<Rtc>>,
145}
146
147#[cfg(feature = "low-power")]
148impl<'a> ops::Deref for RtcBorrow<'a> {
149 type Target = Rtc;
150
151 fn deref(&self) -> &Self::Target {
152 self.ref_mut.as_ref().unwrap()
153 }
154}
155
156#[cfg(feature = "low-power")]
157impl<'a> ops::DerefMut for RtcBorrow<'a> {
158 fn deref_mut(&mut self) -> &mut Self::Target {
159 self.ref_mut.as_mut().unwrap()
160 }
161}
162
109/// RTC driver. 163/// RTC driver.
110pub struct Rtc { 164pub struct Rtc {
111 #[cfg(feature = "low-power")] 165 #[cfg(feature = "low-power")]
@@ -121,13 +175,21 @@ pub struct RtcConfig {
121 /// 175 ///
122 /// A high counter frequency may impact stop power consumption 176 /// A high counter frequency may impact stop power consumption
123 pub frequency: Hertz, 177 pub frequency: Hertz,
178
179 #[cfg(feature = "_allow-disable-rtc")]
180 /// Allow disabling the rtc, even when stop is configured
181 pub _disable_rtc: bool,
124} 182}
125 183
126impl Default for RtcConfig { 184impl Default for RtcConfig {
127 /// LSI with prescalers assuming 32.768 kHz. 185 /// LSI with prescalers assuming 32.768 kHz.
128 /// Raw sub-seconds in 1/256. 186 /// Raw sub-seconds in 1/256.
129 fn default() -> Self { 187 fn default() -> Self {
130 RtcConfig { frequency: Hertz(256) } 188 RtcConfig {
189 frequency: Hertz(256),
190 #[cfg(feature = "_allow-disable-rtc")]
191 _disable_rtc: false,
192 }
131 } 193 }
132} 194}
133 195
@@ -145,8 +207,19 @@ pub enum RtcCalibrationCyclePeriod {
145} 207}
146 208
147impl Rtc { 209impl Rtc {
210 #[cfg(not(feature = "low-power"))]
148 /// Create a new RTC instance. 211 /// Create a new RTC instance.
149 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { 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")]
217 /// Create a new RTC instance.
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,18 @@ trait SealedInstance {
315 377
316 // fn apply_config(&mut self, rtc_config: RtcConfig); 378 // fn apply_config(&mut self, rtc_config: RtcConfig);
317} 379}
380
381#[cfg(feature = "low-power")]
382pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig, min_stop_pause: embassy_time::Duration) {
383 use crate::time_driver::get_driver;
384
385 #[cfg(feature = "_allow-disable-rtc")]
386 if config._disable_rtc {
387 return;
388 }
389
390 get_driver().set_rtc(cs, Rtc::new_inner(config));
391 get_driver().set_min_stop_pause(cs, min_stop_pause);
392
393 trace!("low power: stop with rtc configured");
394}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 23f6ccb0c..8ac022536 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -93,7 +93,7 @@ impl super::Rtc {
93 }) 93 })
94 } 94 }
95 95
96 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 96 pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
97 where 97 where
98 F: FnOnce(crate::pac::rtc::Rtc) -> R, 98 F: FnOnce(crate::pac::rtc::Rtc) -> R,
99 { 99 {
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index d0b52049e..f7ebea73e 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -1,4 +1,4 @@
1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; 1use stm32_metapac::rtc::vals::{Calp, Calw8, Calw16, Fmt, Key, Osel, Pol, TampalrmType};
2 2
3use super::RtcCalibrationCyclePeriod; 3use super::RtcCalibrationCyclePeriod;
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
@@ -95,7 +95,7 @@ impl super::Rtc {
95 }) 95 })
96 } 96 }
97 97
98 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 98 pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
99 where 99 where
100 F: FnOnce(crate::pac::rtc::Rtc) -> R, 100 F: FnOnce(crate::pac::rtc::Rtc) -> R,
101 { 101 {
@@ -131,7 +131,7 @@ impl SealedInstance for crate::peripherals::RTC {
131 131
132 #[cfg(feature = "low-power")] 132 #[cfg(feature = "low-power")]
133 cfg_if::cfg_if!( 133 cfg_if::cfg_if!(
134 if #[cfg(stm32g4)] { 134 if #[cfg(any(stm32g4, stm32wlex))] {
135 const EXTI_WAKEUP_LINE: usize = 20; 135 const EXTI_WAKEUP_LINE: usize = 20;
136 } else if #[cfg(stm32g0)] { 136 } else if #[cfg(stm32g0)] {
137 const EXTI_WAKEUP_LINE: usize = 19; 137 const EXTI_WAKEUP_LINE: usize = 19;
@@ -142,7 +142,7 @@ impl SealedInstance for crate::peripherals::RTC {
142 142
143 #[cfg(feature = "low-power")] 143 #[cfg(feature = "low-power")]
144 cfg_if::cfg_if!( 144 cfg_if::cfg_if!(
145 if #[cfg(stm32g4)] { 145 if #[cfg(any(stm32g4, stm32wlex))] {
146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
147 } else if #[cfg(any(stm32g0, stm32u0))] { 147 } else if #[cfg(any(stm32g0, stm32u0))] {
148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; 148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index fb8b23b79..579c34c13 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -6,12 +6,12 @@ use core::marker::PhantomData;
6use embassy_hal_internal::PeripheralType; 6use embassy_hal_internal::PeripheralType;
7 7
8pub use crate::dma::word; 8pub use crate::dma::word;
9use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; 9use crate::dma::{Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer, ringbuffer};
10use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
11pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider; 11pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider;
12use crate::pac::sai::{vals, Sai as Regs}; 12use crate::pac::sai::{Sai as Regs, vals};
13use crate::rcc::{self, RccPeripheral}; 13use crate::rcc::{self, RccPeripheral};
14use crate::{peripherals, Peri}; 14use crate::{Peri, peripherals};
15 15
16/// SAI error 16/// SAI error
17#[derive(Debug, PartialEq, Eq, Clone, Copy)] 17#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -391,10 +391,11 @@ pub struct Config {
391 pub frame_sync_polarity: FrameSyncPolarity, 391 pub frame_sync_polarity: FrameSyncPolarity,
392 pub frame_sync_active_level_length: word::U7, 392 pub frame_sync_active_level_length: word::U7,
393 pub frame_sync_definition: FrameSyncDefinition, 393 pub frame_sync_definition: FrameSyncDefinition,
394 pub frame_length: u8, 394 pub frame_length: u16,
395 pub clock_strobe: ClockStrobe, 395 pub clock_strobe: ClockStrobe,
396 pub output_drive: OutputDrive, 396 pub output_drive: OutputDrive,
397 pub master_clock_divider: Option<MasterClockDivider>, 397 pub master_clock_divider: MasterClockDivider,
398 pub nodiv: bool,
398 pub is_high_impedance_on_inactive_slot: bool, 399 pub is_high_impedance_on_inactive_slot: bool,
399 pub fifo_threshold: FifoThreshold, 400 pub fifo_threshold: FifoThreshold,
400 pub companding: Companding, 401 pub companding: Companding,
@@ -423,7 +424,8 @@ impl Default for Config {
423 frame_sync_active_level_length: word::U7(16), 424 frame_sync_active_level_length: word::U7(16),
424 frame_sync_definition: FrameSyncDefinition::ChannelIdentification, 425 frame_sync_definition: FrameSyncDefinition::ChannelIdentification,
425 frame_length: 32, 426 frame_length: 32,
426 master_clock_divider: None, 427 master_clock_divider: MasterClockDivider::DIV1,
428 nodiv: false,
427 clock_strobe: ClockStrobe::Rising, 429 clock_strobe: ClockStrobe::Rising,
428 output_drive: OutputDrive::Immediately, 430 output_drive: OutputDrive::Immediately,
429 is_high_impedance_on_inactive_slot: false, 431 is_high_impedance_on_inactive_slot: false,
@@ -677,8 +679,8 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
677 w.set_syncen(config.sync_input.syncen()); 679 w.set_syncen(config.sync_input.syncen());
678 w.set_mono(config.stereo_mono.mono()); 680 w.set_mono(config.stereo_mono.mono());
679 w.set_outdriv(config.output_drive.outdriv()); 681 w.set_outdriv(config.output_drive.outdriv());
680 w.set_mckdiv(config.master_clock_divider.unwrap_or(MasterClockDivider::DIV1)); 682 w.set_mckdiv(config.master_clock_divider);
681 w.set_nodiv(config.master_clock_divider.is_none()); 683 w.set_nodiv(config.nodiv);
682 w.set_dmaen(true); 684 w.set_dmaen(true);
683 }); 685 });
684 686
@@ -696,7 +698,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
696 w.set_fspol(config.frame_sync_polarity.fspol()); 698 w.set_fspol(config.frame_sync_polarity.fspol());
697 w.set_fsdef(config.frame_sync_definition.fsdef()); 699 w.set_fsdef(config.frame_sync_definition.fsdef());
698 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); 700 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1);
699 w.set_frl(config.frame_length - 1); 701 w.set_frl((config.frame_length - 1).try_into().unwrap());
700 }); 702 });
701 703
702 ch.slotr().modify(|w| { 704 ch.slotr().modify(|w| {
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index ccbd16cbf..cfe18ef52 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -4,16 +4,16 @@
4use core::default::Default; 4use core::default::Default;
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::ops::{Deref, DerefMut}; 7use core::slice;
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_hal_internal::drop::OnDrop; 10use aligned::{A4, Aligned};
11use embassy_hal_internal::{Peri, PeripheralType}; 11use embassy_hal_internal::{Peri, PeripheralType};
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
13use sdio_host::common_cmd::{self, Resp, ResponseLen}; 13use sdio_host::Cmd;
14use sdio_host::emmc::{ExtCSD, EMMC}; 14use sdio_host::common_cmd::{self, R1, R2, R3, Resp, ResponseLen, Rz};
15use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; 15use sdio_host::sd::{BusWidth, CardStatus};
16use sdio_host::{emmc_cmd, sd_cmd, Cmd}; 16use sdio_host::sd_cmd::{R6, R7};
17 17
18#[cfg(sdmmc_v1)] 18#[cfg(sdmmc_v1)]
19use crate::dma::ChannelAndRequest; 19use crate::dma::ChannelAndRequest;
@@ -22,37 +22,27 @@ use crate::gpio::Pull;
22use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 22use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
23use crate::interrupt::typelevel::Interrupt; 23use crate::interrupt::typelevel::Interrupt;
24use crate::pac::sdmmc::Sdmmc as RegBlock; 24use crate::pac::sdmmc::Sdmmc as RegBlock;
25use crate::rcc::{self, RccPeripheral}; 25use crate::rcc::{self, RccInfo, RccPeripheral, SealedRccPeripheral};
26use crate::sdmmc::sd::Addressable;
26use crate::time::Hertz; 27use crate::time::Hertz;
27use crate::{interrupt, peripherals}; 28use crate::{interrupt, peripherals};
28 29
30/// Module for SD and EMMC cards
31pub mod sd;
32
33/// Module for SDIO interface
34pub mod sdio;
35
29/// Interrupt handler. 36/// Interrupt handler.
30pub struct InterruptHandler<T: Instance> { 37pub struct InterruptHandler<T: Instance> {
31 _phantom: PhantomData<T>, 38 _phantom: PhantomData<T>,
32} 39}
33 40
34impl<T: Instance> InterruptHandler<T> {
35 fn enable_interrupts() {
36 let regs = T::regs();
37 regs.maskr().write(|w| {
38 w.set_dcrcfailie(true);
39 w.set_dtimeoutie(true);
40 w.set_dataendie(true);
41 w.set_dbckendie(true);
42
43 #[cfg(sdmmc_v1)]
44 w.set_stbiterre(true);
45 #[cfg(sdmmc_v2)]
46 w.set_dabortie(true);
47 });
48 }
49}
50
51impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 41impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
52 unsafe fn on_interrupt() { 42 unsafe fn on_interrupt() {
53 T::state().wake(); 43 T::state().waker.wake();
54 let status = T::regs().star().read(); 44 let status = T::info().regs.star().read();
55 T::regs().maskr().modify(|w| { 45 T::info().regs.maskr().modify(|w| {
56 if status.dcrcfail() { 46 if status.dcrcfail() {
57 w.set_dcrcfailie(false) 47 w.set_dcrcfailie(false)
58 } 48 }
@@ -77,6 +67,57 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
77 } 67 }
78} 68}
79 69
70struct U128(pub u128);
71
72trait TypedResp: Resp {
73 type Word: From<U128>;
74}
75
76impl From<U128> for () {
77 fn from(value: U128) -> Self {
78 match value.0 {
79 0 => (),
80 _ => unreachable!(),
81 }
82 }
83}
84
85impl From<U128> for u32 {
86 fn from(value: U128) -> Self {
87 unwrap!(value.0.try_into())
88 }
89}
90
91impl From<U128> for u128 {
92 fn from(value: U128) -> Self {
93 value.0
94 }
95}
96
97impl TypedResp for Rz {
98 type Word = ();
99}
100
101impl TypedResp for R1 {
102 type Word = u32;
103}
104
105impl TypedResp for R2 {
106 type Word = u128;
107}
108
109impl TypedResp for R3 {
110 type Word = u32;
111}
112
113impl TypedResp for R6 {
114 type Word = u32;
115}
116
117impl TypedResp for R7 {
118 type Word = u32;
119}
120
80/// Frequency used for SD Card initialization. Must be no higher than 400 kHz. 121/// Frequency used for SD Card initialization. Must be no higher than 400 kHz.
81const SD_INIT_FREQ: Hertz = Hertz(400_000); 122const SD_INIT_FREQ: Hertz = Hertz(400_000);
82 123
@@ -99,54 +140,36 @@ impl Default for Signalling {
99 } 140 }
100} 141}
101 142
102/// Aligned data block for SDMMC transfers. 143const fn aligned_mut(x: &mut [u32]) -> &mut Aligned<A4, [u8]> {
103/// 144 let len = x.len() * 4;
104/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements. 145 unsafe { core::mem::transmute(slice::from_raw_parts_mut(x.as_mut_ptr() as *mut u8, len)) }
105#[repr(align(4))]
106#[derive(Debug, Clone, PartialEq, Eq)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))]
108pub struct DataBlock(pub [u8; 512]);
109
110impl Deref for DataBlock {
111 type Target = [u8; 512];
112
113 fn deref(&self) -> &Self::Target {
114 &self.0
115 }
116} 146}
117 147
118impl DerefMut for DataBlock { 148const fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
119 fn deref_mut(&mut self) -> &mut Self::Target { 149 let len = x.len() * 4;
120 &mut self.0 150 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as *mut u8, len) }
121 }
122} 151}
123 152
124/// Command Block buffer for SDMMC command transfers. 153#[allow(unused)]
125/// 154const fn slice32_mut(x: &mut Aligned<A4, [u8]>) -> &mut [u32] {
126/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required. 155 let len = (size_of_val(x) + 4 - 1) / 4;
127#[derive(Debug, Clone, PartialEq, Eq)] 156 unsafe { slice::from_raw_parts_mut(x as *mut Aligned<A4, [u8]> as *mut u32, len) }
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub struct CmdBlock(pub [u32; 16]);
130
131impl CmdBlock {
132 /// Creates a new instance of CmdBlock
133 pub const fn new() -> Self {
134 Self([0u32; 16])
135 }
136} 157}
137 158
138impl Deref for CmdBlock { 159const fn aligned_ref(x: &[u32]) -> &Aligned<A4, [u8]> {
139 type Target = [u32; 16]; 160 let len = x.len() * 4;
161 unsafe { core::mem::transmute(slice::from_raw_parts(x.as_ptr() as *const u8, len)) }
162}
140 163
141 fn deref(&self) -> &Self::Target { 164const fn slice8_ref(x: &[u32]) -> &[u8] {
142 &self.0 165 let len = x.len() * 4;
143 } 166 unsafe { slice::from_raw_parts(x.as_ptr() as *const u8, len) }
144} 167}
145 168
146impl DerefMut for CmdBlock { 169#[allow(unused)]
147 fn deref_mut(&mut self) -> &mut Self::Target { 170const fn slice32_ref(x: &Aligned<A4, [u8]>) -> &[u32] {
148 &mut self.0 171 let len = (size_of_val(x) + 4 - 1) / 4;
149 } 172 unsafe { slice::from_raw_parts(x as *const Aligned<A4, [u8]> as *const u32, len) }
150} 173}
151 174
152/// Errors 175/// Errors
@@ -181,48 +204,17 @@ pub enum Error {
181 StBitErr, 204 StBitErr,
182} 205}
183 206
184#[derive(Clone, Copy, Debug, Default)]
185/// SD Card
186pub struct Card {
187 /// The type of this card
188 pub card_type: CardCapacity,
189 /// Operation Conditions Register
190 pub ocr: OCR<SD>,
191 /// Relative Card Address
192 pub rca: u16,
193 /// Card ID
194 pub cid: CID<SD>,
195 /// Card Specific Data
196 pub csd: CSD<SD>,
197 /// SD CARD Configuration Register
198 pub scr: SCR,
199 /// SD Status
200 pub status: SDStatus,
201}
202
203#[derive(Clone, Copy, Debug, Default)]
204/// eMMC storage
205pub struct Emmc {
206 /// The capacity of this card
207 pub capacity: CardCapacity,
208 /// Operation Conditions Register
209 pub ocr: OCR<EMMC>,
210 /// Relative Card Address
211 pub rca: u16,
212 /// Card ID
213 pub cid: CID<EMMC>,
214 /// Card Specific Data
215 pub csd: CSD<EMMC>,
216 /// Extended Card Specific Data
217 pub ext_csd: ExtCSD,
218}
219
220#[repr(u8)] 207#[repr(u8)]
221enum PowerCtrl { 208enum PowerCtrl {
222 Off = 0b00, 209 Off = 0b00,
223 On = 0b11, 210 On = 0b11,
224} 211}
225 212
213enum DatapathMode {
214 Block(BlockSize),
215 Byte,
216}
217
226fn get_waitresp_val(rlen: ResponseLen) -> u8 { 218fn get_waitresp_val(rlen: ResponseLen) -> u8 {
227 match rlen { 219 match rlen {
228 common_cmd::ResponseLen::Zero => 0, 220 common_cmd::ResponseLen::Zero => 0,
@@ -259,6 +251,55 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> {
259 Ok((false, clk_div, clk_f)) 251 Ok((false, clk_div, clk_f))
260} 252}
261 253
254fn bus_width_vals(bus_width: BusWidth) -> (u8, u32) {
255 match bus_width {
256 BusWidth::One => (0, 1u32),
257 BusWidth::Four => (1, 4u32),
258 BusWidth::Eight => (2, 8u32),
259 _ => panic!("Invalid Bus Width"),
260 }
261}
262
263#[repr(u8)]
264enum BlockSize {
265 Size1 = 0b0000,
266 Size2 = 0b0001,
267 Size4 = 0b0010,
268 Size8 = 0b0011,
269 Size16 = 0b0100,
270 Size32 = 0b0101,
271 Size64 = 0b0110,
272 Size128 = 0b0111,
273 Size256 = 0b1000,
274 Size512 = 0b1001,
275 Size1024 = 0b1010,
276 Size2048 = 0b1011,
277 Size4096 = 0b1100,
278 Size8192 = 0b1101,
279 Size16384 = 0b1110,
280}
281
282const fn block_size(bytes: usize) -> BlockSize {
283 match bytes {
284 1 => BlockSize::Size1,
285 2 => BlockSize::Size2,
286 4 => BlockSize::Size4,
287 8 => BlockSize::Size8,
288 16 => BlockSize::Size16,
289 32 => BlockSize::Size32,
290 64 => BlockSize::Size64,
291 128 => BlockSize::Size128,
292 256 => BlockSize::Size256,
293 512 => BlockSize::Size512,
294 1024 => BlockSize::Size1024,
295 2048 => BlockSize::Size2048,
296 4096 => BlockSize::Size4096,
297 8192 => BlockSize::Size8192,
298 16384 => BlockSize::Size16384,
299 _ => core::unreachable!(),
300 }
301}
302
262/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to 303/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
263/// `sdmmc_ck` in Hertz. 304/// `sdmmc_ck` in Hertz.
264/// 305///
@@ -286,6 +327,34 @@ struct Transfer<'a> {
286 _dummy: PhantomData<&'a ()>, 327 _dummy: PhantomData<&'a ()>,
287} 328}
288 329
330struct WrappedTransfer<'a> {
331 _transfer: Transfer<'a>,
332 sdmmc: &'a Sdmmc<'a>,
333 defused: bool,
334}
335
336impl<'a> WrappedTransfer<'a> {
337 pub const fn new(_transfer: Transfer<'a>, sdmmc: &'a Sdmmc) -> Self {
338 Self {
339 _transfer,
340 sdmmc,
341 defused: false,
342 }
343 }
344
345 pub fn defuse(&mut self) {
346 self.defused = true;
347 }
348}
349
350impl<'a> Drop for WrappedTransfer<'a> {
351 fn drop(&mut self) {
352 if !self.defused {
353 self.sdmmc.on_drop();
354 }
355 }
356}
357
289#[cfg(all(sdmmc_v1, dma))] 358#[cfg(all(sdmmc_v1, dma))]
290const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { 359const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {
291 pburst: crate::dma::Burst::Incr4, 360 pburst: crate::dma::Burst::Incr4,
@@ -323,64 +392,11 @@ impl Default for Config {
323 } 392 }
324} 393}
325 394
326/// Peripheral that can be operated over SDMMC
327#[derive(Clone, Copy, Debug)]
328pub enum SdmmcPeripheral {
329 /// SD Card
330 SdCard(Card),
331 /// eMMC memory
332 Emmc(Emmc),
333}
334
335impl SdmmcPeripheral {
336 /// Get this peripheral's address on the SDMMC bus
337 fn get_address(&self) -> u16 {
338 match self {
339 Self::SdCard(c) => c.rca,
340 Self::Emmc(e) => e.rca,
341 }
342 }
343 /// Is this a standard or high capacity peripheral?
344 fn get_capacity(&self) -> CardCapacity {
345 match self {
346 Self::SdCard(c) => c.card_type,
347 Self::Emmc(e) => e.capacity,
348 }
349 }
350 /// Size in bytes
351 fn size(&self) -> u64 {
352 match self {
353 // SDHC / SDXC / SDUC
354 Self::SdCard(c) => u64::from(c.csd.block_count()) * 512,
355 // capacity > 2GB
356 Self::Emmc(e) => u64::from(e.ext_csd.sector_count()) * 512,
357 }
358 }
359
360 /// Get a mutable reference to the SD Card.
361 ///
362 /// Panics if there is another peripheral instead.
363 fn get_sd_card(&mut self) -> &mut Card {
364 match *self {
365 Self::SdCard(ref mut c) => c,
366 _ => unreachable!("SD only"),
367 }
368 }
369
370 /// Get a mutable reference to the eMMC.
371 ///
372 /// Panics if there is another peripheral instead.
373 fn get_emmc(&mut self) -> &mut Emmc {
374 match *self {
375 Self::Emmc(ref mut e) => e,
376 _ => unreachable!("eMMC only"),
377 }
378 }
379}
380
381/// Sdmmc device 395/// Sdmmc device
382pub struct Sdmmc<'d, T: Instance> { 396pub struct Sdmmc<'d> {
383 _peri: Peri<'d, T>, 397 info: &'static Info,
398 state: &'static State,
399 ker_clk: Hertz,
384 #[cfg(sdmmc_v1)] 400 #[cfg(sdmmc_v1)]
385 dma: ChannelAndRequest<'d>, 401 dma: ChannelAndRequest<'d>,
386 402
@@ -400,12 +416,6 @@ pub struct Sdmmc<'d, T: Instance> {
400 clock: Hertz, 416 clock: Hertz,
401 /// Current signalling scheme to card 417 /// Current signalling scheme to card
402 signalling: Signalling, 418 signalling: Signalling,
403 /// Card
404 card: Option<SdmmcPeripheral>,
405
406 /// An optional buffer to be used for commands
407 /// This should be used if there are special memory location requirements for dma
408 cmd_block: Option<&'d mut CmdBlock>,
409} 419}
410 420
411const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); 421const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh);
@@ -416,9 +426,9 @@ const CMD_AF: AfType = AfType::output_pull(OutputType::PushPull, Speed::VeryHigh
416const DATA_AF: AfType = CMD_AF; 426const DATA_AF: AfType = CMD_AF;
417 427
418#[cfg(sdmmc_v1)] 428#[cfg(sdmmc_v1)]
419impl<'d, T: Instance> Sdmmc<'d, T> { 429impl<'d> Sdmmc<'d> {
420 /// Create a new SDMMC driver, with 1 data lane. 430 /// Create a new SDMMC driver, with 1 data lane.
421 pub fn new_1bit( 431 pub fn new_1bit<T: Instance>(
422 sdmmc: Peri<'d, T>, 432 sdmmc: Peri<'d, T>,
423 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 433 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
424 dma: Peri<'d, impl SdmmcDma<T>>, 434 dma: Peri<'d, impl SdmmcDma<T>>,
@@ -451,7 +461,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
451 } 461 }
452 462
453 /// Create a new SDMMC driver, with 4 data lanes. 463 /// Create a new SDMMC driver, with 4 data lanes.
454 pub fn new_4bit( 464 pub fn new_4bit<T: Instance>(
455 sdmmc: Peri<'d, T>, 465 sdmmc: Peri<'d, T>,
456 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 466 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
457 dma: Peri<'d, impl SdmmcDma<T>>, 467 dma: Peri<'d, impl SdmmcDma<T>>,
@@ -491,9 +501,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
491} 501}
492 502
493#[cfg(sdmmc_v1)] 503#[cfg(sdmmc_v1)]
494impl<'d, T: Instance> Sdmmc<'d, T> { 504impl<'d> Sdmmc<'d> {
495 /// Create a new SDMMC driver, with 8 data lanes. 505 /// Create a new SDMMC driver, with 8 data lanes.
496 pub fn new_8bit( 506 pub fn new_8bit<T: Instance>(
497 sdmmc: Peri<'d, T>, 507 sdmmc: Peri<'d, T>,
498 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 508 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
499 dma: Peri<'d, impl SdmmcDma<T>>, 509 dma: Peri<'d, impl SdmmcDma<T>>,
@@ -541,9 +551,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
541} 551}
542 552
543#[cfg(sdmmc_v2)] 553#[cfg(sdmmc_v2)]
544impl<'d, T: Instance> Sdmmc<'d, T> { 554impl<'d> Sdmmc<'d> {
545 /// Create a new SDMMC driver, with 1 data lane. 555 /// Create a new SDMMC driver, with 1 data lane.
546 pub fn new_1bit( 556 pub fn new_1bit<T: Instance>(
547 sdmmc: Peri<'d, T>, 557 sdmmc: Peri<'d, T>,
548 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 558 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
549 clk: Peri<'d, impl CkPin<T>>, 559 clk: Peri<'d, impl CkPin<T>>,
@@ -574,7 +584,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
574 } 584 }
575 585
576 /// Create a new SDMMC driver, with 4 data lanes. 586 /// Create a new SDMMC driver, with 4 data lanes.
577 pub fn new_4bit( 587 pub fn new_4bit<T: Instance>(
578 sdmmc: Peri<'d, T>, 588 sdmmc: Peri<'d, T>,
579 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 589 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
580 clk: Peri<'d, impl CkPin<T>>, 590 clk: Peri<'d, impl CkPin<T>>,
@@ -612,9 +622,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
612} 622}
613 623
614#[cfg(sdmmc_v2)] 624#[cfg(sdmmc_v2)]
615impl<'d, T: Instance> Sdmmc<'d, T> { 625impl<'d> Sdmmc<'d> {
616 /// Create a new SDMMC driver, with 8 data lanes. 626 /// Create a new SDMMC driver, with 8 data lanes.
617 pub fn new_8bit( 627 pub fn new_8bit<T: Instance>(
618 sdmmc: Peri<'d, T>, 628 sdmmc: Peri<'d, T>,
619 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 629 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
620 clk: Peri<'d, impl CkPin<T>>, 630 clk: Peri<'d, impl CkPin<T>>,
@@ -659,9 +669,24 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
659 } 669 }
660} 670}
661 671
662impl<'d, T: Instance> Sdmmc<'d, T> { 672impl<'d> Sdmmc<'d> {
663 fn new_inner( 673 fn enable_interrupts(&self) {
664 sdmmc: Peri<'d, T>, 674 let regs = self.info.regs;
675 regs.maskr().write(|w| {
676 w.set_dcrcfailie(true);
677 w.set_dtimeoutie(true);
678 w.set_dataendie(true);
679 w.set_dbckendie(true);
680
681 #[cfg(sdmmc_v1)]
682 w.set_stbiterre(true);
683 #[cfg(sdmmc_v2)]
684 w.set_dabortie(true);
685 });
686 }
687
688 fn new_inner<T: Instance>(
689 _sdmmc: Peri<'d, T>,
665 #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, 690 #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>,
666 clk: Peri<'d, AnyPin>, 691 clk: Peri<'d, AnyPin>,
667 cmd: Peri<'d, AnyPin>, 692 cmd: Peri<'d, AnyPin>,
@@ -675,13 +700,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
675 d7: Option<Peri<'d, AnyPin>>, 700 d7: Option<Peri<'d, AnyPin>>,
676 config: Config, 701 config: Config,
677 ) -> Self { 702 ) -> Self {
678 rcc::enable_and_reset::<T>(); 703 rcc::enable_and_reset_without_stop::<T>();
679 704
680 T::Interrupt::unpend(); 705 T::Interrupt::unpend();
681 unsafe { T::Interrupt::enable() }; 706 unsafe { T::Interrupt::enable() };
682 707
683 let regs = T::regs(); 708 let info = T::info();
684 regs.clkcr().write(|w| { 709 let state = T::state();
710 let ker_clk = T::frequency();
711
712 info.regs.clkcr().write(|w| {
685 w.set_pwrsav(false); 713 w.set_pwrsav(false);
686 w.set_negedge(false); 714 w.set_negedge(false);
687 715
@@ -698,10 +726,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
698 726
699 // Power off, writen 00: Clock to the card is stopped; 727 // Power off, writen 00: Clock to the card is stopped;
700 // D[7:0], CMD, and CK are driven high. 728 // D[7:0], CMD, and CK are driven high.
701 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); 729 info.regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
702 730
703 Self { 731 Self {
704 _peri: sdmmc, 732 info,
733 state,
734 ker_clk,
705 #[cfg(sdmmc_v1)] 735 #[cfg(sdmmc_v1)]
706 dma, 736 dma,
707 737
@@ -719,15 +749,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
719 config, 749 config,
720 clock: SD_INIT_FREQ, 750 clock: SD_INIT_FREQ,
721 signalling: Default::default(), 751 signalling: Default::default(),
722 card: None,
723 cmd_block: None,
724 } 752 }
725 } 753 }
726 754
727 /// Data transfer is in progress 755 /// Data transfer is in progress
728 #[inline] 756 #[inline]
729 fn data_active() -> bool { 757 fn data_active(&self) -> bool {
730 let regs = T::regs(); 758 let regs = self.info.regs;
731 759
732 let status = regs.star().read(); 760 let status = regs.star().read();
733 #[cfg(sdmmc_v1)] 761 #[cfg(sdmmc_v1)]
@@ -738,8 +766,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
738 766
739 /// Coammand transfer is in progress 767 /// Coammand transfer is in progress
740 #[inline] 768 #[inline]
741 fn cmd_active() -> bool { 769 fn cmd_active(&self) -> bool {
742 let regs = T::regs(); 770 let regs = self.info.regs;
743 771
744 let status = regs.star().read(); 772 let status = regs.star().read();
745 #[cfg(sdmmc_v1)] 773 #[cfg(sdmmc_v1)]
@@ -750,8 +778,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
750 778
751 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) 779 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
752 #[inline] 780 #[inline]
753 fn wait_idle() { 781 fn wait_idle(&self) {
754 while Self::data_active() || Self::cmd_active() {} 782 while self.data_active() || self.cmd_active() {}
783 }
784
785 fn bus_width(&self) -> BusWidth {
786 match (self.d3.is_some(), self.d7.is_some()) {
787 (true, true) => BusWidth::Eight,
788 (true, false) => BusWidth::Four,
789 _ => BusWidth::One,
790 }
755 } 791 }
756 792
757 /// # Safety 793 /// # Safety
@@ -759,23 +795,32 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
759 /// `buffer` must be valid for the whole transfer and word aligned 795 /// `buffer` must be valid for the whole transfer and word aligned
760 #[allow(unused_variables)] 796 #[allow(unused_variables)]
761 fn prepare_datapath_read<'a>( 797 fn prepare_datapath_read<'a>(
762 config: &Config, 798 &'a self,
763 #[cfg(sdmmc_v1)] dma: &'a mut ChannelAndRequest<'d>, 799 buffer: &'a mut Aligned<A4, [u8]>,
764 buffer: &'a mut [u32], 800 mode: DatapathMode,
765 length_bytes: u32, 801 ) -> WrappedTransfer<'a> {
766 block_size: u8, 802 let regs = self.info.regs;
767 ) -> Transfer<'a> { 803
768 assert!(block_size <= 14, "Block size up to 2^14 bytes"); 804 let (byte_mode, block_size) = match mode {
769 let regs = T::regs(); 805 DatapathMode::Block(block_size) => (false, block_size as u8),
806 DatapathMode::Byte => (true, 0),
807 };
770 808
771 // Command AND Data state machines must be idle 809 // Command AND Data state machines must be idle
772 Self::wait_idle(); 810 self.wait_idle();
773 Self::clear_interrupt_flags(); 811 self.clear_interrupt_flags();
774 812
775 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 813 regs.dlenr().write(|w| w.set_datalength(size_of_val(buffer) as u32));
776 814
815 // SAFETY: No other functions use the dma
777 #[cfg(sdmmc_v1)] 816 #[cfg(sdmmc_v1)]
778 let transfer = unsafe { dma.read(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) }; 817 let transfer = unsafe {
818 self.dma.read_unchecked(
819 regs.fifor().as_ptr() as *mut u32,
820 slice32_mut(buffer),
821 DMA_TRANSFER_OPTIONS,
822 )
823 };
779 #[cfg(sdmmc_v2)] 824 #[cfg(sdmmc_v2)]
780 let transfer = { 825 let transfer = {
781 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); 826 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
@@ -785,8 +830,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
785 } 830 }
786 }; 831 };
787 832
833 #[cfg(sdmmc_v2)]
834 let byte_mode = byte_mode as u8;
835
788 regs.dctrl().modify(|w| { 836 regs.dctrl().modify(|w| {
789 w.set_dblocksize(block_size); 837 w.set_dtmode(byte_mode);
838 w.set_dblocksize(block_size as u8);
790 w.set_dtdir(true); 839 w.set_dtdir(true);
791 #[cfg(sdmmc_v1)] 840 #[cfg(sdmmc_v1)]
792 { 841 {
@@ -795,26 +844,36 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
795 } 844 }
796 }); 845 });
797 846
798 transfer 847 self.enable_interrupts();
848
849 WrappedTransfer::new(transfer, &self)
799 } 850 }
800 851
801 /// # Safety 852 /// # Safety
802 /// 853 ///
803 /// `buffer` must be valid for the whole transfer and word aligned 854 /// `buffer` must be valid for the whole transfer and word aligned
804 fn prepare_datapath_write<'a>(&'a mut self, buffer: &'a [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> { 855 fn prepare_datapath_write<'a>(&'a self, buffer: &'a Aligned<A4, [u8]>, mode: DatapathMode) -> WrappedTransfer<'a> {
805 assert!(block_size <= 14, "Block size up to 2^14 bytes"); 856 let regs = self.info.regs;
806 let regs = T::regs(); 857
858 let (byte_mode, block_size) = match mode {
859 DatapathMode::Block(block_size) => (false, block_size as u8),
860 DatapathMode::Byte => (true, 0),
861 };
807 862
808 // Command AND Data state machines must be idle 863 // Command AND Data state machines must be idle
809 Self::wait_idle(); 864 self.wait_idle();
810 Self::clear_interrupt_flags(); 865 self.clear_interrupt_flags();
811 866
812 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 867 regs.dlenr().write(|w| w.set_datalength(size_of_val(buffer) as u32));
813 868
869 // SAFETY: No other functions use the dma
814 #[cfg(sdmmc_v1)] 870 #[cfg(sdmmc_v1)]
815 let transfer = unsafe { 871 let transfer = unsafe {
816 self.dma 872 self.dma.write_unchecked(
817 .write(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) 873 slice32_ref(buffer),
874 regs.fifor().as_ptr() as *mut u32,
875 DMA_TRANSFER_OPTIONS,
876 )
818 }; 877 };
819 #[cfg(sdmmc_v2)] 878 #[cfg(sdmmc_v2)]
820 let transfer = { 879 let transfer = {
@@ -825,8 +884,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
825 } 884 }
826 }; 885 };
827 886
887 #[cfg(sdmmc_v2)]
888 let byte_mode = byte_mode as u8;
889
828 regs.dctrl().modify(|w| { 890 regs.dctrl().modify(|w| {
829 w.set_dblocksize(block_size); 891 w.set_dtmode(byte_mode);
892 w.set_dblocksize(block_size as u8);
830 w.set_dtdir(false); 893 w.set_dtdir(false);
831 #[cfg(sdmmc_v1)] 894 #[cfg(sdmmc_v1)]
832 { 895 {
@@ -835,12 +898,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
835 } 898 }
836 }); 899 });
837 900
838 transfer 901 self.enable_interrupts();
902
903 WrappedTransfer::new(transfer, &self)
839 } 904 }
840 905
841 /// Stops the DMA datapath 906 /// Stops the DMA datapath
842 fn stop_datapath() { 907 fn stop_datapath(&self) {
843 let regs = T::regs(); 908 let regs = self.info.regs;
844 909
845 #[cfg(sdmmc_v1)] 910 #[cfg(sdmmc_v1)]
846 regs.dctrl().modify(|w| { 911 regs.dctrl().modify(|w| {
@@ -851,49 +916,58 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
851 regs.idmactrlr().modify(|w| w.set_idmaen(false)); 916 regs.idmactrlr().modify(|w| w.set_idmaen(false));
852 } 917 }
853 918
919 fn init_idle(&mut self) -> Result<(), Error> {
920 let regs = self.info.regs;
921
922 self.clkcr_set_clkdiv(SD_INIT_FREQ, BusWidth::One)?;
923 regs.dtimer()
924 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
925
926 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
927 self.cmd(common_cmd::idle(), false)
928 }
929
854 /// Sets the CLKDIV field in CLKCR. Updates clock field in self 930 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
855 fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> { 931 fn clkcr_set_clkdiv(&mut self, freq: Hertz, width: BusWidth) -> Result<(), Error> {
856 let regs = T::regs(); 932 let regs = self.info.regs;
857
858 let width_u32 = match width {
859 BusWidth::One => 1u32,
860 BusWidth::Four => 4u32,
861 BusWidth::Eight => 8u32,
862 _ => panic!("Invalid Bus Width"),
863 };
864 933
865 let ker_ck = T::frequency(); 934 let (widbus, width_u32) = bus_width_vals(width);
866 let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; 935 let (_bypass, clkdiv, new_clock) = clk_div(self.ker_clk, freq.0)?;
867 936
868 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 937 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
869 // Section 55.5.8 938 // Section 55.5.8
870 let sdmmc_bus_bandwidth = new_clock.0 * width_u32; 939 let sdmmc_bus_bandwidth = new_clock.0 * width_u32;
871 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); 940 assert!(self.ker_clk.0 > 3 * sdmmc_bus_bandwidth / 32);
872 self.clock = new_clock; 941 self.clock = new_clock;
873 942
874 // CPSMACT and DPSMACT must be 0 to set CLKDIV 943 // CPSMACT and DPSMACT must be 0 to set CLKDIV or WIDBUS
875 Self::wait_idle(); 944 self.wait_idle();
876 regs.clkcr().modify(|w| { 945 regs.clkcr().modify(|w| {
877 w.set_clkdiv(clkdiv); 946 w.set_clkdiv(clkdiv);
878 #[cfg(sdmmc_v1)] 947 #[cfg(sdmmc_v1)]
879 w.set_bypass(_bypass); 948 w.set_bypass(_bypass);
949 w.set_widbus(widbus);
880 }); 950 });
881 951
882 Ok(()) 952 Ok(())
883 } 953 }
884 954
955 fn get_cid(&self) -> Result<u128, Error> {
956 self.cmd(common_cmd::all_send_cid(), false) // CMD2
957 }
958
959 fn get_csd(&self, address: u16) -> Result<u128, Error> {
960 self.cmd(common_cmd::send_csd(address), false)
961 }
962
885 /// Query the card status (CMD13, returns R1) 963 /// Query the card status (CMD13, returns R1)
886 fn read_status<Ext>(&self, card: &SdmmcPeripheral) -> Result<CardStatus<Ext>, Error> 964 fn read_status<A: Addressable>(&self, card: &A) -> Result<CardStatus<A::Ext>, Error>
887 where 965 where
888 CardStatus<Ext>: From<u32>, 966 CardStatus<A::Ext>: From<u32>,
889 { 967 {
890 let regs = T::regs();
891 let rca = card.get_address(); 968 let rca = card.get_address();
892 969
893 Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 970 Ok(self.cmd(common_cmd::card_status(rca, false), false)?.into()) // CMD13
894
895 let r1 = regs.respr(0).read().cardstatus();
896 Ok(r1.into())
897 } 971 }
898 972
899 /// Select one card and place it into the _Tranfer State_ 973 /// Select one card and place it into the _Tranfer State_
@@ -904,17 +978,23 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
904 // Determine Relative Card Address (RCA) of given card 978 // Determine Relative Card Address (RCA) of given card
905 let rca = rca.unwrap_or(0); 979 let rca = rca.unwrap_or(0);
906 980
907 let r = Self::cmd(common_cmd::select_card(rca), false); 981 let resp = self.cmd(common_cmd::select_card(rca), false);
908 match (r, rca) { 982
909 (Err(Error::Timeout), 0) => Ok(()), 983 if let Err(Error::Timeout) = resp
910 _ => r, 984 && rca == 0
985 {
986 return Ok(());
911 } 987 }
988
989 resp?;
990
991 Ok(())
912 } 992 }
913 993
914 /// Clear flags in interrupt clear register 994 /// Clear flags in interrupt clear register
915 #[inline] 995 #[inline]
916 fn clear_interrupt_flags() { 996 fn clear_interrupt_flags(&self) {
917 let regs = T::regs(); 997 let regs = self.info.regs;
918 regs.icr().write(|w| { 998 regs.icr().write(|w| {
919 w.set_ccrcfailc(true); 999 w.set_ccrcfailc(true);
920 w.set_dcrcfailc(true); 1000 w.set_dcrcfailc(true);
@@ -947,12 +1027,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
947 1027
948 /// Send command to card 1028 /// Send command to card
949 #[allow(unused_variables)] 1029 #[allow(unused_variables)]
950 fn cmd<R: Resp>(cmd: Cmd<R>, data: bool) -> Result<(), Error> { 1030 fn cmd<R: TypedResp>(&self, cmd: Cmd<R>, data: bool) -> Result<R::Word, Error> {
951 let regs = T::regs(); 1031 let regs = self.info.regs;
952 1032
953 Self::clear_interrupt_flags(); 1033 self.clear_interrupt_flags();
954 // CP state machine must be idle 1034 // CP state machine must be idle
955 while Self::cmd_active() {} 1035 while self.cmd_active() {}
956 1036
957 // Command arg 1037 // Command arg
958 regs.argr().write(|w| w.set_cmdarg(cmd.arg)); 1038 regs.argr().write(|w| w.set_cmdarg(cmd.arg));
@@ -994,16 +1074,29 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
994 } else if status.ccrcfail() { 1074 } else if status.ccrcfail() {
995 return Err(Error::Crc); 1075 return Err(Error::Crc);
996 } 1076 }
997 Ok(()) 1077
1078 Ok(match R::LENGTH {
1079 ResponseLen::Zero => U128(0u128),
1080 ResponseLen::R48 => U128(self.info.regs.respr(0).read().cardstatus() as u128),
1081 ResponseLen::R136 => {
1082 let cid0 = self.info.regs.respr(0).read().cardstatus() as u128;
1083 let cid1 = self.info.regs.respr(1).read().cardstatus() as u128;
1084 let cid2 = self.info.regs.respr(2).read().cardstatus() as u128;
1085 let cid3 = self.info.regs.respr(3).read().cardstatus() as u128;
1086
1087 U128((cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3))
1088 }
1089 }
1090 .into())
998 } 1091 }
999 1092
1000 fn on_drop() { 1093 fn on_drop(&self) {
1001 let regs = T::regs(); 1094 let regs = self.info.regs;
1002 if Self::data_active() { 1095 if self.data_active() {
1003 Self::clear_interrupt_flags(); 1096 self.clear_interrupt_flags();
1004 // Send abort 1097 // Send abort
1005 // CP state machine must be idle 1098 // CP state machine must be idle
1006 while Self::cmd_active() {} 1099 while self.cmd_active() {}
1007 1100
1008 // Command arg 1101 // Command arg
1009 regs.argr().write(|w| w.set_cmdarg(0)); 1102 regs.argr().write(|w| w.set_cmdarg(0));
@@ -1023,21 +1116,22 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1023 }); 1116 });
1024 1117
1025 // Wait for the abort 1118 // Wait for the abort
1026 while Self::data_active() {} 1119 while self.data_active() {}
1027 } 1120 }
1028 regs.maskr().write(|_| ()); // disable irqs 1121 regs.maskr().write(|_| ()); // disable irqs
1029 Self::clear_interrupt_flags(); 1122 self.clear_interrupt_flags();
1030 Self::stop_datapath(); 1123 self.stop_datapath();
1031 } 1124 }
1032 1125
1033 /// Wait for a previously started datapath transfer to complete from an interrupt. 1126 /// Wait for a previously started datapath transfer to complete from an interrupt.
1034 #[inline] 1127 #[inline]
1035 async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { 1128 #[allow(unused)]
1036 let regs = T::regs(); 1129 async fn complete_datapath_transfer(&self, mut transfer: WrappedTransfer<'_>, block: bool) -> Result<(), Error> {
1037
1038 let res = poll_fn(|cx| { 1130 let res = poll_fn(|cx| {
1039 T::state().register(cx.waker()); 1131 // Compiler might not be sufficiently constrained here
1040 let status = regs.star().read(); 1132 // https://github.com/embassy-rs/embassy/issues/4723
1133 self.state.waker.register(cx.waker());
1134 let status = self.info.regs.star().read();
1041 1135
1042 if status.dcrcfail() { 1136 if status.dcrcfail() {
1043 return Poll::Ready(Err(Error::Crc)); 1137 return Poll::Ready(Err(Error::Crc));
@@ -1052,10 +1146,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1052 if status.stbiterr() { 1146 if status.stbiterr() {
1053 return Poll::Ready(Err(Error::StBitErr)); 1147 return Poll::Ready(Err(Error::StBitErr));
1054 } 1148 }
1149 #[cfg(sdmmc_v1)]
1055 let done = match block { 1150 let done = match block {
1056 true => status.dbckend(), 1151 true => status.dbckend(),
1057 false => status.dataend(), 1152 false => status.dataend(),
1058 }; 1153 };
1154 #[cfg(sdmmc_v2)]
1155 let done = status.dataend();
1059 if done { 1156 if done {
1060 return Poll::Ready(Ok(())); 1157 return Poll::Ready(Ok(()));
1061 } 1158 }
@@ -1063,698 +1160,26 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1063 }) 1160 })
1064 .await; 1161 .await;
1065 1162
1066 Self::clear_interrupt_flags(); 1163 self.clear_interrupt_flags();
1067 1164 self.stop_datapath();
1068 res
1069 }
1070
1071 /// Read a data block.
1072 #[inline]
1073 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
1074 let card_capacity = self.card()?.get_capacity();
1075
1076 // NOTE(unsafe) DataBlock uses align 4
1077 let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
1078 1165
1079 // Always read 1 block of 512 bytes 1166 transfer.defuse();
1080 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes 1167 drop(transfer);
1081 let address = match card_capacity {
1082 CardCapacity::StandardCapacity => block_idx * 512,
1083 _ => block_idx,
1084 };
1085 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1086 1168
1087 let on_drop = OnDrop::new(|| Self::on_drop());
1088
1089 let transfer = Self::prepare_datapath_read(
1090 &self.config,
1091 #[cfg(sdmmc_v1)]
1092 &mut self.dma,
1093 buffer,
1094 512,
1095 9,
1096 );
1097 InterruptHandler::<T>::enable_interrupts();
1098 Self::cmd(common_cmd::read_single_block(address), true)?;
1099
1100 let res = Self::complete_datapath_transfer(true).await;
1101
1102 if res.is_ok() {
1103 on_drop.defuse();
1104 Self::stop_datapath();
1105 drop(transfer);
1106 }
1107 res 1169 res
1108 } 1170 }
1109 1171
1110 /// Read multiple data blocks.
1111 #[inline]
1112 pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
1113 let card_capacity = self.card()?.get_capacity();
1114
1115 // NOTE(unsafe) reinterpret buffer as &mut [u32]
1116 let buffer = unsafe {
1117 let ptr = blocks.as_mut_ptr() as *mut u32;
1118 let len = blocks.len() * 128;
1119 core::slice::from_raw_parts_mut(ptr, len)
1120 };
1121
1122 // Always read 1 block of 512 bytes
1123 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1124 let address = match card_capacity {
1125 CardCapacity::StandardCapacity => block_idx * 512,
1126 _ => block_idx,
1127 };
1128 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1129
1130 let on_drop = OnDrop::new(|| Self::on_drop());
1131
1132 let transfer = Self::prepare_datapath_read(
1133 &self.config,
1134 #[cfg(sdmmc_v1)]
1135 &mut self.dma,
1136 buffer,
1137 512 * blocks.len() as u32,
1138 9,
1139 );
1140 InterruptHandler::<T>::enable_interrupts();
1141
1142 Self::cmd(common_cmd::read_multiple_blocks(address), true)?;
1143
1144 let res = Self::complete_datapath_transfer(false).await;
1145
1146 Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
1147 Self::clear_interrupt_flags();
1148
1149 if res.is_ok() {
1150 on_drop.defuse();
1151 Self::stop_datapath();
1152 drop(transfer);
1153 }
1154 res
1155 }
1156
1157 /// Write a data block.
1158 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
1159 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1160
1161 // NOTE(unsafe) DataBlock uses align 4
1162 let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
1163
1164 // Always read 1 block of 512 bytes
1165 // cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1166 let address = match card.get_capacity() {
1167 CardCapacity::StandardCapacity => block_idx * 512,
1168 _ => block_idx,
1169 };
1170 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1171
1172 let on_drop = OnDrop::new(|| Self::on_drop());
1173
1174 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
1175 #[cfg(sdmmc_v1)]
1176 Self::cmd(common_cmd::write_single_block(address), true)?;
1177
1178 let transfer = self.prepare_datapath_write(buffer, 512, 9);
1179 InterruptHandler::<T>::enable_interrupts();
1180
1181 #[cfg(sdmmc_v2)]
1182 Self::cmd(common_cmd::write_single_block(address), true)?;
1183
1184 let res = Self::complete_datapath_transfer(true).await;
1185
1186 match res {
1187 Ok(_) => {
1188 on_drop.defuse();
1189 Self::stop_datapath();
1190 drop(transfer);
1191
1192 // TODO: Make this configurable
1193 let mut timeout: u32 = 0x00FF_FFFF;
1194
1195 let card = self.card.as_ref().unwrap();
1196 while timeout > 0 {
1197 let ready_for_data = match card {
1198 SdmmcPeripheral::Emmc(_) => self.read_status::<EMMC>(card)?.ready_for_data(),
1199 SdmmcPeripheral::SdCard(_) => self.read_status::<SD>(card)?.ready_for_data(),
1200 };
1201
1202 if ready_for_data {
1203 return Ok(());
1204 }
1205 timeout -= 1;
1206 }
1207 Err(Error::SoftwareTimeout)
1208 }
1209 Err(e) => Err(e),
1210 }
1211 }
1212
1213 /// Write multiple data blocks.
1214 pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> {
1215 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1216
1217 // NOTE(unsafe) reinterpret buffer as &[u32]
1218 let buffer = unsafe {
1219 let ptr = blocks.as_ptr() as *const u32;
1220 let len = blocks.len() * 128;
1221 core::slice::from_raw_parts(ptr, len)
1222 };
1223
1224 // Always read 1 block of 512 bytes
1225 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1226 let address = match card.get_capacity() {
1227 CardCapacity::StandardCapacity => block_idx * 512,
1228 _ => block_idx,
1229 };
1230
1231 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1232
1233 let block_count = blocks.len();
1234
1235 let on_drop = OnDrop::new(|| Self::on_drop());
1236
1237 #[cfg(sdmmc_v1)]
1238 Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
1239
1240 // Setup write command
1241 let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9);
1242 InterruptHandler::<T>::enable_interrupts();
1243
1244 #[cfg(sdmmc_v2)]
1245 Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
1246
1247 let res = Self::complete_datapath_transfer(false).await;
1248
1249 Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
1250 Self::clear_interrupt_flags();
1251
1252 match res {
1253 Ok(_) => {
1254 on_drop.defuse();
1255 Self::stop_datapath();
1256 drop(transfer);
1257
1258 // TODO: Make this configurable
1259 let mut timeout: u32 = 0x00FF_FFFF;
1260
1261 // Try to read card status (ACMD13)
1262 while timeout > 0 {
1263 match self.read_sd_status().await {
1264 Ok(_) => return Ok(()),
1265 Err(Error::Timeout) => (), // Try again
1266 Err(e) => return Err(e),
1267 }
1268 timeout -= 1;
1269 }
1270 Err(Error::SoftwareTimeout)
1271 }
1272 Err(e) => Err(e),
1273 }
1274 }
1275
1276 /// Get a reference to the initialized card
1277 ///
1278 /// # Errors
1279 ///
1280 /// Returns Error::NoCard if [`init_sd_card`](#method.init_sd_card) or
1281 /// [`init_emmc`](#method.init_emmc) has not previously succeeded
1282 #[inline]
1283 pub fn card(&self) -> Result<&SdmmcPeripheral, Error> {
1284 self.card.as_ref().ok_or(Error::NoCard)
1285 }
1286
1287 /// Get the current SDMMC bus clock 1172 /// Get the current SDMMC bus clock
1288 pub fn clock(&self) -> Hertz { 1173 pub fn clock(&self) -> Hertz {
1289 self.clock 1174 self.clock
1290 } 1175 }
1291
1292 /// Set a specific cmd buffer rather than using the default stack allocated one.
1293 /// This is required if stack RAM cannot be used with DMA and usually manifests
1294 /// itself as an indefinite wait on a dma transfer because the dma peripheral
1295 /// cannot access the memory.
1296 pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) {
1297 self.cmd_block = Some(cmd_block)
1298 }
1299
1300 async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> {
1301 let regs = T::regs();
1302 let ker_ck = T::frequency();
1303
1304 let bus_width = match (self.d3.is_some(), self.d7.is_some()) {
1305 (true, true) => {
1306 if matches!(card, SdmmcPeripheral::SdCard(_)) {
1307 return Err(Error::BusWidth);
1308 }
1309 BusWidth::Eight
1310 }
1311 (true, false) => BusWidth::Four,
1312 _ => BusWidth::One,
1313 };
1314
1315 // While the SD/SDIO card or eMMC is in identification mode,
1316 // the SDMMC_CK frequency must be no more than 400 kHz.
1317 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1318 self.clock = init_clock;
1319
1320 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1321 Self::wait_idle();
1322
1323 regs.clkcr().modify(|w| {
1324 w.set_widbus(0);
1325 w.set_clkdiv(clkdiv);
1326 #[cfg(sdmmc_v1)]
1327 w.set_bypass(_bypass);
1328 });
1329 regs.dtimer()
1330 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
1331
1332 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
1333 Self::cmd(common_cmd::idle(), false)?;
1334
1335 match card {
1336 SdmmcPeripheral::SdCard(ref mut card) => {
1337 // Check if cards supports CMD8 (with pattern)
1338 Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?;
1339 let cic = CIC::from(regs.respr(0).read().cardstatus());
1340
1341 if cic.pattern() != 0xAA {
1342 return Err(Error::UnsupportedCardVersion);
1343 }
1344
1345 if cic.voltage_accepted() & 1 == 0 {
1346 return Err(Error::UnsupportedVoltage);
1347 }
1348
1349 let ocr = loop {
1350 // Signal that next command is a app command
1351 Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55
1352
1353 // 3.2-3.3V
1354 let voltage_window = 1 << 5;
1355 // Initialize card
1356 match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) {
1357 // ACMD41
1358 Ok(_) => (),
1359 Err(Error::Crc) => (),
1360 Err(err) => return Err(err),
1361 }
1362 let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into();
1363 if !ocr.is_busy() {
1364 // Power up done
1365 break ocr;
1366 }
1367 };
1368
1369 if ocr.high_capacity() {
1370 // Card is SDHC or SDXC or SDUC
1371 card.card_type = CardCapacity::HighCapacity;
1372 } else {
1373 card.card_type = CardCapacity::StandardCapacity;
1374 }
1375 card.ocr = ocr;
1376 }
1377 SdmmcPeripheral::Emmc(ref mut emmc) => {
1378 let ocr = loop {
1379 let high_voltage = 0b0 << 7;
1380 let access_mode = 0b10 << 29;
1381 let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15;
1382 // Initialize card
1383 match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) {
1384 Ok(_) => (),
1385 Err(Error::Crc) => (),
1386 Err(err) => return Err(err),
1387 }
1388 let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into();
1389 if !ocr.is_busy() {
1390 // Power up done
1391 break ocr;
1392 }
1393 };
1394
1395 emmc.capacity = if ocr.access_mode() == 0b10 {
1396 // Card is SDHC or SDXC or SDUC
1397 CardCapacity::HighCapacity
1398 } else {
1399 CardCapacity::StandardCapacity
1400 };
1401 emmc.ocr = ocr;
1402 }
1403 }
1404
1405 Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2
1406 let cid0 = regs.respr(0).read().cardstatus() as u128;
1407 let cid1 = regs.respr(1).read().cardstatus() as u128;
1408 let cid2 = regs.respr(2).read().cardstatus() as u128;
1409 let cid3 = regs.respr(3).read().cardstatus() as u128;
1410 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1411
1412 match card {
1413 SdmmcPeripheral::SdCard(ref mut card) => {
1414 card.cid = cid.into();
1415
1416 Self::cmd(sd_cmd::send_relative_address(), false)?;
1417 let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus());
1418 card.rca = rca.address();
1419 }
1420 SdmmcPeripheral::Emmc(ref mut emmc) => {
1421 emmc.cid = cid.into();
1422
1423 emmc.rca = 1u16.into();
1424 Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?;
1425 }
1426 }
1427
1428 Self::cmd(common_cmd::send_csd(card.get_address()), false)?;
1429 let csd0 = regs.respr(0).read().cardstatus() as u128;
1430 let csd1 = regs.respr(1).read().cardstatus() as u128;
1431 let csd2 = regs.respr(2).read().cardstatus() as u128;
1432 let csd3 = regs.respr(3).read().cardstatus() as u128;
1433 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1434
1435 self.select_card(Some(card.get_address()))?;
1436
1437 let bus_width = match card {
1438 SdmmcPeripheral::SdCard(ref mut card) => {
1439 card.csd = csd.into();
1440
1441 self.get_scr(card).await?;
1442
1443 if !card.scr.bus_width_four() {
1444 BusWidth::One
1445 } else {
1446 BusWidth::Four
1447 }
1448 }
1449 SdmmcPeripheral::Emmc(ref mut emmc) => {
1450 emmc.csd = csd.into();
1451
1452 bus_width
1453 }
1454 };
1455
1456 // Set bus width
1457 let widbus = match bus_width {
1458 BusWidth::Eight => 2,
1459 BusWidth::Four => 1,
1460 BusWidth::One => 0,
1461 _ => unreachable!(),
1462 };
1463
1464 match card {
1465 SdmmcPeripheral::SdCard(ref mut card) => {
1466 let acmd_arg = match bus_width {
1467 BusWidth::Four if card.scr.bus_width_four() => 2,
1468 _ => 0,
1469 };
1470 Self::cmd(common_cmd::app_cmd(card.rca), false)?;
1471 Self::cmd(sd_cmd::cmd6(acmd_arg), false)?;
1472 }
1473 SdmmcPeripheral::Emmc(_) => {
1474 // Write bus width to ExtCSD byte 183
1475 Self::cmd(
1476 emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus),
1477 false,
1478 )?;
1479
1480 // Wait for ready after R1b response
1481 loop {
1482 let status = self.read_status::<EMMC>(&card)?;
1483
1484 if status.ready_for_data() {
1485 break;
1486 }
1487 }
1488 }
1489 }
1490
1491 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1492 Self::wait_idle();
1493
1494 regs.clkcr().modify(|w| w.set_widbus(widbus));
1495
1496 // Set Clock
1497 if freq.0 <= 25_000_000 {
1498 // Final clock frequency
1499 self.clkcr_set_clkdiv(freq.0, bus_width)?;
1500 } else {
1501 // Switch to max clock for SDR12
1502 self.clkcr_set_clkdiv(25_000_000, bus_width)?;
1503 }
1504
1505 self.card = Some(card);
1506
1507 match card {
1508 SdmmcPeripheral::SdCard(_) => {
1509 // Read status
1510 self.read_sd_status().await?;
1511
1512 if freq.0 > 25_000_000 {
1513 // Switch to SDR25
1514 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1515
1516 if self.signalling == Signalling::SDR25 {
1517 // Set final clock frequency
1518 self.clkcr_set_clkdiv(freq.0, bus_width)?;
1519
1520 if self.read_status::<SD>(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer {
1521 return Err(Error::SignalingSwitchFailed);
1522 }
1523 }
1524 }
1525
1526 // Read status after signalling change
1527 self.read_sd_status().await?;
1528 }
1529 SdmmcPeripheral::Emmc(_) => {
1530 self.read_ext_csd().await?;
1531 }
1532 }
1533
1534 Ok(())
1535 }
1536
1537 /// Initializes card (if present) and sets the bus at the specified frequency.
1538 ///
1539 /// SD only.
1540 pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> {
1541 self.init_internal(freq, SdmmcPeripheral::SdCard(Card::default())).await
1542 }
1543
1544 /// Switch mode using CMD6.
1545 ///
1546 /// Attempt to set a new signalling mode. The selected
1547 /// signalling mode is returned. Expects the current clock
1548 /// frequency to be > 12.5MHz.
1549 ///
1550 /// SD only.
1551 async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> {
1552 let _ = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card();
1553 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
1554 // necessary"
1555
1556 let set_function = 0x8000_0000
1557 | match signalling {
1558 // See PLSS v7_10 Table 4-11
1559 Signalling::DDR50 => 0xFF_FF04,
1560 Signalling::SDR104 => 0xFF_1F03,
1561 Signalling::SDR50 => 0xFF_1F02,
1562 Signalling::SDR25 => 0xFF_FF01,
1563 Signalling::SDR12 => 0xFF_FF00,
1564 };
1565
1566 let status = match self.cmd_block.as_deref_mut() {
1567 Some(x) => x,
1568 None => &mut CmdBlock::new(),
1569 };
1570
1571 // Arm `OnDrop` after the buffer, so it will be dropped first
1572 let on_drop = OnDrop::new(|| Self::on_drop());
1573
1574 let transfer = Self::prepare_datapath_read(
1575 &self.config,
1576 #[cfg(sdmmc_v1)]
1577 &mut self.dma,
1578 status.as_mut(),
1579 64,
1580 6,
1581 );
1582 InterruptHandler::<T>::enable_interrupts();
1583 Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6
1584
1585 let res = Self::complete_datapath_transfer(true).await;
1586
1587 // Host is allowed to use the new functions at least 8
1588 // clocks after the end of the switch command
1589 // transaction. We know the current clock period is < 80ns,
1590 // so a total delay of 640ns is required here
1591 for _ in 0..300 {
1592 cortex_m::asm::nop();
1593 }
1594
1595 match res {
1596 Ok(_) => {
1597 on_drop.defuse();
1598 Self::stop_datapath();
1599 drop(transfer);
1600
1601 // Function Selection of Function Group 1
1602 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
1603
1604 match selection {
1605 0 => Ok(Signalling::SDR12),
1606 1 => Ok(Signalling::SDR25),
1607 2 => Ok(Signalling::SDR50),
1608 3 => Ok(Signalling::SDR104),
1609 4 => Ok(Signalling::DDR50),
1610 _ => Err(Error::UnsupportedCardType),
1611 }
1612 }
1613 Err(e) => Err(e),
1614 }
1615 }
1616
1617 /// Reads the SCR register.
1618 ///
1619 /// SD only.
1620 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
1621 // Read the 64-bit SCR register
1622 Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16
1623 Self::cmd(common_cmd::app_cmd(card.rca), false)?;
1624
1625 let cmd_block = match self.cmd_block.as_deref_mut() {
1626 Some(x) => x,
1627 None => &mut CmdBlock::new(),
1628 };
1629 let scr = &mut cmd_block.0[..2];
1630
1631 // Arm `OnDrop` after the buffer, so it will be dropped first
1632 let on_drop = OnDrop::new(|| Self::on_drop());
1633
1634 let transfer = Self::prepare_datapath_read(
1635 &self.config,
1636 #[cfg(sdmmc_v1)]
1637 &mut self.dma,
1638 scr,
1639 8,
1640 3,
1641 );
1642 InterruptHandler::<T>::enable_interrupts();
1643 Self::cmd(sd_cmd::send_scr(), true)?;
1644
1645 let res = Self::complete_datapath_transfer(true).await;
1646
1647 if res.is_ok() {
1648 on_drop.defuse();
1649 Self::stop_datapath();
1650 drop(transfer);
1651
1652 unsafe {
1653 let scr_bytes = &*(&scr as *const _ as *const [u8; 8]);
1654 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
1655 }
1656 }
1657 res
1658 }
1659
1660 /// Reads the SD Status (ACMD13)
1661 ///
1662 /// SD only.
1663 async fn read_sd_status(&mut self) -> Result<(), Error> {
1664 let card = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card();
1665 let rca = card.rca;
1666
1667 let cmd_block = match self.cmd_block.as_deref_mut() {
1668 Some(x) => x,
1669 None => &mut CmdBlock::new(),
1670 };
1671
1672 Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16
1673 Self::cmd(common_cmd::app_cmd(rca), false)?; // APP
1674
1675 let status = cmd_block;
1676
1677 // Arm `OnDrop` after the buffer, so it will be dropped first
1678 let on_drop = OnDrop::new(|| Self::on_drop());
1679
1680 let transfer = Self::prepare_datapath_read(
1681 &self.config,
1682 #[cfg(sdmmc_v1)]
1683 &mut self.dma,
1684 status.as_mut(),
1685 64,
1686 6,
1687 );
1688 InterruptHandler::<T>::enable_interrupts();
1689 Self::cmd(sd_cmd::sd_status(), true)?;
1690
1691 let res = Self::complete_datapath_transfer(true).await;
1692
1693 if res.is_ok() {
1694 on_drop.defuse();
1695 Self::stop_datapath();
1696 drop(transfer);
1697
1698 for byte in status.iter_mut() {
1699 *byte = u32::from_be(*byte);
1700 }
1701 card.status = status.0.into();
1702 }
1703 res
1704 }
1705
1706 /// Initializes eMMC and sets the bus at the specified frequency.
1707 ///
1708 /// eMMC only.
1709 pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> {
1710 self.init_internal(freq, SdmmcPeripheral::Emmc(Emmc::default())).await
1711 }
1712
1713 /// Gets the EXT_CSD register.
1714 ///
1715 /// eMMC only.
1716 async fn read_ext_csd(&mut self) -> Result<(), Error> {
1717 let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc();
1718
1719 // Note: cmd_block can't be used because ExtCSD is too long to fit.
1720 let mut data_block = DataBlock([0u8; 512]);
1721
1722 // NOTE(unsafe) DataBlock uses align 4
1723 let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) };
1724
1725 Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16
1726
1727 // Arm `OnDrop` after the buffer, so it will be dropped first
1728 let on_drop = OnDrop::new(|| Self::on_drop());
1729
1730 let transfer = Self::prepare_datapath_read(
1731 &self.config,
1732 #[cfg(sdmmc_v1)]
1733 &mut self.dma,
1734 buffer,
1735 512,
1736 9,
1737 );
1738 InterruptHandler::<T>::enable_interrupts();
1739 Self::cmd(emmc_cmd::send_ext_csd(), true)?;
1740
1741 let res = Self::complete_datapath_transfer(true).await;
1742
1743 if res.is_ok() {
1744 on_drop.defuse();
1745 Self::stop_datapath();
1746 drop(transfer);
1747
1748 card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into();
1749 }
1750 res
1751 }
1752} 1176}
1753 1177
1754impl<'d, T: Instance> Drop for Sdmmc<'d, T> { 1178impl<'d> Drop for Sdmmc<'d> {
1755 fn drop(&mut self) { 1179 fn drop(&mut self) {
1756 T::Interrupt::disable(); 1180 // T::Interrupt::disable();
1757 Self::on_drop(); 1181 self.on_drop();
1182 self.info.rcc.disable_without_stop();
1758 1183
1759 critical_section::with(|_| { 1184 critical_section::with(|_| {
1760 self.clk.set_as_disconnected(); 1185 self.clk.set_as_disconnected();
@@ -1787,9 +1212,28 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> {
1787 1212
1788////////////////////////////////////////////////////// 1213//////////////////////////////////////////////////////
1789 1214
1215type Regs = RegBlock;
1216
1217struct Info {
1218 regs: Regs,
1219 rcc: RccInfo,
1220}
1221
1222struct State {
1223 waker: AtomicWaker,
1224}
1225
1226impl State {
1227 const fn new() -> Self {
1228 Self {
1229 waker: AtomicWaker::new(),
1230 }
1231 }
1232}
1233
1790trait SealedInstance { 1234trait SealedInstance {
1791 fn regs() -> RegBlock; 1235 fn info() -> &'static Info;
1792 fn state() -> &'static AtomicWaker; 1236 fn state() -> &'static State;
1793} 1237}
1794 1238
1795/// SDMMC instance trait. 1239/// SDMMC instance trait.
@@ -1816,13 +1260,17 @@ dma_trait!(SdmmcDma, Instance);
1816foreach_peripheral!( 1260foreach_peripheral!(
1817 (sdmmc, $inst:ident) => { 1261 (sdmmc, $inst:ident) => {
1818 impl SealedInstance for peripherals::$inst { 1262 impl SealedInstance for peripherals::$inst {
1819 fn regs() -> RegBlock { 1263 fn info() -> &'static Info {
1820 crate::pac::$inst 1264 static INFO: Info = Info {
1265 regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) },
1266 rcc: crate::peripherals::$inst::RCC_INFO,
1267 };
1268 &INFO
1821 } 1269 }
1822 1270
1823 fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker { 1271 fn state() -> &'static State {
1824 static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new(); 1272 static STATE: State = State::new();
1825 &WAKER 1273 &STATE
1826 } 1274 }
1827 } 1275 }
1828 1276
@@ -1831,46 +1279,3 @@ foreach_peripheral!(
1831 } 1279 }
1832 }; 1280 };
1833); 1281);
1834
1835impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> {
1836 type Error = Error;
1837 type Align = aligned::A4;
1838
1839 async fn read(
1840 &mut self,
1841 block_address: u32,
1842 buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>],
1843 ) -> Result<(), Self::Error> {
1844 // TODO: I think block_address needs to be adjusted by the partition start offset
1845 if buf.len() == 1 {
1846 let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) };
1847 self.read_block(block_address, block).await?;
1848 } else {
1849 let blocks: &mut [DataBlock] =
1850 unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) };
1851 self.read_blocks(block_address, blocks).await?;
1852 }
1853 Ok(())
1854 }
1855
1856 async fn write(
1857 &mut self,
1858 block_address: u32,
1859 buf: &[aligned::Aligned<Self::Align, [u8; 512]>],
1860 ) -> Result<(), Self::Error> {
1861 // TODO: I think block_address needs to be adjusted by the partition start offset
1862 if buf.len() == 1 {
1863 let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) };
1864 self.write_block(block_address, block).await?;
1865 } else {
1866 let blocks: &[DataBlock] =
1867 unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) };
1868 self.write_blocks(block_address, blocks).await?;
1869 }
1870 Ok(())
1871 }
1872
1873 async fn size(&mut self) -> Result<u64, Self::Error> {
1874 Ok(self.card()?.size())
1875 }
1876}
diff --git a/embassy-stm32/src/sdmmc/sd.rs b/embassy-stm32/src/sdmmc/sd.rs
new file mode 100644
index 000000000..20318bbfa
--- /dev/null
+++ b/embassy-stm32/src/sdmmc/sd.rs
@@ -0,0 +1,699 @@
1use core::default::Default;
2use core::ops::{Deref, DerefMut};
3
4use sdio_host::emmc::{EMMC, ExtCSD};
5use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus};
6use sdio_host::{common_cmd, emmc_cmd, sd_cmd};
7
8use crate::sdmmc::{
9 BlockSize, DatapathMode, Error, Sdmmc, Signalling, aligned_mut, aligned_ref, block_size, bus_width_vals,
10 slice8_mut, slice8_ref,
11};
12use crate::time::{Hertz, mhz};
13
14/// Aligned data block for SDMMC transfers.
15///
16/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements.
17#[repr(align(4))]
18#[derive(Debug, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub struct DataBlock(pub [u32; 128]);
21
22impl DataBlock {
23 /// Create a new DataBlock
24 pub const fn new() -> Self {
25 DataBlock([0u32; 128])
26 }
27}
28
29impl Deref for DataBlock {
30 type Target = [u8; 512];
31
32 fn deref(&self) -> &Self::Target {
33 unwrap!(slice8_ref(&self.0[..]).try_into())
34 }
35}
36
37impl DerefMut for DataBlock {
38 fn deref_mut(&mut self) -> &mut Self::Target {
39 unwrap!(slice8_mut(&mut self.0[..]).try_into())
40 }
41}
42
43/// Command Block buffer for SDMMC command transfers.
44///
45/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required.
46#[derive(Debug, Clone, PartialEq, Eq)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub struct CmdBlock(pub [u32; 16]);
49
50impl CmdBlock {
51 /// Creates a new instance of CmdBlock
52 pub const fn new() -> Self {
53 Self([0u32; 16])
54 }
55}
56
57impl Deref for CmdBlock {
58 type Target = [u32; 16];
59
60 fn deref(&self) -> &Self::Target {
61 &self.0
62 }
63}
64
65impl DerefMut for CmdBlock {
66 fn deref_mut(&mut self) -> &mut Self::Target {
67 &mut self.0
68 }
69}
70
71/// Represents either an SD or EMMC card
72pub trait Addressable: Sized + Clone {
73 /// Associated type
74 type Ext;
75
76 /// Get this peripheral's address on the SDMMC bus
77 fn get_address(&self) -> u16;
78
79 /// Is this a standard or high capacity peripheral?
80 fn get_capacity(&self) -> CardCapacity;
81
82 /// Size in bytes
83 fn size(&self) -> u64;
84}
85
86/// Storage Device
87pub struct StorageDevice<'a, 'b, T: Addressable> {
88 info: T,
89 /// Inner member
90 pub sdmmc: &'a mut Sdmmc<'b>,
91}
92
93/// Card Storage Device
94impl<'a, 'b> StorageDevice<'a, 'b, Card> {
95 /// Create a new SD card
96 pub async fn new_sd_card(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> {
97 let mut s = Self {
98 info: Card::default(),
99 sdmmc,
100 };
101
102 s.acquire(cmd_block, freq).await?;
103
104 Ok(s)
105 }
106
107 /// Initializes the card into a known state (or at least tries to).
108 async fn acquire(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> {
109 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
110 let regs = self.sdmmc.info.regs;
111
112 let _bus_width = match self.sdmmc.bus_width() {
113 BusWidth::Eight => return Err(Error::BusWidth),
114 bus_width => bus_width,
115 };
116
117 // While the SD/SDIO card or eMMC is in identification mode,
118 // the SDMMC_CK frequency must be no more than 400 kHz.
119 self.sdmmc.init_idle()?;
120
121 // Check if cards supports CMD8 (with pattern)
122 self.sdmmc.cmd(sd_cmd::send_if_cond(1, 0xAA), false)?;
123 let cic = CIC::from(regs.respr(0).read().cardstatus());
124
125 if cic.pattern() != 0xAA {
126 return Err(Error::UnsupportedCardVersion);
127 }
128
129 if cic.voltage_accepted() & 1 == 0 {
130 return Err(Error::UnsupportedVoltage);
131 }
132
133 let ocr = loop {
134 // Signal that next command is a app command
135 self.sdmmc.cmd(common_cmd::app_cmd(0), false)?; // CMD55
136
137 // 3.2-3.3V
138 let voltage_window = 1 << 5;
139 // Initialize card
140 match self
141 .sdmmc
142 .cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false)
143 {
144 // ACMD41
145 Ok(_) => (),
146 Err(Error::Crc) => (),
147 Err(err) => return Err(err),
148 }
149
150 let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into();
151 if !ocr.is_busy() {
152 // Power up done
153 break ocr;
154 }
155 };
156
157 if ocr.high_capacity() {
158 // Card is SDHC or SDXC or SDUC
159 self.info.card_type = CardCapacity::HighCapacity;
160 } else {
161 self.info.card_type = CardCapacity::StandardCapacity;
162 }
163 self.info.ocr = ocr;
164
165 self.info.cid = self.sdmmc.get_cid()?.into();
166
167 self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?;
168 let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus());
169 self.info.rca = rca.address();
170
171 self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into();
172 self.sdmmc.select_card(Some(self.info.get_address()))?;
173
174 self.info.scr = self.get_scr(cmd_block).await?;
175
176 let (bus_width, acmd_arg) = if !self.info.scr.bus_width_four() {
177 (BusWidth::One, 0)
178 } else {
179 (BusWidth::Four, 2)
180 };
181
182 self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?;
183 self.sdmmc.cmd(sd_cmd::cmd6(acmd_arg), false)?;
184
185 self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?;
186
187 // Read status
188 self.info.status = self.read_sd_status(cmd_block).await?;
189
190 if freq > mhz(25) {
191 // Switch to SDR25
192 self.sdmmc.signalling = self.switch_signalling_mode(cmd_block, Signalling::SDR25).await?;
193
194 if self.sdmmc.signalling == Signalling::SDR25 {
195 // Set final clock frequency
196 self.sdmmc.clkcr_set_clkdiv(freq, bus_width)?;
197
198 if self.sdmmc.read_status(&self.info)?.state() != CurrentState::Transfer {
199 return Err(Error::SignalingSwitchFailed);
200 }
201 }
202
203 // Read status after signalling change
204 self.read_sd_status(cmd_block).await?;
205 }
206
207 Ok(())
208 }
209
210 /// Switch mode using CMD6.
211 ///
212 /// Attempt to set a new signalling mode. The selected
213 /// signalling mode is returned. Expects the current clock
214 /// frequency to be > 12.5MHz.
215 ///
216 /// SD only.
217 async fn switch_signalling_mode(
218 &self,
219 cmd_block: &mut CmdBlock,
220 signalling: Signalling,
221 ) -> Result<Signalling, Error> {
222 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
223 // necessary"
224
225 let set_function = 0x8000_0000
226 | match signalling {
227 // See PLSS v7_10 Table 4-11
228 Signalling::DDR50 => 0xFF_FF04,
229 Signalling::SDR104 => 0xFF_1F03,
230 Signalling::SDR50 => 0xFF_1F02,
231 Signalling::SDR25 => 0xFF_FF01,
232 Signalling::SDR12 => 0xFF_FF00,
233 };
234
235 let buffer = &mut cmd_block.0[..64 / 4];
236 let mode = DatapathMode::Block(block_size(size_of_val(buffer)));
237 let transfer = self.sdmmc.prepare_datapath_read(aligned_mut(buffer), mode);
238
239 self.sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6
240
241 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
242
243 // Host is allowed to use the new functions at least 8
244 // clocks after the end of the switch command
245 // transaction. We know the current clock period is < 80ns,
246 // so a total delay of 640ns is required here
247 for _ in 0..300 {
248 cortex_m::asm::nop();
249 }
250
251 // Function Selection of Function Group 1
252 let selection = (u32::from_be(cmd_block[4]) >> 24) & 0xF;
253
254 match selection {
255 0 => Ok(Signalling::SDR12),
256 1 => Ok(Signalling::SDR25),
257 2 => Ok(Signalling::SDR50),
258 3 => Ok(Signalling::SDR104),
259 4 => Ok(Signalling::DDR50),
260 _ => Err(Error::UnsupportedCardType),
261 }
262 }
263
264 /// Reads the SCR register.
265 ///
266 /// SD only.
267 async fn get_scr(&self, cmd_block: &mut CmdBlock) -> Result<SCR, Error> {
268 // Read the 64-bit SCR register
269 self.sdmmc.cmd(common_cmd::set_block_length(8), false)?; // CMD16
270 self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?;
271
272 let scr = &mut cmd_block.0[..2];
273
274 // Arm `OnDrop` after the buffer, so it will be dropped first
275
276 let transfer = self
277 .sdmmc
278 .prepare_datapath_read(aligned_mut(scr), DatapathMode::Block(BlockSize::Size8));
279 self.sdmmc.cmd(sd_cmd::send_scr(), true)?;
280
281 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
282
283 Ok(SCR(u64::from_be_bytes(unwrap!(slice8_mut(scr).try_into()))))
284 }
285
286 /// Reads the SD Status (ACMD13)
287 ///
288 /// SD only.
289 async fn read_sd_status(&self, cmd_block: &mut CmdBlock) -> Result<SDStatus, Error> {
290 let rca = self.info.rca;
291
292 self.sdmmc.cmd(common_cmd::set_block_length(64), false)?; // CMD16
293 self.sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP
294
295 let buffer = &mut cmd_block.as_mut()[..64 / 4];
296 let mode = DatapathMode::Block(block_size(size_of_val(buffer)));
297
298 let transfer = self.sdmmc.prepare_datapath_read(aligned_mut(buffer), mode);
299 self.sdmmc.cmd(sd_cmd::sd_status(), true)?;
300
301 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
302
303 for byte in cmd_block.iter_mut() {
304 *byte = u32::from_be(*byte);
305 }
306
307 Ok(cmd_block.0.into())
308 }
309}
310
311/// Emmc storage device
312impl<'a, 'b> StorageDevice<'a, 'b, Emmc> {
313 /// Create a new EMMC card
314 pub async fn new_emmc(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> {
315 let mut s = Self {
316 info: Emmc::default(),
317 sdmmc,
318 };
319
320 s.acquire(cmd_block, freq).await?;
321
322 Ok(s)
323 }
324
325 async fn acquire(&mut self, _cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> {
326 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
327 let regs = self.sdmmc.info.regs;
328
329 let bus_width = self.sdmmc.bus_width();
330
331 // While the SD/SDIO card or eMMC is in identification mode,
332 // the SDMMC_CK frequency must be no more than 400 kHz.
333 self.sdmmc.init_idle()?;
334
335 let ocr = loop {
336 let high_voltage = 0b0 << 7;
337 let access_mode = 0b10 << 29;
338 let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15;
339 // Initialize card
340 match self.sdmmc.cmd(emmc_cmd::send_op_cond(op_cond), false) {
341 Ok(_) => (),
342 Err(Error::Crc) => (),
343 Err(err) => return Err(err),
344 }
345 let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into();
346 if !ocr.is_busy() {
347 // Power up done
348 break ocr;
349 }
350 };
351
352 self.info.capacity = if ocr.access_mode() == 0b10 {
353 // Card is SDHC or SDXC or SDUC
354 CardCapacity::HighCapacity
355 } else {
356 CardCapacity::StandardCapacity
357 };
358 self.info.ocr = ocr;
359
360 self.info.cid = self.sdmmc.get_cid()?.into();
361
362 self.info.rca = 1u16.into();
363 self.sdmmc
364 .cmd(emmc_cmd::assign_relative_address(self.info.rca), false)?;
365
366 self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into();
367 self.sdmmc.select_card(Some(self.info.get_address()))?;
368
369 let (widbus, _) = bus_width_vals(bus_width);
370
371 // Write bus width to ExtCSD byte 183
372 self.sdmmc.cmd(
373 emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus),
374 false,
375 )?;
376
377 // Wait for ready after R1b response
378 loop {
379 let status = self.sdmmc.read_status(&self.info)?;
380
381 if status.ready_for_data() {
382 break;
383 }
384 }
385
386 self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?;
387 self.info.ext_csd = self.read_ext_csd().await?;
388
389 Ok(())
390 }
391
392 /// Gets the EXT_CSD register.
393 ///
394 /// eMMC only.
395 async fn read_ext_csd(&self) -> Result<ExtCSD, Error> {
396 // Note: cmd_block can't be used because ExtCSD is too long to fit.
397 let mut data_block = DataBlock::new();
398
399 self.sdmmc
400 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)
401 .unwrap(); // CMD16
402
403 let transfer = self.sdmmc.prepare_datapath_read(
404 aligned_mut(&mut data_block.0),
405 DatapathMode::Block(block_size(size_of::<DataBlock>())),
406 );
407 self.sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?;
408
409 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
410
411 Ok(data_block.0.into())
412 }
413}
414
415/// Card or Emmc storage device
416impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> {
417 /// Write a block
418 pub fn card(&self) -> A {
419 self.info.clone()
420 }
421
422 /// Read a data block.
423 #[inline]
424 pub async fn read_block(&mut self, block_idx: u32, data_block: &mut DataBlock) -> Result<(), Error> {
425 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
426 let card_capacity = self.info.get_capacity();
427
428 // Always read 1 block of 512 bytes
429 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
430 let address = match card_capacity {
431 CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32,
432 _ => block_idx,
433 };
434 self.sdmmc
435 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
436
437 let transfer = self.sdmmc.prepare_datapath_read(
438 aligned_mut(&mut data_block.0),
439 DatapathMode::Block(block_size(size_of::<DataBlock>())),
440 );
441 self.sdmmc.cmd(common_cmd::read_single_block(address), true)?;
442
443 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
444
445 Ok(())
446 }
447
448 /// Read multiple data blocks.
449 #[inline]
450 pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
451 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
452 let card_capacity = self.info.get_capacity();
453
454 // NOTE(unsafe) reinterpret buffer as &mut [u32]
455 let buffer = unsafe {
456 core::slice::from_raw_parts_mut(
457 blocks.as_mut_ptr() as *mut u32,
458 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
459 )
460 };
461
462 // Always read 1 block of 512 bytes
463 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
464 let address = match card_capacity {
465 CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32,
466 _ => block_idx,
467 };
468 self.sdmmc
469 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
470
471 let transfer = self.sdmmc.prepare_datapath_read(
472 aligned_mut(buffer),
473 DatapathMode::Block(block_size(size_of::<DataBlock>())),
474 );
475 self.sdmmc.cmd(common_cmd::read_multiple_blocks(address), true)?;
476
477 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
478
479 self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12
480 self.sdmmc.clear_interrupt_flags();
481
482 Ok(())
483 }
484
485 /// Write a data block.
486 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error>
487 where
488 CardStatus<A::Ext>: From<u32>,
489 {
490 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
491
492 // Always read 1 block of 512 bytes
493 // cards are byte addressed hence the blockaddress is in multiples of 512 bytes
494 let address = match self.info.get_capacity() {
495 CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32,
496 _ => block_idx,
497 };
498 self.sdmmc
499 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
500
501 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
502 #[cfg(sdmmc_v1)]
503 self.sdmmc.cmd(common_cmd::write_single_block(address), true)?;
504
505 let transfer = self.sdmmc.prepare_datapath_write(
506 aligned_ref(&buffer.0),
507 DatapathMode::Block(block_size(size_of::<DataBlock>())),
508 );
509
510 #[cfg(sdmmc_v2)]
511 self.sdmmc.cmd(common_cmd::write_single_block(address), true)?;
512
513 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
514
515 // TODO: Make this configurable
516 let mut timeout: u32 = 0x00FF_FFFF;
517
518 while timeout > 0 {
519 let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data();
520 if ready_for_data {
521 return Ok(());
522 }
523 timeout -= 1;
524 }
525
526 Err(Error::SoftwareTimeout)
527 }
528
529 /// Write multiple data blocks.
530 pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error>
531 where
532 CardStatus<A::Ext>: From<u32>,
533 {
534 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
535
536 // NOTE(unsafe) reinterpret buffer as &[u32]
537 let buffer = unsafe {
538 core::slice::from_raw_parts(
539 blocks.as_ptr() as *const u32,
540 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
541 )
542 };
543 // Always read 1 block of 512 bytes
544 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
545 let address = match self.info.get_capacity() {
546 CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32,
547 _ => block_idx,
548 };
549
550 self.sdmmc
551 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
552
553 #[cfg(sdmmc_v1)]
554 self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
555
556 // Setup write command
557 let transfer = self.sdmmc.prepare_datapath_write(
558 aligned_ref(buffer),
559 DatapathMode::Block(block_size(size_of::<DataBlock>())),
560 );
561 #[cfg(sdmmc_v2)]
562 self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
563
564 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
565
566 self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12
567 self.sdmmc.clear_interrupt_flags();
568
569 // TODO: Make this configurable
570 let mut timeout: u32 = 0x00FF_FFFF;
571
572 while timeout > 0 {
573 let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data();
574
575 if ready_for_data {
576 return Ok(());
577 }
578 timeout -= 1;
579 }
580 Err(Error::SoftwareTimeout)
581 }
582}
583
584#[derive(Clone, Copy, Debug, Default)]
585/// SD Card
586pub struct Card {
587 /// The type of this card
588 pub card_type: CardCapacity,
589 /// Operation Conditions Register
590 pub ocr: OCR<SD>,
591 /// Relative Card Address
592 pub rca: u16,
593 /// Card ID
594 pub cid: CID<SD>,
595 /// Card Specific Data
596 pub csd: CSD<SD>,
597 /// SD CARD Configuration Register
598 pub scr: SCR,
599 /// SD Status
600 pub status: SDStatus,
601}
602
603impl Addressable for Card {
604 type Ext = SD;
605
606 /// Get this peripheral's address on the SDMMC bus
607 fn get_address(&self) -> u16 {
608 self.rca
609 }
610
611 /// Is this a standard or high capacity peripheral?
612 fn get_capacity(&self) -> CardCapacity {
613 self.card_type
614 }
615
616 /// Size in bytes
617 fn size(&self) -> u64 {
618 u64::from(self.csd.block_count()) * 512
619 }
620}
621
622#[derive(Clone, Copy, Debug, Default)]
623/// eMMC storage
624pub struct Emmc {
625 /// The capacity of this card
626 pub capacity: CardCapacity,
627 /// Operation Conditions Register
628 pub ocr: OCR<EMMC>,
629 /// Relative Card Address
630 pub rca: u16,
631 /// Card ID
632 pub cid: CID<EMMC>,
633 /// Card Specific Data
634 pub csd: CSD<EMMC>,
635 /// Extended Card Specific Data
636 pub ext_csd: ExtCSD,
637}
638
639impl Addressable for Emmc {
640 type Ext = EMMC;
641
642 /// Get this peripheral's address on the SDMMC bus
643 fn get_address(&self) -> u16 {
644 self.rca
645 }
646
647 /// Is this a standard or high capacity peripheral?
648 fn get_capacity(&self) -> CardCapacity {
649 self.capacity
650 }
651
652 /// Size in bytes
653 fn size(&self) -> u64 {
654 u64::from(self.ext_csd.sector_count()) * 512
655 }
656}
657
658impl<'d, 'e, A: Addressable> block_device_driver::BlockDevice<512> for StorageDevice<'d, 'e, A> {
659 type Error = Error;
660 type Align = aligned::A4;
661
662 async fn read(
663 &mut self,
664 block_address: u32,
665 buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>],
666 ) -> Result<(), Self::Error> {
667 // TODO: I think block_address needs to be adjusted by the partition start offset
668 if buf.len() == 1 {
669 let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut DataBlock) };
670 self.read_block(block_address, block).await?;
671 } else {
672 let blocks: &mut [DataBlock] =
673 unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) };
674 self.read_blocks(block_address, blocks).await?;
675 }
676 Ok(())
677 }
678
679 async fn write(
680 &mut self,
681 block_address: u32,
682 buf: &[aligned::Aligned<Self::Align, [u8; 512]>],
683 ) -> Result<(), Self::Error> {
684 // TODO: I think block_address needs to be adjusted by the partition start offset
685 if buf.len() == 1 {
686 let block = unsafe { &*(&buf[0] as *const _ as *const DataBlock) };
687 self.write_block(block_address, block).await?;
688 } else {
689 let blocks: &[DataBlock] =
690 unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) };
691 self.write_blocks(block_address, blocks).await?;
692 }
693 Ok(())
694 }
695
696 async fn size(&mut self) -> Result<u64, Self::Error> {
697 Ok(self.info.size())
698 }
699}
diff --git a/embassy-stm32/src/sdmmc/sdio.rs b/embassy-stm32/src/sdmmc/sdio.rs
new file mode 100644
index 000000000..e436d68cb
--- /dev/null
+++ b/embassy-stm32/src/sdmmc/sdio.rs
@@ -0,0 +1,178 @@
1use core::ops::{Deref, DerefMut};
2
3use aligned::{A4, Aligned};
4use sdio_host::common_cmd::{R1, Rz, cmd};
5use sdio_host::sd::BusWidth;
6use sdio_host::sd_cmd;
7
8use crate::sdmmc::{DatapathMode, Error, Sdmmc, aligned_mut, aligned_ref, block_size, slice8_mut, slice8_ref};
9use crate::time::Hertz;
10
11/// Aligned data block for SDMMC transfers.
12///
13/// This is a 64-byte array, aligned to 4 bytes to satisfy DMA requirements.
14#[repr(align(4))]
15#[derive(Debug, Clone, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct DataBlock(pub [u32; 16]);
18
19impl DataBlock {
20 /// Create a new DataBlock
21 pub const fn new() -> Self {
22 DataBlock([0u32; 16])
23 }
24}
25
26impl Deref for DataBlock {
27 type Target = [u8; 64];
28
29 fn deref(&self) -> &Self::Target {
30 unwrap!(slice8_ref(&self.0[..]).try_into())
31 }
32}
33
34impl DerefMut for DataBlock {
35 fn deref_mut(&mut self) -> &mut Self::Target {
36 unwrap!(slice8_mut(&mut self.0[..]).try_into())
37 }
38}
39
40/// Storage Device
41pub struct SerialDataInterface<'a, 'b> {
42 /// Inner member
43 sdmmc: &'a mut Sdmmc<'b>,
44}
45
46/// Card Storage Device
47impl<'a, 'b> SerialDataInterface<'a, 'b> {
48 /// Create a new SD card
49 pub async fn new(sdmmc: &'a mut Sdmmc<'b>, freq: Hertz) -> Result<Self, Error> {
50 let mut s = Self { sdmmc };
51
52 s.acquire(freq).await?;
53
54 Ok(s)
55 }
56
57 /// Initializes the card into a known state (or at least tries to).
58 async fn acquire(&mut self, _freq: Hertz) -> Result<(), Error> {
59 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
60
61 let _bus_width = match self.sdmmc.bus_width() {
62 BusWidth::Eight => return Err(Error::BusWidth),
63 bus_width => bus_width,
64 };
65
66 // While the SD/SDIO card or eMMC is in identification mode,
67 // the SDMMC_CK frequency must be no more than 400 kHz.
68 self.sdmmc.init_idle()?;
69
70 self.sdmmc.cmd(cmd::<Rz>(5, 0), false)?;
71
72 // Get RCA
73 let rca = self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?;
74
75 // Select the card with RCA
76 self.sdmmc.select_card(Some(rca.try_into().unwrap()))?;
77
78 Ok(())
79 }
80
81 /// Set the bus to the 4-bit high-speed frequency
82 pub fn set_bus_to_high_speed(&mut self, frequency: Hertz) -> Result<(), Error> {
83 self.sdmmc.clkcr_set_clkdiv(frequency, BusWidth::Four)?;
84
85 Ok(())
86 }
87
88 /// Run cmd52
89 pub async fn cmd52(&mut self, arg: u32) -> Result<u32, Error> {
90 self.sdmmc.cmd(cmd::<R1>(52, arg), false)
91 }
92
93 /// Read in block mode using cmd53
94 pub async fn cmd53_block_read(&mut self, arg: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
95 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
96
97 // NOTE(unsafe) reinterpret buffer as &mut [u32]
98 let buffer = unsafe {
99 core::slice::from_raw_parts_mut(
100 blocks.as_mut_ptr() as *mut u32,
101 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
102 )
103 };
104
105 let transfer = self.sdmmc.prepare_datapath_read(
106 aligned_mut(buffer),
107 DatapathMode::Block(block_size(size_of::<DataBlock>())),
108 );
109 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
110
111 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
112 self.sdmmc.clear_interrupt_flags();
113
114 Ok(())
115 }
116
117 /// Read in multibyte mode using cmd53
118 pub async fn cmd53_byte_read(&mut self, arg: u32, buffer: &mut Aligned<A4, [u8]>) -> Result<(), Error> {
119 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
120
121 let transfer = self.sdmmc.prepare_datapath_read(buffer, DatapathMode::Byte);
122 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
123
124 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
125 self.sdmmc.clear_interrupt_flags();
126
127 Ok(())
128 }
129
130 /// Write in block mode using cmd53
131 pub async fn cmd53_block_write(&mut self, arg: u32, blocks: &[DataBlock]) -> Result<(), Error> {
132 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
133
134 // NOTE(unsafe) reinterpret buffer as &mut [u32]
135 let buffer = unsafe {
136 core::slice::from_raw_parts_mut(
137 blocks.as_ptr() as *mut u32,
138 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
139 )
140 };
141
142 #[cfg(sdmmc_v1)]
143 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
144
145 let transfer = self.sdmmc.prepare_datapath_write(
146 aligned_ref(buffer),
147 DatapathMode::Block(block_size(size_of::<DataBlock>())),
148 );
149
150 #[cfg(sdmmc_v2)]
151 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
152
153 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
154 self.sdmmc.clear_interrupt_flags();
155
156 Ok(())
157 }
158
159 /// Write in multibyte mode using cmd53
160 pub async fn cmd53_byte_write(&mut self, arg: u32, buffer: &[u32]) -> Result<(), Error> {
161 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
162
163 #[cfg(sdmmc_v1)]
164 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
165
166 let transfer = self
167 .sdmmc
168 .prepare_datapath_write(aligned_ref(buffer), DatapathMode::Byte);
169
170 #[cfg(sdmmc_v2)]
171 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
172
173 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
174 self.sdmmc.clear_interrupt_flags();
175
176 Ok(())
177 }
178}
diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs
index b0a32d5d1..6f2d24560 100644
--- a/embassy-stm32/src/spdifrx/mod.rs
+++ b/embassy-stm32/src/spdifrx/mod.rs
@@ -13,7 +13,7 @@ use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::spdifrx::Spdifrx as Regs; 14use crate::pac::spdifrx::Spdifrx as Regs;
15use crate::rcc::{RccInfo, SealedRccPeripheral}; 15use crate::rcc::{RccInfo, SealedRccPeripheral};
16use crate::{interrupt, peripherals, Peri}; 16use crate::{Peri, interrupt, peripherals};
17 17
18/// Possible S/PDIF preamble types. 18/// Possible S/PDIF preamble types.
19#[allow(dead_code)] 19#[allow(dead_code)]
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c5373a54d..13ff31a34 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -6,15 +6,15 @@ use core::ptr;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 9pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
10 10
11use crate::dma::{word, ChannelAndRequest}; 11use crate::Peri;
12use crate::dma::{ChannelAndRequest, word};
12use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
13use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
14use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{Spi as Regs, regs, vals};
15use crate::rcc::{RccInfo, SealedRccPeripheral}; 16use crate::rcc::{RccInfo, SealedRccPeripheral};
16use crate::time::Hertz; 17use crate::time::Hertz;
17use crate::Peri;
18 18
19/// SPI error. 19/// SPI error.
20#[derive(Debug, PartialEq, Eq, Clone, Copy)] 20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -54,6 +54,26 @@ pub enum BitOrder {
54 MsbFirst, 54 MsbFirst,
55} 55}
56 56
57/// SPI Direction.
58#[derive(Debug, PartialEq, Eq, Clone, Copy)]
59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
60pub enum Direction {
61 /// Transmit
62 Transmit,
63 /// Receive
64 Receive,
65}
66
67/// Slave Select (SS) pin polarity.
68#[derive(Debug, PartialEq, Eq, Clone, Copy)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum SlaveSelectPolarity {
71 /// SS active high
72 ActiveHigh,
73 /// SS active low
74 ActiveLow,
75}
76
57/// SPI configuration. 77/// SPI configuration.
58#[non_exhaustive] 78#[non_exhaustive]
59#[derive(Copy, Clone)] 79#[derive(Copy, Clone)]
@@ -72,6 +92,13 @@ pub struct Config {
72 /// signal rise/fall speed (slew rate) - defaults to `Medium`. 92 /// signal rise/fall speed (slew rate) - defaults to `Medium`.
73 /// Increase for high SPI speeds. Change to `Low` to reduce ringing. 93 /// Increase for high SPI speeds. Change to `Low` to reduce ringing.
74 pub gpio_speed: Speed, 94 pub gpio_speed: Speed,
95 /// If True sets SSOE to zero even if SPI is in Master Mode.
96 /// NSS output enabled (SSM = 0, SSOE = 1): The NSS signal is driven low when the master starts the communication and is kept low until the SPI is disabled.
97 /// NSS output disabled (SSM = 0, SSOE = 0): For devices set as slave, the NSS pin acts as a classical NSS input: the slave is selected when NSS is low and deselected when NSS high.
98 pub nss_output_disable: bool,
99 /// Slave Select (SS) pin polarity.
100 #[cfg(any(spi_v4, spi_v5, spi_v6))]
101 pub nss_polarity: SlaveSelectPolarity,
75} 102}
76 103
77impl Default for Config { 104impl Default for Config {
@@ -82,6 +109,9 @@ impl Default for Config {
82 frequency: Hertz(1_000_000), 109 frequency: Hertz(1_000_000),
83 miso_pull: Pull::None, 110 miso_pull: Pull::None,
84 gpio_speed: Speed::VeryHigh, 111 gpio_speed: Speed::VeryHigh,
112 nss_output_disable: false,
113 #[cfg(any(spi_v4, spi_v5, spi_v6))]
114 nss_polarity: SlaveSelectPolarity::ActiveHigh,
85 } 115 }
86 } 116 }
87} 117}
@@ -108,6 +138,14 @@ impl Config {
108 } 138 }
109 } 139 }
110 140
141 #[cfg(any(spi_v4, spi_v5, spi_v6))]
142 fn raw_nss_polarity(&self) -> vals::Ssiop {
143 match self.nss_polarity {
144 SlaveSelectPolarity::ActiveHigh => vals::Ssiop::ACTIVE_HIGH,
145 SlaveSelectPolarity::ActiveLow => vals::Ssiop::ACTIVE_LOW,
146 }
147 }
148
111 #[cfg(gpio_v1)] 149 #[cfg(gpio_v1)]
112 fn sck_af(&self) -> AfType { 150 fn sck_af(&self) -> AfType {
113 AfType::output(OutputType::PushPull, self.gpio_speed) 151 AfType::output(OutputType::PushPull, self.gpio_speed)
@@ -125,26 +163,69 @@ impl Config {
125 ) 163 )
126 } 164 }
127} 165}
166
167/// SPI communication mode
168pub mod mode {
169 use stm32_metapac::spi::vals;
170
171 trait SealedMode {}
172
173 /// Trait for SPI communication mode operations.
174 #[allow(private_bounds)]
175 pub trait CommunicationMode: SealedMode {
176 /// Spi communication mode
177 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
178 const MASTER: vals::Mstr;
179 /// Spi communication mode
180 #[cfg(any(spi_v4, spi_v5, spi_v6))]
181 const MASTER: vals::Master;
182 }
183
184 /// Mode allowing for SPI master operations.
185 pub struct Master;
186 /// Mode allowing for SPI slave operations.
187 pub struct Slave;
188
189 impl SealedMode for Master {}
190 impl CommunicationMode for Master {
191 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
192 const MASTER: vals::Mstr = vals::Mstr::MASTER;
193 #[cfg(any(spi_v4, spi_v5, spi_v6))]
194 const MASTER: vals::Master = vals::Master::MASTER;
195 }
196
197 impl SealedMode for Slave {}
198 impl CommunicationMode for Slave {
199 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
200 const MASTER: vals::Mstr = vals::Mstr::SLAVE;
201 #[cfg(any(spi_v4, spi_v5, spi_v6))]
202 const MASTER: vals::Master = vals::Master::SLAVE;
203 }
204}
205use mode::{CommunicationMode, Master, Slave};
206
128/// SPI driver. 207/// SPI driver.
129pub struct Spi<'d, M: PeriMode> { 208pub struct Spi<'d, M: PeriMode, CM: CommunicationMode> {
130 pub(crate) info: &'static Info, 209 pub(crate) info: &'static Info,
131 kernel_clock: Hertz, 210 kernel_clock: Hertz,
132 sck: Option<Peri<'d, AnyPin>>, 211 sck: Option<Peri<'d, AnyPin>>,
133 mosi: Option<Peri<'d, AnyPin>>, 212 mosi: Option<Peri<'d, AnyPin>>,
134 miso: Option<Peri<'d, AnyPin>>, 213 miso: Option<Peri<'d, AnyPin>>,
214 nss: Option<Peri<'d, AnyPin>>,
135 tx_dma: Option<ChannelAndRequest<'d>>, 215 tx_dma: Option<ChannelAndRequest<'d>>,
136 rx_dma: Option<ChannelAndRequest<'d>>, 216 rx_dma: Option<ChannelAndRequest<'d>>,
137 _phantom: PhantomData<M>, 217 _phantom: PhantomData<(M, CM)>,
138 current_word_size: word_impl::Config, 218 current_word_size: word_impl::Config,
139 gpio_speed: Speed, 219 gpio_speed: Speed,
140} 220}
141 221
142impl<'d, M: PeriMode> Spi<'d, M> { 222impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
143 fn new_inner<T: Instance>( 223 fn new_inner<T: Instance>(
144 _peri: Peri<'d, T>, 224 _peri: Peri<'d, T>,
145 sck: Option<Peri<'d, AnyPin>>, 225 sck: Option<Peri<'d, AnyPin>>,
146 mosi: Option<Peri<'d, AnyPin>>, 226 mosi: Option<Peri<'d, AnyPin>>,
147 miso: Option<Peri<'d, AnyPin>>, 227 miso: Option<Peri<'d, AnyPin>>,
228 nss: Option<Peri<'d, AnyPin>>,
148 tx_dma: Option<ChannelAndRequest<'d>>, 229 tx_dma: Option<ChannelAndRequest<'d>>,
149 rx_dma: Option<ChannelAndRequest<'d>>, 230 rx_dma: Option<ChannelAndRequest<'d>>,
150 config: Config, 231 config: Config,
@@ -155,6 +236,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
155 sck, 236 sck,
156 mosi, 237 mosi,
157 miso, 238 miso,
239 nss,
158 tx_dma, 240 tx_dma,
159 rx_dma, 241 rx_dma,
160 current_word_size: <u8 as SealedWord>::CONFIG, 242 current_word_size: <u8 as SealedWord>::CONFIG,
@@ -171,24 +253,46 @@ impl<'d, M: PeriMode> Spi<'d, M> {
171 let cpol = config.raw_polarity(); 253 let cpol = config.raw_polarity();
172 let lsbfirst = config.raw_byte_order(); 254 let lsbfirst = config.raw_byte_order();
173 255
174 self.info.rcc.enable_and_reset(); 256 self.info.rcc.enable_and_reset_without_stop();
257
258 /*
259 - Software NSS management (SSM = 1)
260 The slave select information is driven internally by the value of the SSI bit in the
261 SPI_CR1 register. The external NSS pin remains free for other application uses.
262
263 - Hardware NSS management (SSM = 0)
264 Two configurations are possible depending on the NSS output configuration (SSOE bit
265 in register SPI_CR1).
266
267 -- NSS output enabled (SSM = 0, SSOE = 1)
268 This configuration is used only when the device operates in master mode. The
269 NSS signal is driven low when the master starts the communication and is kept
270 low until the SPI is disabled.
271
272 -- NSS output disabled (SSM = 0, SSOE = 0)
273 This configuration allows multimaster capability for devices operating in master
274 mode. For devices set as slave, the NSS pin acts as a classical NSS input: the
275 slave is selected when NSS is low and deselected when NSS high
276 */
277 let ssm = self.nss.is_none();
175 278
176 let regs = self.info.regs; 279 let regs = self.info.regs;
177 #[cfg(any(spi_v1, spi_v2))] 280 #[cfg(any(spi_v1, spi_v2))]
178 { 281 {
282 let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable;
179 regs.cr2().modify(|w| { 283 regs.cr2().modify(|w| {
180 w.set_ssoe(false); 284 w.set_ssoe(ssoe);
181 }); 285 });
182 regs.cr1().modify(|w| { 286 regs.cr1().modify(|w| {
183 w.set_cpha(cpha); 287 w.set_cpha(cpha);
184 w.set_cpol(cpol); 288 w.set_cpol(cpol);
185 289
186 w.set_mstr(vals::Mstr::MASTER); 290 w.set_mstr(CM::MASTER);
187 w.set_br(br); 291 w.set_br(br);
188 w.set_spe(true); 292 w.set_spe(true);
189 w.set_lsbfirst(lsbfirst); 293 w.set_lsbfirst(lsbfirst);
190 w.set_ssi(true); 294 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
191 w.set_ssm(true); 295 w.set_ssm(ssm);
192 w.set_crcen(false); 296 w.set_crcen(false);
193 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 297 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
194 // we're doing "fake rxonly", by actually writing one 298 // we're doing "fake rxonly", by actually writing one
@@ -200,21 +304,22 @@ impl<'d, M: PeriMode> Spi<'d, M> {
200 } 304 }
201 #[cfg(spi_v3)] 305 #[cfg(spi_v3)]
202 { 306 {
307 let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable;
203 regs.cr2().modify(|w| { 308 regs.cr2().modify(|w| {
204 let (ds, frxth) = <u8 as SealedWord>::CONFIG; 309 let (ds, frxth) = <u8 as SealedWord>::CONFIG;
205 w.set_frxth(frxth); 310 w.set_frxth(frxth);
206 w.set_ds(ds); 311 w.set_ds(ds);
207 w.set_ssoe(false); 312 w.set_ssoe(ssoe);
208 }); 313 });
209 regs.cr1().modify(|w| { 314 regs.cr1().modify(|w| {
210 w.set_cpha(cpha); 315 w.set_cpha(cpha);
211 w.set_cpol(cpol); 316 w.set_cpol(cpol);
212 317
213 w.set_mstr(vals::Mstr::MASTER); 318 w.set_mstr(CM::MASTER);
214 w.set_br(br); 319 w.set_br(br);
215 w.set_lsbfirst(lsbfirst); 320 w.set_lsbfirst(lsbfirst);
216 w.set_ssi(true); 321 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
217 w.set_ssm(true); 322 w.set_ssm(ssm);
218 w.set_crcen(false); 323 w.set_crcen(false);
219 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 324 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
220 w.set_spe(true); 325 w.set_spe(true);
@@ -222,21 +327,22 @@ impl<'d, M: PeriMode> Spi<'d, M> {
222 } 327 }
223 #[cfg(any(spi_v4, spi_v5, spi_v6))] 328 #[cfg(any(spi_v4, spi_v5, spi_v6))]
224 { 329 {
330 let ssoe = CM::MASTER == vals::Master::MASTER && !config.nss_output_disable;
331 let ssiop = config.raw_nss_polarity();
225 regs.ifcr().write(|w| w.0 = 0xffff_ffff); 332 regs.ifcr().write(|w| w.0 = 0xffff_ffff);
226 regs.cfg2().modify(|w| { 333 regs.cfg2().modify(|w| {
227 //w.set_ssoe(true); 334 w.set_ssoe(ssoe);
228 w.set_ssoe(false);
229 w.set_cpha(cpha); 335 w.set_cpha(cpha);
230 w.set_cpol(cpol); 336 w.set_cpol(cpol);
231 w.set_lsbfirst(lsbfirst); 337 w.set_lsbfirst(lsbfirst);
232 w.set_ssm(true); 338 w.set_ssm(ssm);
233 w.set_master(vals::Master::MASTER); 339 w.set_master(CM::MASTER);
234 w.set_comm(vals::Comm::FULL_DUPLEX); 340 w.set_comm(vals::Comm::FULL_DUPLEX);
235 w.set_ssom(vals::Ssom::ASSERTED); 341 w.set_ssom(vals::Ssom::ASSERTED);
236 w.set_midi(0); 342 w.set_midi(0);
237 w.set_mssi(0); 343 w.set_mssi(0);
238 w.set_afcntr(true); 344 w.set_afcntr(true);
239 w.set_ssiop(vals::Ssiop::ACTIVE_HIGH); 345 w.set_ssiop(ssiop);
240 }); 346 });
241 regs.cfg1().modify(|w| { 347 regs.cfg1().modify(|w| {
242 w.set_crcen(false); 348 w.set_crcen(false);
@@ -284,6 +390,8 @@ impl<'d, M: PeriMode> Spi<'d, M> {
284 390
285 #[cfg(any(spi_v4, spi_v5, spi_v6))] 391 #[cfg(any(spi_v4, spi_v5, spi_v6))]
286 { 392 {
393 let ssiop = config.raw_nss_polarity();
394
287 self.info.regs.cr1().modify(|w| { 395 self.info.regs.cr1().modify(|w| {
288 w.set_spe(false); 396 w.set_spe(false);
289 }); 397 });
@@ -292,6 +400,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
292 w.set_cpha(cpha); 400 w.set_cpha(cpha);
293 w.set_cpol(cpol); 401 w.set_cpol(cpol);
294 w.set_lsbfirst(lsbfirst); 402 w.set_lsbfirst(lsbfirst);
403 w.set_ssiop(ssiop);
295 }); 404 });
296 self.info.regs.cfg1().modify(|w| { 405 self.info.regs.cfg1().modify(|w| {
297 w.set_mbr(br); 406 w.set_mbr(br);
@@ -304,6 +413,20 @@ impl<'d, M: PeriMode> Spi<'d, M> {
304 Ok(()) 413 Ok(())
305 } 414 }
306 415
416 /// Set SPI direction
417 #[cfg(any(spi_v1, spi_v2, spi_v3))]
418 pub fn set_direction(&mut self, dir: Option<Direction>) {
419 let (bidimode, bidioe) = match dir {
420 Some(Direction::Transmit) => (vals::Bidimode::BIDIRECTIONAL, vals::Bidioe::TRANSMIT),
421 Some(Direction::Receive) => (vals::Bidimode::BIDIRECTIONAL, vals::Bidioe::RECEIVE),
422 None => (vals::Bidimode::UNIDIRECTIONAL, vals::Bidioe::TRANSMIT),
423 };
424 self.info.regs.cr1().modify(|w| {
425 w.set_bidimode(bidimode);
426 w.set_bidioe(bidioe);
427 });
428 }
429
307 /// Get current SPI configuration. 430 /// Get current SPI configuration.
308 pub fn get_current_config(&self) -> Config { 431 pub fn get_current_config(&self) -> Config {
309 #[cfg(any(spi_v1, spi_v2, spi_v3))] 432 #[cfg(any(spi_v1, spi_v2, spi_v3))]
@@ -313,6 +436,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
313 #[cfg(any(spi_v4, spi_v5, spi_v6))] 436 #[cfg(any(spi_v4, spi_v5, spi_v6))]
314 let cfg1 = self.info.regs.cfg1().read(); 437 let cfg1 = self.info.regs.cfg1().read();
315 438
439 #[cfg(any(spi_v1, spi_v2, spi_v3))]
440 let ssoe = self.info.regs.cr2().read().ssoe();
441 #[cfg(any(spi_v4, spi_v5, spi_v6))]
442 let ssoe = cfg.ssoe();
443
316 let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { 444 let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW {
317 Polarity::IdleLow 445 Polarity::IdleLow
318 } else { 446 } else {
@@ -342,12 +470,25 @@ impl<'d, M: PeriMode> Spi<'d, M> {
342 470
343 let frequency = compute_frequency(self.kernel_clock, br); 471 let frequency = compute_frequency(self.kernel_clock, br);
344 472
473 // NSS output disabled if SSOE=0 or if SSM=1 software slave management enabled
474 let nss_output_disable = !ssoe || cfg.ssm();
475
476 #[cfg(any(spi_v4, spi_v5, spi_v6))]
477 let nss_polarity = if cfg.ssiop() == vals::Ssiop::ACTIVE_LOW {
478 SlaveSelectPolarity::ActiveLow
479 } else {
480 SlaveSelectPolarity::ActiveHigh
481 };
482
345 Config { 483 Config {
346 mode: Mode { polarity, phase }, 484 mode: Mode { polarity, phase },
347 bit_order, 485 bit_order,
348 frequency, 486 frequency,
349 miso_pull, 487 miso_pull,
350 gpio_speed: self.gpio_speed, 488 gpio_speed: self.gpio_speed,
489 nss_output_disable,
490 #[cfg(any(spi_v4, spi_v5, spi_v6))]
491 nss_polarity,
351 } 492 }
352 } 493 }
353 494
@@ -469,7 +610,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
469 } 610 }
470} 611}
471 612
472impl<'d> Spi<'d, Blocking> { 613impl<'d> Spi<'d, Blocking, Slave> {
614 /// Create a new blocking SPI slave driver.
615 pub fn new_blocking_slave<T: Instance, #[cfg(afio)] A>(
616 peri: Peri<'d, T>,
617 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
618 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
619 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
620 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
621 config: Config,
622 ) -> Self {
623 Self::new_inner(
624 peri,
625 new_pin!(sck, config.sck_af()),
626 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
627 new_pin!(miso, AfType::input(config.miso_pull)),
628 new_pin!(cs, AfType::input(Pull::None)),
629 None,
630 None,
631 config,
632 )
633 }
634}
635
636impl<'d> Spi<'d, Blocking, Master> {
473 /// Create a new blocking SPI driver. 637 /// Create a new blocking SPI driver.
474 pub fn new_blocking<T: Instance, #[cfg(afio)] A>( 638 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
475 peri: Peri<'d, T>, 639 peri: Peri<'d, T>,
@@ -485,6 +649,7 @@ impl<'d> Spi<'d, Blocking> {
485 new_pin!(miso, AfType::input(config.miso_pull)), 649 new_pin!(miso, AfType::input(config.miso_pull)),
486 None, 650 None,
487 None, 651 None,
652 None,
488 config, 653 config,
489 ) 654 )
490 } 655 }
@@ -503,6 +668,7 @@ impl<'d> Spi<'d, Blocking> {
503 new_pin!(miso, AfType::input(config.miso_pull)), 668 new_pin!(miso, AfType::input(config.miso_pull)),
504 None, 669 None,
505 None, 670 None,
671 None,
506 config, 672 config,
507 ) 673 )
508 } 674 }
@@ -521,6 +687,7 @@ impl<'d> Spi<'d, Blocking> {
521 None, 687 None,
522 None, 688 None,
523 None, 689 None,
690 None,
524 config, 691 config,
525 ) 692 )
526 } 693 }
@@ -540,12 +707,38 @@ impl<'d> Spi<'d, Blocking> {
540 None, 707 None,
541 None, 708 None,
542 None, 709 None,
710 None,
543 config, 711 config,
544 ) 712 )
545 } 713 }
546} 714}
547 715
548impl<'d> Spi<'d, Async> { 716impl<'d> Spi<'d, Async, Slave> {
717 /// Create a new SPI slave driver.
718 pub fn new_slave<T: Instance, #[cfg(afio)] A>(
719 peri: Peri<'d, T>,
720 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
721 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
722 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
723 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
724 tx_dma: Peri<'d, impl TxDma<T>>,
725 rx_dma: Peri<'d, impl RxDma<T>>,
726 config: Config,
727 ) -> Self {
728 Self::new_inner(
729 peri,
730 new_pin!(sck, config.sck_af()),
731 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
732 new_pin!(miso, AfType::input(config.miso_pull)),
733 new_pin!(cs, AfType::input(Pull::None)),
734 new_dma!(tx_dma),
735 new_dma!(rx_dma),
736 config,
737 )
738 }
739}
740
741impl<'d> Spi<'d, Async, Master> {
549 /// Create a new SPI driver. 742 /// Create a new SPI driver.
550 pub fn new<T: Instance, #[cfg(afio)] A>( 743 pub fn new<T: Instance, #[cfg(afio)] A>(
551 peri: Peri<'d, T>, 744 peri: Peri<'d, T>,
@@ -561,6 +754,7 @@ impl<'d> Spi<'d, Async> {
561 new_pin!(sck, config.sck_af()), 754 new_pin!(sck, config.sck_af()),
562 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 755 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
563 new_pin!(miso, AfType::input(config.miso_pull)), 756 new_pin!(miso, AfType::input(config.miso_pull)),
757 None,
564 new_dma!(tx_dma), 758 new_dma!(tx_dma),
565 new_dma!(rx_dma), 759 new_dma!(rx_dma),
566 config, 760 config,
@@ -581,6 +775,7 @@ impl<'d> Spi<'d, Async> {
581 new_pin!(sck, config.sck_af()), 775 new_pin!(sck, config.sck_af()),
582 None, 776 None,
583 new_pin!(miso, AfType::input(config.miso_pull)), 777 new_pin!(miso, AfType::input(config.miso_pull)),
778 None,
584 #[cfg(any(spi_v1, spi_v2, spi_v3))] 779 #[cfg(any(spi_v1, spi_v2, spi_v3))]
585 new_dma!(tx_dma), 780 new_dma!(tx_dma),
586 #[cfg(any(spi_v4, spi_v5, spi_v6))] 781 #[cfg(any(spi_v4, spi_v5, spi_v6))]
@@ -603,12 +798,37 @@ impl<'d> Spi<'d, Async> {
603 new_pin!(sck, config.sck_af()), 798 new_pin!(sck, config.sck_af()),
604 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 799 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
605 None, 800 None,
801 None,
606 new_dma!(tx_dma), 802 new_dma!(tx_dma),
607 None, 803 None,
608 config, 804 config,
609 ) 805 )
610 } 806 }
611 807
808 /// Create a new SPI driver, in bidirectional mode, specifically in tranmit mode
809 #[cfg(any(spi_v1, spi_v2, spi_v3))]
810 pub fn new_bidi<T: Instance, #[cfg(afio)] A>(
811 peri: Peri<'d, T>,
812 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
813 sdio: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
814 tx_dma: Peri<'d, impl TxDma<T>>,
815 rx_dma: Peri<'d, impl RxDma<T>>,
816 config: Config,
817 ) -> Self {
818 let mut this = Self::new_inner(
819 peri,
820 new_pin!(sck, config.sck_af()),
821 new_pin!(sdio, AfType::output(OutputType::PushPull, config.gpio_speed)),
822 None,
823 None,
824 new_dma!(tx_dma),
825 new_dma!(rx_dma),
826 config,
827 );
828 this.set_direction(Some(Direction::Transmit));
829 this
830 }
831
612 /// Create a new SPI driver, in TX-only mode, without SCK pin. 832 /// Create a new SPI driver, in TX-only mode, without SCK pin.
613 /// 833 ///
614 /// This can be useful for bit-banging non-SPI protocols. 834 /// This can be useful for bit-banging non-SPI protocols.
@@ -623,6 +843,7 @@ impl<'d> Spi<'d, Async> {
623 None, 843 None,
624 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 844 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
625 None, 845 None,
846 None,
626 new_dma!(tx_dma), 847 new_dma!(tx_dma),
627 None, 848 None,
628 config, 849 config,
@@ -646,7 +867,7 @@ impl<'d> Spi<'d, Async> {
646 config.bit_order = BitOrder::MsbFirst; 867 config.bit_order = BitOrder::MsbFirst;
647 config.frequency = freq; 868 config.frequency = freq;
648 869
649 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 870 Self::new_inner(peri, None, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
650 } 871 }
651 872
652 #[allow(dead_code)] 873 #[allow(dead_code)]
@@ -656,11 +877,14 @@ impl<'d> Spi<'d, Async> {
656 rx_dma: Option<ChannelAndRequest<'d>>, 877 rx_dma: Option<ChannelAndRequest<'d>>,
657 config: Config, 878 config: Config,
658 ) -> Self { 879 ) -> Self {
659 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config) 880 Self::new_inner(peri, None, None, None, None, tx_dma, rx_dma, config)
660 } 881 }
882}
661 883
884impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> {
662 /// SPI write, using DMA. 885 /// SPI write, using DMA.
663 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { 886 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
887 let _scoped_block_stop = self.info.rcc.block_stop();
664 if data.is_empty() { 888 if data.is_empty() {
665 return Ok(()); 889 return Ok(());
666 } 890 }
@@ -692,6 +916,7 @@ impl<'d> Spi<'d, Async> {
692 /// SPI read, using DMA. 916 /// SPI read, using DMA.
693 #[cfg(any(spi_v4, spi_v5, spi_v6))] 917 #[cfg(any(spi_v4, spi_v5, spi_v6))]
694 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 918 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
919 let _scoped_block_stop = self.info.rcc.block_stop();
695 if data.is_empty() { 920 if data.is_empty() {
696 return Ok(()); 921 return Ok(());
697 } 922 }
@@ -779,6 +1004,7 @@ impl<'d> Spi<'d, Async> {
779 /// SPI read, using DMA. 1004 /// SPI read, using DMA.
780 #[cfg(any(spi_v1, spi_v2, spi_v3))] 1005 #[cfg(any(spi_v1, spi_v2, spi_v3))]
781 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 1006 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
1007 let _scoped_block_stop = self.info.rcc.block_stop();
782 if data.is_empty() { 1008 if data.is_empty() {
783 return Ok(()); 1009 return Ok(());
784 } 1010 }
@@ -826,6 +1052,7 @@ impl<'d> Spi<'d, Async> {
826 } 1052 }
827 1053
828 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> { 1054 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> {
1055 let _scoped_block_stop = self.info.rcc.block_stop();
829 assert_eq!(read.len(), write.len()); 1056 assert_eq!(read.len(), write.len());
830 if read.len() == 0 { 1057 if read.len() == 0 {
831 return Ok(()); 1058 return Ok(());
@@ -877,6 +1104,8 @@ impl<'d> Spi<'d, Async> {
877 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. 1104 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
878 /// If `write` is shorter it is padded with zero bytes. 1105 /// If `write` is shorter it is padded with zero bytes.
879 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 1106 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
1107 let _scoped_block_stop = self.info.rcc.block_stop();
1108
880 self.transfer_inner(read, write).await 1109 self.transfer_inner(read, write).await
881 } 1110 }
882 1111
@@ -884,17 +1113,20 @@ impl<'d> Spi<'d, Async> {
884 /// 1113 ///
885 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. 1114 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
886 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 1115 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
1116 let _scoped_block_stop = self.info.rcc.block_stop();
1117
887 self.transfer_inner(data, data).await 1118 self.transfer_inner(data, data).await
888 } 1119 }
889} 1120}
890 1121
891impl<'d, M: PeriMode> Drop for Spi<'d, M> { 1122impl<'d, M: PeriMode, CM: CommunicationMode> Drop for Spi<'d, M, CM> {
892 fn drop(&mut self) { 1123 fn drop(&mut self) {
893 self.sck.as_ref().map(|x| x.set_as_disconnected()); 1124 self.sck.as_ref().map(|x| x.set_as_disconnected());
894 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 1125 self.mosi.as_ref().map(|x| x.set_as_disconnected());
895 self.miso.as_ref().map(|x| x.set_as_disconnected()); 1126 self.miso.as_ref().map(|x| x.set_as_disconnected());
1127 self.nss.as_ref().map(|x| x.set_as_disconnected());
896 1128
897 self.info.rcc.disable(); 1129 self.info.rcc.disable_without_stop();
898 } 1130 }
899} 1131}
900 1132
@@ -1127,7 +1359,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 1359// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
1128macro_rules! impl_blocking { 1360macro_rules! impl_blocking {
1129 ($w:ident) => { 1361 ($w:ident) => {
1130 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> { 1362 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M, CM> {
1131 type Error = Error; 1363 type Error = Error;
1132 1364
1133 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 1365 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -1135,7 +1367,7 @@ macro_rules! impl_blocking {
1135 } 1367 }
1136 } 1368 }
1137 1369
1138 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> { 1370 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M, CM> {
1139 type Error = Error; 1371 type Error = Error;
1140 1372
1141 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 1373 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -1149,11 +1381,11 @@ macro_rules! impl_blocking {
1149impl_blocking!(u8); 1381impl_blocking!(u8);
1150impl_blocking!(u16); 1382impl_blocking!(u16);
1151 1383
1152impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { 1384impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::ErrorType for Spi<'d, M, CM> {
1153 type Error = Error; 1385 type Error = Error;
1154} 1386}
1155 1387
1156impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> { 1388impl<'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> { 1389 fn flush(&mut self) -> Result<(), Self::Error> {
1158 Ok(()) 1390 Ok(())
1159 } 1391 }
@@ -1186,7 +1418,7 @@ impl embedded_hal_1::spi::Error for Error {
1186 } 1418 }
1187} 1419}
1188 1420
1189impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> { 1421impl<'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> { 1422 async fn flush(&mut self) -> Result<(), Self::Error> {
1191 Ok(()) 1423 Ok(())
1192 } 1424 }
@@ -1328,7 +1560,7 @@ foreach_peripheral!(
1328 }; 1560 };
1329); 1561);
1330 1562
1331impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { 1563impl<'d, M: PeriMode, CM: CommunicationMode> SetConfig for Spi<'d, M, CM> {
1332 type Config = Config; 1564 type Config = Config;
1333 type ConfigError = (); 1565 type ConfigError = ();
1334 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1566 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index 532877f70..88a28ee3d 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -4,7 +4,7 @@ use core::fmt::Display;
4use core::ops::{Div, Mul}; 4use core::ops::{Div, Mul};
5 5
6/// Hertz 6/// Hertz
7#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] 7#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default)]
8pub struct Hertz(pub u32); 8pub struct Hertz(pub u32);
9 9
10impl Display for Hertz { 10impl Display for Hertz {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 7db74bdf6..ed5d902bd 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -1,22 +1,24 @@
1#![allow(non_snake_case)] 1#![allow(non_snake_case)]
2 2
3use core::cell::{Cell, RefCell}; 3use core::cell::{Cell, RefCell};
4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 4#[cfg(all(feature = "low-power", stm32wlex))]
5use core::sync::atomic::AtomicU16;
6use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
5 7
6use critical_section::CriticalSection; 8use critical_section::CriticalSection;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::blocking_mutex::Mutex; 9use embassy_sync::blocking_mutex::Mutex;
10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_time_driver::{Driver, TICK_HZ}; 11use embassy_time_driver::{Driver, TICK_HZ};
10use embassy_time_queue_utils::Queue; 12use embassy_time_queue_utils::Queue;
11use stm32_metapac::timer::{regs, TimGp16}; 13use stm32_metapac::timer::{TimGp16, regs};
12 14
13use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
14use crate::pac::timer::vals; 16use crate::pac::timer::vals;
17use crate::peripherals;
15use crate::rcc::{self, SealedRccPeripheral}; 18use crate::rcc::{self, SealedRccPeripheral};
16#[cfg(feature = "low-power")] 19#[cfg(feature = "low-power")]
17use crate::rtc::Rtc; 20use crate::rtc::Rtc;
18use crate::timer::{CoreInstance, GeneralInstance1Channel}; 21use crate::timer::{CoreInstance, GeneralInstance1Channel};
19use crate::{interrupt, peripherals};
20 22
21// NOTE regarding ALARM_COUNT: 23// NOTE regarding ALARM_COUNT:
22// 24//
@@ -54,121 +56,6 @@ type T = peripherals::TIM23;
54#[cfg(time_driver_tim24)] 56#[cfg(time_driver_tim24)]
55type T = peripherals::TIM24; 57type T = peripherals::TIM24;
56 58
57foreach_interrupt! {
58 (TIM1, timer, $block:ident, CC, $irq:ident) => {
59 #[cfg(time_driver_tim1)]
60 #[cfg(feature = "rt")]
61 #[interrupt]
62 fn $irq() {
63 DRIVER.on_interrupt()
64 }
65 };
66 (TIM2, timer, $block:ident, CC, $irq:ident) => {
67 #[cfg(time_driver_tim2)]
68 #[cfg(feature = "rt")]
69 #[interrupt]
70 fn $irq() {
71 DRIVER.on_interrupt()
72 }
73 };
74 (TIM3, timer, $block:ident, CC, $irq:ident) => {
75 #[cfg(time_driver_tim3)]
76 #[cfg(feature = "rt")]
77 #[interrupt]
78 fn $irq() {
79 DRIVER.on_interrupt()
80 }
81 };
82 (TIM4, timer, $block:ident, CC, $irq:ident) => {
83 #[cfg(time_driver_tim4)]
84 #[cfg(feature = "rt")]
85 #[interrupt]
86 fn $irq() {
87 DRIVER.on_interrupt()
88 }
89 };
90 (TIM5, timer, $block:ident, CC, $irq:ident) => {
91 #[cfg(time_driver_tim5)]
92 #[cfg(feature = "rt")]
93 #[interrupt]
94 fn $irq() {
95 DRIVER.on_interrupt()
96 }
97 };
98 (TIM8, timer, $block:ident, CC, $irq:ident) => {
99 #[cfg(time_driver_tim8)]
100 #[cfg(feature = "rt")]
101 #[interrupt]
102 fn $irq() {
103 DRIVER.on_interrupt()
104 }
105 };
106 (TIM9, timer, $block:ident, CC, $irq:ident) => {
107 #[cfg(time_driver_tim9)]
108 #[cfg(feature = "rt")]
109 #[interrupt]
110 fn $irq() {
111 DRIVER.on_interrupt()
112 }
113 };
114 (TIM12, timer, $block:ident, CC, $irq:ident) => {
115 #[cfg(time_driver_tim12)]
116 #[cfg(feature = "rt")]
117 #[interrupt]
118 fn $irq() {
119 DRIVER.on_interrupt()
120 }
121 };
122 (TIM15, timer, $block:ident, CC, $irq:ident) => {
123 #[cfg(time_driver_tim15)]
124 #[cfg(feature = "rt")]
125 #[interrupt]
126 fn $irq() {
127 DRIVER.on_interrupt()
128 }
129 };
130 (TIM20, timer, $block:ident, CC, $irq:ident) => {
131 #[cfg(time_driver_tim20)]
132 #[cfg(feature = "rt")]
133 #[interrupt]
134 fn $irq() {
135 DRIVER.on_interrupt()
136 }
137 };
138 (TIM21, timer, $block:ident, CC, $irq:ident) => {
139 #[cfg(time_driver_tim21)]
140 #[cfg(feature = "rt")]
141 #[interrupt]
142 fn $irq() {
143 DRIVER.on_interrupt()
144 }
145 };
146 (TIM22, timer, $block:ident, CC, $irq:ident) => {
147 #[cfg(time_driver_tim22)]
148 #[cfg(feature = "rt")]
149 #[interrupt]
150 fn $irq() {
151 DRIVER.on_interrupt()
152 }
153 };
154 (TIM23, timer, $block:ident, CC, $irq:ident) => {
155 #[cfg(time_driver_tim23)]
156 #[cfg(feature = "rt")]
157 #[interrupt]
158 fn $irq() {
159 DRIVER.on_interrupt()
160 }
161 };
162 (TIM24, timer, $block:ident, CC, $irq:ident) => {
163 #[cfg(time_driver_tim24)]
164 #[cfg(feature = "rt")]
165 #[interrupt]
166 fn $irq() {
167 DRIVER.on_interrupt()
168 }
169 };
170}
171
172fn regs_gp16() -> TimGp16 { 59fn regs_gp16() -> TimGp16 {
173 unsafe { TimGp16::from_ptr(T::regs()) } 60 unsafe { TimGp16::from_ptr(T::regs()) }
174} 61}
@@ -194,6 +81,11 @@ fn calc_now(period: u32, counter: u16) -> u64 {
194 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) 81 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
195} 82}
196 83
84#[cfg(feature = "low-power")]
85fn calc_period_counter(ticks: u64) -> (u32, u16) {
86 (2 * (ticks >> 16) as u32 + (ticks as u16 >= 0x8000) as u32, ticks as u16)
87}
88
197struct AlarmState { 89struct AlarmState {
198 timestamp: Cell<u64>, 90 timestamp: Cell<u64>,
199} 91}
@@ -213,7 +105,13 @@ pub(crate) struct RtcDriver {
213 period: AtomicU32, 105 period: AtomicU32,
214 alarm: Mutex<CriticalSectionRawMutex, AlarmState>, 106 alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
215 #[cfg(feature = "low-power")] 107 #[cfg(feature = "low-power")]
216 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, 108 pub(crate) rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
109 #[cfg(feature = "low-power")]
110 /// The minimum pause time beyond which the executor will enter a low-power state.
111 min_stop_pause: Mutex<CriticalSectionRawMutex, Cell<embassy_time::Duration>>,
112 /// Saved count for the timer (its value is lost when entering STOP2)
113 #[cfg(all(feature = "low-power", stm32wlex))]
114 saved_count: AtomicU16,
217 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, 115 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
218} 116}
219 117
@@ -221,12 +119,18 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
221 period: AtomicU32::new(0), 119 period: AtomicU32::new(0),
222 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), 120 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
223 #[cfg(feature = "low-power")] 121 #[cfg(feature = "low-power")]
224 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 122 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)),
123 #[cfg(feature = "low-power")]
124 min_stop_pause: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(embassy_time::Duration::from_millis(0))),
125 #[cfg(all(feature = "low-power", stm32wlex))]
126 saved_count: AtomicU16::new(0),
225 queue: Mutex::new(RefCell::new(Queue::new())) 127 queue: Mutex::new(RefCell::new(Queue::new()))
226}); 128});
227 129
228impl RtcDriver { 130impl RtcDriver {
229 fn init(&'static self, cs: critical_section::CriticalSection) { 131 /// initialize the timer, but don't start it. Used for chips like stm32wle5
132 /// for low power where the timer config is lost in STOP2.
133 pub(crate) fn init_timer(&'static self, cs: critical_section::CriticalSection) {
230 let r = regs_gp16(); 134 let r = regs_gp16();
231 135
232 rcc::enable_and_reset_with_cs::<T>(cs); 136 rcc::enable_and_reset_with_cs::<T>(cs);
@@ -259,13 +163,23 @@ impl RtcDriver {
259 w.set_ccie(0, true); 163 w.set_ccie(0, true);
260 }); 164 });
261 165
166 #[cfg(all(feature = "low-power", stm32wlex))]
167 r.cnt().write(|w| w.set_cnt(self.saved_count.load(Ordering::SeqCst)));
168
262 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend(); 169 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend();
263 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() }; 170 <T as CoreInstance>::UpdateInterrupt::unpend();
171 unsafe {
172 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable();
173 <T as CoreInstance>::UpdateInterrupt::enable();
174 }
175 }
264 176
265 r.cr1().modify(|w| w.set_cen(true)); 177 fn init(&'static self, cs: CriticalSection) {
178 self.init_timer(cs);
179 regs_gp16().cr1().modify(|w| w.set_cen(true));
266 } 180 }
267 181
268 fn on_interrupt(&self) { 182 pub(crate) fn on_interrupt(&self) {
269 let r = regs_gp16(); 183 let r = regs_gp16();
270 184
271 critical_section::with(|cs| { 185 critical_section::with(|cs| {
@@ -338,34 +252,10 @@ impl RtcDriver {
338 #[cfg(feature = "low-power")] 252 #[cfg(feature = "low-power")]
339 /// Add the given offset to the current time 253 /// Add the given offset to the current time
340 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { 254 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
341 let offset = offset.as_ticks(); 255 let (period, counter) = calc_period_counter(self.now() + offset.as_ticks());
342 let cnt = regs_gp16().cnt().read().cnt() as u32;
343 let period = self.period.load(Ordering::SeqCst);
344
345 // Correct the race, if it exists
346 let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 {
347 period + 1
348 } else {
349 period
350 };
351
352 // Normalize to the full overflow
353 let period = (period / 2) * 2;
354
355 // Add the offset
356 let period = period + 2 * (offset / u16::MAX as u64) as u32;
357 let cnt = cnt + (offset % u16::MAX as u64) as u32;
358
359 let (cnt, period) = if cnt > u16::MAX as u32 {
360 (cnt - u16::MAX as u32, period + 2)
361 } else {
362 (cnt, period)
363 };
364
365 let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period };
366 256
367 self.period.store(period, Ordering::SeqCst); 257 self.period.store(period, Ordering::SeqCst);
368 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); 258 regs_gp16().cnt().write(|w| w.set_cnt(counter));
369 259
370 // Now, recompute alarm 260 // Now, recompute alarm
371 let alarm = self.alarm.borrow(cs); 261 let alarm = self.alarm.borrow(cs);
@@ -379,70 +269,70 @@ impl RtcDriver {
379 #[cfg(feature = "low-power")] 269 #[cfg(feature = "low-power")]
380 /// Stop the wakeup alarm, if enabled, and add the appropriate offset 270 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
381 fn stop_wakeup_alarm(&self, cs: CriticalSection) { 271 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
382 if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) { 272 if !regs_gp16().cr1().read().cen()
273 && let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs)
274 {
383 self.add_time(offset, cs); 275 self.add_time(offset, cs);
384 } 276 }
385 } 277 }
386 278
387 /* 279 /*
388 Low-power public functions: all create a critical section 280 Low-power public functions: all require a critical section
389 */ 281 */
390 #[cfg(feature = "low-power")] 282 #[cfg(feature = "low-power")]
391 /// Set the rtc but panic if it's already been set 283 pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) {
392 pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { 284 self.min_stop_pause.borrow(cs).replace(min_stop_pause);
393 critical_section::with(|cs| {
394 rtc.stop_wakeup_alarm(cs);
395
396 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())
397 });
398 } 285 }
399 286
400 #[cfg(feature = "low-power")] 287 #[cfg(feature = "low-power")]
401 /// The minimum pause time beyond which the executor will enter a low-power state. 288 /// Set the rtc but panic if it's already been set
402 pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250); 289 pub(crate) fn set_rtc(&self, cs: CriticalSection, mut rtc: Rtc) {
290 rtc.stop_wakeup_alarm(cs);
291
292 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none());
293 }
403 294
404 #[cfg(feature = "low-power")] 295 #[cfg(feature = "low-power")]
405 /// Pause the timer if ready; return err if not 296 /// Pause the timer if ready; return err if not
406 pub(crate) fn pause_time(&self) -> Result<(), ()> { 297 pub(crate) fn pause_time(&self, cs: CriticalSection) -> Result<(), ()> {
407 critical_section::with(|cs| { 298 self.stop_wakeup_alarm(cs);
408 /* 299
409 If the wakeup timer is currently running, then we need to stop it and 300 let time_until_next_alarm = self.time_until_next_alarm(cs);
410 add the elapsed time to the current time, as this will impact the result 301 if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() {
411 of `time_until_next_alarm`. 302 trace!(
412 */ 303 "time_until_next_alarm < self.min_stop_pause ({})",
413 self.stop_wakeup_alarm(cs); 304 time_until_next_alarm
414 305 );
415 let time_until_next_alarm = self.time_until_next_alarm(cs); 306 Err(())
416 if time_until_next_alarm < Self::MIN_STOP_PAUSE { 307 } else {
417 Err(()) 308 self.rtc
418 } else { 309 .borrow(cs)
419 self.rtc 310 .borrow_mut()
420 .borrow(cs) 311 .as_mut()
421 .get() 312 .unwrap()
422 .unwrap() 313 .start_wakeup_alarm(time_until_next_alarm, cs);
423 .start_wakeup_alarm(time_until_next_alarm, cs); 314
424 315 regs_gp16().cr1().modify(|w| w.set_cen(false));
425 regs_gp16().cr1().modify(|w| w.set_cen(false)); 316 // save the count for the timer as its lost in STOP2 for stm32wlex
426 317 #[cfg(stm32wlex)]
427 Ok(()) 318 self.saved_count
428 } 319 .store(regs_gp16().cnt().read().cnt() as u16, Ordering::SeqCst);
429 }) 320 Ok(())
321 }
430 } 322 }
431 323
432 #[cfg(feature = "low-power")] 324 #[cfg(feature = "low-power")]
433 /// Resume the timer with the given offset 325 /// Resume the timer with the given offset
434 pub(crate) fn resume_time(&self) { 326 pub(crate) fn resume_time(&self, cs: CriticalSection) {
435 if regs_gp16().cr1().read().cen() { 327 self.stop_wakeup_alarm(cs);
436 // Time isn't currently stopped
437 328
438 return; 329 regs_gp16().cr1().modify(|w| w.set_cen(true));
439 } 330 }
440
441 critical_section::with(|cs| {
442 self.stop_wakeup_alarm(cs);
443 331
444 regs_gp16().cr1().modify(|w| w.set_cen(true)); 332 #[cfg(feature = "low-power")]
445 }) 333 /// Returns whether time is currently stopped
334 pub(crate) fn is_stopped(&self) -> bool {
335 !regs_gp16().cr1().read().cen()
446 } 336 }
447 337
448 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { 338 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
@@ -513,8 +403,7 @@ impl Driver for RtcDriver {
513 } 403 }
514} 404}
515 405
516#[cfg(feature = "low-power")] 406pub(crate) const fn get_driver() -> &'static RtcDriver {
517pub(crate) fn get_driver() -> &'static RtcDriver {
518 &DRIVER 407 &DRIVER
519} 408}
520 409
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 484aae1d0..620d7858e 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -2,16 +2,17 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr};
6
7use super::low_level::{CountingMode, OutputPolarity, Timer}; 5use super::low_level::{CountingMode, OutputPolarity, Timer};
8use super::simple_pwm::PwmPin; 6use super::simple_pwm::PwmPin;
9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; 7use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin};
10use crate::gpio::{AnyPin, OutputType}; 8use crate::Peri;
9use crate::dma::word::Word;
10use crate::gpio::{AfType, AnyPin, OutputType};
11pub use crate::pac::timer::vals::{Ccds, Ckd, Mms2, Ossi, Ossr};
11use crate::time::Hertz; 12use crate::time::Hertz;
12use crate::timer::low_level::OutputCompareMode;
13use crate::timer::TimerChannel; 13use crate::timer::TimerChannel;
14use crate::Peri; 14use crate::timer::low_level::OutputCompareMode;
15use crate::timer::simple_pwm::PwmPinConfig;
15 16
16/// Complementary PWM pin wrapper. 17/// Complementary PWM pin wrapper.
17/// 18///
@@ -27,9 +28,27 @@ impl<'d, T: AdvancedInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!(
27 pub fn new(pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>, output_type: OutputType) -> Self { 28 pub fn new(pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>, output_type: OutputType) -> Self {
28 critical_section::with(|_| { 29 critical_section::with(|_| {
29 pin.set_low(); 30 pin.set_low();
30 set_as_af!( 31 set_as_af!(pin, AfType::output(output_type, crate::gpio::Speed::VeryHigh));
31 pin, 32 });
32 crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh) 33 ComplementaryPwmPin {
34 pin: pin.into(),
35 phantom: PhantomData,
36 }
37 }
38
39 /// Create a new PWM pin instance with config.
40 pub fn new_with_config(
41 pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>,
42 pin_config: PwmPinConfig,
43 ) -> Self {
44 critical_section::with(|_| {
45 pin.set_low();
46 #[cfg(gpio_v1)]
47 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
48 #[cfg(gpio_v2)]
49 pin.set_as_af(
50 pin.af_num(),
51 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
33 ); 52 );
34 }); 53 });
35 ComplementaryPwmPin { 54 ComplementaryPwmPin {
@@ -77,8 +96,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
77 96
78 this.inner.set_counting_mode(counting_mode); 97 this.inner.set_counting_mode(counting_mode);
79 this.set_frequency(freq); 98 this.set_frequency(freq);
80 this.inner.start();
81
82 this.inner.enable_outputs(); 99 this.inner.enable_outputs();
83 100
84 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 101 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
@@ -89,6 +106,10 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
89 }); 106 });
90 this.inner.set_autoreload_preload(true); 107 this.inner.set_autoreload_preload(true);
91 108
109 // Generate update event so pre-load registers are written to the shadow registers
110 this.inner.generate_update_event();
111 this.inner.start();
112
92 this 113 this
93 } 114 }
94 115
@@ -136,6 +157,16 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
136 self.inner.get_moe() 157 self.inner.get_moe()
137 } 158 }
138 159
160 /// Set Master Slave Mode 2
161 pub fn set_mms2(&mut self, mms2: Mms2) {
162 self.inner.set_mms2_selection(mms2);
163 }
164
165 /// Set Repetition Counter
166 pub fn set_repetition_counter(&mut self, val: u16) {
167 self.inner.set_repetition_counter(val);
168 }
169
139 /// Enable the given channel. 170 /// Enable the given channel.
140 pub fn enable(&mut self, channel: Channel) { 171 pub fn enable(&mut self, channel: Channel) {
141 self.inner.enable_channel(channel, true); 172 self.inner.enable_channel(channel, true);
@@ -150,8 +181,8 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
150 181
151 /// Set PWM frequency. 182 /// Set PWM frequency.
152 /// 183 ///
153 /// Note: when you call this, the max duty value changes, so you will have to 184 /// Note: that the frequency will not be applied in the timer until an update event
154 /// call `set_duty` on all channels with the duty calculated based on the new max duty. 185 /// occurs.
155 pub fn set_frequency(&mut self, freq: Hertz) { 186 pub fn set_frequency(&mut self, freq: Hertz) {
156 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 187 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
157 2u8 188 2u8
@@ -164,20 +195,20 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
164 /// Get max duty value. 195 /// Get max duty value.
165 /// 196 ///
166 /// This value depends on the configured frequency and the timer's clock rate from RCC. 197 /// This value depends on the configured frequency and the timer's clock rate from RCC.
167 pub fn get_max_duty(&self) -> u16 { 198 pub fn get_max_duty(&self) -> u32 {
168 if self.inner.get_counting_mode().is_center_aligned() { 199 if self.inner.get_counting_mode().is_center_aligned() {
169 self.inner.get_max_compare_value() as u16 200 self.inner.get_max_compare_value().into()
170 } else { 201 } else {
171 self.inner.get_max_compare_value() as u16 + 1 202 self.inner.get_max_compare_value().into() + 1
172 } 203 }
173 } 204 }
174 205
175 /// Set the duty for a given channel. 206 /// Set the duty for a given channel.
176 /// 207 ///
177 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. 208 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
178 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 209 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
179 assert!(duty <= self.get_max_duty()); 210 assert!(duty <= self.get_max_duty());
180 self.inner.set_compare_value(channel, duty as _) 211 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
181 } 212 }
182 213
183 /// Set the output polarity for a given channel. 214 /// Set the output polarity for a given channel.
@@ -207,61 +238,88 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
207 /// Generate a sequence of PWM waveform 238 /// Generate a sequence of PWM waveform
208 /// 239 ///
209 /// Note: 240 /// Note:
210 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 241 /// The DMA channel provided does not need to correspond to the requested channel.
211 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 242 pub async fn waveform<C: TimerChannel, W: Word + Into<T::Word>>(
212 #[allow(clippy::let_unit_value)] // eg. stm32f334 243 &mut self,
213 let req = dma.request(); 244 dma: Peri<'_, impl super::Dma<T, C>>,
214 245 channel: Channel,
215 let original_duty_state = self.inner.get_compare_value(channel); 246 duty: &[W],
216 let original_enable_state = self.inner.get_channel_enable_state(channel); 247 ) {
217 let original_update_dma_state = self.inner.get_update_dma_state(); 248 self.inner.enable_channel(channel, true);
218 249 self.inner.enable_channel(C::CHANNEL, true);
219 if !original_update_dma_state { 250 self.inner.clamp_compare_value::<W>(channel);
220 self.inner.enable_update_dma(true); 251 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE);
221 } 252 self.inner.set_cc_dma_enable_state(C::CHANNEL, true);
222 253 self.inner.setup_channel_update_dma(dma, channel, duty).await;
223 if !original_enable_state { 254 self.inner.set_cc_dma_enable_state(C::CHANNEL, false);
224 self.inner.enable_channel(channel, true); 255 }
225 }
226
227 unsafe {
228 #[cfg(not(any(bdma, gpdma)))]
229 use crate::dma::{Burst, FifoThreshold};
230 use crate::dma::{Transfer, TransferOptions};
231
232 let dma_transfer_option = TransferOptions {
233 #[cfg(not(any(bdma, gpdma)))]
234 fifo_threshold: Some(FifoThreshold::Full),
235 #[cfg(not(any(bdma, gpdma)))]
236 mburst: Burst::Incr8,
237 ..Default::default()
238 };
239
240 Transfer::new_write(
241 dma,
242 req,
243 duty,
244 self.inner.regs_gp16().ccr(channel.index()).as_ptr() as *mut u16,
245 dma_transfer_option,
246 )
247 .await
248 };
249
250 // restore output compare state
251 if !original_enable_state {
252 self.inner.enable_channel(channel, false);
253 }
254 256
255 self.inner.set_compare_value(channel, original_duty_state); 257 /// Generate a sequence of PWM waveform
258 ///
259 /// Note:
260 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
261 pub async fn waveform_up<W: Word + Into<T::Word>>(
262 &mut self,
263 dma: Peri<'_, impl super::UpDma<T>>,
264 channel: Channel,
265 duty: &[W],
266 ) {
267 self.inner.enable_channel(channel, true);
268 self.inner.clamp_compare_value::<W>(channel);
269 self.inner.enable_update_dma(true);
270 self.inner.setup_update_dma(dma, channel, duty).await;
271 self.inner.enable_update_dma(false);
272 }
256 273
257 // Since DMA is closed before timer update event trigger DMA is turn off, 274 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
258 // this can almost always trigger a DMA FIFO error. 275 ///
259 // 276 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
260 // optional TODO: 277 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
261 // clean FEIF after disable UDE 278 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
262 if !original_update_dma_state { 279 ///
263 self.inner.enable_update_dma(false); 280 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
264 } 281 /// represents a single update event and each column corresponds to a specific timer channel (starting
282 /// from `starting_channel` up to and including `ending_channel`).
283 ///
284 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
285 ///
286 /// ```rust,ignore
287 /// let dma_buf: [u16; 16] = [
288 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
289 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
290 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
291 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
292 /// ];
293 /// ```
294 ///
295 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
296 /// updating the duty cycles of all selected channels simultaneously.
297 ///
298 /// Note:
299 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
300 /// Also be aware that embassy timers use one of timers internally. It is possible to
301 /// switch this timer by using `time-driver-timX` feature.
302 ///
303 pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>(
304 &mut self,
305 dma: Peri<'_, impl super::UpDma<T>>,
306 starting_channel: Channel,
307 ending_channel: Channel,
308 duty: &[W],
309 ) {
310 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
311 .iter()
312 .filter(|ch| ch.index() >= starting_channel.index())
313 .filter(|ch| ch.index() <= ending_channel.index())
314 .for_each(|ch| {
315 self.inner.enable_channel(*ch, true);
316 self.inner.clamp_compare_value::<W>(*ch);
317 });
318 self.inner.enable_update_dma(true);
319 self.inner
320 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
321 .await;
322 self.inner.enable_update_dma(false);
265 } 323 }
266} 324}
267 325
@@ -285,20 +343,20 @@ impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<
285 } 343 }
286 344
287 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 345 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
288 self.inner.get_compare_value(channel) as u16 346 unwrap!(self.inner.get_compare_value(channel).try_into())
289 } 347 }
290 348
291 fn get_max_duty(&self) -> Self::Duty { 349 fn get_max_duty(&self) -> Self::Duty {
292 if self.inner.get_counting_mode().is_center_aligned() { 350 if self.inner.get_counting_mode().is_center_aligned() {
293 self.inner.get_max_compare_value() as u16 351 unwrap!(self.inner.get_max_compare_value().try_into())
294 } else { 352 } else {
295 self.inner.get_max_compare_value() as u16 + 1 353 unwrap!(self.inner.get_max_compare_value().try_into()) + 1
296 } 354 }
297 } 355 }
298 356
299 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 357 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
300 assert!(duty <= self.get_max_duty()); 358 assert!(duty <= unwrap!(self.get_max_duty().try_into()));
301 self.inner.set_compare_value(channel, duty as u32) 359 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
302 } 360 }
303 361
304 fn set_period<P>(&mut self, period: P) 362 fn set_period<P>(&mut self, period: P)
@@ -388,7 +446,7 @@ fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
388 446
389#[cfg(test)] 447#[cfg(test)]
390mod tests { 448mod tests {
391 use super::{compute_dead_time_value, Ckd}; 449 use super::{Ckd, compute_dead_time_value};
392 450
393 #[test] 451 #[test]
394 fn test_compute_dead_time_value() { 452 fn test_compute_dead_time_value() {
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index e6739fbc1..905f2de1a 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -8,11 +8,11 @@ use core::task::{Context, Poll};
8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; 8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
9use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin}; 9use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin};
10pub use super::{Ch1, Ch2, Ch3, Ch4}; 10pub use super::{Ch1, Ch2, Ch3, Ch4};
11use crate::Peri;
11use crate::gpio::{AfType, AnyPin, Pull}; 12use crate::gpio::{AfType, AnyPin, Pull};
12use crate::interrupt::typelevel::{Binding, Interrupt}; 13use crate::interrupt::typelevel::{Binding, Interrupt};
13use crate::time::Hertz; 14use crate::time::Hertz;
14use crate::timer::TimerChannel; 15use crate::timer::TimerChannel;
15use crate::Peri;
16 16
17/// Capture pin wrapper. 17/// Capture pin wrapper.
18/// 18///
@@ -60,6 +60,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
60 this.inner.set_counting_mode(counting_mode); 60 this.inner.set_counting_mode(counting_mode);
61 this.inner.set_tick_freq(freq); 61 this.inner.set_tick_freq(freq);
62 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 62 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
63 this.inner.generate_update_event();
63 this.inner.start(); 64 this.inner.start();
64 65
65 // enable NVIC interrupt 66 // enable NVIC interrupt
@@ -96,7 +97,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
96 97
97 /// Get capture value for a channel. 98 /// Get capture value for a channel.
98 pub fn get_capture_value(&self, channel: Channel) -> u32 { 99 pub fn get_capture_value(&self, channel: Channel) -> u32 {
99 self.inner.get_capture_value(channel) 100 self.inner.get_capture_value(channel).into()
100 } 101 }
101 102
102 /// Get input interrupt. 103 /// Get input interrupt.
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index ac039bb0d..82e936f3a 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -10,9 +10,10 @@ use core::mem::ManuallyDrop;
10 10
11use embassy_hal_internal::Peri; 11use embassy_hal_internal::Peri;
12// Re-export useful enums 12// Re-export useful enums
13pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource}; 13pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource};
14 14
15use super::*; 15use super::*;
16use crate::dma::{self, Transfer, WritableRingBuffer};
16use crate::pac::timer::vals; 17use crate::pac::timer::vals;
17use crate::rcc; 18use crate::rcc;
18use crate::time::Hertz; 19use crate::time::Hertz;
@@ -143,20 +144,69 @@ pub enum OutputCompareMode {
143 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as 144 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
144 /// TIMx_CNT>TIMx_CCRx else inactive. 145 /// TIMx_CNT>TIMx_CCRx else inactive.
145 PwmMode2, 146 PwmMode2,
146 // TODO: there's more modes here depending on the chip family. 147
148 #[cfg(timer_v2)]
149 /// In up-counting mode, the channel is active until a trigger
150 /// event is detected (on tim_trgi signal). Then, a comparison is performed as in PWM
151 /// mode 1 and the channels becomes active again at the next update. In down-counting
152 /// mode, the channel is inactive until a trigger event is detected (on tim_trgi signal).
153 /// Then, a comparison is performed as in PWM mode 1 and the channels becomes
154 /// inactive again at the next update.
155 OnePulseMode1,
156
157 #[cfg(timer_v2)]
158 /// In up-counting mode, the channel is inactive until a
159 /// trigger event is detected (on tim_trgi signal). Then, a comparison is performed as in
160 /// PWM mode 2 and the channels becomes inactive again at the next update. In down
161 /// counting mode, the channel is active until a trigger event is detected (on tim_trgi
162 /// signal). Then, a comparison is performed as in PWM mode 1 and the channels
163 /// becomes active again at the next update.
164 OnePulseMode2,
165
166 #[cfg(timer_v2)]
167 /// Combined PWM mode 1 - tim_oc1ref has the same behavior as in PWM mode 1.
168 /// tim_oc1refc is the logical OR between tim_oc1ref and tim_oc2ref.
169 CombinedPwmMode1,
170
171 #[cfg(timer_v2)]
172 /// Combined PWM mode 2 - tim_oc1ref has the same behavior as in PWM mode 2.
173 /// tim_oc1refc is the logical AND between tim_oc1ref and tim_oc2ref.
174 CombinedPwmMode2,
175
176 #[cfg(timer_v2)]
177 /// tim_oc1ref has the same behavior as in PWM mode 1. tim_oc1refc outputs tim_oc1ref
178 /// when the counter is counting up, tim_oc2ref when it is counting down.
179 AsymmetricPwmMode1,
180
181 #[cfg(timer_v2)]
182 /// tim_oc1ref has the same behavior as in PWM mode 2. tim_oc1refc outputs tim_oc1ref
183 /// when the counter is counting up, tim_oc2ref when it is counting down.
184 AsymmetricPwmMode2,
147} 185}
148 186
149impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 187impl From<OutputCompareMode> for crate::pac::timer::vals::Ocm {
150 fn from(mode: OutputCompareMode) -> Self { 188 fn from(mode: OutputCompareMode) -> Self {
151 match mode { 189 match mode {
152 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, 190 OutputCompareMode::Frozen => crate::pac::timer::vals::Ocm::FROZEN,
153 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH, 191 OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::Ocm::ACTIVE_ON_MATCH,
154 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH, 192 OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::Ocm::INACTIVE_ON_MATCH,
155 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, 193 OutputCompareMode::Toggle => crate::pac::timer::vals::Ocm::TOGGLE,
156 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE, 194 OutputCompareMode::ForceInactive => crate::pac::timer::vals::Ocm::FORCE_INACTIVE,
157 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE, 195 OutputCompareMode::ForceActive => crate::pac::timer::vals::Ocm::FORCE_ACTIVE,
158 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1, 196 OutputCompareMode::PwmMode1 => crate::pac::timer::vals::Ocm::PWM_MODE1,
159 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2, 197 OutputCompareMode::PwmMode2 => crate::pac::timer::vals::Ocm::PWM_MODE2,
198 #[cfg(timer_v2)]
199 OutputCompareMode::OnePulseMode1 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_1,
200 #[cfg(timer_v2)]
201 OutputCompareMode::OnePulseMode2 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_2,
202 #[cfg(timer_v2)]
203 OutputCompareMode::CombinedPwmMode1 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_1,
204 #[cfg(timer_v2)]
205 OutputCompareMode::CombinedPwmMode2 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_2,
206 #[cfg(timer_v2)]
207 OutputCompareMode::AsymmetricPwmMode1 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_1,
208 #[cfg(timer_v2)]
209 OutputCompareMode::AsymmetricPwmMode2 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_2,
160 } 210 }
161 } 211 }
162} 212}
@@ -218,11 +268,27 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
218 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } 268 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
219 } 269 }
220 270
271 #[cfg(stm32l0)]
272 fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp16 {
273 unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
274 }
275
221 /// Start the timer. 276 /// Start the timer.
222 pub fn start(&self) { 277 pub fn start(&self) {
223 self.regs_core().cr1().modify(|r| r.set_cen(true)); 278 self.regs_core().cr1().modify(|r| r.set_cen(true));
224 } 279 }
225 280
281 /// Generate timer update event from software.
282 ///
283 /// Set URS to avoid generating interrupt or DMA request. This update event is only
284 /// used to load value from pre-load registers. If called when the timer is running,
285 /// it may disrupt the output waveform.
286 pub fn generate_update_event(&self) {
287 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
288 self.regs_core().egr().write(|r| r.set_ug(true));
289 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
290 }
291
226 /// Stop the timer. 292 /// Stop the timer.
227 pub fn stop(&self) { 293 pub fn stop(&self) {
228 self.regs_core().cr1().modify(|r| r.set_cen(false)); 294 self.regs_core().cr1().modify(|r| r.set_cen(false));
@@ -235,7 +301,12 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
235 301
236 /// get the capability of the timer 302 /// get the capability of the timer
237 pub fn bits(&self) -> TimerBits { 303 pub fn bits(&self) -> TimerBits {
238 T::BITS 304 match T::Word::bits() {
305 16 => TimerBits::Bits16,
306 #[cfg(not(stm32l0))]
307 32 => TimerBits::Bits32,
308 _ => unreachable!(),
309 }
239 } 310 }
240 311
241 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. 312 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
@@ -245,18 +316,10 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
245 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved 316 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
246 /// because it needs to count up and down. 317 /// because it needs to count up and down.
247 pub fn set_frequency(&self, frequency: Hertz) { 318 pub fn set_frequency(&self, frequency: Hertz) {
248 match T::BITS { 319 self.set_frequency_internal(frequency, T::Word::bits());
249 TimerBits::Bits16 => {
250 self.set_frequency_internal(frequency, 16);
251 }
252 #[cfg(not(stm32l0))]
253 TimerBits::Bits32 => {
254 self.set_frequency_internal(frequency, 32);
255 }
256 }
257 } 320 }
258 321
259 pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) { 322 pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: usize) {
260 let f = frequency.0; 323 let f = frequency.0;
261 assert!(f > 0); 324 assert!(f > 0);
262 let timer_f = T::frequency().0; 325 let timer_f = T::frequency().0;
@@ -265,33 +328,15 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
265 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into()); 328 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into());
266 let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1); 329 let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
267 330
268 match T::BITS { 331 // the timer counts `0..=arr`, we want it to count `0..divide_by`
269 TimerBits::Bits16 => { 332 let arr: T::Word = unwrap!(T::Word::try_from(divide_by - 1));
270 // the timer counts `0..=arr`, we want it to count `0..divide_by`
271 let arr = unwrap!(u16::try_from(divide_by - 1));
272
273 let regs = self.regs_core();
274 regs.psc().write_value(psc);
275 regs.arr().write(|r| r.set_arr(arr));
276
277 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
278 regs.egr().write(|r| r.set_ug(true));
279 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
280 }
281 #[cfg(not(stm32l0))]
282 TimerBits::Bits32 => {
283 // the timer counts `0..=arr`, we want it to count `0..divide_by`
284 let arr: u32 = unwrap!(u32::try_from(divide_by - 1));
285
286 let regs = self.regs_gp32_unchecked();
287 regs.psc().write_value(psc);
288 regs.arr().write_value(arr);
289 333
290 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); 334 let regs = self.regs_gp32_unchecked();
291 regs.egr().write(|r| r.set_ug(true)); 335 regs.psc().write_value(psc);
292 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); 336 #[cfg(stm32l0)]
293 } 337 regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into())));
294 } 338 #[cfg(not(stm32l0))]
339 regs.arr().write_value(arr.into());
295 } 340 }
296 341
297 /// Set tick frequency. 342 /// Set tick frequency.
@@ -340,23 +385,14 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
340 pub fn get_frequency(&self) -> Hertz { 385 pub fn get_frequency(&self) -> Hertz {
341 let timer_f = T::frequency(); 386 let timer_f = T::frequency();
342 387
343 match T::BITS { 388 let regs = self.regs_gp32_unchecked();
344 TimerBits::Bits16 => { 389 #[cfg(not(stm32l0))]
345 let regs = self.regs_core(); 390 let arr = regs.arr().read();
346 let arr = regs.arr().read().arr(); 391 #[cfg(stm32l0)]
347 let psc = regs.psc().read(); 392 let arr = regs.arr().read().arr();
348 393 let psc = regs.psc().read();
349 timer_f / arr / (psc + 1)
350 }
351 #[cfg(not(stm32l0))]
352 TimerBits::Bits32 => {
353 let regs = self.regs_gp32_unchecked();
354 let arr = regs.arr().read();
355 let psc = regs.psc().read();
356 394
357 timer_f / arr / (psc + 1) 395 timer_f / arr / (psc + 1)
358 }
359 }
360 } 396 }
361 397
362 /// Get the clock frequency of the timer (before prescaler is applied). 398 /// Get the clock frequency of the timer (before prescaler is applied).
@@ -416,42 +452,29 @@ impl<'d, T: GeneralInstance1Channel> Timer<'d, T> {
416 } 452 }
417 453
418 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. 454 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
419 pub fn get_max_compare_value(&self) -> u32 { 455 pub fn get_max_compare_value(&self) -> T::Word {
420 match T::BITS { 456 #[cfg(not(stm32l0))]
421 TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32, 457 return unwrap!(self.regs_gp32_unchecked().arr().read().try_into());
422 #[cfg(not(stm32l0))] 458 #[cfg(stm32l0)]
423 TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), 459 return unwrap!(self.regs_gp32_unchecked().arr().read().arr().try_into());
424 }
425 } 460 }
426 461
427 /// Set the max compare value. 462 /// Set the max compare value.
428 /// 463 ///
429 /// An update event is generated to load the new value. The update event is 464 /// An update event is generated to load the new value. The update event is
430 /// generated such that it will not cause an interrupt or DMA request. 465 /// generated such that it will not cause an interrupt or DMA request.
431 pub fn set_max_compare_value(&self, ticks: u32) { 466 pub fn set_max_compare_value(&self, ticks: T::Word) {
432 match T::BITS { 467 let arr = ticks;
433 TimerBits::Bits16 => {
434 let arr = unwrap!(u16::try_from(ticks));
435
436 let regs = self.regs_1ch();
437 regs.arr().write(|r| r.set_arr(arr));
438
439 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
440 regs.egr().write(|r| r.set_ug(true));
441 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
442 }
443 #[cfg(not(stm32l0))]
444 TimerBits::Bits32 => {
445 let arr = ticks;
446 468
447 let regs = self.regs_gp32_unchecked(); 469 let regs = self.regs_gp32_unchecked();
448 regs.arr().write_value(arr); 470 #[cfg(not(stm32l0))]
471 regs.arr().write_value(arr.into());
472 #[cfg(stm32l0)]
473 regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into())));
449 474
450 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); 475 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
451 regs.egr().write(|r| r.set_ug(true)); 476 regs.egr().write(|r| r.set_ug(true));
452 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); 477 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
453 }
454 }
455 } 478 }
456} 479}
457 480
@@ -585,30 +608,204 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
585 } 608 }
586 609
587 /// Set compare value for a channel. 610 /// Set compare value for a channel.
588 pub fn set_compare_value(&self, channel: Channel, value: u32) { 611 pub fn set_compare_value(&self, channel: Channel, value: T::Word) {
589 match T::BITS { 612 #[cfg(not(stm32l0))]
590 TimerBits::Bits16 => { 613 self.regs_gp32_unchecked()
591 let value = unwrap!(u16::try_from(value)); 614 .ccr(channel.index())
592 self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); 615 .write_value(value.into());
593 } 616 #[cfg(stm32l0)]
594 #[cfg(not(stm32l0))] 617 self.regs_gp16()
595 TimerBits::Bits32 => { 618 .ccr(channel.index())
596 self.regs_gp32_unchecked().ccr(channel.index()).write_value(value); 619 .modify(|w| w.set_ccr(unwrap!(value.try_into())));
597 }
598 }
599 } 620 }
600 621
601 /// Get compare value for a channel. 622 /// Get compare value for a channel.
602 pub fn get_compare_value(&self, channel: Channel) -> u32 { 623 pub fn get_compare_value(&self, channel: Channel) -> T::Word {
603 match T::BITS { 624 #[cfg(not(stm32l0))]
604 TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32, 625 return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().try_into());
605 #[cfg(not(stm32l0))] 626 #[cfg(stm32l0)]
606 TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(), 627 return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().ccr().try_into());
628 }
629
630 pub(crate) fn clamp_compare_value<W: Word>(&mut self, channel: Channel) {
631 self.set_compare_value(
632 channel,
633 unwrap!(
634 self.get_compare_value(channel)
635 .into()
636 .clamp(0, W::max() as u32)
637 .try_into()
638 ),
639 );
640 }
641
642 /// Setup a ring buffer for the channel
643 pub fn setup_ring_buffer<'a, W: Word + Into<T::Word>>(
644 &mut self,
645 dma: Peri<'a, impl super::UpDma<T>>,
646 channel: Channel,
647 dma_buf: &'a mut [W],
648 ) -> WritableRingBuffer<'a, W> {
649 #[allow(clippy::let_unit_value)] // eg. stm32f334
650 let req = dma.request();
651
652 unsafe {
653 use crate::dma::TransferOptions;
654 #[cfg(not(any(bdma, gpdma)))]
655 use crate::dma::{Burst, FifoThreshold};
656
657 let dma_transfer_option = TransferOptions {
658 #[cfg(not(any(bdma, gpdma)))]
659 fifo_threshold: Some(FifoThreshold::Full),
660 #[cfg(not(any(bdma, gpdma)))]
661 mburst: Burst::Incr8,
662 ..Default::default()
663 };
664
665 WritableRingBuffer::new(
666 dma,
667 req,
668 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut W,
669 dma_buf,
670 dma_transfer_option,
671 )
672 }
673 }
674
675 /// Generate a sequence of PWM waveform
676 ///
677 /// Note:
678 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
679 pub fn setup_update_dma<'a, W: Word + Into<T::Word>>(
680 &mut self,
681 dma: Peri<'a, impl super::UpDma<T>>,
682 channel: Channel,
683 duty: &'a [W],
684 ) -> Transfer<'a> {
685 self.setup_update_dma_inner(dma.request(), dma, channel, duty)
686 }
687
688 /// Generate a sequence of PWM waveform
689 ///
690 /// Note:
691 /// The DMA channel provided does not need to correspond to the requested channel.
692 pub fn setup_channel_update_dma<'a, C: TimerChannel, W: Word + Into<T::Word>>(
693 &mut self,
694 dma: Peri<'a, impl super::Dma<T, C>>,
695 channel: Channel,
696 duty: &'a [W],
697 ) -> Transfer<'a> {
698 self.setup_update_dma_inner(dma.request(), dma, channel, duty)
699 }
700
701 fn setup_update_dma_inner<'a, W: Word + Into<T::Word>>(
702 &mut self,
703 request: dma::Request,
704 dma: Peri<'a, impl dma::Channel>,
705 channel: Channel,
706 duty: &'a [W],
707 ) -> Transfer<'a> {
708 unsafe {
709 #[cfg(not(any(bdma, gpdma)))]
710 use crate::dma::{Burst, FifoThreshold};
711 use crate::dma::{Transfer, TransferOptions};
712
713 let dma_transfer_option = TransferOptions {
714 #[cfg(not(any(bdma, gpdma)))]
715 fifo_threshold: Some(FifoThreshold::Full),
716 #[cfg(not(any(bdma, gpdma)))]
717 mburst: Burst::Incr8,
718 ..Default::default()
719 };
720
721 Transfer::new_write(
722 dma,
723 request,
724 duty,
725 self.regs_gp16().ccr(channel.index()).as_ptr() as *mut W,
726 dma_transfer_option,
727 )
728 }
729 }
730
731 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
732 ///
733 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
734 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
735 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
736 ///
737 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
738 /// represents a single update event and each column corresponds to a specific timer channel (starting
739 /// from `starting_channel` up to and including `ending_channel`).
740 ///
741 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
742 ///
743 /// ```rust,ignore
744 /// let dma_buf: [u16; 16] = [
745 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
746 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
747 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
748 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
749 /// ];
750 /// ```
751 ///
752 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
753 /// updating the duty cycles of all selected channels simultaneously.
754 ///
755 /// Note:
756 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
757 /// Also be aware that embassy timers use one of timers internally. It is possible to
758 /// switch this timer by using `time-driver-timX` feature.
759 ///
760 pub fn setup_update_dma_burst<'a, W: Word + Into<T::Word>>(
761 &mut self,
762 dma: Peri<'a, impl super::UpDma<T>>,
763 starting_channel: Channel,
764 ending_channel: Channel,
765 duty: &'a [W],
766 ) -> Transfer<'a> {
767 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
768 let start_ch_index = starting_channel.index();
769 let end_ch_index = ending_channel.index();
770
771 assert!(start_ch_index <= end_ch_index);
772
773 let ccrx_addr = self.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
774 self.regs_gp16()
775 .dcr()
776 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
777 self.regs_gp16()
778 .dcr()
779 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
780
781 #[allow(clippy::let_unit_value)] // eg. stm32f334
782 let req = dma.request();
783
784 unsafe {
785 #[cfg(not(any(bdma, gpdma)))]
786 use crate::dma::{Burst, FifoThreshold};
787 use crate::dma::{Transfer, TransferOptions};
788
789 let dma_transfer_option = TransferOptions {
790 #[cfg(not(any(bdma, gpdma)))]
791 fifo_threshold: Some(FifoThreshold::Full),
792 #[cfg(not(any(bdma, gpdma)))]
793 mburst: Burst::Incr4,
794 ..Default::default()
795 };
796
797 Transfer::new_write(
798 dma,
799 req,
800 duty,
801 self.regs_gp16().dmar().as_ptr() as *mut W,
802 dma_transfer_option,
803 )
607 } 804 }
608 } 805 }
609 806
610 /// Get capture value for a channel. 807 /// Get capture value for a channel.
611 pub fn get_capture_value(&self, channel: Channel) -> u32 { 808 pub fn get_capture_value(&self, channel: Channel) -> T::Word {
612 self.get_compare_value(channel) 809 self.get_compare_value(channel)
613 } 810 }
614 811
@@ -640,6 +837,11 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
640 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) 837 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
641 } 838 }
642 839
840 /// Set Timer Master Mode
841 pub fn set_master_mode(&self, mms: MasterMode) {
842 self.regs_gp16().cr2().modify(|w| w.set_mms(mms));
843 }
844
643 /// Set Timer Slave Mode 845 /// Set Timer Slave Mode
644 pub fn set_slave_mode(&self, sms: SlaveMode) { 846 pub fn set_slave_mode(&self, sms: SlaveMode) {
645 self.regs_gp16().smcr().modify(|r| r.set_sms(sms)); 847 self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
@@ -760,6 +962,16 @@ impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
760 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val)); 962 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val));
761 } 963 }
762 964
965 /// Set master mode selection 2
966 pub fn set_mms2_selection(&self, mms2: vals::Mms2) {
967 self.regs_advanced().cr2().modify(|w| w.set_mms2(mms2));
968 }
969
970 /// Set repetition counter
971 pub fn set_repetition_counter(&self, val: u16) {
972 self.regs_advanced().rcr().modify(|w| w.set_rep(val));
973 }
974
763 /// Trigger software break 1 or 2 975 /// Trigger software break 1 or 2
764 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware. 976 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware.
765 pub fn trigger_software_break(&self, n: usize) { 977 pub fn trigger_software_break(&self, n: usize) {
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index b09bc7166..998e3a6f4 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -12,8 +12,11 @@ pub mod low_level;
12pub mod one_pulse; 12pub mod one_pulse;
13pub mod pwm_input; 13pub mod pwm_input;
14pub mod qei; 14pub mod qei;
15pub mod ringbuffered;
15pub mod simple_pwm; 16pub mod simple_pwm;
16 17
18use crate::dma::word::Word;
19use crate::fmt::Debuggable;
17use crate::interrupt; 20use crate::interrupt;
18use crate::rcc::RccPeripheral; 21use crate::rcc::RccPeripheral;
19 22
@@ -162,7 +165,12 @@ pub trait CoreInstance: SealedInstance + 'static {
162 type UpdateInterrupt: interrupt::typelevel::Interrupt; 165 type UpdateInterrupt: interrupt::typelevel::Interrupt;
163 166
164 /// Amount of bits this timer has. 167 /// Amount of bits this timer has.
165 const BITS: TimerBits; 168 type Word: Word
169 + TryInto<u16, Error: Debuggable>
170 + From<u16>
171 + TryFrom<u32, Error: Debuggable>
172 + Into<u32>
173 + TryFrom<u64, Error: Debuggable>;
166 174
167 /// Registers for this timer. 175 /// Registers for this timer.
168 /// 176 ///
@@ -240,7 +248,7 @@ dma_trait!(Dma, GeneralInstance4Channel, TimerChannel);
240 248
241#[allow(unused)] 249#[allow(unused)]
242macro_rules! impl_core_timer { 250macro_rules! impl_core_timer {
243 ($inst:ident, $bits:expr) => { 251 ($inst:ident, $bits:ident) => {
244 impl SealedInstance for crate::peripherals::$inst { 252 impl SealedInstance for crate::peripherals::$inst {
245 fn state() -> &'static State { 253 fn state() -> &'static State {
246 static STATE: State = State::new(); 254 static STATE: State = State::new();
@@ -250,8 +258,7 @@ macro_rules! impl_core_timer {
250 258
251 impl CoreInstance for crate::peripherals::$inst { 259 impl CoreInstance for crate::peripherals::$inst {
252 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; 260 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP;
253 261 type Word = $bits;
254 const BITS: TimerBits = $bits;
255 262
256 fn regs() -> *mut () { 263 fn regs() -> *mut () {
257 crate::pac::$inst.as_ptr() 264 crate::pac::$inst.as_ptr()
@@ -305,13 +312,13 @@ macro_rules! impl_general_4ch_blank_sealed {
305 312
306foreach_interrupt! { 313foreach_interrupt! {
307 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 314 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
308 impl_core_timer!($inst, TimerBits::Bits16); 315 impl_core_timer!($inst, u16);
309 impl BasicNoCr2Instance for crate::peripherals::$inst {} 316 impl BasicNoCr2Instance for crate::peripherals::$inst {}
310 impl BasicInstance for crate::peripherals::$inst {} 317 impl BasicInstance for crate::peripherals::$inst {}
311 }; 318 };
312 319
313 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { 320 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => {
314 impl_core_timer!($inst, TimerBits::Bits16); 321 impl_core_timer!($inst, u16);
315 impl BasicNoCr2Instance for crate::peripherals::$inst {} 322 impl BasicNoCr2Instance for crate::peripherals::$inst {}
316 impl BasicInstance for crate::peripherals::$inst {} 323 impl BasicInstance for crate::peripherals::$inst {}
317 impl_general_1ch!($inst); 324 impl_general_1ch!($inst);
@@ -321,7 +328,7 @@ foreach_interrupt! {
321 }; 328 };
322 329
323 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { 330 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
324 impl_core_timer!($inst, TimerBits::Bits16); 331 impl_core_timer!($inst, u16);
325 impl BasicNoCr2Instance for crate::peripherals::$inst {} 332 impl BasicNoCr2Instance for crate::peripherals::$inst {}
326 impl BasicInstance for crate::peripherals::$inst {} 333 impl BasicInstance for crate::peripherals::$inst {}
327 impl_general_1ch!($inst); 334 impl_general_1ch!($inst);
@@ -331,7 +338,7 @@ foreach_interrupt! {
331 }; 338 };
332 339
333 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 340 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
334 impl_core_timer!($inst, TimerBits::Bits16); 341 impl_core_timer!($inst, u16);
335 impl BasicNoCr2Instance for crate::peripherals::$inst {} 342 impl BasicNoCr2Instance for crate::peripherals::$inst {}
336 impl BasicInstance for crate::peripherals::$inst {} 343 impl BasicInstance for crate::peripherals::$inst {}
337 impl_general_1ch!($inst); 344 impl_general_1ch!($inst);
@@ -341,7 +348,7 @@ foreach_interrupt! {
341 }; 348 };
342 349
343 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 350 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
344 impl_core_timer!($inst, TimerBits::Bits32); 351 impl_core_timer!($inst, u32);
345 impl BasicNoCr2Instance for crate::peripherals::$inst {} 352 impl BasicNoCr2Instance for crate::peripherals::$inst {}
346 impl BasicInstance for crate::peripherals::$inst {} 353 impl BasicInstance for crate::peripherals::$inst {}
347 impl_general_1ch!($inst); 354 impl_general_1ch!($inst);
@@ -352,7 +359,7 @@ foreach_interrupt! {
352 }; 359 };
353 360
354 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { 361 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
355 impl_core_timer!($inst, TimerBits::Bits16); 362 impl_core_timer!($inst, u16);
356 impl BasicNoCr2Instance for crate::peripherals::$inst {} 363 impl BasicNoCr2Instance for crate::peripherals::$inst {}
357 impl BasicInstance for crate::peripherals::$inst {} 364 impl BasicInstance for crate::peripherals::$inst {}
358 impl_general_1ch!($inst); 365 impl_general_1ch!($inst);
@@ -365,7 +372,7 @@ foreach_interrupt! {
365 }; 372 };
366 373
367 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { 374 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
368 impl_core_timer!($inst, TimerBits::Bits16); 375 impl_core_timer!($inst, u16);
369 impl BasicNoCr2Instance for crate::peripherals::$inst {} 376 impl BasicNoCr2Instance for crate::peripherals::$inst {}
370 impl BasicInstance for crate::peripherals::$inst {} 377 impl BasicInstance for crate::peripherals::$inst {}
371 impl_general_1ch!($inst); 378 impl_general_1ch!($inst);
@@ -378,7 +385,7 @@ foreach_interrupt! {
378 }; 385 };
379 386
380 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 387 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
381 impl_core_timer!($inst, TimerBits::Bits16); 388 impl_core_timer!($inst, u16);
382 impl BasicNoCr2Instance for crate::peripherals::$inst {} 389 impl BasicNoCr2Instance for crate::peripherals::$inst {}
383 impl BasicInstance for crate::peripherals::$inst {} 390 impl BasicInstance for crate::peripherals::$inst {}
384 impl_general_1ch!($inst); 391 impl_general_1ch!($inst);
@@ -399,7 +406,7 @@ pub struct UpdateInterruptHandler<T: CoreInstance> {
399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { 406impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
400 unsafe fn on_interrupt() { 407 unsafe fn on_interrupt() {
401 #[cfg(feature = "low-power")] 408 #[cfg(feature = "low-power")]
402 crate::low_power::on_wakeup_irq(); 409 crate::low_power::Executor::on_wakeup_irq_or_event();
403 410
404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); 411 let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
405 412
@@ -429,7 +436,7 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare
429{ 436{
430 unsafe fn on_interrupt() { 437 unsafe fn on_interrupt() {
431 #[cfg(feature = "low-power")] 438 #[cfg(feature = "low-power")]
432 crate::low_power::on_wakeup_irq(); 439 crate::low_power::Executor::on_wakeup_irq_or_event();
433 440
434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); 441 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
435 442
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs
index a75b41bd7..989e1d630 100644
--- a/embassy-stm32/src/timer/one_pulse.rs
+++ b/embassy-stm32/src/timer/one_pulse.rs
@@ -11,12 +11,12 @@ use super::low_level::{
11}; 11};
12use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin}; 12use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin};
13pub use super::{Ch1, Ch2}; 13pub use super::{Ch1, Ch2};
14use crate::Peri;
14use crate::gpio::{AfType, AnyPin, Pull}; 15use crate::gpio::{AfType, AnyPin, Pull};
15use crate::interrupt::typelevel::{Binding, Interrupt}; 16use crate::interrupt::typelevel::{Binding, Interrupt};
16use crate::pac::timer::vals::Etp; 17use crate::pac::timer::vals::Etp;
17use crate::time::Hertz; 18use crate::time::Hertz;
18use crate::timer::TimerChannel; 19use crate::timer::TimerChannel;
19use crate::Peri;
20 20
21/// External input marker type. 21/// External input marker type.
22pub enum Ext {} 22pub enum Ext {}
@@ -199,7 +199,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
199 fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) { 199 fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) {
200 self.inner.set_counting_mode(counting_mode); 200 self.inner.set_counting_mode(counting_mode);
201 self.inner.set_tick_freq(freq); 201 self.inner.set_tick_freq(freq);
202 self.inner.set_max_compare_value(pulse_end); 202 self.inner.set_max_compare_value(unwrap!(pulse_end.try_into()));
203 self.inner.regs_core().cr1().modify(|r| r.set_opm(true)); 203 self.inner.regs_core().cr1().modify(|r| r.set_opm(true));
204 // Required for advanced timers, see GeneralInstance4Channel for details 204 // Required for advanced timers, see GeneralInstance4Channel for details
205 self.inner.enable_outputs(); 205 self.inner.enable_outputs();
@@ -211,14 +211,14 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
211 211
212 /// Get the end of the pulse in ticks from the trigger. 212 /// Get the end of the pulse in ticks from the trigger.
213 pub fn pulse_end(&self) -> u32 { 213 pub fn pulse_end(&self) -> u32 {
214 let max = self.inner.get_max_compare_value(); 214 let max: u32 = self.inner.get_max_compare_value().into();
215 assert!(max < u32::MAX); 215 assert!(max < u32::MAX);
216 max + 1 216 max + 1
217 } 217 }
218 218
219 /// Set the end of the pulse in ticks from the trigger. 219 /// Set the end of the pulse in ticks from the trigger.
220 pub fn set_pulse_end(&mut self, ticks: u32) { 220 pub fn set_pulse_end(&mut self, ticks: u32) {
221 self.inner.set_max_compare_value(ticks) 221 self.inner.set_max_compare_value(unwrap!(ticks.try_into()))
222 } 222 }
223 223
224 /// Reset the timer on each trigger 224 /// Reset the timer on each trigger
@@ -327,7 +327,7 @@ pub struct OnePulseChannel<'d, T: GeneralInstance4Channel> {
327impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> { 327impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
328 /// Get the end of the pulse in ticks from the trigger. 328 /// Get the end of the pulse in ticks from the trigger.
329 pub fn pulse_end(&self) -> u32 { 329 pub fn pulse_end(&self) -> u32 {
330 let max = self.inner.get_max_compare_value(); 330 let max: u32 = self.inner.get_max_compare_value().into();
331 assert!(max < u32::MAX); 331 assert!(max < u32::MAX);
332 max + 1 332 max + 1
333 } 333 }
@@ -339,13 +339,13 @@ impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
339 339
340 /// Get the start of the pulse in ticks from the trigger. 340 /// Get the start of the pulse in ticks from the trigger.
341 pub fn pulse_delay(&mut self) -> u32 { 341 pub fn pulse_delay(&mut self) -> u32 {
342 self.inner.get_compare_value(self.channel) 342 self.inner.get_compare_value(self.channel).into()
343 } 343 }
344 344
345 /// Set the start of the pulse in ticks from the trigger. 345 /// Set the start of the pulse in ticks from the trigger.
346 pub fn set_pulse_delay(&mut self, delay: u32) { 346 pub fn set_pulse_delay(&mut self, delay: u32) {
347 assert!(delay <= self.pulse_end()); 347 assert!(delay <= self.pulse_end());
348 self.inner.set_compare_value(self.channel, delay); 348 self.inner.set_compare_value(self.channel, unwrap!(delay.try_into()));
349 } 349 }
350 350
351 /// Set the pulse width in ticks. 351 /// Set the pulse width in ticks.
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index 159b5a177..f2f00927d 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -2,9 +2,9 @@
2 2
3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; 3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource};
4use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin}; 4use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin};
5use crate::Peri;
5use crate::gpio::{AfType, Pull}; 6use crate::gpio::{AfType, Pull};
6use crate::time::Hertz; 7use crate::time::Hertz;
7use crate::Peri;
8 8
9/// PWM Input driver. 9/// PWM Input driver.
10/// 10///
@@ -47,6 +47,7 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
47 inner.set_counting_mode(CountingMode::EdgeAlignedUp); 47 inner.set_counting_mode(CountingMode::EdgeAlignedUp);
48 inner.set_tick_freq(freq); 48 inner.set_tick_freq(freq);
49 inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 49 inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
50 inner.generate_update_event();
50 inner.start(); 51 inner.start();
51 52
52 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 53 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6
@@ -90,16 +91,18 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
90 91
91 /// Get the period tick count 92 /// Get the period tick count
92 pub fn get_period_ticks(&self) -> u32 { 93 pub fn get_period_ticks(&self) -> u32 {
93 self.inner.get_capture_value(self.channel) 94 self.inner.get_capture_value(self.channel).into()
94 } 95 }
95 96
96 /// Get the pulse width tick count 97 /// Get the pulse width tick count
97 pub fn get_width_ticks(&self) -> u32 { 98 pub fn get_width_ticks(&self) -> u32 {
98 self.inner.get_capture_value(match self.channel { 99 self.inner
99 Channel::Ch1 => Channel::Ch2, 100 .get_capture_value(match self.channel {
100 Channel::Ch2 => Channel::Ch1, 101 Channel::Ch1 => Channel::Ch2,
101 _ => panic!("Invalid channel for PWM input"), 102 Channel::Ch2 => Channel::Ch1,
102 }) 103 _ => panic!("Invalid channel for PWM input"),
104 })
105 .into()
103 } 106 }
104 107
105 /// Get the duty cycle in 100% 108 /// Get the duty cycle in 100%
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index bb152731c..a547a2a19 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -5,9 +5,9 @@ use stm32_metapac::timer::vals::{self, Sms};
5use super::low_level::Timer; 5use super::low_level::Timer;
6pub use super::{Ch1, Ch2}; 6pub use super::{Ch1, Ch2};
7use super::{GeneralInstance4Channel, TimerPin}; 7use super::{GeneralInstance4Channel, TimerPin};
8use crate::Peri;
8use crate::gpio::{AfType, AnyPin, Pull}; 9use crate::gpio::{AfType, AnyPin, Pull};
9use crate::timer::TimerChannel; 10use crate::timer::TimerChannel;
10use crate::Peri;
11 11
12/// Qei driver config. 12/// Qei driver config.
13#[cfg_attr(feature = "defmt", derive(defmt::Format))] 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-stm32/src/timer/ringbuffered.rs b/embassy-stm32/src/timer/ringbuffered.rs
new file mode 100644
index 000000000..fbb6b19ea
--- /dev/null
+++ b/embassy-stm32/src/timer/ringbuffered.rs
@@ -0,0 +1,158 @@
1//! RingBuffered PWM driver.
2
3use core::mem::ManuallyDrop;
4use core::task::Waker;
5
6use super::low_level::Timer;
7use super::{Channel, GeneralInstance4Channel};
8use crate::dma::WritableRingBuffer;
9use crate::dma::ringbuffer::Error;
10use crate::dma::word::Word;
11
12/// A PWM channel that uses a DMA ring buffer for continuous waveform generation.
13///
14/// This allows you to continuously update PWM duty cycles via DMA without blocking the CPU.
15/// The ring buffer enables smooth, uninterrupted waveform generation by automatically cycling
16/// through duty cycle values stored in memory.
17///
18/// You can write new duty cycle values to the ring buffer while it's running, enabling
19/// dynamic waveform generation for applications like motor control, LED dimming, or audio output.
20///
21/// # Example
22/// ```ignore
23/// let mut channel = pwm.ch1().into_ring_buffered_channel(dma_ch, &mut buffer);
24/// channel.start(); // Start DMA transfer
25/// channel.write(&[100, 200, 300]).ok(); // Update duty cycles
26/// ```
27pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> {
28 timer: ManuallyDrop<Timer<'d, T>>,
29 ring_buf: WritableRingBuffer<'d, W>,
30 channel: Channel,
31}
32
33impl<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> RingBufferedPwmChannel<'d, T, W> {
34 pub(crate) fn new(
35 timer: ManuallyDrop<Timer<'d, T>>,
36 channel: Channel,
37 ring_buf: WritableRingBuffer<'d, W>,
38 ) -> Self {
39 Self {
40 timer,
41 ring_buf,
42 channel,
43 }
44 }
45
46 /// Start the ring buffer operation.
47 ///
48 /// You must call this after creating it for it to work.
49 pub fn start(&mut self) {
50 self.ring_buf.start()
51 }
52
53 /// Clear all data in the ring buffer.
54 pub fn clear(&mut self) {
55 self.ring_buf.clear()
56 }
57
58 /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer.
59 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
60 self.ring_buf.write_immediate(buf)
61 }
62
63 /// Write elements from the ring buffer
64 /// Return a tuple of the length written and the length remaining in the buffer
65 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
66 self.ring_buf.write(buf)
67 }
68
69 /// Write an exact number of elements to the ringbuffer.
70 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> {
71 self.ring_buf.write_exact(buffer).await
72 }
73
74 /// Wait for any ring buffer write error.
75 pub async fn wait_write_error(&mut self) -> Result<usize, Error> {
76 self.ring_buf.wait_write_error().await
77 }
78
79 /// The current length of the ringbuffer
80 pub fn len(&mut self) -> Result<usize, Error> {
81 self.ring_buf.len()
82 }
83
84 /// The capacity of the ringbuffer
85 pub const fn capacity(&self) -> usize {
86 self.ring_buf.capacity()
87 }
88
89 /// Set a waker to be woken when at least one byte is send.
90 pub fn set_waker(&mut self, waker: &Waker) {
91 self.ring_buf.set_waker(waker)
92 }
93
94 /// Request the DMA to reset. The configuration for this channel will not be preserved.
95 ///
96 /// This doesn't immediately stop the transfer, you have to wait until is_running returns false.
97 pub fn request_reset(&mut self) {
98 self.ring_buf.request_reset()
99 }
100
101 /// Request the transfer to pause, keeping the existing configuration for this channel.
102 /// To restart the transfer, call [`start`](Self::start) again.
103 ///
104 /// This doesn't immediately stop the transfer, you have to wait until is_running returns false.
105 pub fn request_pause(&mut self) {
106 self.ring_buf.request_pause()
107 }
108
109 /// Return whether DMA is still running.
110 ///
111 /// If this returns false, it can be because either the transfer finished, or it was requested to stop early with request_stop.
112 pub fn is_running(&mut self) -> bool {
113 self.ring_buf.is_running()
114 }
115
116 /// Stop the DMA transfer and await until the buffer is empty.
117 ///
118 /// This disables the DMA transfer's circular mode so that the transfer stops when all available data has been written.
119 ///
120 /// This is designed to be used with streaming output data such as the I2S/SAI or DAC.
121 pub async fn stop(&mut self) {
122 self.ring_buf.stop().await
123 }
124
125 /// Enable the given channel.
126 pub fn enable(&mut self) {
127 self.timer.enable_channel(self.channel, true);
128 }
129
130 /// Disable the given channel.
131 pub fn disable(&mut self) {
132 self.timer.enable_channel(self.channel, false);
133 }
134
135 /// Check whether given channel is enabled
136 pub fn is_enabled(&self) -> bool {
137 self.timer.get_channel_enable_state(self.channel)
138 }
139
140 /// Get max duty value.
141 ///
142 /// This value depends on the configured frequency and the timer's clock rate from RCC.
143 pub fn max_duty_cycle(&self) -> u16 {
144 let max: u32 = self.timer.get_max_compare_value().into();
145 assert!(max < u16::MAX as u32);
146 max as u16 + 1
147 }
148
149 /// Set the output polarity for a given channel.
150 pub fn set_polarity(&mut self, polarity: super::low_level::OutputPolarity) {
151 self.timer.set_output_polarity(self.channel, polarity);
152 }
153
154 /// Set the output compare mode for a given channel.
155 pub fn set_output_compare_mode(&mut self, mode: super::low_level::OutputCompareMode) {
156 self.timer.set_output_compare_mode(self.channel, mode);
157 }
158}
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index e6165e42b..4ffa58778 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -4,12 +4,15 @@ use core::marker::PhantomData;
4use core::mem::ManuallyDrop; 4use core::mem::ManuallyDrop;
5 5
6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; 6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; 7use super::ringbuffered::RingBufferedPwmChannel;
8use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin};
9use crate::Peri;
10use crate::dma::word::Word;
8#[cfg(gpio_v2)] 11#[cfg(gpio_v2)]
9use crate::gpio::Pull; 12use crate::gpio::Pull;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 13use crate::gpio::{AfType, AnyPin, OutputType, Speed};
14use crate::pac::timer::vals::Ccds;
11use crate::time::Hertz; 15use crate::time::Hertz;
12use crate::Peri;
13 16
14/// PWM pin wrapper. 17/// PWM pin wrapper.
15/// 18///
@@ -94,21 +97,24 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
94 self.timer.get_channel_enable_state(self.channel) 97 self.timer.get_channel_enable_state(self.channel)
95 } 98 }
96 99
100 /// Get the frequency of the PWM channel.
101 pub fn get_frequency(&self) -> Hertz {
102 self.timer.get_frequency()
103 }
104
97 /// Get max duty value. 105 /// Get max duty value.
98 /// 106 ///
99 /// This value depends on the configured frequency and the timer's clock rate from RCC. 107 /// This value depends on the configured frequency and the timer's clock rate from RCC.
100 pub fn max_duty_cycle(&self) -> u16 { 108 pub fn max_duty_cycle(&self) -> u32 {
101 let max = self.timer.get_max_compare_value(); 109 self.timer.get_max_compare_value().into() + 1
102 assert!(max < u16::MAX as u32);
103 max as u16 + 1
104 } 110 }
105 111
106 /// Set the duty for a given channel. 112 /// Set the duty for a given channel.
107 /// 113 ///
108 /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. 114 /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included.
109 pub fn set_duty_cycle(&mut self, duty: u16) { 115 pub fn set_duty_cycle(&mut self, duty: u32) {
110 assert!(duty <= (*self).max_duty_cycle()); 116 assert!(duty <= (*self).max_duty_cycle());
111 self.timer.set_compare_value(self.channel, duty.into()) 117 self.timer.set_compare_value(self.channel, unwrap!(duty.try_into()))
112 } 118 }
113 119
114 /// Set the duty cycle to 0%, or always inactive. 120 /// Set the duty cycle to 0%, or always inactive.
@@ -125,21 +131,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
125 /// 131 ///
126 /// The caller is responsible for ensuring that `num` is less than or equal to `denom`, 132 /// The caller is responsible for ensuring that `num` is less than or equal to `denom`,
127 /// and that `denom` is not zero. 133 /// and that `denom` is not zero.
128 pub fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { 134 pub fn set_duty_cycle_fraction(&mut self, num: u32, denom: u32) {
129 assert!(denom != 0); 135 assert!(denom != 0);
130 assert!(num <= denom); 136 assert!(num <= denom);
131 let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom); 137 let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom);
132 138
133 // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16) 139 // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16)
134 #[allow(clippy::cast_possible_truncation)] 140 #[allow(clippy::cast_possible_truncation)]
135 self.set_duty_cycle(duty as u16); 141 self.set_duty_cycle(unwrap!(duty.try_into()));
136 } 142 }
137 143
138 /// Set the duty cycle to `percent / 100` 144 /// Set the duty cycle to `percent / 100`
139 /// 145 ///
140 /// The caller is responsible for ensuring that `percent` is less than or equal to 100. 146 /// The caller is responsible for ensuring that `percent` is less than or equal to 100.
141 pub fn set_duty_cycle_percent(&mut self, percent: u8) { 147 pub fn set_duty_cycle_percent(&mut self, percent: u8) {
142 self.set_duty_cycle_fraction(u16::from(percent), 100) 148 self.set_duty_cycle_fraction(percent as u32, 100)
143 } 149 }
144 150
145 /// Get the duty for a given channel. 151 /// Get the duty for a given channel.
@@ -158,6 +164,34 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
158 pub fn set_output_compare_mode(&mut self, mode: OutputCompareMode) { 164 pub fn set_output_compare_mode(&mut self, mode: OutputCompareMode) {
159 self.timer.set_output_compare_mode(self.channel, mode); 165 self.timer.set_output_compare_mode(self.channel, mode);
160 } 166 }
167
168 /// Convert this PWM channel into a ring-buffered PWM channel.
169 ///
170 /// This allows continuous PWM waveform generation using a DMA ring buffer.
171 /// The ring buffer enables dynamic updates to the PWM duty cycle without blocking.
172 ///
173 /// # Arguments
174 /// * `tx_dma` - The DMA channel to use for transferring duty cycle values
175 /// * `dma_buf` - The buffer to use as a ring buffer (must be non-empty and <= 65535 elements)
176 ///
177 /// # Panics
178 /// Panics if `dma_buf` is empty or longer than 65535 elements.
179 pub fn into_ring_buffered_channel<W: Word + Into<T::Word>>(
180 mut self,
181 tx_dma: Peri<'d, impl super::UpDma<T>>,
182 dma_buf: &'d mut [W],
183 ) -> RingBufferedPwmChannel<'d, T, W> {
184 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
185
186 self.timer.clamp_compare_value::<W>(self.channel);
187 self.timer.enable_update_dma(true);
188
189 RingBufferedPwmChannel::new(
190 unsafe { self.timer.clone_unchecked() },
191 self.channel,
192 self.timer.setup_ring_buffer(tx_dma, self.channel, dma_buf),
193 )
194 }
161} 195}
162 196
163/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`]. 197/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`].
@@ -198,7 +232,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
198 this.inner.set_counting_mode(counting_mode); 232 this.inner.set_counting_mode(counting_mode);
199 this.set_frequency(freq); 233 this.set_frequency(freq);
200 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 234 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
201 this.inner.start();
202 235
203 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 236 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
204 .iter() 237 .iter()
@@ -207,6 +240,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
207 240
208 this.inner.set_output_compare_preload(channel, true); 241 this.inner.set_output_compare_preload(channel, true);
209 }); 242 });
243 this.inner.set_autoreload_preload(true);
244
245 // Generate update event so pre-load registers are written to the shadow registers
246 this.inner.generate_update_event();
247 this.inner.start();
210 248
211 this 249 this
212 } 250 }
@@ -285,8 +323,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
285 323
286 /// Set PWM frequency. 324 /// Set PWM frequency.
287 /// 325 ///
288 /// Note: when you call this, the max duty value changes, so you will have to 326 /// Note: that the frequency will not be applied in the timer until an update event
289 /// call `set_duty` on all channels with the duty calculated based on the new max duty. 327 /// occurs.
290 pub fn set_frequency(&mut self, freq: Hertz) { 328 pub fn set_frequency(&mut self, freq: Hertz) {
291 // TODO: prevent ARR = u16::MAX? 329 // TODO: prevent ARR = u16::MAX?
292 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 330 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
@@ -297,73 +335,54 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
297 self.inner.set_frequency_internal(freq * multiplier, 16); 335 self.inner.set_frequency_internal(freq * multiplier, 16);
298 } 336 }
299 337
338 /// Get the PWM driver frequency.
339 pub fn get_frequency(&self) -> Hertz {
340 self.inner.get_frequency()
341 }
342
300 /// Get max duty value. 343 /// Get max duty value.
301 /// 344 ///
302 /// This value depends on the configured frequency and the timer's clock rate from RCC. 345 /// This value depends on the configured frequency and the timer's clock rate from RCC.
303 pub fn max_duty_cycle(&self) -> u16 { 346 pub fn max_duty_cycle(&self) -> u32 {
304 let max = self.inner.get_max_compare_value(); 347 self.inner.get_max_compare_value().into() + 1
305 assert!(max < u16::MAX as u32);
306 max as u16 + 1
307 } 348 }
308 349
309 /// Generate a sequence of PWM waveform 350 /// Generate a sequence of PWM waveform
310 /// 351 ///
311 /// Note: 352 /// Note:
312 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 353 /// The DMA channel provided does not need to correspond to the requested channel.
313 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 354 pub async fn waveform<C: TimerChannel, W: Word + Into<T::Word>>(
314 #[allow(clippy::let_unit_value)] // eg. stm32f334 355 &mut self,
315 let req = dma.request(); 356 dma: Peri<'_, impl super::Dma<T, C>>,
316 357 channel: Channel,
317 let original_duty_state = self.channel(channel).current_duty_cycle(); 358 duty: &[W],
318 let original_enable_state = self.channel(channel).is_enabled(); 359 ) {
319 let original_update_dma_state = self.inner.get_update_dma_state(); 360 self.inner.enable_channel(channel, true);
320 361 self.inner.enable_channel(C::CHANNEL, true);
321 if !original_update_dma_state { 362 self.inner.clamp_compare_value::<W>(channel);
322 self.inner.enable_update_dma(true); 363 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE);
323 } 364 self.inner.set_cc_dma_enable_state(C::CHANNEL, true);
324 365 self.inner.setup_channel_update_dma(dma, channel, duty).await;
325 if !original_enable_state { 366 self.inner.set_cc_dma_enable_state(C::CHANNEL, false);
326 self.channel(channel).enable(); 367 }
327 }
328
329 unsafe {
330 #[cfg(not(any(bdma, gpdma)))]
331 use crate::dma::{Burst, FifoThreshold};
332 use crate::dma::{Transfer, TransferOptions};
333
334 let dma_transfer_option = TransferOptions {
335 #[cfg(not(any(bdma, gpdma)))]
336 fifo_threshold: Some(FifoThreshold::Full),
337 #[cfg(not(any(bdma, gpdma)))]
338 mburst: Burst::Incr8,
339 ..Default::default()
340 };
341
342 Transfer::new_write(
343 dma,
344 req,
345 duty,
346 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
347 dma_transfer_option,
348 )
349 .await
350 };
351
352 // restore output compare state
353 if !original_enable_state {
354 self.channel(channel).disable();
355 }
356
357 self.channel(channel).set_duty_cycle(original_duty_state);
358 368
359 // Since DMA is closed before timer update event trigger DMA is turn off, 369 /// Generate a sequence of PWM waveform
360 // this can almost always trigger a DMA FIFO error. 370 ///
361 // 371 /// Note:
362 // optional TODO: 372 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
363 // clean FEIF after disable UDE 373 /// Also be aware that embassy timers use one of timers internally. It is possible to
364 if !original_update_dma_state { 374 /// switch this timer by using `time-driver-timX` feature.
365 self.inner.enable_update_dma(false); 375 pub async fn waveform_up<W: Word + Into<T::Word>>(
366 } 376 &mut self,
377 dma: Peri<'_, impl super::UpDma<T>>,
378 channel: Channel,
379 duty: &[W],
380 ) {
381 self.inner.enable_channel(channel, true);
382 self.inner.clamp_compare_value::<W>(channel);
383 self.inner.enable_update_dma(true);
384 self.inner.setup_update_dma(dma, channel, duty).await;
385 self.inner.enable_update_dma(false);
367 } 386 }
368 387
369 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. 388 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
@@ -378,167 +397,43 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
378 /// 397 ///
379 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: 398 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
380 /// 399 ///
400 /// ```rust,ignore
381 /// let dma_buf: [u16; 16] = [ 401 /// let dma_buf: [u16; 16] = [
382 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 402 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
383 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 403 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
384 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 404 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
385 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 405 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
386 /// ]; 406 /// ];
407 /// ```
387 /// 408 ///
388 /// Each group of N values (where N = number of channels) is transferred on one update event, 409 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
389 /// updating the duty cycles of all selected channels simultaneously. 410 /// updating the duty cycles of all selected channels simultaneously.
390 /// 411 ///
391 /// Note: 412 /// Note:
392 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 413 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
393 pub async fn waveform_up_multi_channel( 414 /// Also be aware that embassy timers use one of timers internally. It is possible to
415 /// switch this timer by using `time-driver-timX` feature.
416 ///
417 pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>(
394 &mut self, 418 &mut self,
395 dma: Peri<'_, impl super::UpDma<T>>, 419 dma: Peri<'_, impl super::UpDma<T>>,
396 starting_channel: Channel, 420 starting_channel: Channel,
397 ending_channel: Channel, 421 ending_channel: Channel,
398 duty: &[u16], 422 duty: &[W],
399 ) { 423 ) {
400 let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32; 424 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
401 let start_ch_index = starting_channel.index(); 425 .iter()
402 let end_ch_index = ending_channel.index(); 426 .filter(|ch| ch.index() >= starting_channel.index())
403 427 .filter(|ch| ch.index() <= ending_channel.index())
404 assert!(start_ch_index <= end_ch_index); 428 .for_each(|ch| {
405 429 self.inner.enable_channel(*ch, true);
406 let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32; 430 self.inner.clamp_compare_value::<W>(*ch);
407 self.inner 431 });
408 .regs_gp16() 432 self.inner.enable_update_dma(true);
409 .dcr()
410 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
411 self.inner 433 self.inner
412 .regs_gp16() 434 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
413 .dcr() 435 .await;
414 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8)); 436 self.inner.enable_update_dma(false);
415
416 #[allow(clippy::let_unit_value)] // eg. stm32f334
417 let req = dma.request();
418
419 let original_update_dma_state = self.inner.get_update_dma_state();
420 if !original_update_dma_state {
421 self.inner.enable_update_dma(true);
422 }
423
424 unsafe {
425 #[cfg(not(any(bdma, gpdma)))]
426 use crate::dma::{Burst, FifoThreshold};
427 use crate::dma::{Transfer, TransferOptions};
428
429 let dma_transfer_option = TransferOptions {
430 #[cfg(not(any(bdma, gpdma)))]
431 fifo_threshold: Some(FifoThreshold::Full),
432 #[cfg(not(any(bdma, gpdma)))]
433 mburst: Burst::Incr4,
434 ..Default::default()
435 };
436
437 Transfer::new_write(
438 dma,
439 req,
440 duty,
441 self.inner.regs_gp16().dmar().as_ptr() as *mut u16,
442 dma_transfer_option,
443 )
444 .await
445 };
446
447 if !original_update_dma_state {
448 self.inner.enable_update_dma(false);
449 }
450 }
451}
452
453impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
454 /// Generate a sequence of PWM waveform
455 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
456 use crate::pac::timer::vals::Ccds;
457
458 #[allow(clippy::let_unit_value)] // eg. stm32f334
459 let req = dma.request();
460
461 let cc_channel = C::CHANNEL;
462
463 let original_duty_state = self.channel(cc_channel).current_duty_cycle();
464 let original_enable_state = self.channel(cc_channel).is_enabled();
465 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE;
466 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
467
468 // redirect CC DMA request onto Update Event
469 if !original_cc_dma_on_update {
470 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE)
471 }
472
473 if !original_cc_dma_enabled {
474 self.inner.set_cc_dma_enable_state(cc_channel, true);
475 }
476
477 if !original_enable_state {
478 self.channel(cc_channel).enable();
479 }
480
481 unsafe {
482 #[cfg(not(any(bdma, gpdma)))]
483 use crate::dma::{Burst, FifoThreshold};
484 use crate::dma::{Transfer, TransferOptions};
485
486 let dma_transfer_option = TransferOptions {
487 #[cfg(not(any(bdma, gpdma)))]
488 fifo_threshold: Some(FifoThreshold::Full),
489 #[cfg(not(any(bdma, gpdma)))]
490 mburst: Burst::Incr8,
491 ..Default::default()
492 };
493
494 match self.inner.bits() {
495 TimerBits::Bits16 => {
496 Transfer::new_write(
497 dma,
498 req,
499 duty,
500 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
501 dma_transfer_option,
502 )
503 .await
504 }
505 #[cfg(not(any(stm32l0)))]
506 TimerBits::Bits32 => {
507 #[cfg(not(any(bdma, gpdma)))]
508 panic!("unsupported timer bits");
509
510 #[cfg(any(bdma, gpdma))]
511 Transfer::new_write(
512 dma,
513 req,
514 duty,
515 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
516 dma_transfer_option,
517 )
518 .await
519 }
520 };
521 };
522
523 // restore output compare state
524 if !original_enable_state {
525 self.channel(cc_channel).disable();
526 }
527
528 self.channel(cc_channel).set_duty_cycle(original_duty_state);
529
530 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
531 // this can almost always trigger a DMA FIFO error.
532 //
533 // optional TODO:
534 // clean FEIF after disable UDE
535 if !original_cc_dma_enabled {
536 self.inner.set_cc_dma_enable_state(cc_channel, false);
537 }
538
539 if !original_cc_dma_on_update {
540 self.inner.set_cc_dma_selection(Ccds::ON_COMPARE)
541 }
542 } 437 }
543} 438}
544 439
@@ -548,11 +443,11 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePw
548 443
549impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { 444impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> {
550 fn max_duty_cycle(&self) -> u16 { 445 fn max_duty_cycle(&self) -> u16 {
551 self.max_duty_cycle() 446 unwrap!(self.max_duty_cycle().try_into())
552 } 447 }
553 448
554 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { 449 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
555 self.set_duty_cycle(duty); 450 self.set_duty_cycle(duty.into());
556 Ok(()) 451 Ok(())
557 } 452 }
558 453
@@ -567,7 +462,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for Simpl
567 } 462 }
568 463
569 fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> { 464 fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> {
570 self.set_duty_cycle_fraction(num, denom); 465 self.set_duty_cycle_fraction(num.into(), denom.into());
571 Ok(()) 466 Ok(())
572 } 467 }
573 468
@@ -595,16 +490,16 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
595 } 490 }
596 491
597 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 492 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
598 self.inner.get_compare_value(channel) 493 self.inner.get_compare_value(channel).into()
599 } 494 }
600 495
601 fn get_max_duty(&self) -> Self::Duty { 496 fn get_max_duty(&self) -> Self::Duty {
602 self.inner.get_max_compare_value() + 1 497 self.inner.get_max_compare_value().into() + 1
603 } 498 }
604 499
605 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 500 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
606 assert!(duty <= self.max_duty_cycle() as u32); 501 assert!(duty <= self.max_duty_cycle() as u32);
607 self.inner.set_compare_value(channel, duty) 502 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
608 } 503 }
609 504
610 fn set_period<P>(&mut self, period: P) 505 fn set_period<P>(&mut self, period: P)
diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs
index 7d6442b48..097cf7942 100644
--- a/embassy-stm32/src/tsc/acquisition_banks.rs
+++ b/embassy-stm32/src/tsc/acquisition_banks.rs
@@ -1,11 +1,11 @@
1use super::TSC_NUM_GROUPS;
1use super::io_pin::*; 2use super::io_pin::*;
2#[cfg(any(tsc_v2, tsc_v3))] 3#[cfg(any(tsc_v2, tsc_v3))]
3use super::pin_groups::G7; 4use super::pin_groups::G7;
4#[cfg(tsc_v3)] 5#[cfg(tsc_v3)]
5use super::pin_groups::G8; 6use super::pin_groups::G8;
6use super::pin_groups::{pin_roles, G1, G2, G3, G4, G5, G6}; 7use super::pin_groups::{G1, G2, G3, G4, G5, G6, pin_roles};
7use super::types::{Group, GroupStatus}; 8use super::types::{Group, GroupStatus};
8use super::TSC_NUM_GROUPS;
9 9
10/// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank. 10/// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank.
11/// 11///
diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs
index 84421f7ff..9347e6bc0 100644
--- a/embassy-stm32/src/tsc/pin_groups.rs
+++ b/embassy-stm32/src/tsc/pin_groups.rs
@@ -1,11 +1,11 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::ops::BitOr; 2use core::ops::BitOr;
3 3
4use super::Instance;
4use super::errors::GroupError; 5use super::errors::GroupError;
5use super::io_pin::*; 6use super::io_pin::*;
6use super::Instance;
7use crate::gpio::{AfType, AnyPin, OutputType, Speed};
8use crate::Peri; 7use crate::Peri;
8use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9 9
10/// Pin type definition to control IO parameters 10/// Pin type definition to control IO parameters
11#[derive(PartialEq, Clone, Copy)] 11#[derive(PartialEq, Clone, Copy)]
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index 18aff4fbd..ae86d28f0 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -19,8 +19,8 @@ use core::marker::PhantomData;
19use core::sync::atomic::{AtomicBool, Ordering}; 19use core::sync::atomic::{AtomicBool, Ordering};
20use core::task::Poll; 20use core::task::Poll;
21 21
22use embassy_hal_internal::drop::OnDrop;
23use embassy_hal_internal::PeripheralType; 22use embassy_hal_internal::PeripheralType;
23use embassy_hal_internal::drop::OnDrop;
24use embassy_sync::waitqueue::AtomicWaker; 24use embassy_sync::waitqueue::AtomicWaker;
25 25
26use crate::dma::{ChannelAndRequest, TransferOptions}; 26use crate::dma::{ChannelAndRequest, TransferOptions};
@@ -28,11 +28,11 @@ use crate::interrupt::typelevel::Interrupt;
28use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; 28use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
29pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; 29pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState};
30use crate::rcc::{self, RccPeripheral}; 30use crate::rcc::{self, RccPeripheral};
31use crate::{interrupt, Peri}; 31use crate::{Peri, interrupt};
32 32
33pub(crate) fn init( 33pub(crate) fn init(
34 _cs: critical_section::CriticalSection, 34 _cs: critical_section::CriticalSection,
35 #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, 35 #[cfg(all(peri_ucpd1, not(stm32n6)))] ucpd1_db_enable: bool,
36 #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, 36 #[cfg(peri_ucpd2)] ucpd2_db_enable: bool,
37) { 37) {
38 #[cfg(stm32g0x1)] 38 #[cfg(stm32g0x1)]
@@ -349,6 +349,7 @@ impl<'d, T: Instance> CcPhy<'d, T> {
349 critical_section::with(|cs| { 349 critical_section::with(|cs| {
350 init( 350 init(
351 cs, 351 cs,
352 #[cfg(not(stm32n6))]
352 false, 353 false,
353 #[cfg(peri_ucpd2)] 354 #[cfg(peri_ucpd2)]
354 false, 355 false,
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs
index 5e38532bd..2d3e2b972 100644
--- a/embassy-stm32/src/uid.rs
+++ b/embassy-stm32/src/uid.rs
@@ -1,8 +1,8 @@
1//! Unique ID (UID) 1//! Unique ID (UID)
2 2
3/// Get this device's unique 96-bit ID. 3/// Get this device's unique 96-bit ID.
4pub fn uid() -> &'static [u8; 12] { 4pub fn uid() -> [u8; 12] {
5 unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } 5 unsafe { *crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() }
6} 6}
7 7
8/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits. 8/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits.
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index c734eed49..26d2b8991 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,20 +1,20 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::slice; 3use core::slice;
4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
9use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
9use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11 11
12#[cfg(not(any(usart_v1, usart_v2)))] 12#[cfg(not(any(usart_v1, usart_v2)))]
13use super::DePin; 13use super::DePin;
14use super::{ 14use super::{
15 Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, TxPin,
15 clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate, 16 clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate,
16 sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, 17 sr, tdr,
17 TxPin,
18}; 18};
19use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; 19use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
20use crate::interrupt::{self, InterruptExt}; 20use crate::interrupt::{self, InterruptExt};
@@ -68,8 +68,15 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. 68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full.
69 } 69 }
70 70
71 if !state.rx_buf.is_empty() { 71 let eager = state.eager_reads.load(Ordering::Relaxed);
72 state.rx_waker.wake(); 72 if eager > 0 {
73 if state.rx_buf.available() >= eager {
74 state.rx_waker.wake();
75 }
76 } else {
77 if state.rx_buf.is_half_full() {
78 state.rx_waker.wake();
79 }
73 } 80 }
74 } 81 }
75 82
@@ -80,7 +87,7 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
80 // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC) 87 // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC)
81 // indicates that all bytes are pushed out from the FIFO. 88 // indicates that all bytes are pushed out from the FIFO.
82 // For other usart variants it shows that last byte from the buffer was just sent. 89 // For other usart variants it shows that last byte from the buffer was just sent.
83 if sr_val.tc() { 90 if sr_val.tc() && r.cr1().read().tcie() {
84 // For others it is cleared above with `clear_interrupt_flags`. 91 // For others it is cleared above with `clear_interrupt_flags`.
85 #[cfg(any(usart_v1, usart_v2))] 92 #[cfg(any(usart_v1, usart_v2))]
86 sr(r).modify(|w| w.set_tc(false)); 93 sr(r).modify(|w| w.set_tc(false));
@@ -132,6 +139,7 @@ pub(super) struct State {
132 tx_done: AtomicBool, 139 tx_done: AtomicBool,
133 tx_rx_refcount: AtomicU8, 140 tx_rx_refcount: AtomicU8,
134 half_duplex_readback: AtomicBool, 141 half_duplex_readback: AtomicBool,
142 eager_reads: AtomicUsize,
135} 143}
136 144
137impl State { 145impl State {
@@ -144,6 +152,7 @@ impl State {
144 tx_done: AtomicBool::new(true), 152 tx_done: AtomicBool::new(true),
145 tx_rx_refcount: AtomicU8::new(0), 153 tx_rx_refcount: AtomicU8::new(0),
146 half_duplex_readback: AtomicBool::new(false), 154 half_duplex_readback: AtomicBool::new(false),
155 eager_reads: AtomicUsize::new(0),
147 } 156 }
148 } 157 }
149} 158}
@@ -419,6 +428,9 @@ impl<'d> BufferedUart<'d> {
419 let state = T::buffered_state(); 428 let state = T::buffered_state();
420 let kernel_clock = T::frequency(); 429 let kernel_clock = T::frequency();
421 430
431 state
432 .eager_reads
433 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
422 state.half_duplex_readback.store( 434 state.half_duplex_readback.store(
423 config.duplex == Duplex::Half(HalfDuplexReadback::Readback), 435 config.duplex == Duplex::Half(HalfDuplexReadback::Readback),
424 Ordering::Relaxed, 436 Ordering::Relaxed,
@@ -456,6 +468,9 @@ impl<'d> BufferedUart<'d> {
456 let info = self.rx.info; 468 let info = self.rx.info;
457 let state = self.rx.state; 469 let state = self.rx.state;
458 state.tx_rx_refcount.store(2, Ordering::Relaxed); 470 state.tx_rx_refcount.store(2, Ordering::Relaxed);
471 state
472 .eager_reads
473 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
459 474
460 info.rcc.enable_and_reset(); 475 info.rcc.enable_and_reset();
461 476
@@ -527,6 +542,11 @@ impl<'d> BufferedUart<'d> {
527 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 542 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
528 reconfigure(self.rx.info, self.rx.kernel_clock, config)?; 543 reconfigure(self.rx.info, self.rx.kernel_clock, config)?;
529 544
545 self.rx
546 .state
547 .eager_reads
548 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
549
530 self.rx.info.regs.cr1().modify(|w| { 550 self.rx.info.regs.cr1().modify(|w| {
531 w.set_rxneie(true); 551 w.set_rxneie(true);
532 w.set_idleie(true); 552 w.set_idleie(true);
@@ -553,24 +573,30 @@ impl<'d> BufferedUartRx<'d> {
553 poll_fn(move |cx| { 573 poll_fn(move |cx| {
554 let state = self.state; 574 let state = self.state;
555 let mut rx_reader = unsafe { state.rx_buf.reader() }; 575 let mut rx_reader = unsafe { state.rx_buf.reader() };
556 let data = rx_reader.pop_slice(); 576 let mut buf_len = 0;
577 let mut data = rx_reader.pop_slice();
557 578
558 if !data.is_empty() { 579 while !data.is_empty() && buf_len < buf.len() {
559 let len = data.len().min(buf.len()); 580 let data_len = data.len().min(buf.len() - buf_len);
560 buf[..len].copy_from_slice(&data[..len]); 581 buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]);
582 buf_len += data_len;
561 583
562 let do_pend = state.rx_buf.is_full(); 584 let do_pend = state.rx_buf.is_full();
563 rx_reader.pop_done(len); 585 rx_reader.pop_done(data_len);
564 586
565 if do_pend { 587 if do_pend {
566 self.info.interrupt.pend(); 588 self.info.interrupt.pend();
567 } 589 }
568 590
569 return Poll::Ready(Ok(len)); 591 data = rx_reader.pop_slice();
570 } 592 }
571 593
572 state.rx_waker.register(cx.waker()); 594 if buf_len != 0 {
573 Poll::Pending 595 Poll::Ready(Ok(buf_len))
596 } else {
597 state.rx_waker.register(cx.waker());
598 Poll::Pending
599 }
574 }) 600 })
575 .await 601 .await
576 } 602 }
@@ -579,21 +605,24 @@ impl<'d> BufferedUartRx<'d> {
579 loop { 605 loop {
580 let state = self.state; 606 let state = self.state;
581 let mut rx_reader = unsafe { state.rx_buf.reader() }; 607 let mut rx_reader = unsafe { state.rx_buf.reader() };
582 let data = rx_reader.pop_slice(); 608 let mut buf_len = 0;
609 let mut data = rx_reader.pop_slice();
583 610
584 if !data.is_empty() { 611 while !data.is_empty() && buf_len < buf.len() {
585 let len = data.len().min(buf.len()); 612 let data_len = data.len().min(buf.len() - buf_len);
586 buf[..len].copy_from_slice(&data[..len]); 613 buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]);
614 buf_len += data_len;
587 615
588 let do_pend = state.rx_buf.is_full(); 616 let do_pend = state.rx_buf.is_full();
589 rx_reader.pop_done(len); 617 rx_reader.pop_done(data_len);
590 618
591 if do_pend { 619 if do_pend {
592 self.info.interrupt.pend(); 620 self.info.interrupt.pend();
593 } 621 }
594 622
595 return Ok(len); 623 data = rx_reader.pop_slice();
596 } 624 }
625 return Ok(buf_len);
597 } 626 }
598 } 627 }
599 628
@@ -633,6 +662,10 @@ impl<'d> BufferedUartRx<'d> {
633 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 662 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
634 reconfigure(self.info, self.kernel_clock, config)?; 663 reconfigure(self.info, self.kernel_clock, config)?;
635 664
665 self.state
666 .eager_reads
667 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
668
636 self.info.regs.cr1().modify(|w| { 669 self.info.regs.cr1().modify(|w| {
637 w.set_rxneie(true); 670 w.set_rxneie(true);
638 w.set_idleie(true); 671 w.set_idleie(true);
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index ff211e0c9..d2c361c61 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -4,15 +4,16 @@
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; 7use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering, compiler_fence};
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_hal_internal::drop::OnDrop;
12use embassy_hal_internal::PeripheralType; 11use embassy_hal_internal::PeripheralType;
12use embassy_hal_internal::drop::OnDrop;
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14use futures_util::future::{select, Either}; 14use futures_util::future::{Either, select};
15 15
16use crate::Peri;
16use crate::dma::ChannelAndRequest; 17use crate::dma::ChannelAndRequest;
17use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 18use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
18use crate::interrupt::typelevel::Interrupt as _; 19use crate::interrupt::typelevel::Interrupt as _;
@@ -25,7 +26,6 @@ use crate::pac::usart::Usart as Regs;
25use crate::pac::usart::{regs, vals}; 26use crate::pac::usart::{regs, vals};
26use crate::rcc::{RccInfo, SealedRccPeripheral}; 27use crate::rcc::{RccInfo, SealedRccPeripheral};
27use crate::time::Hertz; 28use crate::time::Hertz;
28use crate::Peri;
29 29
30/// Interrupt handler. 30/// Interrupt handler.
31pub struct InterruptHandler<T: Instance> { 31pub struct InterruptHandler<T: Instance> {
@@ -185,6 +185,12 @@ pub enum ConfigError {
185 RxOrTxNotEnabled, 185 RxOrTxNotEnabled,
186 /// Data bits and parity combination not supported 186 /// Data bits and parity combination not supported
187 DataParityNotSupported, 187 DataParityNotSupported,
188 /// DE assertion time too high
189 #[cfg(not(any(usart_v1, usart_v2)))]
190 DeAssertionTimeTooHigh,
191 /// DE deassertion time too high
192 #[cfg(not(any(usart_v1, usart_v2)))]
193 DeDeassertionTimeTooHigh,
188} 194}
189 195
190#[non_exhaustive] 196#[non_exhaustive]
@@ -206,6 +212,21 @@ pub struct Config {
206 /// If false: the error is ignored and cleared 212 /// If false: the error is ignored and cleared
207 pub detect_previous_overrun: bool, 213 pub detect_previous_overrun: bool,
208 214
215 /// If `None` (the default) then read-like calls on `BufferedUartRx` and `RingBufferedUartRx`
216 /// typically only wake/return after line idle or after the buffer is at least half full
217 /// (for `BufferedUartRx`) or the DMA buffer is written at the half or full positions
218 /// (for `RingBufferedUartRx`), though it may also wake/return earlier in some circumstances.
219 ///
220 /// If `Some(n)` then such reads are also woken/return as soon as at least `n` words are
221 /// available in the buffer, in addition to waking/returning when the conditions described
222 /// above are met. `Some(0)` is treated as `None`. Setting this for `RingBufferedUartRx`
223 /// will trigger an interrupt for every received word to check the buffer level, which may
224 /// impact performance at high data rates.
225 ///
226 /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either
227 /// return a single word, a full buffer, or after line idle.
228 pub eager_reads: Option<usize>,
229
209 /// Set this to true if the line is considered noise free. 230 /// Set this to true if the line is considered noise free.
210 /// This will increase the receiver’s tolerance to clock deviations, 231 /// This will increase the receiver’s tolerance to clock deviations,
211 /// but will effectively disable noise detection. 232 /// but will effectively disable noise detection.
@@ -239,6 +260,14 @@ pub struct Config {
239 /// Set the pin configuration for the DE pin. 260 /// Set the pin configuration for the DE pin.
240 pub de_config: OutputConfig, 261 pub de_config: OutputConfig,
241 262
263 /// Set DE assertion time before the first start bit, 0-31 16ths of a bit period.
264 #[cfg(not(any(usart_v1, usart_v2)))]
265 pub de_assertion_time: u8,
266
267 /// Set DE deassertion time after the last stop bit, 0-31 16ths of a bit period.
268 #[cfg(not(any(usart_v1, usart_v2)))]
269 pub de_deassertion_time: u8,
270
242 // private: set by new_half_duplex, not by the user. 271 // private: set by new_half_duplex, not by the user.
243 duplex: Duplex, 272 duplex: Duplex,
244} 273}
@@ -270,6 +299,7 @@ impl Default for Config {
270 parity: Parity::ParityNone, 299 parity: Parity::ParityNone,
271 // historical behavior 300 // historical behavior
272 detect_previous_overrun: false, 301 detect_previous_overrun: false,
302 eager_reads: None,
273 #[cfg(not(usart_v1))] 303 #[cfg(not(usart_v1))]
274 assume_noise_free: false, 304 assume_noise_free: false,
275 #[cfg(any(usart_v3, usart_v4))] 305 #[cfg(any(usart_v3, usart_v4))]
@@ -283,6 +313,10 @@ impl Default for Config {
283 tx_config: OutputConfig::PushPull, 313 tx_config: OutputConfig::PushPull,
284 rts_config: OutputConfig::PushPull, 314 rts_config: OutputConfig::PushPull,
285 de_config: OutputConfig::PushPull, 315 de_config: OutputConfig::PushPull,
316 #[cfg(not(any(usart_v1, usart_v2)))]
317 de_assertion_time: 0,
318 #[cfg(not(any(usart_v1, usart_v2)))]
319 de_deassertion_time: 0,
286 duplex: Duplex::Full, 320 duplex: Duplex::Full,
287 } 321 }
288 } 322 }
@@ -457,6 +491,8 @@ impl<'d> UartTx<'d, Async> {
457 491
458 /// Initiate an asynchronous UART write 492 /// Initiate an asynchronous UART write
459 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 493 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
494 let _scoped_block_stop = self.info.rcc.block_stop();
495
460 let r = self.info.regs; 496 let r = self.info.regs;
461 497
462 half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); 498 half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback));
@@ -474,6 +510,8 @@ impl<'d> UartTx<'d, Async> {
474 510
475 /// Wait until transmission complete 511 /// Wait until transmission complete
476 pub async fn flush(&mut self) -> Result<(), Error> { 512 pub async fn flush(&mut self) -> Result<(), Error> {
513 let _scoped_block_stop = self.info.rcc.block_stop();
514
477 flush(&self.info, &self.state).await 515 flush(&self.info, &self.state).await
478 } 516 }
479} 517}
@@ -535,7 +573,7 @@ impl<'d, M: Mode> UartTx<'d, M> {
535 let state = self.state; 573 let state = self.state;
536 state.tx_rx_refcount.store(1, Ordering::Relaxed); 574 state.tx_rx_refcount.store(1, Ordering::Relaxed);
537 575
538 info.rcc.enable_and_reset(); 576 info.rcc.enable_and_reset_without_stop();
539 577
540 info.regs.cr3().modify(|w| { 578 info.regs.cr3().modify(|w| {
541 w.set_ctse(self.cts.is_some()); 579 w.set_ctse(self.cts.is_some());
@@ -692,6 +730,8 @@ impl<'d> UartRx<'d, Async> {
692 730
693 /// Initiate an asynchronous UART read 731 /// Initiate an asynchronous UART read
694 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 732 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
733 let _scoped_block_stop = self.info.rcc.block_stop();
734
695 self.inner_read(buffer, false).await?; 735 self.inner_read(buffer, false).await?;
696 736
697 Ok(()) 737 Ok(())
@@ -699,6 +739,8 @@ impl<'d> UartRx<'d, Async> {
699 739
700 /// Initiate an asynchronous read with idle line detection enabled 740 /// Initiate an asynchronous read with idle line detection enabled
701 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 741 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
742 let _scoped_block_stop = self.info.rcc.block_stop();
743
702 self.inner_read(buffer, true).await 744 self.inner_read(buffer, true).await
703 } 745 }
704 746
@@ -966,8 +1008,11 @@ impl<'d, M: Mode> UartRx<'d, M> {
966 let info = self.info; 1008 let info = self.info;
967 let state = self.state; 1009 let state = self.state;
968 state.tx_rx_refcount.store(1, Ordering::Relaxed); 1010 state.tx_rx_refcount.store(1, Ordering::Relaxed);
1011 state
1012 .eager_reads
1013 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
969 1014
970 info.rcc.enable_and_reset(); 1015 info.rcc.enable_and_reset_without_stop();
971 1016
972 info.regs.cr3().write(|w| { 1017 info.regs.cr3().write(|w| {
973 w.set_rtse(self.rts.is_some()); 1018 w.set_rtse(self.rts.is_some());
@@ -982,6 +1027,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
982 1027
983 /// Reconfigure the driver 1028 /// Reconfigure the driver
984 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 1029 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1030 self.state
1031 .eager_reads
1032 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
985 reconfigure(self.info, self.kernel_clock, config) 1033 reconfigure(self.info, self.kernel_clock, config)
986 } 1034 }
987 1035
@@ -1103,7 +1151,7 @@ fn drop_tx_rx(info: &Info, state: &State) {
1103 refcount == 1 1151 refcount == 1
1104 }); 1152 });
1105 if is_last_drop { 1153 if is_last_drop {
1106 info.rcc.disable(); 1154 info.rcc.disable_without_stop();
1107 } 1155 }
1108} 1156}
1109 1157
@@ -1462,8 +1510,11 @@ impl<'d, M: Mode> Uart<'d, M> {
1462 let info = self.rx.info; 1510 let info = self.rx.info;
1463 let state = self.rx.state; 1511 let state = self.rx.state;
1464 state.tx_rx_refcount.store(2, Ordering::Relaxed); 1512 state.tx_rx_refcount.store(2, Ordering::Relaxed);
1513 state
1514 .eager_reads
1515 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
1465 1516
1466 info.rcc.enable_and_reset(); 1517 info.rcc.enable_and_reset_without_stop();
1467 1518
1468 info.regs.cr3().write(|w| { 1519 info.regs.cr3().write(|w| {
1469 w.set_rtse(self.rx.rts.is_some()); 1520 w.set_rtse(self.rx.rts.is_some());
@@ -1690,6 +1741,16 @@ fn configure(
1690 return Err(ConfigError::RxOrTxNotEnabled); 1741 return Err(ConfigError::RxOrTxNotEnabled);
1691 } 1742 }
1692 1743
1744 #[cfg(not(any(usart_v1, usart_v2)))]
1745 let dem = r.cr3().read().dem();
1746
1747 #[cfg(not(any(usart_v1, usart_v2)))]
1748 if config.de_assertion_time > 31 {
1749 return Err(ConfigError::DeAssertionTimeTooHigh);
1750 } else if config.de_deassertion_time > 31 {
1751 return Err(ConfigError::DeDeassertionTimeTooHigh);
1752 }
1753
1693 // UART must be disabled during configuration. 1754 // UART must be disabled during configuration.
1694 r.cr1().modify(|w| { 1755 r.cr1().modify(|w| {
1695 w.set_ue(false); 1756 w.set_ue(false);
@@ -1738,6 +1799,20 @@ fn configure(
1738 w.set_re(enable_rx); 1799 w.set_re(enable_rx);
1739 } 1800 }
1740 1801
1802 #[cfg(not(any(usart_v1, usart_v2)))]
1803 if dem {
1804 w.set_deat(if over8 {
1805 config.de_assertion_time / 2
1806 } else {
1807 config.de_assertion_time
1808 });
1809 w.set_dedt(if over8 {
1810 config.de_assertion_time / 2
1811 } else {
1812 config.de_assertion_time
1813 });
1814 }
1815
1741 // configure word size and parity, since the parity bit is inserted into the MSB position, 1816 // configure word size and parity, since the parity bit is inserted into the MSB position,
1742 // it increases the effective word size 1817 // it increases the effective word size
1743 match (config.parity, config.data_bits) { 1818 match (config.parity, config.data_bits) {
@@ -2022,6 +2097,7 @@ struct State {
2022 rx_waker: AtomicWaker, 2097 rx_waker: AtomicWaker,
2023 tx_waker: AtomicWaker, 2098 tx_waker: AtomicWaker,
2024 tx_rx_refcount: AtomicU8, 2099 tx_rx_refcount: AtomicU8,
2100 eager_reads: AtomicUsize,
2025} 2101}
2026 2102
2027impl State { 2103impl State {
@@ -2030,6 +2106,7 @@ impl State {
2030 rx_waker: AtomicWaker::new(), 2106 rx_waker: AtomicWaker::new(),
2031 tx_waker: AtomicWaker::new(), 2107 tx_waker: AtomicWaker::new(),
2032 tx_rx_refcount: AtomicU8::new(0), 2108 tx_rx_refcount: AtomicU8::new(0),
2109 eager_reads: AtomicUsize::new(0),
2033 } 2110 }
2034 } 2111 }
2035} 2112}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 5f4e87834..cc5224b69 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -1,19 +1,21 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::mem; 2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{Ordering, compiler_fence};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
7use embedded_io_async::ReadReady; 7use embedded_io_async::ReadReady;
8use futures_util::future::{select, Either}; 8use futures_util::future::{Either, select};
9 9
10use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; 10use super::{
11 Config, ConfigError, Error, Info, State, UartRx, clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr,
12};
13use crate::Peri;
11use crate::dma::ReadableRingBuffer; 14use crate::dma::ReadableRingBuffer;
12use crate::gpio::{AnyPin, SealedPin as _}; 15use crate::gpio::{AnyPin, SealedPin as _};
13use crate::mode::Async; 16use crate::mode::Async;
14use crate::time::Hertz; 17use crate::time::Hertz;
15use crate::usart::Regs; 18use crate::usart::Regs;
16use crate::Peri;
17 19
18/// Rx-only Ring-buffered UART Driver 20/// Rx-only Ring-buffered UART Driver
19/// 21///
@@ -26,9 +28,9 @@ use crate::Peri;
26/// contain enough bytes to fill the buffer passed by the caller of 28/// contain enough bytes to fill the buffer passed by the caller of
27/// the function, or is empty. 29/// the function, or is empty.
28/// 30///
29/// Waiting for bytes operates in one of two modes, depending on 31/// Waiting for bytes operates in one of three modes, depending on
30/// the behavior of the sender and the size of the buffer passed 32/// the behavior of the sender, the size of the buffer passed
31/// to the function: 33/// to the function, and the configuration:
32/// 34///
33/// - If the sender sends intermittently, the 'idle line' 35/// - If the sender sends intermittently, the 'idle line'
34/// condition will be detected when the sender stops, and any 36/// condition will be detected when the sender stops, and any
@@ -47,7 +49,11 @@ use crate::Peri;
47/// interrupt when those specific buffer addresses have been 49/// interrupt when those specific buffer addresses have been
48/// written. 50/// written.
49/// 51///
50/// In both cases this will result in variable latency due to the 52/// - If `eager_reads` is enabled in `config`, the UART interrupt
53/// is enabled on all data reception and the call will only wait
54/// for at least one byte to be available before returning.
55///
56/// In the first two cases this will result in variable latency due to the
51/// buffering effect. For example, if the baudrate is 2400 bps, and 57/// buffering effect. For example, if the baudrate is 2400 bps, and
52/// the configuration is 8 data bits, no parity bit, and one stop bit, 58/// the configuration is 8 data bits, no parity bit, and one stop bit,
53/// then a byte will be received every ~4.16ms. If the ring buffer is 59/// then a byte will be received every ~4.16ms. If the ring buffer is
@@ -68,15 +74,10 @@ use crate::Peri;
68/// sending, but would be falsely triggered in the worst-case 74/// sending, but would be falsely triggered in the worst-case
69/// buffer delay scenario. 75/// buffer delay scenario.
70/// 76///
71/// Note: This latency is caused by the limited capabilities of the 77/// Note: Enabling `eager_reads` with `RingBufferedUartRx` will enable
72/// STM32 DMA controller; since it cannot generate an interrupt when 78/// an UART RXNE interrupt, which will cause an interrupt to occur on
73/// it stores a byte into an empty ring buffer, or in any other 79/// every received data byte. The data is still copied using DMA, but
74/// configurable conditions, it is not possible to take notice of the 80/// there is nevertheless additional processing overhead for each byte.
75/// contents of the ring buffer more quickly without introducing
76/// polling. As a result the latency can be reduced by calling the
77/// read functions repeatedly with smaller buffers to receive the
78/// available bytes, as each call to a read function will explicitly
79/// check the ring buffer for available bytes.
80pub struct RingBufferedUartRx<'d> { 81pub struct RingBufferedUartRx<'d> {
81 info: &'static Info, 82 info: &'static Info,
82 state: &'static State, 83 state: &'static State,
@@ -116,6 +117,8 @@ impl<'d> UartRx<'d, Async> {
116 let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) }; 117 let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) };
117 let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) }; 118 let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) };
118 119
120 info.rcc.increment_stop_refcount();
121
119 // Don't disable the clock 122 // Don't disable the clock
120 mem::forget(self); 123 mem::forget(self);
121 124
@@ -133,6 +136,9 @@ impl<'d> UartRx<'d, Async> {
133impl<'d> RingBufferedUartRx<'d> { 136impl<'d> RingBufferedUartRx<'d> {
134 /// Reconfigure the driver 137 /// Reconfigure the driver
135 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 138 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
139 self.state
140 .eager_reads
141 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
136 reconfigure(self.info, self.kernel_clock, config) 142 reconfigure(self.info, self.kernel_clock, config)
137 } 143 }
138 144
@@ -148,8 +154,8 @@ impl<'d> RingBufferedUartRx<'d> {
148 let r = self.info.regs; 154 let r = self.info.regs;
149 // clear all interrupts and DMA Rx Request 155 // clear all interrupts and DMA Rx Request
150 r.cr1().modify(|w| { 156 r.cr1().modify(|w| {
151 // disable RXNE interrupt 157 // use RXNE only when returning reads early
152 w.set_rxneie(false); 158 w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed) > 0);
153 // enable parity interrupt if not ParityNone 159 // enable parity interrupt if not ParityNone
154 w.set_peie(w.pce()); 160 w.set_peie(w.pce());
155 // enable idle line interrupt 161 // enable idle line interrupt
@@ -248,39 +254,67 @@ impl<'d> RingBufferedUartRx<'d> {
248 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { 254 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> {
249 compiler_fence(Ordering::SeqCst); 255 compiler_fence(Ordering::SeqCst);
250 256
251 // Future which completes when idle line is detected 257 loop {
252 let s = self.state; 258 // Future which completes when idle line is detected
253 let uart = poll_fn(|cx| { 259 let s = self.state;
254 s.rx_waker.register(cx.waker()); 260 let mut uart_init = false;
255 261 let uart = poll_fn(|cx| {
256 compiler_fence(Ordering::SeqCst); 262 s.rx_waker.register(cx.waker());
257 263
258 if check_idle_and_errors(self.info.regs)? { 264 compiler_fence(Ordering::SeqCst);
259 // Idle line is detected 265
260 Poll::Ready(Ok(())) 266 // We may have been woken by IDLE or, if eager_reads is set, by RXNE.
261 } else { 267 // However, DMA will clear RXNE, so we can't check directly, and because
262 Poll::Pending 268 // the other future borrows `ring_buf`, we can't check `len()` here either.
263 } 269 // Instead, return from this future and we'll check the length afterwards.
264 }); 270 let eager = s.eager_reads.load(Ordering::Relaxed) > 0;
271
272 let idle = check_idle_and_errors(self.info.regs)?;
273 if idle || (eager && uart_init) {
274 // Idle line is detected, or eager reads is set and some data is available.
275 Poll::Ready(Ok(idle))
276 } else {
277 uart_init = true;
278 Poll::Pending
279 }
280 });
265 281
266 let mut dma_init = false; 282 let mut dma_init = false;
267 // Future which completes when the DMA controller indicates it 283 // Future which completes when the DMA controller indicates it
268 // has written to the ring buffer's middle byte, or last byte 284 // has written to the ring buffer's middle byte, or last byte
269 let dma = poll_fn(|cx| { 285 let dma = poll_fn(|cx| {
270 self.ring_buf.set_waker(cx.waker()); 286 self.ring_buf.set_waker(cx.waker());
271 287
272 let status = match dma_init { 288 let status = match dma_init {
273 false => Poll::Pending, 289 false => Poll::Pending,
274 true => Poll::Ready(()), 290 true => Poll::Ready(()),
275 }; 291 };
276 292
277 dma_init = true; 293 dma_init = true;
278 status 294 status
279 }); 295 });
280 296
281 match select(uart, dma).await { 297 match select(uart, dma).await {
282 Either::Left((result, _)) => result, 298 // UART woke with line idle
283 Either::Right(((), _)) => Ok(()), 299 Either::Left((Ok(true), _)) => {
300 return Ok(());
301 }
302 // UART woke without idle or error: word received
303 Either::Left((Ok(false), _)) => {
304 let eager = self.state.eager_reads.load(Ordering::Relaxed);
305 if eager > 0 && self.ring_buf.len().unwrap_or(0) >= eager {
306 return Ok(());
307 } else {
308 continue;
309 }
310 }
311 // UART woke with error
312 Either::Left((Err(e), _)) => {
313 return Err(e);
314 }
315 // DMA woke
316 Either::Right(((), _)) => return Ok(()),
317 }
284 } 318 }
285 } 319 }
286 320
@@ -292,6 +326,7 @@ impl<'d> RingBufferedUartRx<'d> {
292 326
293impl Drop for RingBufferedUartRx<'_> { 327impl Drop for RingBufferedUartRx<'_> {
294 fn drop(&mut self) { 328 fn drop(&mut self) {
329 self.info.rcc.decrement_stop_refcount();
295 self.stop_uart(); 330 self.stop_uart();
296 self.rx.as_ref().map(|x| x.set_as_disconnected()); 331 self.rx.as_ref().map(|x| x.set_as_disconnected());
297 self.rts.as_ref().map(|x| x.set_as_disconnected()); 332 self.rts.as_ref().map(|x| x.set_as_disconnected());
@@ -308,26 +343,16 @@ impl Drop for RingBufferedUartRx<'_> {
308/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags 343/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags
309/// are cleared by a single read to the RDR register. 344/// are cleared by a single read to the RDR register.
310fn check_idle_and_errors(r: Regs) -> Result<bool, Error> { 345fn check_idle_and_errors(r: Regs) -> Result<bool, Error> {
311 // Critical section is required so that the flags aren't set after read and before clear 346 // SAFETY: read only and we only use Rx related flags
312 let sr = critical_section::with(|_| { 347 let sr = sr(r).read();
313 // SAFETY: read only and we only use Rx related flags 348
314 let sr = sr(r).read(); 349 #[cfg(not(any(usart_v3, usart_v4)))]
315 350 unsafe {
316 #[cfg(any(usart_v3, usart_v4))] 351 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
317 r.icr().write(|w| { 352 rdr(r).read_volatile()
318 w.set_idle(true); 353 };
319 w.set_pe(true); 354 clear_interrupt_flags(r, sr);
320 w.set_fe(true); 355
321 w.set_ne(true);
322 w.set_ore(true);
323 });
324 #[cfg(not(any(usart_v3, usart_v4)))]
325 unsafe {
326 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
327 rdr(r).read_volatile()
328 };
329 sr
330 });
331 if sr.pe() { 356 if sr.pe() {
332 Err(Error::Parity) 357 Err(Error::Parity)
333 } else if sr.fe() { 358 } else if sr.fe() {
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 5ce81b131..f6b1a81db 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -2,18 +2,18 @@ use core::marker::PhantomData;
2 2
3use embassy_hal_internal::PeripheralType; 3use embassy_hal_internal::PeripheralType;
4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported}; 4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported};
5use embassy_usb_synopsys_otg::otg_v1::vals::Dspd;
6use embassy_usb_synopsys_otg::otg_v1::Otg;
7pub use embassy_usb_synopsys_otg::Config; 5pub use embassy_usb_synopsys_otg::Config;
6use embassy_usb_synopsys_otg::otg_v1::Otg;
7use embassy_usb_synopsys_otg::otg_v1::vals::Dspd;
8use embassy_usb_synopsys_otg::{ 8use embassy_usb_synopsys_otg::{
9 on_interrupt as on_interrupt_impl, Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, 9 Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, PhyType, State,
10 PhyType, State, 10 on_interrupt as on_interrupt_impl,
11}; 11};
12 12
13use crate::gpio::{AfType, OutputType, Speed}; 13use crate::gpio::{AfType, OutputType, Speed};
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::rcc::{self, RccPeripheral}; 15use crate::rcc::{self, RccPeripheral};
16use crate::{interrupt, Peri}; 16use crate::{Peri, interrupt};
17 17
18const MAX_EP_COUNT: usize = 9; 18const MAX_EP_COUNT: usize = 9;
19 19
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 9e08d99b3..d405e4802 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -12,11 +12,11 @@ use embassy_usb_driver::{
12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, 12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
13}; 13};
14 14
15use crate::pac::USBRAM;
15use crate::pac::usb::regs; 16use crate::pac::usb::regs;
16use crate::pac::usb::vals::{EpType, Stat}; 17use crate::pac::usb::vals::{EpType, Stat};
17use crate::pac::USBRAM;
18use crate::rcc::RccPeripheral; 18use crate::rcc::RccPeripheral;
19use crate::{interrupt, Peri}; 19use crate::{Peri, interrupt};
20 20
21/// Interrupt handler. 21/// Interrupt handler.
22pub struct InterruptHandler<T: Instance> { 22pub struct InterruptHandler<T: Instance> {
diff --git a/embassy-stm32/src/vrefbuf/mod.rs b/embassy-stm32/src/vrefbuf/mod.rs
index ccbd748d5..43dd9c800 100644
--- a/embassy-stm32/src/vrefbuf/mod.rs
+++ b/embassy-stm32/src/vrefbuf/mod.rs
@@ -14,10 +14,10 @@ pub struct VoltageReferenceBuffer<'d, T: Instance> {
14#[cfg(rcc_wba)] 14#[cfg(rcc_wba)]
15fn get_refbuf_trim(voltage_scale: Vrs) -> usize { 15fn get_refbuf_trim(voltage_scale: Vrs) -> usize {
16 match voltage_scale { 16 match voltage_scale {
17 Vrs::VREF0 => 0x0BFA_07A8usize, 17 Vrs::VREF0 => 0x0BFA_07ABusize,
18 Vrs::VREF1 => 0x0BFA_07A9usize, 18 Vrs::VREF1 => 0x0BFA_07AAusize,
19 Vrs::VREF2 => 0x0BFA_07AAusize, 19 Vrs::VREF2 => 0x0BFA_07A9usize,
20 Vrs::VREF3 => 0x0BFA_07ABusize, 20 Vrs::VREF3 => 0x0BFA_07A8usize,
21 _ => panic!("Incorrect Vrs setting!"), 21 _ => panic!("Incorrect Vrs setting!"),
22 } 22 }
23} 23}
@@ -62,8 +62,7 @@ impl<'d, T: Instance> VoltageReferenceBuffer<'d, T> {
62 } 62 }
63 trace!( 63 trace!(
64 "Vrefbuf configured with voltage scale {} and impedance mode {}", 64 "Vrefbuf configured with voltage scale {} and impedance mode {}",
65 voltage_scale as u8, 65 voltage_scale as u8, impedance_mode as u8,
66 impedance_mode as u8,
67 ); 66 );
68 VoltageReferenceBuffer { vrefbuf: PhantomData } 67 VoltageReferenceBuffer { vrefbuf: PhantomData }
69 } 68 }
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index fb5c3d930..1164739ff 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -4,8 +4,8 @@ use core::marker::PhantomData;
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5use stm32_metapac::iwdg::vals::{Key, Pr}; 5use stm32_metapac::iwdg::vals::{Key, Pr};
6 6
7use crate::rcc::LSI_FREQ;
8use crate::Peri; 7use crate::Peri;
8use crate::rcc::LSI_FREQ;
9 9
10/// Independent watchdog (IWDG) driver. 10/// Independent watchdog (IWDG) driver.
11pub struct IndependentWatchdog<'d, T: Instance> { 11pub struct IndependentWatchdog<'d, T: Instance> {
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs
index 901569f64..466e1a9b4 100644
--- a/embassy-stm32/src/xspi/mod.rs
+++ b/embassy-stm32/src/xspi/mod.rs
@@ -11,15 +11,15 @@ use embassy_embedded_hal::{GetConfig, SetConfig};
11use embassy_hal_internal::PeripheralType; 11use embassy_hal_internal::PeripheralType;
12pub use enums::*; 12pub use enums::*;
13 13
14use crate::dma::{word, ChannelAndRequest}; 14use crate::dma::{ChannelAndRequest, word};
15use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 15use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
16use crate::mode::{Async, Blocking, Mode as PeriMode}; 16use crate::mode::{Async, Blocking, Mode as PeriMode};
17use crate::pac::xspi::vals::*;
18use crate::pac::xspi::Xspi as Regs; 17use crate::pac::xspi::Xspi as Regs;
18use crate::pac::xspi::vals::*;
19#[cfg(xspim_v1)] 19#[cfg(xspim_v1)]
20use crate::pac::xspim::Xspim; 20use crate::pac::xspim::Xspim;
21use crate::rcc::{self, RccPeripheral}; 21use crate::rcc::{self, RccPeripheral};
22use crate::{peripherals, Peri}; 22use crate::{Peri, peripherals};
23 23
24/// XPSI driver config. 24/// XPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
@@ -420,9 +420,9 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
420 return Err(XspiError::InvalidCommand); 420 return Err(XspiError::InvalidCommand);
421 } 421 }
422 422
423 T::REGS.cr().modify(|w| { 423 T::REGS
424 w.set_fmode(0.into()); 424 .cr()
425 }); 425 .modify(|w| w.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
426 426
427 // Configure alternate bytes 427 // Configure alternate bytes
428 if let Some(ab) = command.alternate_bytes { 428 if let Some(ab) = command.alternate_bytes {
@@ -538,8 +538,8 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
538 w.set_dmaen(false); 538 w.set_dmaen(false);
539 }); 539 });
540 540
541 // self.configure_command(&transaction, Some(buf.len()))?; 541 let transfer_size_bytes = buf.len() * W::size().bytes();
542 self.configure_command(&transaction, Some(buf.len())).unwrap(); 542 self.configure_command(&transaction, Some(transfer_size_bytes))?;
543 543
544 let current_address = T::REGS.ar().read().address(); 544 let current_address = T::REGS.ar().read().address();
545 let current_instruction = T::REGS.ir().read().instruction(); 545 let current_instruction = T::REGS.ir().read().instruction();
@@ -578,7 +578,8 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
578 w.set_dmaen(false); 578 w.set_dmaen(false);
579 }); 579 });
580 580
581 self.configure_command(&transaction, Some(buf.len()))?; 581 let transfer_size_bytes = buf.len() * W::size().bytes();
582 self.configure_command(&transaction, Some(transfer_size_bytes))?;
582 583
583 T::REGS 584 T::REGS
584 .cr() 585 .cr()
@@ -1145,7 +1146,8 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
1145 // Wait for peripheral to be free 1146 // Wait for peripheral to be free
1146 while T::REGS.sr().read().busy() {} 1147 while T::REGS.sr().read().busy() {}
1147 1148
1148 self.configure_command(&transaction, Some(buf.len()))?; 1149 let transfer_size_bytes = buf.len() * W::size().bytes();
1150 self.configure_command(&transaction, Some(transfer_size_bytes))?;
1149 1151
1150 let current_address = T::REGS.ar().read().address(); 1152 let current_address = T::REGS.ar().read().address();
1151 let current_instruction = T::REGS.ir().read().instruction(); 1153 let current_instruction = T::REGS.ir().read().instruction();
@@ -1160,16 +1162,18 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
1160 T::REGS.ar().write(|v| v.set_address(current_address)); 1162 T::REGS.ar().write(|v| v.set_address(current_address));
1161 } 1163 }
1162 1164
1163 let transfer = unsafe { 1165 for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
1164 self.dma 1166 let transfer = unsafe {
1165 .as_mut() 1167 self.dma
1166 .unwrap() 1168 .as_mut()
1167 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) 1169 .unwrap()
1168 }; 1170 .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
1171 };
1169 1172
1170 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1173 T::REGS.cr().modify(|w| w.set_dmaen(true));
1171 1174
1172 transfer.blocking_wait(); 1175 transfer.blocking_wait();
1176 }
1173 1177
1174 finish_dma(T::REGS); 1178 finish_dma(T::REGS);
1175 1179
@@ -1185,21 +1189,24 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
1185 // Wait for peripheral to be free 1189 // Wait for peripheral to be free
1186 while T::REGS.sr().read().busy() {} 1190 while T::REGS.sr().read().busy() {}
1187 1191
1188 self.configure_command(&transaction, Some(buf.len()))?; 1192 let transfer_size_bytes = buf.len() * W::size().bytes();
1193 self.configure_command(&transaction, Some(transfer_size_bytes))?;
1189 T::REGS 1194 T::REGS
1190 .cr() 1195 .cr()
1191 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); 1196 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
1192 1197
1193 let transfer = unsafe { 1198 for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
1194 self.dma 1199 let transfer = unsafe {
1195 .as_mut() 1200 self.dma
1196 .unwrap() 1201 .as_mut()
1197 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) 1202 .unwrap()
1198 }; 1203 .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
1204 };
1199 1205
1200 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1206 T::REGS.cr().modify(|w| w.set_dmaen(true));
1201 1207
1202 transfer.blocking_wait(); 1208 transfer.blocking_wait();
1209 }
1203 1210
1204 finish_dma(T::REGS); 1211 finish_dma(T::REGS);
1205 1212
@@ -1215,7 +1222,8 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
1215 // Wait for peripheral to be free 1222 // Wait for peripheral to be free
1216 while T::REGS.sr().read().busy() {} 1223 while T::REGS.sr().read().busy() {}
1217 1224
1218 self.configure_command(&transaction, Some(buf.len()))?; 1225 let transfer_size_bytes = buf.len() * W::size().bytes();
1226 self.configure_command(&transaction, Some(transfer_size_bytes))?;
1219 1227
1220 let current_address = T::REGS.ar().read().address(); 1228 let current_address = T::REGS.ar().read().address();
1221 let current_instruction = T::REGS.ir().read().instruction(); 1229 let current_instruction = T::REGS.ir().read().instruction();
@@ -1230,16 +1238,18 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
1230 T::REGS.ar().write(|v| v.set_address(current_address)); 1238 T::REGS.ar().write(|v| v.set_address(current_address));
1231 } 1239 }
1232 1240
1233 let transfer = unsafe { 1241 for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
1234 self.dma 1242 let transfer = unsafe {
1235 .as_mut() 1243 self.dma
1236 .unwrap() 1244 .as_mut()
1237 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) 1245 .unwrap()
1238 }; 1246 .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
1247 };
1239 1248
1240 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1249 T::REGS.cr().modify(|w| w.set_dmaen(true));
1241 1250
1242 transfer.await; 1251 transfer.await;
1252 }
1243 1253
1244 finish_dma(T::REGS); 1254 finish_dma(T::REGS);
1245 1255
@@ -1255,21 +1265,25 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
1255 // Wait for peripheral to be free 1265 // Wait for peripheral to be free
1256 while T::REGS.sr().read().busy() {} 1266 while T::REGS.sr().read().busy() {}
1257 1267
1258 self.configure_command(&transaction, Some(buf.len()))?; 1268 let transfer_size_bytes = buf.len() * W::size().bytes();
1269 self.configure_command(&transaction, Some(transfer_size_bytes))?;
1259 T::REGS 1270 T::REGS
1260 .cr() 1271 .cr()
1261 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); 1272 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
1262 1273
1263 let transfer = unsafe { 1274 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
1264 self.dma 1275 for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
1265 .as_mut() 1276 let transfer = unsafe {
1266 .unwrap() 1277 self.dma
1267 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) 1278 .as_mut()
1268 }; 1279 .unwrap()
1280 .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
1281 };
1269 1282
1270 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1283 T::REGS.cr().modify(|w| w.set_dmaen(true));
1271 1284
1272 transfer.await; 1285 transfer.await;
1286 }
1273 1287
1274 finish_dma(T::REGS); 1288 finish_dma(T::REGS);
1275 1289