Skip to content

Commit 9d1e3fe

Browse files
authored
ADC improvements (#121)
* adc: correct pinouts for all stm32gxx * adc: expose VDDA voltage read * adc: add temperature reading
1 parent 67fdbd3 commit 9d1e3fe

File tree

1 file changed

+96
-44
lines changed

1 file changed

+96
-44
lines changed

src/analog/adc.rs

Lines changed: 96 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ pub struct Adc {
106106
sample_time: SampleTime,
107107
align: Align,
108108
precision: Precision,
109-
vdda_mv: Option<u32>,
109+
vref_cache: Option<u16>,
110110
}
111111

112112
/// Contains the calibration factors for the ADC which can be reused with [`Adc::set_calibration()`]
@@ -125,7 +125,7 @@ impl Adc {
125125
sample_time: SampleTime::T_2,
126126
align: Align::Right,
127127
precision: Precision::B_12,
128-
vdda_mv: None,
128+
vref_cache: None,
129129
}
130130
}
131131

@@ -228,41 +228,81 @@ impl Adc {
228228
self.rb.ier.modify(|_, w| w.eocie().clear_bit()); // end of sequence interupt disable
229229
}
230230

231+
/// Read actual VREF voltage using the internal reference
232+
///
233+
/// If oversampling is enabled, the return value is scaled down accordingly.
234+
/// The product of the return value and any ADC reading always gives correct voltage in 4096ths of mV
235+
/// regardless of oversampling and shift settings provided that these settings remain the same.
236+
pub fn read_vref(&mut self) -> nb::Result<u16, ()> {
237+
let mut vref = VRef::new();
238+
let vref_val: u32 = if vref.enabled(self) {
239+
self.read(&mut vref)?
240+
} else {
241+
vref.enable(self);
242+
let vref_val = self.read(&mut vref)?;
243+
vref.disable(self);
244+
vref_val
245+
};
246+
247+
let vref_cal: u32 = unsafe {
248+
// DS12766 3.13.2
249+
ptr::read_volatile(0x1FFF_75AA as *const u16) as u32
250+
};
251+
252+
// RM0454 14.9 Calculating the actual VDDA voltage using the internal reference voltage
253+
// V_DDA = 3 V x VREFINT_CAL / VREFINT_DATA
254+
let vref = (vref_cal * 3_000_u32 / vref_val) as u16;
255+
self.vref_cache = Some(vref);
256+
Ok(vref)
257+
}
258+
259+
/// Get VREF value using cached value if possible
260+
///
261+
/// See `read_vref` for more details.
262+
pub fn get_vref_cached(&mut self) -> nb::Result<u16, ()> {
263+
if let Some(vref) = self.vref_cache {
264+
Ok(vref)
265+
} else {
266+
self.read_vref()
267+
}
268+
}
269+
231270
pub fn read_voltage<PIN: Channel<Adc, ID = u8>>(
232271
&mut self,
233272
pin: &mut PIN,
234273
) -> nb::Result<u16, ()> {
235-
let vdda_mv = if let Some(vdda_mv) = self.vdda_mv {
236-
vdda_mv
237-
} else {
238-
let mut vref = VRef::new();
239-
let vref_val: u32 = if vref.enabled(self) {
240-
self.read(&mut vref)?
241-
} else {
242-
vref.enable(self);
243-
let vref_val = self.read(&mut vref)?;
244-
vref.disable(self);
245-
vref_val
246-
};
247-
248-
let vref_cal: u32 = unsafe {
249-
// DS12766 3.13.2
250-
ptr::read_volatile(0x1FFF_75AA as *const u16) as u32
251-
};
252-
253-
// RM0454 14.9 Calculating the actual VDDA voltage using the internal reference voltage
254-
// V_DDA = 3 V x VREFINT_CAL / VREFINT_DATA
255-
let vdda_mv = vref_cal * 3_000_u32 / vref_val;
256-
self.vdda_mv = Some(vdda_mv);
257-
vdda_mv
258-
};
274+
let vref = self.get_vref_cached()?;
259275

260276
self.read(pin).map(|raw: u32| {
261-
let adc_mv = (vdda_mv * raw) >> 12;
277+
let adc_mv = (vref as u32 * raw) >> 12;
262278
adc_mv as u16
263279
})
264280
}
265281

282+
pub fn read_temperature(&mut self) -> nb::Result<i16, ()> {
283+
let mut vtemp = VTemp::new();
284+
let vtemp_voltage: u16 = if vtemp.enabled(self) {
285+
self.read_voltage(&mut vtemp)?
286+
} else {
287+
vtemp.enable(self);
288+
let vtemp_voltage = self.read_voltage(&mut vtemp)?;
289+
vtemp.disable(self);
290+
vtemp_voltage
291+
};
292+
293+
let ts_cal1: u32 = unsafe {
294+
// DS12991 3.14.1
295+
// at 3000 mV Vref+ and 30 degC
296+
ptr::read_volatile(0x1FFF_75A8 as *const u16) as u32
297+
};
298+
299+
let v30 = (3000_u32 * ts_cal1) >> 12; // mV
300+
// 2.5 mV/degC
301+
let t = 30 + (vtemp_voltage as i32 - v30 as i32) * 10 / 25;
302+
303+
Ok(t as i16)
304+
}
305+
266306
pub fn release(self) -> ADC {
267307
self.rb
268308
}
@@ -453,21 +493,33 @@ macro_rules! adc_pin {
453493
}
454494

455495
adc_pin! {
456-
Channel0: (PA0<Analog>, 0u8),
457-
Channel1: (PA1<Analog>, 1u8),
458-
Channel2: (PA2<Analog>, 2u8),
459-
Channel3: (PA3<Analog>, 3u8),
460-
Channel4: (PA4<Analog>, 4u8),
461-
Channel5: (PA5<Analog>, 5u8),
462-
Channel6: (PA6<Analog>, 6u8),
463-
Channel7: (PA7<Analog>, 7u8),
464-
Channel8: (PB0<Analog>, 8u8),
465-
Channel9: (PB1<Analog>, 9u8),
466-
Channel10: (PB2<Analog>, 10u8),
467-
Channel11: (PB10<Analog>, 11u8),
468-
Channel11: (PB7<Analog>, 11u8),
469-
Channel15: (PB11<Analog>, 15u8),
470-
Channel16: (PB12<Analog>, 16u8),
471-
Channel17: (PC4<Analog>, 17u8),
472-
Channel18: (PC5<Analog>, 18u8),
496+
Channel0: (gpioa::PA0<Analog>, 0u8),
497+
Channel1: (gpioa::PA1<Analog>, 1u8),
498+
Channel2: (gpioa::PA2<Analog>, 2u8),
499+
Channel3: (gpioa::PA3<Analog>, 3u8),
500+
Channel4: (gpioa::PA4<Analog>, 4u8),
501+
Channel5: (gpioa::PA5<Analog>, 5u8),
502+
Channel6: (gpioa::PA6<Analog>, 6u8),
503+
Channel7: (gpioa::PA7<Analog>, 7u8),
504+
Channel8: (gpiob::PB0<Analog>, 8u8),
505+
Channel9: (gpiob::PB1<Analog>, 9u8),
506+
Channel10: (gpiob::PB2<Analog>, 10u8),
507+
Channel11: (gpiob::PB10<Analog>, 11u8),
508+
Channel15: (gpiob::PB11<Analog>, 15u8),
509+
Channel16: (gpiob::PB12<Analog>, 16u8),
510+
}
511+
512+
#[cfg(any(feature = "stm32g030", feature = "stm32g031", feature = "stm32g041",))]
513+
adc_pin! {
514+
Channel11: (gpiob::PB7<Analog>, 11u8),
515+
Channel15: (gpioa::PA11<Analog>, 15u8),
516+
Channel16: (gpioa::PA12<Analog>, 16u8),
517+
Channel17: (gpioa::PA13<Analog>, 17u8),
518+
Channel18: (gpioa::PA14<Analog>, 18u8),
519+
}
520+
521+
#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081",))]
522+
adc_pin! {
523+
Channel17: (gpioc::PC4<Analog>, 17u8),
524+
Channel18: (gpioc::PC5<Analog>, 18u8),
473525
}

0 commit comments

Comments
 (0)