tmp006/
reading.rs

1use crate::{BitFlagsLow, Error, Register, SensorData, Tmp006};
2use embedded_hal::i2c;
3
4impl<I2C, E> Tmp006<I2C>
5where
6    I2C: i2c::I2c<Error = E>,
7{
8    /// Read the object temperature in Kelvins.
9    ///
10    /// This uses the sensor voltage and ambient temperature as well as an
11    /// input calibration factor.
12    ///
13    /// The input calibration factor can be calculated with the formulas
14    /// provided in the [TMP006 user guide].
15    /// Typical values are between `5*10^-14` and `7*10^-14`
16    ///
17    /// [TMP006 user guide](https://cdn-shop.adafruit.com/datasheets/tmp006ug.pdf)
18    pub fn read_object_temperature(
19        &mut self,
20        calibration_factor: f64,
21    ) -> nb::Result<f64, Error<E>> {
22        let data = self.read_sensor_data()?;
23        let temp = self.calculate_object_temperature(data, calibration_factor);
24        Ok(temp)
25    }
26
27    /// Calculate the object temperature in Kelvins.
28    ///
29    /// Given the sensor data and a calibration factor.
30    ///
31    /// The input calibration factor can be calculated with the formulas
32    /// provided in the [TMP006 user guide].
33    /// Typical values are between `5*10^-14` and `7*10^-14`
34    ///
35    /// [TMP006 user guide](https://cdn-shop.adafruit.com/datasheets/tmp006ug.pdf)
36    pub fn calculate_object_temperature(&self, data: SensorData, calibration_factor: f64) -> f64 {
37        const A1: f64 = 1.75e-3;
38        const A2: f64 = -1.678e-5;
39        const B0: f64 = -2.94e-5;
40        const B1: f64 = -5.7e-7;
41        const B2: f64 = 4.63e-9;
42        const C2: f64 = 13.4;
43        const T_REF: f64 = 298.15;
44        const V_LSB_SIZE: f64 = 156.25e-9;
45
46        let v_obj = f64::from(data.object_voltage) * V_LSB_SIZE;
47        let t_die_k = f64::from(data.ambient_temperature) / 128.0 + 273.15;
48
49        let t_diff = t_die_k - T_REF;
50        let t_diff_sq = t_diff * t_diff;
51        let v_os = B0 + B1 * t_diff + B2 * t_diff_sq;
52        let v_diff = v_obj - v_os;
53        let fv_obj = v_diff + C2 * v_diff * v_diff;
54        let s0 = calibration_factor;
55        let s = s0 * (1.0 + A1 * t_diff + A2 * t_diff_sq);
56        libm::pow(libm::pow(t_die_k, 4.0) + fv_obj / s, 0.25)
57    }
58
59    /// Read the data from the sensor.
60    ///
61    /// These values can be used to calculate the object temperature as done in
62    /// [`read_object_temperature()`].
63    ///
64    /// [`read_object_temperature()`]: struct.Tmp006.html#method.read_object_temperature
65    pub fn read_sensor_data(&mut self) -> nb::Result<SensorData, Error<E>> {
66        let ready = self.is_data_ready().map_err(nb::Error::Other)?;
67        if !ready {
68            return Err(nb::Error::WouldBlock);
69        }
70        let v = self
71            .read_register(Register::V_OBJECT)
72            .map_err(nb::Error::Other)?;
73        let temp = self
74            .read_register(Register::TEMP_AMBIENT)
75            .map_err(nb::Error::Other)?;
76        let data = SensorData {
77            object_voltage: v as i16,
78            ambient_temperature: temp as i16 / 4,
79        };
80        Ok(data)
81    }
82
83    /// Reads whether there is data ready to be read.
84    ///
85    /// When this returens `false` it means that a conversion is in progress.
86    #[allow(clippy::wrong_self_convention)]
87    pub fn is_data_ready(&mut self) -> Result<bool, Error<E>> {
88        let config = self.read_register(Register::CONFIG)?;
89        Ok((config & u16::from(BitFlagsLow::DRDY)) != 0)
90    }
91
92    /// Read the manufacturer ID.
93    ///
94    /// This is per default `0x5449`.
95    pub fn read_manufacturer_id(&mut self) -> Result<u16, Error<E>> {
96        self.read_register(Register::MANUFAC_ID)
97    }
98
99    /// Read the device ID.
100    ///
101    /// This is per default `0x0067`.
102    pub fn read_device_id(&mut self) -> Result<u16, Error<E>> {
103        self.read_register(Register::DEVICE_ID)
104    }
105
106    fn read_register(&mut self, register: u8) -> Result<u16, Error<E>> {
107        let mut data = [0; 2];
108        self.i2c
109            .write_read(self.address, &[register], &mut data)
110            .map_err(Error::I2C)?;
111        Ok((u16::from(data[0]) << 8) | u16::from(data[1]))
112    }
113}