capsules_extra/
bmp280.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 2022.
4
5//! hil driver for Bmp280 Temperature and Pressure Sensor
6//!
7//! Written by Dorota <gihu.dcz@porcupinefactory.org>
8//!
9//! Based off the SHT3x code.
10//!
11//! Not implemented: pressure
12
13use core::cell::Cell;
14use kernel::debug;
15use kernel::hil;
16use kernel::hil::i2c;
17use kernel::hil::time::{Alarm, ConvertTicks};
18use kernel::utilities::cells::{OptionalCell, TakeCell};
19use kernel::ErrorCode;
20
21pub static BASE_ADDR: u8 = 0x76;
22
23/// Currently sized enough for temperature readings only.
24pub const BUFFER_SIZE: usize = 6;
25
26#[allow(non_camel_case_types)]
27#[allow(dead_code)]
28enum Register {
29    /// First register of calibration data.
30    /// Each register is 2 bytes long.
31    DIG_T1 = 0x88,
32    DIG_T2 = 0x8a,
33    DIG_T3 = 0x8c,
34    ID = 0xd0,
35    RESET = 0xe0,
36    // measuring: [3]
37    // im_update: [0]
38    STATUS = 0xf3,
39    // osrs_t: [7:5]
40    // osrs_p: [4:2]
41    // mode: [1:0]
42    CTRL_MEAS = 0xf4,
43    // t_sb: [7:5]
44    // filter: [4:2]
45    // spi3w_en: [0]
46    CONFIG = 0xf5,
47    PRESS_MSB = 0xf7,
48    PRESS_LSB = 0xf8,
49    // xlsb: [7:4]
50    PRESS_XLSB = 0xf9,
51    TEMP_MSB = 0xfa,
52    TEMP_LSB = 0xfb,
53    // xlsb: [7:4]
54    TEMP_XLSB = 0xfc,
55}
56
57#[derive(Clone, Copy, PartialEq, Debug)]
58struct CalibrationData {
59    dig_t1: u16,
60    dig_t2: i16,
61    dig_t3: i16,
62    // TODO: pressure calibration
63}
64
65/// CAUTION: calibration data puts least significant byte in the lowest address,
66/// readouts do the opposite.
67fn twobyte(lsb: u8, msb: u8) -> u16 {
68    u16::from_be_bytes([msb, lsb])
69}
70
71impl CalibrationData {
72    fn new(i2c_raw: &[u8]) -> Self {
73        CalibrationData {
74            dig_t1: twobyte(i2c_raw[0], i2c_raw[1]),
75            dig_t2: twobyte(i2c_raw[2], i2c_raw[3]) as i16,
76            dig_t3: twobyte(i2c_raw[4], i2c_raw[5]) as i16,
77        }
78    }
79
80    fn temp_from_raw(&self, temp: i32) -> i32 {
81        let dig_t1 = self.dig_t1 as i32; // same, 16-bits
82        let dig_t2 = self.dig_t2 as i32; // same, 16-bits
83        let dig_t3 = self.dig_t3 as i32; // same, 16-bits
84                                         // From the datasheet
85        let var1 = (((temp >> 3) - (dig_t1 << 1)) * dig_t2) >> 11;
86        let a = (temp >> 4) - dig_t1;
87        let var2 = (((a * a) >> 12) * dig_t3) >> 14;
88        let t_fine = var1 + var2;
89        ((t_fine * 5) + 128) >> 8
90    }
91}
92
93/// Internal state.
94/// Each state can lead to the next on in order of appearance.
95#[derive(Clone, Copy, PartialEq, Debug)]
96enum State {
97    Uninitialized,
98    InitId,
99    /// It's not guaranteed that the MCU reset is the same as device power-on,
100    /// so an explicit reset is necessary.
101    InitResetting,
102    InitWaitingReady,
103    InitReadingCalibration,
104
105    Idle(CalibrationData),
106
107    // States related to sample readout
108    /// One-shot mode request sent
109    Configuring(CalibrationData),
110    /// Sampling takes milliseconds, so spend most of that time sleeping.
111    WaitingForAlarm(CalibrationData),
112    /// Polling for the readout to become ready.
113    Waiting(CalibrationData),
114    /// Waiting for readout to return.
115    /// This state can also lead back to Idle.
116    Reading(CalibrationData),
117
118    /// Reset cannot be attempted.
119    /// This is because reset failed before, or because the ID is mismatched.
120    IrrecoverableError,
121    /// Irrecoverable. Currently only when init fails.
122    /// Reset will clear this.
123    Error,
124    /// An unexpected, irrecoverable situation was encountered,
125    /// and the driver is giving up.
126    /// Reset clears this.
127    Bug,
128}
129
130impl State {
131    /// Changes state to one denoting this driver is buggy.
132    fn to_bug(self) -> Self {
133        match self {
134            // A bug does not override the device not being present.
135            State::IrrecoverableError => State::IrrecoverableError,
136            _ => State::Bug,
137        }
138    }
139}
140
141/// Complies with the reading and writing protocol used by the sensor.
142struct I2cWrapper<'a, I: i2c::I2CDevice> {
143    i2c: &'a I,
144}
145
146impl<I: i2c::I2CDevice> I2cWrapper<'_, I> {
147    fn write<const COUNT: usize>(
148        &self,
149        buffer: &'static mut [u8],
150        addr: Register,
151        data: [u8; COUNT],
152    ) -> Result<(), (i2c::Error, &'static mut [u8])> {
153        buffer[0] = addr as u8;
154        buffer[1..][..COUNT].copy_from_slice(&data);
155        self.i2c.enable();
156        self.i2c.write(buffer, COUNT + 1)
157    }
158
159    /// Requests a read into buffer.
160    /// Parse the result using `parse_read`.
161    fn read(
162        &self,
163        buffer: &'static mut [u8],
164        addr: Register,
165        count: usize,
166    ) -> Result<(), (i2c::Error, &'static mut [u8])> {
167        buffer[0] = addr as u8;
168        self.i2c.enable();
169        self.i2c.write_read(buffer, 1, count)
170    }
171
172    fn disable(&self) {
173        self.i2c.disable()
174    }
175
176    fn parse_read(buffer: &[u8], count: u8) -> &[u8] {
177        &buffer[..(count as usize)]
178    }
179}
180
181pub struct Bmp280<'a, A: Alarm<'a>, I: i2c::I2CDevice> {
182    i2c: I2cWrapper<'a, I>,
183    temperature_client: OptionalCell<&'a dyn hil::sensors::TemperatureClient>,
184    // This might be better as a `RefCell`,
185    // because `State` is multiple bytes due to the `CalibrationData`.
186    // `Cell` requires Copy, which might get expensive, while `RefCell` doesn't.
187    // It's probably not a good idea to split `CalibrationData`
188    // into a separate place, because it will make state more duplicated.
189    state: Cell<State>,
190    /// Stores i2c commands
191    buffer: TakeCell<'static, [u8]>,
192    /// Needed to wait for readout completion, which can take milliseconds.
193    /// It's possible to implement this without an alarm with busy polling, but that's wasteful.
194    alarm: &'a A,
195}
196
197impl<'a, A: Alarm<'a>, I: i2c::I2CDevice> Bmp280<'a, A, I> {
198    pub fn new(i2c: &'a I, buffer: &'static mut [u8], alarm: &'a A) -> Self {
199        Self {
200            i2c: I2cWrapper { i2c },
201            temperature_client: OptionalCell::empty(),
202            state: Cell::new(State::Uninitialized),
203            buffer: TakeCell::new(buffer),
204            alarm,
205        }
206    }
207
208    /// Resets the device and brings it into a known state.
209    pub fn begin_reset(&self) -> Result<(), ErrorCode> {
210        self.buffer
211            .take()
212            .map_or(Err(ErrorCode::NOMEM), |buffer| match self.state.get() {
213                State::Uninitialized | State::Error | State::Bug => {
214                    let (ret, new_state) = match self.i2c.read(buffer, Register::ID, 1) {
215                        Ok(()) => (Ok(()), State::InitId),
216                        Err((_e, buffer)) => {
217                            self.i2c.disable();
218                            self.buffer.replace(buffer);
219                            (Err(ErrorCode::FAIL), State::IrrecoverableError)
220                        }
221                    };
222                    self.state.set(new_state);
223                    ret
224                }
225                State::IrrecoverableError => Err(ErrorCode::NODEVICE),
226                _ => Err(ErrorCode::ALREADY),
227            })
228    }
229
230    pub fn read_temperature(&self) -> Result<(), ErrorCode> {
231        match self.state.get() {
232            // Actually, the sensor might be on, just in default state.
233            State::Uninitialized => Err(ErrorCode::OFF),
234            State::InitId
235            | State::InitResetting
236            | State::InitWaitingReady
237            | State::InitReadingCalibration => Err(ErrorCode::BUSY),
238            State::Idle(calibration) => {
239                self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
240                    // todo: use bitfield crate
241                    // forced mode, oversampling 1
242                    let val = 0b00100001;
243                    let (ret, new_state) = match self.i2c.write(buffer, Register::CTRL_MEAS, [val])
244                    {
245                        Ok(()) => (Ok(()), State::Configuring(calibration)),
246                        Err((_e, buffer)) => {
247                            self.i2c.disable();
248                            self.buffer.replace(buffer);
249                            (Err(ErrorCode::FAIL), State::Idle(calibration))
250                        }
251                    };
252                    self.state.set(new_state);
253                    ret
254                })
255            }
256            State::Configuring(_)
257            | State::WaitingForAlarm(_)
258            | State::Waiting(_)
259            | State::Reading(_) => Err(ErrorCode::BUSY),
260            State::Error | State::Bug => Err(ErrorCode::FAIL),
261            State::IrrecoverableError => Err(ErrorCode::NODEVICE),
262        }
263    }
264
265    fn handle_alarm(&self) {
266        match self.state.get() {
267            State::WaitingForAlarm(calibration) => self.buffer.take().map_or_else(
268                || {
269                    debug!("BMP280 No buffer available!");
270                    self.state.set(State::IrrecoverableError)
271                },
272                |buffer| {
273                    let new_state = match self.check_ready(buffer) {
274                        Ok(()) => State::Waiting(calibration),
275                        Err((_e, buffer)) => {
276                            self.i2c.disable();
277                            self.buffer.replace(buffer);
278                            State::Idle(calibration)
279                        }
280                    };
281                    self.state.set(new_state)
282                },
283            ),
284            State::IrrecoverableError => {}
285            other => {
286                debug!("BMP280 received unexpected alarm in state {:?}", other);
287                self.state.set(other.to_bug())
288            }
289        }
290    }
291
292    fn arm_alarm(&self) {
293        // Datasheet says temp oversampling=1 makes a reading typically take 5.5ms.
294        // (Maximally 6.4ms).
295        let delay = self.alarm.ticks_from_us(6400);
296        self.alarm.set_alarm(self.alarm.now(), delay);
297    }
298
299    fn check_ready(
300        &self,
301        buffer: &'static mut [u8],
302    ) -> Result<(), (i2c::Error, &'static mut [u8])> {
303        self.i2c.read(buffer, Register::STATUS, 1)
304    }
305}
306
307enum I2cOperation {
308    Read {
309        addr: Register,
310        count: usize,
311        fail_state: State,
312    },
313    Write {
314        addr: Register,
315        data: u8,
316        fail_state: State,
317    },
318    Disable,
319}
320
321impl I2cOperation {
322    fn check_ready(fail_state: State) -> Self {
323        Self::Read {
324            addr: Register::STATUS,
325            count: 1,
326            fail_state,
327        }
328    }
329}
330
331impl<'a, A: Alarm<'a>, I: i2c::I2CDevice> i2c::I2CClient for Bmp280<'a, A, I> {
332    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
333        let mut temp_readout = None;
334        let mut i2c_op = I2cOperation::Disable;
335
336        let new_state = match status {
337            Ok(()) => match self.state.get() {
338                State::InitId => {
339                    let id = I2cWrapper::<I>::parse_read(buffer, 1);
340                    if id[0] == 0x58 {
341                        i2c_op = I2cOperation::Write {
342                            addr: Register::RESET,
343                            data: 0xb6,
344                            fail_state: State::IrrecoverableError,
345                        };
346                        State::InitResetting
347                    } else {
348                        State::IrrecoverableError
349                    }
350                }
351                State::InitResetting => {
352                    i2c_op = I2cOperation::check_ready(State::Error);
353                    State::InitWaitingReady
354                }
355                State::InitWaitingReady => {
356                    let waiting = I2cWrapper::<I>::parse_read(buffer, 1)[0];
357                    if waiting & 0b1 == 0 {
358                        // finished init
359                        i2c_op = I2cOperation::Read {
360                            addr: Register::DIG_T1,
361                            count: 6,
362                            fail_state: State::Error,
363                        };
364                        State::InitReadingCalibration
365                    } else {
366                        i2c_op = I2cOperation::check_ready(State::Error);
367                        State::InitWaitingReady
368                    }
369                }
370                State::InitReadingCalibration => {
371                    let data = I2cWrapper::<I>::parse_read(buffer, 6);
372                    let calibration = CalibrationData::new(data);
373                    State::Idle(calibration)
374                }
375                // Readout-related states
376                State::Configuring(calibration) => {
377                    self.arm_alarm();
378                    State::WaitingForAlarm(calibration)
379                }
380                State::Waiting(calibration) => {
381                    let waiting_value = I2cWrapper::<I>::parse_read(buffer, 1);
382                    // not waiting
383                    if waiting_value[0] & 0b1000 == 0 {
384                        i2c_op = I2cOperation::Read {
385                            addr: Register::TEMP_MSB,
386                            count: 3,
387                            fail_state: State::Idle(calibration),
388                        };
389                        State::Reading(calibration)
390                    } else {
391                        i2c_op = I2cOperation::check_ready(State::Idle(calibration));
392                        State::Waiting(calibration)
393                    }
394                }
395                State::Reading(calibration) => {
396                    let readout = I2cWrapper::<I>::parse_read(buffer, 3);
397                    let msb = readout[0] as u32;
398                    let lsb = readout[1] as u32;
399                    let xlsb = readout[2] as u32;
400                    let raw_temp: i32 =
401                        ((((msb << 12) + (lsb << 4) + (xlsb >> 4)) << 12) as i32) >> 12; // ensure sign extention
402                    temp_readout = Some(Ok(calibration.temp_from_raw(raw_temp)));
403                    State::Idle(calibration)
404                }
405                other => {
406                    debug!("BMP280 received unexpected i2c reply in state {:?}", other);
407                    other.to_bug()
408                }
409            },
410            Err(i2c_err) => match self.state.get() {
411                State::Configuring(calibration)
412                | State::Waiting(calibration)
413                | State::Reading(calibration) => {
414                    temp_readout = Some(Err(i2c_err.into()));
415                    State::Idle(calibration)
416                }
417                State::InitId
418                | State::InitResetting
419                | State::InitWaitingReady
420                | State::InitReadingCalibration => State::Error,
421                other => {
422                    debug!("BMP280 received unexpected i2c reply in state {:?}", other);
423                    other.to_bug()
424                }
425            },
426        };
427
428        // Try enqueueing the requested i2c operation
429        let new_state = match i2c_op {
430            I2cOperation::Disable => {
431                self.i2c.disable();
432                self.buffer.replace(buffer);
433                new_state
434            }
435            I2cOperation::Read {
436                addr,
437                count,
438                fail_state,
439            } => {
440                if let Err((_e, buffer)) = self.i2c.read(buffer, addr, count) {
441                    self.i2c.disable();
442                    self.buffer.replace(buffer);
443                    fail_state
444                } else {
445                    new_state
446                }
447            }
448            I2cOperation::Write {
449                addr,
450                data,
451                fail_state,
452            } => {
453                if let Err((_e, buffer)) = self.i2c.write(buffer, addr, [data]) {
454                    self.i2c.disable();
455                    self.buffer.replace(buffer);
456                    fail_state
457                } else {
458                    new_state
459                }
460            }
461        };
462
463        // Setting state before the callback,
464        // in case the callback wants to use the same driver again.
465        self.state.set(new_state);
466        if let Some(temp) = temp_readout {
467            self.temperature_client.map(|cb| cb.callback(temp));
468        }
469    }
470}
471
472impl<'a, A: Alarm<'a>, I: i2c::I2CDevice> hil::sensors::TemperatureDriver<'a> for Bmp280<'a, A, I> {
473    fn set_client(&self, client: &'a dyn hil::sensors::TemperatureClient) {
474        self.temperature_client.set(client)
475    }
476
477    fn read_temperature(&self) -> Result<(), ErrorCode> {
478        self.read_temperature()
479    }
480}
481
482impl<'a, A: hil::time::Alarm<'a>, I: i2c::I2CDevice> hil::time::AlarmClient for Bmp280<'a, A, I> {
483    fn alarm(&self) {
484        self.handle_alarm()
485    }
486}