Skip to main content

ws63_hal/
tsensor.rs

1//! Temperature Sensor (TSENSOR) driver for WS63.
2//!
3//! The WS63 temperature sensor provides a 10-bit digital temperature code
4//! covering approximately -40°C to +125°C. It supports automatic refresh,
5//! high/low temperature thresholds, and over-temperature detection.
6//!
7//! # Temperature calculation
8//!
9//! Temperature code range: 114 to 896 (approximate).
10//! Temperature (°C) can be derived from the code using chip-specific
11//! calibration data. Without calibration, the raw code is provided.
12//!
13//! # Interrupts
14//!
15//! - Conversion done interrupt
16//! - Out-of-threshold interrupt (temperature outside [low, high])
17//! - Over-temperature interrupt
18
19use crate::peripherals::Tsensor;
20
21/// Temperature sensor driver.
22pub struct TempSensor<'d> {
23    _tsensor: Tsensor<'d>,
24}
25
26/// Temperature code range constants.
27pub const TEMP_CODE_MIN: u16 = 114;
28pub const TEMP_CODE_MAX: u16 = 896;
29
30impl<'d> TempSensor<'d> {
31    /// Create a new temperature sensor driver.
32    pub fn new(tsensor: Tsensor<'d>) -> Self {
33        Self { _tsensor: tsensor }
34    }
35
36    fn regs(&self) -> &'static ws63_pac::tsensor::RegisterBlock {
37        // SAFETY: PAC peripheral pointer is a static physical MMIO address, always valid
38        unsafe { &*Tsensor::ptr() }
39    }
40
41    /// Enable the temperature sensor.
42    pub fn enable(&mut self) {
43        let r = self.regs();
44        let ctrl = r.tsensor_ctrl().read().bits();
45        unsafe {
46            r.tsensor_ctrl().write(|w| w.bits(ctrl | 0x01));
47        }
48    }
49
50    /// Disable the temperature sensor.
51    pub fn disable(&mut self) {
52        let r = self.regs();
53        let ctrl = r.tsensor_ctrl().read().bits();
54        unsafe {
55            r.tsensor_ctrl().write(|w| w.bits(ctrl & !0x01));
56        }
57    }
58
59    /// Set the operating mode.
60    ///
61    /// * `mode` — Mode value (0-3). The exact meaning depends on the chip
62    ///   configuration.
63    pub fn set_mode(&mut self, mode: u8) {
64        let r = self.regs();
65        let ctrl = r.tsensor_ctrl().read().bits();
66        let ctrl = (ctrl & !0x06) | (((mode as u32) & 0x03) << 1);
67        unsafe {
68            r.tsensor_ctrl().write(|w| w.bits(ctrl));
69        }
70    }
71
72    /// Trigger a single temperature reading (software start).
73    ///
74    /// Writes 1 to the start register to refresh the temperature value.
75    pub fn start_conversion(&mut self) {
76        unsafe {
77            self.regs().tsensor_start().write(|w| w.bits(0x01));
78        }
79    }
80
81    /// Check if a temperature reading is ready.
82    pub fn data_ready(&self) -> bool {
83        self.regs().tsensor_sts().read().bits() & 0x02 != 0
84    }
85
86    /// Read the raw temperature code (10-bit, range 114-896).
87    ///
88    /// Returns `None` if data is not ready.
89    pub fn read_raw(&self) -> Option<u16> {
90        if !self.data_ready() {
91            return None;
92        }
93        let sts = self.regs().tsensor_sts().read().bits();
94        Some(((sts >> 2) & 0x3FF) as u16)
95    }
96
97    /// Read the temperature code, blocking until ready.
98    pub fn read_blocking(&self) -> u16 {
99        while !self.data_ready() {}
100        let sts = self.regs().tsensor_sts().read().bits();
101        ((sts >> 2) & 0x3FF) as u16
102    }
103
104    /// Clear the temperature sensor status.
105    pub fn clear_status(&mut self) {
106        let r = self.regs();
107        let sts = r.tsensor_sts().read().bits();
108        unsafe {
109            r.tsensor_sts().write(|w| w.bits(sts | 0x01));
110        }
111    }
112
113    /// Set the high temperature limit.
114    ///
115    /// Interrupt triggers when temperature code exceeds this value.
116    pub fn set_high_limit(&mut self, code: u16) {
117        unsafe {
118            self.regs().tsensor_temp_high_limit().write(|w| w.bits((code & 0x3FF) as u32));
119        }
120    }
121
122    /// Set the low temperature limit.
123    ///
124    /// Interrupt triggers when temperature code falls below this value.
125    pub fn set_low_limit(&mut self, code: u16) {
126        unsafe {
127            self.regs().tsensor_temp_low_limit().write(|w| w.bits((code & 0x3FF) as u32));
128        }
129    }
130
131    /// Set the over-temperature threshold.
132    pub fn set_over_temp_threshold(&mut self, code: u16, enable_interrupt: bool) {
133        let mut val = (code & 0x3FF) as u32;
134        if enable_interrupt {
135            val |= 1 << 10; // over_temp_en
136        }
137        unsafe {
138            self.regs().tsensor_over_temp().write(|w| w.bits(val));
139        }
140    }
141
142    /// Enable specific temperature interrupts.
143    ///
144    /// * `done_int` — Conversion done interrupt
145    /// * `out_thresh_int` — Out-of-threshold interrupt
146    /// * `overtemp_int` — Over-temperature interrupt
147    pub fn enable_interrupts(&mut self, done_int: bool, out_thresh_int: bool, overtemp_int: bool) {
148        let mut val: u32 = 0;
149        if done_int {
150            val |= 0x01;
151        }
152        if out_thresh_int {
153            val |= 0x02;
154        }
155        if overtemp_int {
156            val |= 0x04;
157        }
158        unsafe {
159            self.regs().tsensor_temp_int_en().write(|w| w.bits(val));
160        }
161    }
162
163    /// Disable all temperature interrupts.
164    pub fn disable_all_interrupts(&mut self) {
165        unsafe {
166            self.regs().tsensor_temp_int_en().write(|w| w.bits(0));
167        }
168    }
169
170    /// Check interrupt status.
171    ///
172    /// Returns `(done, out_thresh, overtemp)`.
173    pub fn interrupt_status(&self) -> (bool, bool, bool) {
174        let sts = self.regs().tsensor_temp_int_sts().read().bits();
175        ((sts & 0x01) != 0, (sts & 0x02) != 0, (sts & 0x04) != 0)
176    }
177
178    /// Clear specific temperature interrupts.
179    pub fn clear_interrupts(&mut self, done: bool, out_thresh: bool, overtemp: bool) {
180        let mut val: u32 = 0;
181        if done {
182            val |= 0x01;
183        }
184        if out_thresh {
185            val |= 0x02;
186        }
187        if overtemp {
188            val |= 0x04;
189        }
190        unsafe {
191            self.regs().tsensor_temp_int_clr().write(|w| w.bits(val));
192        }
193    }
194
195    /// Configure automatic temperature refresh.
196    ///
197    /// * `period` — Refresh period in 32kHz clock cycles.
198    /// * `enable` — Enable auto refresh.
199    pub fn configure_auto_refresh(&mut self, period: u16, enable: bool) {
200        unsafe {
201            self.regs().tsensor_auto_refresh_period().write(|w| w.bits(period as u32));
202            self.regs().tsensor_auto_refresh_cfg().write(|w| w.bits(if enable { 1 } else { 0 }));
203        }
204    }
205
206    /// Enable temperature calibration.
207    pub fn enable_calibration(&mut self) {
208        let ctrl1 = self.regs().tsensor_ctrl1().read().bits();
209        unsafe {
210            self.regs().tsensor_ctrl1().write(|w| w.bits(ctrl1 | 0x01));
211        }
212    }
213
214    /// Disable temperature calibration.
215    pub fn disable_calibration(&mut self) {
216        let ctrl1 = self.regs().tsensor_ctrl1().read().bits();
217        unsafe {
218            self.regs().tsensor_ctrl1().write(|w| w.bits(ctrl1 & !0x01));
219        }
220    }
221}