aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/adc/g4.rs
diff options
context:
space:
mode:
authorRaul Alimbekov <[email protected]>2025-12-16 09:05:22 +0300
committerGitHub <[email protected]>2025-12-16 09:05:22 +0300
commitc9a04b4b732b7a3b696eb8223664c1a7942b1875 (patch)
tree6dbe5c02e66eed8d8762f13f95afd24f8db2b38c /embassy-stm32/src/adc/g4.rs
parentcde24a3ef1117653ba5ed4184102b33f745782fb (diff)
parent5ae6e060ec1c90561719aabdc29d5b6e7b8b0a82 (diff)
Merge branch 'main' into main
Diffstat (limited to 'embassy-stm32/src/adc/g4.rs')
-rw-r--r--embassy-stm32/src/adc/g4.rs788
1 files changed, 401 insertions, 387 deletions
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 43498966f..e93ed945f 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,175 +1,275 @@
1#[cfg(stm32g4)]
2use pac::adc::regs::Difsel as DifselReg;
3#[allow(unused)]
4#[cfg(stm32g4)]
5pub use pac::adc::vals::{Adcaldif, Adstp, Difsel, Dmacfg, Dmaen, Exten, Rovsm, Trovs};
1#[allow(unused)] 6#[allow(unused)]
2#[cfg(stm32h7)] 7#[cfg(stm32h7)]
3use pac::adc::vals::{Adcaldif, Difsel, Exten}; 8use pac::adc::vals::{Adcaldif, Difsel, Exten};
4#[allow(unused)] 9pub use pac::adccommon::vals::{Dual, Presc};
5#[cfg(stm32g4)] 10
6use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; 11use super::{
7use pac::adccommon::vals::Presc; 12 Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime,
8use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; 13 blocking_delay_us,
9 14};
10use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; 15use crate::adc::{AdcRegs, BasicAdcRegs, SealedAdcChannel};
11use crate::adc::SealedAdcChannel; 16use crate::pac::adc::regs::{Smpr, Smpr2, Sqr1, Sqr2, Sqr3, Sqr4};
12use crate::dma::Transfer;
13use crate::time::Hertz; 17use crate::time::Hertz;
14use crate::{pac, rcc, Peri}; 18use crate::{Peri, pac, rcc};
19
20mod injected;
21pub use injected::InjectedAdc;
15 22
16/// Default VREF voltage used for sample conversion to millivolts. 23/// Default VREF voltage used for sample conversion to millivolts.
17pub const VREF_DEFAULT_MV: u32 = 3300; 24pub const VREF_DEFAULT_MV: u32 = 3300;
18/// VREF voltage used for factory calibration of VREFINTCAL register. 25/// VREF voltage used for factory calibration of VREFINTCAL register.
19pub const VREF_CALIB_MV: u32 = 3300; 26pub const VREF_CALIB_MV: u32 = 3300;
20 27
28const NR_INJECTED_RANKS: usize = 4;
29
21/// Max single ADC operation clock frequency 30/// Max single ADC operation clock frequency
22#[cfg(stm32g4)] 31#[cfg(stm32g4)]
23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); 32const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
24#[cfg(stm32h7)] 33#[cfg(stm32h7)]
25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 34const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
26 35
27// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 36fn from_ker_ck(frequency: Hertz) -> Presc {
28/// Internal voltage reference channel. 37 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
29pub struct VrefInt; 38 match raw_prescaler {
30impl<T: Instance + VrefChannel> AdcChannel<T> for VrefInt {} 39 0 => Presc::DIV1,
31impl<T: Instance + VrefChannel> super::SealedAdcChannel<T> for VrefInt { 40 1 => Presc::DIV2,
32 fn channel(&self) -> u8 { 41 2..=3 => Presc::DIV4,
33 T::CHANNEL 42 4..=5 => Presc::DIV6,
43 6..=7 => Presc::DIV8,
44 8..=9 => Presc::DIV10,
45 10..=11 => Presc::DIV12,
46 _ => unimplemented!(),
34 } 47 }
35} 48}
36 49
37/// Internal temperature channel. 50/// ADC configuration
38pub struct Temperature; 51#[derive(Default)]
39impl<T: Instance + TemperatureChannel> AdcChannel<T> for Temperature {} 52pub struct AdcConfig {
40impl<T: Instance + TemperatureChannel> super::SealedAdcChannel<T> for Temperature { 53 pub dual_mode: Option<Dual>,
41 fn channel(&self) -> u8 { 54 pub resolution: Option<Resolution>,
42 T::CHANNEL 55 #[cfg(stm32g4)]
43 } 56 pub oversampling_shift: Option<u8>,
57 #[cfg(stm32g4)]
58 pub oversampling_ratio: Option<u8>,
59 #[cfg(stm32g4)]
60 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
44} 61}
45 62
46/// Internal battery voltage channel. 63// Trigger source for ADC conversions¨
47pub struct Vbat; 64#[derive(Copy, Clone)]
48impl<T: Instance + VBatChannel> AdcChannel<T> for Vbat {} 65pub struct ConversionTrigger {
49impl<T: Instance + VBatChannel> super::SealedAdcChannel<T> for Vbat { 66 // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers
50 fn channel(&self) -> u8 { 67 // Note that Injected and Regular channels uses different mappings
51 T::CHANNEL 68 pub channel: u8,
52 } 69 pub edge: Exten,
53} 70}
54 71
55// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 72impl super::AdcRegs for crate::pac::adc::Adc {
56// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 73 fn data(&self) -> *mut u16 {
57#[allow(unused)] 74 crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
58enum Prescaler { 75 }
59 NotDivided, 76
60 DividedBy2, 77 fn enable(&self) {
61 DividedBy4, 78 // Make sure bits are off
62 DividedBy6, 79 while self.cr().read().addis() {
63 DividedBy8, 80 // spin
64 DividedBy10, 81 }
65 DividedBy12, 82
66 DividedBy16, 83 if !self.cr().read().aden() {
67 DividedBy32, 84 // Enable ADC
68 DividedBy64, 85 self.isr().modify(|reg| {
69 DividedBy128, 86 reg.set_adrdy(true);
70 DividedBy256, 87 });
71} 88 self.cr().modify(|reg| {
89 reg.set_aden(true);
90 });
72 91
73impl Prescaler { 92 while !self.isr().read().adrdy() {
74 fn from_ker_ck(frequency: Hertz) -> Self { 93 // spin
75 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 94 }
76 match raw_prescaler {
77 0 => Self::NotDivided,
78 1 => Self::DividedBy2,
79 2..=3 => Self::DividedBy4,
80 4..=5 => Self::DividedBy6,
81 6..=7 => Self::DividedBy8,
82 8..=9 => Self::DividedBy10,
83 10..=11 => Self::DividedBy12,
84 _ => unimplemented!(),
85 } 95 }
86 } 96 }
87 97
88 fn divisor(&self) -> u32 { 98 fn start(&self) {
89 match self { 99 self.cr().modify(|reg| {
90 Prescaler::NotDivided => 1, 100 reg.set_adstart(true);
91 Prescaler::DividedBy2 => 2, 101 });
92 Prescaler::DividedBy4 => 4, 102 }
93 Prescaler::DividedBy6 => 6, 103
94 Prescaler::DividedBy8 => 8, 104 fn stop(&self) {
95 Prescaler::DividedBy10 => 10, 105 if self.cr().read().adstart() && !self.cr().read().addis() {
96 Prescaler::DividedBy12 => 12, 106 self.cr().modify(|reg| {
97 Prescaler::DividedBy16 => 16, 107 reg.set_adstp(Adstp::STOP);
98 Prescaler::DividedBy32 => 32, 108 });
99 Prescaler::DividedBy64 => 64, 109 // The software must poll ADSTART until the bit is reset before assuming the
100 Prescaler::DividedBy128 => 128, 110 // ADC is completely stopped
101 Prescaler::DividedBy256 => 256, 111 while self.cr().read().adstart() {}
102 } 112 }
113
114 // Disable dma control and continuous conversion, if enabled
115 self.cfgr().modify(|reg| {
116 reg.set_cont(false);
117 reg.set_dmaen(Dmaen::DISABLE);
118 });
103 } 119 }
104 120
105 fn presc(&self) -> Presc { 121 fn convert(&self) {
106 match self { 122 self.isr().modify(|reg| {
107 Prescaler::NotDivided => Presc::DIV1, 123 reg.set_eos(true);
108 Prescaler::DividedBy2 => Presc::DIV2, 124 reg.set_eoc(true);
109 Prescaler::DividedBy4 => Presc::DIV4, 125 });
110 Prescaler::DividedBy6 => Presc::DIV6, 126
111 Prescaler::DividedBy8 => Presc::DIV8, 127 // Start conversion
112 Prescaler::DividedBy10 => Presc::DIV10, 128 self.cr().modify(|reg| {
113 Prescaler::DividedBy12 => Presc::DIV12, 129 reg.set_adstart(true);
114 Prescaler::DividedBy16 => Presc::DIV16, 130 });
115 Prescaler::DividedBy32 => Presc::DIV32, 131
116 Prescaler::DividedBy64 => Presc::DIV64, 132 while !self.isr().read().eos() {
117 Prescaler::DividedBy128 => Presc::DIV128, 133 // spin
118 Prescaler::DividedBy256 => Presc::DIV256,
119 } 134 }
120 } 135 }
121}
122 136
123impl<'d, T: Instance> Adc<'d, T> { 137 fn configure_dma(&self, conversion_mode: ConversionMode) {
124 /// Create a new ADC driver. 138 self.isr().modify(|reg| {
125 pub fn new(adc: Peri<'d, T>) -> Self { 139 reg.set_ovr(true);
126 rcc::enable_and_reset::<T>(); 140 });
127 141
128 let prescaler = Prescaler::from_ker_ck(T::frequency()); 142 self.cfgr().modify(|reg| {
143 reg.set_discen(false); // Convert all channels for each trigger
144 reg.set_dmacfg(match conversion_mode {
145 ConversionMode::Singular => Dmacfg::ONE_SHOT,
146 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
147 });
148 reg.set_dmaen(Dmaen::ENABLE);
149 });
129 150
130 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 151 if let ConversionMode::Repeated(mode) = conversion_mode {
152 match mode {
153 RegularConversionMode::Continuous => {
154 self.cfgr().modify(|reg| {
155 reg.set_cont(true);
156 });
157 }
158 RegularConversionMode::Triggered(trigger) => {
159 self.cfgr().modify(|r| {
160 r.set_cont(false); // New trigger is neede for each sample to be read
161 });
131 162
132 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 163 self.cfgr().modify(|r| {
133 trace!("ADC frequency set to {}", frequency); 164 r.set_extsel(trigger.channel);
165 r.set_exten(trigger.edge);
166 });
134 167
135 if frequency > MAX_ADC_CLK_FREQ { 168 // Regular conversions uses DMA so no need to generate interrupt
136 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 169 self.ier().modify(|r| r.set_eosie(false));
170 }
171 }
137 } 172 }
173 }
138 174
139 let mut s = Self { 175 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
140 adc, 176 self.cr().modify(|w| w.set_aden(false));
141 sample_time: SampleTime::from_bits(0),
142 };
143 s.power_up();
144 s.configure_differential_inputs();
145 177
146 s.calibrate(); 178 #[cfg(stm32g4)]
147 blocking_delay_us(1); 179 let mut difsel = DifselReg::default();
180 let mut smpr = Smpr::default();
181 let mut smpr2 = Smpr2::default();
182 let mut sqr1 = Sqr1::default();
183 let mut sqr2 = Sqr2::default();
184 let mut sqr3 = Sqr3::default();
185 let mut sqr4 = Sqr4::default();
186
187 // Set sequence length
188 sqr1.set_l(sequence.len() as u8 - 1);
189
190 // Configure channels and ranks
191 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() {
192 let sample_time = sample_time.into();
193 if ch <= 9 {
194 smpr.set_smp(ch as _, sample_time);
195 } else {
196 smpr2.set_smp((ch - 10) as _, sample_time);
197 }
198
199 match _i {
200 0..=3 => {
201 sqr1.set_sq(_i, ch);
202 }
203 4..=8 => {
204 sqr2.set_sq(_i - 4, ch);
205 }
206 9..=13 => {
207 sqr3.set_sq(_i - 9, ch);
208 }
209 14..=15 => {
210 sqr4.set_sq(_i - 14, ch);
211 }
212 _ => unreachable!(),
213 }
148 214
149 s.enable(); 215 #[cfg(stm32g4)]
150 s.configure(); 216 {
217 if ch < 18 {
218 difsel.set_difsel(
219 ch.into(),
220 if is_differential {
221 Difsel::DIFFERENTIAL
222 } else {
223 Difsel::SINGLE_ENDED
224 },
225 );
226 }
227 }
228 }
151 229
152 s 230 self.smpr().write_value(smpr);
231 self.smpr2().write_value(smpr2);
232 self.sqr1().write_value(sqr1);
233 self.sqr2().write_value(sqr2);
234 self.sqr3().write_value(sqr3);
235 self.sqr4().write_value(sqr4);
236 #[cfg(stm32g4)]
237 self.difsel().write_value(difsel);
153 } 238 }
239}
240
241impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
242 /// Create a new ADC driver.
243 pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self {
244 rcc::enable_and_reset::<T>();
245
246 let prescaler = from_ker_ck(T::frequency());
247
248 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
249
250 let frequency = T::frequency() / prescaler;
251 trace!("ADC frequency set to {}", frequency);
252
253 if frequency > MAX_ADC_CLK_FREQ {
254 panic!(
255 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
256 MAX_ADC_CLK_FREQ.0 / 1_000_000
257 );
258 }
154 259
155 fn power_up(&mut self) {
156 T::regs().cr().modify(|reg| { 260 T::regs().cr().modify(|reg| {
157 reg.set_deeppwd(false); 261 reg.set_deeppwd(false);
158 reg.set_advregen(true); 262 reg.set_advregen(true);
159 }); 263 });
160 264
161 blocking_delay_us(20); 265 blocking_delay_us(20);
162 }
163 266
164 fn configure_differential_inputs(&mut self) {
165 T::regs().difsel().modify(|w| { 267 T::regs().difsel().modify(|w| {
166 for n in 0..18 { 268 for n in 0..18 {
167 w.set_difsel(n, Difsel::SINGLE_ENDED); 269 w.set_difsel(n, Difsel::SINGLE_ENDED);
168 } 270 }
169 }); 271 });
170 }
171 272
172 fn calibrate(&mut self) {
173 T::regs().cr().modify(|w| { 273 T::regs().cr().modify(|w| {
174 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 274 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
175 }); 275 });
@@ -189,120 +289,79 @@ impl<'d, T: Instance> Adc<'d, T> {
189 while T::regs().cr().read().adcal() {} 289 while T::regs().cr().read().adcal() {}
190 290
191 blocking_delay_us(20); 291 blocking_delay_us(20);
192 }
193 292
194 fn enable(&mut self) { 293 T::regs().enable();
195 // Make sure bits are off
196 while T::regs().cr().read().addis() {
197 // spin
198 }
199
200 if !T::regs().cr().read().aden() {
201 // Enable ADC
202 T::regs().isr().modify(|reg| {
203 reg.set_adrdy(true);
204 });
205 T::regs().cr().modify(|reg| {
206 reg.set_aden(true);
207 });
208
209 while !T::regs().isr().read().adrdy() {
210 // spin
211 }
212 }
213 }
214 294
215 fn configure(&mut self) {
216 // single conversion mode, software trigger 295 // single conversion mode, software trigger
217 T::regs().cfgr().modify(|w| { 296 T::regs().cfgr().modify(|w| {
218 w.set_cont(false); 297 w.set_cont(false);
219 w.set_exten(Exten::DISABLED); 298 w.set_exten(Exten::DISABLED);
220 }); 299 });
300
301 if let Some(dual) = config.dual_mode {
302 T::common_regs().ccr().modify(|reg| {
303 reg.set_dual(dual);
304 })
305 }
306
307 if let Some(resolution) = config.resolution {
308 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
309 }
310
311 #[cfg(stm32g4)]
312 if let Some(shift) = config.oversampling_shift {
313 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
314 }
315
316 #[cfg(stm32g4)]
317 if let Some(ratio) = config.oversampling_ratio {
318 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
319 }
320
321 #[cfg(stm32g4)]
322 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
323 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
324 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
325 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
326 }
327
328 Self { adc }
221 } 329 }
222 330
223 /// Enable reading the voltage reference internal channel. 331 /// Enable reading the voltage reference internal channel.
224 pub fn enable_vrefint(&self) -> VrefInt 332 pub fn enable_vrefint(&self) -> super::VrefInt
225 where 333 where
226 T: VrefChannel, 334 T: super::SpecialConverter<super::VrefInt>,
227 { 335 {
228 T::common_regs().ccr().modify(|reg| { 336 T::common_regs().ccr().modify(|reg| {
229 reg.set_vrefen(true); 337 reg.set_vrefen(true);
230 }); 338 });
231 339
232 VrefInt {} 340 super::VrefInt {}
233 } 341 }
234 342
235 /// Enable reading the temperature internal channel. 343 /// Enable reading the temperature internal channel.
236 pub fn enable_temperature(&self) -> Temperature 344 pub fn enable_temperature(&self) -> super::Temperature
237 where 345 where
238 T: TemperatureChannel, 346 T: super::SpecialConverter<super::Temperature>,
239 { 347 {
240 T::common_regs().ccr().modify(|reg| { 348 T::common_regs().ccr().modify(|reg| {
241 reg.set_vsenseen(true); 349 reg.set_vsenseen(true);
242 }); 350 });
243 351
244 Temperature {} 352 super::Temperature {}
245 } 353 }
246 354
247 /// Enable reading the vbat internal channel. 355 /// Enable reading the vbat internal channel.
248 pub fn enable_vbat(&self) -> Vbat 356 pub fn enable_vbat(&self) -> super::Vbat
249 where 357 where
250 T: VBatChannel, 358 T: super::SpecialConverter<super::Vbat>,
251 { 359 {
252 T::common_regs().ccr().modify(|reg| { 360 T::common_regs().ccr().modify(|reg| {
253 reg.set_vbaten(true); 361 reg.set_vbaten(true);
254 }); 362 });
255 363
256 Vbat {} 364 super::Vbat {}
257 }
258
259 /// Enable differential channel.
260 /// Caution:
261 /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i]
262 /// is connected to another channel. As a consequence, this channel is no longer usable in
263 /// single-ended mode or in differential mode and must never be configured to be converted.
264 /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the
265 /// channel on the other ADC unusable. The only exception is when ADC master and the slave
266 /// operate in interleaved mode.
267 #[cfg(stm32g4)]
268 pub fn set_differential_channel(&mut self, ch: usize, enable: bool) {
269 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
270 T::regs().difsel().modify(|w| {
271 w.set_difsel(
272 ch,
273 if enable {
274 Difsel::DIFFERENTIAL
275 } else {
276 Difsel::SINGLE_ENDED
277 },
278 );
279 });
280 T::regs().cr().modify(|w| w.set_aden(true));
281 }
282
283 #[cfg(stm32g4)]
284 pub fn set_differential(&mut self, channel: &mut impl AdcChannel<T>, enable: bool) {
285 self.set_differential_channel(channel.channel() as usize, enable);
286 }
287
288 /// Set oversampling shift.
289 #[cfg(stm32g4)]
290 pub fn set_oversampling_shift(&mut self, shift: u8) {
291 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
292 }
293
294 /// Set oversampling ratio.
295 #[cfg(stm32g4)]
296 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
297 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
298 }
299
300 /// Enable oversampling in regular mode.
301 #[cfg(stm32g4)]
302 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
303 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
304 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
305 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
306 } 365 }
307 366
308 // Reads that are not implemented as INJECTED in "blocking_read" 367 // Reads that are not implemented as INJECTED in "blocking_read"
@@ -318,260 +377,215 @@ impl<'d, T: Instance> Adc<'d, T> {
318 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); 377 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
319 // } 378 // }
320 379
321 /// Set the ADC sample time. 380 /// Configures the ADC for injected conversions.
322 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
323 self.sample_time = sample_time;
324 }
325
326 /// Set the ADC resolution.
327 pub fn set_resolution(&mut self, resolution: Resolution) {
328 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
329 }
330
331 /// Perform a single conversion.
332 fn convert(&mut self) -> u16 {
333 T::regs().isr().modify(|reg| {
334 reg.set_eos(true);
335 reg.set_eoc(true);
336 });
337
338 // Start conversion
339 T::regs().cr().modify(|reg| {
340 reg.set_adstart(true);
341 });
342
343 while !T::regs().isr().read().eos() {
344 // spin
345 }
346
347 T::regs().dr().read().0 as u16
348 }
349
350 /// Read an ADC pin.
351 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
352 channel.setup();
353
354 self.read_channel(channel)
355 }
356
357 /// Read one or multiple ADC channels using DMA.
358 /// 381 ///
359 /// `sequence` iterator and `readings` must have the same length. 382 /// Injected conversions are separate from the regular conversion sequence and are typically
383 /// triggered by software or an external event. This method sets up a fixed-length sequence of
384 /// injected channels with specified sample times, the trigger source, and whether the end-of-sequence
385 /// interrupt should be enabled.
360 /// 386 ///
361 /// Example 387 /// # Parameters
362 /// ```rust,ignore 388 /// - `sequence`: An array of tuples containing the ADC channels and their sample times. The length
363 /// use embassy_stm32::adc::{Adc, AdcChannel} 389 /// `N` determines the number of injected ranks to configure (maximum 4 for STM32).
390 /// - `trigger`: The trigger source that starts the injected conversion sequence.
391 /// - `interrupt`: If `true`, enables the end-of-sequence (JEOS) interrupt for injected conversions.
364 /// 392 ///
365 /// let mut adc = Adc::new(p.ADC1); 393 /// # Returns
366 /// let mut adc_pin0 = p.PA0.into(); 394 /// An `InjectedAdc<T, N>` instance that represents the configured injected sequence. The returned
367 /// let mut adc_pin1 = p.PA1.into(); 395 /// type encodes the sequence length `N` in its type, ensuring that reads return exactly `N` samples.
368 /// let mut measurements = [0u16; 2];
369 /// 396 ///
370 /// adc.read( 397 /// # Panics
371 /// p.DMA1_CH2.reborrow(), 398 /// This function will panic if:
372 /// [ 399 /// - `sequence` is empty.
373 /// (&mut *adc_pin0, SampleTime::CYCLES160_5), 400 /// - `sequence` length exceeds the maximum number of injected ranks (`NR_INJECTED_RANKS`).
374 /// (&mut *adc_pin1, SampleTime::CYCLES160_5), 401 ///
375 /// ] 402 /// # Notes
376 /// .into_iter(), 403 /// - Injected conversions can run independently of regular ADC conversions.
377 /// &mut measurements, 404 /// - The order of channels in `sequence` determines the rank order in the injected sequence.
378 /// ) 405 /// - Accessing samples beyond `N` will result in a panic; use the returned type
379 /// .await; 406 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
380 /// defmt::info!("measurements: {}", measurements); 407 pub fn setup_injected_conversions<'a, const N: usize>(
381 /// ``` 408 self,
382 pub async fn read( 409 sequence: [(AnyAdcChannel<'a, T>, SampleTime); N],
383 &mut self, 410 trigger: ConversionTrigger,
384 rx_dma: Peri<'_, impl RxDma<T>>, 411 interrupt: bool,
385 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, 412 ) -> InjectedAdc<'a, T, N> {
386 readings: &mut [u16], 413 assert!(N != 0, "Read sequence cannot be empty");
387 ) {
388 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
389 assert!(
390 sequence.len() == readings.len(),
391 "Sequence length must be equal to readings length"
392 );
393 assert!( 414 assert!(
394 sequence.len() <= 16, 415 N <= NR_INJECTED_RANKS,
395 "Asynchronous read sequence cannot be more than 16 in length" 416 "Read sequence cannot be more than {} in length",
417 NR_INJECTED_RANKS
396 ); 418 );
397 419
398 // Ensure no conversions are ongoing and ADC is enabled. 420 T::regs().enable();
399 Self::cancel_conversions();
400 self.enable();
401 421
402 // Set sequence length 422 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
403 T::regs().sqr1().modify(|w| {
404 w.set_l(sequence.len() as u8 - 1);
405 });
406
407 // Configure channels and ranks
408 for (_i, (channel, sample_time)) in sequence.enumerate() {
409 Self::configure_channel(channel, sample_time);
410 423
411 match _i { 424 for (n, (channel, sample_time)) in sequence.iter().enumerate() {
412 0..=3 => { 425 let sample_time = sample_time.clone().into();
413 T::regs().sqr1().modify(|w| { 426 if channel.channel() <= 9 {
414 w.set_sq(_i, channel.channel()); 427 T::regs()
415 }); 428 .smpr()
416 } 429 .modify(|reg| reg.set_smp(channel.channel() as _, sample_time));
417 4..=8 => { 430 } else {
418 T::regs().sqr2().modify(|w| { 431 T::regs()
419 w.set_sq(_i - 4, channel.channel()); 432 .smpr2()
420 }); 433 .modify(|reg| reg.set_smp((channel.channel() - 10) as _, sample_time));
421 }
422 9..=13 => {
423 T::regs().sqr3().modify(|w| {
424 w.set_sq(_i - 9, channel.channel());
425 });
426 }
427 14..=15 => {
428 T::regs().sqr4().modify(|w| {
429 w.set_sq(_i - 14, channel.channel());
430 });
431 }
432 _ => unreachable!(),
433 } 434 }
434 }
435
436 // Set continuous mode with oneshot dma.
437 // Clear overrun flag before starting transfer.
438 T::regs().isr().modify(|reg| {
439 reg.set_ovr(true);
440 });
441 435
442 T::regs().cfgr().modify(|reg| { 436 let idx = match n {
443 reg.set_discen(false); 437 0..=3 => n,
444 reg.set_cont(true); 438 4..=8 => n - 4,
445 reg.set_dmacfg(Dmacfg::ONE_SHOT); 439 9..=13 => n - 9,
446 reg.set_dmaen(Dmaen::ENABLE); 440 14..=15 => n - 14,
447 }); 441 _ => unreachable!(),
448 442 };
449 let request = rx_dma.request();
450 let transfer = unsafe {
451 Transfer::new_read(
452 rx_dma,
453 request,
454 T::regs().dr().as_ptr() as *mut u16,
455 readings,
456 Default::default(),
457 )
458 };
459
460 // Start conversion
461 T::regs().cr().modify(|reg| {
462 reg.set_adstart(true);
463 });
464 443
465 // Wait for conversion sequence to finish. 444 T::regs().jsqr().modify(|w| w.set_jsq(idx, channel.channel()));
466 transfer.await; 445 }
467 446
468 // Ensure conversions are finished. 447 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
469 Self::cancel_conversions();
470 448
471 // Reset configuration. 449 // Set external trigger for injected conversion sequence
472 T::regs().cfgr().modify(|reg| { 450 // Possible trigger values are seen in Table 167 in RM0440 Rev 9
473 reg.set_cont(false); 451 T::regs().jsqr().modify(|r| {
452 r.set_jextsel(trigger.channel);
453 r.set_jexten(trigger.edge);
474 }); 454 });
475 }
476
477 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
478 // Configure channel
479 Self::set_channel_sample_time(channel.channel(), sample_time);
480 }
481 455
482 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 456 // Enable end of injected sequence interrupt
483 Self::configure_channel(channel, self.sample_time); 457 T::regs().ier().modify(|r| r.set_jeosie(interrupt));
484 #[cfg(stm32h7)]
485 {
486 T::regs().cfgr2().modify(|w| w.set_lshift(0));
487 T::regs()
488 .pcsel()
489 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
490 }
491 458
492 T::regs().sqr1().write(|reg| { 459 Self::start_injected_conversions();
493 reg.set_sq(0, channel.channel());
494 reg.set_l(0);
495 });
496 460
497 self.convert() 461 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
498 } 462 }
499 463
500 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 464 /// Configures ADC for both regular conversions with a ring-buffered DMA and injected conversions.
501 let sample_time = sample_time.into(); 465 ///
502 if ch <= 9 { 466 /// # Parameters
503 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); 467 /// - `dma`: The DMA peripheral to use for the ring-buffered ADC transfers.
504 } else { 468 /// - `dma_buf`: The buffer to store DMA-transferred samples for regular conversions.
505 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); 469 /// - `regular_sequence`: The sequence of channels and their sample times for regular conversions.
470 /// - `regular_conversion_mode`: The mode for regular conversions (e.g., continuous or triggered).
471 /// - `injected_sequence`: An array of channels and sample times for injected conversions (length `N`).
472 /// - `injected_trigger`: The trigger source for injected conversions.
473 /// - `injected_interrupt`: Whether to enable the end-of-sequence interrupt for injected conversions.
474 ///
475 /// Injected conversions are typically used with interrupts. If ADC1 and ADC2 are used in dual mode,
476 /// it is recommended to enable interrupts only for the ADC whose sequence takes the longest to complete.
477 ///
478 /// # Returns
479 /// A tuple containing:
480 /// 1. `RingBufferedAdc<'a, T>` — the configured ADC for regular conversions using DMA.
481 /// 2. `InjectedAdc<T, N>` — the configured ADC for injected conversions.
482 ///
483 /// # Safety
484 /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the
485 /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently.
486 /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way.
487 pub fn into_ring_buffered_and_injected<'a, 'b, const N: usize>(
488 self,
489 dma: Peri<'a, impl RxDma<T>>,
490 dma_buf: &'a mut [u16],
491 regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>,
492 regular_conversion_mode: RegularConversionMode,
493 injected_sequence: [(AnyAdcChannel<'b, T>, SampleTime); N],
494 injected_trigger: ConversionTrigger,
495 injected_interrupt: bool,
496 ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<'b, T, N>) {
497 unsafe {
498 (
499 Self {
500 adc: self.adc.clone_unchecked(),
501 }
502 .into_ring_buffered(dma, dma_buf, regular_sequence, regular_conversion_mode),
503 Self {
504 adc: self.adc.clone_unchecked(),
505 }
506 .setup_injected_conversions(injected_sequence, injected_trigger, injected_interrupt),
507 )
506 } 508 }
507 } 509 }
508 510
509 fn cancel_conversions() { 511 /// Stop injected conversions
512 pub(super) fn stop_injected_conversions() {
510 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 513 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
511 T::regs().cr().modify(|reg| { 514 T::regs().cr().modify(|reg| {
512 reg.set_adstp(Adstp::STOP); 515 reg.set_jadstp(Adstp::STOP);
513 }); 516 });
514 while T::regs().cr().read().adstart() {} 517 // The software must poll JADSTART until the bit is reset before assuming the
518 // ADC is completely stopped
519 while T::regs().cr().read().jadstart() {}
515 } 520 }
516 } 521 }
517}
518 522
519/// Implemented for ADCs that have a Temperature channel 523 /// Start injected ADC conversion
520pub trait TemperatureChannel { 524 pub(super) fn start_injected_conversions() {
521 const CHANNEL: u8; 525 T::regs().cr().modify(|reg| {
522} 526 reg.set_jadstart(true);
523/// Implemented for ADCs that have a Vref channel 527 });
524pub trait VrefChannel { 528 }
525 const CHANNEL: u8;
526} 529}
527/// Implemented for ADCs that have a VBat channel 530
528pub trait VBatChannel { 531impl<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> InjectedAdc<'a, T, N> {
529 const CHANNEL: u8; 532 /// Read sampled data from all injected ADC injected ranks
533 /// Clear the JEOS flag to allow a new injected sequence
534 pub(super) fn read_injected_data() -> [u16; N] {
535 let mut data = [0u16; N];
536 for i in 0..N {
537 data[i] = T::regs().jdr(i).read().jdata();
538 }
539
540 // Clear JEOS by writing 1
541 T::regs().isr().modify(|r| r.set_jeos(true));
542 data
543 }
530} 544}
531 545
532#[cfg(stm32g4)] 546#[cfg(stm32g4)]
533mod g4 { 547mod g4 {
534 pub use super::*; 548 use crate::adc::{SealedSpecialConverter, Temperature, Vbat, VrefInt};
535 549
536 impl TemperatureChannel for crate::peripherals::ADC1 { 550 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC1 {
537 const CHANNEL: u8 = 16; 551 const CHANNEL: u8 = 16;
538 } 552 }
539 553
540 impl VrefChannel for crate::peripherals::ADC1 { 554 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC1 {
541 const CHANNEL: u8 = 18; 555 const CHANNEL: u8 = 18;
542 } 556 }
543 557
544 impl VBatChannel for crate::peripherals::ADC1 { 558 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC1 {
545 const CHANNEL: u8 = 17; 559 const CHANNEL: u8 = 17;
546 } 560 }
547 561
548 #[cfg(peri_adc3_common)] 562 #[cfg(peri_adc3_common)]
549 impl VrefChannel for crate::peripherals::ADC3 { 563 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC3 {
550 const CHANNEL: u8 = 18; 564 const CHANNEL: u8 = 18;
551 } 565 }
552 566
553 #[cfg(peri_adc3_common)] 567 #[cfg(peri_adc3_common)]
554 impl VBatChannel for crate::peripherals::ADC3 { 568 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC3 {
555 const CHANNEL: u8 = 17; 569 const CHANNEL: u8 = 17;
556 } 570 }
557 571
558 #[cfg(not(stm32g4x1))] 572 #[cfg(not(stm32g4x1))]
559 impl VrefChannel for crate::peripherals::ADC4 { 573 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC4 {
560 const CHANNEL: u8 = 18; 574 const CHANNEL: u8 = 18;
561 } 575 }
562 576
563 #[cfg(not(stm32g4x1))] 577 #[cfg(not(stm32g4x1))]
564 impl TemperatureChannel for crate::peripherals::ADC5 { 578 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC5 {
565 const CHANNEL: u8 = 4; 579 const CHANNEL: u8 = 4;
566 } 580 }
567 581
568 #[cfg(not(stm32g4x1))] 582 #[cfg(not(stm32g4x1))]
569 impl VrefChannel for crate::peripherals::ADC5 { 583 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC5 {
570 const CHANNEL: u8 = 18; 584 const CHANNEL: u8 = 18;
571 } 585 }
572 586
573 #[cfg(not(stm32g4x1))] 587 #[cfg(not(stm32g4x1))]
574 impl VBatChannel for crate::peripherals::ADC5 { 588 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC5 {
575 const CHANNEL: u8 = 17; 589 const CHANNEL: u8 = 17;
576 } 590 }
577} 591}
@@ -579,13 +593,13 @@ mod g4 {
579// TODO this should look at each ADC individually and impl the correct channels 593// TODO this should look at each ADC individually and impl the correct channels
580#[cfg(stm32h7)] 594#[cfg(stm32h7)]
581mod h7 { 595mod h7 {
582 impl<T: Instance> TemperatureChannel for T { 596 impl<T: Instance> SealedSpecialConverter<Temperature> for T {
583 const CHANNEL: u8 = 18; 597 const CHANNEL: u8 = 18;
584 } 598 }
585 impl<T: Instance> VrefChannel for T { 599 impl<T: Instance> SealedSpecialConverter<VrefInt> for T {
586 const CHANNEL: u8 = 19; 600 const CHANNEL: u8 = 19;
587 } 601 }
588 impl<T: Instance> VBatChannel for T { 602 impl<T: Instance> SealedSpecialConverter<Vbat> for T {
589 // TODO this should be 14 for H7a/b/35 603 // TODO this should be 14 for H7a/b/35
590 const CHANNEL: u8 = 17; 604 const CHANNEL: u8 = 17;
591 } 605 }