Skip to content

Commit

Permalink
Add in CPU Temperature reading
Browse files Browse the repository at this point in the history
  • Loading branch information
rnd-ash committed Jan 23, 2025
1 parent 9262d33 commit 627d9a9
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 7 deletions.
69 changes: 62 additions & 7 deletions hal/src/peripherals/adc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ pub enum Error {
ClockTooFast,
/// Buffer overflowed
BufferOverrun,
/// Temperature sensor not enabled
///
/// This is returned when attempting to read the CPU temperature, and
/// the SUPC peripheral has not been configured correctly to expose
/// the temperature sensors.
TemperatureSensorNotEnabled,
}

bitflags::bitflags! {
Expand Down Expand Up @@ -252,6 +258,7 @@ impl<I: AdcInstance, Id: ChId, P: AdcPin<I, Id>> Channel<I, Id, P> {
pub struct Adc<I: AdcInstance, F = NoneT> {
adc: I::Instance,
_irqs: PhantomData<F>,
cfg: AdcSettingsBuilder,
}

pub struct AdcFuture;
Expand Down Expand Up @@ -282,6 +289,7 @@ impl<I: AdcInstance> Adc<I> {
let mut new_adc = Self {
adc,
_irqs: PhantomData,
cfg: settings.clone(),
};
new_adc.configure(settings);
Ok((new_adc, Channels::new()))
Expand Down Expand Up @@ -400,13 +408,27 @@ impl<I: AdcInstance> Adc<I> {
}

#[inline]
pub fn read_ptat_blocking(&mut self) -> u16 {
self.read_blocking(0x19)
}

#[inline]
pub fn read_ctat_blocking(&mut self) -> u16 {
self.read_blocking(0x1A)
/// Returns the CPU temperature in degrees C
///
/// This requires that the [pac::Supc] peripheral is configured with
/// tsen and ondemand bits enabled, otherwise this function will return
/// [Error::TemperatureSensorNotEnabled]
pub fn read_cpu_temperature_blocking(&mut self, supc: &pac::Supc) -> Result<f32, Error> {
let vref = supc.vref().read();
if vref.tsen().bit_is_clear() || vref.ondemand().bit_is_clear() {
return Err(Error::TemperatureSensorNotEnabled);
}
let mut tp = self.read_blocking(0x1C) as f32;
let mut tc = self.read_blocking(0x1D) as f32;

if let AdcAccumulation::Summed(sum) = self.cfg.accumulation {
// to prevent incorrect readings, divide by number of samples if the
// ADC was already configured in summation mode
let div: f32 = (2u16.pow(sum as u32)) as f32;
tp /= div;
tc /= div;
}
Ok(self.tp_tc_to_temp(tp, tc))
}

/// Return the underlying ADC PAC object
Expand Down Expand Up @@ -443,6 +465,7 @@ impl<I: AdcInstance, T> Adc<I, T> {
Adc {
adc: self.adc,
_irqs: PhantomData,
cfg: self.cfg,
}
}

Expand Down Expand Up @@ -474,6 +497,19 @@ impl<I: AdcInstance, T> Adc<I, T> {
}
}

#[inline]
fn tp_tc_to_temp(&self, tp: f32, tc: f32) -> f32 {
let tl = calibration::tl();
let th = calibration::th();
let vpl = calibration::vpl() as f32;
let vph = calibration::vph() as f32;
let vcl = calibration::vcl() as f32;
let vch = calibration::vch() as f32;

(tl * vph * tc - vpl * th * tc - tl * vch * tp + th * vcl * tp)
/ (vcl * tp - vch * tp - vpl * tc + vph * tc)
}

#[inline]
fn sync(&self) {
// Slightly more performant than checking the individual bits
Expand Down Expand Up @@ -580,6 +616,25 @@ where
self.power_down();
Ok(())
}

#[inline]
pub async fn read_cpu_temperature(&mut self, supc: &pac::Supc) -> Result<f32, Error> {
let vref = supc.vref().read();
if vref.tsen().bit_is_clear() || vref.ondemand().bit_is_clear() {
return Err(Error::TemperatureSensorNotEnabled);
}
let mut tp = self.read(0x1C).await as f32;
let mut tc = self.read(0x1D).await as f32;

if let AdcAccumulation::Summed(sum) = self.cfg.accumulation {
// to prevent incorrect readings, divide by number of samples if the
// ADC was already configured in summation mode
let div: f32 = (2u16.pow(sum as u32)) as f32;
tp /= div;
tc /= div;
}
Ok(self.tp_tc_to_temp(tp, tc))
}
}

// Here I declare the number of channels for the SAME51 ADC
Expand Down
22 changes: 22 additions & 0 deletions hal/src/peripherals/calibration/d5x.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ fn cal(addr_offset: u32, bit_shift: u32, bit_mask: u32) -> u32 {
}
}

// Needed for temperature calibration values stored in NVM
fn parts_to_f32(int: u32, dec: u32) -> f32 {
let mut dec = dec as f32;

if dec < 10.0 {
dec /= 10.0;
} else if dec <= 100.0 {
dec /= 100.0;
} else {
dec /= 1000.0;
}
int as f32 + dec
}

/// USB TRANSN calibration value. Should be written to USB PADCAL register.
pub fn usb_transn_cal() -> u8 {
cal(4, 0, 0b11111) as u8
Expand Down Expand Up @@ -60,6 +74,14 @@ pub fn adc1_biasr2r_scale_cal() -> u8 {
cal(3, 0, 0b111) as u8
}

pub fn tl() -> f32 {
parts_to_f32(cal(0x80, 7, 0b11111111), cal(0x80 + 1, 3, 0b1111))
}

pub fn th() -> f32 {
parts_to_f32(cal(0x80 + 2, 3, 0b11111111), cal(0x80 + 2, 7, 0b1111))
}

/// Temperature calibration - Integer part of calibration temperature TL
pub fn tli() -> u8 {
cal(0x80, 7, 0b11111111) as u8
Expand Down

0 comments on commit 627d9a9

Please sign in to comment.