Skip to content

Commit

Permalink
Add support for ESP internal temperature sensor (#337)
Browse files Browse the repository at this point in the history
* Add first version of temp sensor driver

Code is very rudimentary and still suspect to change.
Notably, error handling is not implemented yet.

* Change cfg attribute to not any

* Rename TemperatureSensor to TemperatureSensorDriver

* Switch to `core::ptr`

* Add error handling

* Build the internal temperature sensor only on supported targets

* Fix the derives in TemperatureSensorConfig, TemperatureSensorClockSource

* Implement From<TemperatureSensorConfig> for temperature_sensor_config_t

* Use right clocks for temperature sensor depending on target

* Rename config and move it into own module

* Provide const new constructor for temperature sensor config

* Change config argument to be a reference

* Rename TemperatureSensor to TempSensor

* Avoid cloning config in temp driver constructor

* Add back derived Copy trait for TempSensorClockSource

* Add non_exhaustive option to TempSensorConfig

* Add temp sensor peripheral

* Cause panic if uninstalling the temp driver fails

* Implement Send for TempSensorDriver

* Make use of esp_idf_soc_temp_sensor_supported

* Add an example for temperature_sensor

---------

Co-authored-by: Luca Barbato <[email protected]>
  • Loading branch information
GamerBene19 and lu-zero authored Sep 9, 2024
1 parent e20ef5c commit a619f13
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 0 deletions.
28 changes: 28 additions & 0 deletions examples/temperature_sensor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::peripherals::Peripherals;

#[cfg(all(esp_idf_soc_temp_sensor_supported, esp_idf_version_major = "5"))]
fn main() -> anyhow::Result<()> {
use esp_idf_hal::temp_sensor::*;
esp_idf_hal::sys::link_patches();

let peripherals = Peripherals::take()?;
let cfg = TempSensorConfig::default();
let mut temp = TempSensorDriver::new(&cfg, peripherals.temp_sensor)?;
temp.enable()?;

loop {
let t = temp.get_celsius()?;
println!("Temperature {t}C");
FreeRtos::delay_ms(1000);
}
}

#[cfg(not(all(esp_idf_soc_temp_sensor_supported, esp_idf_version_major = "5")))]
fn main() -> anyhow::Result<()> {
println!("This example requires feature `esp_idf_soc_temp_sensor_supported` enabled");

loop {
std::thread::sleep(std::time::Duration::from_millis(1000));
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub mod sd;
pub mod spi;
pub mod sys;
pub mod task;
#[cfg(all(esp_idf_soc_temp_sensor_supported, esp_idf_version_major = "5"))]
pub mod temp_sensor;
pub mod timer;
pub mod uart;
#[cfg(all(
Expand Down
6 changes: 6 additions & 0 deletions src/peripherals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use crate::spi;
any(esp_idf_version_major = "4", esp_idf_version = "5.0")
))]
use crate::task::watchdog;
#[cfg(all(esp_idf_soc_temp_sensor_supported, esp_idf_version_major = "5"))]
use crate::temp_sensor;
use crate::timer;
use crate::uart;
#[cfg(all(
Expand Down Expand Up @@ -86,6 +88,8 @@ pub struct Peripherals {
pub sdmmc0: sd::mmc::SDMMC0,
#[cfg(all(esp_idf_soc_sdmmc_host_supported, feature = "experimental"))]
pub sdmmc1: sd::mmc::SDMMC1,
#[cfg(all(esp_idf_soc_temp_sensor_supported, esp_idf_version_major = "5"))]
pub temp_sensor: temp_sensor::TempSensor,
// TODO: Check the timer story for c2, h2, c5, c6, and p4
pub timer00: timer::TIMER00,
#[cfg(any(esp32, esp32s2, esp32s3))]
Expand Down Expand Up @@ -187,6 +191,8 @@ impl Peripherals {
sdmmc0: sd::mmc::SDMMC0::new(),
#[cfg(all(esp_idf_soc_sdmmc_host_supported, feature = "experimental"))]
sdmmc1: sd::mmc::SDMMC1::new(),
#[cfg(all(esp_idf_soc_temp_sensor_supported, esp_idf_version_major = "5"))]
temp_sensor: temp_sensor::TempSensor::new(),
timer00: timer::TIMER00::new(),
#[cfg(any(esp32, esp32s2, esp32s3))]
timer01: timer::TIMER01::new(),
Expand Down
190 changes: 190 additions & 0 deletions src/temp_sensor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
use esp_idf_sys::{
esp, soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_DEFAULT,
temperature_sensor_clk_src_t, temperature_sensor_config_t, temperature_sensor_disable,
temperature_sensor_enable, temperature_sensor_get_celsius, temperature_sensor_handle_t,
temperature_sensor_install, temperature_sensor_uninstall, EspError,
};

#[cfg(esp32p4)]
use esp_idf_sys::soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_LP_PERI;
#[cfg(any(
esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2, esp32s2, esp32s3
))]
use esp_idf_sys::soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_RC_FAST;
#[cfg(any(esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2))]
use esp_idf_sys::soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_XTAL;

use crate::peripheral::Peripheral;
use core::marker::PhantomData;

// -- TempSensorClockSource --

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Rust translation of `temperature_sensor_clk_src_t`
pub enum TempSensorClockSource {
Default,
#[cfg(any(
esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2, esp32s2, esp32s3
))]
RcFast,
#[cfg(any(esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2))]
XTAL,
#[cfg(esp32p4)]
LpPeri,
}

impl From<TempSensorClockSource> for temperature_sensor_clk_src_t {
fn from(value: TempSensorClockSource) -> Self {
match value {
#[cfg(any(
esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2, esp32s2, esp32s3
))]
TempSensorClockSource::RcFast => {
soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_RC_FAST
}
#[cfg(any(esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2))]
TempSensorClockSource::XTAL => {
soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_XTAL
}
#[cfg(esp32p4)]
TempSensorClockSource::LpPeri => {
soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_LP_PERI
}
TempSensorClockSource::Default => {
soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_DEFAULT
}
}
}
}

impl From<temperature_sensor_clk_src_t> for TempSensorClockSource {
fn from(value: temperature_sensor_clk_src_t) -> Self {
match value {
#[cfg(any(
esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2, esp32s2, esp32s3
))]
#[allow(non_upper_case_globals)]
soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_RC_FAST => {
Self::RcFast
}
#[cfg(any(esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2))]
#[allow(non_upper_case_globals)]
soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_XTAL => Self::XTAL,
#[cfg(esp32p4)]
#[allow(non_upper_case_globals)]
soc_periph_temperature_sensor_clk_src_t_TEMPERATURE_SENSOR_CLK_SRC_LP_PERI => {
Self::LpPeri
}
// TODO: Perhaps the default value should be mapped explicitly
// and all other (u32) values should cause a failure
_ => Self::Default,
}
}
}

// -- TempSensorConfig --
pub type TempSensorConfig = config::Config;
pub mod config {
use super::*;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
/// Rust wrapper for `temperature_sensor_config_t`
pub struct Config {
// TODO: check int size
pub range_min: i32,
pub range_max: i32,
pub clk_src: TempSensorClockSource,
}

impl From<temperature_sensor_config_t> for Config {
fn from(value: temperature_sensor_config_t) -> Self {
Config {
range_min: value.range_min,
range_max: value.range_max,
clk_src: value.clk_src.into(),
}
}
}

impl From<&Config> for temperature_sensor_config_t {
fn from(value: &Config) -> Self {
temperature_sensor_config_t {
clk_src: value.clk_src.into(),
range_max: value.range_max,
range_min: value.range_min,
}
}
}

impl Default for Config {
fn default() -> Self {
Config::new()
}
}

impl Config {
pub const fn new() -> Self {
Self {
range_min: -10,
range_max: 80,
clk_src: TempSensorClockSource::Default,
}
}
}
}

// -- TempSensorDriver --

pub struct TempSensorDriver<'d> {
ptr: temperature_sensor_handle_t,
_p: PhantomData<&'d mut ()>,
}

impl<'d> TempSensorDriver<'d> {
pub fn new(
config: &TempSensorConfig,
_sensor: impl Peripheral<P = TempSensor> + 'd,
) -> Result<Self, EspError> {
let mut sensor = core::ptr::null_mut();
esp!(unsafe { temperature_sensor_install(&config.into(), &mut sensor) })?;
Ok(TempSensorDriver {
ptr: sensor,
_p: PhantomData,
})
}

pub fn enable(&mut self) -> Result<(), EspError> {
esp!(unsafe { temperature_sensor_enable(self.ptr) })
}

pub fn disable(&mut self) -> Result<(), EspError> {
esp!(unsafe { temperature_sensor_disable(self.ptr) })
}

pub fn get_celsius(&self) -> Result<f32, EspError> {
let mut val = 0.0;
esp!(unsafe { temperature_sensor_get_celsius(self.ptr, &mut val) })?;
Ok(val)
}

pub fn get_fahrenheit(&self) -> Result<f32, EspError> {
let celsius = self.get_celsius()?;
Ok((celsius * 1.8) + 32.0)
}

pub fn get_kelvin(&self) -> Result<f32, EspError> {
let celsius = self.get_celsius()?;
Ok(celsius + 273.15)
}
}

impl Drop for TempSensorDriver<'_> {
fn drop(&mut self) {
let _ = self.disable();
esp!(unsafe { temperature_sensor_uninstall(self.ptr) }).unwrap();
}
}

unsafe impl<'d> Send for TempSensorDriver<'d> {}

crate::impl_peripheral!(TempSensor);

0 comments on commit a619f13

Please sign in to comment.