Skip to content

Commit

Permalink
Merge pull request #42 from mattico/adc-cal
Browse files Browse the repository at this point in the history
ADC: Implement calibration
  • Loading branch information
andresv authored Feb 23, 2021
2 parents 32d1d4c + 0fbb774 commit 77dace3
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 0 deletions.
4 changes: 4 additions & 0 deletions examples/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ use rt::entry;
#[entry]
fn main() -> ! {
let dp = stm32::Peripherals::take().expect("cannot take peripherals");
let cp = stm32::CorePeripherals::take().expect("cannot take core peripherals");
let mut rcc = dp.RCC.constrain();
let mut delay = cp.SYST.delay(&mut rcc);

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

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

let mut adc_pin = gpioa.pa0.into_analog();
let mut vtemp = VTemp::new();
Expand Down
39 changes: 39 additions & 0 deletions src/analog/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ pub struct Adc {
precision: Precision,
}

/// Contains the calibration factors for the ADC which can be reused with [`Adc::set_calibration()`]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct CalibrationFactor(pub u8);

impl Adc {
pub fn new(adc: ADC, rcc: &mut Rcc) -> Self {
// Enable ADC clocks
Expand All @@ -68,6 +72,41 @@ impl Adc {
}
}

/// Runs the calibration routine on the ADC
///
/// Wait for tADCVREG_SETUP (20us on STM32G071x8) after calling [`Self::new()`] before calibrating, to wait for the
/// ADC voltage regulator to stabilize.
///
/// Do not call if an ADC reading is ongoing.
pub fn calibrate(&mut self) {
self.rb.cr.modify(|_, w| w.adcal().set_bit());
while self.rb.cr.read().adcal().bit_is_set() {}
}

/// Returns the calibration factors used by the ADC
///
/// The ADC does not have a factory-stored calibration, [`Self::calibrate()`] must be run before calling this
/// for the returned value to be useful.
///
/// The ADC loses its calibration factors when Standby or Vbat mode is entered. Saving and restoring the calibration
/// factors can be used to recalibrate the ADC after waking up from sleep more quickly than re-running calibraiton.
/// Note that VDDA changes and to a lesser extent temperature changes affect the ADC operating conditions and
/// calibration should be run again for the best accuracy.
pub fn get_calibration(&self) -> CalibrationFactor {
CalibrationFactor(self.rb.calfact.read().calfact().bits())
}

/// Writes the calibration factors used by the ADC
///
/// See [`Self::get_calibration()`].
///
/// Do not call if an ADC reading is ongoing.
pub fn set_calibration(&mut self, calfact: CalibrationFactor) {
self.rb
.calfact
.write(|w| unsafe { w.calfact().bits(calfact.0) });
}

/// Set the Adc sampling time
pub fn set_sample_time(&mut self, t_samp: SampleTime) {
self.sample_time = t_samp;
Expand Down

0 comments on commit 77dace3

Please sign in to comment.