esp_hal/tsens.rs
1//! # Temperature Sensor (tsens)
2//!
3//! ## Overview
4//!
5//! The Temperature Sensor peripheral is used to measure the internal
6//! temperature inside the chip. The voltage is internally converted via an ADC
7//! into a digital value, and has a measuring range of –40 °C to 125 °C.
8//! The temperature value depends on factors like microcontroller clock
9//! frequency or I/O load. Generally, the chip’s internal temperature is higher
10//! than the operating ambient temperature.
11//!
12//! It is recommended to wait a few hundred microseconds after turning it on
13//! before measuring, in order to allow the sensor to stabilize.
14//!
15//! ## Configuration
16//!
17//! The temperature sensor can be configured with different clock sources.
18//!
19//! ## Examples
20//!
21//! The following example will measure the internal chip temperature every
22//! second, and print it
23//!
24//! ```rust, no_run
25#![doc = crate::before_snippet!()]
26//! # use esp_hal::tsens::{TemperatureSensor, Config};
27//! # use esp_hal::delay::Delay;
28//!
29//! let temperature_sensor = TemperatureSensor::new(
30//! peripherals.TSENS,
31//! Config::default())?;
32//! let delay = Delay::new();
33//! delay.delay_micros(200);
34//! loop {
35//! let temp = temperature_sensor.get_temperature();
36//! println!("Temperature: {:.2}°C", temp.to_celcius());
37//! delay.delay_millis(1_000);
38//! }
39//! # }
40//! ```
41//!
42//! ## Implementation State
43//!
44//! - Temperature calibration range is not supported
45//! - Interrupts are not supported
46
47use crate::{
48 peripherals::{APB_SARADC, TSENS},
49 system::GenericPeripheralGuard,
50};
51
52/// Clock source for the temperature sensor
53#[derive(Debug, Clone, Default, PartialEq, Eq, Copy, Hash)]
54#[cfg_attr(feature = "defmt", derive(defmt::Format))]
55#[non_exhaustive]
56pub enum ClockSource {
57 /// Use RC_FAST clock source
58 RcFast,
59 /// Use XTAL clock source
60 #[default]
61 Xtal,
62}
63
64/// Temperature sensor configuration
65#[derive(Debug, Clone, Default, PartialEq, Eq, Copy, Hash, procmacros::BuilderLite)]
66#[cfg_attr(feature = "defmt", derive(defmt::Format))]
67#[non_exhaustive]
68pub struct Config {
69 /// Clock source for the temperature sensor
70 clock_source: ClockSource,
71}
72
73/// Temperature sensor configuration error
74#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
75#[non_exhaustive]
76pub enum ConfigError {}
77
78/// Temperature value
79/// This struct stores the raw ADC value, and can be used to calculate the
80/// temperature in Celsius using the formula:
81/// `(raw_value * 0.4386) - (offset * 27.88) - 20.52`
82#[derive(Debug)]
83pub struct Temperature {
84 /// Raw ADC value
85 pub raw_value: u8,
86
87 /// Offset value - depends on the temperature range configured
88 pub offset: i8,
89}
90
91impl Temperature {
92 /// Create a new temperature value
93 #[inline]
94 pub fn new(raw_value: u8, offset: i8) -> Self {
95 Self { raw_value, offset }
96 }
97
98 /// Get the temperature in Celsius
99 #[inline]
100 pub fn to_celsius(&self) -> f32 {
101 (self.raw_value as f32) * 0.4386 - (self.offset as f32) * 27.88 - 20.52
102 }
103
104 /// Get the temperature in Fahrenheit
105 #[inline]
106 pub fn to_fahrenheit(&self) -> f32 {
107 let celsius = self.to_celsius();
108 (celsius * 1.8) + 32.0
109 }
110
111 /// Get the temperature in Kelvin
112 #[inline]
113 pub fn to_kelvin(&self) -> f32 {
114 let celsius = self.to_celsius();
115 celsius + 273.15
116 }
117}
118
119/// Temperature sensor driver
120#[derive(Debug)]
121pub struct TemperatureSensor<'d> {
122 _peripheral: TSENS<'d>,
123 _tsens_guard: GenericPeripheralGuard<{ crate::system::Peripheral::Tsens as u8 }>,
124 _abp_saradc_guard: GenericPeripheralGuard<{ crate::system::Peripheral::ApbSarAdc as u8 }>,
125}
126
127impl<'d> TemperatureSensor<'d> {
128 /// Create a new temperature sensor instance with configuration
129 /// The sensor will be automatically powered up
130 pub fn new(peripheral: TSENS<'d>, config: Config) -> Result<Self, ConfigError> {
131 // NOTE: We need enable ApbSarAdc before enabling Tsens
132 let apb_saradc_guard = GenericPeripheralGuard::new();
133 let tsens_guard = GenericPeripheralGuard::new();
134
135 let mut tsens = Self {
136 _peripheral: peripheral,
137 _tsens_guard: tsens_guard,
138 _abp_saradc_guard: apb_saradc_guard,
139 };
140 tsens.apply_config(&config)?;
141
142 tsens.power_up();
143
144 Ok(tsens)
145 }
146
147 /// Power up the temperature sensor
148 pub fn power_up(&self) {
149 debug!("Power up");
150 APB_SARADC::regs()
151 .tsens_ctrl()
152 .modify(|_, w| w.pu().set_bit());
153 }
154
155 /// Power down the temperature sensor - useful if you want to save power
156 pub fn power_down(&self) {
157 APB_SARADC::regs()
158 .tsens_ctrl()
159 .modify(|_, w| w.pu().clear_bit());
160 }
161
162 /// Change the temperature sensor configuration
163 pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
164 // Set clock source
165 APB_SARADC::regs().tsens_ctrl2().write(|w| {
166 w.clk_sel()
167 .bit(matches!(config.clock_source, ClockSource::Xtal))
168 });
169
170 Ok(())
171 }
172
173 /// Get the raw temperature value
174 #[inline]
175 pub fn get_temperature(&self) -> Temperature {
176 let raw_value = APB_SARADC::regs().tsens_ctrl().read().out().bits();
177
178 // TODO Address multiple temperature ranges and offsets
179 let offset = -1i8;
180
181 Temperature::new(raw_value, offset)
182 }
183}