aht10_embedded/
lib.rs

1#![no_std]
2
3use data::Aht10Data;
4/// Datasheet used for this driver : https://en.maritex.com.pl/product/attachment/147096/c5093eda6658ef654b651f3d5705c2ef
5/// It's very basic, and lot of information is missing.
6use embedded_hal as hal;
7use hal::blocking::{
8    delay::DelayMs,
9    i2c::{Read, Write},
10};
11
12pub mod data;
13
14const AHT10_ADDRESS: u8 = 0x38;
15
16const AHT10_INIT_MODE_NORMAL: u8 = 0x00;
17
18const AHT10_INIT_MODE_CYCLE: u8 = 0x20;
19const AHT10_INIT_MODE_CMD: u8 = 0x40; // ???
20
21const AHT10_INIT_CALIBRATION_ON: u8 = 0x08;
22const AHT10_INIT_CALIBRATION_OFF: u8 = 0x00;
23
24enum Aht10Commands {
25    Initialization = 0b1110_0001,
26    TriggerMeasure = 0b1010_1100,
27    SoftReset = 0b1011_1010,
28}
29
30#[derive(Debug, Copy, Clone)]
31pub enum AhtError<E> {
32    ReadTimeout,
33    BusError(E),
34}
35
36#[derive(Debug, Copy, Clone)]
37pub struct Aht10Status {
38    pub is_busy: bool,
39    pub working_mode: u8,
40    pub calibration_enable: bool,
41}
42
43pub struct AHT10<I2C> {
44    i2c_dev: I2C,
45}
46
47impl<I2C, E> AHT10<I2C>
48where
49    I2C: Write<Error = E> + Read<Error = E>,
50{
51    pub fn new(i2c: I2C) -> Self {
52        Self { i2c_dev: i2c }
53    }
54
55    /// Initialize the sensor.
56    pub fn initialize(&mut self) -> Result<(), AhtError<E>> {
57        self.write_command(
58            Aht10Commands::Initialization,
59            AHT10_INIT_MODE_NORMAL | AHT10_INIT_CALIBRATION_ON,
60            0x00,
61        )
62    }
63
64    /// Read the internal status register.
65    pub fn read_status(&mut self) -> Result<Aht10Status, AhtError<E>> {
66        let mut buffer: [u8; 6] = [0; 6];
67        self.i2c_dev
68            .read(AHT10_ADDRESS, &mut buffer)
69            .map_err(|e| AhtError::BusError(e))?;
70
71        let is_busy = (buffer[0] & 0x80) > 0;
72        let working_mode = (buffer[0] & 0x60) >> 4;
73        let calibration_enable = (buffer[0] & 0x08) > 0;
74
75        Ok(Aht10Status {
76            is_busy,
77            working_mode,
78            calibration_enable,
79        })
80    }
81
82    /// Triggers and waits for measurements. This is a blocking function, which takes at least 70 ms (3 retries of 75ms each).
83    pub fn read_data<Delay: DelayMs<u16>>(
84        &mut self,
85        delay: &mut Delay,
86    ) -> Result<Aht10Data, AhtError<E>> {
87        self.write_command(Aht10Commands::TriggerMeasure, 0x33, 0x00)?; // 0x33 is a magic value given by the "datasheet"
88
89        let mut status = self.read_status()?;
90        for _ in 0..3 {
91            if !status.is_busy {
92                break;
93            }
94
95            delay.delay_ms(75);
96            status = self.read_status()?;
97        }
98
99        if status.is_busy {
100            return Err(AhtError::ReadTimeout);
101        }
102
103        let raw = self.read_raw_data()?;
104        Ok(Aht10Data::new(raw))
105    }
106
107    /// Reset the sensor. This is a blocking function, the reset takes 20ms. WARNING: You must re-initialize the sensor after the reset !
108    pub fn soft_reset<Delay: DelayMs<u16>>(
109        &mut self,
110        delay: &mut Delay,
111    ) -> Result<(), AhtError<E>> {
112        self.write_command(Aht10Commands::SoftReset, 0, 0)?;
113        delay.delay_ms(20);
114        Ok(())
115    }
116
117    fn write_command(
118        &mut self,
119        cmd: Aht10Commands,
120        data0: u8,
121        data1: u8,
122    ) -> Result<(), AhtError<E>> {
123        self.i2c_dev
124            .write(AHT10_ADDRESS, &[cmd as u8, data0, data1])
125            .map_err(|e| AhtError::BusError(e))
126    }
127
128    fn read_raw_data(&mut self) -> Result<[u8; 5], AhtError<E>> {
129        let mut buffer: [u8; 6] = [0; 6];
130        self.i2c_dev
131            .read(AHT10_ADDRESS, &mut buffer)
132            .map_err(|e| AhtError::BusError(e))?;
133
134        Ok(buffer[1..6].try_into().unwrap())
135    }
136}