-
Notifications
You must be signed in to change notification settings - Fork 181
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for ESP internal temperature sensor (#337)
* 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
1 parent
e20ef5c
commit a619f13
Showing
4 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |