Skip to content

Commit 4fb9450

Browse files
authored
Temperature calculation improvements (#111)
* Improve temperature calculation * Minor cleanup
1 parent 66b9952 commit 4fb9450

File tree

4 files changed

+92
-16
lines changed

4 files changed

+92
-16
lines changed

examples/adc-continious-dma.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod utils;
55

66
use crate::hal::{
77
adc::{
8+
config,
89
config::{Continuous, Dma as AdcDma, SampleTime, Sequence},
910
AdcClaim, ClockSource, Temperature, Vref,
1011
},
@@ -13,13 +14,11 @@ use crate::hal::{
1314
gpio::GpioExt,
1415
pwr::PwrExt,
1516
rcc::{Config, RccExt},
17+
signature::{VrefCal, VDDA_CALIB},
1618
stm32::Peripherals,
1719
};
1820
use stm32g4xx_hal as hal;
1921

20-
use stm32g4xx_hal::adc::config;
21-
use stm32g4xx_hal::signature::{VrefCal, VDDA_CALIB};
22-
2322
use cortex_m_rt::entry;
2423
use utils::logger::info;
2524

@@ -92,8 +91,11 @@ fn main() -> ! {
9291
let vref =
9392
Vref::sample_to_millivolts_ext((b[2] + b[5]) / 2, vdda, config::Resolution::Twelve);
9493
info!("vref: {}mV", vref);
95-
let raw_temp = (((b[1] + b[4]) / 2) as f32 * (vdda as f32 / 3000.0)) as u16;
96-
let temp = Temperature::temperature_to_degrees_centigrade(raw_temp);
94+
let temp = Temperature::temperature_to_degrees_centigrade(
95+
(b[1] + b[4]) / 2,
96+
vdda as f32 / 1000.,
97+
config::Resolution::Twelve,
98+
);
9799
info!("temp: {}°C", temp);
98100
}
99101
}

examples/adc-continious.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33

44
use crate::hal::{
55
adc::{
6-
config::{Continuous, SampleTime, Sequence},
6+
config::{Continuous, Resolution, SampleTime, Sequence},
77
AdcClaim, ClockSource, Temperature, Vref,
88
},
99
delay::SYSTDelayExt,
1010
gpio::GpioExt,
1111
pwr::PwrExt,
1212
rcc::{Config, RccExt},
13+
signature::{VrefCal, VDDA_CALIB},
1314
stm32::Peripherals,
1415
};
1516
use stm32g4xx_hal as hal;
@@ -65,11 +66,17 @@ fn main() -> ! {
6566
info!("pa3: {}mV", millivolts);
6667

6768
adc = adc.wait_for_conversion_sequence().unwrap_active();
68-
let millivolts = Vref::sample_to_millivolts(adc.current_sample());
69+
let vref_sample = adc.current_sample();
70+
let millivolts = Vref::sample_to_millivolts(vref_sample);
71+
let vdda = VDDA_CALIB * VrefCal::get().read() as u32 / vref_sample as u32;
6972
info!("vref: {}mV", millivolts);
7073

7174
adc = adc.wait_for_conversion_sequence().unwrap_active();
72-
let millivolts = Temperature::temperature_to_degrees_centigrade(adc.current_sample());
73-
info!("temp: {}℃C", millivolts); // Note: Temperature seems quite low...
75+
let temp = Temperature::temperature_to_degrees_centigrade(
76+
adc.current_sample(),
77+
vdda as f32 / 1000.,
78+
Resolution::Twelve,
79+
);
80+
info!("temp: {}°C", temp);
7481
}
7582
}

examples/adc-one-shot-dma.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use cortex_m_rt::entry;
55

66
use crate::hal::{
77
adc::{
8-
config::{Continuous, Dma as AdcDma, SampleTime, Sequence},
8+
config::{Continuous, Dma as AdcDma, Resolution, SampleTime, Sequence},
99
AdcClaim, ClockSource, Temperature,
1010
},
1111
delay::SYSTDelayExt,
@@ -81,8 +81,11 @@ fn main() -> ! {
8181

8282
let millivolts = adc.sample_to_millivolts(first_buffer[0]);
8383
info!("pa3: {}mV", millivolts);
84-
let millivolts = Temperature::temperature_to_degrees_centigrade(first_buffer[1]);
85-
info!("temp: {}℃C", millivolts); // Note: Temperature seems quite low...
84+
85+
// Assume vdda is 3.3V, see adc-continious.rs for an example of measuring VDDA using VREF
86+
let temp =
87+
Temperature::temperature_to_degrees_centigrade(first_buffer[1], 3.3, Resolution::Twelve);
88+
info!("temp: {}°C", temp);
8689

8790
#[allow(clippy::empty_loop)]
8891
loop {}

src/adc.rs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,76 @@ pub struct Vbat;
6060
/// Core temperature internal signal
6161
pub struct Temperature;
6262
impl Temperature {
63+
/// Precompute the inverse of `VTEMP_CAL_VREFANALOG`, in volts,
64+
/// for floating point calculations
65+
const INV_VREFANALOG_VOLTS: f32 = 1000. / VDDA_CALIB as f32;
66+
/// Temperature at which temperature sensor has been calibrated in production
67+
/// for data into [`VtempCal30`] (tolerance: +-5 DegC) (unit: DegC).
68+
const VTEMP_CAL_T30: u16 = 30;
69+
/// Temperature at which temperature sensor has been calibrated in production
70+
/// for data into [`VtempCal130`] (tolerance: +-5 DegC) (unit: DegC).
71+
const VTEMP_CAL_T130: u16 = 130;
72+
73+
/// Convert a sample to 12 bits. Reference voltages were captured at 12 bits.
74+
const fn to_12b(sample: u16, resolution: config::Resolution) -> u16 {
75+
match resolution {
76+
config::Resolution::Six => sample << 6,
77+
config::Resolution::Eight => sample << 4,
78+
config::Resolution::Ten => sample << 2,
79+
config::Resolution::Twelve => sample,
80+
}
81+
}
82+
83+
/// Convert a raw sample from `Temperature` to deg C.
84+
///
85+
/// ## Arguments
86+
/// * `sample`: ADC sample taken on the [`Temperature`] channel.
87+
/// * `vdda`: Analog reference voltage (vref+) when the temperature
88+
/// sample was taken, in volts.
89+
/// * `resolution`: Configured ADC resolution.
90+
#[inline(always)]
91+
pub fn temperature_to_degrees_centigrade(
92+
sample: u16,
93+
vdda: f32,
94+
resolution: config::Resolution,
95+
) -> f32 {
96+
// Reference measurements were taken at 12 bits
97+
let sample_12b = Self::to_12b(sample, resolution);
98+
99+
// Normalize for the difference in VDDA
100+
let sample_normalized = sample_12b as f32 * (vdda * Self::INV_VREFANALOG_VOLTS);
101+
102+
((sample_normalized - VtempCal30::get().read() as f32)
103+
* ((Self::VTEMP_CAL_T130 - Self::VTEMP_CAL_T30) as f32))
104+
/ ((VtempCal130::get().read() - VtempCal30::get().read()) as f32)
105+
+ Self::VTEMP_CAL_T30 as f32
106+
}
107+
63108
/// Convert a raw sample from `Temperature` to deg C
109+
///
110+
/// ## Arguments
111+
/// * `sample`: ADC sample taken on the [`Temperature`] channel.
112+
/// * `vdda`: Analog reference voltage (vref+) when the temperature
113+
/// sample was taken, in millivolts.
114+
/// * `resolution`: Configured ADC resolution.
64115
#[inline(always)]
65-
pub fn temperature_to_degrees_centigrade(sample: u16) -> f32 {
66-
((130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
67-
* (sample as f32 - VtempCal30::get().read() as f32))
68-
+ 30.0
116+
pub fn temperature_to_degrees_centigrade_coarse(
117+
sample: u16,
118+
vdda: u32,
119+
resolution: config::Resolution,
120+
) -> i16 {
121+
// Reference measurements were taken at 12 bits
122+
let sample_12b = Self::to_12b(sample, resolution);
123+
124+
// Normalize for the difference in VDDA
125+
let sample_normalized = ((sample_12b as u32 * vdda) / VDDA_CALIB) as u16;
126+
127+
let t = ((sample_normalized as i32 - VtempCal30::get().read() as i32)
128+
* ((Self::VTEMP_CAL_T130 - Self::VTEMP_CAL_T30) as i32))
129+
/ ((VtempCal130::get().read() - VtempCal30::get().read()) as i32)
130+
+ Self::VTEMP_CAL_T30 as i32;
131+
132+
t as i16
69133
}
70134
}
71135

0 commit comments

Comments
 (0)