Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: add Temperature struct to avoid enforcing usage of floats
- Also add misc derives to multiple structs
- Add power_up / power_down methods to TemperatureSensor
- Enable ApbSarAdc via PeripheralGuard
  • Loading branch information
davoclavo committed Jan 6, 2025
commit 1410db7ac25ce51dea921bf8744d44c8ba68a2c8
115 changes: 79 additions & 36 deletions esp-hal/src/tsens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
//! Config::default()
//! ).unwrap();
//! let delay = Delay::new();
//!
//! delay.delay_micros(200);
//! loop {
//! let temp = temperature_sensor.get_celsius();
//! println!("Temperature: {:.2}°C", temp);
//! let temp = temperature_sensor.get_temperature();
//! println!("Temperature: {:.2}°C", temp.to_celcius());
//! delay.delay_millis(1_000);
//! }
//! # }
Expand All @@ -48,11 +48,11 @@
use crate::{
peripheral::{Peripheral, PeripheralRef},
peripherals::TSENS,
system::{GenericPeripheralGuard, PeripheralClockControl},
system::GenericPeripheralGuard,
};

/// Clock source for the temperature sensor
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Copy, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ClockSource {
/// Use RC_FAST clock source
Expand All @@ -63,48 +63,104 @@ pub enum ClockSource {
}

/// Temperature sensor configuration
#[derive(Debug, Clone, Default, PartialEq, Eq, Copy, procmacros::BuilderLite)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Copy, Hash, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct Config {
clock_source: ClockSource,
}

/// Temperature sensor configuration error
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
#[non_exhaustive]
pub enum ConfigError {}

/// Temperature value
/// This struct stores the raw ADC value, and can be used to calculate the
/// temperature in Celsius using the formula:
/// `(raw_value * 0.4386) - (offset * 27.88) - 20.52`
#[derive(Debug)]
pub struct Temperature {
/// Raw ADC value
pub raw_value: u8,

/// Offset value - depends on the temperature range configured
pub offset: i8,
}

impl Temperature {
/// Create a new temperature value
#[inline]
pub fn new(raw_value: u8, offset: i8) -> Self {
Self { raw_value, offset }
}

/// Get the temperature in Celsius
#[inline]
pub fn to_celsius(&self) -> f32 {
(self.raw_value as f32) * 0.4386 - (self.offset as f32) * 27.88 - 20.52
}

/// Get the temperature in Fahrenheit
#[inline]
pub fn to_fahrenheit(&self) -> f32 {
let celsius = self.to_celsius();
(celsius * 1.8) + 32.0
}

/// Get the temperature in Kelvin
#[inline]
pub fn to_kelvin(&self) -> f32 {
let celsius = self.to_celsius();
celsius + 273.15
}
}

/// Temperature sensor driver
#[derive(Debug)]
pub struct TemperatureSensor<'d> {
_peripheral: PeripheralRef<'d, TSENS>,
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::Tsens as u8 }>,
_tsens_guard: GenericPeripheralGuard<{ crate::system::Peripheral::Tsens as u8 }>,
_abp_saradc_guard: GenericPeripheralGuard<{ crate::system::Peripheral::ApbSarAdc as u8 }>,
}

impl<'d> TemperatureSensor<'d> {
/// Create a new temperature sensor instance with configuration
/// The sensor will be automatically powered up
pub fn new(
peripheral: impl Peripheral<P = TSENS> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
crate::into_ref!(peripheral);
let guard = GenericPeripheralGuard::new();

// We need to enable ApbSarAdc clock before trying to write on the tsens_ctrl
// register
PeripheralClockControl::enable(crate::system::Peripheral::ApbSarAdc);
let apb_saradc = unsafe { &*crate::peripherals::APB_SARADC::PTR };

// Power Up
apb_saradc.tsens_ctrl().write(|w| w.pu().set_bit());
// NOTE: We need enable ApbSarAdc before enabling Tsens
let apb_saradc_guard = GenericPeripheralGuard::new();
let tsens_guard = GenericPeripheralGuard::new();

let mut tsens = Self {
_guard: guard,
_peripheral: peripheral,
_tsens_guard: tsens_guard,
_abp_saradc_guard: apb_saradc_guard,
};
tsens.apply_config(&config)?;

tsens.power_up();

Ok(tsens)
}

/// Power up the temperature sensor
pub fn power_up(&self) {
debug!("Power up");
let abp_saradc = unsafe { &*crate::peripherals::APB_SARADC::PTR };
abp_saradc.tsens_ctrl().modify(|_, w| w.pu().set_bit());
}

/// Power down the temperature sensor - useful if you want to save power
pub fn power_down(&self) {
let abp_saradc = unsafe { &*crate::peripherals::APB_SARADC::PTR };
abp_saradc.tsens_ctrl().modify(|_, w| w.pu().clear_bit());
}

/// Change the temperature sensor configuration
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
let apb_saradc = unsafe { &*crate::peripherals::APB_SARADC::PTR };
Expand All @@ -118,29 +174,16 @@ impl<'d> TemperatureSensor<'d> {
Ok(())
}

/// Get the temperature in Celsius
/// Get the raw temperature value
#[inline]
pub fn get_celsius(&self) -> f32 {
pub fn get_temperature(&self) -> Temperature {
let abp_saradc = unsafe { &*crate::peripherals::APB_SARADC::PTR };

let measurement = abp_saradc.tsens_ctrl().read().out().bits();
let raw_value = abp_saradc.tsens_ctrl().read().out().bits();

// TODO Address multiple temperature ranges and offsets
let offset = -1f32;
(measurement as f32) * 0.4386 - offset * 27.88 - 20.52
}

/// Get the temperature in Fahrenheit
#[inline]
pub fn get_fahrenheit(&self) -> f32 {
let celsius = self.get_celsius();
(celsius * 1.8) + 32.0
}
let offset = -1i8;

/// Get the temperature in Kelvin
#[inline]
pub fn get_kelvin(&self) -> f32 {
let celsius = self.get_celsius();
celsius + 273.15
Temperature::new(raw_value, offset)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! This example uses the internal temperature sensor to measure the chip's temperature
//!
//! This example uses the internal temperature sensor to measure the chip's
//! temperature

//% CHIPS: esp32c6 esp32c3

Expand All @@ -26,8 +26,8 @@ fn main() -> ! {
delay.delay_micros(200);

loop {
let temp = temperature_sensor.get_celsius();
println!("Temperature: {:.2}°C", temp);
let temp = temperature_sensor.get_temperature();
println!("Temperature: {:.2}°C", temp.to_celsius());
delay.delay_millis(1_000);
}
}