mlx9061x/
mlx90615.rs

1use crate::{
2    ic,
3    register_access::mlx90615::{self, Register, DEV_ADDR},
4    Error, Mlx9061x, SlaveAddr,
5};
6use core::marker::PhantomData;
7use embedded_hal::{delay::DelayNs, digital::OutputPin, i2c::I2c};
8
9impl<E, I2C> Mlx9061x<I2C, ic::Mlx90615>
10where
11    I2C: I2c<Error = E>,
12{
13    /// Create new instance of the MLX90615 device.
14    ///
15    /// The slave address must match the address stored in the device EEPROM.
16    /// To change it you need to connect first and then change it with `set_address()`.
17    /// An invalid alternative slave address will return `Error::InvalidInputData`.
18    ///
19    /// When writing to the EEPROM waiting a certain amount of time is necessary.
20    /// This delay is configured through the `eeprom_write_delay_ms` parameter
21    /// in milliseconds.
22    pub fn new_mlx90615(
23        i2c: I2C,
24        address: SlaveAddr,
25        eeprom_write_delay_ms: u8,
26    ) -> Result<Self, Error<E>> {
27        let address = Self::get_address(address, DEV_ADDR)?;
28        Ok(Mlx9061x {
29            i2c,
30            eeprom_write_delay_ms,
31            address,
32            _ic: PhantomData,
33        })
34    }
35}
36
37impl<E, I2C> Mlx9061x<I2C, ic::Mlx90615>
38where
39    I2C: I2c<Error = E>,
40{
41    /// Read the ambient temperature in celsius degrees
42    pub fn ambient_temperature(&mut self) -> Result<f32, Error<E>> {
43        let t = self.read_u16(Register::TA)?;
44        let t = f32::from(t) * 0.02 - 273.15;
45        Ok(t)
46    }
47
48    /// Read the ambient temperature in celsius degrees as u16 value
49    ///
50    /// Note ONLY use to avoid floating-point ops, as this gives less accurate
51    /// temperature readings compared to using `ambient_temperature()`.
52    pub fn ambient_temperature_as_int(&mut self) -> Result<u16, Error<E>> {
53        let t = self.read_u16(Register::TA)?;
54        let t = (t * 2) / 100 - 273;
55        Ok(t)
56    }
57
58    /// Read the object temperature in celsius degrees
59    pub fn object_temperature(&mut self) -> Result<f32, Error<E>> {
60        let t = self.read_u16(Register::TOBJ)?;
61        let t = f32::from(t) * 0.02 - 273.15;
62        Ok(t)
63    }
64
65    /// Read the object temperature in celsius degrees
66    ///
67    /// Note ONLY use to avoid floating-point ops, as this gives less accurate
68    /// temperature readings compared to using `object_temperature()`.
69    pub fn object_temperature_as_int(&mut self) -> Result<u16, Error<E>> {
70        let t = self.read_u16(Register::TOBJ)?;
71        let t = (t * 2) / 100 - 273;
72        Ok(t)
73    }
74
75    /// Read the raw IR data
76    pub fn raw_ir(&mut self) -> Result<u16, Error<E>> {
77        self.read_u16(Register::RAW_IR)
78    }
79
80    /// Get emissivity epsilon
81    pub fn emissivity(&mut self) -> Result<f32, Error<E>> {
82        let raw = self.read_u16(Register::EMISSIVITY)?;
83        Ok(f32::from(raw) / 16384.0)
84    }
85
86    /// Set emissivity epsilon [0.0-1.0]
87    ///
88    /// Wrong values will return `Error::InvalidInputData`.
89    pub fn set_emissivity<D: DelayNs>(
90        &mut self,
91        epsilon: f32,
92        delay: &mut D,
93    ) -> Result<(), Error<E>> {
94        if epsilon < 0.0 || epsilon > 1.0 {
95            return Err(Error::InvalidInputData);
96        }
97        let eps = (epsilon * 16384.0 + 0.5) as u16;
98        self.write_u16_eeprom(Register::EMISSIVITY, eps, delay)
99    }
100
101    /// Get the device ID
102    pub fn device_id(&mut self) -> Result<u32, Error<E>> {
103        let id0 = self.read_u16(Register::ID0)?;
104        let id1 = self.read_u16(Register::ID0 + 1)?;
105        Ok((u32::from(id0) << 16) | u32::from(id1))
106    }
107}
108
109/// Wake device from sleep mode.
110///
111/// Note that this includes a 39ms delay.
112pub fn wake_mlx90615<E, P: OutputPin<Error = E>, D: DelayNs>(
113    scl: &mut P,
114    delay: &mut D,
115) -> Result<(), E> {
116    scl.set_low()?;
117    delay.delay_ms(u32::from(mlx90615::WAKE_DELAY_MS));
118    scl.set_high()
119}