aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-12 13:14:15 -0600
committerxoviat <[email protected]>2025-11-12 13:14:15 -0600
commite32f78fde6f8130f1eb3effa131e42b7ca153ba6 (patch)
tree615ea29191266cd34dcf7bb7b259204e2a125abe
parent2d73fe88935bcc42452907b42a7de5a9fa5ab1f8 (diff)
stm32/adc: extract into common
add common low-level interface for adc
-rw-r--r--embassy-stm32/src/adc/adc4.rs110
-rw-r--r--embassy-stm32/src/adc/g4.rs459
-rw-r--r--embassy-stm32/src/adc/injected.rs2
-rw-r--r--embassy-stm32/src/adc/mod.rs173
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs2
-rw-r--r--embassy-stm32/src/adc/v2.rs233
-rw-r--r--embassy-stm32/src/adc/v3.rs738
-rw-r--r--embassy-stm32/src/adc/v4.rs327
-rw-r--r--examples/stm32f4/src/bin/adc.rs2
-rw-r--r--examples/stm32f4/src/bin/adc_dma.rs8
-rw-r--r--examples/stm32g0/src/bin/adc_oversampling.rs14
-rw-r--r--examples/stm32g4/src/bin/adc.rs4
-rw-r--r--examples/stm32g4/src/bin/adc_differential.rs2
-rw-r--r--examples/stm32g4/src/bin/adc_dma.rs2
-rw-r--r--examples/stm32g4/src/bin/adc_injected_and_regular.rs2
-rw-r--r--examples/stm32g4/src/bin/adc_oversampling.rs13
-rw-r--r--examples/stm32l4/src/bin/adc.rs9
-rw-r--r--examples/stm32l4/src/bin/adc_dma.rs5
-rw-r--r--examples/stm32u0/src/bin/adc.rs7
-rw-r--r--examples/stm32u5/src/bin/adc.rs16
20 files changed, 869 insertions, 1259 deletions
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index befa8ed4a..04d976513 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -4,7 +4,7 @@ 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::{AdcChannel, AnyAdcChannel, RxDma4, blocking_delay_us};
8use crate::dma::Transfer; 8use crate::dma::Transfer;
9#[cfg(stm32u5)] 9#[cfg(stm32u5)]
10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; 10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr;
@@ -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)]
@@ -214,20 +182,6 @@ impl<'d, T: Instance> Adc4<'d, T> {
214 ); 182 );
215 } 183 }
216 184
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| { 185 T::regs().isr().modify(|w| {
232 w.set_ldordy(true); 186 w.set_ldordy(true);
233 }); 187 });
@@ -239,22 +193,15 @@ impl<'d, T: Instance> Adc4<'d, T> {
239 T::regs().isr().modify(|w| { 193 T::regs().isr().modify(|w| {
240 w.set_ldordy(true); 194 w.set_ldordy(true);
241 }); 195 });
242 }
243 196
244 fn calibrate(&mut self) {
245 T::regs().cr().modify(|w| w.set_adcal(true)); 197 T::regs().cr().modify(|w| w.set_adcal(true));
246 while T::regs().cr().read().adcal() {} 198 while T::regs().cr().read().adcal() {}
247 T::regs().isr().modify(|w| w.set_eocal(true)); 199 T::regs().isr().modify(|w| w.set_eocal(true));
248 }
249 200
250 fn enable(&mut self) { 201 blocking_delay_us(1);
251 T::regs().isr().write(|w| w.set_adrdy(true)); 202
252 T::regs().cr().modify(|w| w.set_aden(true)); 203 Self::enable();
253 while !T::regs().isr().read().adrdy() {}
254 T::regs().isr().write(|w| w.set_adrdy(true));
255 }
256 204
257 fn configure(&mut self) {
258 // single conversion mode, software trigger 205 // single conversion mode, software trigger
259 T::regs().cfgr1().modify(|w| { 206 T::regs().cfgr1().modify(|w| {
260 #[cfg(stm32u5)] 207 #[cfg(stm32u5)]
@@ -280,51 +227,60 @@ impl<'d, T: Instance> Adc4<'d, T> {
280 w.set_smpsel(i, Smpsel::SMP1); 227 w.set_smpsel(i, Smpsel::SMP1);
281 } 228 }
282 }); 229 });
230
231 Self { adc }
232 }
233
234 fn enable() {
235 T::regs().isr().write(|w| w.set_adrdy(true));
236 T::regs().cr().modify(|w| w.set_aden(true));
237 while !T::regs().isr().read().adrdy() {}
238 T::regs().isr().write(|w| w.set_adrdy(true));
283 } 239 }
284 240
285 /// Enable reading the voltage reference internal channel. 241 /// Enable reading the voltage reference internal channel.
286 pub fn enable_vrefint(&self) -> VrefInt { 242 pub fn enable_vrefint(&self) -> super::VrefInt {
287 T::regs().ccr().modify(|w| { 243 T::regs().ccr().modify(|w| {
288 w.set_vrefen(true); 244 w.set_vrefen(true);
289 }); 245 });
290 246
291 VrefInt {} 247 super::VrefInt {}
292 } 248 }
293 249
294 /// Enable reading the temperature internal channel. 250 /// Enable reading the temperature internal channel.
295 pub fn enable_temperature(&self) -> Temperature { 251 pub fn enable_temperature(&self) -> super::Temperature {
296 T::regs().ccr().modify(|w| { 252 T::regs().ccr().modify(|w| {
297 w.set_vsensesel(true); 253 w.set_vsensesel(true);
298 }); 254 });
299 255
300 Temperature {} 256 super::Temperature {}
301 } 257 }
302 258
303 /// Enable reading the vbat internal channel. 259 /// Enable reading the vbat internal channel.
304 #[cfg(stm32u5)] 260 #[cfg(stm32u5)]
305 pub fn enable_vbat(&self) -> Vbat { 261 pub fn enable_vbat(&self) -> super::Vbat {
306 T::regs().ccr().modify(|w| { 262 T::regs().ccr().modify(|w| {
307 w.set_vbaten(true); 263 w.set_vbaten(true);
308 }); 264 });
309 265
310 Vbat {} 266 super::Vbat {}
311 } 267 }
312 268
313 /// Enable reading the vbat internal channel. 269 /// Enable reading the vbat internal channel.
314 pub fn enable_vcore(&self) -> Vcore { 270 pub fn enable_vcore(&self) -> super::Vcore {
315 Vcore {} 271 super::Vcore {}
316 } 272 }
317 273
318 /// Enable reading the vbat internal channel. 274 /// Enable reading the vbat internal channel.
319 #[cfg(stm32u5)] 275 #[cfg(stm32u5)]
320 pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { 276 pub fn enable_dac_channel(&self, dac: DacChannel) -> super::Dac {
321 let mux; 277 let mux;
322 match dac { 278 match dac {
323 DacChannel::OUT1 => mux = false, 279 DacChannel::OUT1 => mux = false,
324 DacChannel::OUT2 => mux = true, 280 DacChannel::OUT2 => mux = true,
325 } 281 }
326 T::regs().or().modify(|w| w.set_chn21sel(mux)); 282 T::regs().or().modify(|w| w.set_chn21sel(mux));
327 Dac {} 283 super::Dac {}
328 } 284 }
329 285
330 /// Set the ADC resolution. 286 /// Set the ADC resolution.
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 6430b0243..0a9f35a5b 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,5 +1,3 @@
1use core::mem;
2
3#[allow(unused)] 1#[allow(unused)]
4#[cfg(stm32h7)] 2#[cfg(stm32h7)]
5use pac::adc::vals::{Adcaldif, Difsel, Exten}; 3use pac::adc::vals::{Adcaldif, Difsel, Exten};
@@ -10,15 +8,14 @@ pub use pac::adccommon::vals::Presc;
10pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; 8pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
11pub use stm32_metapac::adccommon::vals::Dual; 9pub use stm32_metapac::adccommon::vals::Dual;
12 10
13use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us}; 11use super::{
12 Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime,
13 blocking_delay_us,
14};
14use crate::adc::SealedAdcChannel; 15use 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
@@ -103,6 +100,19 @@ impl Prescaler {
103 } 100 }
104} 101}
105 102
103/// ADC configuration
104#[derive(Default)]
105pub struct AdcConfig {
106 pub dual_mode: Option<Dual>,
107 pub resolution: Option<Resolution>,
108 #[cfg(stm32g4)]
109 pub oversampling_shift: Option<u8>,
110 #[cfg(stm32g4)]
111 pub oversampling_ratio: Option<u8>,
112 #[cfg(stm32g4)]
113 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
114}
115
106// Trigger source for ADC conversions¨ 116// Trigger source for ADC conversions¨
107#[derive(Copy, Clone)] 117#[derive(Copy, Clone)]
108pub struct ConversionTrigger { 118pub struct ConversionTrigger {
@@ -112,18 +122,9 @@ pub struct ConversionTrigger {
112 pub edge: Exten, 122 pub edge: Exten,
113} 123}
114 124
115// Conversion mode for regular ADC channels
116#[derive(Copy, Clone)]
117pub enum RegularConversionMode {
118 // Samples as fast as possible
119 Continuous,
120 // Sample at rate determined by external trigger
121 Triggered(ConversionTrigger),
122}
123
124impl<'d, T: Instance> Adc<'d, T> { 125impl<'d, T: Instance> Adc<'d, T> {
125 /// Create a new ADC driver. 126 /// Create a new ADC driver.
126 pub fn new(adc: Peri<'d, T>) -> Self { 127 pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self {
127 rcc::enable_and_reset::<T>(); 128 rcc::enable_and_reset::<T>();
128 129
129 let prescaler = Prescaler::from_ker_ck(T::frequency()); 130 let prescaler = Prescaler::from_ker_ck(T::frequency());
@@ -181,10 +182,38 @@ impl<'d, T: Instance> Adc<'d, T> {
181 w.set_exten(Exten::DISABLED); 182 w.set_exten(Exten::DISABLED);
182 }); 183 });
183 184
185 if let Some(dual) = config.dual_mode {
186 T::common_regs().ccr().modify(|reg| {
187 reg.set_dual(dual);
188 })
189 }
190
191 if let Some(resolution) = config.resolution {
192 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
193 }
194
195 #[cfg(stm32g4)]
196 if let Some(shift) = config.oversampling_shift {
197 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
198 }
199
200 #[cfg(stm32g4)]
201 if let Some(ratio) = config.oversampling_ratio {
202 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
203 }
204
205 #[cfg(stm32g4)]
206 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
207 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
208 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
209 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
210 }
211
184 Self { adc } 212 Self { adc }
185 } 213 }
186 214
187 fn enable() { 215 /// Enable the ADC
216 pub(super) fn enable() {
188 // Make sure bits are off 217 // Make sure bits are off
189 while T::regs().cr().read().addis() { 218 while T::regs().cr().read().addis() {
190 // spin 219 // spin
@@ -205,82 +234,33 @@ impl<'d, T: Instance> Adc<'d, T> {
205 } 234 }
206 } 235 }
207 236
208 /// Enable reading the voltage reference internal channel. 237 /// Start regular adc conversion
209 pub fn enable_vrefint(&self) -> super::VrefInt 238 pub(super) fn start() {
210 where 239 T::regs().cr().modify(|reg| {
211 T: super::SpecialConverter<super::VrefInt>, 240 reg.set_adstart(true);
212 {
213 T::common_regs().ccr().modify(|reg| {
214 reg.set_vrefen(true);
215 }); 241 });
216
217 super::VrefInt {}
218 } 242 }
219 243
220 /// Enable reading the temperature internal channel. 244 /// Stop regular conversions and disable DMA
221 pub fn enable_temperature(&self) -> super::Temperature 245 pub(super) fn stop() {
222 where 246 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
223 T: super::SpecialConverter<super::Temperature>, 247 T::regs().cr().modify(|reg| {
224 { 248 reg.set_adstp(Adstp::STOP);
225 T::common_regs().ccr().modify(|reg| { 249 });
226 reg.set_vsenseen(true); 250 // The software must poll ADSTART until the bit is reset before assuming the
227 }); 251 // ADC is completely stopped
228 252 while T::regs().cr().read().adstart() {}
229 super::Temperature {} 253 }
230 }
231 254
232 /// Enable reading the vbat internal channel. 255 // Disable dma control and continuous conversion, if enabled
233 pub fn enable_vbat(&self) -> super::Vbat 256 T::regs().cfgr().modify(|reg| {
234 where 257 reg.set_cont(false);
235 T: super::SpecialConverter<super::Vbat>, 258 reg.set_dmaen(Dmaen::DISABLE);
236 {
237 T::common_regs().ccr().modify(|reg| {
238 reg.set_vbaten(true);
239 }); 259 });
240
241 super::Vbat {}
242 }
243
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"
265 // #[cfg(stm32g4)]
266 // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) {
267 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
268 // }
269
270 // #[cfg(stm32g4)]
271 // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) {
272 // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored),
273 // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
274 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
275 // }
276
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 } 260 }
281 261
282 /// Perform a single conversion. 262 /// Perform a single conversion.
283 fn convert(&mut self) -> u16 { 263 pub(super) fn convert() -> u16 {
284 T::regs().isr().modify(|reg| { 264 T::regs().isr().modify(|reg| {
285 reg.set_eos(true); 265 reg.set_eos(true);
286 reg.set_eoc(true); 266 reg.set_eoc(true);
@@ -298,136 +278,42 @@ impl<'d, T: Instance> Adc<'d, T> {
298 T::regs().dr().read().0 as u16 278 T::regs().dr().read().0 as u16
299 } 279 }
300 280
301 /// Read an ADC pin. 281 pub(super) fn configure_dma(conversion_mode: ConversionMode) {
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| { 282 T::regs().isr().modify(|reg| {
395 reg.set_ovr(true); 283 reg.set_ovr(true);
396 }); 284 });
397 285
398 T::regs().cfgr().modify(|reg| { 286 T::regs().cfgr().modify(|reg| {
399 reg.set_discen(false); 287 reg.set_discen(false); // Convert all channels for each trigger
400 reg.set_cont(true); 288 reg.set_dmacfg(match conversion_mode {
401 reg.set_dmacfg(Dmacfg::ONE_SHOT); 289 ConversionMode::Singular => Dmacfg::ONE_SHOT,
290 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
291 });
402 reg.set_dmaen(Dmaen::ENABLE); 292 reg.set_dmaen(Dmaen::ENABLE);
403 }); 293 });
404 294
405 let request = rx_dma.request(); 295 if let ConversionMode::Repeated(mode) = conversion_mode {
406 let transfer = unsafe { 296 match mode {
407 Transfer::new_read( 297 RegularConversionMode::Continuous => {
408 rx_dma, 298 T::regs().cfgr().modify(|reg| {
409 request, 299 reg.set_cont(true);
410 T::regs().dr().as_ptr() as *mut u16, 300 });
411 readings, 301 }
412 Default::default(), 302 RegularConversionMode::Triggered(trigger) => {
413 ) 303 T::regs().cfgr().modify(|r| {
414 }; 304 r.set_cont(false); // New trigger is neede for each sample to be read
415 305 });
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 306
424 // Ensure conversions are finished. 307 T::regs().cfgr().modify(|r| {
425 Self::stop_regular_conversions(); 308 r.set_extsel(trigger.channel);
309 r.set_exten(trigger.edge);
310 });
426 311
427 // Reset configuration. 312 // Regular conversions uses DMA so no need to generate interrupt
428 T::regs().cfgr().modify(|reg| { 313 T::regs().ier().modify(|r| r.set_eosie(false));
429 reg.set_cont(false); 314 }
430 }); 315 }
316 }
431 } 317 }
432 318
433 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { 319 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
@@ -489,95 +375,54 @@ impl<'d, T: Instance> Adc<'d, T> {
489 } 375 }
490 } 376 }
491 377
492 /// Set external trigger for regular conversion sequence 378 /// Enable reading the voltage reference internal channel.
493 fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) { 379 pub fn enable_vrefint(&self) -> super::VrefInt
494 T::regs().cfgr().modify(|r| { 380 where
495 r.set_extsel(trigger.channel); 381 T: super::SpecialConverter<super::VrefInt>,
496 r.set_exten(trigger.edge); 382 {
383 T::common_regs().ccr().modify(|reg| {
384 reg.set_vrefen(true);
497 }); 385 });
498 // Regular conversions uses DMA so no need to generate interrupt
499 T::regs().ier().modify(|r| r.set_eosie(false));
500 }
501 386
502 // Dual ADC mode selection 387 super::VrefInt {}
503 pub fn configure_dual_mode(&mut self, val: Dual) {
504 T::common_regs().ccr().modify(|reg| {
505 reg.set_dual(val);
506 })
507 } 388 }
508 389
509 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. 390 /// Enable reading the temperature internal channel.
510 /// 391 pub fn enable_temperature(&self) -> super::Temperature
511 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer 392 where
512 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended 393 T: super::SpecialConverter<super::Temperature>,
513 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half 394 {
514 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively 395 T::common_regs().ccr().modify(|reg| {
515 /// defines the period at which the buffer should be read. 396 reg.set_vsenseen(true);
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 }); 397 });
556 398
557 T::regs().cfgr().modify(|reg| { 399 super::Temperature {}
558 reg.set_discen(false); // Convert all channels for each trigger 400 }
559 reg.set_dmacfg(Dmacfg::CIRCULAR); 401
560 reg.set_dmaen(Dmaen::ENABLE); 402 /// Enable reading the vbat internal channel.
403 pub fn enable_vbat(&self) -> super::Vbat
404 where
405 T: super::SpecialConverter<super::Vbat>,
406 {
407 T::common_regs().ccr().modify(|reg| {
408 reg.set_vbaten(true);
561 }); 409 });
562 410
563 match mode { 411 super::Vbat {}
564 RegularConversionMode::Continuous => { 412 }
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 413
577 mem::forget(self); 414 // Reads that are not implemented as INJECTED in "blocking_read"
415 // #[cfg(stm32g4)]
416 // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) {
417 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
418 // }
578 419
579 RingBufferedAdc::new(dma, dma_buf) 420 // #[cfg(stm32g4)]
580 } 421 // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) {
422 // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored),
423 // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
424 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
425 // }
581 426
582 /// Configures the ADC for injected conversions. 427 /// Configures the ADC for injected conversions.
583 /// 428 ///
@@ -607,7 +452,7 @@ impl<'d, T: Instance> Adc<'d, T> {
607 /// - Accessing samples beyond `N` will result in a panic; use the returned type 452 /// - Accessing samples beyond `N` will result in a panic; use the returned type
608 /// `InjectedAdc<T, N>` to enforce bounds at compile time. 453 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
609 pub fn setup_injected_conversions<'a, const N: usize>( 454 pub fn setup_injected_conversions<'a, const N: usize>(
610 mut self, 455 self,
611 sequence: [(AnyAdcChannel<T>, SampleTime); N], 456 sequence: [(AnyAdcChannel<T>, SampleTime); N],
612 trigger: ConversionTrigger, 457 trigger: ConversionTrigger,
613 interrupt: bool, 458 interrupt: bool,
@@ -619,7 +464,7 @@ impl<'d, T: Instance> Adc<'d, T> {
619 NR_INJECTED_RANKS 464 NR_INJECTED_RANKS
620 ); 465 );
621 466
622 Self::stop_regular_conversions(); 467 Self::stop();
623 Self::enable(); 468 Self::enable();
624 469
625 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); 470 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
@@ -649,8 +494,16 @@ impl<'d, T: Instance> Adc<'d, T> {
649 494
650 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false)); 495 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
651 496
652 self.set_injected_conversion_trigger(trigger); 497 // Set external trigger for injected conversion sequence
653 self.enable_injected_eos_interrupt(interrupt); 498 // Possible trigger values are seen in Table 167 in RM0440 Rev 9
499 T::regs().jsqr().modify(|r| {
500 r.set_jextsel(trigger.channel);
501 r.set_jexten(trigger.edge);
502 });
503
504 // Enable end of injected sequence interrupt
505 T::regs().ier().modify(|r| r.set_jeosie(interrupt));
506
654 Self::start_injected_conversions(); 507 Self::start_injected_conversions();
655 508
656 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels 509 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
@@ -688,7 +541,7 @@ impl<'d, T: Instance> Adc<'d, T> {
688 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N], 541 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N],
689 injected_trigger: ConversionTrigger, 542 injected_trigger: ConversionTrigger,
690 injected_interrupt: bool, 543 injected_interrupt: bool,
691 ) -> (RingBufferedAdc<'a, T>, InjectedAdc<T, N>) { 544 ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<T, N>) {
692 unsafe { 545 unsafe {
693 ( 546 (
694 Self { 547 Self {
@@ -721,32 +574,6 @@ impl<'d, T: Instance> Adc<'d, T> {
721 reg.set_jadstart(true); 574 reg.set_jadstart(true);
722 }); 575 });
723 } 576 }
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} 577}
751 578
752impl<T: Instance, const N: usize> InjectedAdc<T, N> { 579impl<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..7bb3a541c 100644
--- a/embassy-stm32/src/adc/injected.rs
+++ b/embassy-stm32/src/adc/injected.rs
@@ -38,7 +38,7 @@ impl<T: Instance, const N: usize> InjectedAdc<T, N> {
38 38
39impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> { 39impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> {
40 fn drop(&mut self) { 40 fn drop(&mut self) {
41 Adc::<T>::teardown_dma(); 41 Adc::<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..bf404d6ef 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,6 +28,8 @@ 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"]
@@ -105,6 +110,166 @@ pub(crate) fn blocking_delay_us(us: u32) {
105 } 110 }
106} 111}
107 112
113#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
114pub(self) enum ConversionMode {
115 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
116 Singular,
117 #[allow(dead_code)]
118 Repeated(RegularConversionMode),
119}
120
121#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
122// Conversion mode for regular ADC channels
123#[derive(Copy, Clone)]
124pub enum RegularConversionMode {
125 // Samples as fast as possible
126 Continuous,
127 #[cfg(adc_g4)]
128 // Sample at rate determined by external trigger
129 Triggered(ConversionTrigger),
130}
131
132impl<'d, T: Instance> Adc<'d, T> {
133 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4))]
134 /// Read an ADC pin.
135 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
136 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
137 channel.setup();
138
139 #[cfg(not(adc_v4))]
140 Self::enable();
141 Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
142
143 Self::convert()
144 }
145
146 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
147 /// Read one or multiple ADC regular channels using DMA.
148 ///
149 /// `sequence` iterator and `readings` must have the same length.
150 ///
151 /// Example
152 /// ```rust,ignore
153 /// use embassy_stm32::adc::{Adc, AdcChannel}
154 ///
155 /// let mut adc = Adc::new(p.ADC1);
156 /// let mut adc_pin0 = p.PA0.into();
157 /// let mut adc_pin1 = p.PA1.into();
158 /// let mut measurements = [0u16; 2];
159 ///
160 /// adc.read(
161 /// p.DMA1_CH2.reborrow(),
162 /// [
163 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
164 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
165 /// ]
166 /// .into_iter(),
167 /// &mut measurements,
168 /// )
169 /// .await;
170 /// defmt::info!("measurements: {}", measurements);
171 /// ```
172 ///
173 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
174 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
175 pub async fn read(
176 &mut self,
177 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
178 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
179 readings: &mut [u16],
180 ) {
181 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
182 assert!(
183 sequence.len() == readings.len(),
184 "Sequence length must be equal to readings length"
185 );
186 assert!(
187 sequence.len() <= 16,
188 "Asynchronous read sequence cannot be more than 16 in length"
189 );
190
191 // Ensure no conversions are ongoing and ADC is enabled.
192 Self::stop();
193 Self::enable();
194
195 Self::configure_sequence(
196 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
197 );
198
199 Self::configure_dma(ConversionMode::Singular);
200
201 let request = rx_dma.request();
202 let transfer = unsafe {
203 crate::dma::Transfer::new_read(
204 rx_dma,
205 request,
206 T::regs().dr().as_ptr() as *mut u16,
207 readings,
208 Default::default(),
209 )
210 };
211
212 Self::start();
213
214 // Wait for conversion sequence to finish.
215 transfer.await;
216
217 // Ensure conversions are finished.
218 Self::stop();
219 }
220
221 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
222 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
223 ///
224 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
225 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
226 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
227 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
228 /// defines the period at which the buffer should be read.
229 ///
230 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
231 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
232 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
233 /// the buffer length should be `3 * 40 = 120`.
234 ///
235 /// # Parameters
236 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
237 /// - `dma_buf`: The buffer where DMA stores ADC samples.
238 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
239 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
240 ///
241 /// # Returns
242 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
243 pub fn into_ring_buffered<'a>(
244 self,
245 dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>,
246 dma_buf: &'a mut [u16],
247 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
248 mode: RegularConversionMode,
249 ) -> RingBufferedAdc<'a, T> {
250 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
251 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
252 assert!(
253 sequence.len() <= 16,
254 "Asynchronous read sequence cannot be more than 16 in length"
255 );
256 // reset conversions and enable the adc
257 Self::stop();
258 Self::enable();
259
260 //adc side setup
261 Self::configure_sequence(
262 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
263 );
264
265 Self::configure_dma(ConversionMode::Repeated(mode));
266
267 core::mem::forget(self);
268
269 RingBufferedAdc::new(dma, dma_buf)
270 }
271}
272
108pub(self) trait SpecialChannel {} 273pub(self) trait SpecialChannel {}
109 274
110/// Implemented for ADCs that have a special channel 275/// Implemented for ADCs that have a special channel
@@ -143,6 +308,14 @@ impl SpecialChannel for Temperature {}
143pub struct Vbat; 308pub struct Vbat;
144impl SpecialChannel for Vbat {} 309impl SpecialChannel for Vbat {}
145 310
311/// Vcore channel.
312pub struct Vcore;
313impl SpecialChannel for Vcore {}
314
315/// Internal dac channel.
316pub struct Dac;
317impl SpecialChannel for Dac {}
318
146/// ADC instance. 319/// ADC instance.
147#[cfg(not(any( 320#[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, 321 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,
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs
index 024c6acdc..62ea0d3a2 100644
--- a/embassy-stm32/src/adc/ringbuffered.rs
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -172,7 +172,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
172 172
173impl<T: Instance> Drop for RingBufferedAdc<'_, T> { 173impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
174 fn drop(&mut self) { 174 fn drop(&mut self) {
175 Adc::<T>::teardown_dma(); 175 Adc::<T>::stop();
176 176
177 compiler_fence(Ordering::SeqCst); 177 compiler_fence(Ordering::SeqCst);
178 178
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index efa1cc68c..2f9fabafb 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,15 +1,11 @@
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;
7use crate::time::Hertz; 6use crate::time::Hertz;
8use crate::{Peri, rcc}; 7use crate::{Peri, rcc};
9 8
10mod ringbuffered;
11pub use ringbuffered::RingBufferedAdc;
12
13fn clear_interrupt_flags(r: crate::pac::adc::Adc) { 9fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
14 r.sr().modify(|regs| { 10 r.sr().modify(|regs| {
15 regs.set_eoc(false); 11 regs.set_eoc(false);
@@ -89,11 +85,21 @@ impl Prescaler {
89 } 85 }
90} 86}
91 87
88/// ADC configuration
89#[derive(Default)]
90pub struct AdcConfig {
91 resolution: Option<Resolution>,
92}
93
92impl<'d, T> Adc<'d, T> 94impl<'d, T> Adc<'d, T>
93where 95where
94 T: Instance, 96 T: Instance,
95{ 97{
96 pub fn new(adc: Peri<'d, T>) -> Self { 98 pub fn new(adc: Peri<'d, T>) -> Self {
99 Self::new_with_config(adc, Default::default())
100 }
101
102 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
97 rcc::enable_and_reset::<T>(); 103 rcc::enable_and_reset::<T>();
98 104
99 let presc = Prescaler::from_pclk2(T::frequency()); 105 let presc = Prescaler::from_pclk2(T::frequency());
@@ -104,84 +110,14 @@ where
104 110
105 blocking_delay_us(3); 111 blocking_delay_us(3);
106 112
107 Self { adc } 113 if let Some(resolution) = config.resolution {
108 } 114 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
109 115 }
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 116
173 Temperature {} 117 Self { adc }
174 } 118 }
175 119
176 /// Enables vbat input and returns [Vbat], which can be used in 120 pub(super) fn enable() {}
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 }
185 121
186 pub(super) fn start() { 122 pub(super) fn start() {
187 // Begin ADC conversions 123 // Begin ADC conversions
@@ -192,18 +128,31 @@ where
192 } 128 }
193 129
194 pub(super) fn stop() { 130 pub(super) fn stop() {
131 let r = T::regs();
132
195 // Stop ADC 133 // Stop ADC
196 T::regs().cr2().modify(|reg| { 134 r.cr2().modify(|reg| {
197 // Stop ADC 135 // Stop ADC
198 reg.set_swstart(false); 136 reg.set_swstart(false);
137 // Stop ADC
138 reg.set_adon(false);
139 // Stop DMA
140 reg.set_dma(false);
199 }); 141 });
200 }
201 142
202 pub fn set_resolution(&mut self, resolution: Resolution) { 143 r.cr1().modify(|w| {
203 T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); 144 // Disable interrupt for end of conversion
145 w.set_eocie(false);
146 // Disable interrupt for overrun
147 w.set_ovrie(false);
148 });
149
150 clear_interrupt_flags(r);
151
152 compiler_fence(Ordering::SeqCst);
204 } 153 }
205 154
206 pub(super) fn blocking_convert() -> u16 { 155 pub(super) fn convert() -> u16 {
207 // clear end of conversion flag 156 // clear end of conversion flag
208 T::regs().sr().modify(|reg| { 157 T::regs().sr().modify(|reg| {
209 reg.set_eoc(false); 158 reg.set_eoc(false);
@@ -224,7 +173,44 @@ where
224 T::regs().dr().read().0 as u16 173 T::regs().dr().read().0 as u16
225 } 174 }
226 175
227 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) { 176 pub(super) fn configure_dma(conversion_mode: ConversionMode) {
177 match conversion_mode {
178 ConversionMode::Repeated(_) => {
179 let r = T::regs();
180
181 // Clear all interrupts
182 r.sr().modify(|regs| {
183 regs.set_eoc(false);
184 regs.set_ovr(false);
185 regs.set_strt(false);
186 });
187
188 r.cr1().modify(|w| {
189 // Enable interrupt for end of conversion
190 w.set_eocie(true);
191 // Enable interrupt for overrun
192 w.set_ovrie(true);
193 // Scanning converisons of multiple channels
194 w.set_scan(true);
195 // Continuous conversion mode
196 w.set_discen(false);
197 });
198
199 r.cr2().modify(|w| {
200 // Enable DMA mode
201 w.set_dma(true);
202 // Enable continuous conversions
203 w.set_cont(true);
204 // DMA requests are issues as long as DMA=1 and data are converted.
205 w.set_dds(vals::Dds::CONTINUOUS);
206 // EOC flag is set at the end of each conversion.
207 w.set_eocs(vals::Eocs::EACH_CONVERSION);
208 });
209 }
210 }
211 }
212
213 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
228 T::regs().cr2().modify(|reg| { 214 T::regs().cr2().modify(|reg| {
229 reg.set_adon(true); 215 reg.set_adon(true);
230 }); 216 });
@@ -234,7 +220,7 @@ where
234 r.set_l((sequence.len() - 1).try_into().unwrap()); 220 r.set_l((sequence.len() - 1).try_into().unwrap());
235 }); 221 });
236 222
237 for (i, (ch, sample_time)) in sequence.enumerate() { 223 for (i, ((ch, _), sample_time)) in sequence.enumerate() {
238 // Set the channel in the right sequence field. 224 // Set the channel in the right sequence field.
239 T::regs().sqr3().modify(|w| w.set_sq(i, ch)); 225 T::regs().sqr3().modify(|w| w.set_sq(i, ch));
240 226
@@ -247,62 +233,37 @@ where
247 } 233 }
248 } 234 }
249 235
250 pub(super) fn setup_dma() { 236 /// Enables internal voltage reference and returns [VrefInt], which can be used in
251 let r = T::regs(); 237 /// [Adc::read_internal()] to perform conversion.
252 238 pub fn enable_vrefint(&self) -> VrefInt {
253 // Clear all interrupts 239 T::common_regs().ccr().modify(|reg| {
254 r.sr().modify(|regs| { 240 reg.set_tsvrefe(true);
255 regs.set_eoc(false);
256 regs.set_ovr(false);
257 regs.set_strt(false);
258 });
259
260 r.cr1().modify(|w| {
261 // Enable interrupt for end of conversion
262 w.set_eocie(true);
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 }); 241 });
270 242
271 r.cr2().modify(|w| { 243 VrefInt {}
272 // Enable DMA mode
273 w.set_dma(true);
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 } 244 }
282 245
283 pub(super) fn teardown_dma() { 246 /// Enables internal temperature sensor and returns [Temperature], which can be used in
284 let r = T::regs(); 247 /// [Adc::read_internal()] to perform conversion.
285 248 ///
286 // Stop ADC 249 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
287 r.cr2().modify(|reg| { 250 /// temperature sensor will return vbat value.
288 // Stop ADC 251 pub fn enable_temperature(&self) -> Temperature {
289 reg.set_swstart(false); 252 T::common_regs().ccr().modify(|reg| {
290 // Stop ADC 253 reg.set_tsvrefe(true);
291 reg.set_adon(false);
292 // Stop DMA
293 reg.set_dma(false);
294 }); 254 });
295 255
296 r.cr1().modify(|w| { 256 Temperature {}
297 // Disable interrupt for end of conversion 257 }
298 w.set_eocie(false);
299 // Disable interrupt for overrun
300 w.set_ovrie(false);
301 });
302 258
303 clear_interrupt_flags(r); 259 /// Enables vbat input and returns [Vbat], which can be used in
260 /// [Adc::read_internal()] to perform conversion.
261 pub fn enable_vbat(&self) -> Vbat {
262 T::common_regs().ccr().modify(|reg| {
263 reg.set_vbate(true);
264 });
304 265
305 compiler_fence(Ordering::SeqCst); 266 Vbat {}
306 } 267 }
307} 268}
308 269
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index cbc217545..62b5043ee 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, 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.
@@ -89,7 +79,7 @@ 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 6
@@ -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
@@ -145,6 +135,32 @@ pub enum Clock {
145 135
146}} 136}}
147 137
138#[cfg(adc_u0)]
139type Ovss = u8;
140#[cfg(adc_u0)]
141type Ovsr = u8;
142#[cfg(adc_v3)]
143type Ovss = OversamplingShift;
144#[cfg(adc_v3)]
145type Ovsr = OversamplingRatio;
146
147/// Adc configuration
148#[derive(Default)]
149pub struct AdcConfig {
150 #[cfg(any(adc_u0, adc_g0, adc_v3))]
151 pub oversampling_shift: Option<Ovss>,
152 #[cfg(any(adc_u0, adc_g0, adc_v3))]
153 pub oversampling_ratio: Option<Ovsr>,
154 #[cfg(any(adc_u0, adc_g0))]
155 pub oversampling_enable: Option<bool>,
156 #[cfg(adc_v3)]
157 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
158 #[cfg(adc_g0)]
159 pub clock: Option<Clock>,
160 pub resolution: Option<Resolution>,
161 pub averaging: Option<Averaging>,
162}
163
148impl<'d, T: Instance> Adc<'d, T> { 164impl<'d, T: Instance> Adc<'d, T> {
149 /// Enable the voltage regulator 165 /// Enable the voltage regulator
150 fn init_regulator() { 166 fn init_regulator() {
@@ -178,38 +194,6 @@ impl<'d, T: Instance> Adc<'d, T> {
178 blocking_delay_us(1); 194 blocking_delay_us(1);
179 } 195 }
180 196
181 #[cfg(any(adc_v3, adc_g0, adc_u0))]
182 pub(super) fn start() {
183 // Start adc conversion
184 T::regs().cr().modify(|reg| {
185 reg.set_adstart(true);
186 });
187 }
188
189 #[cfg(any(adc_v3, adc_g0, adc_u0))]
190 pub(super) fn stop() {
191 // Stop adc conversion
192 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
193 T::regs().cr().modify(|reg| {
194 reg.set_adstp(true);
195 });
196 while T::regs().cr().read().adstart() {}
197 }
198 }
199
200 #[cfg(any(adc_v3, adc_g0, adc_u0))]
201 pub(super) fn teardown_dma() {
202 //disable dma control
203 #[cfg(not(any(adc_g0, adc_u0)))]
204 T::regs().cfgr().modify(|reg| {
205 reg.set_dmaen(false);
206 });
207 #[cfg(any(adc_g0, adc_u0))]
208 T::regs().cfgr1().modify(|reg| {
209 reg.set_dmaen(false);
210 });
211 }
212
213 /// Initialize the ADC leaving any analog clock at reset value. 197 /// Initialize the ADC leaving any analog clock at reset value.
214 /// For G0 and WL, this is the async clock without prescaler. 198 /// For G0 and WL, this is the async clock without prescaler.
215 pub fn new(adc: Peri<'d, T>) -> Self { 199 pub fn new(adc: Peri<'d, T>) -> Self {
@@ -218,6 +202,73 @@ impl<'d, T: Instance> Adc<'d, T> {
218 Self { adc } 202 Self { adc }
219 } 203 }
220 204
205 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
206 #[cfg(not(adc_g0))]
207 let s = Self::new(adc);
208
209 #[cfg(adc_g0)]
210 let s = match config.clock {
211 Some(clock) => Self::new_with_clock(adc, clock),
212 None => Self::new(adc),
213 };
214
215 #[cfg(any(adc_g0, adc_u0, adc_v3))]
216 if let Some(shift) = config.oversampling_shift {
217 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
218 }
219
220 #[cfg(any(adc_g0, adc_u0, adc_v3))]
221 if let Some(ratio) = config.oversampling_ratio {
222 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
223 }
224
225 #[cfg(any(adc_g0, adc_u0))]
226 if let Some(enable) = config.oversampling_enable {
227 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
228 }
229
230 #[cfg(adc_v3)]
231 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
232 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
233 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
234 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
235 }
236
237 if let Some(resolution) = config.resolution {
238 #[cfg(not(any(adc_g0, adc_u0)))]
239 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
240 #[cfg(any(adc_g0, adc_u0))]
241 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
242 }
243
244 if let Some(averaging) = config.averaging {
245 let (enable, samples, right_shift) = match averaging {
246 Averaging::Disabled => (false, 0, 0),
247 Averaging::Samples2 => (true, 0, 1),
248 Averaging::Samples4 => (true, 1, 2),
249 Averaging::Samples8 => (true, 2, 3),
250 Averaging::Samples16 => (true, 3, 4),
251 Averaging::Samples32 => (true, 4, 5),
252 Averaging::Samples64 => (true, 5, 6),
253 Averaging::Samples128 => (true, 6, 7),
254 Averaging::Samples256 => (true, 7, 8),
255 };
256 T::regs().cfgr2().modify(|reg| {
257 #[cfg(not(any(adc_g0, adc_u0)))]
258 reg.set_rovse(enable);
259 #[cfg(any(adc_g0, adc_u0))]
260 reg.set_ovse(enable);
261 #[cfg(any(adc_h5, adc_h7rs))]
262 reg.set_ovsr(samples.into());
263 #[cfg(not(any(adc_h5, adc_h7rs)))]
264 reg.set_ovsr(samples.into());
265 reg.set_ovss(right_shift.into());
266 })
267 }
268
269 s
270 }
271
221 #[cfg(adc_g0)] 272 #[cfg(adc_g0)]
222 /// Initialize ADC with explicit clock for the analog ADC 273 /// Initialize ADC with explicit clock for the analog ADC
223 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { 274 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self {
@@ -255,7 +306,7 @@ impl<'d, T: Instance> Adc<'d, T> {
255 } 306 }
256 307
257 // Enable ADC only when it is not already running. 308 // Enable ADC only when it is not already running.
258 fn enable(&mut self) { 309 pub(super) fn enable() {
259 // Make sure bits are off 310 // Make sure bits are off
260 while T::regs().cr().read().addis() { 311 while T::regs().cr().read().addis() {
261 // spin 312 // spin
@@ -276,258 +327,75 @@ impl<'d, T: Instance> Adc<'d, T> {
276 } 327 }
277 } 328 }
278 329
279 pub fn enable_vrefint(&self) -> VrefInt { 330 pub(super) fn start() {
280 #[cfg(not(any(adc_g0, adc_u0)))] 331 #[cfg(any(adc_v3, adc_g0, adc_u0))]
281 T::common_regs().ccr().modify(|reg| { 332 {
282 reg.set_vrefen(true); 333 // Start adc conversion
283 }); 334 T::regs().cr().modify(|reg| {
284 #[cfg(any(adc_g0, adc_u0))] 335 reg.set_adstart(true);
285 T::regs().ccr().modify(|reg| { 336 });
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 } 337 }
312
313 Temperature {}
314 } 338 }
315 339
316 pub fn enable_vbat(&self) -> Vbat { 340 pub(super) fn stop() {
317 cfg_if! { 341 #[cfg(any(adc_v3, adc_g0, adc_u0))]
318 if #[cfg(any(adc_g0, adc_u0))] { 342 {
319 T::regs().ccr().modify(|reg| { 343 // Ensure conversions are finished.
320 reg.set_vbaten(true); 344 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
321 }); 345 T::regs().cr().modify(|reg| {
322 } else if #[cfg(any(adc_h5, adc_h7rs))] { 346 reg.set_adstp(true);
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 }); 347 });
348 while T::regs().cr().read().adstart() {}
330 } 349 }
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 350
344 pub fn set_averaging(&mut self, averaging: Averaging) { 351 // Reset configuration.
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)))] 352 #[cfg(not(any(adc_g0, adc_u0)))]
358 reg.set_rovse(enable); 353 T::regs().cfgr().modify(|reg| {
354 reg.set_cont(false);
355 reg.set_dmaen(false);
356 });
359 #[cfg(any(adc_g0, adc_u0))] 357 #[cfg(any(adc_g0, adc_u0))]
360 reg.set_ovse(enable); 358 T::regs().cfgr1().modify(|reg| {
361 #[cfg(any(adc_h5, adc_h7rs))] 359 reg.set_cont(false);
362 reg.set_ovsr(samples.into()); 360 reg.set_dmaen(false);
363 #[cfg(not(any(adc_h5, adc_h7rs)))] 361 });
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 }
375 */
376
377 /// Perform a single conversion.
378 fn convert(&mut self) -> u16 {
379 T::regs().isr().modify(|reg| {
380 reg.set_eos(true);
381 reg.set_eoc(true);
382 });
383
384 // Start conversion
385 T::regs().cr().modify(|reg| {
386 reg.set_adstart(true);
387 });
388
389 while !T::regs().isr().read().eos() {
390 // spin
391 } 362 }
392
393 T::regs().dr().read().0 as u16
394 } 363 }
395 364
396 /// Read an ADC channel. 365 /// Perform a single conversion.
397 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 366 pub(super) fn convert() -> u16 {
398 self.read_channel(channel, sample_time) 367 // Some models are affected by an erratum:
399 } 368 // If we perform conversions slower than 1 kHz, the first read ADC value can be
400 369 // corrupted, so we discard it and measure again.
401 /// Read one or multiple ADC channels using DMA. 370 //
402 /// 371 // STM32L471xx: Section 2.7.3
403 /// `readings` must have a length that is a multiple of the length of the 372 // STM32G4: Section 2.7.3
404 /// `sequence` iterator. 373 #[cfg(any(rcc_l4, rcc_g4))]
405 /// 374 let len = 2;
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 375
453 // Set sequence length 376 #[cfg(not(any(rcc_l4, rcc_g4)))]
454 #[cfg(not(any(adc_g0, adc_u0)))] 377 let len = 1;
455 T::regs().sqr1().modify(|w| {
456 w.set_l(sequence.len() as u8 - 1);
457 });
458 378
459 #[cfg(adc_g0)] 379 for _ in 0..len {
460 { 380 T::regs().isr().modify(|reg| {
461 let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new(); 381 reg.set_eos(true);
462 382 reg.set_eoc(true);
463 T::regs().chselr().write(|chselr| {
464 T::regs().smpr().write(|smpr| {
465 for (channel, sample_time) in sequence {
466 chselr.set_chsel(channel.channel.into(), true);
467 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
468 smpr.set_smpsel(channel.channel.into(), (i as u8).into());
469 } else {
470 smpr.set_sample_time(sample_times.len(), sample_time);
471 if let Err(_) = sample_times.push(sample_time) {
472 panic!(
473 "Implementation is limited to {} unique sample times among all channels.",
474 SAMPLE_TIMES_CAPACITY
475 );
476 }
477 }
478 }
479 })
480 }); 383 });
481 }
482 #[cfg(not(adc_g0))]
483 {
484 #[cfg(adc_u0)]
485 let mut channel_mask = 0;
486
487 // Configure channels and ranks
488 for (_i, (channel, sample_time)) in sequence.enumerate() {
489 Self::configure_channel(channel, sample_time);
490 384
491 // Each channel is sampled according to sequence 385 // Start conversion
492 #[cfg(not(any(adc_g0, adc_u0)))] 386 T::regs().cr().modify(|reg| {
493 match _i { 387 reg.set_adstart(true);
494 0..=3 => { 388 });
495 T::regs().sqr1().modify(|w| {
496 w.set_sq(_i, channel.channel());
497 });
498 }
499 4..=8 => {
500 T::regs().sqr2().modify(|w| {
501 w.set_sq(_i - 4, channel.channel());
502 });
503 }
504 9..=13 => {
505 T::regs().sqr3().modify(|w| {
506 w.set_sq(_i - 9, channel.channel());
507 });
508 }
509 14..=15 => {
510 T::regs().sqr4().modify(|w| {
511 w.set_sq(_i - 14, channel.channel());
512 });
513 }
514 _ => unreachable!(),
515 }
516 389
517 #[cfg(adc_u0)] 390 while !T::regs().isr().read().eos() {
518 { 391 // spin
519 channel_mask |= 1 << channel.channel();
520 }
521 } 392 }
522
523 // 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.
525 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
526 #[cfg(adc_u0)]
527 T::regs().chselr().modify(|reg| {
528 reg.set_chsel(channel_mask);
529 });
530 } 393 }
394
395 T::regs().dr().read().0 as u16
396 }
397
398 pub(super) fn configure_dma(conversion_mode: ConversionMode) {
531 // Set continuous mode with oneshot dma. 399 // Set continuous mode with oneshot dma.
532 // Clear overrun flag before starting transfer. 400 // Clear overrun flag before starting transfer.
533 T::regs().isr().modify(|reg| { 401 T::regs().isr().modify(|reg| {
@@ -535,82 +403,23 @@ impl<'d, T: Instance> Adc<'d, T> {
535 }); 403 });
536 404
537 #[cfg(not(any(adc_g0, adc_u0)))] 405 #[cfg(not(any(adc_g0, adc_u0)))]
538 T::regs().cfgr().modify(|reg| { 406 let regs = T::regs().cfgr();
539 reg.set_discen(false); 407
540 reg.set_cont(true);
541 reg.set_dmacfg(Dmacfg::ONE_SHOT);
542 reg.set_dmaen(true);
543 });
544 #[cfg(any(adc_g0, adc_u0))] 408 #[cfg(any(adc_g0, adc_u0))]
545 T::regs().cfgr1().modify(|reg| { 409 let regs = T::regs().cfgr1();
410
411 regs.modify(|reg| {
546 reg.set_discen(false); 412 reg.set_discen(false);
547 reg.set_cont(true); 413 reg.set_cont(true);
548 reg.set_dmacfg(Dmacfg::ONE_SHOT); 414 reg.set_dmacfg(match conversion_mode {
415 ConversionMode::Singular => Dmacfg::ONE_SHOT,
416 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
417 });
549 reg.set_dmaen(true); 418 reg.set_dmaen(true);
550 }); 419 });
551
552 let request = rx_dma.request();
553 let transfer = unsafe {
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
563 // Start conversion
564 T::regs().cr().modify(|reg| {
565 reg.set_adstart(true);
566 });
567
568 // Wait for conversion sequence to finish.
569 transfer.await;
570
571 // Ensure conversions are finished.
572 Self::cancel_conversions();
573
574 // Reset configuration.
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 } 420 }
584 421
585 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. 422 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
586 ///
587 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
588 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
589 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
590 ///
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.
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
614 // Set sequence length 423 // Set sequence length
615 #[cfg(not(any(adc_g0, adc_u0)))] 424 #[cfg(not(any(adc_g0, adc_u0)))]
616 T::regs().sqr1().modify(|w| { 425 T::regs().sqr1().modify(|w| {
@@ -623,10 +432,10 @@ impl<'d, T: Instance> Adc<'d, T> {
623 432
624 T::regs().chselr().write(|chselr| { 433 T::regs().chselr().write(|chselr| {
625 T::regs().smpr().write(|smpr| { 434 T::regs().smpr().write(|smpr| {
626 for (channel, sample_time) in sequence { 435 for ((channel, _), sample_time) in sequence {
627 chselr.set_chsel(channel.channel.into(), true); 436 chselr.set_chsel(channel.into(), true);
628 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { 437 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
629 smpr.set_smpsel(channel.channel.into(), (i as u8).into()); 438 smpr.set_smpsel(channel.into(), (i as u8).into());
630 } else { 439 } else {
631 smpr.set_sample_time(sample_times.len(), sample_time); 440 smpr.set_sample_time(sample_times.len(), sample_time);
632 if let Err(_) = sample_times.push(sample_time) { 441 if let Err(_) = sample_times.push(sample_time) {
@@ -646,30 +455,63 @@ impl<'d, T: Instance> Adc<'d, T> {
646 let mut channel_mask = 0; 455 let mut channel_mask = 0;
647 456
648 // Configure channels and ranks 457 // Configure channels and ranks
649 for (_i, (mut channel, sample_time)) in sequence.enumerate() { 458 for (_i, ((channel, _), sample_time)) in sequence.enumerate() {
650 Self::configure_channel(&mut channel, sample_time); 459 // RM0492, RM0481, etc.
460 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
461 #[cfg(any(adc_h5, adc_h7rs))]
462 if channel == 0 {
463 T::regs().or().modify(|reg| reg.set_op0(true));
464 }
465
466 // Configure channel
467 cfg_if! {
468 if #[cfg(adc_u0)] {
469 // On G0 and U6 all channels use the same sampling time.
470 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
471 } else if #[cfg(any(adc_h5, adc_h7rs))] {
472 match channel {
473 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
474 _ => T::regs().smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
475 }
476 } else {
477 let sample_time = sample_time.into();
478 T::regs()
479 .smpr(channel as usize / 10)
480 .modify(|reg| reg.set_smp(channel as usize % 10, sample_time));
481 }
482 }
483
484 #[cfg(stm32h7)]
485 {
486 use crate::pac::adc::vals::Pcsel;
487
488 T::regs().cfgr2().modify(|w| w.set_lshift(0));
489 T::regs()
490 .pcsel()
491 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
492 }
651 493
652 // Each channel is sampled according to sequence 494 // Each channel is sampled according to sequence
653 #[cfg(not(any(adc_g0, adc_u0)))] 495 #[cfg(not(any(adc_g0, adc_u0)))]
654 match _i { 496 match _i {
655 0..=3 => { 497 0..=3 => {
656 T::regs().sqr1().modify(|w| { 498 T::regs().sqr1().modify(|w| {
657 w.set_sq(_i, channel.channel()); 499 w.set_sq(_i, channel);
658 }); 500 });
659 } 501 }
660 4..=8 => { 502 4..=8 => {
661 T::regs().sqr2().modify(|w| { 503 T::regs().sqr2().modify(|w| {
662 w.set_sq(_i - 4, channel.channel()); 504 w.set_sq(_i - 4, channel);
663 }); 505 });
664 } 506 }
665 9..=13 => { 507 9..=13 => {
666 T::regs().sqr3().modify(|w| { 508 T::regs().sqr3().modify(|w| {
667 w.set_sq(_i - 9, channel.channel()); 509 w.set_sq(_i - 9, channel);
668 }); 510 });
669 } 511 }
670 14..=15 => { 512 14..=15 => {
671 T::regs().sqr4().modify(|w| { 513 T::regs().sqr4().modify(|w| {
672 w.set_sq(_i - 14, channel.channel()); 514 w.set_sq(_i - 14, channel);
673 }); 515 });
674 } 516 }
675 _ => unreachable!(), 517 _ => unreachable!(),
@@ -677,7 +519,7 @@ impl<'d, T: Instance> Adc<'d, T> {
677 519
678 #[cfg(adc_u0)] 520 #[cfg(adc_u0)]
679 { 521 {
680 channel_mask |= 1 << channel.channel(); 522 channel_mask |= 1 << channel;
681 } 523 }
682 } 524 }
683 525
@@ -689,151 +531,71 @@ impl<'d, T: Instance> Adc<'d, T> {
689 reg.set_chsel(channel_mask); 531 reg.set_chsel(channel_mask);
690 }); 532 });
691 } 533 }
692 // Set continuous mode with Circular dma. 534 }
693 // Clear overrun flag before starting transfer.
694 T::regs().isr().modify(|reg| {
695 reg.set_ovr(true);
696 });
697 535
536 pub fn enable_vrefint(&self) -> VrefInt {
698 #[cfg(not(any(adc_g0, adc_u0)))] 537 #[cfg(not(any(adc_g0, adc_u0)))]
699 T::regs().cfgr().modify(|reg| { 538 T::common_regs().ccr().modify(|reg| {
700 reg.set_discen(false); 539 reg.set_vrefen(true);
701 reg.set_cont(true);
702 reg.set_dmacfg(Dmacfg::CIRCULAR);
703 reg.set_dmaen(true);
704 }); 540 });
705 #[cfg(any(adc_g0, adc_u0))] 541 #[cfg(any(adc_g0, adc_u0))]
706 T::regs().cfgr1().modify(|reg| { 542 T::regs().ccr().modify(|reg| {
707 reg.set_discen(false); 543 reg.set_vrefen(true);
708 reg.set_cont(true);
709 reg.set_dmacfg(Dmacfg::CIRCULAR);
710 reg.set_dmaen(true);
711 }); 544 });
712 545
713 RingBufferedAdc::new(dma, dma_buf) 546 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
714 } 547 // to stabilize the internal voltage reference.
715 548 blocking_delay_us(15);
716 #[cfg(not(adc_g0))]
717 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
718 // RM0492, RM0481, etc.
719 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
720 #[cfg(any(adc_h5, adc_h7rs))]
721 if channel.channel() == 0 {
722 T::regs().or().modify(|reg| reg.set_op0(true));
723 }
724 549
725 // Configure channel 550 VrefInt {}
726 Self::set_channel_sample_time(channel.channel(), sample_time);
727 } 551 }
728 552
729 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 553 pub fn enable_temperature(&self) -> Temperature {
730 self.enable(); 554 cfg_if! {
731 #[cfg(not(adc_g0))] 555 if #[cfg(any(adc_g0, adc_u0))] {
732 Self::configure_channel(channel, sample_time); 556 T::regs().ccr().modify(|reg| {
733 #[cfg(adc_g0)] 557 reg.set_tsen(true);
734 T::regs().smpr().write(|reg| { 558 });
735 reg.set_sample_time(0, sample_time); 559 } else if #[cfg(any(adc_h5, adc_h7rs))] {
736 reg.set_smpsel(channel.channel().into(), Smpsel::SMP1); 560 T::common_regs().ccr().modify(|reg| {
737 }); 561 reg.set_tsen(true);
738 // Select channel 562 });
739 #[cfg(not(any(adc_g0, adc_u0)))] 563 } else {
740 T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel())); 564 T::common_regs().ccr().modify(|reg| {
741 #[cfg(any(adc_g0, adc_u0))] 565 reg.set_ch17sel(true);
742 T::regs().chselr().write(|reg| { 566 });
743 #[cfg(adc_g0)] 567 }
744 reg.set_chsel(channel.channel().into(), true);
745 #[cfg(adc_u0)]
746 reg.set_chsel(1 << channel.channel());
747 });
748
749 // Some models are affected by an erratum:
750 // If we perform conversions slower than 1 kHz, the first read ADC value can be
751 // corrupted, so we discard it and measure again.
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 } 568 }
767 569
768 val 570 Temperature {}
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
780 #[cfg(adc_g0)]
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 }
788
789 #[cfg(any(adc_g0, adc_u0))]
790 pub fn oversampling_enable(&mut self, enable: bool) {
791 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
792 }
793
794 #[cfg(adc_v3)]
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 }
800
801 #[cfg(adc_v3)]
802 pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) {
803 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
804 }
805
806 #[cfg(adc_v3)]
807 pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) {
808 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
809 } 571 }
810 572
811 #[cfg(not(adc_g0))] 573 pub fn enable_vbat(&self) -> Vbat {
812 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
813 cfg_if! { 574 cfg_if! {
814 if #[cfg(adc_u0)] { 575 if #[cfg(any(adc_g0, adc_u0))] {
815 // On G0 and U6 all channels use the same sampling time. 576 T::regs().ccr().modify(|reg| {
816 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 577 reg.set_vbaten(true);
578 });
817 } else if #[cfg(any(adc_h5, adc_h7rs))] { 579 } else if #[cfg(any(adc_h5, adc_h7rs))] {
818 match _ch { 580 T::common_regs().ccr().modify(|reg| {
819 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 581 reg.set_vbaten(true);
820 _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 582 });
821 }
822 } else { 583 } else {
823 let sample_time = sample_time.into(); 584 T::common_regs().ccr().modify(|reg| {
824 T::regs() 585 reg.set_ch18sel(true);
825 .smpr(_ch as usize / 10) 586 });
826 .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time));
827 } 587 }
828 } 588 }
589
590 Vbat {}
829 } 591 }
830 592
831 fn cancel_conversions() { 593 /*
832 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 594 /// Convert a raw sample from the `Temperature` to deg C
833 T::regs().cr().modify(|reg| { 595 pub fn to_degrees_centigrade(sample: u16) -> f32 {
834 reg.set_adstp(true); 596 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
835 }); 597 * (sample as f32 - VtempCal30::get().read() as f32)
836 while T::regs().cr().read().adstart() {} 598 + 30.0
837 }
838 } 599 }
600 */
839} 601}
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 1d5d3fb92..9be6bcd0b 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, 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
@@ -147,7 +144,48 @@ pub enum Averaging {
147 Samples1024, 144 Samples1024,
148} 145}
149 146
147/// Adc configuration
148#[derive(Default)]
149pub struct AdcConfig {
150 pub resolution: Option<Resolution>,
151 pub averaging: Option<Averaging>,
152}
153
150impl<'d, T: Instance> Adc<'d, T> { 154impl<'d, T: Instance> Adc<'d, T> {
155 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
156 let s = Self::new(adc);
157
158 // Set the ADC resolution.
159 if let Some(resolution) = config.resolution {
160 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
161 }
162
163 // Set hardware averaging.
164 if let Some(averaging) = config.averaging {
165 let (enable, samples, right_shift) = match averaging {
166 Averaging::Disabled => (false, 0, 0),
167 Averaging::Samples2 => (true, 1, 1),
168 Averaging::Samples4 => (true, 3, 2),
169 Averaging::Samples8 => (true, 7, 3),
170 Averaging::Samples16 => (true, 15, 4),
171 Averaging::Samples32 => (true, 31, 5),
172 Averaging::Samples64 => (true, 63, 6),
173 Averaging::Samples128 => (true, 127, 7),
174 Averaging::Samples256 => (true, 255, 8),
175 Averaging::Samples512 => (true, 511, 9),
176 Averaging::Samples1024 => (true, 1023, 10),
177 };
178
179 T::regs().cfgr2().modify(|reg| {
180 reg.set_rovse(enable);
181 reg.set_ovsr(samples);
182 reg.set_ovss(right_shift);
183 })
184 }
185
186 s
187 }
188
151 /// Create a new ADC driver. 189 /// Create a new ADC driver.
152 pub fn new(adc: Peri<'d, T>) -> Self { 190 pub fn new(adc: Peri<'d, T>) -> Self {
153 rcc::enable_and_reset::<T>(); 191 rcc::enable_and_reset::<T>();
@@ -179,37 +217,20 @@ impl<'d, T: Instance> Adc<'d, T> {
179 }; 217 };
180 T::regs().cr().modify(|w| w.set_boost(boost)); 218 T::regs().cr().modify(|w| w.set_boost(boost));
181 } 219 }
182 let mut s = Self { adc };
183 s.power_up();
184 s.configure_differential_inputs();
185
186 s.calibrate();
187 blocking_delay_us(1);
188
189 s.enable();
190 s.configure();
191
192 s
193 }
194 220
195 fn power_up(&mut self) {
196 T::regs().cr().modify(|reg| { 221 T::regs().cr().modify(|reg| {
197 reg.set_deeppwd(false); 222 reg.set_deeppwd(false);
198 reg.set_advregen(true); 223 reg.set_advregen(true);
199 }); 224 });
200 225
201 blocking_delay_us(10); 226 blocking_delay_us(10);
202 }
203 227
204 fn configure_differential_inputs(&mut self) {
205 T::regs().difsel().modify(|w| { 228 T::regs().difsel().modify(|w| {
206 for n in 0..20 { 229 for n in 0..20 {
207 w.set_difsel(n, Difsel::SINGLE_ENDED); 230 w.set_difsel(n, Difsel::SINGLE_ENDED);
208 } 231 }
209 }); 232 });
210 }
211 233
212 fn calibrate(&mut self) {
213 T::regs().cr().modify(|w| { 234 T::regs().cr().modify(|w| {
214 #[cfg(not(adc_u5))] 235 #[cfg(not(adc_u5))]
215 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 236 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
@@ -219,80 +240,50 @@ impl<'d, T: Instance> Adc<'d, T> {
219 T::regs().cr().modify(|w| w.set_adcal(true)); 240 T::regs().cr().modify(|w| w.set_adcal(true));
220 241
221 while T::regs().cr().read().adcal() {} 242 while T::regs().cr().read().adcal() {}
222 }
223 243
224 fn enable(&mut self) { 244 blocking_delay_us(1);
225 T::regs().isr().write(|w| w.set_adrdy(true)); 245
226 T::regs().cr().modify(|w| w.set_aden(true)); 246 Self::enable();
227 while !T::regs().isr().read().adrdy() {}
228 T::regs().isr().write(|w| w.set_adrdy(true));
229 }
230 247
231 fn configure(&mut self) {
232 // single conversion mode, software trigger 248 // single conversion mode, software trigger
233 T::regs().cfgr().modify(|w| { 249 T::regs().cfgr().modify(|w| {
234 w.set_cont(false); 250 w.set_cont(false);
235 w.set_exten(Exten::DISABLED); 251 w.set_exten(Exten::DISABLED);
236 }); 252 });
237 }
238 253
239 /// Enable reading the voltage reference internal channel. 254 Self { adc }
240 pub fn enable_vrefint(&self) -> VrefInt {
241 T::common_regs().ccr().modify(|reg| {
242 reg.set_vrefen(true);
243 });
244
245 VrefInt {}
246 } 255 }
247 256
248 /// Enable reading the temperature internal channel. 257 pub(super) fn enable() {
249 pub fn enable_temperature(&self) -> Temperature { 258 T::regs().isr().write(|w| w.set_adrdy(true));
250 T::common_regs().ccr().modify(|reg| { 259 T::regs().cr().modify(|w| w.set_aden(true));
251 reg.set_vsenseen(true); 260 while !T::regs().isr().read().adrdy() {}
252 }); 261 T::regs().isr().write(|w| w.set_adrdy(true));
253
254 Temperature {}
255 } 262 }
256 263
257 /// Enable reading the vbat internal channel. 264 pub(super) fn start() {
258 pub fn enable_vbat(&self) -> Vbat { 265 // Start conversion
259 T::common_regs().ccr().modify(|reg| { 266 T::regs().cr().modify(|reg| {
260 reg.set_vbaten(true); 267 reg.set_adstart(true);
261 }); 268 });
262
263 Vbat {}
264 } 269 }
265 270
266 /// Set the ADC resolution. 271 pub(super) fn stop() {
267 pub fn set_resolution(&mut self, resolution: Resolution) { 272 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
268 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 273 T::regs().cr().modify(|reg| {
269 } 274 reg.set_adstp(Adstp::STOP);
275 });
276 while T::regs().cr().read().adstart() {}
277 }
270 278
271 /// Set hardware averaging. 279 // Reset configuration.
272 pub fn set_averaging(&mut self, averaging: Averaging) { 280 T::regs().cfgr().modify(|reg| {
273 let (enable, samples, right_shift) = match averaging { 281 reg.set_cont(false);
274 Averaging::Disabled => (false, 0, 0), 282 reg.set_dmngt(Dmngt::from_bits(0));
275 Averaging::Samples2 => (true, 1, 1), 283 });
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 } 284 }
293 285
294 /// Perform a single conversion. 286 pub(super) fn convert() -> u16 {
295 fn convert(&mut self) -> u16 {
296 T::regs().isr().modify(|reg| { 287 T::regs().isr().modify(|reg| {
297 reg.set_eos(true); 288 reg.set_eos(true);
298 reg.set_eoc(true); 289 reg.set_eoc(true);
@@ -310,170 +301,96 @@ impl<'d, T: Instance> Adc<'d, T> {
310 T::regs().dr().read().0 as u16 301 T::regs().dr().read().0 as u16
311 } 302 }
312 303
313 /// Read an ADC channel. 304 pub(super) fn configure_dma(conversion_mode: ConversionMode) {
314 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 305 match conversion_mode {
315 self.read_channel(channel, sample_time) 306 ConversionMode::Singular => {
307 T::regs().isr().modify(|reg| {
308 reg.set_ovr(true);
309 });
310 T::regs().cfgr().modify(|reg| {
311 reg.set_cont(true);
312 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
313 });
314 }
315 _ => unreachable!(),
316 }
316 } 317 }
317 318
318 /// Read one or multiple ADC channels using DMA. 319 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
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 320 // Set sequence length
363 T::regs().sqr1().modify(|w| { 321 T::regs().sqr1().modify(|w| {
364 w.set_l(sequence.len() as u8 - 1); 322 w.set_l(sequence.len() as u8 - 1);
365 }); 323 });
366 324
367 // Configure channels and ranks 325 // Configure channels and ranks
368 for (i, (channel, sample_time)) in sequence.enumerate() { 326 for (i, ((channel, _), sample_time)) in sequence.enumerate() {
369 Self::configure_channel(channel, sample_time); 327 let sample_time = sample_time.into();
328 if channel <= 9 {
329 T::regs().smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time));
330 } else {
331 T::regs()
332 .smpr(1)
333 .modify(|reg| reg.set_smp((channel - 10) as _, sample_time));
334 }
335
336 #[cfg(any(stm32h7, stm32u5))]
337 {
338 T::regs().cfgr2().modify(|w| w.set_lshift(0));
339 T::regs()
340 .pcsel()
341 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
342 }
343
370 match i { 344 match i {
371 0..=3 => { 345 0..=3 => {
372 T::regs().sqr1().modify(|w| { 346 T::regs().sqr1().modify(|w| {
373 w.set_sq(i, channel.channel()); 347 w.set_sq(i, channel);
374 }); 348 });
375 } 349 }
376 4..=8 => { 350 4..=8 => {
377 T::regs().sqr2().modify(|w| { 351 T::regs().sqr2().modify(|w| {
378 w.set_sq(i - 4, channel.channel()); 352 w.set_sq(i - 4, channel);
379 }); 353 });
380 } 354 }
381 9..=13 => { 355 9..=13 => {
382 T::regs().sqr3().modify(|w| { 356 T::regs().sqr3().modify(|w| {
383 w.set_sq(i - 9, channel.channel()); 357 w.set_sq(i - 9, channel);
384 }); 358 });
385 } 359 }
386 14..=15 => { 360 14..=15 => {
387 T::regs().sqr4().modify(|w| { 361 T::regs().sqr4().modify(|w| {
388 w.set_sq(i - 14, channel.channel()); 362 w.set_sq(i - 14, channel);
389 }); 363 });
390 } 364 }
391 _ => unreachable!(), 365 _ => unreachable!(),
392 } 366 }
393 } 367 }
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 } 368 }
434 369
435 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 370 /// Enable reading the voltage reference internal channel.
436 channel.setup(); 371 pub fn enable_vrefint(&self) -> VrefInt {
437 372 T::common_regs().ccr().modify(|reg| {
438 let channel = channel.channel(); 373 reg.set_vrefen(true);
439 374 });
440 Self::set_channel_sample_time(channel, sample_time);
441 375
442 #[cfg(any(stm32h7, stm32u5))] 376 VrefInt {}
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 } 377 }
450 378
451 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 379 /// Enable reading the temperature internal channel.
452 Self::configure_channel(channel, sample_time); 380 pub fn enable_temperature(&self) -> Temperature {
453 381 T::common_regs().ccr().modify(|reg| {
454 T::regs().sqr1().modify(|reg| { 382 reg.set_vsenseen(true);
455 reg.set_sq(0, channel.channel());
456 reg.set_l(0);
457 }); 383 });
458 384
459 self.convert() 385 Temperature {}
460 } 386 }
461 387
462 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 388 /// Enable reading the vbat internal channel.
463 let sample_time = sample_time.into(); 389 pub fn enable_vbat(&self) -> Vbat {
464 if ch <= 9 { 390 T::common_regs().ccr().modify(|reg| {
465 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); 391 reg.set_vbaten(true);
466 } else { 392 });
467 T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
468 }
469 }
470 393
471 fn cancel_conversions() { 394 Vbat {}
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 } 395 }
479} 396}
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 5628cb827..694e85657 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let mut delay = Delay; 16 let mut delay = Delay;
17 let mut adc = Adc::new(p.ADC1); 17 let mut adc = Adc::new_with_config(p.ADC1, Default::default());
18 let mut pin = p.PC1; 18 let mut pin = p.PC1;
19 19
20 let mut vrefint = adc.enable_vrefint(); 20 let mut vrefint = adc.enable_vrefint();
diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs
index 01b881c79..d61b1b2eb 100644
--- a/examples/stm32f4/src/bin/adc_dma.rs
+++ b/examples/stm32f4/src/bin/adc_dma.rs
@@ -4,7 +4,7 @@ use cortex_m::singleton;
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::Peripherals; 6use embassy_stm32::Peripherals;
7use embassy_stm32::adc::{Adc, AdcChannel, RingBufferedAdc, SampleTime}; 7use embassy_stm32::adc::{Adc, AdcChannel, RegularConversionMode, RingBufferedAdc, SampleTime};
8use embassy_time::Instant; 8use embassy_time::Instant;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -20,8 +20,8 @@ async fn adc_task(p: Peripherals) {
20 let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); 20 let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
21 let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); 21 let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
22 22
23 let adc = Adc::new(p.ADC1); 23 let adc = Adc::new_with_config(p.ADC1, Default::default());
24 let adc2 = Adc::new(p.ADC2); 24 let adc2 = Adc::new_with_config(p.ADC2, Default::default());
25 25
26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered( 26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
27 p.DMA2_CH0, 27 p.DMA2_CH0,
@@ -31,6 +31,7 @@ async fn adc_task(p: Peripherals) {
31 (p.PA2.degrade_adc(), SampleTime::CYCLES112), 31 (p.PA2.degrade_adc(), SampleTime::CYCLES112),
32 ] 32 ]
33 .into_iter(), 33 .into_iter(),
34 RegularConversionMode::Continuous,
34 ); 35 );
35 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered( 36 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(
36 p.DMA2_CH2, 37 p.DMA2_CH2,
@@ -40,6 +41,7 @@ async fn adc_task(p: Peripherals) {
40 (p.PA3.degrade_adc(), SampleTime::CYCLES112), 41 (p.PA3.degrade_adc(), SampleTime::CYCLES112),
41 ] 42 ]
42 .into_iter(), 43 .into_iter(),
44 RegularConversionMode::Continuous,
43 ); 45 );
44 46
45 // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around 47 // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around
diff --git a/examples/stm32g0/src/bin/adc_oversampling.rs b/examples/stm32g0/src/bin/adc_oversampling.rs
index f6979889d..aa8b1771b 100644
--- a/examples/stm32g0/src/bin/adc_oversampling.rs
+++ b/examples/stm32g0/src/bin/adc_oversampling.rs
@@ -7,7 +7,7 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::adc::{Adc, Clock, Ovsr, Ovss, Presc, SampleTime}; 10use embassy_stm32::adc::{Adc, AdcConfig, Clock, Ovsr, Ovss, Presc, SampleTime};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
@@ -16,12 +16,14 @@ async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default()); 16 let p = embassy_stm32::init(Default::default());
17 info!("Adc oversample test"); 17 info!("Adc oversample test");
18 18
19 let mut adc = Adc::new_with_clock(p.ADC1, Clock::Async { div: Presc::DIV1 }); 19 let mut config = AdcConfig::default();
20 let mut pin = p.PA1; 20 config.clock = Some(Clock::Async { div: Presc::DIV1 });
21 config.oversampling_ratio = Some(Ovsr::MUL16);
22 config.oversampling_shift = Some(Ovss::NO_SHIFT);
23 config.oversampling_enable = Some(true);
21 24
22 adc.set_oversampling_ratio(Ovsr::MUL16); 25 let mut adc = Adc::new_with_config(p.ADC1, config);
23 adc.set_oversampling_shift(Ovss::NO_SHIFT); 26 let mut pin = p.PA1;
24 adc.oversampling_enable(true);
25 27
26 loop { 28 loop {
27 let v = adc.blocking_read(&mut pin, SampleTime::CYCLES1_5); 29 let v = adc.blocking_read(&mut pin, SampleTime::CYCLES1_5);
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 94315141c..2149e0748 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) {
28 let mut p = embassy_stm32::init(config); 28 let mut p = embassy_stm32::init(config);
29 info!("Hello World!"); 29 info!("Hello World!");
30 30
31 let mut adc = Adc::new(p.ADC2); 31 let mut adc = Adc::new(p.ADC2, Default::default());
32 32
33 let mut adc_temp = Adc::new(p.ADC1); 33 let mut adc_temp = Adc::new(p.ADC1, Default::default());
34 let mut temperature = adc_temp.enable_temperature(); 34 let mut temperature = adc_temp.enable_temperature();
35 35
36 loop { 36 loop {
diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs
index 2773723e9..6dedf88d6 100644
--- a/examples/stm32g4/src/bin/adc_differential.rs
+++ b/examples/stm32g4/src/bin/adc_differential.rs
@@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) {
32 } 32 }
33 let p = embassy_stm32::init(config); 33 let p = embassy_stm32::init(config);
34 34
35 let mut adc = Adc::new(p.ADC1); 35 let mut adc = Adc::new(p.ADC1, Default::default());
36 let mut differential_channel = (p.PA0, p.PA1); 36 let mut differential_channel = (p.PA0, p.PA1);
37 37
38 // can also use 38 // can also use
diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs
index ef8b0c3c2..478b6b2ca 100644
--- a/examples/stm32g4/src/bin/adc_dma.rs
+++ b/examples/stm32g4/src/bin/adc_dma.rs
@@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) {
33 33
34 info!("Hello World!"); 34 info!("Hello World!");
35 35
36 let mut adc = Adc::new(p.ADC1); 36 let mut adc = Adc::new(p.ADC1, Default::default());
37 37
38 let mut dma = p.DMA1_CH1; 38 let mut dma = p.DMA1_CH1;
39 let mut vrefint_channel = adc.enable_vrefint().degrade_adc(); 39 let mut vrefint_channel = adc.enable_vrefint().degrade_adc();
diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs
index 3ae2ff064..1e97fa925 100644
--- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs
+++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs
@@ -77,7 +77,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
77 pwm.set_mms2(Mms2::UPDATE); 77 pwm.set_mms2(Mms2::UPDATE);
78 78
79 // Configure regular conversions with DMA 79 // Configure regular conversions with DMA
80 let adc1 = Adc::new(p.ADC1); 80 let adc1 = Adc::new(p.ADC1, Default::default());
81 81
82 let vrefint_channel = adc1.enable_vrefint().degrade_adc(); 82 let vrefint_channel = adc1.enable_vrefint().degrade_adc();
83 let pa0 = p.PC1.degrade_adc(); 83 let pa0 = p.PC1.degrade_adc();
diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs
index cb99ab2a7..87ffea4be 100644
--- a/examples/stm32g4/src/bin/adc_oversampling.rs
+++ b/examples/stm32g4/src/bin/adc_oversampling.rs
@@ -9,7 +9,7 @@ use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::Config; 10use embassy_stm32::Config;
11use embassy_stm32::adc::vals::{Rovsm, Trovs}; 11use embassy_stm32::adc::vals::{Rovsm, Trovs};
12use embassy_stm32::adc::{Adc, SampleTime}; 12use embassy_stm32::adc::{Adc, AdcConfig, SampleTime};
13use embassy_time::Timer; 13use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
15 15
@@ -32,7 +32,8 @@ async fn main(_spawner: Spawner) {
32 } 32 }
33 let mut p = embassy_stm32::init(config); 33 let mut p = embassy_stm32::init(config);
34 34
35 let mut adc = Adc::new(p.ADC1); 35 let mut config = AdcConfig::default();
36
36 // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf 37 // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
37 // page652 Oversampler 38 // page652 Oversampler
38 // Table 172. Maximum output results vs N and M. Grayed values indicates truncation 39 // Table 172. Maximum output results vs N and M. Grayed values indicates truncation
@@ -44,9 +45,11 @@ async fn main(_spawner: Spawner) {
44 // 0x05 oversampling ratio X64 45 // 0x05 oversampling ratio X64
45 // 0x06 oversampling ratio X128 46 // 0x06 oversampling ratio X128
46 // 0x07 oversampling ratio X256 47 // 0x07 oversampling ratio X256
47 adc.set_oversampling_ratio(0x03); // ratio X3 48 config.oversampling_ratio = Some(0x03); // ratio X3
48 adc.set_oversampling_shift(0b0000); // no shift 49 config.oversampling_shift = Some(0b0000); // no shift
49 adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true); 50 config.oversampling_mode = Some((Rovsm::RESUMED, Trovs::AUTOMATIC, true));
51
52 let mut adc = Adc::new(p.ADC1, config);
50 53
51 loop { 54 loop {
52 let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES6_5); 55 let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES6_5);
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 835bf5411..42766a5e3 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::Config; 5use embassy_stm32::Config;
6use embassy_stm32::adc::{Adc, Resolution, SampleTime}; 6use embassy_stm32::adc::{Adc, AdcConfig, Resolution, SampleTime};
7use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
8 8
9#[cortex_m_rt::entry] 9#[cortex_m_rt::entry]
@@ -17,9 +17,12 @@ fn main() -> ! {
17 } 17 }
18 let p = embassy_stm32::init(config); 18 let p = embassy_stm32::init(config);
19 19
20 let mut adc = Adc::new(p.ADC1); 20 let mut config = AdcConfig::default();
21 config.resolution = Some(Resolution::BITS8);
22
23 let mut adc = Adc::new_with_config(p.ADC1, config);
21 //adc.enable_vref(); 24 //adc.enable_vref();
22 adc.set_resolution(Resolution::BITS8); 25
23 let mut channel = p.PC0; 26 let mut channel = p.PC0;
24 27
25 loop { 28 loop {
diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs
index ab1e9d2e9..550da95a4 100644
--- a/examples/stm32l4/src/bin/adc_dma.rs
+++ b/examples/stm32l4/src/bin/adc_dma.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::Config; 6use embassy_stm32::Config;
7use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; 7use embassy_stm32::adc::{Adc, AdcChannel, RegularConversionMode, SampleTime};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10const DMA_BUF_LEN: usize = 512; 10const DMA_BUF_LEN: usize = 512;
@@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
20 } 20 }
21 let p = embassy_stm32::init(config); 21 let p = embassy_stm32::init(config);
22 22
23 let mut adc = Adc::new(p.ADC1); 23 let adc = Adc::new(p.ADC1);
24 let adc_pin0 = p.PA0.degrade_adc(); 24 let adc_pin0 = p.PA0.degrade_adc();
25 let adc_pin1 = p.PA1.degrade_adc(); 25 let adc_pin1 = p.PA1.degrade_adc();
26 let mut adc_dma_buf = [0u16; DMA_BUF_LEN]; 26 let mut adc_dma_buf = [0u16; DMA_BUF_LEN];
@@ -29,6 +29,7 @@ async fn main(_spawner: Spawner) {
29 p.DMA1_CH1, 29 p.DMA1_CH1,
30 &mut adc_dma_buf, 30 &mut adc_dma_buf,
31 [(adc_pin0, SampleTime::CYCLES640_5), (adc_pin1, SampleTime::CYCLES640_5)].into_iter(), 31 [(adc_pin0, SampleTime::CYCLES640_5), (adc_pin1, SampleTime::CYCLES640_5)].into_iter(),
32 RegularConversionMode::Continuous,
32 ); 33 );
33 34
34 info!("starting measurement loop"); 35 info!("starting measurement loop");
diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs
index 4fbc6f17f..53bd37303 100644
--- a/examples/stm32u0/src/bin/adc.rs
+++ b/examples/stm32u0/src/bin/adc.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::Config; 5use embassy_stm32::Config;
6use embassy_stm32::adc::{Adc, Resolution, SampleTime}; 6use embassy_stm32::adc::{Adc, AdcConfig, Resolution, SampleTime};
7use embassy_time::Duration; 7use embassy_time::Duration;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
@@ -18,8 +18,9 @@ fn main() -> ! {
18 } 18 }
19 let p = embassy_stm32::init(config); 19 let p = embassy_stm32::init(config);
20 20
21 let mut adc = Adc::new(p.ADC1); 21 let mut config = AdcConfig::default();
22 adc.set_resolution(Resolution::BITS8); 22 config.resolution = Some(Resolution::BITS8);
23 let mut adc = Adc::new_with_config(p.ADC1, config);
23 let mut channel = p.PC0; 24 let mut channel = p.PC0;
24 25
25 loop { 26 loop {
diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs
index 99944f7c7..6b9a91d6e 100644
--- a/examples/stm32u5/src/bin/adc.rs
+++ b/examples/stm32u5/src/bin/adc.rs
@@ -2,7 +2,7 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::adc::{self, AdcChannel, SampleTime, adc4}; 5use embassy_stm32::adc::{self, AdcChannel, AdcConfig, SampleTime, adc4};
6use {defmt_rtt as _, panic_probe as _}; 6use {defmt_rtt as _, panic_probe as _};
7 7
8#[embassy_executor::main] 8#[embassy_executor::main]
@@ -12,19 +12,21 @@ async fn main(_spawner: embassy_executor::Spawner) {
12 let mut p = embassy_stm32::init(config); 12 let mut p = embassy_stm32::init(config);
13 13
14 // **** ADC1 init **** 14 // **** ADC1 init ****
15 let mut adc1 = adc::Adc::new(p.ADC1); 15 let mut config = AdcConfig::default();
16 config.averaging = Some(adc::Averaging::Samples1024);
17 config.resolution = Some(adc::Resolution::BITS14);
18 let mut adc1 = adc::Adc::new_with_config(p.ADC1, config);
16 let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 19 let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5
17 let mut adc1_pin2 = p.PA2; // A1 20 let mut adc1_pin2 = p.PA2; // A1
18 adc1.set_resolution(adc::Resolution::BITS14);
19 adc1.set_averaging(adc::Averaging::Samples1024);
20 let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); 21 let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14);
21 22
22 // **** ADC2 init **** 23 // **** ADC2 init ****
23 let mut adc2 = adc::Adc::new(p.ADC2); 24 let mut config = AdcConfig::default();
25 config.averaging = Some(adc::Averaging::Samples1024);
26 config.resolution = Some(adc::Resolution::BITS14);
27 let mut adc2 = adc::Adc::new_with_config(p.ADC2, config);
24 let mut adc2_pin1 = p.PC3; // A2 28 let mut adc2_pin1 = p.PC3; // A2
25 let mut adc2_pin2 = p.PB0; // A3 29 let mut adc2_pin2 = p.PB0; // A3
26 adc2.set_resolution(adc::Resolution::BITS14);
27 adc2.set_averaging(adc::Averaging::Samples1024);
28 let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); 30 let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14);
29 31
30 // **** ADC4 init **** 32 // **** ADC4 init ****