aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorElias Hanelt <[email protected]>2025-11-25 13:18:00 -0800
committerElias Hanelt <[email protected]>2025-11-25 13:18:00 -0800
commit2b219b7cb59ec3e4370edc88538ea3ea996f37b9 (patch)
treec602a4b7c39d50ada628f2d715c6cc59f2e35c3a /embassy-stm32/src
parent576fb23faabf6df7f2c9ed2039e94d3586a3788f (diff)
parent906eaee53f84381dd10583894edf2de67275f083 (diff)
Merge remote-tracking branch 'origin/main' into feature/spi-bidi
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/adc/adc4.rs482
-rw-r--r--embassy-stm32/src/adc/c0.rs493
-rw-r--r--embassy-stm32/src/adc/f1.rs4
-rw-r--r--embassy-stm32/src/adc/f3.rs2
-rw-r--r--embassy-stm32/src/adc/g4.rs716
-rw-r--r--embassy-stm32/src/adc/injected.rs6
-rw-r--r--embassy-stm32/src/adc/mod.rs301
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs14
-rw-r--r--embassy-stm32/src/adc/v2.rs309
-rw-r--r--embassy-stm32/src/adc/v3.rs885
-rw-r--r--embassy-stm32/src/adc/v4.rs493
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs16
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs13
-rw-r--r--embassy-stm32/src/dma/gpdma/ringbuffered.rs10
-rw-r--r--embassy-stm32/src/dma/mod.rs66
-rw-r--r--embassy-stm32/src/dsihost.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.rs259
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs197
-rw-r--r--embassy-stm32/src/exti.rs137
-rw-r--r--embassy-stm32/src/flash/c.rs131
-rw-r--r--embassy-stm32/src/flash/common.rs8
-rw-r--r--embassy-stm32/src/flash/g.rs5
-rw-r--r--embassy-stm32/src/flash/h7.rs190
-rw-r--r--embassy-stm32/src/flash/mod.rs7
-rw-r--r--embassy-stm32/src/gpio.rs21
-rw-r--r--embassy-stm32/src/hsem/mod.rs285
-rw-r--r--embassy-stm32/src/hspi/mod.rs93
-rw-r--r--embassy-stm32/src/i2c/v2.rs713
-rw-r--r--embassy-stm32/src/ipcc.rs250
-rw-r--r--embassy-stm32/src/lcd.rs510
-rw-r--r--embassy-stm32/src/lib.rs28
-rw-r--r--embassy-stm32/src/low_power.rs237
-rw-r--r--embassy-stm32/src/opamp.rs13
-rw-r--r--embassy-stm32/src/ospi/mod.rs60
-rw-r--r--embassy-stm32/src/rcc/l.rs43
-rw-r--r--embassy-stm32/src/rcc/mod.rs93
-rw-r--r--embassy-stm32/src/rtc/low_power.rs69
-rw-r--r--embassy-stm32/src/rtc/mod.rs7
-rw-r--r--embassy-stm32/src/sai/mod.rs4
-rw-r--r--embassy-stm32/src/time_driver.rs109
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs108
-rw-r--r--embassy-stm32/src/timer/input_capture.rs1
-rw-r--r--embassy-stm32/src/timer/low_level.rs181
-rw-r--r--embassy-stm32/src/timer/mod.rs1
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs1
-rw-r--r--embassy-stm32/src/timer/ringbuffered.rs169
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs274
-rw-r--r--embassy-stm32/src/usart/buffered.rs2
-rw-r--r--embassy-stm32/src/xspi/mod.rs98
54 files changed, 4886 insertions, 3576 deletions
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index befa8ed4a..453513309 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::{AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel, blocking_delay_us}; 7use super::blocking_delay_us;
8use crate::dma::Transfer; 8use crate::adc::ConversionMode;
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)]
@@ -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<'d, T: Instance> super::SealedSpecialConverter<super::VrefInt> for Adc4<'d, T> {
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<'d, T: Instance> super::SealedSpecialConverter<super::Temperature> for Adc4<'d, T> {
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<'d, T: Instance> super::SealedSpecialConverter<super::Vcore> for Adc4<'d, T> {
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<'d, T: Instance> super::SealedSpecialConverter<super::Vbat> for Adc4<'d, T> {
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<'d, T: Instance> super::SealedSpecialConverter<super::Dac> for Adc4<'d, T> {
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,71 +76,17 @@ 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,
123 DividedBy32,
124 DividedBy64,
125 DividedBy128,
126 DividedBy256,
127}
128
129impl Prescaler {
130 fn from_ker_ck(frequency: Hertz) -> Self {
131 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
132 match raw_prescaler {
133 0 => Self::NotDivided,
134 1 => Self::DividedBy2,
135 2..=3 => Self::DividedBy4,
136 4..=5 => Self::DividedBy6,
137 6..=7 => Self::DividedBy8,
138 8..=9 => Self::DividedBy10,
139 10..=11 => Self::DividedBy12,
140 _ => unimplemented!(),
141 }
142 }
143
144 fn divisor(&self) -> u32 {
145 match self {
146 Prescaler::NotDivided => 1,
147 Prescaler::DividedBy2 => 2,
148 Prescaler::DividedBy4 => 4,
149 Prescaler::DividedBy6 => 6,
150 Prescaler::DividedBy8 => 8,
151 Prescaler::DividedBy10 => 10,
152 Prescaler::DividedBy12 => 12,
153 Prescaler::DividedBy16 => 16,
154 Prescaler::DividedBy32 => 32,
155 Prescaler::DividedBy64 => 64,
156 Prescaler::DividedBy128 => 128,
157 Prescaler::DividedBy256 => 256,
158 }
159 }
160
161 fn presc(&self) -> Presc {
162 match self {
163 Prescaler::NotDivided => Presc::DIV1,
164 Prescaler::DividedBy2 => Presc::DIV2,
165 Prescaler::DividedBy4 => Presc::DIV4,
166 Prescaler::DividedBy6 => Presc::DIV6,
167 Prescaler::DividedBy8 => Presc::DIV8,
168 Prescaler::DividedBy10 => Presc::DIV10,
169 Prescaler::DividedBy12 => Presc::DIV12,
170 Prescaler::DividedBy16 => Presc::DIV16,
171 Prescaler::DividedBy32 => Presc::DIV32,
172 Prescaler::DividedBy64 => Presc::DIV64,
173 Prescaler::DividedBy128 => Presc::DIV128,
174 Prescaler::DividedBy256 => Presc::DIV256,
175 }
176 } 90 }
177} 91}
178 92
@@ -185,6 +99,127 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri
185 type Interrupt: crate::interrupt::typelevel::Interrupt; 99 type Interrupt: crate::interrupt::typelevel::Interrupt;
186} 100}
187 101
102foreach_adc!(
103 (ADC4, $common_inst:ident, $clock:ident) => {
104 use crate::peripherals::ADC4;
105
106 impl super::BasicAnyInstance for ADC4 {
107 type SampleTime = SampleTime;
108 }
109
110 impl super::SealedAnyInstance for ADC4 {
111 fn dr() -> *mut u16 {
112 ADC4::regs().dr().as_ptr() as *mut u16
113 }
114
115 fn enable() {
116 if !ADC4::regs().cr().read().aden() || !ADC4::regs().isr().read().adrdy() {
117 ADC4::regs().isr().write(|w| w.set_adrdy(true));
118 ADC4::regs().cr().modify(|w| w.set_aden(true));
119 while !ADC4::regs().isr().read().adrdy() {}
120 }
121 }
122
123 fn start() {
124 // Start conversion
125 ADC4::regs().cr().modify(|reg| {
126 reg.set_adstart(true);
127 });
128 }
129
130 fn stop() {
131 let cr = ADC4::regs().cr().read();
132 if cr.adstart() {
133 ADC4::regs().cr().modify(|w| w.set_adstp(true));
134 while ADC4::regs().cr().read().adstart() {}
135 }
136
137 if cr.aden() || cr.adstart() {
138 ADC4::regs().cr().modify(|w| w.set_addis(true));
139 while ADC4::regs().cr().read().aden() {}
140 }
141
142 // Reset configuration.
143 ADC4::regs().cfgr1().modify(|reg| {
144 reg.set_dmaen(false);
145 });
146 }
147
148 fn configure_dma(conversion_mode: ConversionMode) {
149 match conversion_mode {
150 ConversionMode::Singular => {
151 ADC4::regs().isr().modify(|reg| {
152 reg.set_ovr(true);
153 reg.set_eos(true);
154 reg.set_eoc(true);
155 });
156
157 ADC4::regs().cfgr1().modify(|reg| {
158 reg.set_dmaen(true);
159 reg.set_dmacfg(Dmacfg::ONE_SHOT);
160 #[cfg(stm32u5)]
161 reg.set_chselrmod(false);
162 #[cfg(stm32wba)]
163 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
164 });
165 }
166 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
167 _ => unreachable!(),
168 }
169 }
170
171 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
172 let mut prev_channel: i16 = -1;
173 #[cfg(stm32wba)]
174 ADC4::regs().chselr().write_value(Chselr(0_u32));
175 #[cfg(stm32u5)]
176 ADC4::regs().chselrmod0().write_value(Chselr(0_u32));
177 for (_i, ((channel, _), sample_time)) in sequence.enumerate() {
178 ADC4::regs().smpr().modify(|w| {
179 w.set_smp(_i, sample_time);
180 });
181
182 let channel_num = channel;
183 if channel_num as i16 <= prev_channel {
184 return;
185 };
186 prev_channel = channel_num as i16;
187
188 #[cfg(stm32wba)]
189 ADC4::regs().chselr().modify(|w| {
190 w.set_chsel0(channel as usize, true);
191 });
192 #[cfg(stm32u5)]
193 ADC4::regs().chselrmod0().modify(|w| {
194 w.set_chsel(channel as usize, true);
195 });
196 }
197 }
198
199 fn convert() -> u16 {
200 // Reset interrupts
201 ADC4::regs().isr().modify(|reg| {
202 reg.set_eos(true);
203 reg.set_eoc(true);
204 });
205
206 // Start conversion
207 ADC4::regs().cr().modify(|reg| {
208 reg.set_adstart(true);
209 });
210
211 while !ADC4::regs().isr().read().eos() {
212 // spin
213 }
214
215 ADC4::regs().dr().read().0 as u16
216 }
217 }
218
219 impl super::AnyInstance for ADC4 {}
220 };
221);
222
188pub struct Adc4<'d, T: Instance> { 223pub struct Adc4<'d, T: Instance> {
189 #[allow(unused)] 224 #[allow(unused)]
190 adc: crate::Peri<'d, T>, 225 adc: crate::Peri<'d, T>,
@@ -196,15 +231,15 @@ pub enum Adc4Error {
196 DMAError, 231 DMAError,
197} 232}
198 233
199impl<'d, T: Instance> Adc4<'d, T> { 234impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> {
200 /// Create a new ADC driver. 235 /// Create a new ADC driver.
201 pub fn new(adc: Peri<'d, T>) -> Self { 236 pub fn new_adc4(adc: Peri<'d, T>) -> Self {
202 rcc::enable_and_reset::<T>(); 237 rcc::enable_and_reset::<T>();
203 let prescaler = Prescaler::from_ker_ck(T::frequency()); 238 let prescaler = from_ker_ck(T::frequency());
204 239
205 T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 240 T::regs().ccr().modify(|w| w.set_presc(prescaler));
206 241
207 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 242 let frequency = T::frequency() / prescaler;
208 info!("ADC4 frequency set to {}", frequency); 243 info!("ADC4 frequency set to {}", frequency);
209 244
210 if frequency > MAX_ADC_CLK_FREQ { 245 if frequency > MAX_ADC_CLK_FREQ {
@@ -214,20 +249,6 @@ impl<'d, T: Instance> Adc4<'d, T> {
214 ); 249 );
215 } 250 }
216 251
217 let mut s = Self { adc };
218
219 s.power_up();
220
221 s.calibrate();
222 blocking_delay_us(1);
223
224 s.enable();
225 s.configure();
226
227 s
228 }
229
230 fn power_up(&mut self) {
231 T::regs().isr().modify(|w| { 252 T::regs().isr().modify(|w| {
232 w.set_ldordy(true); 253 w.set_ldordy(true);
233 }); 254 });
@@ -239,22 +260,15 @@ impl<'d, T: Instance> Adc4<'d, T> {
239 T::regs().isr().modify(|w| { 260 T::regs().isr().modify(|w| {
240 w.set_ldordy(true); 261 w.set_ldordy(true);
241 }); 262 });
242 }
243 263
244 fn calibrate(&mut self) {
245 T::regs().cr().modify(|w| w.set_adcal(true)); 264 T::regs().cr().modify(|w| w.set_adcal(true));
246 while T::regs().cr().read().adcal() {} 265 while T::regs().cr().read().adcal() {}
247 T::regs().isr().modify(|w| w.set_eocal(true)); 266 T::regs().isr().modify(|w| w.set_eocal(true));
248 }
249 267
250 fn enable(&mut self) { 268 blocking_delay_us(1);
251 T::regs().isr().write(|w| w.set_adrdy(true)); 269
252 T::regs().cr().modify(|w| w.set_aden(true)); 270 T::enable();
253 while !T::regs().isr().read().adrdy() {}
254 T::regs().isr().write(|w| w.set_adrdy(true));
255 }
256 271
257 fn configure(&mut self) {
258 // single conversion mode, software trigger 272 // single conversion mode, software trigger
259 T::regs().cfgr1().modify(|w| { 273 T::regs().cfgr1().modify(|w| {
260 #[cfg(stm32u5)] 274 #[cfg(stm32u5)]
@@ -280,61 +294,63 @@ impl<'d, T: Instance> Adc4<'d, T> {
280 w.set_smpsel(i, Smpsel::SMP1); 294 w.set_smpsel(i, Smpsel::SMP1);
281 } 295 }
282 }); 296 });
297
298 Self { adc }
283 } 299 }
284 300
285 /// Enable reading the voltage reference internal channel. 301 /// Enable reading the voltage reference internal channel.
286 pub fn enable_vrefint(&self) -> VrefInt { 302 pub fn enable_vrefint_adc4(&self) -> super::VrefInt {
287 T::regs().ccr().modify(|w| { 303 T::regs().ccr().modify(|w| {
288 w.set_vrefen(true); 304 w.set_vrefen(true);
289 }); 305 });
290 306
291 VrefInt {} 307 super::VrefInt {}
292 } 308 }
293 309
294 /// Enable reading the temperature internal channel. 310 /// Enable reading the temperature internal channel.
295 pub fn enable_temperature(&self) -> Temperature { 311 pub fn enable_temperature_adc4(&self) -> super::Temperature {
296 T::regs().ccr().modify(|w| { 312 T::regs().ccr().modify(|w| {
297 w.set_vsensesel(true); 313 w.set_vsensesel(true);
298 }); 314 });
299 315
300 Temperature {} 316 super::Temperature {}
301 } 317 }
302 318
303 /// Enable reading the vbat internal channel. 319 /// Enable reading the vbat internal channel.
304 #[cfg(stm32u5)] 320 #[cfg(stm32u5)]
305 pub fn enable_vbat(&self) -> Vbat { 321 pub fn enable_vbat_adc4(&self) -> super::Vbat {
306 T::regs().ccr().modify(|w| { 322 T::regs().ccr().modify(|w| {
307 w.set_vbaten(true); 323 w.set_vbaten(true);
308 }); 324 });
309 325
310 Vbat {} 326 super::Vbat {}
311 } 327 }
312 328
313 /// Enable reading the vbat internal channel. 329 /// Enable reading the vbat internal channel.
314 pub fn enable_vcore(&self) -> Vcore { 330 pub fn enable_vcore_adc4(&self) -> super::Vcore {
315 Vcore {} 331 super::Vcore {}
316 } 332 }
317 333
318 /// Enable reading the vbat internal channel. 334 /// Enable reading the vbat internal channel.
319 #[cfg(stm32u5)] 335 #[cfg(stm32u5)]
320 pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { 336 pub fn enable_dac_channel_adc4(&self, dac: DacChannel) -> super::Dac {
321 let mux; 337 let mux;
322 match dac { 338 match dac {
323 DacChannel::OUT1 => mux = false, 339 DacChannel::OUT1 => mux = false,
324 DacChannel::OUT2 => mux = true, 340 DacChannel::OUT2 => mux = true,
325 } 341 }
326 T::regs().or().modify(|w| w.set_chn21sel(mux)); 342 T::regs().or().modify(|w| w.set_chn21sel(mux));
327 Dac {} 343 super::Dac {}
328 } 344 }
329 345
330 /// Set the ADC resolution. 346 /// Set the ADC resolution.
331 pub fn set_resolution(&mut self, resolution: Resolution) { 347 pub fn set_resolution_adc4(&mut self, resolution: Resolution) {
332 T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); 348 T::regs().cfgr1().modify(|w| w.set_res(resolution.into()));
333 } 349 }
334 350
335 /// Set hardware averaging. 351 /// Set hardware averaging.
336 #[cfg(stm32u5)] 352 #[cfg(stm32u5)]
337 pub fn set_averaging(&mut self, averaging: Averaging) { 353 pub fn set_averaging_adc4(&mut self, averaging: Averaging) {
338 let (enable, samples, right_shift) = match averaging { 354 let (enable, samples, right_shift) = match averaging {
339 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0), 355 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0),
340 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1), 356 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1),
@@ -354,7 +370,7 @@ impl<'d, T: Instance> Adc4<'d, T> {
354 }) 370 })
355 } 371 }
356 #[cfg(stm32wba)] 372 #[cfg(stm32wba)]
357 pub fn set_averaging(&mut self, averaging: Averaging) { 373 pub fn set_averaging_adc4(&mut self, averaging: Averaging) {
358 let (enable, samples, right_shift) = match averaging { 374 let (enable, samples, right_shift) = match averaging {
359 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0), 375 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0),
360 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1), 376 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1),
@@ -373,168 +389,4 @@ impl<'d, T: Instance> Adc4<'d, T> {
373 w.set_ovse(enable) 389 w.set_ovse(enable)
374 }) 390 })
375 } 391 }
376
377 /// Read an ADC channel.
378 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
379 T::regs().smpr().modify(|w| {
380 w.set_smp(0, sample_time);
381 });
382
383 channel.setup();
384
385 // Select channel
386 #[cfg(stm32wba)]
387 {
388 T::regs().chselr().write_value(Chselr(0_u32));
389 T::regs().chselr().modify(|w| {
390 w.set_chsel0(channel.channel() as usize, true);
391 });
392 }
393 #[cfg(stm32u5)]
394 {
395 T::regs().chselrmod0().write_value(Chselr(0_u32));
396 T::regs().chselrmod0().modify(|w| {
397 w.set_chsel(channel.channel() as usize, true);
398 });
399 }
400
401 // Reset interrupts
402 T::regs().isr().modify(|reg| {
403 reg.set_eos(true);
404 reg.set_eoc(true);
405 });
406
407 // Start conversion
408 T::regs().cr().modify(|reg| {
409 reg.set_adstart(true);
410 });
411
412 while !T::regs().isr().read().eos() {
413 // spin
414 }
415
416 T::regs().dr().read().0 as u16
417 }
418
419 /// Read one or multiple ADC channels using DMA.
420 ///
421 /// `sequence` iterator and `readings` must have the same length.
422 /// The channels in `sequence` must be in ascending order.
423 ///
424 /// Example
425 /// ```rust,ignore
426 /// use embassy_stm32::adc::adc4;
427 /// use embassy_stm32::adc::AdcChannel;
428 ///
429 /// let mut adc4 = adc4::Adc4::new(p.ADC4);
430 /// let mut adc4_pin1 = p.PC1;
431 /// let mut adc4_pin2 = p.PC0;
432 /// let mut.into()d41 = adc4_pin1.into();
433 /// let mut.into()d42 = adc4_pin2.into();
434 /// let mut measurements = [0u16; 2];
435 /// // not that the channels must be in ascending order
436 /// adc4.read(
437 /// &mut p.GPDMA1_CH1,
438 /// [
439 /// &mut.into()d42,
440 /// &mut.into()d41,
441 /// ]
442 /// .into_iter(),
443 /// &mut measurements,
444 /// ).await.unwrap();
445 /// ```
446 pub async fn read(
447 &mut self,
448 rx_dma: Peri<'_, impl RxDma4<T>>,
449 sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
450 readings: &mut [u16],
451 ) -> Result<(), Adc4Error> {
452 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
453 assert!(
454 sequence.len() == readings.len(),
455 "Sequence length must be equal to readings length"
456 );
457
458 // Ensure no conversions are ongoing
459 Self::cancel_conversions();
460
461 T::regs().isr().modify(|reg| {
462 reg.set_ovr(true);
463 reg.set_eos(true);
464 reg.set_eoc(true);
465 });
466
467 T::regs().cfgr1().modify(|reg| {
468 reg.set_dmaen(true);
469 reg.set_dmacfg(Dmacfg::ONE_SHOT);
470 #[cfg(stm32u5)]
471 reg.set_chselrmod(false);
472 #[cfg(stm32wba)]
473 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
474 });
475
476 // Verify and activate sequence
477 let mut prev_channel: i16 = -1;
478 #[cfg(stm32wba)]
479 T::regs().chselr().write_value(Chselr(0_u32));
480 #[cfg(stm32u5)]
481 T::regs().chselrmod0().write_value(Chselr(0_u32));
482 for channel in sequence {
483 let channel_num = channel.channel;
484 if channel_num as i16 <= prev_channel {
485 return Err(Adc4Error::InvalidSequence);
486 };
487 prev_channel = channel_num as i16;
488
489 #[cfg(stm32wba)]
490 T::regs().chselr().modify(|w| {
491 w.set_chsel0(channel.channel as usize, true);
492 });
493 #[cfg(stm32u5)]
494 T::regs().chselrmod0().modify(|w| {
495 w.set_chsel(channel.channel as usize, true);
496 });
497 }
498
499 let request = rx_dma.request();
500 let transfer = unsafe {
501 Transfer::new_read(
502 rx_dma,
503 request,
504 T::regs().dr().as_ptr() as *mut u16,
505 readings,
506 Default::default(),
507 )
508 };
509
510 // Start conversion
511 T::regs().cr().modify(|reg| {
512 reg.set_adstart(true);
513 });
514
515 transfer.await;
516
517 // Ensure conversions are finished.
518 Self::cancel_conversions();
519
520 // Reset configuration.
521 T::regs().cfgr1().modify(|reg| {
522 reg.set_dmaen(false);
523 });
524
525 if T::regs().isr().read().ovr() {
526 Err(Adc4Error::DMAError)
527 } else {
528 Ok(())
529 }
530 }
531
532 fn cancel_conversions() {
533 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
534 T::regs().cr().modify(|reg| {
535 reg.set_adstp(true);
536 });
537 while T::regs().cr().read().adstart() {}
538 }
539 }
540} 392}
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index bc97a7c4b..3e109e429 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -1,12 +1,10 @@
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 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, 7use crate::adc::{AnyInstance, ConversionMode};
8};
9use crate::dma::Transfer;
10use crate::time::Hertz; 8use crate::time::Hertz;
11use crate::{Peri, pac, rcc}; 9use crate::{Peri, pac, rcc};
12 10
@@ -19,7 +17,6 @@ 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 NUM_HW_CHANNELS: u8 = 22;
23const CHSELR_SQ_SIZE: usize = 8; 20const CHSELR_SQ_SIZE: usize = 8;
24const CHSELR_SQ_MAX_CHANNEL: u8 = 14; 21const CHSELR_SQ_MAX_CHANNEL: u8 = 14;
25const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; 22const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111;
@@ -32,123 +29,169 @@ impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
32 const CHANNEL: u8 = 9; 29 const CHANNEL: u8 = 9;
33} 30}
34 31
35#[derive(Copy, Clone, Debug)] 32fn from_ker_ck(frequency: Hertz) -> Presc {
36pub enum Prescaler { 33 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
37 NotDivided, 34 match raw_prescaler {
38 DividedBy2, 35 0 => Presc::DIV1,
39 DividedBy4, 36 1 => Presc::DIV2,
40 DividedBy6, 37 2..=3 => Presc::DIV4,
41 DividedBy8, 38 4..=5 => Presc::DIV6,
42 DividedBy10, 39 6..=7 => Presc::DIV8,
43 DividedBy12, 40 8..=9 => Presc::DIV10,
44 DividedBy16, 41 10..=11 => Presc::DIV12,
45 DividedBy32, 42 _ => unimplemented!(),
46 DividedBy64, 43 }
47 DividedBy128,
48 DividedBy256,
49} 44}
50 45
51impl Prescaler { 46impl<T: Instance> super::SealedAnyInstance for T {
52 fn from_ker_ck(frequency: Hertz) -> Self { 47 fn dr() -> *mut u16 {
53 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 48 T::regs().dr().as_ptr() as *mut u16
54 match raw_prescaler { 49 }
55 0 => Self::NotDivided, 50
56 1 => Self::DividedBy2, 51 fn enable() {
57 2..=3 => Self::DividedBy4, 52 T::regs().isr().modify(|w| w.set_adrdy(true));
58 4..=5 => Self::DividedBy6, 53 T::regs().cr().modify(|w| w.set_aden(true));
59 6..=7 => Self::DividedBy8, 54 // ADRDY is "ADC ready". Wait until it will be True.
60 8..=9 => Self::DividedBy10, 55 while !T::regs().isr().read().adrdy() {}
61 10..=11 => Self::DividedBy12,
62 _ => unimplemented!(),
63 }
64 } 56 }
65 57
66 #[allow(unused)] 58 fn start() {
67 fn divisor(&self) -> u32 { 59 // Start conversion
68 match self { 60 T::regs().cr().modify(|reg| {
69 Prescaler::NotDivided => 1, 61 reg.set_adstart(true);
70 Prescaler::DividedBy2 => 2, 62 });
71 Prescaler::DividedBy4 => 4, 63 }
72 Prescaler::DividedBy6 => 6, 64
73 Prescaler::DividedBy8 => 8, 65 fn stop() {
74 Prescaler::DividedBy10 => 10, 66 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
75 Prescaler::DividedBy12 => 12, 67 T::regs().cr().modify(|reg| {
76 Prescaler::DividedBy16 => 16, 68 reg.set_adstp(Adstp::STOP);
77 Prescaler::DividedBy32 => 32, 69 });
78 Prescaler::DividedBy64 => 64, 70 while T::regs().cr().read().adstart() {}
79 Prescaler::DividedBy128 => 128,
80 Prescaler::DividedBy256 => 256,
81 } 71 }
72
73 // Reset configuration.
74 T::regs().cfgr1().modify(|reg| {
75 reg.set_cont(false);
76 reg.set_dmacfg(Dmacfg::from_bits(0));
77 reg.set_dmaen(false);
78 });
82 } 79 }
83 80
84 fn presc(&self) -> Presc { 81 fn configure_dma(conversion_mode: super::ConversionMode) {
85 match self { 82 match conversion_mode {
86 Prescaler::NotDivided => Presc::DIV1, 83 ConversionMode::Singular => {
87 Prescaler::DividedBy2 => Presc::DIV2, 84 // Enable overrun control, so no new DMA requests will be generated until
88 Prescaler::DividedBy4 => Presc::DIV4, 85 // previous DR values is read.
89 Prescaler::DividedBy6 => Presc::DIV6, 86 T::regs().isr().modify(|reg| {
90 Prescaler::DividedBy8 => Presc::DIV8, 87 reg.set_ovr(true);
91 Prescaler::DividedBy10 => Presc::DIV10, 88 });
92 Prescaler::DividedBy12 => Presc::DIV12, 89
93 Prescaler::DividedBy16 => Presc::DIV16, 90 // Set continuous mode with oneshot dma.
94 Prescaler::DividedBy32 => Presc::DIV32, 91 T::regs().cfgr1().modify(|reg| {
95 Prescaler::DividedBy64 => Presc::DIV64, 92 reg.set_discen(false);
96 Prescaler::DividedBy128 => Presc::DIV128, 93 reg.set_cont(true);
97 Prescaler::DividedBy256 => Presc::DIV256, 94 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
95 reg.set_dmaen(true);
96 reg.set_ovrmod(Ovrmod::PRESERVE);
97 });
98 }
98 } 99 }
99 } 100 }
100}
101 101
102#[cfg(feature = "defmt")] 102 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>) {
103impl<'a> defmt::Format for Prescaler { 103 let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE;
104 fn format(&self, fmt: defmt::Formatter) { 104 let mut is_ordered_up = true;
105 match self { 105 let mut is_ordered_down = true;
106 Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), 106
107 Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), 107 let sequence_len = sequence.len();
108 Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), 108 let mut hw_channel_selection: u32 = 0;
109 Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), 109 let mut last_channel: u8 = 0;
110 Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), 110 let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5;
111 Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), 111
112 Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), 112 T::regs().chselr_sq().write(|w| {
113 Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), 113 for (i, ((channel, _), _sample_time)) in sequence.enumerate() {
114 Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), 114 assert!(
115 Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), 115 sample_time == _sample_time || i == 0,
116 Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), 116 "C0 only supports one sample time for the sequence."
117 Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), 117 );
118
119 sample_time = _sample_time;
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;
125
126 if !needs_hw {
127 w.set_sq(i, channel);
128 }
129 }
130
131 for i in sequence_len..CHSELR_SQ_SIZE {
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 { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
118 } 150 }
151
152 T::regs().smpr().modify(|w| {
153 w.smpsel(0);
154 w.set_smp1(sample_time);
155 });
156
157 T::regs().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 });
162
163 // Trigger and wait for the channel selection procedure to complete.
164 T::regs().isr().modify(|w| w.set_ccrdy(false));
165 while !T::regs().isr().read().ccrdy() {}
119 } 166 }
120}
121 167
122/// Number of samples used for averaging. 168 fn convert() -> u16 {
123/// TODO: Implement hardware averaging setting. 169 // Set single conversion mode.
124#[allow(unused)] 170 T::regs().cfgr1().modify(|w| w.set_cont(false));
125#[derive(Copy, Clone, Debug)] 171
126#[cfg_attr(feature = "defmt", derive(defmt::Format))] 172 // Start conversion
127pub enum Averaging { 173 T::regs().cr().modify(|reg| {
128 Disabled, 174 reg.set_adstart(true);
129 Samples2, 175 });
130 Samples4, 176
131 Samples8, 177 // Waiting for End Of Conversion (EOC).
132 Samples16, 178 while !T::regs().isr().read().eoc() {}
133 Samples32, 179
134 Samples64, 180 T::regs().dr().read().data() as u16
135 Samples128, 181 }
136 Samples256,
137 Samples512,
138 Samples1024,
139} 182}
140 183
141impl<'d, T: Instance> Adc<'d, T> { 184impl<'d, T: AnyInstance> Adc<'d, T> {
142 /// Create a new ADC driver. 185 /// Create a new ADC driver.
143 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { 186 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self {
144 rcc::enable_and_reset::<T>(); 187 rcc::enable_and_reset::<T>();
145 188
146 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); 189 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
147 190
148 let prescaler = Prescaler::from_ker_ck(T::frequency()); 191 let prescaler = from_ker_ck(T::frequency());
149 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 192 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
150 193
151 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 194 let frequency = T::frequency() / prescaler;
152 debug!("ADC frequency set to {}", frequency); 195 debug!("ADC frequency set to {}", frequency);
153 196
154 if frequency > MAX_ADC_CLK_FREQ { 197 if frequency > MAX_ADC_CLK_FREQ {
@@ -158,32 +201,16 @@ impl<'d, T: Instance> Adc<'d, T> {
158 ); 201 );
159 } 202 }
160 203
161 let mut s = Self { adc };
162
163 s.power_up();
164
165 s.set_resolution(resolution);
166
167 s.calibrate();
168
169 s.enable();
170
171 s.configure_default();
172
173 s
174 }
175
176 fn power_up(&mut self) {
177 T::regs().cr().modify(|reg| { 204 T::regs().cr().modify(|reg| {
178 reg.set_advregen(true); 205 reg.set_advregen(true);
179 }); 206 });
180 207
181 // "The software must wait for the ADC voltage regulator startup time." 208 // "The software must wait for the ADC voltage regulator startup time."
182 // See datasheet for the value. 209 // See datasheet for the value.
183 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); 210 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US as u64 + 1);
184 } 211
212 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
185 213
186 fn calibrate(&mut self) {
187 // We have to make sure AUTOFF is OFF, but keep its value after calibration. 214 // We have to make sure AUTOFF is OFF, but keep its value after calibration.
188 let autoff_value = T::regs().cfgr1().read().autoff(); 215 let autoff_value = T::regs().cfgr1().read().autoff();
189 T::regs().cfgr1().modify(|w| w.set_autoff(false)); 216 T::regs().cfgr1().modify(|w| w.set_autoff(false));
@@ -197,22 +224,17 @@ impl<'d, T: Instance> Adc<'d, T> {
197 debug!("ADC calibration value: {}.", T::regs().dr().read().data()); 224 debug!("ADC calibration value: {}.", T::regs().dr().read().data());
198 225
199 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); 226 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value));
200 }
201 227
202 fn enable(&mut self) { 228 T::enable();
203 T::regs().isr().modify(|w| w.set_adrdy(true));
204 T::regs().cr().modify(|w| w.set_aden(true));
205 // ADRDY is "ADC ready". Wait until it will be True.
206 while !T::regs().isr().read().adrdy() {}
207 }
208 229
209 fn configure_default(&mut self) {
210 // single conversion mode, software trigger 230 // single conversion mode, software trigger
211 T::regs().cfgr1().modify(|w| { 231 T::regs().cfgr1().modify(|w| {
212 w.set_cont(false); 232 w.set_cont(false);
213 w.set_exten(Exten::DISABLED); 233 w.set_exten(Exten::DISABLED);
214 w.set_align(Align::RIGHT); 234 w.set_align(Align::RIGHT);
215 }); 235 });
236
237 Self { adc }
216 } 238 }
217 239
218 /// Enable reading the voltage reference internal channel. 240 /// Enable reading the voltage reference internal channel.
@@ -233,219 +255,4 @@ impl<'d, T: Instance> Adc<'d, T> {
233 255
234 super::Temperature {} 256 super::Temperature {}
235 } 257 }
236
237 /// Set the ADC sample time.
238 /// Shall only be called when ADC is not converting.
239 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
240 // Set all channels to use SMP1 field as source.
241 T::regs().smpr().modify(|w| {
242 w.smpsel(0);
243 w.set_smp1(sample_time);
244 });
245 }
246
247 /// Set the ADC resolution.
248 pub fn set_resolution(&mut self, resolution: Resolution) {
249 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
250 }
251
252 /// Perform a single conversion.
253 fn convert(&mut self) -> u16 {
254 // Set single conversion mode.
255 T::regs().cfgr1().modify(|w| w.set_cont(false));
256
257 // Start conversion
258 T::regs().cr().modify(|reg| {
259 reg.set_adstart(true);
260 });
261
262 // Waiting for End Of Conversion (EOC).
263 while !T::regs().isr().read().eoc() {}
264
265 T::regs().dr().read().data() as u16
266 }
267
268 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
269 self.set_sample_time_all_channels(sample_time);
270
271 Self::configure_channel(channel);
272 T::regs().cfgr1().write(|reg| {
273 reg.set_chselrmod(false);
274 reg.set_align(Align::RIGHT);
275 });
276 self.convert()
277 }
278
279 fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) {
280 assert!(
281 channel_sequence.len() <= CHSELR_SQ_SIZE,
282 "Seqenced read set cannot be more than {} in size.",
283 CHSELR_SQ_SIZE
284 );
285 let mut last_sq_set: usize = 0;
286 T::regs().chselr_sq().write(|w| {
287 for (i, channel) in channel_sequence.enumerate() {
288 assert!(
289 channel.channel() <= CHSELR_SQ_MAX_CHANNEL,
290 "Sequencer only support HW channels smaller than {}.",
291 CHSELR_SQ_MAX_CHANNEL
292 );
293 w.set_sq(i, channel.channel());
294 last_sq_set = i;
295 }
296
297 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
298 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
299 }
300 });
301
302 Self::apply_channel_conf()
303 }
304
305 async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) {
306 // Enable overrun control, so no new DMA requests will be generated until
307 // previous DR values is read.
308 T::regs().isr().modify(|reg| {
309 reg.set_ovr(true);
310 });
311
312 // Set continuous mode with oneshot dma.
313 T::regs().cfgr1().modify(|reg| {
314 reg.set_discen(false);
315 reg.set_cont(true);
316 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
317 reg.set_dmaen(true);
318 reg.set_ovrmod(Ovrmod::PRESERVE);
319 });
320
321 let request = rx_dma.request();
322 let transfer = unsafe {
323 Transfer::new_read(
324 rx_dma,
325 request,
326 T::regs().dr().as_ptr() as *mut u16,
327 readings,
328 Default::default(),
329 )
330 };
331
332 // Start conversion.
333 T::regs().cr().modify(|reg| {
334 reg.set_adstart(true);
335 });
336
337 // Wait for conversion sequence to finish.
338 transfer.await;
339
340 // Ensure conversions are finished.
341 Self::cancel_conversions();
342
343 // Reset configuration.
344 T::regs().cfgr1().modify(|reg| {
345 reg.set_cont(false);
346 reg.set_dmacfg(Dmacfg::from_bits(0));
347 reg.set_dmaen(false);
348 });
349 }
350
351 /// Read one or multiple ADC channels using DMA in hardware order.
352 /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting.
353 /// Readings won't be in the same order as in the `set`!
354 ///
355 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
356 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
357 /// TODO(chudsaviet): externalize generic code and merge with read().
358 pub async fn read_in_hw_order(
359 &mut self,
360 rx_dma: Peri<'_, impl RxDma<T>>,
361 hw_channel_selection: u32,
362 scandir: Scandir,
363 readings: &mut [u16],
364 ) {
365 assert!(
366 hw_channel_selection != 0,
367 "Some bits in `hw_channel_selection` shall be set."
368 );
369 assert!(
370 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
371 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
372 NUM_HW_CHANNELS
373 );
374 // To check for correct readings slice size, we shall solve Hamming weight problem,
375 // which is either slow or memory consuming.
376 // Since we have limited resources, we don't do it here.
377 // Not doing this have a great potential for a bug through.
378
379 // Ensure no conversions are ongoing.
380 Self::cancel_conversions();
381
382 T::regs().cfgr1().modify(|reg| {
383 reg.set_chselrmod(false);
384 reg.set_scandir(scandir);
385 reg.set_align(Align::RIGHT);
386 });
387
388 // Set required channels for multi-convert.
389 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
390
391 Self::apply_channel_conf();
392
393 self.dma_convert(rx_dma, readings).await
394 }
395
396 // Read ADC channels in specified order using DMA (CHSELRMOD = 1).
397 // In STM32C0, only lower 14 ADC channels can be read this way.
398 // For other channels, use `read_in_hw_order()` or blocking read.
399 pub async fn read(
400 &mut self,
401 rx_dma: Peri<'_, impl RxDma<T>>,
402 channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
403 readings: &mut [u16],
404 ) {
405 assert!(
406 channel_sequence.len() != 0,
407 "Asynchronous read channel sequence cannot be empty."
408 );
409 assert!(
410 channel_sequence.len() == readings.len(),
411 "Channel sequence length must be equal to readings length."
412 );
413
414 // Ensure no conversions are ongoing.
415 Self::cancel_conversions();
416
417 T::regs().cfgr1().modify(|reg| {
418 reg.set_chselrmod(true);
419 reg.set_align(Align::RIGHT);
420 });
421
422 Self::setup_channel_sequencer(channel_sequence);
423
424 self.dma_convert(rx_dma, readings).await
425 }
426
427 fn configure_channel(channel: &mut impl AdcChannel<T>) {
428 channel.setup();
429 // write() because we want all other bits to be set to 0.
430 T::regs()
431 .chselr()
432 .write(|w| w.set_chsel(channel.channel().into(), true));
433
434 Self::apply_channel_conf();
435 }
436
437 fn apply_channel_conf() {
438 // Trigger and wait for the channel selection procedure to complete.
439 T::regs().isr().modify(|w| w.set_ccrdy(false));
440 while !T::regs().isr().read().ccrdy() {}
441 }
442
443 fn cancel_conversions() {
444 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
445 T::regs().cr().modify(|reg| {
446 reg.set_adstp(Adstp::STOP);
447 });
448 while T::regs().cr().read().adstart() {}
449 }
450 }
451} 258}
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index f6220de78..d6c6f480b 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -43,7 +43,7 @@ impl<'d, T: Instance> Adc<'d, T> {
43 43
44 // 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’)
45 // for at least two ADC clock cycles. 45 // for at least two ADC clock cycles.
46 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);
47 47
48 // Reset calibration 48 // Reset calibration
49 T::regs().cr2().modify(|reg| reg.set_rstcal(true)); 49 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
@@ -58,7 +58,7 @@ impl<'d, T: Instance> Adc<'d, T> {
58 } 58 }
59 59
60 // One cycle after calibration 60 // One cycle after calibration
61 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);
62 62
63 T::Interrupt::unpend(); 63 T::Interrupt::unpend();
64 unsafe { T::Interrupt::enable() }; 64 unsafe { T::Interrupt::enable() };
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 4a77f3c5b..29bfdac97 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -62,7 +62,7 @@ impl<'d, T: Instance> Adc<'d, T> {
62 while T::regs().cr().read().adcal() {} 62 while T::regs().cr().read().adcal() {}
63 63
64 // 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).
65 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);
66 66
67 // Enable the adc 67 // Enable the adc
68 T::regs().cr().modify(|w| w.set_aden(true)); 68 T::regs().cr().modify(|w| w.set_aden(true));
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 6430b0243..1767a3bb3 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,24 +1,21 @@
1use core::mem; 1#[cfg(stm32g4)]
2 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};
3#[allow(unused)] 6#[allow(unused)]
4#[cfg(stm32h7)] 7#[cfg(stm32h7)]
5use pac::adc::vals::{Adcaldif, Difsel, Exten}; 8use pac::adc::vals::{Adcaldif, Difsel, Exten};
6#[allow(unused)] 9pub use pac::adccommon::vals::{Dual, Presc};
7#[cfg(stm32g4)] 10
8pub use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; 11use super::{
9pub use pac::adccommon::vals::Presc; 12 Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime,
10pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; 13 blocking_delay_us,
11pub use stm32_metapac::adccommon::vals::Dual; 14};
12 15use crate::adc::{AnyInstance, SealedAdcChannel};
13use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us};
14use crate::adc::SealedAdcChannel;
15use crate::dma::Transfer;
16use crate::time::Hertz; 16use crate::time::Hertz;
17use crate::{Peri, pac, rcc}; 17use crate::{Peri, pac, rcc};
18 18
19mod ringbuffered;
20pub use ringbuffered::RingBufferedAdc;
21
22mod injected; 19mod injected;
23pub use injected::InjectedAdc; 20pub use injected::InjectedAdc;
24 21
@@ -35,72 +32,31 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
35#[cfg(stm32h7)] 32#[cfg(stm32h7)]
36const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 33const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
37 34
38// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 35fn from_ker_ck(frequency: Hertz) -> Presc {
39// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 36 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
40#[allow(unused)] 37 match raw_prescaler {
41enum Prescaler { 38 0 => Presc::DIV1,
42 NotDivided, 39 1 => Presc::DIV2,
43 DividedBy2, 40 2..=3 => Presc::DIV4,
44 DividedBy4, 41 4..=5 => Presc::DIV6,
45 DividedBy6, 42 6..=7 => Presc::DIV8,
46 DividedBy8, 43 8..=9 => Presc::DIV10,
47 DividedBy10, 44 10..=11 => Presc::DIV12,
48 DividedBy12, 45 _ => unimplemented!(),
49 DividedBy16,
50 DividedBy32,
51 DividedBy64,
52 DividedBy128,
53 DividedBy256,
54}
55
56impl Prescaler {
57 fn from_ker_ck(frequency: Hertz) -> Self {
58 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
59 match raw_prescaler {
60 0 => Self::NotDivided,
61 1 => Self::DividedBy2,
62 2..=3 => Self::DividedBy4,
63 4..=5 => Self::DividedBy6,
64 6..=7 => Self::DividedBy8,
65 8..=9 => Self::DividedBy10,
66 10..=11 => Self::DividedBy12,
67 _ => unimplemented!(),
68 }
69 }
70
71 fn divisor(&self) -> u32 {
72 match self {
73 Prescaler::NotDivided => 1,
74 Prescaler::DividedBy2 => 2,
75 Prescaler::DividedBy4 => 4,
76 Prescaler::DividedBy6 => 6,
77 Prescaler::DividedBy8 => 8,
78 Prescaler::DividedBy10 => 10,
79 Prescaler::DividedBy12 => 12,
80 Prescaler::DividedBy16 => 16,
81 Prescaler::DividedBy32 => 32,
82 Prescaler::DividedBy64 => 64,
83 Prescaler::DividedBy128 => 128,
84 Prescaler::DividedBy256 => 256,
85 }
86 } 46 }
47}
87 48
88 fn presc(&self) -> Presc { 49/// ADC configuration
89 match self { 50#[derive(Default)]
90 Prescaler::NotDivided => Presc::DIV1, 51pub struct AdcConfig {
91 Prescaler::DividedBy2 => Presc::DIV2, 52 pub dual_mode: Option<Dual>,
92 Prescaler::DividedBy4 => Presc::DIV4, 53 pub resolution: Option<Resolution>,
93 Prescaler::DividedBy6 => Presc::DIV6, 54 #[cfg(stm32g4)]
94 Prescaler::DividedBy8 => Presc::DIV8, 55 pub oversampling_shift: Option<u8>,
95 Prescaler::DividedBy10 => Presc::DIV10, 56 #[cfg(stm32g4)]
96 Prescaler::DividedBy12 => Presc::DIV12, 57 pub oversampling_ratio: Option<u8>,
97 Prescaler::DividedBy16 => Presc::DIV16, 58 #[cfg(stm32g4)]
98 Prescaler::DividedBy32 => Presc::DIV32, 59 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
99 Prescaler::DividedBy64 => Presc::DIV64,
100 Prescaler::DividedBy128 => Presc::DIV128,
101 Prescaler::DividedBy256 => Presc::DIV256,
102 }
103 }
104} 60}
105 61
106// Trigger source for ADC conversions¨ 62// Trigger source for ADC conversions¨
@@ -112,25 +68,189 @@ pub struct ConversionTrigger {
112 pub edge: Exten, 68 pub edge: Exten,
113} 69}
114 70
115// Conversion mode for regular ADC channels 71impl<T: Instance> super::SealedAnyInstance for T {
116#[derive(Copy, Clone)] 72 fn dr() -> *mut u16 {
117pub enum RegularConversionMode { 73 T::regs().dr().as_ptr() as *mut u16
118 // Samples as fast as possible 74 }
119 Continuous, 75
120 // Sample at rate determined by external trigger 76 fn enable() {
121 Triggered(ConversionTrigger), 77 // Make sure bits are off
78 while T::regs().cr().read().addis() {
79 // spin
80 }
81
82 if !T::regs().cr().read().aden() {
83 // Enable ADC
84 T::regs().isr().modify(|reg| {
85 reg.set_adrdy(true);
86 });
87 T::regs().cr().modify(|reg| {
88 reg.set_aden(true);
89 });
90
91 while !T::regs().isr().read().adrdy() {
92 // spin
93 }
94 }
95 }
96
97 fn start() {
98 T::regs().cr().modify(|reg| {
99 reg.set_adstart(true);
100 });
101 }
102
103 fn stop() {
104 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
105 T::regs().cr().modify(|reg| {
106 reg.set_adstp(Adstp::STOP);
107 });
108 // The software must poll ADSTART until the bit is reset before assuming the
109 // ADC is completely stopped
110 while T::regs().cr().read().adstart() {}
111 }
112
113 // Disable dma control and continuous conversion, if enabled
114 T::regs().cfgr().modify(|reg| {
115 reg.set_cont(false);
116 reg.set_dmaen(Dmaen::DISABLE);
117 });
118 }
119
120 fn convert() -> u16 {
121 T::regs().isr().modify(|reg| {
122 reg.set_eos(true);
123 reg.set_eoc(true);
124 });
125
126 // Start conversion
127 T::regs().cr().modify(|reg| {
128 reg.set_adstart(true);
129 });
130
131 while !T::regs().isr().read().eos() {
132 // spin
133 }
134
135 T::regs().dr().read().0 as u16
136 }
137
138 fn configure_dma(conversion_mode: ConversionMode) {
139 T::regs().isr().modify(|reg| {
140 reg.set_ovr(true);
141 });
142
143 T::regs().cfgr().modify(|reg| {
144 reg.set_discen(false); // Convert all channels for each trigger
145 reg.set_dmacfg(match conversion_mode {
146 ConversionMode::Singular => Dmacfg::ONE_SHOT,
147 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
148 });
149 reg.set_dmaen(Dmaen::ENABLE);
150 });
151
152 if let ConversionMode::Repeated(mode) = conversion_mode {
153 match mode {
154 RegularConversionMode::Continuous => {
155 T::regs().cfgr().modify(|reg| {
156 reg.set_cont(true);
157 });
158 }
159 RegularConversionMode::Triggered(trigger) => {
160 T::regs().cfgr().modify(|r| {
161 r.set_cont(false); // New trigger is neede for each sample to be read
162 });
163
164 T::regs().cfgr().modify(|r| {
165 r.set_extsel(trigger.channel);
166 r.set_exten(trigger.edge);
167 });
168
169 // Regular conversions uses DMA so no need to generate interrupt
170 T::regs().ier().modify(|r| r.set_eosie(false));
171 }
172 }
173 }
174 }
175
176 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
177 T::regs().cr().modify(|w| w.set_aden(false));
178
179 // Set sequence length
180 T::regs().sqr1().modify(|w| {
181 w.set_l(sequence.len() as u8 - 1);
182 });
183
184 #[cfg(stm32g4)]
185 let mut difsel = DifselReg::default();
186 let mut smpr = T::regs().smpr().read();
187 let mut smpr2 = T::regs().smpr2().read();
188 let mut sqr1 = T::regs().sqr1().read();
189 let mut sqr2 = T::regs().sqr2().read();
190 let mut sqr3 = T::regs().sqr3().read();
191 let mut sqr4 = T::regs().sqr4().read();
192
193 // Configure channels and ranks
194 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() {
195 let sample_time = sample_time.into();
196 if ch <= 9 {
197 smpr.set_smp(ch as _, sample_time);
198 } else {
199 smpr2.set_smp((ch - 10) as _, sample_time);
200 }
201
202 match _i {
203 0..=3 => {
204 sqr1.set_sq(_i, ch);
205 }
206 4..=8 => {
207 sqr2.set_sq(_i - 4, ch);
208 }
209 9..=13 => {
210 sqr3.set_sq(_i - 9, ch);
211 }
212 14..=15 => {
213 sqr4.set_sq(_i - 14, ch);
214 }
215 _ => unreachable!(),
216 }
217
218 #[cfg(stm32g4)]
219 {
220 if ch < 18 {
221 difsel.set_difsel(
222 ch.into(),
223 if is_differential {
224 Difsel::DIFFERENTIAL
225 } else {
226 Difsel::SINGLE_ENDED
227 },
228 );
229 }
230 }
231 }
232
233 T::regs().smpr().write_value(smpr);
234 T::regs().smpr2().write_value(smpr2);
235 T::regs().sqr1().write_value(sqr1);
236 T::regs().sqr2().write_value(sqr2);
237 T::regs().sqr3().write_value(sqr3);
238 T::regs().sqr4().write_value(sqr4);
239 #[cfg(stm32g4)]
240 T::regs().difsel().write_value(difsel);
241 }
122} 242}
123 243
124impl<'d, T: Instance> Adc<'d, T> { 244impl<'d, T: Instance + AnyInstance> Adc<'d, T> {
125 /// Create a new ADC driver. 245 /// Create a new ADC driver.
126 pub fn new(adc: Peri<'d, T>) -> Self { 246 pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self {
127 rcc::enable_and_reset::<T>(); 247 rcc::enable_and_reset::<T>();
128 248
129 let prescaler = Prescaler::from_ker_ck(T::frequency()); 249 let prescaler = from_ker_ck(T::frequency());
130 250
131 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 251 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
132 252
133 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 253 let frequency = T::frequency() / prescaler;
134 trace!("ADC frequency set to {}", frequency); 254 trace!("ADC frequency set to {}", frequency);
135 255
136 if frequency > MAX_ADC_CLK_FREQ { 256 if frequency > MAX_ADC_CLK_FREQ {
@@ -173,7 +293,7 @@ impl<'d, T: Instance> Adc<'d, T> {
173 293
174 blocking_delay_us(20); 294 blocking_delay_us(20);
175 295
176 Self::enable(); 296 T::enable();
177 297
178 // single conversion mode, software trigger 298 // single conversion mode, software trigger
179 T::regs().cfgr().modify(|w| { 299 T::regs().cfgr().modify(|w| {
@@ -181,28 +301,34 @@ impl<'d, T: Instance> Adc<'d, T> {
181 w.set_exten(Exten::DISABLED); 301 w.set_exten(Exten::DISABLED);
182 }); 302 });
183 303
184 Self { adc } 304 if let Some(dual) = config.dual_mode {
185 } 305 T::common_regs().ccr().modify(|reg| {
306 reg.set_dual(dual);
307 })
308 }
186 309
187 fn enable() { 310 if let Some(resolution) = config.resolution {
188 // Make sure bits are off 311 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
189 while T::regs().cr().read().addis() {
190 // spin
191 } 312 }
192 313
193 if !T::regs().cr().read().aden() { 314 #[cfg(stm32g4)]
194 // Enable ADC 315 if let Some(shift) = config.oversampling_shift {
195 T::regs().isr().modify(|reg| { 316 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
196 reg.set_adrdy(true); 317 }
197 });
198 T::regs().cr().modify(|reg| {
199 reg.set_aden(true);
200 });
201 318
202 while !T::regs().isr().read().adrdy() { 319 #[cfg(stm32g4)]
203 // spin 320 if let Some(ratio) = config.oversampling_ratio {
204 } 321 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
205 } 322 }
323
324 #[cfg(stm32g4)]
325 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
326 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
327 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
328 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
329 }
330
331 Self { adc }
206 } 332 }
207 333
208 /// Enable reading the voltage reference internal channel. 334 /// Enable reading the voltage reference internal channel.
@@ -241,26 +367,6 @@ impl<'d, T: Instance> Adc<'d, T> {
241 super::Vbat {} 367 super::Vbat {}
242 } 368 }
243 369
244 /// Set oversampling shift.
245 #[cfg(stm32g4)]
246 pub fn set_oversampling_shift(&mut self, shift: u8) {
247 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
248 }
249
250 /// Set oversampling ratio.
251 #[cfg(stm32g4)]
252 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
253 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
254 }
255
256 /// Enable oversampling in regular mode.
257 #[cfg(stm32g4)]
258 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
259 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
260 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
261 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
262 }
263
264 // Reads that are not implemented as INJECTED in "blocking_read" 370 // Reads that are not implemented as INJECTED in "blocking_read"
265 // #[cfg(stm32g4)] 371 // #[cfg(stm32g4)]
266 // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) { 372 // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) {
@@ -274,311 +380,6 @@ impl<'d, T: Instance> Adc<'d, T> {
274 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); 380 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
275 // } 381 // }
276 382
277 /// Set the ADC resolution.
278 pub fn set_resolution(&mut self, resolution: Resolution) {
279 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
280 }
281
282 /// Perform a single conversion.
283 fn convert(&mut self) -> u16 {
284 T::regs().isr().modify(|reg| {
285 reg.set_eos(true);
286 reg.set_eoc(true);
287 });
288
289 // Start conversion
290 T::regs().cr().modify(|reg| {
291 reg.set_adstart(true);
292 });
293
294 while !T::regs().isr().read().eos() {
295 // spin
296 }
297
298 T::regs().dr().read().0 as u16
299 }
300
301 /// Read an ADC pin.
302 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
303 channel.setup();
304
305 Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
306
307 #[cfg(stm32h7)]
308 {
309 T::regs().cfgr2().modify(|w| w.set_lshift(0));
310 T::regs()
311 .pcsel()
312 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
313 }
314
315 self.convert()
316 }
317
318 /// Start regular adc conversion
319 pub(super) fn start() {
320 T::regs().cr().modify(|reg| {
321 reg.set_adstart(true);
322 });
323 }
324
325 /// Stop regular conversions
326 pub(super) fn stop() {
327 Self::stop_regular_conversions();
328 }
329
330 /// Teardown method for stopping regular ADC conversions
331 pub(super) fn teardown_dma() {
332 Self::stop_regular_conversions();
333
334 // Disable dma control
335 T::regs().cfgr().modify(|reg| {
336 reg.set_dmaen(Dmaen::DISABLE);
337 });
338 }
339
340 /// Read one or multiple ADC regular channels using DMA.
341 ///
342 /// `sequence` iterator and `readings` must have the same length.
343 ///
344 /// Example
345 /// ```rust,ignore
346 /// use embassy_stm32::adc::{Adc, AdcChannel}
347 ///
348 /// let mut adc = Adc::new(p.ADC1);
349 /// let mut adc_pin0 = p.PA0.into();
350 /// let mut adc_pin1 = p.PA1.into();
351 /// let mut measurements = [0u16; 2];
352 ///
353 /// adc.read(
354 /// p.DMA1_CH2.reborrow(),
355 /// [
356 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
357 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
358 /// ]
359 /// .into_iter(),
360 /// &mut measurements,
361 /// )
362 /// .await;
363 /// defmt::info!("measurements: {}", measurements);
364 /// ```
365 ///
366 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
367 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
368 pub async fn read(
369 &mut self,
370 rx_dma: Peri<'_, impl RxDma<T>>,
371 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
372 readings: &mut [u16],
373 ) {
374 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
375 assert!(
376 sequence.len() == readings.len(),
377 "Sequence length must be equal to readings length"
378 );
379 assert!(
380 sequence.len() <= 16,
381 "Asynchronous read sequence cannot be more than 16 in length"
382 );
383
384 // Ensure no conversions are ongoing and ADC is enabled.
385 Self::stop_regular_conversions();
386 Self::enable();
387
388 Self::configure_sequence(
389 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
390 );
391
392 // Set continuous mode with oneshot dma.
393 // Clear overrun flag before starting transfer.
394 T::regs().isr().modify(|reg| {
395 reg.set_ovr(true);
396 });
397
398 T::regs().cfgr().modify(|reg| {
399 reg.set_discen(false);
400 reg.set_cont(true);
401 reg.set_dmacfg(Dmacfg::ONE_SHOT);
402 reg.set_dmaen(Dmaen::ENABLE);
403 });
404
405 let request = rx_dma.request();
406 let transfer = unsafe {
407 Transfer::new_read(
408 rx_dma,
409 request,
410 T::regs().dr().as_ptr() as *mut u16,
411 readings,
412 Default::default(),
413 )
414 };
415
416 // Start conversion
417 T::regs().cr().modify(|reg| {
418 reg.set_adstart(true);
419 });
420
421 // Wait for conversion sequence to finish.
422 transfer.await;
423
424 // Ensure conversions are finished.
425 Self::stop_regular_conversions();
426
427 // Reset configuration.
428 T::regs().cfgr().modify(|reg| {
429 reg.set_cont(false);
430 });
431 }
432
433 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
434 // Set sequence length
435 T::regs().sqr1().modify(|w| {
436 w.set_l(sequence.len() as u8 - 1);
437 });
438
439 // Configure channels and ranks
440 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() {
441 let sample_time = sample_time.into();
442 if ch <= 9 {
443 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time));
444 } else {
445 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
446 }
447
448 match _i {
449 0..=3 => {
450 T::regs().sqr1().modify(|w| {
451 w.set_sq(_i, ch);
452 });
453 }
454 4..=8 => {
455 T::regs().sqr2().modify(|w| {
456 w.set_sq(_i - 4, ch);
457 });
458 }
459 9..=13 => {
460 T::regs().sqr3().modify(|w| {
461 w.set_sq(_i - 9, ch);
462 });
463 }
464 14..=15 => {
465 T::regs().sqr4().modify(|w| {
466 w.set_sq(_i - 14, ch);
467 });
468 }
469 _ => unreachable!(),
470 }
471
472 #[cfg(stm32g4)]
473 {
474 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
475
476 T::regs().difsel().modify(|w| {
477 w.set_difsel(
478 ch.into(),
479 if is_differential {
480 Difsel::DIFFERENTIAL
481 } else {
482 Difsel::SINGLE_ENDED
483 },
484 );
485 });
486
487 T::regs().cr().modify(|w| w.set_aden(true)); // enable adc
488 }
489 }
490 }
491
492 /// Set external trigger for regular conversion sequence
493 fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) {
494 T::regs().cfgr().modify(|r| {
495 r.set_extsel(trigger.channel);
496 r.set_exten(trigger.edge);
497 });
498 // Regular conversions uses DMA so no need to generate interrupt
499 T::regs().ier().modify(|r| r.set_eosie(false));
500 }
501
502 // Dual ADC mode selection
503 pub fn configure_dual_mode(&mut self, val: Dual) {
504 T::common_regs().ccr().modify(|reg| {
505 reg.set_dual(val);
506 })
507 }
508
509 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
510 ///
511 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
512 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
513 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
514 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
515 /// defines the period at which the buffer should be read.
516 ///
517 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
518 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
519 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
520 /// the buffer length should be `3 * 40 = 120`.
521 ///
522 /// # Parameters
523 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
524 /// - `dma_buf`: The buffer where DMA stores ADC samples.
525 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
526 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
527 ///
528 /// # Returns
529 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
530 pub fn into_ring_buffered<'a>(
531 mut self,
532 dma: Peri<'a, impl RxDma<T>>,
533 dma_buf: &'a mut [u16],
534 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
535 mode: RegularConversionMode,
536 ) -> RingBufferedAdc<'a, T> {
537 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
538 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
539 assert!(
540 sequence.len() <= 16,
541 "Asynchronous read sequence cannot be more than 16 in length"
542 );
543 // reset conversions and enable the adc
544 Self::stop_regular_conversions();
545 Self::enable();
546
547 //adc side setup
548 Self::configure_sequence(
549 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
550 );
551
552 // Clear overrun flag before starting transfer.
553 T::regs().isr().modify(|reg| {
554 reg.set_ovr(true);
555 });
556
557 T::regs().cfgr().modify(|reg| {
558 reg.set_discen(false); // Convert all channels for each trigger
559 reg.set_dmacfg(Dmacfg::CIRCULAR);
560 reg.set_dmaen(Dmaen::ENABLE);
561 });
562
563 match mode {
564 RegularConversionMode::Continuous => {
565 T::regs().cfgr().modify(|reg| {
566 reg.set_cont(true);
567 });
568 }
569 RegularConversionMode::Triggered(trigger) => {
570 T::regs().cfgr().modify(|r| {
571 r.set_cont(false); // New trigger is neede for each sample to be read
572 });
573 self.set_regular_conversion_trigger(trigger);
574 }
575 }
576
577 mem::forget(self);
578
579 RingBufferedAdc::new(dma, dma_buf)
580 }
581
582 /// Configures the ADC for injected conversions. 383 /// Configures the ADC for injected conversions.
583 /// 384 ///
584 /// Injected conversions are separate from the regular conversion sequence and are typically 385 /// Injected conversions are separate from the regular conversion sequence and are typically
@@ -607,7 +408,7 @@ impl<'d, T: Instance> Adc<'d, T> {
607 /// - Accessing samples beyond `N` will result in a panic; use the returned type 408 /// - Accessing samples beyond `N` will result in a panic; use the returned type
608 /// `InjectedAdc<T, N>` to enforce bounds at compile time. 409 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
609 pub fn setup_injected_conversions<'a, const N: usize>( 410 pub fn setup_injected_conversions<'a, const N: usize>(
610 mut self, 411 self,
611 sequence: [(AnyAdcChannel<T>, SampleTime); N], 412 sequence: [(AnyAdcChannel<T>, SampleTime); N],
612 trigger: ConversionTrigger, 413 trigger: ConversionTrigger,
613 interrupt: bool, 414 interrupt: bool,
@@ -619,8 +420,7 @@ impl<'d, T: Instance> Adc<'d, T> {
619 NR_INJECTED_RANKS 420 NR_INJECTED_RANKS
620 ); 421 );
621 422
622 Self::stop_regular_conversions(); 423 T::enable();
623 Self::enable();
624 424
625 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); 425 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
626 426
@@ -649,8 +449,16 @@ impl<'d, T: Instance> Adc<'d, T> {
649 449
650 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false)); 450 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
651 451
652 self.set_injected_conversion_trigger(trigger); 452 // Set external trigger for injected conversion sequence
653 self.enable_injected_eos_interrupt(interrupt); 453 // Possible trigger values are seen in Table 167 in RM0440 Rev 9
454 T::regs().jsqr().modify(|r| {
455 r.set_jextsel(trigger.channel);
456 r.set_jexten(trigger.edge);
457 });
458
459 // Enable end of injected sequence interrupt
460 T::regs().ier().modify(|r| r.set_jeosie(interrupt));
461
654 Self::start_injected_conversions(); 462 Self::start_injected_conversions();
655 463
656 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels 464 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
@@ -683,12 +491,12 @@ impl<'d, T: Instance> Adc<'d, T> {
683 self, 491 self,
684 dma: Peri<'a, impl RxDma<T>>, 492 dma: Peri<'a, impl RxDma<T>>,
685 dma_buf: &'a mut [u16], 493 dma_buf: &'a mut [u16],
686 regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>, 494 regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, T::SampleTime)>,
687 regular_conversion_mode: RegularConversionMode, 495 regular_conversion_mode: RegularConversionMode,
688 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N], 496 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N],
689 injected_trigger: ConversionTrigger, 497 injected_trigger: ConversionTrigger,
690 injected_interrupt: bool, 498 injected_interrupt: bool,
691 ) -> (RingBufferedAdc<'a, T>, InjectedAdc<T, N>) { 499 ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<T, N>) {
692 unsafe { 500 unsafe {
693 ( 501 (
694 Self { 502 Self {
@@ -721,32 +529,6 @@ impl<'d, T: Instance> Adc<'d, T> {
721 reg.set_jadstart(true); 529 reg.set_jadstart(true);
722 }); 530 });
723 } 531 }
724
725 /// Set external trigger for injected conversion sequence
726 /// Possible trigger values are seen in Table 167 in RM0440 Rev 9
727 fn set_injected_conversion_trigger(&mut self, trigger: ConversionTrigger) {
728 T::regs().jsqr().modify(|r| {
729 r.set_jextsel(trigger.channel);
730 r.set_jexten(trigger.edge);
731 });
732 }
733
734 /// Enable end of injected sequence interrupt
735 fn enable_injected_eos_interrupt(&mut self, enable: bool) {
736 T::regs().ier().modify(|r| r.set_jeosie(enable));
737 }
738
739 // Stop regular conversions
740 fn stop_regular_conversions() {
741 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
742 T::regs().cr().modify(|reg| {
743 reg.set_adstp(Adstp::STOP);
744 });
745 // The software must poll ADSTART until the bit is reset before assuming the
746 // ADC is completely stopped
747 while T::regs().cr().read().adstart() {}
748 }
749 }
750} 532}
751 533
752impl<T: Instance, const N: usize> InjectedAdc<T, N> { 534impl<T: Instance, const N: usize> InjectedAdc<T, N> {
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs
index f9f1bba2a..ccaa5d1b2 100644
--- a/embassy-stm32/src/adc/injected.rs
+++ b/embassy-stm32/src/adc/injected.rs
@@ -5,9 +5,9 @@ use core::sync::atomic::{Ordering, compiler_fence};
5use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
6 6
7use super::{AnyAdcChannel, SampleTime}; 7use super::{AnyAdcChannel, SampleTime};
8use crate::adc::Adc;
9#[allow(unused_imports)] 8#[allow(unused_imports)]
10use crate::adc::Instance; 9use crate::adc::Instance;
10use crate::adc::{Adc, AnyInstance};
11 11
12/// Injected ADC sequence with owned channels. 12/// Injected ADC sequence with owned channels.
13pub struct InjectedAdc<T: Instance, const N: usize> { 13pub struct InjectedAdc<T: Instance, const N: usize> {
@@ -36,9 +36,9 @@ impl<T: Instance, const N: usize> InjectedAdc<T, N> {
36 } 36 }
37} 37}
38 38
39impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> { 39impl<T: Instance + AnyInstance, const N: usize> Drop for InjectedAdc<T, N> {
40 fn drop(&mut self) { 40 fn drop(&mut self) {
41 Adc::<T>::teardown_dma(); 41 T::stop();
42 compiler_fence(Ordering::SeqCst); 42 compiler_fence(Ordering::SeqCst);
43 } 43 }
44} 44}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index e321c4fa1..6d53d9b91 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -17,6 +17,9 @@
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)]
@@ -25,26 +28,25 @@ pub use _version::*;
25use embassy_hal_internal::{PeripheralType, impl_peripheral}; 28use embassy_hal_internal::{PeripheralType, impl_peripheral};
26#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] 29#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))]
27use embassy_sync::waitqueue::AtomicWaker; 30use embassy_sync::waitqueue::AtomicWaker;
31#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
32pub use ringbuffered::RingBufferedAdc;
28 33
29#[cfg(any(adc_u5, adc_wba))] 34#[cfg(any(adc_u5, adc_wba))]
30#[path = "adc4.rs"] 35#[path = "adc4.rs"]
31pub mod adc4; 36pub mod adc4;
32 37
38#[allow(unused)]
39pub(self) use crate::block_for_us as blocking_delay_us;
33pub use crate::pac::adc::vals; 40pub use crate::pac::adc::vals;
34#[cfg(not(any(adc_f1, adc_f3v3)))] 41#[cfg(not(any(adc_f1, adc_f3v3)))]
35pub use crate::pac::adc::vals::Res as Resolution; 42pub use crate::pac::adc::vals::Res as Resolution;
36pub use crate::pac::adc::vals::SampleTime; 43pub use crate::pac::adc::vals::SampleTime;
37use crate::peripherals; 44use crate::peripherals;
38 45
39#[cfg(not(adc_wba))] 46dma_trait!(RxDma, AnyInstance);
40dma_trait!(RxDma, Instance);
41#[cfg(adc_u5)]
42dma_trait!(RxDma4, adc4::Instance);
43#[cfg(adc_wba)]
44dma_trait!(RxDma4, adc4::Instance);
45 47
46/// Analog to Digital driver. 48/// Analog to Digital driver.
47pub struct Adc<'d, T: Instance> { 49pub struct Adc<'d, T: AnyInstance> {
48 #[allow(unused)] 50 #[allow(unused)]
49 adc: crate::Peri<'d, T>, 51 adc: crate::Peri<'d, T>,
50} 52}
@@ -87,21 +89,262 @@ pub(crate) trait SealedAdcChannel<T> {
87 } 89 }
88} 90}
89 91
90/// Performs a busy-wait delay for a specified number of microseconds. 92// Temporary patch for ADCs that have not implemented the standard iface yet
91#[allow(unused)] 93#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))]
92pub(crate) fn blocking_delay_us(us: u32) { 94trait_set::trait_set! {
93 cfg_if::cfg_if! { 95 pub trait AnyInstance = Instance;
94 // this does strange things on stm32wlx in low power mode depending on exactly when it's called 96}
95 // as in sometimes 15 us (1 tick) would take > 20 seconds. 97
96 if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] { 98#[cfg(any(
97 let duration = embassy_time::Duration::from_micros(us as u64); 99 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
98 embassy_time::block_for(duration); 100))]
99 } else { 101pub trait BasicAnyInstance {
100 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; 102 type SampleTime;
101 let us = us as u64; 103}
102 let cycles = freq * us / 1_000_000; 104
103 cortex_m::asm::delay(cycles as u32); 105#[cfg(any(
104 } 106 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
107))]
108pub(self) trait SealedAnyInstance: BasicAnyInstance {
109 fn enable();
110 fn start();
111 fn stop();
112 fn convert() -> u16;
113 fn configure_dma(conversion_mode: ConversionMode);
114 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>);
115 #[allow(dead_code)]
116 fn dr() -> *mut u16;
117}
118
119// On chips without ADC4, AnyInstance is an Instance
120#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))]
121#[allow(private_bounds)]
122pub trait AnyInstance: SealedAnyInstance + Instance {}
123
124// On chips with ADC4, AnyInstance is an Instance or adc4::Instance
125#[cfg(any(adc_v4, adc_u5, adc_wba))]
126#[allow(private_bounds)]
127pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {}
128
129// Implement AnyInstance automatically for SealedAnyInstance
130#[cfg(any(
131 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
132))]
133impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T {
134 type SampleTime = SampleTime;
135}
136
137#[cfg(any(
138 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
139))]
140impl<T: SealedAnyInstance + Instance> AnyInstance for T {}
141
142#[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
143/// Number of samples used for averaging.
144#[derive(Copy, Clone, Debug)]
145#[cfg_attr(feature = "defmt", derive(defmt::Format))]
146pub enum Averaging {
147 Disabled,
148 Samples2,
149 Samples4,
150 Samples8,
151 Samples16,
152 Samples32,
153 Samples64,
154 Samples128,
155 Samples256,
156 #[cfg(any(adc_c0, adc_v4, adc_u5))]
157 Samples512,
158 #[cfg(any(adc_c0, adc_v4, adc_u5))]
159 Samples1024,
160}
161
162#[cfg(any(
163 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0
164))]
165pub(crate) enum ConversionMode {
166 // Should match the cfg on "read" below
167 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
168 Singular,
169 // Should match the cfg on "into_ring_buffered" below
170 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
171 Repeated(RegularConversionMode),
172}
173
174// Should match the cfg on "into_ring_buffered" below
175#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
176// Conversion mode for regular ADC channels
177#[derive(Copy, Clone)]
178pub enum RegularConversionMode {
179 // Samples as fast as possible
180 Continuous,
181 #[cfg(adc_g4)]
182 // Sample at rate determined by external trigger
183 Triggered(ConversionTrigger),
184}
185
186impl<'d, T: AnyInstance> Adc<'d, T> {
187 #[cfg(any(
188 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0
189 ))]
190 /// Read an ADC pin.
191 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 {
192 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
193 channel.setup();
194
195 // Ensure no conversions are ongoing
196 T::stop();
197 #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))]
198 T::enable();
199 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
200
201 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
202 //
203 // TODO: If hardware allows, enable after configure_sequence on all chips
204 #[cfg(any(adc_g4, adc_h5))]
205 T::enable();
206
207 T::convert()
208 }
209
210 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
211 /// Read one or multiple ADC regular channels using DMA.
212 ///
213 /// `sequence` iterator and `readings` must have the same length.
214 ///
215 /// Example
216 /// ```rust,ignore
217 /// use embassy_stm32::adc::{Adc, AdcChannel}
218 ///
219 /// let mut adc = Adc::new(p.ADC1);
220 /// let mut adc_pin0 = p.PA0.into();
221 /// let mut adc_pin1 = p.PA1.into();
222 /// let mut measurements = [0u16; 2];
223 ///
224 /// adc.read(
225 /// p.DMA1_CH2.reborrow(),
226 /// [
227 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
228 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
229 /// ]
230 /// .into_iter(),
231 /// &mut measurements,
232 /// )
233 /// .await;
234 /// defmt::info!("measurements: {}", measurements);
235 /// ```
236 ///
237 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
238 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
239 ///
240 /// Note: Depending on hardware limitations, this method may require channels to be passed
241 /// in order or require the sequence to have the same sample time for all channnels, depending
242 /// on the number and properties of the channels in the sequence. This method will panic if
243 /// the hardware cannot deliver the requested configuration.
244 pub async fn read(
245 &mut self,
246 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
247 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, T::SampleTime)>,
248 readings: &mut [u16],
249 ) {
250 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
251 assert!(
252 sequence.len() == readings.len(),
253 "Sequence length must be equal to readings length"
254 );
255 assert!(
256 sequence.len() <= 16,
257 "Asynchronous read sequence cannot be more than 16 in length"
258 );
259
260 // Ensure no conversions are ongoing
261 T::stop();
262 #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
263 T::enable();
264
265 T::configure_sequence(
266 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
267 );
268
269 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
270 //
271 // TODO: If hardware allows, enable after configure_sequence on all chips
272 #[cfg(any(adc_g4, adc_h5))]
273 T::enable();
274 T::configure_dma(ConversionMode::Singular);
275
276 let request = rx_dma.request();
277 let transfer =
278 unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::dr(), readings, Default::default()) };
279
280 T::start();
281
282 // Wait for conversion sequence to finish.
283 transfer.await;
284
285 // Ensure conversions are finished.
286 T::stop();
287 }
288
289 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
290 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
291 ///
292 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
293 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
294 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
295 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
296 /// defines the period at which the buffer should be read.
297 ///
298 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
299 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
300 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
301 /// the buffer length should be `3 * 40 = 120`.
302 ///
303 /// # Parameters
304 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
305 /// - `dma_buf`: The buffer where DMA stores ADC samples.
306 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
307 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
308 ///
309 /// # Returns
310 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
311 ///
312 /// Note: Depending on hardware limitations, this method may require channels to be passed
313 /// in order or require the sequence to have the same sample time for all channnels, depending
314 /// on the number and properties of the channels in the sequence. This method will panic if
315 /// the hardware cannot deliver the requested configuration.
316 pub fn into_ring_buffered<'a>(
317 self,
318 dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>,
319 dma_buf: &'a mut [u16],
320 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, T::SampleTime)>,
321 mode: RegularConversionMode,
322 ) -> RingBufferedAdc<'a, T> {
323 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
324 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
325 assert!(
326 sequence.len() <= 16,
327 "Asynchronous read sequence cannot be more than 16 in length"
328 );
329 // Ensure no conversions are ongoing
330 T::stop();
331 #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
332 T::enable();
333
334 T::configure_sequence(
335 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
336 );
337
338 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
339 //
340 // TODO: If hardware allows, enable after configure_sequence on all chips
341 #[cfg(any(adc_g4, adc_h5))]
342 T::enable();
343 T::configure_dma(ConversionMode::Repeated(mode));
344
345 core::mem::forget(self);
346
347 RingBufferedAdc::new(dma, dma_buf)
105 } 348 }
106} 349}
107 350
@@ -143,6 +386,14 @@ impl SpecialChannel for Temperature {}
143pub struct Vbat; 386pub struct Vbat;
144impl SpecialChannel for Vbat {} 387impl SpecialChannel for Vbat {}
145 388
389/// Vcore channel.
390pub struct Vcore;
391impl SpecialChannel for Vcore {}
392
393/// Internal dac channel.
394pub struct Dac;
395impl SpecialChannel for Dac {}
396
146/// ADC instance. 397/// ADC instance.
147#[cfg(not(any( 398#[cfg(not(any(
148 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, 399 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,
@@ -187,9 +438,9 @@ pub struct AnyAdcChannel<T> {
187 is_differential: bool, 438 is_differential: bool,
188 _phantom: PhantomData<T>, 439 _phantom: PhantomData<T>,
189} 440}
190impl_peripheral!(AnyAdcChannel<T: Instance>); 441impl_peripheral!(AnyAdcChannel<T: AnyInstance>);
191impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {} 442impl<T: AnyInstance> AdcChannel<T> for AnyAdcChannel<T> {}
192impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> { 443impl<T: AnyInstance> SealedAdcChannel<T> for AnyAdcChannel<T> {
193 fn channel(&self) -> u8 { 444 fn channel(&self) -> u8 {
194 self.channel 445 self.channel
195 } 446 }
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs
index 024c6acdc..5437866d3 100644
--- a/embassy-stm32/src/adc/ringbuffered.rs
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -4,7 +4,7 @@ use core::sync::atomic::{Ordering, compiler_fence};
4#[allow(unused_imports)] 4#[allow(unused_imports)]
5use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
6 6
7use crate::adc::Adc; 7use crate::adc::AnyInstance;
8#[allow(unused_imports)] 8#[allow(unused_imports)]
9use crate::adc::{Instance, RxDma}; 9use crate::adc::{Instance, RxDma};
10#[allow(unused_imports)] 10#[allow(unused_imports)]
@@ -19,7 +19,7 @@ pub struct RingBufferedAdc<'d, T: Instance> {
19 ring_buf: ReadableRingBuffer<'d, u16>, 19 ring_buf: ReadableRingBuffer<'d, u16>,
20} 20}
21 21
22impl<'d, T: Instance> RingBufferedAdc<'d, T> { 22impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> {
23 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self { 23 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self {
24 //dma side setup 24 //dma side setup
25 let opts = TransferOptions { 25 let opts = TransferOptions {
@@ -45,12 +45,10 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
45 compiler_fence(Ordering::SeqCst); 45 compiler_fence(Ordering::SeqCst);
46 self.ring_buf.start(); 46 self.ring_buf.start();
47 47
48 Adc::<T>::start(); 48 T::start();
49 } 49 }
50 50
51 pub fn stop(&mut self) { 51 pub fn stop(&mut self) {
52 Adc::<T>::stop();
53
54 self.ring_buf.request_pause(); 52 self.ring_buf.request_pause();
55 53
56 compiler_fence(Ordering::SeqCst); 54 compiler_fence(Ordering::SeqCst);
@@ -161,7 +159,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
161 return Ok(len); 159 return Ok(len);
162 } 160 }
163 Err(_) => { 161 Err(_) => {
164 self.stop(); 162 self.ring_buf.request_pause();
165 163
166 return Err(OverrunError); 164 return Err(OverrunError);
167 } 165 }
@@ -170,9 +168,9 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
170 } 168 }
171} 169}
172 170
173impl<T: Instance> Drop for RingBufferedAdc<'_, T> { 171impl<T: Instance + AnyInstance> Drop for RingBufferedAdc<'_, T> {
174 fn drop(&mut self) { 172 fn drop(&mut self) {
175 Adc::<T>::teardown_dma(); 173 T::stop();
176 174
177 compiler_fence(Ordering::SeqCst); 175 compiler_fence(Ordering::SeqCst);
178 176
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index efa1cc68c..3c4431ae0 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,15 +1,12 @@
1use core::mem;
2use core::sync::atomic::{Ordering, compiler_fence}; 1use core::sync::atomic::{Ordering, compiler_fence};
3 2
4use super::{Temperature, Vbat, VrefInt, blocking_delay_us}; 3use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us};
5use crate::adc::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel}; 4use crate::adc::{Adc, Instance, Resolution, SampleTime};
6use crate::pac::adc::vals; 5use crate::pac::adc::vals;
6pub use crate::pac::adccommon::vals::Adcpre;
7use crate::time::Hertz; 7use crate::time::Hertz;
8use crate::{Peri, rcc}; 8use crate::{Peri, rcc};
9 9
10mod ringbuffered;
11pub use ringbuffered::RingBufferedAdc;
12
13fn clear_interrupt_flags(r: crate::pac::adc::Adc) { 10fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
14 r.sr().modify(|regs| { 11 r.sr().modify(|regs| {
15 regs.set_eoc(false); 12 regs.set_eoc(false);
@@ -54,156 +51,75 @@ impl Temperature {
54 } 51 }
55} 52}
56 53
57enum Prescaler { 54fn from_pclk2(freq: Hertz) -> Adcpre {
58 Div2, 55 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V).
59 Div4, 56 #[cfg(stm32f2)]
60 Div6, 57 const MAX_FREQUENCY: Hertz = Hertz(30_000_000);
61 Div8, 58 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
62} 59 #[cfg(not(stm32f2))]
63 60 const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
64impl Prescaler { 61 let raw_div = rcc::raw_prescaler(freq.0, MAX_FREQUENCY.0);
65 fn from_pclk2(freq: Hertz) -> Self { 62 match raw_div {
66 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). 63 0..=1 => Adcpre::DIV2,
67 #[cfg(stm32f2)] 64 2..=3 => Adcpre::DIV4,
68 const MAX_FREQUENCY: Hertz = Hertz(30_000_000); 65 4..=5 => Adcpre::DIV6,
69 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. 66 6..=7 => Adcpre::DIV8,
70 #[cfg(not(stm32f2))] 67 _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."),
71 const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
72 let raw_div = freq.0 / MAX_FREQUENCY.0;
73 match raw_div {
74 0..=1 => Self::Div2,
75 2..=3 => Self::Div4,
76 4..=5 => Self::Div6,
77 6..=7 => Self::Div8,
78 _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."),
79 }
80 } 68 }
69}
81 70
82 fn adcpre(&self) -> crate::pac::adccommon::vals::Adcpre { 71/// ADC configuration
83 match self { 72#[derive(Default)]
84 Prescaler::Div2 => crate::pac::adccommon::vals::Adcpre::DIV2, 73pub struct AdcConfig {
85 Prescaler::Div4 => crate::pac::adccommon::vals::Adcpre::DIV4, 74 resolution: Option<Resolution>,
86 Prescaler::Div6 => crate::pac::adccommon::vals::Adcpre::DIV6,
87 Prescaler::Div8 => crate::pac::adccommon::vals::Adcpre::DIV8,
88 }
89 }
90} 75}
91 76
92impl<'d, T> Adc<'d, T> 77impl<T: Instance> super::SealedAnyInstance for T {
93where 78 fn dr() -> *mut u16 {
94 T: Instance, 79 T::regs().dr().as_ptr() as *mut u16
95{ 80 }
96 pub fn new(adc: Peri<'d, T>) -> Self {
97 rcc::enable_and_reset::<T>();
98 81
99 let presc = Prescaler::from_pclk2(T::frequency()); 82 fn enable() {
100 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
101 T::regs().cr2().modify(|reg| { 83 T::regs().cr2().modify(|reg| {
102 reg.set_adon(true); 84 reg.set_adon(true);
103 }); 85 });
104 86
105 blocking_delay_us(3); 87 blocking_delay_us(3);
106
107 Self { adc }
108 }
109
110 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
111 ///
112 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
113 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
114 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
115 ///
116 /// `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.
117 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
118 ///
119 /// [`read`]: #method.read
120 pub fn into_ring_buffered<'a>(
121 self,
122 dma: Peri<'d, impl RxDma<T>>,
123 dma_buf: &'d mut [u16],
124 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
125 ) -> RingBufferedAdc<'d, T> {
126 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
127
128 Self::configure_sequence(sequence.map(|(mut channel, sample_time)| {
129 channel.setup();
130
131 (channel.channel, sample_time)
132 }));
133 compiler_fence(Ordering::SeqCst);
134
135 Self::setup_dma();
136
137 // Don't disable the clock
138 mem::forget(self);
139
140 RingBufferedAdc::new(dma, dma_buf)
141 }
142
143 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
144 channel.setup();
145
146 // Configure ADC
147 let channel = channel.channel();
148
149 Self::configure_sequence([(channel, sample_time)].into_iter());
150 Self::blocking_convert()
151 }
152
153 /// Enables internal voltage reference and returns [VrefInt], which can be used in
154 /// [Adc::read_internal()] to perform conversion.
155 pub fn enable_vrefint(&self) -> VrefInt {
156 T::common_regs().ccr().modify(|reg| {
157 reg.set_tsvrefe(true);
158 });
159
160 VrefInt {}
161 }
162
163 /// Enables internal temperature sensor and returns [Temperature], which can be used in
164 /// [Adc::read_internal()] to perform conversion.
165 ///
166 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
167 /// temperature sensor will return vbat value.
168 pub fn enable_temperature(&self) -> Temperature {
169 T::common_regs().ccr().modify(|reg| {
170 reg.set_tsvrefe(true);
171 });
172
173 Temperature {}
174 }
175
176 /// Enables vbat input and returns [Vbat], which can be used in
177 /// [Adc::read_internal()] to perform conversion.
178 pub fn enable_vbat(&self) -> Vbat {
179 T::common_regs().ccr().modify(|reg| {
180 reg.set_vbate(true);
181 });
182
183 Vbat {}
184 } 88 }
185 89
186 pub(super) fn start() { 90 fn start() {
187 // Begin ADC conversions 91 // Begin ADC conversions
188 T::regs().cr2().modify(|reg| { 92 T::regs().cr2().modify(|reg| {
189 reg.set_adon(true);
190 reg.set_swstart(true); 93 reg.set_swstart(true);
191 }); 94 });
192 } 95 }
193 96
194 pub(super) fn stop() { 97 fn stop() {
98 let r = T::regs();
99
195 // Stop ADC 100 // Stop ADC
196 T::regs().cr2().modify(|reg| { 101 r.cr2().modify(|reg| {
197 // Stop ADC 102 // Stop ADC
198 reg.set_swstart(false); 103 reg.set_swstart(false);
104 // Stop ADC
105 reg.set_adon(false);
106 // Stop DMA
107 reg.set_dma(false);
199 }); 108 });
200 }
201 109
202 pub fn set_resolution(&mut self, resolution: Resolution) { 110 r.cr1().modify(|w| {
203 T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); 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);
204 } 120 }
205 121
206 pub(super) fn blocking_convert() -> u16 { 122 fn convert() -> u16 {
207 // clear end of conversion flag 123 // clear end of conversion flag
208 T::regs().sr().modify(|reg| { 124 T::regs().sr().modify(|reg| {
209 reg.set_eoc(false); 125 reg.set_eoc(false);
@@ -224,7 +140,44 @@ where
224 T::regs().dr().read().0 as u16 140 T::regs().dr().read().0 as u16
225 } 141 }
226 142
227 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) { 143 fn configure_dma(conversion_mode: ConversionMode) {
144 match conversion_mode {
145 ConversionMode::Repeated(_) => {
146 let r = T::regs();
147
148 // Clear all interrupts
149 r.sr().modify(|regs| {
150 regs.set_eoc(false);
151 regs.set_ovr(false);
152 regs.set_strt(false);
153 });
154
155 r.cr1().modify(|w| {
156 // Enable interrupt for end of conversion
157 w.set_eocie(true);
158 // Enable interrupt for overrun
159 w.set_ovrie(true);
160 // Scanning converisons of multiple channels
161 w.set_scan(true);
162 // Continuous conversion mode
163 w.set_discen(false);
164 });
165
166 r.cr2().modify(|w| {
167 // Enable DMA mode
168 w.set_dma(true);
169 // Enable continuous conversions
170 w.set_cont(true);
171 // DMA requests are issues as long as DMA=1 and data are converted.
172 w.set_dds(vals::Dds::CONTINUOUS);
173 // EOC flag is set at the end of each conversion.
174 w.set_eocs(vals::Eocs::EACH_CONVERSION);
175 });
176 }
177 }
178 }
179
180 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
228 T::regs().cr2().modify(|reg| { 181 T::regs().cr2().modify(|reg| {
229 reg.set_adon(true); 182 reg.set_adon(true);
230 }); 183 });
@@ -234,7 +187,7 @@ where
234 r.set_l((sequence.len() - 1).try_into().unwrap()); 187 r.set_l((sequence.len() - 1).try_into().unwrap());
235 }); 188 });
236 189
237 for (i, (ch, sample_time)) in sequence.enumerate() { 190 for (i, ((ch, _), sample_time)) in sequence.enumerate() {
238 // Set the channel in the right sequence field. 191 // Set the channel in the right sequence field.
239 T::regs().sqr3().modify(|w| w.set_sq(i, ch)); 192 T::regs().sqr3().modify(|w| w.set_sq(i, ch));
240 193
@@ -246,63 +199,61 @@ where
246 } 199 }
247 } 200 }
248 } 201 }
202}
249 203
250 pub(super) fn setup_dma() { 204impl<'d, T> Adc<'d, T>
251 let r = T::regs(); 205where
206 T: Instance + super::AnyInstance,
207{
208 pub fn new(adc: Peri<'d, T>) -> Self {
209 Self::new_with_config(adc, Default::default())
210 }
252 211
253 // Clear all interrupts 212 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
254 r.sr().modify(|regs| { 213 rcc::enable_and_reset::<T>();
255 regs.set_eoc(false);
256 regs.set_ovr(false);
257 regs.set_strt(false);
258 });
259 214
260 r.cr1().modify(|w| { 215 let presc = from_pclk2(T::frequency());
261 // Enable interrupt for end of conversion 216 T::common_regs().ccr().modify(|w| w.set_adcpre(presc));
262 w.set_eocie(true); 217 T::enable();
263 // Enable interrupt for overrun
264 w.set_ovrie(true);
265 // Scanning converisons of multiple channels
266 w.set_scan(true);
267 // Continuous conversion mode
268 w.set_discen(false);
269 });
270 218
271 r.cr2().modify(|w| { 219 if let Some(resolution) = config.resolution {
272 // Enable DMA mode 220 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
273 w.set_dma(true); 221 }
274 // Enable continuous conversions
275 w.set_cont(true);
276 // DMA requests are issues as long as DMA=1 and data are converted.
277 w.set_dds(vals::Dds::CONTINUOUS);
278 // EOC flag is set at the end of each conversion.
279 w.set_eocs(vals::Eocs::EACH_CONVERSION);
280 });
281 }
282 222
283 pub(super) fn teardown_dma() { 223 Self { adc }
284 let r = T::regs(); 224 }
285 225
286 // Stop ADC 226 /// Enables internal voltage reference and returns [VrefInt], which can be used in
287 r.cr2().modify(|reg| { 227 /// [Adc::read_internal()] to perform conversion.
288 // Stop ADC 228 pub fn enable_vrefint(&self) -> VrefInt {
289 reg.set_swstart(false); 229 T::common_regs().ccr().modify(|reg| {
290 // Stop ADC 230 reg.set_tsvrefe(true);
291 reg.set_adon(false);
292 // Stop DMA
293 reg.set_dma(false);
294 }); 231 });
295 232
296 r.cr1().modify(|w| { 233 VrefInt {}
297 // Disable interrupt for end of conversion 234 }
298 w.set_eocie(false); 235
299 // Disable interrupt for overrun 236 /// Enables internal temperature sensor and returns [Temperature], which can be used in
300 w.set_ovrie(false); 237 /// [Adc::read_internal()] to perform conversion.
238 ///
239 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
240 /// temperature sensor will return vbat value.
241 pub fn enable_temperature(&self) -> Temperature {
242 T::common_regs().ccr().modify(|reg| {
243 reg.set_tsvrefe(true);
301 }); 244 });
302 245
303 clear_interrupt_flags(r); 246 Temperature {}
247 }
304 248
305 compiler_fence(Ordering::SeqCst); 249 /// Enables vbat input and returns [Vbat], which can be used in
250 /// [Adc::read_internal()] to perform conversion.
251 pub fn enable_vbat(&self) -> Vbat {
252 T::common_regs().ccr().modify(|reg| {
253 reg.set_vbate(true);
254 });
255
256 Vbat {}
306 } 257 }
307} 258}
308 259
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index cbc217545..b270588c4 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,9 +1,9 @@
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)]
@@ -11,18 +11,8 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc};
11 11
12#[allow(unused_imports)] 12#[allow(unused_imports)]
13use super::SealedAdcChannel; 13use super::SealedAdcChannel;
14use super::{ 14use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
15 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, Temperature, Vbat, VrefInt, 15use crate::adc::ConversionMode;
16 blocking_delay_us,
17};
18
19#[cfg(any(adc_v3, adc_g0, adc_u0))]
20mod ringbuffered;
21
22#[cfg(any(adc_v3, adc_g0, adc_u0))]
23use ringbuffered::RingBufferedAdc;
24
25use crate::dma::Transfer;
26use crate::{Peri, pac, rcc}; 16use crate::{Peri, pac, rcc};
27 17
28/// Default VREF voltage used for sample conversion to millivolts. 18/// Default VREF voltage used for sample conversion to millivolts.
@@ -75,7 +65,7 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
75} 65}
76#[cfg(any(adc_h5, adc_h7rs))] 66#[cfg(any(adc_h5, adc_h7rs))]
77impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { 67impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
78 const CHANNEL: u8 = 2; 68 const CHANNEL: u8 = 16;
79} 69}
80#[cfg(adc_u0)] 70#[cfg(adc_u0)]
81impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { 71impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
@@ -89,10 +79,10 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
89cfg_if! { 79cfg_if! {
90 if #[cfg(any(adc_h5, adc_h7rs))] { 80 if #[cfg(any(adc_h5, adc_h7rs))] {
91 pub struct VddCore; 81 pub struct VddCore;
92 impl<T: Instance> AdcChannel<T> for VddCore {} 82 impl<T: Instance> super::AdcChannel<T> for VddCore {}
93 impl<T: Instance> super::SealedAdcChannel<T> for VddCore { 83 impl<T: Instance> super::SealedAdcChannel<T> for VddCore {
94 fn channel(&self) -> u8 { 84 fn channel(&self) -> u8 {
95 6 85 17
96 } 86 }
97 } 87 }
98 } 88 }
@@ -101,7 +91,7 @@ cfg_if! {
101cfg_if! { 91cfg_if! {
102 if #[cfg(adc_u0)] { 92 if #[cfg(adc_u0)] {
103 pub struct DacOut; 93 pub struct DacOut;
104 impl<T: Instance> AdcChannel<T> for DacOut {} 94 impl<T: Instance> super::AdcChannel<T> for DacOut {}
105 impl<T: Instance> super::SealedAdcChannel<T> for DacOut { 95 impl<T: Instance> super::SealedAdcChannel<T> for DacOut {
106 fn channel(&self) -> u8 { 96 fn channel(&self) -> u8 {
107 19 97 19
@@ -110,21 +100,6 @@ cfg_if! {
110 } 100 }
111} 101}
112 102
113/// Number of samples used for averaging.
114#[derive(Copy, Clone, Debug)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub enum Averaging {
117 Disabled,
118 Samples2,
119 Samples4,
120 Samples8,
121 Samples16,
122 Samples32,
123 Samples64,
124 Samples128,
125 Samples256,
126}
127
128cfg_if! { if #[cfg(adc_g0)] { 103cfg_if! { if #[cfg(adc_g0)] {
129 104
130/// Synchronous PCLK prescaler 105/// Synchronous PCLK prescaler
@@ -145,310 +120,148 @@ pub enum Clock {
145 120
146}} 121}}
147 122
148impl<'d, T: Instance> Adc<'d, T> { 123#[cfg(adc_u0)]
149 /// Enable the voltage regulator 124type Ovss = u8;
150 fn init_regulator() { 125#[cfg(adc_u0)]
151 rcc::enable_and_reset::<T>(); 126type Ovsr = u8;
152 T::regs().cr().modify(|reg| { 127#[cfg(adc_v3)]
153 #[cfg(not(any(adc_g0, adc_u0)))] 128type Ovss = OversamplingShift;
154 reg.set_deeppwd(false); 129#[cfg(adc_v3)]
155 reg.set_advregen(true); 130type Ovsr = OversamplingRatio;
156 }); 131
157 132/// Adc configuration
158 // If this is false then each ADC_CHSELR bit enables an input channel. 133#[derive(Default)]
159 // This is the reset value, so has no effect. 134pub struct AdcConfig {
160 #[cfg(any(adc_g0, adc_u0))] 135 #[cfg(any(adc_u0, adc_g0, adc_v3))]
161 T::regs().cfgr1().modify(|reg| { 136 pub oversampling_shift: Option<Ovss>,
162 reg.set_chselrmod(false); 137 #[cfg(any(adc_u0, adc_g0, adc_v3))]
163 }); 138 pub oversampling_ratio: Option<Ovsr>,
139 #[cfg(any(adc_u0, adc_g0))]
140 pub oversampling_enable: Option<bool>,
141 #[cfg(adc_v3)]
142 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
143 #[cfg(adc_g0)]
144 pub clock: Option<Clock>,
145 pub resolution: Option<Resolution>,
146 pub averaging: Option<Averaging>,
147}
164 148
165 blocking_delay_us(20); 149impl<T: Instance> super::SealedAnyInstance for T {
150 fn dr() -> *mut u16 {
151 T::regs().dr().as_ptr() as *mut u16
166 } 152 }
167 153
168 /// Calibrate to remove conversion offset 154 // Enable ADC only when it is not already running.
169 fn init_calibrate() { 155 fn enable() {
170 T::regs().cr().modify(|reg| { 156 // Make sure bits are off
171 reg.set_adcal(true); 157 while T::regs().cr().read().addis() {
172 });
173
174 while T::regs().cr().read().adcal() {
175 // spin 158 // spin
176 } 159 }
177 160
178 blocking_delay_us(1); 161 if !T::regs().cr().read().aden() {
162 // Enable ADC
163 T::regs().isr().modify(|reg| {
164 reg.set_adrdy(true);
165 });
166 T::regs().cr().modify(|reg| {
167 reg.set_aden(true);
168 });
169
170 while !T::regs().isr().read().adrdy() {
171 // spin
172 }
173 }
179 } 174 }
180 175
181 #[cfg(any(adc_v3, adc_g0, adc_u0))] 176 fn start() {
182 pub(super) fn start() {
183 // Start adc conversion
184 T::regs().cr().modify(|reg| { 177 T::regs().cr().modify(|reg| {
185 reg.set_adstart(true); 178 reg.set_adstart(true);
186 }); 179 });
187 } 180 }
188 181
189 #[cfg(any(adc_v3, adc_g0, adc_u0))] 182 fn stop() {
190 pub(super) fn stop() { 183 // Ensure conversions are finished.
191 // Stop adc conversion
192 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 184 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
193 T::regs().cr().modify(|reg| { 185 T::regs().cr().modify(|reg| {
194 reg.set_adstp(true); 186 reg.set_adstp(true);
195 }); 187 });
196 while T::regs().cr().read().adstart() {} 188 while T::regs().cr().read().adstart() {}
197 } 189 }
198 }
199 190
200 #[cfg(any(adc_v3, adc_g0, adc_u0))] 191 // Reset configuration.
201 pub(super) fn teardown_dma() {
202 //disable dma control
203 #[cfg(not(any(adc_g0, adc_u0)))] 192 #[cfg(not(any(adc_g0, adc_u0)))]
204 T::regs().cfgr().modify(|reg| { 193 T::regs().cfgr().modify(|reg| {
194 reg.set_cont(false);
205 reg.set_dmaen(false); 195 reg.set_dmaen(false);
206 }); 196 });
207 #[cfg(any(adc_g0, adc_u0))] 197 #[cfg(any(adc_g0, adc_u0))]
208 T::regs().cfgr1().modify(|reg| { 198 T::regs().cfgr1().modify(|reg| {
199 reg.set_cont(false);
209 reg.set_dmaen(false); 200 reg.set_dmaen(false);
210 }); 201 });
211 } 202 }
212 203
213 /// Initialize the ADC leaving any analog clock at reset value. 204 /// Perform a single conversion.
214 /// For G0 and WL, this is the async clock without prescaler. 205 fn convert() -> u16 {
215 pub fn new(adc: Peri<'d, T>) -> Self { 206 // Some models are affected by an erratum:
216 Self::init_regulator(); 207 // If we perform conversions slower than 1 kHz, the first read ADC value can be
217 Self::init_calibrate(); 208 // corrupted, so we discard it and measure again.
218 Self { adc } 209 //
219 } 210 // STM32L471xx: Section 2.7.3
220 211 // STM32G4: Section 2.7.3
221 #[cfg(adc_g0)] 212 #[cfg(any(rcc_l4, rcc_g4))]
222 /// Initialize ADC with explicit clock for the analog ADC 213 let len = 2;
223 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self {
224 Self::init_regulator();
225
226 #[cfg(any(stm32wl5x))]
227 {
228 // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual
229 let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0;
230 match clock {
231 Clock::Async { div: _ } => {
232 assert!(async_clock_available);
233 }
234 Clock::Sync { div: _ } => {
235 if async_clock_available {
236 warn!("Not using configured ADC clock");
237 }
238 }
239 }
240 }
241 match clock {
242 Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)),
243 Clock::Sync { div } => T::regs().cfgr2().modify(|reg| {
244 reg.set_ckmode(match div {
245 CkModePclk::DIV1 => Ckmode::PCLK,
246 CkModePclk::DIV2 => Ckmode::PCLK_DIV2,
247 CkModePclk::DIV4 => Ckmode::PCLK_DIV4,
248 })
249 }),
250 }
251
252 Self::init_calibrate();
253
254 Self { adc }
255 }
256 214
257 // Enable ADC only when it is not already running. 215 #[cfg(not(any(rcc_l4, rcc_g4)))]
258 fn enable(&mut self) { 216 let len = 1;
259 // Make sure bits are off
260 while T::regs().cr().read().addis() {
261 // spin
262 }
263 217
264 if !T::regs().cr().read().aden() { 218 for _ in 0..len {
265 // Enable ADC
266 T::regs().isr().modify(|reg| { 219 T::regs().isr().modify(|reg| {
267 reg.set_adrdy(true); 220 reg.set_eos(true);
221 reg.set_eoc(true);
268 }); 222 });
223
224 // Start conversion
269 T::regs().cr().modify(|reg| { 225 T::regs().cr().modify(|reg| {
270 reg.set_aden(true); 226 reg.set_adstart(true);
271 }); 227 });
272 228
273 while !T::regs().isr().read().adrdy() { 229 while !T::regs().isr().read().eos() {
274 // spin 230 // spin
275 } 231 }
276 } 232 }
277 }
278
279 pub fn enable_vrefint(&self) -> VrefInt {
280 #[cfg(not(any(adc_g0, adc_u0)))]
281 T::common_regs().ccr().modify(|reg| {
282 reg.set_vrefen(true);
283 });
284 #[cfg(any(adc_g0, adc_u0))]
285 T::regs().ccr().modify(|reg| {
286 reg.set_vrefen(true);
287 });
288
289 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
290 // to stabilize the internal voltage reference.
291 blocking_delay_us(15);
292
293 VrefInt {}
294 }
295
296 pub fn enable_temperature(&self) -> Temperature {
297 cfg_if! {
298 if #[cfg(any(adc_g0, adc_u0))] {
299 T::regs().ccr().modify(|reg| {
300 reg.set_tsen(true);
301 });
302 } else if #[cfg(any(adc_h5, adc_h7rs))] {
303 T::common_regs().ccr().modify(|reg| {
304 reg.set_tsen(true);
305 });
306 } else {
307 T::common_regs().ccr().modify(|reg| {
308 reg.set_ch17sel(true);
309 });
310 }
311 }
312
313 Temperature {}
314 }
315 233
316 pub fn enable_vbat(&self) -> Vbat { 234 T::regs().dr().read().0 as u16
317 cfg_if! {
318 if #[cfg(any(adc_g0, adc_u0))] {
319 T::regs().ccr().modify(|reg| {
320 reg.set_vbaten(true);
321 });
322 } else if #[cfg(any(adc_h5, adc_h7rs))] {
323 T::common_regs().ccr().modify(|reg| {
324 reg.set_vbaten(true);
325 });
326 } else {
327 T::common_regs().ccr().modify(|reg| {
328 reg.set_ch18sel(true);
329 });
330 }
331 }
332
333 Vbat {}
334 }
335
336 /// Set the ADC resolution.
337 pub fn set_resolution(&mut self, resolution: Resolution) {
338 #[cfg(not(any(adc_g0, adc_u0)))]
339 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
340 #[cfg(any(adc_g0, adc_u0))]
341 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
342 }
343
344 pub fn set_averaging(&mut self, averaging: Averaging) {
345 let (enable, samples, right_shift) = match averaging {
346 Averaging::Disabled => (false, 0, 0),
347 Averaging::Samples2 => (true, 0, 1),
348 Averaging::Samples4 => (true, 1, 2),
349 Averaging::Samples8 => (true, 2, 3),
350 Averaging::Samples16 => (true, 3, 4),
351 Averaging::Samples32 => (true, 4, 5),
352 Averaging::Samples64 => (true, 5, 6),
353 Averaging::Samples128 => (true, 6, 7),
354 Averaging::Samples256 => (true, 7, 8),
355 };
356 T::regs().cfgr2().modify(|reg| {
357 #[cfg(not(any(adc_g0, adc_u0)))]
358 reg.set_rovse(enable);
359 #[cfg(any(adc_g0, adc_u0))]
360 reg.set_ovse(enable);
361 #[cfg(any(adc_h5, adc_h7rs))]
362 reg.set_ovsr(samples.into());
363 #[cfg(not(any(adc_h5, adc_h7rs)))]
364 reg.set_ovsr(samples.into());
365 reg.set_ovss(right_shift.into());
366 })
367 }
368 /*
369 /// Convert a raw sample from the `Temperature` to deg C
370 pub fn to_degrees_centigrade(sample: u16) -> f32 {
371 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
372 * (sample as f32 - VtempCal30::get().read() as f32)
373 + 30.0
374 } 235 }
375 */
376 236
377 /// Perform a single conversion. 237 fn configure_dma(conversion_mode: ConversionMode) {
378 fn convert(&mut self) -> u16 { 238 // Set continuous mode with oneshot dma.
239 // Clear overrun flag before starting transfer.
379 T::regs().isr().modify(|reg| { 240 T::regs().isr().modify(|reg| {
380 reg.set_eos(true); 241 reg.set_ovr(true);
381 reg.set_eoc(true);
382 });
383
384 // Start conversion
385 T::regs().cr().modify(|reg| {
386 reg.set_adstart(true);
387 }); 242 });
388 243
389 while !T::regs().isr().read().eos() { 244 #[cfg(not(any(adc_g0, adc_u0)))]
390 // spin 245 let regs = T::regs().cfgr();
391 }
392 246
393 T::regs().dr().read().0 as u16 247 #[cfg(any(adc_g0, adc_u0))]
394 } 248 let regs = T::regs().cfgr1();
395 249
396 /// Read an ADC channel. 250 regs.modify(|reg| {
397 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 251 reg.set_discen(false);
398 self.read_channel(channel, sample_time) 252 reg.set_cont(true);
253 reg.set_dmacfg(match conversion_mode {
254 ConversionMode::Singular => Dmacfg::ONE_SHOT,
255 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
256 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
257 });
258 reg.set_dmaen(true);
259 });
399 } 260 }
400 261
401 /// Read one or multiple ADC channels using DMA. 262 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
402 /// 263 #[cfg(adc_h5)]
403 /// `readings` must have a length that is a multiple of the length of the 264 T::regs().cr().modify(|w| w.set_aden(false));
404 /// `sequence` iterator.
405 ///
406 /// Note: The order of values in `readings` is defined by the pin ADC
407 /// channel number and not the pin order in `sequence`.
408 ///
409 /// Example
410 /// ```rust,ignore
411 /// use embassy_stm32::adc::{Adc, AdcChannel}
412 ///
413 /// let mut adc = Adc::new(p.ADC1);
414 /// let mut adc_pin0 = p.PA0.degrade_adc();
415 /// let mut adc_pin1 = p.PA1.degrade_adc();
416 /// let mut measurements = [0u16; 2];
417 ///
418 /// adc.read(
419 /// p.DMA1_CH2.reborrow(),
420 /// [
421 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
422 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
423 /// ]
424 /// .into_iter(),
425 /// &mut measurements,
426 /// )
427 /// .await;
428 /// defmt::info!("measurements: {}", measurements);
429 /// ```
430 pub async fn read(
431 &mut self,
432 rx_dma: Peri<'_, impl RxDma<T>>,
433 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
434 readings: &mut [u16],
435 ) {
436 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
437 assert!(
438 readings.len() % sequence.len() == 0,
439 "Readings length must be a multiple of sequence length"
440 );
441 assert!(
442 sequence.len() <= 16,
443 "Asynchronous read sequence cannot be more than 16 in length"
444 );
445
446 #[cfg(all(feature = "low-power", stm32wlex))]
447 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
448
449 // Ensure no conversions are ongoing and ADC is enabled.
450 Self::cancel_conversions();
451 self.enable();
452 265
453 // Set sequence length 266 // Set sequence length
454 #[cfg(not(any(adc_g0, adc_u0)))] 267 #[cfg(not(any(adc_g0, adc_u0)))]
@@ -462,10 +275,10 @@ impl<'d, T: Instance> Adc<'d, T> {
462 275
463 T::regs().chselr().write(|chselr| { 276 T::regs().chselr().write(|chselr| {
464 T::regs().smpr().write(|smpr| { 277 T::regs().smpr().write(|smpr| {
465 for (channel, sample_time) in sequence { 278 for ((channel, _), sample_time) in sequence {
466 chselr.set_chsel(channel.channel.into(), true); 279 chselr.set_chsel(channel.into(), true);
467 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { 280 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
468 smpr.set_smpsel(channel.channel.into(), (i as u8).into()); 281 smpr.set_smpsel(channel.into(), (i as u8).into());
469 } else { 282 } else {
470 smpr.set_sample_time(sample_times.len(), sample_time); 283 smpr.set_sample_time(sample_times.len(), sample_time);
471 if let Err(_) = sample_times.push(sample_time) { 284 if let Err(_) = sample_times.push(sample_time) {
@@ -484,42 +297,86 @@ impl<'d, T: Instance> Adc<'d, T> {
484 #[cfg(adc_u0)] 297 #[cfg(adc_u0)]
485 let mut channel_mask = 0; 298 let mut channel_mask = 0;
486 299
300 #[cfg(adc_h5)]
301 let mut difsel = 0u32;
302
487 // Configure channels and ranks 303 // Configure channels and ranks
488 for (_i, (channel, sample_time)) in sequence.enumerate() { 304 for (_i, ((channel, _is_differential), sample_time)) in sequence.enumerate() {
489 Self::configure_channel(channel, sample_time); 305 // RM0492, RM0481, etc.
306 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
307 #[cfg(any(adc_h5, adc_h7rs))]
308 if channel == 0 {
309 T::regs().or().modify(|reg| reg.set_op0(true));
310 }
311
312 // Configure channel
313 cfg_if! {
314 if #[cfg(adc_u0)] {
315 // On G0 and U6 all channels use the same sampling time.
316 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
317 } else if #[cfg(any(adc_h5, adc_h7rs))] {
318 match channel {
319 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
320 _ => T::regs().smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
321 }
322 } else {
323 let sample_time = sample_time.into();
324 T::regs()
325 .smpr(channel as usize / 10)
326 .modify(|reg| reg.set_smp(channel as usize % 10, sample_time));
327 }
328 }
329
330 #[cfg(stm32h7)]
331 {
332 use crate::pac::adc::vals::Pcsel;
333
334 T::regs().cfgr2().modify(|w| w.set_lshift(0));
335 T::regs()
336 .pcsel()
337 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
338 }
490 339
491 // Each channel is sampled according to sequence 340 // Each channel is sampled according to sequence
492 #[cfg(not(any(adc_g0, adc_u0)))] 341 #[cfg(not(any(adc_g0, adc_u0)))]
493 match _i { 342 match _i {
494 0..=3 => { 343 0..=3 => {
495 T::regs().sqr1().modify(|w| { 344 T::regs().sqr1().modify(|w| {
496 w.set_sq(_i, channel.channel()); 345 w.set_sq(_i, channel);
497 }); 346 });
498 } 347 }
499 4..=8 => { 348 4..=8 => {
500 T::regs().sqr2().modify(|w| { 349 T::regs().sqr2().modify(|w| {
501 w.set_sq(_i - 4, channel.channel()); 350 w.set_sq(_i - 4, channel);
502 }); 351 });
503 } 352 }
504 9..=13 => { 353 9..=13 => {
505 T::regs().sqr3().modify(|w| { 354 T::regs().sqr3().modify(|w| {
506 w.set_sq(_i - 9, channel.channel()); 355 w.set_sq(_i - 9, channel);
507 }); 356 });
508 } 357 }
509 14..=15 => { 358 14..=15 => {
510 T::regs().sqr4().modify(|w| { 359 T::regs().sqr4().modify(|w| {
511 w.set_sq(_i - 14, channel.channel()); 360 w.set_sq(_i - 14, channel);
512 }); 361 });
513 } 362 }
514 _ => unreachable!(), 363 _ => unreachable!(),
515 } 364 }
516 365
366 #[cfg(adc_h5)]
367 {
368 difsel |= (_is_differential as u32) << channel;
369 }
370
517 #[cfg(adc_u0)] 371 #[cfg(adc_u0)]
518 { 372 {
519 channel_mask |= 1 << channel.channel(); 373 channel_mask |= 1 << channel;
520 } 374 }
521 } 375 }
522 376
377 #[cfg(adc_h5)]
378 T::regs().difsel().write(|w| w.set_difsel(difsel));
379
523 // On G0 and U0 enabled channels are sampled from 0 to last channel. 380 // On G0 and U0 enabled channels are sampled from 0 to last channel.
524 // It is possible to add up to 8 sequences if CHSELRMOD = 1. 381 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
525 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. 382 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
@@ -528,312 +385,234 @@ impl<'d, T: Instance> Adc<'d, T> {
528 reg.set_chsel(channel_mask); 385 reg.set_chsel(channel_mask);
529 }); 386 });
530 } 387 }
531 // Set continuous mode with oneshot dma. 388 }
532 // Clear overrun flag before starting transfer. 389}
533 T::regs().isr().modify(|reg| {
534 reg.set_ovr(true);
535 });
536 390
537 #[cfg(not(any(adc_g0, adc_u0)))] 391impl<'d, T: Instance> Adc<'d, T> {
538 T::regs().cfgr().modify(|reg| { 392 /// Enable the voltage regulator
539 reg.set_discen(false); 393 fn init_regulator() {
540 reg.set_cont(true); 394 rcc::enable_and_reset::<T>();
541 reg.set_dmacfg(Dmacfg::ONE_SHOT); 395 T::regs().cr().modify(|reg| {
542 reg.set_dmaen(true); 396 #[cfg(not(any(adc_g0, adc_u0)))]
397 reg.set_deeppwd(false);
398 reg.set_advregen(true);
543 }); 399 });
400
401 // If this is false then each ADC_CHSELR bit enables an input channel.
402 // This is the reset value, so has no effect.
544 #[cfg(any(adc_g0, adc_u0))] 403 #[cfg(any(adc_g0, adc_u0))]
545 T::regs().cfgr1().modify(|reg| { 404 T::regs().cfgr1().modify(|reg| {
546 reg.set_discen(false); 405 reg.set_chselrmod(false);
547 reg.set_cont(true);
548 reg.set_dmacfg(Dmacfg::ONE_SHOT);
549 reg.set_dmaen(true);
550 }); 406 });
551 407
552 let request = rx_dma.request(); 408 blocking_delay_us(20);
553 let transfer = unsafe { 409 }
554 Transfer::new_read(
555 rx_dma,
556 request,
557 T::regs().dr().as_ptr() as *mut u16,
558 readings,
559 Default::default(),
560 )
561 };
562 410
563 // Start conversion 411 /// Calibrate to remove conversion offset
412 fn init_calibrate() {
564 T::regs().cr().modify(|reg| { 413 T::regs().cr().modify(|reg| {
565 reg.set_adstart(true); 414 reg.set_adcal(true);
566 }); 415 });
567 416
568 // Wait for conversion sequence to finish. 417 while T::regs().cr().read().adcal() {
569 transfer.await; 418 // spin
570 419 }
571 // Ensure conversions are finished.
572 Self::cancel_conversions();
573 420
574 // Reset configuration. 421 blocking_delay_us(1);
575 #[cfg(not(any(adc_g0, adc_u0)))]
576 T::regs().cfgr().modify(|reg| {
577 reg.set_cont(false);
578 });
579 #[cfg(any(adc_g0, adc_u0))]
580 T::regs().cfgr1().modify(|reg| {
581 reg.set_cont(false);
582 });
583 } 422 }
584 423
585 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. 424 /// Initialize the ADC leaving any analog clock at reset value.
586 /// 425 /// For G0 and WL, this is the async clock without prescaler.
587 /// The `dma_buf` should be large enough to prevent DMA buffer overrun. 426 pub fn new(adc: Peri<'d, T>) -> Self {
588 /// The length of the `dma_buf` should be a multiple of the ADC channel count. 427 Self::init_regulator();
589 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements. 428 Self::init_calibrate();
590 /// 429 Self { adc }
591 /// `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. 430 }
592 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
593 ///
594 /// [`read`]: #method.read
595 #[cfg(any(adc_v3, adc_g0, adc_u0))]
596 pub fn into_ring_buffered<'a>(
597 &mut self,
598 dma: Peri<'a, impl RxDma<T>>,
599 dma_buf: &'a mut [u16],
600 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
601 ) -> RingBufferedAdc<'a, T> {
602 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
603 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
604 assert!(
605 sequence.len() <= 16,
606 "Asynchronous read sequence cannot be more than 16 in length"
607 );
608 // reset conversions and enable the adc
609 Self::cancel_conversions();
610 self.enable();
611
612 //adc side setup
613 431
614 // Set sequence length 432 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
615 #[cfg(not(any(adc_g0, adc_u0)))] 433 #[cfg(not(adc_g0))]
616 T::regs().sqr1().modify(|w| { 434 let s = Self::new(adc);
617 w.set_l(sequence.len() as u8 - 1);
618 });
619 435
620 #[cfg(adc_g0)] 436 #[cfg(adc_g0)]
621 { 437 let s = match config.clock {
622 let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new(); 438 Some(clock) => Self::new_with_clock(adc, clock),
439 None => Self::new(adc),
440 };
623 441
624 T::regs().chselr().write(|chselr| { 442 #[cfg(any(adc_g0, adc_u0, adc_v3))]
625 T::regs().smpr().write(|smpr| { 443 if let Some(shift) = config.oversampling_shift {
626 for (channel, sample_time) in sequence { 444 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
627 chselr.set_chsel(channel.channel.into(), true);
628 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
629 smpr.set_smpsel(channel.channel.into(), (i as u8).into());
630 } else {
631 smpr.set_sample_time(sample_times.len(), sample_time);
632 if let Err(_) = sample_times.push(sample_time) {
633 panic!(
634 "Implementation is limited to {} unique sample times among all channels.",
635 SAMPLE_TIMES_CAPACITY
636 );
637 }
638 }
639 }
640 })
641 });
642 } 445 }
643 #[cfg(not(adc_g0))]
644 {
645 #[cfg(adc_u0)]
646 let mut channel_mask = 0;
647 446
648 // Configure channels and ranks 447 #[cfg(any(adc_g0, adc_u0, adc_v3))]
649 for (_i, (mut channel, sample_time)) in sequence.enumerate() { 448 if let Some(ratio) = config.oversampling_ratio {
650 Self::configure_channel(&mut channel, sample_time); 449 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
450 }
651 451
652 // Each channel is sampled according to sequence 452 #[cfg(any(adc_g0, adc_u0))]
653 #[cfg(not(any(adc_g0, adc_u0)))] 453 if let Some(enable) = config.oversampling_enable {
654 match _i { 454 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
655 0..=3 => { 455 }
656 T::regs().sqr1().modify(|w| {
657 w.set_sq(_i, channel.channel());
658 });
659 }
660 4..=8 => {
661 T::regs().sqr2().modify(|w| {
662 w.set_sq(_i - 4, channel.channel());
663 });
664 }
665 9..=13 => {
666 T::regs().sqr3().modify(|w| {
667 w.set_sq(_i - 9, channel.channel());
668 });
669 }
670 14..=15 => {
671 T::regs().sqr4().modify(|w| {
672 w.set_sq(_i - 14, channel.channel());
673 });
674 }
675 _ => unreachable!(),
676 }
677 456
678 #[cfg(adc_u0)] 457 #[cfg(adc_v3)]
679 { 458 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
680 channel_mask |= 1 << channel.channel(); 459 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
681 } 460 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
682 } 461 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
462 }
683 463
684 // On G0 and U0 enabled channels are sampled from 0 to last channel. 464 if let Some(resolution) = config.resolution {
685 // It is possible to add up to 8 sequences if CHSELRMOD = 1. 465 #[cfg(not(any(adc_g0, adc_u0)))]
686 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. 466 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
687 #[cfg(adc_u0)] 467 #[cfg(any(adc_g0, adc_u0))]
688 T::regs().chselr().modify(|reg| { 468 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
689 reg.set_chsel(channel_mask);
690 });
691 } 469 }
692 // Set continuous mode with Circular dma.
693 // Clear overrun flag before starting transfer.
694 T::regs().isr().modify(|reg| {
695 reg.set_ovr(true);
696 });
697 470
698 #[cfg(not(any(adc_g0, adc_u0)))] 471 if let Some(averaging) = config.averaging {
699 T::regs().cfgr().modify(|reg| { 472 let (enable, samples, right_shift) = match averaging {
700 reg.set_discen(false); 473 Averaging::Disabled => (false, 0, 0),
701 reg.set_cont(true); 474 Averaging::Samples2 => (true, 0, 1),
702 reg.set_dmacfg(Dmacfg::CIRCULAR); 475 Averaging::Samples4 => (true, 1, 2),
703 reg.set_dmaen(true); 476 Averaging::Samples8 => (true, 2, 3),
704 }); 477 Averaging::Samples16 => (true, 3, 4),
705 #[cfg(any(adc_g0, adc_u0))] 478 Averaging::Samples32 => (true, 4, 5),
706 T::regs().cfgr1().modify(|reg| { 479 Averaging::Samples64 => (true, 5, 6),
707 reg.set_discen(false); 480 Averaging::Samples128 => (true, 6, 7),
708 reg.set_cont(true); 481 Averaging::Samples256 => (true, 7, 8),
709 reg.set_dmacfg(Dmacfg::CIRCULAR); 482 };
710 reg.set_dmaen(true); 483 T::regs().cfgr2().modify(|reg| {
711 }); 484 #[cfg(not(any(adc_g0, adc_u0)))]
485 reg.set_rovse(enable);
486 #[cfg(any(adc_g0, adc_u0))]
487 reg.set_ovse(enable);
488 #[cfg(any(adc_h5, adc_h7rs))]
489 reg.set_ovsr(samples.into());
490 #[cfg(not(any(adc_h5, adc_h7rs)))]
491 reg.set_ovsr(samples.into());
492 reg.set_ovss(right_shift.into());
493 })
494 }
712 495
713 RingBufferedAdc::new(dma, dma_buf) 496 s
714 } 497 }
715 498
716 #[cfg(not(adc_g0))] 499 #[cfg(adc_g0)]
717 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 500 /// Initialize ADC with explicit clock for the analog ADC
718 // RM0492, RM0481, etc. 501 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self {
719 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 502 Self::init_regulator();
720 #[cfg(any(adc_h5, adc_h7rs))] 503
721 if channel.channel() == 0 { 504 #[cfg(any(stm32wl5x))]
722 T::regs().or().modify(|reg| reg.set_op0(true)); 505 {
506 // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual
507 let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0;
508 match clock {
509 Clock::Async { div: _ } => {
510 assert!(async_clock_available);
511 }
512 Clock::Sync { div: _ } => {
513 if async_clock_available {
514 warn!("Not using configured ADC clock");
515 }
516 }
517 }
518 }
519 match clock {
520 Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)),
521 Clock::Sync { div } => T::regs().cfgr2().modify(|reg| {
522 reg.set_ckmode(match div {
523 CkModePclk::DIV1 => Ckmode::PCLK,
524 CkModePclk::DIV2 => Ckmode::PCLK_DIV2,
525 CkModePclk::DIV4 => Ckmode::PCLK_DIV4,
526 })
527 }),
723 } 528 }
724 529
725 // Configure channel 530 Self::init_calibrate();
726 Self::set_channel_sample_time(channel.channel(), sample_time); 531
532 Self { adc }
727 } 533 }
728 534
729 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 535 pub fn enable_vrefint(&self) -> VrefInt {
730 self.enable();
731 #[cfg(not(adc_g0))]
732 Self::configure_channel(channel, sample_time);
733 #[cfg(adc_g0)]
734 T::regs().smpr().write(|reg| {
735 reg.set_sample_time(0, sample_time);
736 reg.set_smpsel(channel.channel().into(), Smpsel::SMP1);
737 });
738 // Select channel
739 #[cfg(not(any(adc_g0, adc_u0)))] 536 #[cfg(not(any(adc_g0, adc_u0)))]
740 T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel())); 537 T::common_regs().ccr().modify(|reg| {
538 reg.set_vrefen(true);
539 });
741 #[cfg(any(adc_g0, adc_u0))] 540 #[cfg(any(adc_g0, adc_u0))]
742 T::regs().chselr().write(|reg| { 541 T::regs().ccr().modify(|reg| {
743 #[cfg(adc_g0)] 542 reg.set_vrefen(true);
744 reg.set_chsel(channel.channel().into(), true);
745 #[cfg(adc_u0)]
746 reg.set_chsel(1 << channel.channel());
747 }); 543 });
748 544
749 // Some models are affected by an erratum: 545 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
750 // If we perform conversions slower than 1 kHz, the first read ADC value can be 546 // to stabilize the internal voltage reference.
751 // corrupted, so we discard it and measure again. 547 blocking_delay_us(15);
752 //
753 // STM32L471xx: Section 2.7.3
754 // STM32G4: Section 2.7.3
755 #[cfg(any(rcc_l4, rcc_g4))]
756 let _ = self.convert();
757 let val = self.convert();
758
759 T::regs().cr().modify(|reg| reg.set_addis(true));
760
761 // RM0492, RM0481, etc.
762 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
763 #[cfg(any(adc_h5, adc_h7rs))]
764 if channel.channel() == 0 {
765 T::regs().or().modify(|reg| reg.set_op0(false));
766 }
767
768 val
769 }
770
771 #[cfg(adc_g0)]
772 pub fn set_oversampling_shift(&mut self, shift: Ovss) {
773 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
774 }
775 #[cfg(adc_u0)]
776 pub fn set_oversampling_shift(&mut self, shift: u8) {
777 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
778 }
779 548
780 #[cfg(adc_g0)] 549 VrefInt {}
781 pub fn set_oversampling_ratio(&mut self, ratio: Ovsr) {
782 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
783 }
784 #[cfg(adc_u0)]
785 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
786 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
787 } 550 }
788 551
789 #[cfg(any(adc_g0, adc_u0))] 552 pub fn enable_temperature(&self) -> Temperature {
790 pub fn oversampling_enable(&mut self, enable: bool) { 553 cfg_if! {
791 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); 554 if #[cfg(any(adc_g0, adc_u0))] {
792 } 555 T::regs().ccr().modify(|reg| {
556 reg.set_tsen(true);
557 });
558 } else if #[cfg(any(adc_h5, adc_h7rs))] {
559 T::common_regs().ccr().modify(|reg| {
560 reg.set_tsen(true);
561 });
562 } else {
563 T::common_regs().ccr().modify(|reg| {
564 reg.set_ch17sel(true);
565 });
566 }
567 }
793 568
794 #[cfg(adc_v3)] 569 Temperature {}
795 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
796 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
797 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
798 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
799 } 570 }
800 571
801 #[cfg(adc_v3)] 572 pub fn enable_vbat(&self) -> Vbat {
802 pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) { 573 cfg_if! {
803 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); 574 if #[cfg(any(adc_g0, adc_u0))] {
804 } 575 T::regs().ccr().modify(|reg| {
576 reg.set_vbaten(true);
577 });
578 } else if #[cfg(any(adc_h5, adc_h7rs))] {
579 T::common_regs().ccr().modify(|reg| {
580 reg.set_vbaten(true);
581 });
582 } else {
583 T::common_regs().ccr().modify(|reg| {
584 reg.set_ch18sel(true);
585 });
586 }
587 }
805 588
806 #[cfg(adc_v3)] 589 Vbat {}
807 pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) {
808 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
809 } 590 }
810 591
811 #[cfg(not(adc_g0))] 592 pub fn disable_vbat(&self) {
812 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
813 cfg_if! { 593 cfg_if! {
814 if #[cfg(adc_u0)] { 594 if #[cfg(any(adc_g0, adc_u0))] {
815 // On G0 and U6 all channels use the same sampling time. 595 T::regs().ccr().modify(|reg| {
816 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 596 reg.set_vbaten(false);
597 });
817 } else if #[cfg(any(adc_h5, adc_h7rs))] { 598 } else if #[cfg(any(adc_h5, adc_h7rs))] {
818 match _ch { 599 T::common_regs().ccr().modify(|reg| {
819 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 600 reg.set_vbaten(false);
820 _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 601 });
821 }
822 } else { 602 } else {
823 let sample_time = sample_time.into(); 603 T::common_regs().ccr().modify(|reg| {
824 T::regs() 604 reg.set_ch18sel(false);
825 .smpr(_ch as usize / 10) 605 });
826 .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time));
827 } 606 }
828 } 607 }
829 } 608 }
830 609
831 fn cancel_conversions() { 610 /*
832 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 611 /// Convert a raw sample from the `Temperature` to deg C
833 T::regs().cr().modify(|reg| { 612 pub fn to_degrees_centigrade(sample: u16) -> f32 {
834 reg.set_adstp(true); 613 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
835 }); 614 * (sample as f32 - VtempCal30::get().read() as f32)
836 while T::regs().cr().read().adstart() {} 615 + 30.0
837 }
838 } 616 }
617 */
839} 618}
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 1d5d3fb92..a3d9e6176 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -4,11 +4,8 @@ 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 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, Temperature, Vbat, 8use crate::adc::ConversionMode;
9 VrefInt, blocking_delay_us,
10};
11use crate::dma::Transfer;
12use crate::time::Hertz; 9use crate::time::Hertz;
13use crate::{Peri, pac, rcc}; 10use crate::{Peri, pac, rcc};
14 11
@@ -62,101 +59,191 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
62 const CHANNEL: u8 = 18; 59 const CHANNEL: u8 = 18;
63} 60}
64 61
65// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 62fn from_ker_ck(frequency: Hertz) -> Presc {
66// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 63 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
67#[allow(unused)] 64 match raw_prescaler {
68enum Prescaler { 65 0 => Presc::DIV1,
69 NotDivided, 66 1 => Presc::DIV2,
70 DividedBy2, 67 2..=3 => Presc::DIV4,
71 DividedBy4, 68 4..=5 => Presc::DIV6,
72 DividedBy6, 69 6..=7 => Presc::DIV8,
73 DividedBy8, 70 8..=9 => Presc::DIV10,
74 DividedBy10, 71 10..=11 => Presc::DIV12,
75 DividedBy12, 72 _ => unimplemented!(),
76 DividedBy16, 73 }
77 DividedBy32, 74}
78 DividedBy64, 75
79 DividedBy128, 76/// Adc configuration
80 DividedBy256, 77#[derive(Default)]
78pub struct AdcConfig {
79 pub resolution: Option<Resolution>,
80 pub averaging: Option<Averaging>,
81} 81}
82 82
83impl Prescaler { 83impl<T: Instance> super::SealedAnyInstance for T {
84 fn from_ker_ck(frequency: Hertz) -> Self { 84 fn dr() -> *mut u16 {
85 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 85 T::regs().dr().as_ptr() as *mut u16
86 match raw_prescaler { 86 }
87 0 => Self::NotDivided, 87
88 1 => Self::DividedBy2, 88 fn enable() {
89 2..=3 => Self::DividedBy4, 89 T::regs().isr().write(|w| w.set_adrdy(true));
90 4..=5 => Self::DividedBy6, 90 T::regs().cr().modify(|w| w.set_aden(true));
91 6..=7 => Self::DividedBy8, 91 while !T::regs().isr().read().adrdy() {}
92 8..=9 => Self::DividedBy10, 92 T::regs().isr().write(|w| w.set_adrdy(true));
93 10..=11 => Self::DividedBy12, 93 }
94 _ => unimplemented!(), 94
95 fn start() {
96 // Start conversion
97 T::regs().cr().modify(|reg| {
98 reg.set_adstart(true);
99 });
100 }
101
102 fn stop() {
103 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
104 T::regs().cr().modify(|reg| {
105 reg.set_adstp(Adstp::STOP);
106 });
107 while T::regs().cr().read().adstart() {}
95 } 108 }
109
110 // Reset configuration.
111 T::regs().cfgr().modify(|reg| {
112 reg.set_cont(false);
113 reg.set_dmngt(Dmngt::from_bits(0));
114 });
96 } 115 }
97 116
98 fn divisor(&self) -> u32 { 117 fn convert() -> u16 {
99 match self { 118 T::regs().isr().modify(|reg| {
100 Prescaler::NotDivided => 1, 119 reg.set_eos(true);
101 Prescaler::DividedBy2 => 2, 120 reg.set_eoc(true);
102 Prescaler::DividedBy4 => 4, 121 });
103 Prescaler::DividedBy6 => 6, 122
104 Prescaler::DividedBy8 => 8, 123 // Start conversion
105 Prescaler::DividedBy10 => 10, 124 T::regs().cr().modify(|reg| {
106 Prescaler::DividedBy12 => 12, 125 reg.set_adstart(true);
107 Prescaler::DividedBy16 => 16, 126 });
108 Prescaler::DividedBy32 => 32, 127
109 Prescaler::DividedBy64 => 64, 128 while !T::regs().isr().read().eos() {
110 Prescaler::DividedBy128 => 128, 129 // spin
111 Prescaler::DividedBy256 => 256,
112 } 130 }
131
132 T::regs().dr().read().0 as u16
113 } 133 }
114 134
115 fn presc(&self) -> Presc { 135 fn configure_dma(conversion_mode: ConversionMode) {
116 match self { 136 match conversion_mode {
117 Prescaler::NotDivided => Presc::DIV1, 137 ConversionMode::Singular => {
118 Prescaler::DividedBy2 => Presc::DIV2, 138 T::regs().isr().modify(|reg| {
119 Prescaler::DividedBy4 => Presc::DIV4, 139 reg.set_ovr(true);
120 Prescaler::DividedBy6 => Presc::DIV6, 140 });
121 Prescaler::DividedBy8 => Presc::DIV8, 141 T::regs().cfgr().modify(|reg| {
122 Prescaler::DividedBy10 => Presc::DIV10, 142 reg.set_cont(true);
123 Prescaler::DividedBy12 => Presc::DIV12, 143 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
124 Prescaler::DividedBy16 => Presc::DIV16, 144 });
125 Prescaler::DividedBy32 => Presc::DIV32, 145 }
126 Prescaler::DividedBy64 => Presc::DIV64, 146 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
127 Prescaler::DividedBy128 => Presc::DIV128, 147 _ => unreachable!(),
128 Prescaler::DividedBy256 => Presc::DIV256,
129 } 148 }
130 } 149 }
131}
132 150
133/// Number of samples used for averaging. 151 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
134#[derive(Copy, Clone, Debug)] 152 // Set sequence length
135#[cfg_attr(feature = "defmt", derive(defmt::Format))] 153 T::regs().sqr1().modify(|w| {
136pub enum Averaging { 154 w.set_l(sequence.len() as u8 - 1);
137 Disabled, 155 });
138 Samples2, 156
139 Samples4, 157 // Configure channels and ranks
140 Samples8, 158 for (i, ((channel, _), sample_time)) in sequence.enumerate() {
141 Samples16, 159 let sample_time = sample_time.into();
142 Samples32, 160 if channel <= 9 {
143 Samples64, 161 T::regs().smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time));
144 Samples128, 162 } else {
145 Samples256, 163 T::regs()
146 Samples512, 164 .smpr(1)
147 Samples1024, 165 .modify(|reg| reg.set_smp((channel - 10) as _, sample_time));
166 }
167
168 #[cfg(any(stm32h7, stm32u5))]
169 {
170 T::regs().cfgr2().modify(|w| w.set_lshift(0));
171 T::regs()
172 .pcsel()
173 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
174 }
175
176 match i {
177 0..=3 => {
178 T::regs().sqr1().modify(|w| {
179 w.set_sq(i, channel);
180 });
181 }
182 4..=8 => {
183 T::regs().sqr2().modify(|w| {
184 w.set_sq(i - 4, channel);
185 });
186 }
187 9..=13 => {
188 T::regs().sqr3().modify(|w| {
189 w.set_sq(i - 9, channel);
190 });
191 }
192 14..=15 => {
193 T::regs().sqr4().modify(|w| {
194 w.set_sq(i - 14, channel);
195 });
196 }
197 _ => unreachable!(),
198 }
199 }
200 }
148} 201}
149 202
150impl<'d, T: Instance> Adc<'d, T> { 203impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> {
204 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
205 let s = Self::new(adc);
206
207 // Set the ADC resolution.
208 if let Some(resolution) = config.resolution {
209 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
210 }
211
212 // Set hardware averaging.
213 if let Some(averaging) = config.averaging {
214 let (enable, samples, right_shift) = match averaging {
215 Averaging::Disabled => (false, 0, 0),
216 Averaging::Samples2 => (true, 1, 1),
217 Averaging::Samples4 => (true, 3, 2),
218 Averaging::Samples8 => (true, 7, 3),
219 Averaging::Samples16 => (true, 15, 4),
220 Averaging::Samples32 => (true, 31, 5),
221 Averaging::Samples64 => (true, 63, 6),
222 Averaging::Samples128 => (true, 127, 7),
223 Averaging::Samples256 => (true, 255, 8),
224 Averaging::Samples512 => (true, 511, 9),
225 Averaging::Samples1024 => (true, 1023, 10),
226 };
227
228 T::regs().cfgr2().modify(|reg| {
229 reg.set_rovse(enable);
230 reg.set_ovsr(samples);
231 reg.set_ovss(right_shift);
232 })
233 }
234
235 s
236 }
237
151 /// Create a new ADC driver. 238 /// Create a new ADC driver.
152 pub fn new(adc: Peri<'d, T>) -> Self { 239 pub fn new(adc: Peri<'d, T>) -> Self {
153 rcc::enable_and_reset::<T>(); 240 rcc::enable_and_reset::<T>();
154 241
155 let prescaler = Prescaler::from_ker_ck(T::frequency()); 242 let prescaler = from_ker_ck(T::frequency());
156 243
157 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 244 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
158 245
159 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 246 let frequency = T::frequency() / prescaler;
160 info!("ADC frequency set to {}", frequency); 247 info!("ADC frequency set to {}", frequency);
161 248
162 if frequency > MAX_ADC_CLK_FREQ { 249 if frequency > MAX_ADC_CLK_FREQ {
@@ -179,37 +266,20 @@ impl<'d, T: Instance> Adc<'d, T> {
179 }; 266 };
180 T::regs().cr().modify(|w| w.set_boost(boost)); 267 T::regs().cr().modify(|w| w.set_boost(boost));
181 } 268 }
182 let mut s = Self { adc };
183 s.power_up();
184 s.configure_differential_inputs();
185 269
186 s.calibrate();
187 blocking_delay_us(1);
188
189 s.enable();
190 s.configure();
191
192 s
193 }
194
195 fn power_up(&mut self) {
196 T::regs().cr().modify(|reg| { 270 T::regs().cr().modify(|reg| {
197 reg.set_deeppwd(false); 271 reg.set_deeppwd(false);
198 reg.set_advregen(true); 272 reg.set_advregen(true);
199 }); 273 });
200 274
201 blocking_delay_us(10); 275 blocking_delay_us(10);
202 }
203 276
204 fn configure_differential_inputs(&mut self) {
205 T::regs().difsel().modify(|w| { 277 T::regs().difsel().modify(|w| {
206 for n in 0..20 { 278 for n in 0..20 {
207 w.set_difsel(n, Difsel::SINGLE_ENDED); 279 w.set_difsel(n, Difsel::SINGLE_ENDED);
208 } 280 }
209 }); 281 });
210 }
211 282
212 fn calibrate(&mut self) {
213 T::regs().cr().modify(|w| { 283 T::regs().cr().modify(|w| {
214 #[cfg(not(adc_u5))] 284 #[cfg(not(adc_u5))]
215 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 285 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
@@ -219,21 +289,18 @@ impl<'d, T: Instance> Adc<'d, T> {
219 T::regs().cr().modify(|w| w.set_adcal(true)); 289 T::regs().cr().modify(|w| w.set_adcal(true));
220 290
221 while T::regs().cr().read().adcal() {} 291 while T::regs().cr().read().adcal() {}
222 }
223 292
224 fn enable(&mut self) { 293 blocking_delay_us(1);
225 T::regs().isr().write(|w| w.set_adrdy(true)); 294
226 T::regs().cr().modify(|w| w.set_aden(true)); 295 T::enable();
227 while !T::regs().isr().read().adrdy() {}
228 T::regs().isr().write(|w| w.set_adrdy(true));
229 }
230 296
231 fn configure(&mut self) {
232 // single conversion mode, software trigger 297 // single conversion mode, software trigger
233 T::regs().cfgr().modify(|w| { 298 T::regs().cfgr().modify(|w| {
234 w.set_cont(false); 299 w.set_cont(false);
235 w.set_exten(Exten::DISABLED); 300 w.set_exten(Exten::DISABLED);
236 }); 301 });
302
303 Self { adc }
237 } 304 }
238 305
239 /// Enable reading the voltage reference internal channel. 306 /// Enable reading the voltage reference internal channel.
@@ -262,218 +329,4 @@ impl<'d, T: Instance> Adc<'d, T> {
262 329
263 Vbat {} 330 Vbat {}
264 } 331 }
265
266 /// Set the ADC resolution.
267 pub fn set_resolution(&mut self, resolution: Resolution) {
268 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
269 }
270
271 /// Set hardware averaging.
272 pub fn set_averaging(&mut self, averaging: Averaging) {
273 let (enable, samples, right_shift) = match averaging {
274 Averaging::Disabled => (false, 0, 0),
275 Averaging::Samples2 => (true, 1, 1),
276 Averaging::Samples4 => (true, 3, 2),
277 Averaging::Samples8 => (true, 7, 3),
278 Averaging::Samples16 => (true, 15, 4),
279 Averaging::Samples32 => (true, 31, 5),
280 Averaging::Samples64 => (true, 63, 6),
281 Averaging::Samples128 => (true, 127, 7),
282 Averaging::Samples256 => (true, 255, 8),
283 Averaging::Samples512 => (true, 511, 9),
284 Averaging::Samples1024 => (true, 1023, 10),
285 };
286
287 T::regs().cfgr2().modify(|reg| {
288 reg.set_rovse(enable);
289 reg.set_ovsr(samples);
290 reg.set_ovss(right_shift);
291 })
292 }
293
294 /// Perform a single conversion.
295 fn convert(&mut self) -> u16 {
296 T::regs().isr().modify(|reg| {
297 reg.set_eos(true);
298 reg.set_eoc(true);
299 });
300
301 // Start conversion
302 T::regs().cr().modify(|reg| {
303 reg.set_adstart(true);
304 });
305
306 while !T::regs().isr().read().eos() {
307 // spin
308 }
309
310 T::regs().dr().read().0 as u16
311 }
312
313 /// Read an ADC channel.
314 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
315 self.read_channel(channel, sample_time)
316 }
317
318 /// Read one or multiple ADC channels using DMA.
319 ///
320 /// `sequence` iterator and `readings` must have the same length.
321 ///
322 /// Example
323 /// ```rust,ignore
324 /// use embassy_stm32::adc::{Adc, AdcChannel}
325 ///
326 /// let mut adc = Adc::new(p.ADC1);
327 /// let mut adc_pin0 = p.PA0.into();
328 /// let mut adc_pin2 = p.PA2.into();
329 /// let mut measurements = [0u16; 2];
330 ///
331 /// adc.read(
332 /// p.DMA2_CH0.reborrow(),
333 /// [
334 /// (&mut *adc_pin0, SampleTime::CYCLES112),
335 /// (&mut *adc_pin2, SampleTime::CYCLES112),
336 /// ]
337 /// .into_iter(),
338 /// &mut measurements,
339 /// )
340 /// .await;
341 /// defmt::info!("measurements: {}", measurements);
342 /// ```
343 pub async fn read(
344 &mut self,
345 rx_dma: Peri<'_, impl RxDma<T>>,
346 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
347 readings: &mut [u16],
348 ) {
349 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
350 assert!(
351 sequence.len() == readings.len(),
352 "Sequence length must be equal to readings length"
353 );
354 assert!(
355 sequence.len() <= 16,
356 "Asynchronous read sequence cannot be more than 16 in length"
357 );
358
359 // Ensure no conversions are ongoing
360 Self::cancel_conversions();
361
362 // Set sequence length
363 T::regs().sqr1().modify(|w| {
364 w.set_l(sequence.len() as u8 - 1);
365 });
366
367 // Configure channels and ranks
368 for (i, (channel, sample_time)) in sequence.enumerate() {
369 Self::configure_channel(channel, sample_time);
370 match i {
371 0..=3 => {
372 T::regs().sqr1().modify(|w| {
373 w.set_sq(i, channel.channel());
374 });
375 }
376 4..=8 => {
377 T::regs().sqr2().modify(|w| {
378 w.set_sq(i - 4, channel.channel());
379 });
380 }
381 9..=13 => {
382 T::regs().sqr3().modify(|w| {
383 w.set_sq(i - 9, channel.channel());
384 });
385 }
386 14..=15 => {
387 T::regs().sqr4().modify(|w| {
388 w.set_sq(i - 14, channel.channel());
389 });
390 }
391 _ => unreachable!(),
392 }
393 }
394
395 // Set continuous mode with oneshot dma.
396 // Clear overrun flag before starting transfer.
397
398 T::regs().isr().modify(|reg| {
399 reg.set_ovr(true);
400 });
401 T::regs().cfgr().modify(|reg| {
402 reg.set_cont(true);
403 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
404 });
405
406 let request = rx_dma.request();
407 let transfer = unsafe {
408 Transfer::new_read(
409 rx_dma,
410 request,
411 T::regs().dr().as_ptr() as *mut u16,
412 readings,
413 Default::default(),
414 )
415 };
416
417 // Start conversion
418 T::regs().cr().modify(|reg| {
419 reg.set_adstart(true);
420 });
421
422 // Wait for conversion sequence to finish.
423 transfer.await;
424
425 // Ensure conversions are finished.
426 Self::cancel_conversions();
427
428 // Reset configuration.
429 T::regs().cfgr().modify(|reg| {
430 reg.set_cont(false);
431 reg.set_dmngt(Dmngt::from_bits(0));
432 });
433 }
434
435 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
436 channel.setup();
437
438 let channel = channel.channel();
439
440 Self::set_channel_sample_time(channel, sample_time);
441
442 #[cfg(any(stm32h7, stm32u5))]
443 {
444 T::regs().cfgr2().modify(|w| w.set_lshift(0));
445 T::regs()
446 .pcsel()
447 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
448 }
449 }
450
451 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
452 Self::configure_channel(channel, sample_time);
453
454 T::regs().sqr1().modify(|reg| {
455 reg.set_sq(0, channel.channel());
456 reg.set_l(0);
457 });
458
459 self.convert()
460 }
461
462 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
463 let sample_time = sample_time.into();
464 if ch <= 9 {
465 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
466 } else {
467 T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
468 }
469 }
470
471 fn cancel_conversions() {
472 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
473 T::regs().cr().modify(|reg| {
474 reg.set_adstp(Adstp::STOP);
475 });
476 while T::regs().cr().read().adstart() {}
477 }
478 }
479} 332}
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
index 90dbf4f09..b46ae2813 100644
--- a/embassy-stm32/src/dma/dma_bdma.rs
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -8,7 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker;
8 8
9use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 9use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
10use super::word::{Word, WordSize}; 10use super::word::{Word, WordSize};
11use super::{AnyChannel, Channel, Dir, Request, STATE}; 11use super::{AnyChannel, BusyChannel, Channel, Dir, Request, STATE};
12use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac}; 13use crate::{interrupt, pac};
14 14
@@ -602,7 +602,7 @@ impl AnyChannel {
602/// DMA transfer. 602/// DMA transfer.
603#[must_use = "futures do nothing unless you `.await` or poll them"] 603#[must_use = "futures do nothing unless you `.await` or poll them"]
604pub struct Transfer<'a> { 604pub struct Transfer<'a> {
605 channel: Peri<'a, AnyChannel>, 605 channel: BusyChannel<'a>,
606} 606}
607 607
608impl<'a> Transfer<'a> { 608impl<'a> Transfer<'a> {
@@ -713,7 +713,9 @@ impl<'a> Transfer<'a> {
713 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options, 713 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options,
714 ); 714 );
715 channel.start(); 715 channel.start();
716 Self { channel } 716 Self {
717 channel: BusyChannel::new(channel),
718 }
717 } 719 }
718 720
719 /// Request the transfer to pause, keeping the existing configuration for this channel. 721 /// Request the transfer to pause, keeping the existing configuration for this channel.
@@ -816,7 +818,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
816 818
817/// Ringbuffer for receiving data using DMA circular mode. 819/// Ringbuffer for receiving data using DMA circular mode.
818pub struct ReadableRingBuffer<'a, W: Word> { 820pub struct ReadableRingBuffer<'a, W: Word> {
819 channel: Peri<'a, AnyChannel>, 821 channel: BusyChannel<'a>,
820 ringbuf: ReadableDmaRingBuffer<'a, W>, 822 ringbuf: ReadableDmaRingBuffer<'a, W>,
821} 823}
822 824
@@ -853,7 +855,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
853 ); 855 );
854 856
855 Self { 857 Self {
856 channel, 858 channel: BusyChannel::new(channel),
857 ringbuf: ReadableDmaRingBuffer::new(buffer), 859 ringbuf: ReadableDmaRingBuffer::new(buffer),
858 } 860 }
859 } 861 }
@@ -972,7 +974,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
972 974
973/// Ringbuffer for writing data using DMA circular mode. 975/// Ringbuffer for writing data using DMA circular mode.
974pub struct WritableRingBuffer<'a, W: Word> { 976pub struct WritableRingBuffer<'a, W: Word> {
975 channel: Peri<'a, AnyChannel>, 977 channel: BusyChannel<'a>,
976 ringbuf: WritableDmaRingBuffer<'a, W>, 978 ringbuf: WritableDmaRingBuffer<'a, W>,
977} 979}
978 980
@@ -1009,7 +1011,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
1009 ); 1011 );
1010 1012
1011 Self { 1013 Self {
1012 channel, 1014 channel: BusyChannel::new(channel),
1013 ringbuf: WritableDmaRingBuffer::new(buffer), 1015 ringbuf: WritableDmaRingBuffer::new(buffer),
1014 } 1016 }
1015 } 1017 }
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs
index 106558d20..383c74a78 100644
--- a/embassy-stm32/src/dma/gpdma/mod.rs
+++ b/embassy-stm32/src/dma/gpdma/mod.rs
@@ -11,6 +11,7 @@ use linked_list::Table;
11 11
12use super::word::{Word, WordSize}; 12use super::word::{Word, WordSize};
13use super::{AnyChannel, Channel, Dir, Request, STATE}; 13use super::{AnyChannel, Channel, Dir, Request, STATE};
14use crate::dma::BusyChannel;
14use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
15use crate::pac; 16use crate::pac;
16use crate::pac::gpdma::vals; 17use crate::pac::gpdma::vals;
@@ -408,7 +409,7 @@ impl AnyChannel {
408/// Linked-list DMA transfer. 409/// Linked-list DMA transfer.
409#[must_use = "futures do nothing unless you `.await` or poll them"] 410#[must_use = "futures do nothing unless you `.await` or poll them"]
410pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { 411pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> {
411 channel: Peri<'a, AnyChannel>, 412 channel: BusyChannel<'a>,
412} 413}
413 414
414impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { 415impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> {
@@ -429,7 +430,9 @@ impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> {
429 channel.configure_linked_list(&table, options); 430 channel.configure_linked_list(&table, options);
430 channel.start(); 431 channel.start();
431 432
432 Self { channel } 433 Self {
434 channel: BusyChannel::new(channel),
435 }
433 } 436 }
434 437
435 /// Request the transfer to pause, keeping the existing configuration for this channel. 438 /// Request the transfer to pause, keeping the existing configuration for this channel.
@@ -505,7 +508,7 @@ impl<'a, const ITEM_COUNT: usize> Future for LinkedListTransfer<'a, ITEM_COUNT>
505/// DMA transfer. 508/// DMA transfer.
506#[must_use = "futures do nothing unless you `.await` or poll them"] 509#[must_use = "futures do nothing unless you `.await` or poll them"]
507pub struct Transfer<'a> { 510pub struct Transfer<'a> {
508 channel: Peri<'a, AnyChannel>, 511 channel: BusyChannel<'a>,
509} 512}
510 513
511impl<'a> Transfer<'a> { 514impl<'a> Transfer<'a> {
@@ -625,7 +628,9 @@ impl<'a> Transfer<'a> {
625 ); 628 );
626 channel.start(); 629 channel.start();
627 630
628 Self { channel } 631 Self {
632 channel: BusyChannel::new(channel),
633 }
629 } 634 }
630 635
631 /// Request the transfer to pause, keeping the existing configuration for this channel. 636 /// 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 94c597e0d..54e4d5f71 100644
--- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs
+++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
@@ -12,7 +12,7 @@ use 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::{BusyChannel, Channel, Dir, Request};
16 16
17struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); 17struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>);
18 18
@@ -49,7 +49,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
49 49
50/// Ringbuffer for receiving data using GPDMA linked-list mode. 50/// Ringbuffer for receiving data using GPDMA linked-list mode.
51pub struct ReadableRingBuffer<'a, W: Word> { 51pub struct ReadableRingBuffer<'a, W: Word> {
52 channel: Peri<'a, AnyChannel>, 52 channel: BusyChannel<'a>,
53 ringbuf: ReadableDmaRingBuffer<'a, W>, 53 ringbuf: ReadableDmaRingBuffer<'a, W>,
54 table: Table<2>, 54 table: Table<2>,
55 options: TransferOptions, 55 options: TransferOptions,
@@ -70,7 +70,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
70 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory); 70 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory);
71 71
72 Self { 72 Self {
73 channel, 73 channel: BusyChannel::new(channel),
74 ringbuf: ReadableDmaRingBuffer::new(buffer), 74 ringbuf: ReadableDmaRingBuffer::new(buffer),
75 table, 75 table,
76 options, 76 options,
@@ -189,7 +189,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
189 189
190/// Ringbuffer for writing data using GPDMA linked-list mode. 190/// Ringbuffer for writing data using GPDMA linked-list mode.
191pub struct WritableRingBuffer<'a, W: Word> { 191pub struct WritableRingBuffer<'a, W: Word> {
192 channel: Peri<'a, AnyChannel>, 192 channel: BusyChannel<'a>,
193 ringbuf: WritableDmaRingBuffer<'a, W>, 193 ringbuf: WritableDmaRingBuffer<'a, W>,
194 table: Table<2>, 194 table: Table<2>,
195 options: TransferOptions, 195 options: TransferOptions,
@@ -210,7 +210,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
210 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral); 210 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral);
211 211
212 Self { 212 Self {
213 channel, 213 channel: BusyChannel::new(channel),
214 ringbuf: WritableDmaRingBuffer::new(buffer), 214 ringbuf: WritableDmaRingBuffer::new(buffer),
215 table, 215 table,
216 options, 216 options,
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index de7a2c175..4becc2d87 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -3,11 +3,14 @@
3 3
4#[cfg(any(bdma, dma))] 4#[cfg(any(bdma, dma))]
5mod dma_bdma; 5mod dma_bdma;
6use core::ops;
7
6#[cfg(any(bdma, dma))] 8#[cfg(any(bdma, dma))]
7pub use dma_bdma::*; 9pub use dma_bdma::*;
8 10
9#[cfg(gpdma)] 11#[cfg(gpdma)]
10pub(crate) mod gpdma; 12pub(crate) mod gpdma;
13use embassy_hal_internal::Peri;
11#[cfg(gpdma)] 14#[cfg(gpdma)]
12pub use gpdma::ringbuffered::*; 15pub use gpdma::ringbuffered::*;
13#[cfg(gpdma)] 16#[cfg(gpdma)]
@@ -48,6 +51,8 @@ pub type Request = ();
48pub(crate) trait SealedChannel { 51pub(crate) trait SealedChannel {
49 #[cfg(not(stm32n6))] 52 #[cfg(not(stm32n6))]
50 fn id(&self) -> u8; 53 fn id(&self) -> u8;
54 #[cfg(feature = "low-power")]
55 fn stop_mode(&self) -> crate::rcc::StopMode;
51} 56}
52 57
53#[cfg(not(stm32n6))] 58#[cfg(not(stm32n6))]
@@ -62,15 +67,25 @@ pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {
62 67
63#[cfg(not(stm32n6))] 68#[cfg(not(stm32n6))]
64macro_rules! dma_channel_impl { 69macro_rules! dma_channel_impl {
65 ($channel_peri:ident, $index:expr) => { 70 ($channel_peri:ident, $index:expr, $stop_mode:ident) => {
66 impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { 71 impl crate::dma::SealedChannel for crate::peripherals::$channel_peri {
67 fn id(&self) -> u8 { 72 fn id(&self) -> u8 {
68 $index 73 $index
69 } 74 }
75
76 #[cfg(feature = "low-power")]
77 fn stop_mode(&self) -> crate::rcc::StopMode {
78 crate::rcc::StopMode::$stop_mode
79 }
70 } 80 }
71 impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri { 81 impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri {
72 unsafe fn on_irq() { 82 unsafe fn on_irq() {
73 crate::dma::AnyChannel { id: $index }.on_irq(); 83 crate::dma::AnyChannel {
84 id: $index,
85 #[cfg(feature = "low-power")]
86 stop_mode: crate::rcc::StopMode::$stop_mode,
87 }
88 .on_irq();
74 } 89 }
75 } 90 }
76 91
@@ -80,15 +95,57 @@ macro_rules! dma_channel_impl {
80 fn from(val: crate::peripherals::$channel_peri) -> Self { 95 fn from(val: crate::peripherals::$channel_peri) -> Self {
81 Self { 96 Self {
82 id: crate::dma::SealedChannel::id(&val), 97 id: crate::dma::SealedChannel::id(&val),
98 #[cfg(feature = "low-power")]
99 stop_mode: crate::dma::SealedChannel::stop_mode(&val),
83 } 100 }
84 } 101 }
85 } 102 }
86 }; 103 };
87} 104}
88 105
106pub(crate) struct BusyChannel<'a> {
107 channel: Peri<'a, AnyChannel>,
108}
109
110impl<'a> BusyChannel<'a> {
111 pub fn new(channel: Peri<'a, AnyChannel>) -> Self {
112 #[cfg(feature = "low-power")]
113 critical_section::with(|cs| {
114 crate::rcc::increment_stop_refcount(cs, channel.stop_mode);
115 });
116
117 Self { channel }
118 }
119}
120
121impl<'a> Drop for BusyChannel<'a> {
122 fn drop(&mut self) {
123 #[cfg(feature = "low-power")]
124 critical_section::with(|cs| {
125 crate::rcc::decrement_stop_refcount(cs, self.stop_mode);
126 });
127 }
128}
129
130impl<'a> ops::Deref for BusyChannel<'a> {
131 type Target = Peri<'a, AnyChannel>;
132
133 fn deref(&self) -> &Self::Target {
134 &self.channel
135 }
136}
137
138impl<'a> ops::DerefMut for BusyChannel<'a> {
139 fn deref_mut(&mut self) -> &mut Self::Target {
140 &mut self.channel
141 }
142}
143
89/// Type-erased DMA channel. 144/// Type-erased DMA channel.
90pub struct AnyChannel { 145pub struct AnyChannel {
91 pub(crate) id: u8, 146 pub(crate) id: u8,
147 #[cfg(feature = "low-power")]
148 pub(crate) stop_mode: crate::rcc::StopMode,
92} 149}
93impl_peripheral!(AnyChannel); 150impl_peripheral!(AnyChannel);
94 151
@@ -103,6 +160,11 @@ impl SealedChannel for AnyChannel {
103 fn id(&self) -> u8 { 160 fn id(&self) -> u8 {
104 self.id 161 self.id
105 } 162 }
163
164 #[cfg(feature = "low-power")]
165 fn stop_mode(&self) -> crate::rcc::StopMode {
166 self.stop_mode
167 }
106} 168}
107impl Channel for AnyChannel {} 169impl Channel for AnyChannel {}
108 170
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index 59a2cbcdb..b8945820c 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -5,18 +5,11 @@ 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::{Peri, peripherals}; 11use crate::{Peri, peripherals};
11 12
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
20/// PacketTypes extracted from CubeMX 13/// PacketTypes extracted from CubeMX
21#[repr(u8)] 14#[repr(u8)]
22#[allow(dead_code)] 15#[allow(dead_code)]
@@ -334,7 +327,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
334 if T::regs().gpsr().read().cmdfe() { 327 if T::regs().gpsr().read().cmdfe() {
335 return Ok(()); 328 return Ok(());
336 } 329 }
337 blocking_delay_ms(1); 330 block_for_us(1_000);
338 } 331 }
339 Err(Error::FifoTimeout) 332 Err(Error::FifoTimeout)
340 } 333 }
@@ -345,7 +338,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
345 if !T::regs().gpsr().read().cmdff() { 338 if !T::regs().gpsr().read().cmdff() {
346 return Ok(()); 339 return Ok(());
347 } 340 }
348 blocking_delay_ms(1); 341 block_for_us(1_000);
349 } 342 }
350 Err(Error::FifoTimeout) 343 Err(Error::FifoTimeout)
351 } 344 }
@@ -356,7 +349,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
356 if !self.read_busy() { 349 if !self.read_busy() {
357 return Ok(()); 350 return Ok(());
358 } 351 }
359 blocking_delay_ms(1); 352 block_for_us(1_000);
360 } 353 }
361 Err(Error::ReadTimeout) 354 Err(Error::ReadTimeout)
362 } 355 }
@@ -367,7 +360,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
367 if !T::regs().gpsr().read().prdfe() { 360 if !T::regs().gpsr().read().prdfe() {
368 return Ok(()); 361 return Ok(());
369 } 362 }
370 blocking_delay_ms(1); 363 block_for_us(1_000);
371 } 364 }
372 Err(Error::FifoTimeout) 365 Err(Error::FifoTimeout)
373 } 366 }
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 a77eb8719..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;
7use core::sync::atomic::{Ordering, fence}; 6use core::sync::atomic::{Ordering, fence};
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
@@ -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,58 +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!( 364 config_pins!(
354 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 365 rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
355 ); 366 );
356 367
357 let pins = Pins::Mii([ 368 let pins = Pins::Mii([
358 rx_clk.into(), 369 rx_clk.into(),
359 tx_clk.into(), 370 tx_clk.into(),
360 mdio.into(),
361 mdc.into(),
362 rxdv.into(), 371 rxdv.into(),
363 rx_d0.into(), 372 rx_d0.into(),
364 rx_d1.into(), 373 rx_d1.into(),
@@ -371,43 +380,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
371 tx_en.into(), 380 tx_en.into(),
372 ]); 381 ]);
373 382
374 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 383 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, false)
375 }
376}
377
378/// Ethernet station management interface.
379pub(crate) struct EthernetStationManagement<T: Instance> {
380 peri: PhantomData<T>,
381 clock_range: Cr,
382}
383
384impl<T: Instance> StationManagement for EthernetStationManagement<T> {
385 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
386 let mac = T::regs().ethernet_mac();
387
388 mac.macmiiar().modify(|w| {
389 w.set_pa(phy_addr);
390 w.set_mr(reg);
391 w.set_mw(Mw::READ); // read operation
392 w.set_cr(self.clock_range);
393 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
394 });
395 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
396 mac.macmiidr().read().md()
397 }
398
399 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
400 let mac = T::regs().ethernet_mac();
401
402 mac.macmiidr().write(|w| w.set_md(val));
403 mac.macmiiar().modify(|w| {
404 w.set_pa(phy_addr);
405 w.set_mr(reg);
406 w.set_mw(Mw::WRITE); // write
407 w.set_cr(self.clock_range);
408 w.set_mb(MbProgress::BUSY);
409 });
410 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
411 } 384 }
412} 385}
413 386
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 39a6e8b0f..7f92e351c 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,6 +1,5 @@
1mod descriptors; 1mod descriptors;
2 2
3use core::marker::PhantomData;
4use core::sync::atomic::{Ordering, fence}; 3use core::sync::atomic::{Ordering, fence};
5 4
6use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
@@ -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,31 +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
135 critical_section::with(|_| {
136 crate::pac::RCC.ahb1enr().modify(|w| {
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!( 184 config_pins!(
148 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 185 rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
149 ); 186 );
150 187
151 let pins = Pins::Mii([ 188 let pins = Pins::Mii([
152 rx_clk.into(), 189 rx_clk.into(),
153 tx_clk.into(), 190 tx_clk.into(),
154 mdio.into(),
155 mdc.into(),
156 rxdv.into(), 191 rxdv.into(),
157 rx_d0.into(), 192 rx_d0.into(),
158 rx_d1.into(), 193 rx_d1.into(),
@@ -165,7 +200,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
165 tx_en.into(), 200 tx_en.into(),
166 ]); 201 ]);
167 202
168 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 203 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, EthSelPhy::MII_GMII)
169 } 204 }
170 205
171 fn new_inner<const TX: usize, const RX: usize>( 206 fn new_inner<const TX: usize, const RX: usize>(
@@ -175,7 +210,19 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
175 pins: Pins<'d>, 210 pins: Pins<'d>,
176 phy: P, 211 phy: P,
177 mac_addr: [u8; 6], 212 mac_addr: [u8; 6],
213 eth_sel_phy: EthSelPhy,
178 ) -> 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
179 let dma = T::regs().ethernet_dma(); 226 let dma = T::regs().ethernet_dma();
180 let mac = T::regs().ethernet_mac(); 227 let mac = T::regs().ethernet_mac();
181 let mtl = T::regs().ethernet_mtl(); 228 let mtl = T::regs().ethernet_mtl();
@@ -237,32 +284,12 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
237 w.set_rbsz(RX_BUFFER_SIZE as u16); 284 w.set_rbsz(RX_BUFFER_SIZE as u16);
238 }); 285 });
239 286
240 let hclk = <T as SealedRccPeripheral>::frequency();
241 let hclk_mhz = hclk.0 / 1_000_000;
242
243 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
244 let clock_range = match hclk_mhz {
245 0..=34 => 2, // Divide by 16
246 35..=59 => 3, // Divide by 26
247 60..=99 => 0, // Divide by 42
248 100..=149 => 1, // Divide by 62
249 150..=249 => 4, // Divide by 102
250 250..=310 => 5, // Divide by 124
251 _ => {
252 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
253 }
254 };
255
256 let mut this = Self { 287 let mut this = Self {
257 _peri: peri, 288 _peri: peri,
258 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 289 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
259 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 290 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
260 pins, 291 pins,
261 phy, 292 phy,
262 station_management: EthernetStationManagement {
263 peri: PhantomData,
264 clock_range: clock_range,
265 },
266 mac_addr, 293 mac_addr,
267 }; 294 };
268 295
@@ -288,8 +315,8 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
288 w.set_tie(true); 315 w.set_tie(true);
289 }); 316 });
290 317
291 this.phy.phy_reset(&mut this.station_management); 318 this.phy.phy_reset();
292 this.phy.phy_init(&mut this.station_management); 319 this.phy.phy_init();
293 320
294 interrupt::ETH.unpend(); 321 interrupt::ETH.unpend();
295 unsafe { interrupt::ETH.enable() }; 322 unsafe { interrupt::ETH.enable() };
@@ -298,42 +325,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
298 } 325 }
299} 326}
300 327
301/// Ethernet SMI driver.
302pub struct EthernetStationManagement<T: Instance> {
303 peri: PhantomData<T>,
304 clock_range: u8,
305}
306
307impl<T: Instance> StationManagement for EthernetStationManagement<T> {
308 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
309 let mac = T::regs().ethernet_mac();
310
311 mac.macmdioar().modify(|w| {
312 w.set_pa(phy_addr);
313 w.set_rda(reg);
314 w.set_goc(0b11); // read
315 w.set_cr(self.clock_range);
316 w.set_mb(true);
317 });
318 while mac.macmdioar().read().mb() {}
319 mac.macmdiodr().read().md()
320 }
321
322 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
323 let mac = T::regs().ethernet_mac();
324
325 mac.macmdiodr().write(|w| w.set_md(val));
326 mac.macmdioar().modify(|w| {
327 w.set_pa(phy_addr);
328 w.set_rda(reg);
329 w.set_goc(0b01); // write
330 w.set_cr(self.clock_range);
331 w.set_mb(true);
332 });
333 while mac.macmdioar().read().mb() {}
334 }
335}
336
337impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { 328impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> {
338 fn drop(&mut self) { 329 fn drop(&mut self) {
339 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 cb46d362c..7b7896d46 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::{PeripheralType, impl_peripheral}; 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, PinNumber, Pull}; 12use crate::gpio::{AnyPin, ExtiPin, Input, Level, Pin as GpioPin, PinNumber, Pull};
13use crate::interrupt::Interrupt as InterruptEnum;
14use crate::interrupt::typelevel::{Binding, Handler, Interrupt as InterruptType};
12use crate::pac::EXTI; 15use crate::pac::EXTI;
13use crate::pac::exti::regs::Lines; 16use crate::pac::exti::regs::Lines;
14use crate::{Peri, interrupt, pac, peripherals}; 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];
@@ -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
@@ -227,11 +258,12 @@ impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> {
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: PinNumber, 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: PinNumber, port: PinNumber, 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));
@@ -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) -> PinNumber; 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 {
392 #[allow(unused)]
344 number: PinNumber, 393 number: PinNumber,
345} 394}
346 395
347impl_peripheral!(AnyChannel);
348impl SealedChannel for AnyChannel {}
349impl Channel for AnyChannel {
350 fn number(&self) -> PinNumber {
351 self.number
352 }
353}
354
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) -> PinNumber { 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 PinNumber, 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/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 b595938a6..60d00e766 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -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/g.rs b/embassy-stm32/src/flash/g.rs
index d026541a4..d7ba2f571 100644
--- a/embassy-stm32/src/flash/g.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -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 });
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 8a43cce3f..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::{Ordering, fence}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use embassy_sync::waitqueue::AtomicWaker;
5use pac::flash::regs::Sr;
6
4use super::{BANK1_REGION, FLASH_REGIONS, FlashSector, WRITE_SIZE}; 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/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/gpio.rs b/embassy-stm32/src/gpio.rs
index 17c5a9962..e7d4e9ad3 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -812,15 +812,19 @@ pub type PinNumber = u8;
812#[cfg(stm32n6)] 812#[cfg(stm32n6)]
813pub type PinNumber = u16; 813pub type PinNumber = u16;
814 814
815/// GPIO pin trait. 815/// Pin that can be used to configure an [ExtiInput](crate::exti::ExtiInput). This trait is lost when converting to [AnyPin].
816#[cfg(feature = "exti")]
816#[allow(private_bounds)] 817#[allow(private_bounds)]
817pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static { 818pub trait ExtiPin: PeripheralType + SealedPin {
818 /// EXTI channel assigned to this pin. 819 /// EXTI channel assigned to this pin.
819 /// 820 ///
820 /// For example, PC4 uses EXTI4. 821 /// For example, PC4 uses EXTI4.
821 #[cfg(feature = "exti")]
822 type ExtiChannel: crate::exti::Channel; 822 type ExtiChannel: crate::exti::Channel;
823}
823 824
825/// GPIO pin trait.
826#[allow(private_bounds)]
827pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
824 /// Number of the pin within the port (0..31) 828 /// Number of the pin within the port (0..31)
825 #[inline] 829 #[inline]
826 fn pin(&self) -> PinNumber { 830 fn pin(&self) -> PinNumber {
@@ -834,7 +838,7 @@ pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
834 } 838 }
835} 839}
836 840
837/// Type-erased GPIO pin 841/// Type-erased GPIO pin.
838pub struct AnyPin { 842pub struct AnyPin {
839 pin_port: PinNumber, 843 pin_port: PinNumber,
840} 844}
@@ -862,10 +866,7 @@ impl AnyPin {
862} 866}
863 867
864impl_peripheral!(AnyPin); 868impl_peripheral!(AnyPin);
865impl Pin for AnyPin { 869impl Pin for AnyPin {}
866 #[cfg(feature = "exti")]
867 type ExtiChannel = crate::exti::AnyChannel;
868}
869impl SealedPin for AnyPin { 870impl SealedPin for AnyPin {
870 #[inline] 871 #[inline]
871 fn pin_port(&self) -> PinNumber { 872 fn pin_port(&self) -> PinNumber {
@@ -878,7 +879,9 @@ impl SealedPin for AnyPin {
878foreach_pin!( 879foreach_pin!(
879 ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => { 880 ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => {
880 impl Pin for peripherals::$pin_name { 881 impl Pin for peripherals::$pin_name {
881 #[cfg(feature = "exti")] 882 }
883 #[cfg(feature = "exti")]
884 impl ExtiPin for peripherals::$pin_name {
882 type ExtiChannel = peripherals::$exti_ch; 885 type ExtiChannel = peripherals::$exti_ch;
883 } 886 }
884 impl SealedPin for peripherals::$pin_name { 887 impl SealedPin for peripherals::$pin_name {
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index 4d3a5d68d..e62de0454 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
5// 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.
6// Those MCUs have a different HSEM implementation (Secure semaphore lock support, 14// Those MCUs have a different HSEM implementation (Secure semaphore lock support,
7// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), 15// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute),
8// which is not yet supported by this code. 16// which is not yet supported by this code.
9use crate::Peri; 17use crate::Peri;
10use crate::pac;
11use crate::rcc::{self, RccPeripheral}; 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,152 @@ 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 core_id = CoreId::current();
152
153 poll_fn(|cx| {
154 T::state().waker_for(self.index).register(cx.waker());
155
156 compiler_fence(Ordering::SeqCst);
157
158 T::regs()
159 .ier(core_id.to_index())
160 .modify(|w| w.set_ise(self.index as usize, true));
161
162 match self.try_lock(process_id) {
163 Some(mutex) => Poll::Ready(mutex),
164 None => Poll::Pending,
165 }
166 })
167 .await
168 }
84 169
85 HardwareSemaphore { _peri: peripheral } 170 /// Try to lock the semaphor
171 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
172 /// check if the lock has been successful, carried out from the HSEM_Rx register.
173 pub fn try_lock(&mut self, process_id: u8) -> Option<HardwareSemaphoreMutex<'a, T>> {
174 if self.two_step_lock(process_id).is_ok() {
175 Some(HardwareSemaphoreMutex {
176 index: self.index,
177 process_id: process_id,
178 _lifetime: PhantomData,
179 })
180 } else {
181 None
182 }
86 } 183 }
87 184
88 /// Locks the semaphore. 185 /// Locks the semaphore.
89 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to 186 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
90 /// check if the lock has been successful, carried out from the HSEM_Rx register. 187 /// check if the lock has been successful, carried out from the HSEM_Rx register.
91 pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemError> { 188 pub fn two_step_lock(&mut self, process_id: u8) -> Result<(), HsemError> {
92 T::regs().r(sem_id as usize).write(|w| { 189 T::regs().r(self.index as usize).write(|w| {
93 w.set_procid(process_id); 190 w.set_procid(process_id);
94 w.set_coreid(get_current_coreid() as u8); 191 w.set_coreid(CoreId::current() as u8);
95 w.set_lock(true); 192 w.set_lock(true);
96 }); 193 });
97 let reg = T::regs().r(sem_id as usize).read(); 194 let reg = T::regs().r(self.index as usize).read();
98 match ( 195 match (
99 reg.lock(), 196 reg.lock(),
100 reg.coreid() == get_current_coreid() as u8, 197 reg.coreid() == CoreId::current() as u8,
101 reg.procid() == process_id, 198 reg.procid() == process_id,
102 ) { 199 ) {
103 (true, true, true) => Ok(()), 200 (true, true, true) => Ok(()),
@@ -108,9 +205,9 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
108 /// Locks the semaphore. 205 /// Locks the semaphore.
109 /// The 1-step procedure consists in a read to lock and check the semaphore in a single step, 206 /// 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. 207 /// carried out from the HSEM_RLRx register.
111 pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemError> { 208 pub fn one_step_lock(&mut self) -> Result<(), HsemError> {
112 let reg = T::regs().rlr(sem_id as usize).read(); 209 let reg = T::regs().rlr(self.index as usize).read();
113 match (reg.lock(), reg.coreid() == get_current_coreid() as u8, reg.procid()) { 210 match (reg.lock(), reg.coreid() == CoreId::current() as u8, reg.procid()) {
114 (false, true, 0) => Ok(()), 211 (false, true, 0) => Ok(()),
115 _ => Err(HsemError::LockFailed), 212 _ => Err(HsemError::LockFailed),
116 } 213 }
@@ -119,14 +216,60 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
119 /// Unlocks the semaphore. 216 /// Unlocks the semaphore.
120 /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus 217 /// 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. 218 /// core ID or by a process not having the semaphore lock right.
122 pub fn unlock(&mut self, sem_id: u8, process_id: u8) { 219 pub fn unlock(&mut self, process_id: u8) {
123 T::regs().r(sem_id as usize).write(|w| { 220 T::regs().r(self.index as usize).write(|w| {
124 w.set_procid(process_id); 221 w.set_procid(process_id);
125 w.set_coreid(get_current_coreid() as u8); 222 w.set_coreid(CoreId::current() as u8);
126 w.set_lock(false); 223 w.set_lock(false);
127 }); 224 });
128 } 225 }
129 226
227 /// Return the channel number
228 pub const fn channel(&self) -> u8 {
229 self.index + 1
230 }
231}
232
233/// HSEM driver
234pub struct HardwareSemaphore<T: Instance> {
235 _type: PhantomData<T>,
236}
237
238impl<T: Instance> HardwareSemaphore<T> {
239 /// Creates a new HardwareSemaphore instance.
240 pub fn new<'d>(
241 _peripheral: Peri<'d, T>,
242 _irq: impl interrupt::typelevel::Binding<T::Interrupt, HardwareSemaphoreInterruptHandler<T>> + 'd,
243 ) -> Self {
244 rcc::enable_and_reset::<T>();
245
246 HardwareSemaphore { _type: PhantomData }
247 }
248
249 /// Get a single channel, and keep the global struct
250 pub const fn channel_for<'a>(&'a mut self, number: u8) -> HardwareSemaphoreChannel<'a, T> {
251 #[cfg(all(stm32wb, feature = "low-power"))]
252 core::assert!(number != 3 && number != 4);
253
254 HardwareSemaphoreChannel::new(number)
255 }
256
257 /// Split the global struct into channels
258 ///
259 /// If using low-power mode, channels 3 and 4 will not be returned
260 pub const fn split<'a>(self) -> [HardwareSemaphoreChannel<'a, T>; PUB_CHANNELS] {
261 [
262 HardwareSemaphoreChannel::new(1),
263 HardwareSemaphoreChannel::new(2),
264 #[cfg(not(all(stm32wb, feature = "low-power")))]
265 HardwareSemaphoreChannel::new(3),
266 #[cfg(not(all(stm32wb, feature = "low-power")))]
267 HardwareSemaphoreChannel::new(4),
268 HardwareSemaphoreChannel::new(5),
269 HardwareSemaphoreChannel::new(6),
270 ]
271 }
272
130 /// Unlocks all semaphores. 273 /// Unlocks all semaphores.
131 /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR 274 /// 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 275 /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a
@@ -138,11 +281,6 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
138 }); 281 });
139 } 282 }
140 283
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 284 /// Sets the clear (unlock) key
147 pub fn set_clear_key(&mut self, key: u16) { 285 pub fn set_clear_key(&mut self, key: u16) {
148 T::regs().keyr().modify(|w| w.set_key(key)); 286 T::regs().keyr().modify(|w| w.set_key(key));
@@ -152,38 +290,61 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
152 pub fn get_clear_key(&mut self) -> u16 { 290 pub fn get_clear_key(&mut self) -> u16 {
153 T::regs().keyr().read().key() 291 T::regs().keyr().read().key()
154 } 292 }
293}
155 294
156 /// Sets the interrupt enable bit for the semaphore. 295#[cfg(all(stm32wb, feature = "low-power"))]
157 pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) { 296pub(crate) fn init_hsem(cs: CriticalSection) {
158 T::regs() 297 rcc::enable_and_reset_with_cs::<crate::peripherals::HSEM>(cs);
159 .ier(core_id_to_index(core_id)) 298
160 .modify(|w| w.set_ise(sem_x, enable)); 299 unsafe {
300 crate::rcc::REFCOUNT_STOP1 = 0;
301 crate::rcc::REFCOUNT_STOP2 = 0;
161 } 302 }
303}
162 304
163 /// Gets the interrupt flag for the semaphore. 305struct State {
164 pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool { 306 wakers: [AtomicWaker; 6],
165 T::regs().isr(core_id_to_index(core_id)).read().isf(sem_x) 307}
308
309impl State {
310 const fn new() -> Self {
311 Self {
312 wakers: [const { AtomicWaker::new() }; 6],
313 }
166 } 314 }
167 315
168 /// Clears the interrupt flag for the semaphore. 316 const fn waker_for(&self, index: u8) -> &AtomicWaker {
169 pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) { 317 &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 } 318 }
174} 319}
175 320
176trait SealedInstance { 321trait SealedInstance {
177 fn regs() -> pac::hsem::Hsem; 322 fn regs() -> pac::hsem::Hsem;
323 fn state() -> &'static State;
178} 324}
179 325
180/// HSEM instance trait. 326/// HSEM instance trait.
181#[allow(private_bounds)] 327#[allow(private_bounds)]
182pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {} 328pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {
329 /// Interrupt for this peripheral.
330 type Interrupt: interrupt::typelevel::Interrupt;
331}
183 332
184impl SealedInstance for crate::peripherals::HSEM { 333impl SealedInstance for crate::peripherals::HSEM {
185 fn regs() -> crate::pac::hsem::Hsem { 334 fn regs() -> crate::pac::hsem::Hsem {
186 crate::pac::HSEM 335 crate::pac::HSEM
187 } 336 }
337
338 fn state() -> &'static State {
339 static STATE: State = State::new();
340 &STATE
341 }
188} 342}
189impl Instance for crate::peripherals::HSEM {} 343
344foreach_interrupt!(
345 ($inst:ident, hsem, $block:ident, $signal_name:ident, $irq:ident) => {
346 impl Instance for crate::peripherals::$inst {
347 type Interrupt = crate::interrupt::typelevel::$irq;
348 }
349 };
350);
diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs
index 69baa708e..1d3560678 100644
--- a/embassy-stm32/src/hspi/mod.rs
+++ b/embassy-stm32/src/hspi/mod.rs
@@ -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/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 4527e55b9..b2ba94e21 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -98,6 +98,27 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
98} 98}
99 99
100impl<'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
101 pub(crate) fn init(&mut self, config: Config) { 122 pub(crate) fn init(&mut self, config: Config) {
102 self.info.regs.cr1().modify(|reg| { 123 self.info.regs.cr1().modify(|reg| {
103 reg.set_pe(false); 124 reg.set_pe(false);
@@ -147,12 +168,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
147 // `buffer`. The START bit can be set even if the bus 168 // `buffer`. The START bit can be set even if the bus
148 // is BUSY or I2C is in slave mode. 169 // is BUSY or I2C is in slave mode.
149 170
150 let reload = if reload {
151 i2c::vals::Reload::NOT_COMPLETED
152 } else {
153 i2c::vals::Reload::COMPLETED
154 };
155
156 info.regs.cr2().modify(|w| { 171 info.regs.cr2().modify(|w| {
157 w.set_sadd(address.addr() << 1); 172 w.set_sadd(address.addr() << 1);
158 w.set_add10(address.add_mode()); 173 w.set_add10(address.add_mode());
@@ -160,7 +175,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
160 w.set_nbytes(length as u8); 175 w.set_nbytes(length as u8);
161 w.set_start(true); 176 w.set_start(true);
162 w.set_autoend(stop.autoend()); 177 w.set_autoend(stop.autoend());
163 w.set_reload(reload); 178 w.set_reload(Self::to_reload(reload));
164 }); 179 });
165 180
166 Ok(()) 181 Ok(())
@@ -172,28 +187,25 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
172 length: usize, 187 length: usize,
173 stop: Stop, 188 stop: Stop,
174 reload: bool, 189 reload: bool,
190 restart: bool,
175 timeout: Timeout, 191 timeout: Timeout,
176 ) -> Result<(), Error> { 192 ) -> Result<(), Error> {
177 assert!(length < 256); 193 assert!(length < 256);
178 194
179 // Wait for any previous address sequence to end 195 if !restart {
180 // automatically. This could be up to 50% of a bus 196 // Wait for any previous address sequence to end
181 // cycle (ie. up to 0.5/freq) 197 // automatically. This could be up to 50% of a bus
182 while info.regs.cr2().read().start() { 198 // cycle (ie. up to 0.5/freq)
183 timeout.check()?; 199 while info.regs.cr2().read().start() {
184 } 200 timeout.check()?;
201 }
185 202
186 // Wait for the bus to be free 203 // Wait for the bus to be free
187 while info.regs.isr().read().busy() { 204 while info.regs.isr().read().busy() {
188 timeout.check()?; 205 timeout.check()?;
206 }
189 } 207 }
190 208
191 let reload = if reload {
192 i2c::vals::Reload::NOT_COMPLETED
193 } else {
194 i2c::vals::Reload::COMPLETED
195 };
196
197 // Set START and prepare to send `bytes`. The 209 // Set START and prepare to send `bytes`. The
198 // 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
199 // I2C is in slave mode. 211 // I2C is in slave mode.
@@ -204,28 +216,36 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
204 w.set_nbytes(length as u8); 216 w.set_nbytes(length as u8);
205 w.set_start(true); 217 w.set_start(true);
206 w.set_autoend(stop.autoend()); 218 w.set_autoend(stop.autoend());
207 w.set_reload(reload); 219 w.set_reload(Self::to_reload(reload));
208 }); 220 });
209 221
210 Ok(()) 222 Ok(())
211 } 223 }
212 224
213 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> {
214 assert!(length < 256 && length > 0); 232 assert!(length < 256 && length > 0);
215 233
216 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 }
217 timeout.check()?; 242 timeout.check()?;
218 } 243 }
219 244
220 let will_reload = if will_reload {
221 i2c::vals::Reload::NOT_COMPLETED
222 } else {
223 i2c::vals::Reload::COMPLETED
224 };
225
226 info.regs.cr2().modify(|w| { 245 info.regs.cr2().modify(|w| {
227 w.set_nbytes(length as u8); 246 w.set_nbytes(length as u8);
228 w.set_reload(will_reload); 247 w.set_reload(Self::to_reload(will_reload));
248 w.set_autoend(stop.autoend());
229 }); 249 });
230 250
231 Ok(()) 251 Ok(())
@@ -369,7 +389,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
369 loop { 389 loop {
370 let isr = self.info.regs.isr().read(); 390 let isr = self.info.regs.isr().read();
371 self.error_occurred(&isr, timeout)?; 391 self.error_occurred(&isr, timeout)?;
372 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() {
373 return Ok(()); 395 return Ok(());
374 } 396 }
375 timeout.check()?; 397 timeout.check()?;
@@ -396,14 +418,20 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
396 address, 418 address,
397 read.len().min(255), 419 read.len().min(255),
398 Stop::Automatic, 420 Stop::Automatic,
399 last_chunk_idx != 0, 421 last_chunk_idx != 0, // reload
400 restart, 422 restart,
401 timeout, 423 timeout,
402 )?; 424 )?;
403 425
404 for (number, chunk) in read.chunks_mut(255).enumerate() { 426 for (number, chunk) in read.chunks_mut(255).enumerate() {
405 if number != 0 { 427 if number != 0 {
406 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 )?;
407 } 435 }
408 436
409 for byte in chunk { 437 for byte in chunk {
@@ -441,6 +469,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
441 write.len().min(255), 469 write.len().min(255),
442 Stop::Software, 470 Stop::Software,
443 last_chunk_idx != 0, 471 last_chunk_idx != 0,
472 false, // restart
444 timeout, 473 timeout,
445 ) { 474 ) {
446 if send_stop { 475 if send_stop {
@@ -451,7 +480,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
451 480
452 for (number, chunk) in write.chunks(255).enumerate() { 481 for (number, chunk) in write.chunks(255).enumerate() {
453 if number != 0 { 482 if number != 0 {
454 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 )?;
455 } 490 }
456 491
457 for byte in chunk { 492 for byte in chunk {
@@ -507,9 +542,215 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
507 /// 542 ///
508 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 543 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
509 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> {
510 let _ = addr; 545 if operations.is_empty() {
511 let _ = operations; 546 return Err(Error::ZeroLengthTransfer);
512 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(())
513 } 754 }
514 755
515 /// Blocking write multiple buffers. 756 /// Blocking write multiple buffers.
@@ -531,6 +772,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
531 first_length.min(255), 772 first_length.min(255),
532 Stop::Software, 773 Stop::Software,
533 (first_length > 255) || (last_slice_index != 0), 774 (first_length > 255) || (last_slice_index != 0),
775 false, // restart
534 timeout, 776 timeout,
535 ) { 777 ) {
536 self.master_stop(); 778 self.master_stop();
@@ -552,6 +794,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
552 self.info, 794 self.info,
553 slice_len.min(255), 795 slice_len.min(255),
554 (idx != last_slice_index) || (slice_len > 255), 796 (idx != last_slice_index) || (slice_len > 255),
797 Stop::Software,
555 timeout, 798 timeout,
556 ) { 799 ) {
557 if err != Error::Nack { 800 if err != Error::Nack {
@@ -567,6 +810,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
567 self.info, 810 self.info,
568 chunk.len(), 811 chunk.len(),
569 (number != last_chunk_idx) || (idx != last_slice_index), 812 (number != last_chunk_idx) || (idx != last_slice_index),
813 Stop::Software,
570 timeout, 814 timeout,
571 ) { 815 ) {
572 if err != Error::Nack { 816 if err != Error::Nack {
@@ -610,6 +854,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
610 first_slice: bool, 854 first_slice: bool,
611 last_slice: bool, 855 last_slice: bool,
612 send_stop: bool, 856 send_stop: bool,
857 restart: bool,
613 timeout: Timeout, 858 timeout: Timeout,
614 ) -> Result<(), Error> { 859 ) -> Result<(), Error> {
615 let total_len = write.len(); 860 let total_len = write.len();
@@ -676,10 +921,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
676 total_len.min(255), 921 total_len.min(255),
677 Stop::Software, 922 Stop::Software,
678 (total_len > 255) || !last_slice, 923 (total_len > 255) || !last_slice,
924 restart,
679 timeout, 925 timeout,
680 )?; 926 )?;
681 } else { 927 } else {
682 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 )?;
683 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 935 self.info.regs.cr1().modify(|w| w.set_tcie(true));
684 } 936 }
685 } else if !(isr.tcr() || isr.tc()) { 937 } else if !(isr.tcr() || isr.tc()) {
@@ -688,9 +940,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
688 } else if remaining_len == 0 { 940 } else if remaining_len == 0 {
689 return Poll::Ready(Ok(())); 941 return Poll::Ready(Ok(()));
690 } else { 942 } else {
691 let last_piece = (remaining_len <= 255) && last_slice; 943 if let Err(e) = Self::reload(
692 944 self.info,
693 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 ) {
694 return Poll::Ready(Err(e)); 950 return Poll::Ready(Err(e));
695 } 951 }
696 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 952 self.info.regs.cr1().modify(|w| w.set_tcie(true));
@@ -702,10 +958,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
702 .await?; 958 .await?;
703 959
704 dma_transfer.await; 960 dma_transfer.await;
705 if last_slice { 961
706 // This should be done already 962 // Always wait for TC after DMA completes - needed for consecutive buffers
707 self.wait_tc(timeout)?; 963 self.wait_tc(timeout)?;
708 }
709 964
710 if last_slice & send_stop { 965 if last_slice & send_stop {
711 self.master_stop(); 966 self.master_stop();
@@ -780,7 +1035,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
780 address, 1035 address,
781 total_len.min(255), 1036 total_len.min(255),
782 Stop::Automatic, 1037 Stop::Automatic,
783 total_len > 255, 1038 total_len > 255, // reload
784 restart, 1039 restart,
785 timeout, 1040 timeout,
786 )?; 1041 )?;
@@ -788,12 +1043,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
788 return Poll::Ready(Ok(())); 1043 return Poll::Ready(Ok(()));
789 } 1044 }
790 } else if isr.tcr() { 1045 } else if isr.tcr() {
791 // poll_fn was woken without an interrupt present 1046 // Transfer Complete Reload - need to set up next chunk
792 return Poll::Pending;
793 } else {
794 let last_piece = remaining_len <= 255; 1047 let last_piece = remaining_len <= 255;
795 1048
796 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) {
797 return Poll::Ready(Err(e)); 1050 return Poll::Ready(Err(e));
798 } 1051 }
799 // Return here if we are on last chunk, 1052 // Return here if we are on last chunk,
@@ -802,6 +1055,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
802 return Poll::Ready(Ok(())); 1055 return Poll::Ready(Ok(()));
803 } 1056 }
804 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;
805 } 1061 }
806 1062
807 remaining_len = remaining_len.saturating_sub(255); 1063 remaining_len = remaining_len.saturating_sub(255);
@@ -819,14 +1075,12 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
819 1075
820 /// Write. 1076 /// Write.
821 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> {
822 #[cfg(all(feature = "low-power", stm32wlex))]
823 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
824 let timeout = self.timeout(); 1078 let timeout = self.timeout();
825 if write.is_empty() { 1079 if write.is_empty() {
826 self.write_internal(address.into(), write, true, timeout) 1080 self.write_internal(address.into(), write, true, timeout)
827 } else { 1081 } else {
828 timeout 1082 timeout
829 .with(self.write_dma_internal(address.into(), write, true, true, true, timeout)) 1083 .with(self.write_dma_internal(address.into(), write, true, true, true, false, timeout))
830 .await 1084 .await
831 } 1085 }
832 } 1086 }
@@ -835,23 +1089,29 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
835 /// 1089 ///
836 /// The buffers are concatenated in a single write transaction. 1090 /// The buffers are concatenated in a single write transaction.
837 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { 1091 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> {
838 #[cfg(all(feature = "low-power", stm32wlex))]
839 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
840 let timeout = self.timeout(); 1092 let timeout = self.timeout();
841 1093
842 if write.is_empty() { 1094 if write.is_empty() {
843 return Err(Error::ZeroLengthTransfer); 1095 return Err(Error::ZeroLengthTransfer);
844 } 1096 }
845 let mut iter = write.iter();
846 1097
1098 let mut iter = write.iter();
847 let mut first = true; 1099 let mut first = true;
848 let mut current = iter.next(); 1100 let mut current = iter.next();
1101
849 while let Some(c) = current { 1102 while let Some(c) = current {
850 let next = iter.next(); 1103 let next = iter.next();
851 let is_last = next.is_none(); 1104 let is_last = next.is_none();
852 1105
853 let fut = self.write_dma_internal(address, c, first, is_last, is_last, timeout); 1106 let fut = self.write_dma_internal(
1107 address, c, first, // first_slice
1108 is_last, // last_slice
1109 is_last, // send_stop (only on last buffer)
1110 false, // restart (false for all - they're one continuous write)
1111 timeout,
1112 );
854 timeout.with(fut).await?; 1113 timeout.with(fut).await?;
1114
855 first = false; 1115 first = false;
856 current = next; 1116 current = next;
857 } 1117 }
@@ -860,8 +1120,6 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
860 1120
861 /// Read. 1121 /// Read.
862 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 1122 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
863 #[cfg(all(feature = "low-power", stm32wlex))]
864 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
865 let timeout = self.timeout(); 1123 let timeout = self.timeout();
866 1124
867 if buffer.is_empty() { 1125 if buffer.is_empty() {
@@ -874,14 +1132,12 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
874 1132
875 /// Write, restart, read. 1133 /// Write, restart, read.
876 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 1134 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
877 #[cfg(all(feature = "low-power", stm32wlex))]
878 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
879 let timeout = self.timeout(); 1135 let timeout = self.timeout();
880 1136
881 if write.is_empty() { 1137 if write.is_empty() {
882 self.write_internal(address.into(), write, false, timeout)?; 1138 self.write_internal(address.into(), write, false, timeout)?;
883 } else { 1139 } else {
884 let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout); 1140 let fut = self.write_dma_internal(address.into(), write, true, true, false, false, timeout);
885 timeout.with(fut).await?; 1141 timeout.with(fut).await?;
886 } 1142 }
887 1143
@@ -901,11 +1157,298 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
901 /// 1157 ///
902 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 1158 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
903 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 1159 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
904 #[cfg(all(feature = "low-power", stm32wlex))] 1160 if operations.is_empty() {
905 let _device_busy = crate::low_power::DeviceBusy::new_stop1(); 1161 return Err(Error::ZeroLengthTransfer);
906 let _ = addr; 1162 }
907 let _ = operations; 1163
908 todo!() 1164 let address = addr.into();
1165 let timeout = self.timeout();
1166
1167 // Group consecutive operations of the same type
1168 let mut op_idx = 0;
1169 let mut is_first_group = true;
1170
1171 while op_idx < operations.len() {
1172 // Determine the type of current group and find all consecutive operations of same type
1173 let is_read = matches!(operations[op_idx], Operation::Read(_));
1174 let group_start = op_idx;
1175
1176 // Find end of this group (consecutive operations of same type)
1177 while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read {
1178 op_idx += 1;
1179 }
1180 let group_end = op_idx;
1181 let is_last_group = op_idx >= operations.len();
1182
1183 // Execute this group of operations
1184 if is_read {
1185 self.execute_read_group_async(
1186 address,
1187 &mut operations[group_start..group_end],
1188 is_first_group,
1189 is_last_group,
1190 timeout,
1191 )
1192 .await?;
1193 } else {
1194 self.execute_write_group_async(
1195 address,
1196 &operations[group_start..group_end],
1197 is_first_group,
1198 is_last_group,
1199 timeout,
1200 )
1201 .await?;
1202 }
1203
1204 is_first_group = false;
1205 }
1206
1207 Ok(())
1208 }
1209
1210 async fn execute_write_group_async(
1211 &mut self,
1212 address: Address,
1213 operations: &[Operation<'_>],
1214 is_first_group: bool,
1215 is_last_group: bool,
1216 timeout: Timeout,
1217 ) -> Result<(), Error> {
1218 // Calculate total bytes across all operations in this group
1219 let total_bytes = Self::total_operation_bytes(operations);
1220
1221 if total_bytes == 0 {
1222 // Handle empty write group using blocking call
1223 if is_first_group {
1224 Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?;
1225 }
1226 if is_last_group {
1227 self.master_stop();
1228 }
1229 return Ok(());
1230 }
1231
1232 // Collect all write buffers
1233 let mut write_buffers: heapless::Vec<&[u8], 16> = heapless::Vec::new();
1234 for operation in operations {
1235 if let Operation::Write(buffer) = operation {
1236 if !buffer.is_empty() {
1237 let _ = write_buffers.push(buffer);
1238 }
1239 }
1240 }
1241
1242 if write_buffers.is_empty() {
1243 return Ok(());
1244 }
1245
1246 // Send each buffer using DMA
1247 let num_buffers = write_buffers.len();
1248 for (idx, buffer) in write_buffers.iter().enumerate() {
1249 let is_first_buffer = idx == 0;
1250 let is_last_buffer = idx == num_buffers - 1;
1251
1252 let fut = self.write_dma_internal(
1253 address,
1254 buffer,
1255 is_first_buffer, // first_slice
1256 is_last_buffer, // last_slice
1257 is_last_buffer && is_last_group, // send_stop
1258 is_first_buffer && !is_first_group, // restart (only for first buffer if not first group)
1259 timeout,
1260 );
1261 timeout.with(fut).await?;
1262 }
1263
1264 Ok(())
1265 }
1266
1267 async fn execute_read_group_async(
1268 &mut self,
1269 address: Address,
1270 operations: &mut [Operation<'_>],
1271 is_first_group: bool,
1272 is_last_group: bool,
1273 timeout: Timeout,
1274 ) -> Result<(), Error> {
1275 // Calculate total bytes across all operations in this group
1276 let total_bytes = Self::total_operation_bytes(operations);
1277
1278 if total_bytes == 0 {
1279 // Handle empty read group using blocking call
1280 if is_first_group {
1281 Self::master_read(
1282 self.info,
1283 address,
1284 0,
1285 if is_last_group { Stop::Automatic } else { Stop::Software },
1286 false, // reload
1287 !is_first_group,
1288 timeout,
1289 )?;
1290 }
1291 if is_last_group {
1292 self.wait_stop(timeout)?;
1293 }
1294 return Ok(());
1295 }
1296
1297 // Use DMA for read operations - need to handle multiple buffers
1298 let restart = !is_first_group;
1299 let mut total_remaining = total_bytes;
1300 let mut is_first_in_group = true;
1301
1302 for operation in operations {
1303 if let Operation::Read(buffer) = operation {
1304 if buffer.is_empty() {
1305 // Skip empty buffers
1306 continue;
1307 }
1308
1309 let buf_len = buffer.len();
1310 total_remaining -= buf_len;
1311 let is_last_in_group = total_remaining == 0;
1312
1313 // Perform DMA read
1314 if is_first_in_group {
1315 // First buffer: use read_dma_internal which handles restart properly
1316 // Only use Automatic stop if this is the last buffer in the last group
1317 let stop_mode = if is_last_group && is_last_in_group {
1318 Stop::Automatic
1319 } else {
1320 Stop::Software
1321 };
1322
1323 // We need a custom DMA read that respects our stop mode
1324 self.read_dma_group_internal(address, buffer, restart, stop_mode, timeout)
1325 .await?;
1326 is_first_in_group = false;
1327 } else {
1328 // Subsequent buffers: need to reload and continue
1329 let stop_mode = if is_last_group && is_last_in_group {
1330 Stop::Automatic
1331 } else {
1332 Stop::Software
1333 };
1334
1335 self.read_dma_group_internal(
1336 address, buffer, false, // no restart for subsequent buffers in same group
1337 stop_mode, timeout,
1338 )
1339 .await?;
1340 }
1341 }
1342 }
1343
1344 // Wait for transfer to complete
1345 if is_last_group {
1346 self.wait_stop(timeout)?;
1347 }
1348
1349 Ok(())
1350 }
1351
1352 /// Internal DMA read helper for transaction groups
1353 async fn read_dma_group_internal(
1354 &mut self,
1355 address: Address,
1356 buffer: &mut [u8],
1357 restart: bool,
1358 stop_mode: Stop,
1359 timeout: Timeout,
1360 ) -> Result<(), Error> {
1361 let total_len = buffer.len();
1362
1363 let dma_transfer = unsafe {
1364 let regs = self.info.regs;
1365 regs.cr1().modify(|w| {
1366 w.set_rxdmaen(true);
1367 w.set_tcie(true);
1368 w.set_nackie(true);
1369 w.set_errie(true);
1370 });
1371 let src = regs.rxdr().as_ptr() as *mut u8;
1372
1373 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1374 };
1375
1376 let mut remaining_len = total_len;
1377
1378 let on_drop = OnDrop::new(|| {
1379 let regs = self.info.regs;
1380 regs.cr1().modify(|w| {
1381 w.set_rxdmaen(false);
1382 w.set_tcie(false);
1383 w.set_nackie(false);
1384 w.set_errie(false);
1385 });
1386 regs.icr().write(|w| {
1387 w.set_nackcf(true);
1388 w.set_berrcf(true);
1389 w.set_arlocf(true);
1390 w.set_ovrcf(true);
1391 });
1392 });
1393
1394 poll_fn(|cx| {
1395 self.state.waker.register(cx.waker());
1396
1397 let isr = self.info.regs.isr().read();
1398
1399 if isr.nackf() {
1400 return Poll::Ready(Err(Error::Nack));
1401 }
1402 if isr.arlo() {
1403 return Poll::Ready(Err(Error::Arbitration));
1404 }
1405 if isr.berr() {
1406 return Poll::Ready(Err(Error::Bus));
1407 }
1408 if isr.ovr() {
1409 return Poll::Ready(Err(Error::Overrun));
1410 }
1411
1412 if remaining_len == total_len {
1413 Self::master_read(
1414 self.info,
1415 address,
1416 total_len.min(255),
1417 stop_mode,
1418 total_len > 255, // reload
1419 restart,
1420 timeout,
1421 )?;
1422 if total_len <= 255 {
1423 return Poll::Ready(Ok(()));
1424 }
1425 } else if isr.tcr() {
1426 // Transfer Complete Reload - need to set up next chunk
1427 let last_piece = remaining_len <= 255;
1428
1429 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, stop_mode, timeout) {
1430 return Poll::Ready(Err(e));
1431 }
1432 // Return here if we are on last chunk,
1433 // end of transfer will be awaited with the DMA below
1434 if last_piece {
1435 return Poll::Ready(Ok(()));
1436 }
1437 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1438 } else {
1439 // poll_fn was woken without TCR interrupt
1440 return Poll::Pending;
1441 }
1442
1443 remaining_len = remaining_len.saturating_sub(255);
1444 Poll::Pending
1445 })
1446 .await?;
1447
1448 dma_transfer.await;
1449 drop(on_drop);
1450
1451 Ok(())
909 } 1452 }
910} 1453}
911 1454
@@ -1043,7 +1586,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1043 if number == 0 { 1586 if number == 0 {
1044 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1587 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1045 } else { 1588 } else {
1046 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1589 Self::reload(
1590 self.info,
1591 chunk.len(),
1592 number != last_chunk_idx,
1593 Stop::Software,
1594 timeout,
1595 )?;
1047 } 1596 }
1048 1597
1049 let mut index = 0; 1598 let mut index = 0;
@@ -1092,7 +1641,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1092 if number == 0 { 1641 if number == 0 {
1093 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1642 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1094 } else { 1643 } else {
1095 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1644 Self::reload(
1645 self.info,
1646 chunk.len(),
1647 number != last_chunk_idx,
1648 Stop::Software,
1649 timeout,
1650 )?;
1096 } 1651 }
1097 1652
1098 let mut index = 0; 1653 let mut index = 0;
@@ -1228,7 +1783,13 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1228 Poll::Pending 1783 Poll::Pending
1229 } else if isr.tcr() { 1784 } else if isr.tcr() {
1230 let is_last_slice = remaining_len <= 255; 1785 let is_last_slice = remaining_len <= 255;
1231 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { 1786 if let Err(e) = Self::reload(
1787 self.info,
1788 remaining_len.min(255),
1789 !is_last_slice,
1790 Stop::Software,
1791 timeout,
1792 ) {
1232 return Poll::Ready(Err(e)); 1793 return Poll::Ready(Err(e));
1233 } 1794 }
1234 remaining_len = remaining_len.saturating_sub(255); 1795 remaining_len = remaining_len.saturating_sub(255);
@@ -1292,7 +1853,13 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1292 Poll::Pending 1853 Poll::Pending
1293 } else if isr.tcr() { 1854 } else if isr.tcr() {
1294 let is_last_slice = remaining_len <= 255; 1855 let is_last_slice = remaining_len <= 255;
1295 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { 1856 if let Err(e) = Self::reload(
1857 self.info,
1858 remaining_len.min(255),
1859 !is_last_slice,
1860 Stop::Software,
1861 timeout,
1862 ) {
1296 return Poll::Ready(Err(e)); 1863 return Poll::Ready(Err(e));
1297 } 1864 }
1298 remaining_len = remaining_len.saturating_sub(255); 1865 remaining_len = remaining_len.saturating_sub(255);
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index e1d8b1c2a..10c4a820b 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,9 +1,11 @@
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::marker::PhantomData;
4use core::sync::atomic::{Ordering, compiler_fence}; 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;
@@ -17,25 +19,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive
17 unsafe fn on_interrupt() { 19 unsafe fn on_interrupt() {
18 let regs = IPCC::regs(); 20 let regs = IPCC::regs();
19 21
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. 22 // Status register gives channel occupied status. For rx, use cpu1.
30 let sr = regs.cpu(1).sr().read(); 23 let sr = regs.cpu(1).sr().read();
31 regs.cpu(0).mr().modify(|w| { 24 regs.cpu(0).mr().modify(|w| {
32 for channel in channels { 25 for index in 0..5 {
33 if sr.chf(channel as usize) { 26 if sr.chf(index as usize) {
34 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 27 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
35 w.set_chom(channel as usize, true); 28 w.set_chom(index as usize, true);
36 29
37 // There shouldn't be a race because the channel is masked only if the interrupt has fired 30 // 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(); 31 IPCC::state().rx_waker_for(index).wake();
39 } 32 }
40 } 33 }
41 }) 34 })
@@ -49,25 +42,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi
49 unsafe fn on_interrupt() { 42 unsafe fn on_interrupt() {
50 let regs = IPCC::regs(); 43 let regs = IPCC::regs();
51 44
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. 45 // Status register gives channel occupied status. For tx, use cpu0.
62 let sr = regs.cpu(0).sr().read(); 46 let sr = regs.cpu(0).sr().read();
63 regs.cpu(0).mr().modify(|w| { 47 regs.cpu(0).mr().modify(|w| {
64 for channel in channels { 48 for index in 0..5 {
65 if !sr.chf(channel as usize) { 49 if !sr.chf(index as usize) {
66 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 50 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
67 w.set_chfm(channel as usize, true); 51 w.set_chfm(index as usize, true);
68 52
69 // There shouldn't be a race because the channel is masked only if the interrupt has fired 53 // 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(); 54 IPCC::state().tx_waker_for(index).wake();
71 } 55 }
72 } 56 }
73 }); 57 });
@@ -82,76 +66,55 @@ pub struct Config {
82 // reserved for future use 66 // reserved for future use
83} 67}
84 68
85/// Channel. 69/// IPCC TX Channel
86#[allow(missing_docs)] 70pub struct IpccTxChannel<'a> {
87#[derive(Debug, Clone, Copy)] 71 index: u8,
88#[repr(C)] 72 _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} 73}
97 74
98/// IPCC driver. 75impl<'a> IpccTxChannel<'a> {
99pub struct Ipcc; 76 pub(crate) const fn new(index: u8) -> Self {
100 77 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
109 regs.cpu(0).cr().modify(|w| {
110 w.set_rxoie(true);
111 w.set_txfie(true);
112 });
113
114 // enable interrupts
115 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
116 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
117 78
118 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() }; 79 Self {
119 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() }; 80 index: index,
81 _lifetime: PhantomData,
82 }
120 } 83 }
121 84
122 /// Send data to an IPCC channel. The closure is called to write the data when appropriate. 85 /// 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()) { 86 pub async fn send(&mut self, f: impl FnOnce()) {
124 let regs = IPCC::regs(); 87 let regs = IPCC::regs();
125 88
126 Self::flush(channel).await; 89 self.flush().await;
127 90
128 f(); 91 f();
129 92
130 compiler_fence(Ordering::SeqCst); 93 compiler_fence(Ordering::SeqCst);
131 94
132 trace!("ipcc: ch {}: send data", channel as u8); 95 trace!("ipcc: ch {}: send data", self.index as u8);
133 regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)); 96 regs.cpu(0).scr().write(|w| w.set_chs(self.index as usize, true));
134 } 97 }
135 98
136 /// Wait for the tx channel to become clear 99 /// Wait for the tx channel to become clear
137 pub async fn flush(channel: IpccChannel) { 100 pub async fn flush(&mut self) {
138 let regs = IPCC::regs(); 101 let regs = IPCC::regs();
139 102
140 // This is a race, but is nice for debugging 103 // This is a race, but is nice for debugging
141 if regs.cpu(0).sr().read().chf(channel as usize) { 104 if regs.cpu(0).sr().read().chf(self.index as usize) {
142 trace!("ipcc: ch {}: wait for tx free", channel as u8); 105 trace!("ipcc: ch {}: wait for tx free", self.index as u8);
143 } 106 }
144 107
145 poll_fn(|cx| { 108 poll_fn(|cx| {
146 IPCC::state().tx_waker_for(channel).register(cx.waker()); 109 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 110 // 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)); 111 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, false));
149 112
150 compiler_fence(Ordering::SeqCst); 113 compiler_fence(Ordering::SeqCst);
151 114
152 if !regs.cpu(0).sr().read().chf(channel as usize) { 115 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 116 // 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)); 117 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, true));
155 118
156 Poll::Ready(()) 119 Poll::Ready(())
157 } else { 120 } else {
@@ -160,27 +123,44 @@ impl Ipcc {
160 }) 123 })
161 .await; 124 .await;
162 } 125 }
126}
127
128/// IPCC RX Channel
129pub struct IpccRxChannel<'a> {
130 index: u8,
131 _lifetime: PhantomData<&'a mut usize>,
132}
133
134impl<'a> IpccRxChannel<'a> {
135 pub(crate) const fn new(index: u8) -> Self {
136 core::assert!(index < 6);
137
138 Self {
139 index: index,
140 _lifetime: PhantomData,
141 }
142 }
163 143
164 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate. 144 /// 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 { 145 pub async fn receive<R>(&mut self, mut f: impl FnMut() -> Option<R>) -> R {
166 let regs = IPCC::regs(); 146 let regs = IPCC::regs();
167 147
168 loop { 148 loop {
169 // This is a race, but is nice for debugging 149 // This is a race, but is nice for debugging
170 if !regs.cpu(1).sr().read().chf(channel as usize) { 150 if !regs.cpu(1).sr().read().chf(self.index as usize) {
171 trace!("ipcc: ch {}: wait for rx occupied", channel as u8); 151 trace!("ipcc: ch {}: wait for rx occupied", self.index as u8);
172 } 152 }
173 153
174 poll_fn(|cx| { 154 poll_fn(|cx| {
175 IPCC::state().rx_waker_for(channel).register(cx.waker()); 155 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 156 // 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)); 157 regs.cpu(0).mr().modify(|w| w.set_chom(self.index as usize, false));
178 158
179 compiler_fence(Ordering::SeqCst); 159 compiler_fence(Ordering::SeqCst);
180 160
181 if regs.cpu(1).sr().read().chf(channel as usize) { 161 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 162 // 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)); 163 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, true));
184 164
185 Poll::Ready(()) 165 Poll::Ready(())
186 } else { 166 } else {
@@ -189,21 +169,111 @@ impl Ipcc {
189 }) 169 })
190 .await; 170 .await;
191 171
192 trace!("ipcc: ch {}: read data", channel as u8); 172 trace!("ipcc: ch {}: read data", self.index as u8);
193 173
194 match f() { 174 match f() {
195 Some(ret) => return ret, 175 Some(ret) => return ret,
196 None => {} 176 None => {}
197 } 177 }
198 178
199 trace!("ipcc: ch {}: clear rx", channel as u8); 179 trace!("ipcc: ch {}: clear rx", self.index as u8);
200 compiler_fence(Ordering::SeqCst); 180 compiler_fence(Ordering::SeqCst);
201 // If the channel is clear and the read function returns none, fetch more data 181 // 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)); 182 regs.cpu(0).scr().write(|w| w.set_chc(self.index as usize, true));
203 } 183 }
204 } 184 }
205} 185}
206 186
187/// IPCC Channel
188pub struct IpccChannel<'a> {
189 index: u8,
190 _lifetime: PhantomData<&'a mut usize>,
191}
192
193impl<'a> IpccChannel<'a> {
194 pub(crate) const fn new(number: u8) -> Self {
195 core::assert!(number > 0 && number <= 6);
196
197 Self {
198 index: number - 1,
199 _lifetime: PhantomData,
200 }
201 }
202
203 /// Split into a tx and rx channel
204 pub const fn split(self) -> (IpccTxChannel<'a>, IpccRxChannel<'a>) {
205 (IpccTxChannel::new(self.index), IpccRxChannel::new(self.index))
206 }
207}
208
209/// IPCC driver.
210pub struct Ipcc {
211 _private: (),
212}
213
214impl Ipcc {
215 /// Creates a new HardwareSemaphore instance.
216 pub fn new<'d>(
217 _peripheral: Peri<'d, crate::peripherals::IPCC>,
218 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
219 + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>
220 + 'd,
221 _config: Config,
222 ) -> Self {
223 rcc::enable_and_reset::<IPCC>();
224 IPCC::set_cpu2(true);
225
226 let regs = IPCC::regs();
227
228 regs.cpu(0).cr().modify(|w| {
229 w.set_rxoie(true);
230 w.set_txfie(true);
231 });
232
233 // enable interrupts
234 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
235 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
236
237 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
238 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
239
240 Self { _private: () }
241 }
242
243 /// Split into a tx and rx channel
244 pub const fn split<'a>(self) -> [(IpccTxChannel<'a>, IpccRxChannel<'a>); 6] {
245 [
246 IpccChannel::new(1).split(),
247 IpccChannel::new(2).split(),
248 IpccChannel::new(3).split(),
249 IpccChannel::new(4).split(),
250 IpccChannel::new(5).split(),
251 IpccChannel::new(6).split(),
252 ]
253 }
254
255 /// Receive from a channel number
256 pub async unsafe fn receive<R>(number: u8, f: impl FnMut() -> Option<R>) -> R {
257 core::assert!(number > 0 && number <= 6);
258
259 IpccRxChannel::new(number - 1).receive(f).await
260 }
261
262 /// Send to a channel number
263 pub async unsafe fn send(number: u8, f: impl FnOnce()) {
264 core::assert!(number > 0 && number <= 6);
265
266 IpccTxChannel::new(number - 1).send(f).await
267 }
268
269 /// Send to a channel number
270 pub async unsafe fn flush(number: u8) {
271 core::assert!(number > 0 && number <= 6);
272
273 IpccTxChannel::new(number - 1).flush().await
274 }
275}
276
207impl SealedInstance for crate::peripherals::IPCC { 277impl SealedInstance for crate::peripherals::IPCC {
208 fn regs() -> crate::pac::ipcc::Ipcc { 278 fn regs() -> crate::pac::ipcc::Ipcc {
209 crate::pac::IPCC 279 crate::pac::IPCC
@@ -232,26 +302,12 @@ impl State {
232 } 302 }
233 } 303 }
234 304
235 const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { 305 const fn rx_waker_for(&self, index: u8) -> &AtomicWaker {
236 match channel { 306 &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 } 307 }
245 308
246 const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { 309 const fn tx_waker_for(&self, index: u8) -> &AtomicWaker {
247 match channel { 310 &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 } 311 }
256} 312}
257 313
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 680edf433..2f783bf64 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -95,6 +95,8 @@ pub mod i2c;
95pub mod i2s; 95pub mod i2s;
96#[cfg(stm32wb)] 96#[cfg(stm32wb)]
97pub mod ipcc; 97pub mod ipcc;
98#[cfg(lcd)]
99pub mod lcd;
98#[cfg(feature = "low-power")] 100#[cfg(feature = "low-power")]
99pub mod low_power; 101pub mod low_power;
100#[cfg(lptim)] 102#[cfg(lptim)]
@@ -151,7 +153,7 @@ pub use crate::_generated::interrupt;
151/// Macro to bind interrupts to handlers. 153/// Macro to bind interrupts to handlers.
152/// 154///
153/// 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;`)
154/// 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
155/// prove at compile-time that the right interrupts have been bound. 157/// prove at compile-time that the right interrupts have been bound.
156/// 158///
157/// Example of how to bind one interrupt: 159/// Example of how to bind one interrupt:
@@ -178,6 +180,10 @@ pub use crate::_generated::interrupt;
178/// } 180/// }
179/// ); 181/// );
180/// ``` 182/// ```
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.
181// 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`.
182#[macro_export] 188#[macro_export]
183macro_rules! bind_interrupts { 189macro_rules! bind_interrupts {
@@ -649,12 +655,26 @@ fn init_hw(config: Config) -> Peripherals {
649 rcc::init_rcc(cs, config.rcc); 655 rcc::init_rcc(cs, config.rcc);
650 656
651 #[cfg(feature = "low-power")] 657 #[cfg(feature = "low-power")]
652 crate::rtc::init_rtc(cs, config.rtc); 658 rtc::init_rtc(cs, config.rtc, config.min_stop_pause);
653 659
654 #[cfg(feature = "low-power")] 660 #[cfg(all(stm32wb, feature = "low-power"))]
655 crate::time_driver::get_driver().set_min_stop_pause(cs, config.min_stop_pause); 661 hsem::init_hsem(cs);
656 } 662 }
657 663
658 p 664 p
659 }) 665 })
660} 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 696dfe83f..bd8290da0 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,21 +22,16 @@
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);
@@ -45,11 +40,9 @@
45//! } 40//! }
46//! ``` 41//! ```
47 42
48// TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.`
49#![allow(static_mut_refs)]
50
51use core::arch::asm; 43use core::arch::asm;
52use core::marker::PhantomData; 44use core::marker::PhantomData;
45use core::mem;
53use core::sync::atomic::{Ordering, compiler_fence}; 46use core::sync::atomic::{Ordering, compiler_fence};
54 47
55use cortex_m::peripheral::SCB; 48use cortex_m::peripheral::SCB;
@@ -57,11 +50,13 @@ use critical_section::CriticalSection;
57use embassy_executor::*; 50use embassy_executor::*;
58 51
59use crate::interrupt; 52use crate::interrupt;
53pub use crate::rcc::StopMode;
54use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2, decrement_stop_refcount, increment_stop_refcount};
60use crate::time_driver::get_driver; 55use crate::time_driver::get_driver;
61 56
62const THREAD_PENDER: usize = usize::MAX; 57const THREAD_PENDER: usize = usize::MAX;
63 58
64static mut EXECUTOR: Option<Executor> = None; 59static mut EXECUTOR_TAKEN: bool = false;
65 60
66/// Prevent the device from going into the stop mode if held 61/// Prevent the device from going into the stop mode if held
67pub struct DeviceBusy(StopMode); 62pub struct DeviceBusy(StopMode);
@@ -79,15 +74,8 @@ impl DeviceBusy {
79 74
80 /// Create a new DeviceBusy. 75 /// Create a new DeviceBusy.
81 pub fn new(stop_mode: StopMode) -> Self { 76 pub fn new(stop_mode: StopMode) -> Self {
82 critical_section::with(|_| unsafe { 77 critical_section::with(|cs| {
83 match stop_mode { 78 increment_stop_refcount(cs, stop_mode);
84 StopMode::Stop1 => {
85 crate::rcc::REFCOUNT_STOP1 += 1;
86 }
87 StopMode::Stop2 => {
88 crate::rcc::REFCOUNT_STOP2 += 1;
89 }
90 }
91 }); 79 });
92 80
93 Self(stop_mode) 81 Self(stop_mode)
@@ -96,15 +84,8 @@ impl DeviceBusy {
96 84
97impl Drop for DeviceBusy { 85impl Drop for DeviceBusy {
98 fn drop(&mut self) { 86 fn drop(&mut self) {
99 critical_section::with(|_| unsafe { 87 critical_section::with(|cs| {
100 match self.0 { 88 decrement_stop_refcount(cs, self.0);
101 StopMode::Stop1 => {
102 crate::rcc::REFCOUNT_STOP1 -= 1;
103 }
104 StopMode::Stop2 => {
105 crate::rcc::REFCOUNT_STOP2 -= 1;
106 }
107 }
108 }); 89 });
109 } 90 }
110} 91}
@@ -137,34 +118,24 @@ foreach_interrupt! {
137/// prevents entering the given stop mode. 118/// prevents entering the given stop mode.
138pub fn stop_ready(stop_mode: StopMode) -> bool { 119pub fn stop_ready(stop_mode: StopMode) -> bool {
139 critical_section::with(|cs| match Executor::stop_mode(cs) { 120 critical_section::with(|cs| match Executor::stop_mode(cs) {
140 Some(StopMode::Stop2) => true, 121 Some(StopMode::Standby | StopMode::Stop2) => true,
141 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, 122 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1,
142 None => false, 123 None => false,
143 }) 124 })
144} 125}
145 126
146/// Available Stop modes. 127#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))]
147#[non_exhaustive] 128use crate::pac::pwr::vals::Lpms;
148#[derive(PartialEq)]
149pub enum StopMode {
150 /// STOP 1
151 Stop1,
152 /// STOP 2
153 Stop2,
154}
155 129
156#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))] 130#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))]
157use stm32_metapac::pwr::vals::Lpms;
158
159#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))]
160impl Into<Lpms> for StopMode { 131impl Into<Lpms> for StopMode {
161 fn into(self) -> Lpms { 132 fn into(self) -> Lpms {
162 match self { 133 match self {
163 StopMode::Stop1 => Lpms::STOP1, 134 StopMode::Stop1 => Lpms::STOP1,
164 #[cfg(not(stm32wba))] 135 #[cfg(not(any(stm32wb, stm32wba)))]
165 StopMode::Stop2 => Lpms::STOP2, 136 StopMode::Standby | StopMode::Stop2 => Lpms::STOP2,
166 #[cfg(stm32wba)] 137 #[cfg(any(stm32wb, stm32wba))]
167 StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2? 138 StopMode::Standby | StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2?
168 } 139 }
169 } 140 }
170} 141}
@@ -182,42 +153,47 @@ impl Into<Lpms> for StopMode {
182pub struct Executor { 153pub struct Executor {
183 inner: raw::Executor, 154 inner: raw::Executor,
184 not_send: PhantomData<*mut ()>, 155 not_send: PhantomData<*mut ()>,
185 scb: SCB,
186} 156}
187 157
188impl Executor { 158impl Executor {
189 /// Create a new Executor. 159 /// Create a new Executor.
190 pub fn take() -> &'static mut Self { 160 pub fn new() -> Self {
191 critical_section::with(|_| unsafe { 161 unsafe {
192 assert!(EXECUTOR.is_none()); 162 if EXECUTOR_TAKEN {
193 163 panic!("Low power executor can only be taken once.");
194 EXECUTOR = Some(Self { 164 } else {
195 inner: raw::Executor::new(THREAD_PENDER as *mut ()), 165 EXECUTOR_TAKEN = true;
196 not_send: PhantomData, 166 }
197 scb: cortex_m::Peripherals::steal().SCB, 167 }
198 });
199
200 let executor = EXECUTOR.as_mut().unwrap();
201 168
202 executor 169 Self {
203 }) 170 inner: raw::Executor::new(THREAD_PENDER as *mut ()),
171 not_send: PhantomData,
172 }
204 } 173 }
205 174
206 pub(crate) unsafe fn on_wakeup_irq() { 175 pub(crate) unsafe fn on_wakeup_irq() {
207 critical_section::with(|cs| { 176 critical_section::with(|cs| {
208 #[cfg(stm32wlex)] 177 #[cfg(stm32wlex)]
209 { 178 {
210 let extscr = crate::pac::PWR.extscr().read(); 179 use crate::pac::rcc::vals::Sw;
180 use crate::pac::{PWR, RCC};
181 use crate::rcc::init as init_rcc;
182
183 let extscr = PWR.extscr().read();
211 if extscr.c1stop2f() || extscr.c1stopf() { 184 if extscr.c1stop2f() || extscr.c1stopf() {
212 // when we wake from any stop mode we need to re-initialize the rcc 185 // when we wake from any stop mode we need to re-initialize the rcc
213 crate::rcc::apply_resume_config(); 186 while RCC.cfgr().read().sws() != Sw::MSI {}
187
188 init_rcc(RCC_CONFIG.unwrap());
189
214 if extscr.c1stop2f() { 190 if extscr.c1stop2f() {
215 // when we wake from STOP2, we need to re-initialize the time driver 191 // when we wake from STOP2, we need to re-initialize the time driver
216 crate::time_driver::init_timer(cs); 192 get_driver().init_timer(cs);
217 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) 193 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
218 // and given that we just woke from STOP2, we can reset them 194 // and given that we just woke from STOP2, we can reset them
219 crate::rcc::REFCOUNT_STOP2 = 0; 195 REFCOUNT_STOP2 = 0;
220 crate::rcc::REFCOUNT_STOP1 = 0; 196 REFCOUNT_STOP1 = 0;
221 } 197 }
222 } 198 }
223 } 199 }
@@ -226,19 +202,90 @@ impl Executor {
226 }); 202 });
227 } 203 }
228 204
205 const fn get_scb() -> SCB {
206 unsafe { mem::transmute(()) }
207 }
208
229 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { 209 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> {
230 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 && crate::rcc::REFCOUNT_STOP1 == 0 } { 210 // We cannot enter standby because we will lose program state.
211 if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } {
212 trace!("low power: stop 2");
231 Some(StopMode::Stop2) 213 Some(StopMode::Stop2)
232 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 214 } else if unsafe { REFCOUNT_STOP1 == 0 } {
215 trace!("low power: stop 1");
233 Some(StopMode::Stop1) 216 Some(StopMode::Stop1)
234 } else { 217 } else {
218 trace!("low power: not ready to stop (refcount_stop1: {})", unsafe {
219 REFCOUNT_STOP1
220 });
235 None 221 None
236 } 222 }
237 } 223 }
238 224
225 #[cfg(all(stm32wb, feature = "low-power"))]
226 fn configure_stop_stm32wb(&self, _cs: CriticalSection) -> Result<(), ()> {
227 use core::task::Poll;
228
229 use embassy_futures::poll_once;
230
231 use crate::hsem::HardwareSemaphoreChannel;
232 use crate::pac::rcc::vals::{Smps, Sw};
233 use crate::pac::{PWR, RCC};
234
235 trace!("low power: trying to get sem3");
236
237 let sem3_mutex = match poll_once(HardwareSemaphoreChannel::<crate::peripherals::HSEM>::new(3).lock(0)) {
238 Poll::Pending => None,
239 Poll::Ready(mutex) => Some(mutex),
240 }
241 .ok_or(())?;
242
243 trace!("low power: got sem3");
244
245 let sem4_mutex = HardwareSemaphoreChannel::<crate::peripherals::HSEM>::new(4).try_lock(0);
246 if let Some(sem4_mutex) = sem4_mutex {
247 trace!("low power: got sem4");
248
249 if PWR.extscr().read().c2ds() {
250 drop(sem4_mutex);
251 } else {
252 return Ok(());
253 }
254 }
255
256 // Sem4 not granted
257 // Set HSION
258 RCC.cr().modify(|w| {
259 w.set_hsion(true);
260 });
261
262 // Wait for HSIRDY
263 while !RCC.cr().read().hsirdy() {}
264
265 // Set SW to HSI
266 RCC.cfgr().modify(|w| {
267 w.set_sw(Sw::HSI);
268 });
269
270 // Wait for SWS to report HSI
271 while !RCC.cfgr().read().sws().eq(&Sw::HSI) {}
272
273 // Set SMPSSEL to HSI
274 RCC.smpscr().modify(|w| {
275 w.set_smpssel(Smps::HSI);
276 });
277
278 drop(sem3_mutex);
279
280 Ok(())
281 }
282
239 #[allow(unused_variables)] 283 #[allow(unused_variables)]
240 fn configure_stop(&mut self, stop_mode: StopMode) { 284 fn configure_stop(&self, _cs: CriticalSection, stop_mode: StopMode) -> Result<(), ()> {
241 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))] 285 #[cfg(all(stm32wb, feature = "low-power"))]
286 self.configure_stop_stm32wb(_cs)?;
287
288 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wlex))]
242 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 289 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
243 #[cfg(stm32h5)] 290 #[cfg(stm32h5)]
244 crate::pac::PWR.pmcr().modify(|v| { 291 crate::pac::PWR.pmcr().modify(|v| {
@@ -246,10 +293,12 @@ impl Executor {
246 v.set_lpms(vals::Lpms::STOP); 293 v.set_lpms(vals::Lpms::STOP);
247 v.set_svos(vals::Svos::SCALE3); 294 v.set_svos(vals::Svos::SCALE3);
248 }); 295 });
296
297 Ok(())
249 } 298 }
250 299
251 fn configure_pwr(&mut self) { 300 fn configure_pwr(&self) {
252 self.scb.clear_sleepdeep(); 301 Self::get_scb().clear_sleepdeep();
253 // Clear any previous stop flags 302 // Clear any previous stop flags
254 #[cfg(stm32wlex)] 303 #[cfg(stm32wlex)]
255 crate::pac::PWR.extscr().modify(|w| { 304 crate::pac::PWR.extscr().modify(|w| {
@@ -258,27 +307,18 @@ impl Executor {
258 307
259 compiler_fence(Ordering::SeqCst); 308 compiler_fence(Ordering::SeqCst);
260 309
261 let stop_mode = critical_section::with(|cs| Self::stop_mode(cs)); 310 critical_section::with(|cs| {
262 311 let _ = unsafe { RCC_CONFIG }?;
263 if stop_mode.is_none() { 312 let stop_mode = Self::stop_mode(cs)?;
264 trace!("low power: not ready to stop"); 313 get_driver().pause_time(cs).ok()?;
265 return; 314 self.configure_stop(cs, stop_mode).ok()?;
266 }
267
268 if get_driver().pause_time().is_err() {
269 trace!("low power: failed to pause time");
270 return;
271 }
272
273 let stop_mode = stop_mode.unwrap();
274 match stop_mode {
275 StopMode::Stop1 => trace!("low power: stop 1"),
276 StopMode::Stop2 => trace!("low power: stop 2"),
277 }
278 self.configure_stop(stop_mode);
279 315
280 #[cfg(not(feature = "low-power-debug-with-sleep"))] 316 Some(())
281 self.scb.set_sleepdeep(); 317 })
318 .map(|_| {
319 #[cfg(not(feature = "low-power-debug-with-sleep"))]
320 Self::get_scb().set_sleepdeep();
321 });
282 } 322 }
283 323
284 /// Run the executor. 324 /// Run the executor.
@@ -300,12 +340,11 @@ impl Executor {
300 /// 340 ///
301 /// This function never returns. 341 /// This function never returns.
302 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 342 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
303 let executor = unsafe { EXECUTOR.as_mut().unwrap() }; 343 init(self.inner.spawner());
304 init(executor.inner.spawner());
305 344
306 loop { 345 loop {
307 unsafe { 346 unsafe {
308 executor.inner.poll(); 347 self.inner.poll();
309 self.configure_pwr(); 348 self.configure_pwr();
310 asm!("wfe"); 349 asm!("wfe");
311 #[cfg(stm32wlex)] 350 #[cfg(stm32wlex)]
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index ac8d5de21..4a55f5bd3 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -4,19 +4,12 @@
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::Peri; 6use crate::Peri;
7#[cfg(opamp_v5)]
8use crate::block_for_us;
7use crate::pac::opamp::vals::*; 9use crate::pac::opamp::vals::*;
8#[cfg(not(any(stm32g4, stm32f3)))] 10#[cfg(not(any(stm32g4, stm32f3)))]
9use crate::rcc::RccInfo; 11use crate::rcc::RccInfo;
10 12
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
20/// Gain 13/// Gain
21#[allow(missing_docs)] 14#[allow(missing_docs)]
22#[derive(Clone, Copy)] 15#[derive(Clone, Copy)]
@@ -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 592a8594a..2d5dbd95a 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -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/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 584957c6d..2e1cbd702 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -1,6 +1,3 @@
1#[cfg(all(feature = "low-power", stm32wlex))]
2use core::mem::MaybeUninit;
3
4#[cfg(any(stm32l0, stm32l1))] 1#[cfg(any(stm32l0, stm32l1))]
5pub use crate::pac::pwr::vals::Vos as VoltageScale; 2pub use crate::pac::pwr::vals::Vos as VoltageScale;
6use crate::pac::rcc::regs::Cfgr; 3use crate::pac::rcc::regs::Cfgr;
@@ -14,42 +11,6 @@ use crate::time::Hertz;
14/// HSI speed 11/// HSI speed
15pub const HSI_FREQ: Hertz = Hertz(16_000_000); 12pub const HSI_FREQ: Hertz = Hertz(16_000_000);
16 13
17/// Saved RCC Config
18///
19/// Used when exiting STOP2 to re-enable clocks to their last configured state
20/// for chips that need it.
21#[cfg(all(feature = "low-power", stm32wlex))]
22static mut RESUME_RCC_CONFIG: MaybeUninit<Config> = MaybeUninit::uninit();
23
24/// Set the rcc config to be restored when exiting STOP2
25///
26/// Safety: Sets a mutable global.
27#[cfg(all(feature = "low-power", stm32wlex))]
28pub(crate) unsafe fn set_resume_config(config: Config) {
29 trace!("rcc set_resume_config()");
30 RESUME_RCC_CONFIG = MaybeUninit::new(config);
31}
32
33/// Get the rcc config to be restored when exiting STOP2
34///
35/// Safety: Reads a mutable global.
36#[cfg(all(feature = "low-power", stm32wlex))]
37pub(crate) unsafe fn get_resume_config() -> Config {
38 *(*core::ptr::addr_of_mut!(RESUME_RCC_CONFIG)).assume_init_ref()
39}
40
41#[cfg(all(feature = "low-power", stm32wlex))]
42/// Safety: should only be called from low power executable just after resuming from STOP2
43pub(crate) unsafe fn apply_resume_config() {
44 trace!("rcc apply_resume_config()");
45
46 while RCC.cfgr().read().sws() != Sysclk::MSI {}
47
48 let config = get_resume_config();
49
50 init(config);
51}
52
53#[derive(Clone, Copy, Eq, PartialEq)] 14#[derive(Clone, Copy, Eq, PartialEq)]
54pub enum HseMode { 15pub enum HseMode {
55 /// crystal/ceramic oscillator (HSEBYP=0) 16 /// crystal/ceramic oscillator (HSEBYP=0)
@@ -193,10 +154,6 @@ fn msi_enable(range: MSIRange) {
193} 154}
194 155
195pub(crate) unsafe fn init(config: Config) { 156pub(crate) unsafe fn init(config: Config) {
196 // save the rcc config because if we enter stop 2 we need to re-apply it on wakeup
197 #[cfg(all(feature = "low-power", stm32wlex))]
198 set_resume_config(config);
199
200 // Switch to MSI to prevent problems with PLL configuration. 157 // Switch to MSI to prevent problems with PLL configuration.
201 if !RCC.cr().read().msion() { 158 if !RCC.cr().read().msion() {
202 // Turn on MSI and configure it to 4MHz. 159 // Turn on MSI and configure it to 4MHz.
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 592890777..85434fa83 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -49,6 +49,9 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
49/// May be read without a critical section 49/// May be read without a critical section
50pub(crate) static mut REFCOUNT_STOP2: u32 = 0; 50pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
51 51
52#[cfg(feature = "low-power")]
53pub(crate) static mut RCC_CONFIG: Option<Config> = None;
54
52#[cfg(backup_sram)] 55#[cfg(backup_sram)]
53pub(crate) static mut BKSRAM_RETAINED: bool = false; 56pub(crate) static mut BKSRAM_RETAINED: bool = false;
54 57
@@ -108,6 +111,32 @@ pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clo
108 unsafe { get_freqs() } 111 unsafe { get_freqs() }
109} 112}
110 113
114#[cfg(feature = "low-power")]
115pub(crate) fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
116 match stop_mode {
117 StopMode::Standby => {}
118 StopMode::Stop2 => unsafe {
119 REFCOUNT_STOP2 += 1;
120 },
121 StopMode::Stop1 => unsafe {
122 REFCOUNT_STOP1 += 1;
123 },
124 }
125}
126
127#[cfg(feature = "low-power")]
128pub(crate) fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
129 match stop_mode {
130 StopMode::Standby => {}
131 StopMode::Stop2 => unsafe {
132 REFCOUNT_STOP2 -= 1;
133 },
134 StopMode::Stop1 => unsafe {
135 REFCOUNT_STOP1 -= 1;
136 },
137 }
138}
139
111pub(crate) trait SealedRccPeripheral { 140pub(crate) trait SealedRccPeripheral {
112 fn frequency() -> Hertz; 141 fn frequency() -> Hertz;
113 #[allow(dead_code)] 142 #[allow(dead_code)]
@@ -138,12 +167,19 @@ pub(crate) struct RccInfo {
138 stop_mode: StopMode, 167 stop_mode: StopMode,
139} 168}
140 169
170/// Specifies a limit for the stop mode of the peripheral or the stop mode to be entered.
171/// E.g. if `StopMode::Stop1` is selected, the peripheral prevents the chip from entering Stop1 mode.
141#[cfg(feature = "low-power")] 172#[cfg(feature = "low-power")]
142#[allow(dead_code)] 173#[allow(dead_code)]
143pub(crate) enum StopMode { 174#[derive(Debug, Clone, Copy, PartialEq, Default)]
144 Standby, 175pub enum StopMode {
145 Stop2, 176 #[default]
177 /// Peripheral prevents chip from entering Stop1 or executor will enter Stop1
146 Stop1, 178 Stop1,
179 /// Peripheral prevents chip from entering Stop2 or executor will enter Stop2
180 Stop2,
181 /// Peripheral does not prevent chip from entering Stop
182 Standby,
147} 183}
148 184
149impl RccInfo { 185impl RccInfo {
@@ -199,15 +235,7 @@ impl RccInfo {
199 } 235 }
200 236
201 #[cfg(feature = "low-power")] 237 #[cfg(feature = "low-power")]
202 match self.stop_mode { 238 increment_stop_refcount(_cs, self.stop_mode);
203 StopMode::Standby => {}
204 StopMode::Stop2 => unsafe {
205 REFCOUNT_STOP2 += 1;
206 },
207 StopMode::Stop1 => unsafe {
208 REFCOUNT_STOP1 += 1;
209 },
210 }
211 239
212 // set the xxxRST bit 240 // set the xxxRST bit
213 let reset_ptr = self.reset_ptr(); 241 let reset_ptr = self.reset_ptr();
@@ -265,15 +293,7 @@ impl RccInfo {
265 } 293 }
266 294
267 #[cfg(feature = "low-power")] 295 #[cfg(feature = "low-power")]
268 match self.stop_mode { 296 decrement_stop_refcount(_cs, self.stop_mode);
269 StopMode::Standby => {}
270 StopMode::Stop2 => unsafe {
271 REFCOUNT_STOP2 -= 1;
272 },
273 StopMode::Stop1 => unsafe {
274 REFCOUNT_STOP1 -= 1;
275 },
276 }
277 297
278 // clear the xxxEN bit 298 // clear the xxxEN bit
279 let enable_ptr = self.enable_ptr(); 299 let enable_ptr = self.enable_ptr();
@@ -408,8 +428,39 @@ pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) {
408 428
409 #[cfg(feature = "low-power")] 429 #[cfg(feature = "low-power")]
410 { 430 {
431 RCC_CONFIG = Some(config);
411 REFCOUNT_STOP2 = 0; 432 REFCOUNT_STOP2 = 0;
412 REFCOUNT_STOP1 = 0; 433 REFCOUNT_STOP1 = 0;
413 } 434 }
414 } 435 }
415} 436}
437
438/// Calculate intermediate prescaler number used to calculate peripheral prescalers
439///
440/// This function is intended to calculate a number indicating a minimum division
441/// necessary to result in a frequency lower than the provided `freq_max`.
442///
443/// The returned value indicates the `val + 1` divider is necessary to result in
444/// the output frequency that is below the maximum provided.
445///
446/// For example:
447/// 0 = divider of 1 => no division necessary as the input frequency is below max
448/// 1 = divider of 2 => division by 2 necessary
449/// ...
450///
451/// The provided max frequency is inclusive. So if `freq_in == freq_max` the result
452/// will be 0, indicating that no division is necessary. To accomplish that we subtract
453/// 1 from the input frequency so that the integer rounding plays in our favor.
454///
455/// For example:
456/// Let the input frequency be 110 and the max frequency be 55.
457/// If we naiively do `110/55 = 2` the renult will indicate that we need a divider by 3
458/// which in reality will be rounded up to 4 as usually a 3 division is not available.
459/// In either case the resulting frequency will be either 36 or 27 which is lower than
460/// what we would want. The result should be 1.
461/// If we do the following instead `109/55 = 1` indicating that we need a divide by 2
462/// which will result in the correct 55.
463#[allow(unused)]
464pub(crate) fn raw_prescaler(freq_in: u32, freq_max: u32) -> u32 {
465 freq_in.saturating_sub(1) / freq_max
466}
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index e5bf30927..f049d6b12 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -3,6 +3,7 @@ use embassy_time::{Duration, TICK_HZ};
3 3
4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; 4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte};
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::pac::rtc::vals::Wucksel;
6use crate::peripherals::RTC; 7use crate::peripherals::RTC;
7use crate::rtc::{RtcTimeProvider, SealedInstance}; 8use crate::rtc::{RtcTimeProvider, SealedInstance};
8 9
@@ -58,60 +59,16 @@ 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, stm32wlex
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, stm32wlex
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 {
@@ -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));
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 116b3c7ed..e88bd7ab2 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -379,13 +379,16 @@ trait SealedInstance {
379} 379}
380 380
381#[cfg(feature = "low-power")] 381#[cfg(feature = "low-power")]
382pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig) { 382pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig, min_stop_pause: embassy_time::Duration) {
383 use crate::time_driver::get_driver;
384
383 #[cfg(feature = "_allow-disable-rtc")] 385 #[cfg(feature = "_allow-disable-rtc")]
384 if config._disable_rtc { 386 if config._disable_rtc {
385 return; 387 return;
386 } 388 }
387 389
388 crate::time_driver::get_driver().set_rtc(cs, Rtc::new_inner(config)); 390 get_driver().set_rtc(cs, Rtc::new_inner(config));
391 get_driver().set_min_stop_pause(cs, min_stop_pause);
389 392
390 trace!("low power: stop with rtc configured"); 393 trace!("low power: stop with rtc configured");
391} 394}
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index 726d1729a..ce4bc43c3 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -391,7 +391,7 @@ 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: Option<MasterClockDivider>,
@@ -696,7 +696,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
696 w.set_fspol(config.frame_sync_polarity.fspol()); 696 w.set_fspol(config.frame_sync_polarity.fspol());
697 w.set_fsdef(config.frame_sync_definition.fsdef()); 697 w.set_fsdef(config.frame_sync_definition.fsdef());
698 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); 698 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1);
699 w.set_frl(config.frame_length - 1); 699 w.set_frl((config.frame_length - 1).try_into().unwrap());
700 }); 700 });
701 701
702 ch.slotr().modify(|w| { 702 ch.slotr().modify(|w| {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 7db51d72e..0b75aef92 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -196,6 +196,11 @@ fn calc_now(period: u32, counter: u16) -> u64 {
196 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) 196 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
197} 197}
198 198
199#[cfg(feature = "low-power")]
200fn calc_period_counter(ticks: u64) -> (u32, u16) {
201 (2 * (ticks >> 16) as u32 + (ticks as u16 >= 0x8000) as u32, ticks as u16)
202}
203
199struct AlarmState { 204struct AlarmState {
200 timestamp: Cell<u64>, 205 timestamp: Cell<u64>,
201} 206}
@@ -240,7 +245,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
240impl RtcDriver { 245impl RtcDriver {
241 /// initialize the timer, but don't start it. Used for chips like stm32wle5 246 /// initialize the timer, but don't start it. Used for chips like stm32wle5
242 /// for low power where the timer config is lost in STOP2. 247 /// for low power where the timer config is lost in STOP2.
243 fn init_timer(&'static self, cs: critical_section::CriticalSection) { 248 pub(crate) fn init_timer(&'static self, cs: critical_section::CriticalSection) {
244 let r = regs_gp16(); 249 let r = regs_gp16();
245 250
246 rcc::enable_and_reset_with_cs::<T>(cs); 251 rcc::enable_and_reset_with_cs::<T>(cs);
@@ -358,34 +363,10 @@ impl RtcDriver {
358 #[cfg(feature = "low-power")] 363 #[cfg(feature = "low-power")]
359 /// Add the given offset to the current time 364 /// Add the given offset to the current time
360 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { 365 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
361 let offset = offset.as_ticks(); 366 let (period, counter) = calc_period_counter(self.now() + offset.as_ticks());
362 let cnt = regs_gp16().cnt().read().cnt() as u32;
363 let period = self.period.load(Ordering::SeqCst);
364
365 // Correct the race, if it exists
366 let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 {
367 period + 1
368 } else {
369 period
370 };
371
372 // Normalize to the full overflow
373 let period = (period / 2) * 2;
374
375 // Add the offset
376 let period = period + 2 * (offset / u16::MAX as u64) as u32;
377 let cnt = cnt + (offset % u16::MAX as u64) as u32;
378
379 let (cnt, period) = if cnt > u16::MAX as u32 {
380 (cnt - u16::MAX as u32, period + 2)
381 } else {
382 (cnt, period)
383 };
384
385 let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period };
386 367
387 self.period.store(period, Ordering::SeqCst); 368 self.period.store(period, Ordering::SeqCst);
388 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); 369 regs_gp16().cnt().write(|w| w.set_cnt(counter));
389 370
390 // Now, recompute alarm 371 // Now, recompute alarm
391 let alarm = self.alarm.borrow(cs); 372 let alarm = self.alarm.borrow(cs);
@@ -399,13 +380,15 @@ impl RtcDriver {
399 #[cfg(feature = "low-power")] 380 #[cfg(feature = "low-power")]
400 /// Stop the wakeup alarm, if enabled, and add the appropriate offset 381 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
401 fn stop_wakeup_alarm(&self, cs: CriticalSection) { 382 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
402 if let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs) { 383 if !regs_gp16().cr1().read().cen()
384 && let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs)
385 {
403 self.add_time(offset, cs); 386 self.add_time(offset, cs);
404 } 387 }
405 } 388 }
406 389
407 /* 390 /*
408 Low-power public functions: all create or require a critical section 391 Low-power public functions: all require a critical section
409 */ 392 */
410 #[cfg(feature = "low-power")] 393 #[cfg(feature = "low-power")]
411 pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) { 394 pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) {
@@ -422,49 +405,36 @@ impl RtcDriver {
422 405
423 #[cfg(feature = "low-power")] 406 #[cfg(feature = "low-power")]
424 /// Pause the timer if ready; return err if not 407 /// Pause the timer if ready; return err if not
425 pub(crate) fn pause_time(&self) -> Result<(), ()> { 408 pub(crate) fn pause_time(&self, cs: CriticalSection) -> Result<(), ()> {
426 critical_section::with(|cs| { 409 self.stop_wakeup_alarm(cs);
427 /* 410
428 If the wakeup timer is currently running, then we need to stop it and 411 let time_until_next_alarm = self.time_until_next_alarm(cs);
429 add the elapsed time to the current time, as this will impact the result 412 if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() {
430 of `time_until_next_alarm`. 413 trace!(
431 */ 414 "time_until_next_alarm < self.min_stop_pause ({})",
432 self.stop_wakeup_alarm(cs); 415 time_until_next_alarm
433 416 );
434 let time_until_next_alarm = self.time_until_next_alarm(cs); 417 Err(())
435 if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() { 418 } else {
436 trace!( 419 self.rtc
437 "time_until_next_alarm < self.min_stop_pause ({})", 420 .borrow(cs)
438 time_until_next_alarm 421 .borrow_mut()
439 ); 422 .as_mut()
440 Err(()) 423 .unwrap()
441 } else { 424 .start_wakeup_alarm(time_until_next_alarm, cs);
442 self.rtc 425
443 .borrow(cs) 426 regs_gp16().cr1().modify(|w| w.set_cen(false));
444 .borrow_mut() 427 // save the count for the timer as its lost in STOP2 for stm32wlex
445 .as_mut() 428 #[cfg(stm32wlex)]
446 .unwrap() 429 self.saved_count
447 .start_wakeup_alarm(time_until_next_alarm, cs); 430 .store(regs_gp16().cnt().read().cnt() as u16, Ordering::SeqCst);
448 431 Ok(())
449 regs_gp16().cr1().modify(|w| w.set_cen(false)); 432 }
450 // save the count for the timer as its lost in STOP2 for stm32wlex
451 #[cfg(stm32wlex)]
452 self.saved_count
453 .store(regs_gp16().cnt().read().cnt() as u16, Ordering::SeqCst);
454 Ok(())
455 }
456 })
457 } 433 }
458 434
459 #[cfg(feature = "low-power")] 435 #[cfg(feature = "low-power")]
460 /// Resume the timer with the given offset 436 /// Resume the timer with the given offset
461 pub(crate) fn resume_time(&self, cs: CriticalSection) { 437 pub(crate) fn resume_time(&self, cs: CriticalSection) {
462 if regs_gp16().cr1().read().cen() {
463 // Time isn't currently stopped
464
465 return;
466 }
467
468 self.stop_wakeup_alarm(cs); 438 self.stop_wakeup_alarm(cs);
469 439
470 regs_gp16().cr1().modify(|w| w.set_cen(true)); 440 regs_gp16().cr1().modify(|w| w.set_cen(true));
@@ -546,8 +516,3 @@ pub(crate) const fn get_driver() -> &'static RtcDriver {
546pub(crate) fn init(cs: CriticalSection) { 516pub(crate) fn init(cs: CriticalSection) {
547 DRIVER.init(cs) 517 DRIVER.init(cs)
548} 518}
549
550#[cfg(all(feature = "low-power", stm32wlex))]
551pub(crate) fn init_timer(cs: CriticalSection) {
552 DRIVER.init_timer(cs)
553}
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 9a56a41fb..77f19a37b 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -77,8 +77,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
77 77
78 this.inner.set_counting_mode(counting_mode); 78 this.inner.set_counting_mode(counting_mode);
79 this.set_frequency(freq); 79 this.set_frequency(freq);
80 this.inner.start();
81
82 this.inner.enable_outputs(); 80 this.inner.enable_outputs();
83 81
84 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 82 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
@@ -89,6 +87,10 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
89 }); 87 });
90 this.inner.set_autoreload_preload(true); 88 this.inner.set_autoreload_preload(true);
91 89
90 // Generate update event so pre-load registers are written to the shadow registers
91 this.inner.generate_update_event();
92 this.inner.start();
93
92 this 94 this
93 } 95 }
94 96
@@ -160,8 +162,8 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
160 162
161 /// Set PWM frequency. 163 /// Set PWM frequency.
162 /// 164 ///
163 /// Note: when you call this, the max duty value changes, so you will have to 165 /// Note: that the frequency will not be applied in the timer until an update event
164 /// call `set_duty` on all channels with the duty calculated based on the new max duty. 166 /// occurs.
165 pub fn set_frequency(&mut self, freq: Hertz) { 167 pub fn set_frequency(&mut self, freq: Hertz) {
166 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 168 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
167 2u8 169 2u8
@@ -219,59 +221,53 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
219 /// Note: 221 /// Note:
220 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 222 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
221 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 223 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
222 #[allow(clippy::let_unit_value)] // eg. stm32f334 224 self.inner.enable_channel(channel, true);
223 let req = dma.request(); 225 self.inner.enable_update_dma(true);
224 226 self.inner.setup_update_dma(dma, channel, duty).await;
225 let original_duty_state = self.inner.get_compare_value(channel); 227 self.inner.enable_update_dma(false);
226 let original_enable_state = self.inner.get_channel_enable_state(channel); 228 }
227 let original_update_dma_state = self.inner.get_update_dma_state();
228
229 if !original_update_dma_state {
230 self.inner.enable_update_dma(true);
231 }
232
233 if !original_enable_state {
234 self.inner.enable_channel(channel, true);
235 }
236
237 unsafe {
238 #[cfg(not(any(bdma, gpdma)))]
239 use crate::dma::{Burst, FifoThreshold};
240 use crate::dma::{Transfer, TransferOptions};
241
242 let dma_transfer_option = TransferOptions {
243 #[cfg(not(any(bdma, gpdma)))]
244 fifo_threshold: Some(FifoThreshold::Full),
245 #[cfg(not(any(bdma, gpdma)))]
246 mburst: Burst::Incr8,
247 ..Default::default()
248 };
249
250 Transfer::new_write(
251 dma,
252 req,
253 duty,
254 self.inner.regs_gp16().ccr(channel.index()).as_ptr() as *mut u16,
255 dma_transfer_option,
256 )
257 .await
258 };
259
260 // restore output compare state
261 if !original_enable_state {
262 self.inner.enable_channel(channel, false);
263 }
264
265 self.inner.set_compare_value(channel, original_duty_state);
266 229
267 // Since DMA is closed before timer update event trigger DMA is turn off, 230 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
268 // this can almost always trigger a DMA FIFO error. 231 ///
269 // 232 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
270 // optional TODO: 233 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
271 // clean FEIF after disable UDE 234 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
272 if !original_update_dma_state { 235 ///
273 self.inner.enable_update_dma(false); 236 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
274 } 237 /// represents a single update event and each column corresponds to a specific timer channel (starting
238 /// from `starting_channel` up to and including `ending_channel`).
239 ///
240 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
241 ///
242 /// ```rust,ignore
243 /// let dma_buf: [u16; 16] = [
244 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
245 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
246 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
247 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
248 /// ];
249 /// ```
250 ///
251 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
252 /// updating the duty cycles of all selected channels simultaneously.
253 ///
254 /// Note:
255 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
256 /// Also be aware that embassy timers use one of timers internally. It is possible to
257 /// switch this timer by using `time-driver-timX` feature.
258 ///
259 pub async fn waveform_up_multi_channel(
260 &mut self,
261 dma: Peri<'_, impl super::UpDma<T>>,
262 starting_channel: Channel,
263 ending_channel: Channel,
264 duty: &[u16],
265 ) {
266 self.inner.enable_update_dma(true);
267 self.inner
268 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
269 .await;
270 self.inner.enable_update_dma(false);
275 } 271 }
276} 272}
277 273
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index 2a4ec2db0..9cf0f8c34 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -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
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index 0122fe4f7..aba08081f 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -13,6 +13,7 @@ use embassy_hal_internal::Peri;
13pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, 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::{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;
@@ -272,6 +273,17 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
272 self.regs_core().cr1().modify(|r| r.set_cen(true)); 273 self.regs_core().cr1().modify(|r| r.set_cen(true));
273 } 274 }
274 275
276 /// Generate timer update event from software.
277 ///
278 /// Set URS to avoid generating interrupt or DMA request. This update event is only
279 /// used to load value from pre-load registers. If called when the timer is running,
280 /// it may disrupt the output waveform.
281 pub fn generate_update_event(&self) {
282 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
283 self.regs_core().egr().write(|r| r.set_ug(true));
284 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
285 }
286
275 /// Stop the timer. 287 /// Stop the timer.
276 pub fn stop(&self) { 288 pub fn stop(&self) {
277 self.regs_core().cr1().modify(|r| r.set_cen(false)); 289 self.regs_core().cr1().modify(|r| r.set_cen(false));
@@ -322,10 +334,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
322 let regs = self.regs_core(); 334 let regs = self.regs_core();
323 regs.psc().write_value(psc); 335 regs.psc().write_value(psc);
324 regs.arr().write(|r| r.set_arr(arr)); 336 regs.arr().write(|r| r.set_arr(arr));
325
326 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
327 regs.egr().write(|r| r.set_ug(true));
328 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
329 } 337 }
330 #[cfg(not(stm32l0))] 338 #[cfg(not(stm32l0))]
331 TimerBits::Bits32 => { 339 TimerBits::Bits32 => {
@@ -335,10 +343,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
335 let regs = self.regs_gp32_unchecked(); 343 let regs = self.regs_gp32_unchecked();
336 regs.psc().write_value(psc); 344 regs.psc().write_value(psc);
337 regs.arr().write_value(arr); 345 regs.arr().write_value(arr);
338
339 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
340 regs.egr().write(|r| r.set_ug(true));
341 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
342 } 346 }
343 } 347 }
344 } 348 }
@@ -656,6 +660,167 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
656 } 660 }
657 } 661 }
658 662
663 /// Setup a ring buffer for the channel
664 pub fn setup_ring_buffer<'a>(
665 &mut self,
666 dma: Peri<'a, impl super::UpDma<T>>,
667 channel: Channel,
668 dma_buf: &'a mut [u16],
669 ) -> WritableRingBuffer<'a, u16> {
670 #[allow(clippy::let_unit_value)] // eg. stm32f334
671 let req = dma.request();
672
673 unsafe {
674 use crate::dma::TransferOptions;
675 #[cfg(not(any(bdma, gpdma)))]
676 use crate::dma::{Burst, FifoThreshold};
677
678 let dma_transfer_option = TransferOptions {
679 #[cfg(not(any(bdma, gpdma)))]
680 fifo_threshold: Some(FifoThreshold::Full),
681 #[cfg(not(any(bdma, gpdma)))]
682 mburst: Burst::Incr8,
683 ..Default::default()
684 };
685
686 WritableRingBuffer::new(
687 dma,
688 req,
689 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
690 dma_buf,
691 dma_transfer_option,
692 )
693 }
694 }
695
696 /// Generate a sequence of PWM waveform
697 ///
698 /// Note:
699 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
700 pub fn setup_update_dma<'a>(
701 &mut self,
702 dma: Peri<'a, impl super::UpDma<T>>,
703 channel: Channel,
704 duty: &'a [u16],
705 ) -> Transfer<'a> {
706 #[allow(clippy::let_unit_value)] // eg. stm32f334
707 let req = dma.request();
708
709 unsafe {
710 #[cfg(not(any(bdma, gpdma)))]
711 use crate::dma::{Burst, FifoThreshold};
712 use crate::dma::{Transfer, TransferOptions};
713
714 let dma_transfer_option = TransferOptions {
715 #[cfg(not(any(bdma, gpdma)))]
716 fifo_threshold: Some(FifoThreshold::Full),
717 #[cfg(not(any(bdma, gpdma)))]
718 mburst: Burst::Incr8,
719 ..Default::default()
720 };
721
722 match self.bits() {
723 TimerBits::Bits16 => Transfer::new_write(
724 dma,
725 req,
726 duty,
727 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
728 dma_transfer_option,
729 ),
730 #[cfg(not(any(stm32l0)))]
731 TimerBits::Bits32 => {
732 #[cfg(not(any(bdma, gpdma)))]
733 panic!("unsupported timer bits");
734
735 #[cfg(any(bdma, gpdma))]
736 Transfer::new_write(
737 dma,
738 req,
739 duty,
740 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
741 dma_transfer_option,
742 )
743 }
744 }
745 }
746 }
747
748 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
749 ///
750 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
751 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
752 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
753 ///
754 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
755 /// represents a single update event and each column corresponds to a specific timer channel (starting
756 /// from `starting_channel` up to and including `ending_channel`).
757 ///
758 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
759 ///
760 /// ```rust,ignore
761 /// let dma_buf: [u16; 16] = [
762 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
763 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
764 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
765 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
766 /// ];
767 /// ```
768 ///
769 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
770 /// updating the duty cycles of all selected channels simultaneously.
771 ///
772 /// Note:
773 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
774 /// Also be aware that embassy timers use one of timers internally. It is possible to
775 /// switch this timer by using `time-driver-timX` feature.
776 ///
777 pub fn setup_update_dma_burst<'a>(
778 &mut self,
779 dma: Peri<'a, impl super::UpDma<T>>,
780 starting_channel: Channel,
781 ending_channel: Channel,
782 duty: &'a [u16],
783 ) -> Transfer<'a> {
784 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
785 let start_ch_index = starting_channel.index();
786 let end_ch_index = ending_channel.index();
787
788 assert!(start_ch_index <= end_ch_index);
789
790 let ccrx_addr = self.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
791 self.regs_gp16()
792 .dcr()
793 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
794 self.regs_gp16()
795 .dcr()
796 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
797
798 #[allow(clippy::let_unit_value)] // eg. stm32f334
799 let req = dma.request();
800
801 unsafe {
802 #[cfg(not(any(bdma, gpdma)))]
803 use crate::dma::{Burst, FifoThreshold};
804 use crate::dma::{Transfer, TransferOptions};
805
806 let dma_transfer_option = TransferOptions {
807 #[cfg(not(any(bdma, gpdma)))]
808 fifo_threshold: Some(FifoThreshold::Full),
809 #[cfg(not(any(bdma, gpdma)))]
810 mburst: Burst::Incr4,
811 ..Default::default()
812 };
813
814 Transfer::new_write(
815 dma,
816 req,
817 duty,
818 self.regs_gp16().dmar().as_ptr() as *mut u16,
819 dma_transfer_option,
820 )
821 }
822 }
823
659 /// Get capture value for a channel. 824 /// Get capture value for a channel.
660 pub fn get_capture_value(&self, channel: Channel) -> u32 { 825 pub fn get_capture_value(&self, channel: Channel) -> u32 {
661 self.get_compare_value(channel) 826 self.get_compare_value(channel)
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 804d1ef37..3fa363881 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -12,6 +12,7 @@ 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
17use crate::interrupt; 18use crate::interrupt;
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index da8a79b09..057ab011a 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -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
diff --git a/embassy-stm32/src/timer/ringbuffered.rs b/embassy-stm32/src/timer/ringbuffered.rs
new file mode 100644
index 000000000..e8f97bf59
--- /dev/null
+++ b/embassy-stm32/src/timer/ringbuffered.rs
@@ -0,0 +1,169 @@
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;
10
11/// A PWM channel that uses a DMA ring buffer for continuous waveform generation.
12///
13/// This allows you to continuously update PWM duty cycles via DMA without blocking the CPU.
14/// The ring buffer enables smooth, uninterrupted waveform generation by automatically cycling
15/// through duty cycle values stored in memory.
16///
17/// You can write new duty cycle values to the ring buffer while it's running, enabling
18/// dynamic waveform generation for applications like motor control, LED dimming, or audio output.
19///
20/// # Example
21/// ```ignore
22/// let mut channel = pwm.ch1().into_ring_buffered_channel(dma_ch, &mut buffer);
23/// channel.start(); // Start DMA transfer
24/// channel.write(&[100, 200, 300]).ok(); // Update duty cycles
25/// ```
26pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel> {
27 timer: ManuallyDrop<Timer<'d, T>>,
28 ring_buf: WritableRingBuffer<'d, u16>,
29 channel: Channel,
30}
31
32impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> {
33 pub(crate) fn new(
34 timer: ManuallyDrop<Timer<'d, T>>,
35 channel: Channel,
36 ring_buf: WritableRingBuffer<'d, u16>,
37 ) -> Self {
38 Self {
39 timer,
40 ring_buf,
41 channel,
42 }
43 }
44
45 /// Start the ring buffer operation.
46 ///
47 /// You must call this after creating it for it to work.
48 pub fn start(&mut self) {
49 self.ring_buf.start()
50 }
51
52 /// Clear all data in the ring buffer.
53 pub fn clear(&mut self) {
54 self.ring_buf.clear()
55 }
56
57 /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer.
58 pub fn write_immediate(&mut self, buf: &[u16]) -> Result<(usize, usize), Error> {
59 self.ring_buf.write_immediate(buf)
60 }
61
62 /// Write elements from the ring buffer
63 /// Return a tuple of the length written and the length remaining in the buffer
64 pub fn write(&mut self, buf: &[u16]) -> Result<(usize, usize), Error> {
65 self.ring_buf.write(buf)
66 }
67
68 /// Write an exact number of elements to the ringbuffer.
69 pub async fn write_exact(&mut self, buffer: &[u16]) -> Result<usize, Error> {
70 self.ring_buf.write_exact(buffer).await
71 }
72
73 /// Wait for any ring buffer write error.
74 pub async fn wait_write_error(&mut self) -> Result<usize, Error> {
75 self.ring_buf.wait_write_error().await
76 }
77
78 /// The current length of the ringbuffer
79 pub fn len(&mut self) -> Result<usize, Error> {
80 self.ring_buf.len()
81 }
82
83 /// The capacity of the ringbuffer
84 pub const fn capacity(&self) -> usize {
85 self.ring_buf.capacity()
86 }
87
88 /// Set a waker to be woken when at least one byte is send.
89 pub fn set_waker(&mut self, waker: &Waker) {
90 self.ring_buf.set_waker(waker)
91 }
92
93 /// Request the DMA to reset. The configuration for this channel will not be preserved.
94 ///
95 /// This doesn't immediately stop the transfer, you have to wait until is_running returns false.
96 pub fn request_reset(&mut self) {
97 self.ring_buf.request_reset()
98 }
99
100 /// Request the transfer to pause, keeping the existing configuration for this channel.
101 /// To restart the transfer, call [`start`](Self::start) again.
102 ///
103 /// This doesn't immediately stop the transfer, you have to wait until is_running returns false.
104 pub fn request_pause(&mut self) {
105 self.ring_buf.request_pause()
106 }
107
108 /// Return whether DMA is still running.
109 ///
110 /// If this returns false, it can be because either the transfer finished, or it was requested to stop early with request_stop.
111 pub fn is_running(&mut self) -> bool {
112 self.ring_buf.is_running()
113 }
114
115 /// Stop the DMA transfer and await until the buffer is empty.
116 ///
117 /// This disables the DMA transfer's circular mode so that the transfer stops when all available data has been written.
118 ///
119 /// This is designed to be used with streaming output data such as the I2S/SAI or DAC.
120 pub async fn stop(&mut self) {
121 self.ring_buf.stop().await
122 }
123
124 /// Enable the given channel.
125 pub fn enable(&mut self) {
126 self.timer.enable_channel(self.channel, true);
127 }
128
129 /// Disable the given channel.
130 pub fn disable(&mut self) {
131 self.timer.enable_channel(self.channel, false);
132 }
133
134 /// Check whether given channel is enabled
135 pub fn is_enabled(&self) -> bool {
136 self.timer.get_channel_enable_state(self.channel)
137 }
138
139 /// Get max duty value.
140 ///
141 /// This value depends on the configured frequency and the timer's clock rate from RCC.
142 pub fn max_duty_cycle(&self) -> u16 {
143 let max = self.timer.get_max_compare_value();
144 assert!(max < u16::MAX as u32);
145 max as u16 + 1
146 }
147
148 /// Set the output polarity for a given channel.
149 pub fn set_polarity(&mut self, polarity: super::low_level::OutputPolarity) {
150 self.timer.set_output_polarity(self.channel, polarity);
151 }
152
153 /// Set the output compare mode for a given channel.
154 pub fn set_output_compare_mode(&mut self, mode: super::low_level::OutputCompareMode) {
155 self.timer.set_output_compare_mode(self.channel, mode);
156 }
157}
158
159/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`].
160pub struct RingBufferedPwmChannels<'d, T: GeneralInstance4Channel> {
161 /// Channel 1
162 pub ch1: RingBufferedPwmChannel<'d, T>,
163 /// Channel 2
164 pub ch2: RingBufferedPwmChannel<'d, T>,
165 /// Channel 3
166 pub ch3: RingBufferedPwmChannel<'d, T>,
167 /// Channel 4
168 pub ch4: RingBufferedPwmChannel<'d, T>,
169}
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 36303aeb4..484e9fd81 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -4,7 +4,8 @@ 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};
8use crate::Peri; 9use crate::Peri;
9#[cfg(gpio_v2)] 10#[cfg(gpio_v2)]
10use crate::gpio::Pull; 11use crate::gpio::Pull;
@@ -158,6 +159,33 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
158 pub fn set_output_compare_mode(&mut self, mode: OutputCompareMode) { 159 pub fn set_output_compare_mode(&mut self, mode: OutputCompareMode) {
159 self.timer.set_output_compare_mode(self.channel, mode); 160 self.timer.set_output_compare_mode(self.channel, mode);
160 } 161 }
162
163 /// Convert this PWM channel into a ring-buffered PWM channel.
164 ///
165 /// This allows continuous PWM waveform generation using a DMA ring buffer.
166 /// The ring buffer enables dynamic updates to the PWM duty cycle without blocking.
167 ///
168 /// # Arguments
169 /// * `tx_dma` - The DMA channel to use for transferring duty cycle values
170 /// * `dma_buf` - The buffer to use as a ring buffer (must be non-empty and <= 65535 elements)
171 ///
172 /// # Panics
173 /// Panics if `dma_buf` is empty or longer than 65535 elements.
174 pub fn into_ring_buffered_channel(
175 mut self,
176 tx_dma: Peri<'d, impl super::UpDma<T>>,
177 dma_buf: &'d mut [u16],
178 ) -> RingBufferedPwmChannel<'d, T> {
179 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
180
181 self.timer.enable_update_dma(true);
182
183 RingBufferedPwmChannel::new(
184 unsafe { self.timer.clone_unchecked() },
185 self.channel,
186 self.timer.setup_ring_buffer(tx_dma, self.channel, dma_buf),
187 )
188 }
161} 189}
162 190
163/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`]. 191/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`].
@@ -198,7 +226,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
198 this.inner.set_counting_mode(counting_mode); 226 this.inner.set_counting_mode(counting_mode);
199 this.set_frequency(freq); 227 this.set_frequency(freq);
200 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 228 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
201 this.inner.start();
202 229
203 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 230 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
204 .iter() 231 .iter()
@@ -207,6 +234,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
207 234
208 this.inner.set_output_compare_preload(channel, true); 235 this.inner.set_output_compare_preload(channel, true);
209 }); 236 });
237 this.inner.set_autoreload_preload(true);
238
239 // Generate update event so pre-load registers are written to the shadow registers
240 this.inner.generate_update_event();
241 this.inner.start();
210 242
211 this 243 this
212 } 244 }
@@ -285,8 +317,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
285 317
286 /// Set PWM frequency. 318 /// Set PWM frequency.
287 /// 319 ///
288 /// Note: when you call this, the max duty value changes, so you will have to 320 /// 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. 321 /// occurs.
290 pub fn set_frequency(&mut self, freq: Hertz) { 322 pub fn set_frequency(&mut self, freq: Hertz) {
291 // TODO: prevent ARR = u16::MAX? 323 // TODO: prevent ARR = u16::MAX?
292 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 324 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
@@ -309,80 +341,14 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
309 /// Generate a sequence of PWM waveform 341 /// Generate a sequence of PWM waveform
310 /// 342 ///
311 /// Note: 343 /// Note:
312 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 344 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
345 /// Also be aware that embassy timers use one of timers internally. It is possible to
346 /// switch this timer by using `time-driver-timX` feature.
313 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 347 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
314 #[allow(clippy::let_unit_value)] // eg. stm32f334 348 self.inner.enable_channel(channel, true);
315 let req = dma.request(); 349 self.inner.enable_update_dma(true);
316 350 self.inner.setup_update_dma(dma, channel, duty).await;
317 let original_duty_state = self.channel(channel).current_duty_cycle(); 351 self.inner.enable_update_dma(false);
318 let original_enable_state = self.channel(channel).is_enabled();
319 let original_update_dma_state = self.inner.get_update_dma_state();
320
321 if !original_update_dma_state {
322 self.inner.enable_update_dma(true);
323 }
324
325 if !original_enable_state {
326 self.channel(channel).enable();
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 match self.inner.bits() {
343 TimerBits::Bits16 => {
344 Transfer::new_write(
345 dma,
346 req,
347 duty,
348 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
349 dma_transfer_option,
350 )
351 .await
352 }
353 #[cfg(not(any(stm32l0)))]
354 TimerBits::Bits32 => {
355 #[cfg(not(any(bdma, gpdma)))]
356 panic!("unsupported timer bits");
357
358 #[cfg(any(bdma, gpdma))]
359 Transfer::new_write(
360 dma,
361 req,
362 duty,
363 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
364 dma_transfer_option,
365 )
366 .await
367 }
368 };
369 };
370
371 // restore output compare state
372 if !original_enable_state {
373 self.channel(channel).disable();
374 }
375
376 self.channel(channel).set_duty_cycle(original_duty_state);
377
378 // Since DMA is closed before timer update event trigger DMA is turn off,
379 // this can almost always trigger a DMA FIFO error.
380 //
381 // optional TODO:
382 // clean FEIF after disable UDE
383 if !original_update_dma_state {
384 self.inner.enable_update_dma(false);
385 }
386 } 352 }
387 353
388 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. 354 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
@@ -397,18 +363,23 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
397 /// 363 ///
398 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: 364 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
399 /// 365 ///
366 /// ```rust,ignore
400 /// let dma_buf: [u16; 16] = [ 367 /// let dma_buf: [u16; 16] = [
401 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 368 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
402 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 369 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
403 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 370 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
404 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 371 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
405 /// ]; 372 /// ];
373 /// ```
406 /// 374 ///
407 /// Each group of N values (where N = number of channels) is transferred on one update event, 375 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
408 /// updating the duty cycles of all selected channels simultaneously. 376 /// updating the duty cycles of all selected channels simultaneously.
409 /// 377 ///
410 /// Note: 378 /// Note:
411 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 379 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
380 /// Also be aware that embassy timers use one of timers internally. It is possible to
381 /// switch this timer by using `time-driver-timX` feature.
382 ///
412 pub async fn waveform_up_multi_channel( 383 pub async fn waveform_up_multi_channel(
413 &mut self, 384 &mut self,
414 dma: Peri<'_, impl super::UpDma<T>>, 385 dma: Peri<'_, impl super::UpDma<T>>,
@@ -416,148 +387,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
416 ending_channel: Channel, 387 ending_channel: Channel,
417 duty: &[u16], 388 duty: &[u16],
418 ) { 389 ) {
419 let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32; 390 self.inner.enable_update_dma(true);
420 let start_ch_index = starting_channel.index();
421 let end_ch_index = ending_channel.index();
422
423 assert!(start_ch_index <= end_ch_index);
424
425 let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
426 self.inner
427 .regs_gp16()
428 .dcr()
429 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
430 self.inner 391 self.inner
431 .regs_gp16() 392 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
432 .dcr() 393 .await;
433 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8)); 394 self.inner.enable_update_dma(false);
434
435 #[allow(clippy::let_unit_value)] // eg. stm32f334
436 let req = dma.request();
437
438 let original_update_dma_state = self.inner.get_update_dma_state();
439 if !original_update_dma_state {
440 self.inner.enable_update_dma(true);
441 }
442
443 unsafe {
444 #[cfg(not(any(bdma, gpdma)))]
445 use crate::dma::{Burst, FifoThreshold};
446 use crate::dma::{Transfer, TransferOptions};
447
448 let dma_transfer_option = TransferOptions {
449 #[cfg(not(any(bdma, gpdma)))]
450 fifo_threshold: Some(FifoThreshold::Full),
451 #[cfg(not(any(bdma, gpdma)))]
452 mburst: Burst::Incr4,
453 ..Default::default()
454 };
455
456 Transfer::new_write(
457 dma,
458 req,
459 duty,
460 self.inner.regs_gp16().dmar().as_ptr() as *mut u16,
461 dma_transfer_option,
462 )
463 .await
464 };
465
466 if !original_update_dma_state {
467 self.inner.enable_update_dma(false);
468 }
469 }
470}
471
472impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
473 /// Generate a sequence of PWM waveform
474 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
475 use crate::pac::timer::vals::Ccds;
476
477 #[allow(clippy::let_unit_value)] // eg. stm32f334
478 let req = dma.request();
479
480 let cc_channel = C::CHANNEL;
481
482 let original_duty_state = self.channel(cc_channel).current_duty_cycle();
483 let original_enable_state = self.channel(cc_channel).is_enabled();
484 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE;
485 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
486
487 // redirect CC DMA request onto Update Event
488 if !original_cc_dma_on_update {
489 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE)
490 }
491
492 if !original_cc_dma_enabled {
493 self.inner.set_cc_dma_enable_state(cc_channel, true);
494 }
495
496 if !original_enable_state {
497 self.channel(cc_channel).enable();
498 }
499
500 unsafe {
501 #[cfg(not(any(bdma, gpdma)))]
502 use crate::dma::{Burst, FifoThreshold};
503 use crate::dma::{Transfer, TransferOptions};
504
505 let dma_transfer_option = TransferOptions {
506 #[cfg(not(any(bdma, gpdma)))]
507 fifo_threshold: Some(FifoThreshold::Full),
508 #[cfg(not(any(bdma, gpdma)))]
509 mburst: Burst::Incr8,
510 ..Default::default()
511 };
512
513 match self.inner.bits() {
514 TimerBits::Bits16 => {
515 Transfer::new_write(
516 dma,
517 req,
518 duty,
519 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
520 dma_transfer_option,
521 )
522 .await
523 }
524 #[cfg(not(any(stm32l0)))]
525 TimerBits::Bits32 => {
526 #[cfg(not(any(bdma, gpdma)))]
527 panic!("unsupported timer bits");
528
529 #[cfg(any(bdma, gpdma))]
530 Transfer::new_write(
531 dma,
532 req,
533 duty,
534 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
535 dma_transfer_option,
536 )
537 .await
538 }
539 };
540 };
541
542 // restore output compare state
543 if !original_enable_state {
544 self.channel(cc_channel).disable();
545 }
546
547 self.channel(cc_channel).set_duty_cycle(original_duty_state);
548
549 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
550 // this can almost always trigger a DMA FIFO error.
551 //
552 // optional TODO:
553 // clean FEIF after disable UDE
554 if !original_cc_dma_enabled {
555 self.inner.set_cc_dma_enable_state(cc_channel, false);
556 }
557
558 if !original_cc_dma_on_update {
559 self.inner.set_cc_dma_selection(Ccds::ON_COMPARE)
560 }
561 } 395 }
562} 396}
563 397
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 69c3a740f..26d2b8991 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -87,7 +87,7 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
87 // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC) 87 // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC)
88 // indicates that all bytes are pushed out from the FIFO. 88 // indicates that all bytes are pushed out from the FIFO.
89 // 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.
90 if sr_val.tc() { 90 if sr_val.tc() && r.cr1().read().tcie() {
91 // For others it is cleared above with `clear_interrupt_flags`. 91 // For others it is cleared above with `clear_interrupt_flags`.
92 #[cfg(any(usart_v1, usart_v2))] 92 #[cfg(any(usart_v1, usart_v2))]
93 sr(r).modify(|w| w.set_tc(false)); 93 sr(r).modify(|w| w.set_tc(false));
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs
index a80a2692b..466e1a9b4 100644
--- a/embassy-stm32/src/xspi/mod.rs
+++ b/embassy-stm32/src/xspi/mod.rs
@@ -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