From 7d4770dc9e0886978390690f3ffb34c482e62be1 Mon Sep 17 00:00:00 2001 From: cscherr Date: Mon, 28 Apr 2025 17:20:36 +0200 Subject: [PATCH] refactor: try to read the temperature but smarter --- examples/temperature.rs | 80 ++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/examples/temperature.rs b/examples/temperature.rs index 442f6cb..a31fb62 100755 --- a/examples/temperature.rs +++ b/examples/temperature.rs @@ -1,10 +1,11 @@ +// NOTE: This is at least unreliable and likely wrong + #![no_main] #![no_std] -use defmt::info; -use hal::adc::{Adc, Ready, VTemp}; -use hal::gpio::Analog; -use hal::gpio::gpiob::PB1; +use defmt::{debug, info}; +use hal::adc::{Adc, Ready, VRef, VTemp}; +use hal::calibration::{VtempCal30, VtempCal130}; use panic_probe as _; use defmt_rtt as _; // global logger @@ -12,8 +13,6 @@ use defmt_rtt as _; // global logger use cortex_m_rt::entry; use hal::{pac, prelude::*, rcc::Config}; -const MAGIC_TEMPERATURE_NUMBER: f32 = 12.412122; - #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); @@ -22,28 +21,61 @@ fn main() -> ! { let mut rcc = dp.RCC.freeze(Config::hsi16()); let mut adc = dp.ADC.constrain(&mut rcc); - let gpiob = dp.GPIOB.split(&mut rcc); - - let mut temp_pin = gpiob.pb1.into_analog(); - - // Get the delay provider. let mut delay = cp.SYST.delay(rcc.clocks); - let mut temp; - let mut i = 0; + // manual says i need to calibrate but then boom + adc.set_sample_time(hal::adc::SampleTime::T_1_5); + delay.delay_ms(50_u16); + adc.calibrate().unwrap(); + delay.delay_ms(5000_u16); + + // NOTE: TSEN bit must be enabled for reading the temperature + VTemp.enable(&mut adc); + + // reference temperatures from the chips readonly memory + // [Source](https://www.st.com/resource/en/datasheet/stm32l053r8.pdf), + // Table 6 in Secion 3.13 "Temperature sensor" + // + // More and better info in the large 1000+ page sheet "Ultra-low-power + // STM32L0x3 advanced ArmĀ®-based 32-bit MCUs" (RM0367), 14.9 + // + // This is basically calibration data + info!( + "reading calibration data... If this is the last thing you hear from me something has gone terribly wrong" + ); + let vref_cal = hal::calibration::VrefintCal::get().read(); + let tsense_cal1 = (30, VtempCal30::get().read()); + let tsense_cal2 = (130, VtempCal130::get().read()); + info!("tsense_cal1: {:?}", (30, tsense_cal1)); + info!("tsense_cal2: {:?}", (130, tsense_cal2)); + + delay.delay_ms(50_u16); + let vref_actual: u16 = adc.read(&mut VRef).unwrap(); + let vref_factor = vref_cal as f32 / vref_actual as f32; + debug!( + "vref real={} register={} => factor={}", + vref_actual, vref_cal, vref_factor + ); + + let mut temp_c; + let mut temp_mv; loop { - if i % 10_000 == 0 { - temp = read_temp_c(&mut temp_pin, &mut adc); - info!("Temperature: {}", temp); - } - // delay.delay_ms(200_u16); - i += 1; + temp_mv = read_temp_mv(&mut adc, vref_factor); + temp_c = temp_mv_to_c(temp_mv, tsense_cal1, tsense_cal2); + info!("Temperature: {:03}mv, {:04}c", temp_mv, temp_c as i32); + delay.delay_ms(500_u16); } } -fn read_temp_c(pin: &mut PB1, adc: &mut Adc) -> i16 { - let v: f32 = adc - .read(pin /* or maybe VTemp from the adc module? */) - .expect("could not read with adc"); - (v / MAGIC_TEMPERATURE_NUMBER) as i16 - 50 +fn read_temp_mv(adc: &mut Adc, vref_factor: f32) -> f32 { + let bare: f32 = adc.read(&mut VTemp).expect("could not read with adc"); + bare * vref_factor +} + +// This unholy abomination is from the datasheet and does not actually look so bad if it's written +// in Math instead of Rust. +fn temp_mv_to_c(temp: f32, ts_cal_1: (i32, u16), ts_cal_2: (i32, u16)) -> f32 { + ((ts_cal_2.0 as f32 - ts_cal_1.0 as f32) / (ts_cal_2.1 as f32 - ts_cal_1.1 as f32)) + * (temp - ts_cal_1.1 as f32) + + ts_cal_1.0 as f32 }