Skip to content

Commit 77dace3

Browse files
authored
Merge pull request #42 from mattico/adc-cal
ADC: Implement calibration
2 parents 32d1d4c + 0fbb774 commit 77dace3

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

examples/adc.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@ use rt::entry;
1717
#[entry]
1818
fn main() -> ! {
1919
let dp = stm32::Peripherals::take().expect("cannot take peripherals");
20+
let cp = stm32::CorePeripherals::take().expect("cannot take core peripherals");
2021
let mut rcc = dp.RCC.constrain();
22+
let mut delay = cp.SYST.delay(&mut rcc);
2123

2224
let gpioa = dp.GPIOA.split(&mut rcc);
2325

2426
let mut adc = dp.ADC.constrain(&mut rcc);
2527
adc.set_sample_time(SampleTime::T_80);
2628
adc.set_precision(Precision::B_12);
29+
delay.delay(20.us()); // Wait for ADC voltage regulator to stabilize
30+
adc.calibrate();
2731

2832
let mut adc_pin = gpioa.pa0.into_analog();
2933
let mut vtemp = VTemp::new();

src/analog/adc.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ pub struct Adc {
5454
precision: Precision,
5555
}
5656

57+
/// Contains the calibration factors for the ADC which can be reused with [`Adc::set_calibration()`]
58+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
59+
pub struct CalibrationFactor(pub u8);
60+
5761
impl Adc {
5862
pub fn new(adc: ADC, rcc: &mut Rcc) -> Self {
5963
// Enable ADC clocks
@@ -68,6 +72,41 @@ impl Adc {
6872
}
6973
}
7074

75+
/// Runs the calibration routine on the ADC
76+
///
77+
/// Wait for tADCVREG_SETUP (20us on STM32G071x8) after calling [`Self::new()`] before calibrating, to wait for the
78+
/// ADC voltage regulator to stabilize.
79+
///
80+
/// Do not call if an ADC reading is ongoing.
81+
pub fn calibrate(&mut self) {
82+
self.rb.cr.modify(|_, w| w.adcal().set_bit());
83+
while self.rb.cr.read().adcal().bit_is_set() {}
84+
}
85+
86+
/// Returns the calibration factors used by the ADC
87+
///
88+
/// The ADC does not have a factory-stored calibration, [`Self::calibrate()`] must be run before calling this
89+
/// for the returned value to be useful.
90+
///
91+
/// The ADC loses its calibration factors when Standby or Vbat mode is entered. Saving and restoring the calibration
92+
/// factors can be used to recalibrate the ADC after waking up from sleep more quickly than re-running calibraiton.
93+
/// Note that VDDA changes and to a lesser extent temperature changes affect the ADC operating conditions and
94+
/// calibration should be run again for the best accuracy.
95+
pub fn get_calibration(&self) -> CalibrationFactor {
96+
CalibrationFactor(self.rb.calfact.read().calfact().bits())
97+
}
98+
99+
/// Writes the calibration factors used by the ADC
100+
///
101+
/// See [`Self::get_calibration()`].
102+
///
103+
/// Do not call if an ADC reading is ongoing.
104+
pub fn set_calibration(&mut self, calfact: CalibrationFactor) {
105+
self.rb
106+
.calfact
107+
.write(|w| unsafe { w.calfact().bits(calfact.0) });
108+
}
109+
71110
/// Set the Adc sampling time
72111
pub fn set_sample_time(&mut self, t_samp: SampleTime) {
73112
self.sample_time = t_samp;

0 commit comments

Comments
 (0)