capsules_extra/
lps22hb.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2023.
4
5//! Sensor Driver for the LPS22HB MEMS nano pressure sensor
6//! using the I2C bus.
7//!
8//! <https://www.st.com/resource/en/datasheet/lps22hb.pdf>
9//!
10//! > The LPS22HB is an ultra-compact piezoresistive absolute
11//! > pressure sensor which functions as a digital output barometer.
12//! > The device comprises a sensing element and an IC interface
13//! > which communicates through I2C or SPI from the sensing element
14//! > to the application.
15//!
16//! Driver Semantics
17//! ----------------
18//!
19//! This driver exposes the LPS22HB's pressure functionality via
20//! the [PressureDriver] HIL interface. It doesn't support handling
21//! multiple concurrent pressure requests.
22//!
23//! Usage
24//! -----
25//!
26//! ```rust,ignore
27//! # use kernel::static_init;
28//!
29//! let lps22hb_i2c = static_init!(
30//!     capsules::virtual_i2c::I2CDevice,
31//!     capsules::virtual_i2c::I2CDevice::new(i2c_bus, 0x5C));
32//! let lps22hb = static_init!(
33//!     capsules::lps22hb::Lps22hb<'static>,
34//!     capsules::lps22hb::Lps22hb::new(lps22hb_i2c,
35//!         &mut capsules::lps22hb::BUFFER));
36//! lps22hb_i2c.set_client(lps22hb);
37//! ```
38
39use core::cell::Cell;
40use kernel::hil::i2c::{self, I2CClient, I2CDevice};
41use kernel::hil::sensors::{PressureClient, PressureDriver};
42use kernel::utilities::cells::{OptionalCell, TakeCell};
43use kernel::ErrorCode;
44
45/// Syscall driver number.
46use capsules_core::driver;
47pub const DRIVER_NUM: usize = driver::NUM::Pressure as usize;
48
49/// Register values
50
51const REGISTER_AUTO_INCREMENT: u8 = 0x80;
52const CTRL_REG1_ONE_SHOT: u8 = 0x00;
53
54#[allow(dead_code)]
55enum Registers {
56    IntCfgReg = 0x0B,
57    ThsPL = 0x0C,
58    ThsPH = 0x0D,
59    WhoAmI = 0x0F,
60    CtrlReg1 = 0x10,
61    CtrlReg2 = 0x11,
62    CtrlReg3 = 0x12,
63    FifoCtrl = 0x14,
64    RefPXl = 0x15,
65    RefPL = 0x16,
66    RefPH = 0x17,
67    RpdsL = 0x18,
68    RpdsH = 0x19,
69    ResConf = 0x1A,
70    IntSourceReg = 0x25,
71    FifoStatus = 0x26,
72    StatusReg = 0x27,
73    PressOutXl = 0x28,
74    PressOutL = 0x29,
75    PressOutH = 0x2A,
76    TempOutL = 0x2B,
77    TempOutH = 0x2C,
78    LpfpRes = 0x33,
79}
80
81pub struct Lps22hb<'a, I: I2CDevice> {
82    buffer: TakeCell<'static, [u8]>,
83    i2c_bus: &'a I,
84    pressure_client: OptionalCell<&'a dyn PressureClient>,
85    pending_pressure: Cell<bool>,
86    state: Cell<State>,
87}
88
89impl<'a, I: I2CDevice> Lps22hb<'a, I> {
90    pub fn new(i2c_bus: &'a I, buffer: &'static mut [u8]) -> Lps22hb<'a, I> {
91        Lps22hb {
92            buffer: TakeCell::new(buffer),
93            i2c_bus,
94            pressure_client: OptionalCell::empty(),
95            pending_pressure: Cell::new(false),
96            state: Cell::new(State::Sleep),
97        }
98    }
99
100    fn start_measurement(&self) -> Result<(), ErrorCode> {
101        self.buffer
102            .take()
103            .map(|buffer| {
104                self.i2c_bus.enable();
105                match self.state.get() {
106                    State::Sleep => {
107                        buffer[0] = Registers::WhoAmI as u8;
108
109                        if let Err((_error, buffer)) = self.i2c_bus.write_read(buffer, 1, 1) {
110                            self.buffer.replace(buffer);
111                            self.i2c_bus.disable();
112                        } else {
113                            self.state.set(State::PowerOn);
114                        }
115                    }
116                    State::Idle => {
117                        buffer[0] = Registers::CtrlReg2 as u8;
118                        buffer[1] = 0x11_u8;
119
120                        if let Err((_error, buffer)) = self.i2c_bus.write(buffer, 2) {
121                            self.buffer.replace(buffer);
122                            self.i2c_bus.disable();
123                        } else {
124                            self.state.set(State::Status);
125                        }
126                    }
127                    _ => {}
128                }
129            })
130            .ok_or(ErrorCode::FAIL)
131    }
132}
133
134impl<'a, I: I2CDevice> PressureDriver<'a> for Lps22hb<'a, I> {
135    fn set_client(&self, client: &'a dyn PressureClient) {
136        self.pressure_client.set(client);
137    }
138
139    fn read_atmospheric_pressure(&self) -> Result<(), ErrorCode> {
140        if !self.pending_pressure.get() {
141            self.pending_pressure.set(true);
142            self.start_measurement()
143        } else {
144            Err(ErrorCode::BUSY)
145        }
146    }
147}
148
149#[derive(Clone, Copy, PartialEq)]
150pub enum State {
151    Sleep,
152    PowerOn,
153    Idle,
154    ConfOut,
155    Status,
156    ReadMeasurementInit,
157    ReadMeasurement,
158    GotMeasurement,
159}
160
161impl<I: I2CDevice> I2CClient for Lps22hb<'_, I> {
162    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
163        if let Err(i2c_err) = status {
164            self.state.set(State::Idle);
165            self.buffer.replace(buffer);
166            self.pressure_client
167                .map(|client| client.callback(Err(i2c_err.into())));
168            return;
169        }
170
171        match self.state.get() {
172            State::PowerOn => {
173                if buffer[0] == 0xB1 {
174                    buffer[0] = Registers::CtrlReg1 as u8;
175                    buffer[1] = CTRL_REG1_ONE_SHOT;
176
177                    if let Err((i2c_err, buffer)) = self.i2c_bus.write(buffer, 2) {
178                        self.state.set(State::Idle);
179                        self.buffer.replace(buffer);
180                        self.pressure_client
181                            .map(|client| client.callback(Err(i2c_err.into())));
182                    } else {
183                        self.state.set(State::ConfOut);
184                    }
185                } else {
186                    self.state.set(State::Sleep);
187                }
188            }
189            State::ConfOut => {
190                buffer[0] = Registers::CtrlReg2 as u8;
191                buffer[1] = 0x11_u8;
192
193                if let Err((i2c_err, buffer)) = self.i2c_bus.write(buffer, 2) {
194                    self.state.set(State::Idle);
195                    self.buffer.replace(buffer);
196                    self.pressure_client
197                        .map(|client| client.callback(Err(i2c_err.into())));
198                } else {
199                    self.state.set(State::Status);
200                }
201            }
202            State::Status => {
203                buffer[0] = Registers::CtrlReg2 as u8;
204
205                if let Err((i2c_err, buffer)) = self.i2c_bus.write_read(buffer, 1, 1) {
206                    self.state.set(State::Idle);
207                    self.buffer.replace(buffer);
208                    self.pressure_client
209                        .map(|client| client.callback(Err(i2c_err.into())));
210                } else {
211                    self.state.set(State::ReadMeasurementInit);
212                }
213            }
214            State::ReadMeasurementInit => {
215                if buffer[0] == 0x10 {
216                    buffer[0] = Registers::PressOutXl as u8 | REGISTER_AUTO_INCREMENT;
217
218                    if let Err((i2c_err, buffer)) = self.i2c_bus.write(buffer, 1) {
219                        self.state.set(State::Idle);
220                        self.buffer.replace(buffer);
221                        self.pressure_client
222                            .map(|client| client.callback(Err(i2c_err.into())));
223                    } else {
224                        self.state.set(State::ReadMeasurement);
225                    }
226                } else {
227                    buffer[0] = Registers::CtrlReg2 as u8;
228
229                    if let Err((i2c_err, buffer)) = self.i2c_bus.write_read(buffer, 1, 1) {
230                        self.state.set(State::Idle);
231                        self.buffer.replace(buffer);
232                        self.pressure_client
233                            .map(|client| client.callback(Err(i2c_err.into())));
234                    } else {
235                        self.state.set(State::ReadMeasurementInit);
236                    }
237                }
238            }
239            State::ReadMeasurement => {
240                if let Err((i2c_err, buffer)) = self.i2c_bus.read(buffer, 3) {
241                    self.state.set(State::Idle);
242                    self.buffer.replace(buffer);
243                    self.pressure_client
244                        .map(|client| client.callback(Err(i2c_err.into())));
245                } else {
246                    self.state.set(State::GotMeasurement);
247                }
248            }
249            State::GotMeasurement => {
250                let pressure =
251                    (((buffer[2] as u32) << 16) | ((buffer[1] as u32) << 8) | (buffer[0] as u32))
252                        / 4096;
253
254                self.buffer.replace(buffer);
255                self.i2c_bus.disable();
256                if self.pending_pressure.get() {
257                    self.pending_pressure.set(false);
258                    self.pressure_client
259                        .map(|client| client.callback(Ok(pressure)));
260                }
261
262                self.state.set(State::Idle);
263            }
264            State::Sleep => {}
265            State::Idle => {}
266        }
267    }
268}