Skip to content

Commit

Permalink
Temperature calculation improvements (#111)
Browse files Browse the repository at this point in the history
* Improve temperature calculation

* Minor cleanup
  • Loading branch information
stabler authored Jan 4, 2024
1 parent 66b9952 commit 4fb9450
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 16 deletions.
12 changes: 7 additions & 5 deletions examples/adc-continious-dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod utils;

use crate::hal::{
adc::{
config,
config::{Continuous, Dma as AdcDma, SampleTime, Sequence},
AdcClaim, ClockSource, Temperature, Vref,
},
Expand All @@ -13,13 +14,11 @@ use crate::hal::{
gpio::GpioExt,
pwr::PwrExt,
rcc::{Config, RccExt},
signature::{VrefCal, VDDA_CALIB},
stm32::Peripherals,
};
use stm32g4xx_hal as hal;

use stm32g4xx_hal::adc::config;
use stm32g4xx_hal::signature::{VrefCal, VDDA_CALIB};

use cortex_m_rt::entry;
use utils::logger::info;

Expand Down Expand Up @@ -92,8 +91,11 @@ fn main() -> ! {
let vref =
Vref::sample_to_millivolts_ext((b[2] + b[5]) / 2, vdda, config::Resolution::Twelve);
info!("vref: {}mV", vref);
let raw_temp = (((b[1] + b[4]) / 2) as f32 * (vdda as f32 / 3000.0)) as u16;
let temp = Temperature::temperature_to_degrees_centigrade(raw_temp);
let temp = Temperature::temperature_to_degrees_centigrade(
(b[1] + b[4]) / 2,
vdda as f32 / 1000.,
config::Resolution::Twelve,
);
info!("temp: {}°C", temp);
}
}
15 changes: 11 additions & 4 deletions examples/adc-continious.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

use crate::hal::{
adc::{
config::{Continuous, SampleTime, Sequence},
config::{Continuous, Resolution, SampleTime, Sequence},
AdcClaim, ClockSource, Temperature, Vref,
},
delay::SYSTDelayExt,
gpio::GpioExt,
pwr::PwrExt,
rcc::{Config, RccExt},
signature::{VrefCal, VDDA_CALIB},
stm32::Peripherals,
};
use stm32g4xx_hal as hal;
Expand Down Expand Up @@ -65,11 +66,17 @@ fn main() -> ! {
info!("pa3: {}mV", millivolts);

adc = adc.wait_for_conversion_sequence().unwrap_active();
let millivolts = Vref::sample_to_millivolts(adc.current_sample());
let vref_sample = adc.current_sample();
let millivolts = Vref::sample_to_millivolts(vref_sample);
let vdda = VDDA_CALIB * VrefCal::get().read() as u32 / vref_sample as u32;
info!("vref: {}mV", millivolts);

adc = adc.wait_for_conversion_sequence().unwrap_active();
let millivolts = Temperature::temperature_to_degrees_centigrade(adc.current_sample());
info!("temp: {}℃C", millivolts); // Note: Temperature seems quite low...
let temp = Temperature::temperature_to_degrees_centigrade(
adc.current_sample(),
vdda as f32 / 1000.,
Resolution::Twelve,
);
info!("temp: {}°C", temp);
}
}
9 changes: 6 additions & 3 deletions examples/adc-one-shot-dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cortex_m_rt::entry;

use crate::hal::{
adc::{
config::{Continuous, Dma as AdcDma, SampleTime, Sequence},
config::{Continuous, Dma as AdcDma, Resolution, SampleTime, Sequence},
AdcClaim, ClockSource, Temperature,
},
delay::SYSTDelayExt,
Expand Down Expand Up @@ -81,8 +81,11 @@ fn main() -> ! {

let millivolts = adc.sample_to_millivolts(first_buffer[0]);
info!("pa3: {}mV", millivolts);
let millivolts = Temperature::temperature_to_degrees_centigrade(first_buffer[1]);
info!("temp: {}℃C", millivolts); // Note: Temperature seems quite low...

// Assume vdda is 3.3V, see adc-continious.rs for an example of measuring VDDA using VREF
let temp =
Temperature::temperature_to_degrees_centigrade(first_buffer[1], 3.3, Resolution::Twelve);
info!("temp: {}°C", temp);

#[allow(clippy::empty_loop)]
loop {}
Expand Down
72 changes: 68 additions & 4 deletions src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,76 @@ pub struct Vbat;
/// Core temperature internal signal
pub struct Temperature;
impl Temperature {
/// Precompute the inverse of `VTEMP_CAL_VREFANALOG`, in volts,
/// for floating point calculations
const INV_VREFANALOG_VOLTS: f32 = 1000. / VDDA_CALIB as f32;
/// Temperature at which temperature sensor has been calibrated in production
/// for data into [`VtempCal30`] (tolerance: +-5 DegC) (unit: DegC).
const VTEMP_CAL_T30: u16 = 30;
/// Temperature at which temperature sensor has been calibrated in production
/// for data into [`VtempCal130`] (tolerance: +-5 DegC) (unit: DegC).
const VTEMP_CAL_T130: u16 = 130;

/// Convert a sample to 12 bits. Reference voltages were captured at 12 bits.
const fn to_12b(sample: u16, resolution: config::Resolution) -> u16 {
match resolution {
config::Resolution::Six => sample << 6,
config::Resolution::Eight => sample << 4,
config::Resolution::Ten => sample << 2,
config::Resolution::Twelve => sample,
}
}

/// Convert a raw sample from `Temperature` to deg C.
///
/// ## Arguments
/// * `sample`: ADC sample taken on the [`Temperature`] channel.
/// * `vdda`: Analog reference voltage (vref+) when the temperature
/// sample was taken, in volts.
/// * `resolution`: Configured ADC resolution.
#[inline(always)]
pub fn temperature_to_degrees_centigrade(
sample: u16,
vdda: f32,
resolution: config::Resolution,
) -> f32 {
// Reference measurements were taken at 12 bits
let sample_12b = Self::to_12b(sample, resolution);

// Normalize for the difference in VDDA
let sample_normalized = sample_12b as f32 * (vdda * Self::INV_VREFANALOG_VOLTS);

((sample_normalized - VtempCal30::get().read() as f32)
* ((Self::VTEMP_CAL_T130 - Self::VTEMP_CAL_T30) as f32))
/ ((VtempCal130::get().read() - VtempCal30::get().read()) as f32)
+ Self::VTEMP_CAL_T30 as f32
}

/// Convert a raw sample from `Temperature` to deg C
///
/// ## Arguments
/// * `sample`: ADC sample taken on the [`Temperature`] channel.
/// * `vdda`: Analog reference voltage (vref+) when the temperature
/// sample was taken, in millivolts.
/// * `resolution`: Configured ADC resolution.
#[inline(always)]
pub fn temperature_to_degrees_centigrade(sample: u16) -> f32 {
((130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
* (sample as f32 - VtempCal30::get().read() as f32))
+ 30.0
pub fn temperature_to_degrees_centigrade_coarse(
sample: u16,
vdda: u32,
resolution: config::Resolution,
) -> i16 {
// Reference measurements were taken at 12 bits
let sample_12b = Self::to_12b(sample, resolution);

// Normalize for the difference in VDDA
let sample_normalized = ((sample_12b as u32 * vdda) / VDDA_CALIB) as u16;

let t = ((sample_normalized as i32 - VtempCal30::get().read() as i32)
* ((Self::VTEMP_CAL_T130 - Self::VTEMP_CAL_T30) as i32))
/ ((VtempCal130::get().read() - VtempCal30::get().read()) as i32)
+ Self::VTEMP_CAL_T30 as i32;

t as i16
}
}

Expand Down

0 comments on commit 4fb9450

Please sign in to comment.