1use embedded_hal::delay::DelayNs;
4use embedded_hal::i2c::I2c;
5use embedded_hal::spi::SpiDevice;
6use pamoja_core::Sensor;
7
8use super::{
9 image_updating, max_measurement_micros, measuring, register, Calibration, Config, CtrlMeas,
10 Measurement, Mode, Oversampling, Reading, CALIBRATION_LEN, CHIP_ID, DATA_LEN, RESET_WORD,
11 STARTUP_MICROS,
12};
13use crate::driver::{I2cRegisters, RegisterBus, SpiRegisters};
14use crate::error::{DriverError, SensorError};
15
16pub const STATUS_POLLS: u8 = 20;
19
20#[derive(Debug)]
50pub struct Bmp280<B, D> {
51 bus: B,
52 delay: D,
53 temperature: Oversampling,
54 pressure: Oversampling,
55 filter: u8,
56 calibration: Option<Calibration>,
57}
58
59impl<I2C: I2c, D> Bmp280<I2cRegisters<I2C>, D> {
60 pub fn i2c(bus: I2C, address: u8, delay: D) -> Self {
74 Bmp280::new(I2cRegisters::new(bus, address), delay)
75 }
76}
77
78impl<SPI: SpiDevice, D> Bmp280<SpiRegisters<SPI>, D> {
79 pub fn spi(device: SPI, delay: D) -> Self {
90 Bmp280::new(SpiRegisters::new(device), delay)
91 }
92}
93
94impl<B, D> Bmp280<B, D> {
95 pub fn new(bus: B, delay: D) -> Self {
106 Bmp280 {
107 bus,
108 delay,
109 temperature: Oversampling::X1,
110 pressure: Oversampling::X1,
111 filter: 0,
112 calibration: None,
113 }
114 }
115
116 pub fn with_oversampling(mut self, temperature: Oversampling, pressure: Oversampling) -> Self {
129 self.temperature = temperature;
130 self.pressure = pressure;
131 self
132 }
133
134 pub fn with_filter(mut self, code: u8) -> Self {
148 self.filter = code;
149 self
150 }
151
152 pub fn calibration(&self) -> Option<&Calibration> {
154 self.calibration.as_ref()
155 }
156
157 pub fn release(self) -> (B, D) {
163 (self.bus, self.delay)
164 }
165}
166
167impl<B: RegisterBus, D: DelayNs> Bmp280<B, D> {
168 pub fn init(&mut self) -> Result<(), DriverError<B::Error>> {
184 self.write(register::RESET, RESET_WORD)?;
185 self.delay.delay_us(STARTUP_MICROS);
186 self.wait(image_updating)?;
187
188 if self.read(register::CHIP_ID)? != CHIP_ID {
189 return Err(SensorError::Identity.into());
190 }
191
192 let mut trimming = [0u8; CALIBRATION_LEN];
193 self.bus
194 .read_registers(register::CALIBRATION, &mut trimming)
195 .map_err(DriverError::Bus)?;
196 self.calibration = Some(Calibration::parse(&trimming));
197
198 let config = Config {
199 filter: self.filter,
200 ..Config::default()
201 };
202 self.write(register::CONFIG, config.bits())?;
203 self.write(register::CTRL_MEAS, self.ctrl_meas(Mode::Sleep).bits())?;
204 Ok(())
205 }
206
207 pub fn measure(&mut self) -> Result<Reading, DriverError<B::Error>> {
226 if self.calibration.is_none() {
227 self.init()?;
228 }
229 self.write(register::CTRL_MEAS, self.ctrl_meas(Mode::Forced).bits())?;
230 self.delay
231 .delay_us(max_measurement_micros(self.temperature, self.pressure));
232 self.wait(measuring)?;
233
234 let mut data = [0u8; DATA_LEN];
235 self.bus
236 .read_registers(register::DATA, &mut data)
237 .map_err(DriverError::Bus)?;
238 let raw = Measurement::parse(&data);
239 let calibration = self.calibration.as_ref().expect("read at initialization");
240 Ok(calibration.compensate(&raw))
241 }
242
243 fn ctrl_meas(&self, mode: Mode) -> CtrlMeas {
244 CtrlMeas {
245 temperature: self.temperature,
246 pressure: self.pressure,
247 mode,
248 }
249 }
250
251 fn read(&mut self, register: u8) -> Result<u8, DriverError<B::Error>> {
252 self.bus.read_register(register).map_err(DriverError::Bus)
253 }
254
255 fn write(&mut self, register: u8, value: u8) -> Result<(), DriverError<B::Error>> {
256 self.bus
257 .write_register(register, value)
258 .map_err(DriverError::Bus)
259 }
260
261 fn wait(&mut self, busy: fn(u8) -> bool) -> Result<(), DriverError<B::Error>> {
262 for _ in 0..STATUS_POLLS {
263 if !busy(self.read(register::STATUS)?) {
264 return Ok(());
265 }
266 self.delay.delay_ms(1);
267 }
268 Err(DriverError::Timeout)
269 }
270}
271
272impl<B, D> Sensor for Bmp280<B, D>
273where
274 B: RegisterBus + Send,
275 B::Error: core::fmt::Debug,
276 D: DelayNs + Send,
277{
278 type Reading = Reading;
279
280 async fn read(&mut self) -> pamoja_core::Result<Reading> {
281 self.measure().map_err(pamoja_core::Error::from)
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288 use crate::bmp280::{Standby, I2C_ADDRESS_PRIMARY, I2C_ADDRESS_SECONDARY};
289 use crate::driver::{SPI_ADDRESS_MASK, SPI_READ};
290 use alloc::vec;
291 use alloc::vec::Vec;
292 use embedded_hal::i2c::{ErrorKind, NoAcknowledgeSource};
293 use pamoja_hal::script::{block_on, DelayLog, I2cScript, I2cStep, SpiScript, SpiStep};
294
295 const CALIBRATION: [u8; CALIBRATION_LEN] = [
298 0x70, 0x6B, 0x43, 0x67, 0x18, 0xFC, 0x7D, 0x8E, 0x43, 0xD6, 0xD0, 0x0B, 0x27, 0x0B, 0x8C,
299 0x00, 0xF9, 0xFF, 0x8C, 0x3C, 0xF8, 0xC6, 0x70, 0x17,
300 ];
301 const DATA: [u8; DATA_LEN] = [0x65, 0x5A, 0xC0, 0x7E, 0xED, 0x00];
302
303 fn init_steps(address: u8, config: u8, ctrl_meas: u8) -> Vec<I2cStep> {
304 vec![
305 I2cStep::write(address, [register::RESET, RESET_WORD]),
306 I2cStep::write_read(address, [register::STATUS], [0x00]),
307 I2cStep::write_read(address, [register::CHIP_ID], [CHIP_ID]),
308 I2cStep::write_read(address, [register::CALIBRATION], CALIBRATION),
309 I2cStep::write(address, [register::CONFIG, config]),
310 I2cStep::write(address, [register::CTRL_MEAS, ctrl_meas]),
311 ]
312 }
313
314 fn measure_steps(address: u8, ctrl_meas: u8) -> Vec<I2cStep> {
315 vec![
316 I2cStep::write(address, [register::CTRL_MEAS, ctrl_meas]),
317 I2cStep::write_read(address, [register::STATUS], [0x00]),
318 I2cStep::write_read(address, [register::DATA], DATA),
319 ]
320 }
321
322 #[test]
323 fn init_follows_the_datasheet_sequence_and_keeps_the_calibration() {
324 let mut steps = init_steps(I2C_ADDRESS_PRIMARY, 0x00, 0x24);
325 steps.extend(measure_steps(I2C_ADDRESS_PRIMARY, 0x25));
326 let mut sensor = Bmp280::i2c(I2cScript::new(steps), I2C_ADDRESS_PRIMARY, DelayLog::new());
327 sensor.init().unwrap();
328 let expected = Calibration::parse(&CALIBRATION);
329 assert_eq!(sensor.calibration(), Some(&expected));
330
331 let reading = sensor.measure().unwrap();
332 assert_eq!(reading, expected.compensate(&Measurement::parse(&DATA)));
333 assert_eq!(reading.temperature_centi_celsius, 2508);
334 assert_eq!(reading.pascals(), 100_653);
335
336 let (bus, delay) = sensor.release();
337 assert!(bus.release().done());
338 assert_eq!(delay.waits_ns()[0], STARTUP_MICROS * 1_000);
339 assert_eq!(
340 delay.waits_ns()[1],
341 6_425 * 1_000,
342 "x1, x1 is 6.425 ms at most"
343 );
344 }
345
346 #[test]
347 fn oversampling_and_filter_settings_reach_the_control_registers() {
348 let config = Config {
349 standby: Standby::Ms0_5,
350 filter: 0b100,
351 spi_3wire: false,
352 }
353 .bits();
354 let ctrl_meas_sleep = CtrlMeas {
355 temperature: Oversampling::X2,
356 pressure: Oversampling::X16,
357 mode: Mode::Sleep,
358 }
359 .bits();
360 let mut steps = init_steps(I2C_ADDRESS_SECONDARY, config, ctrl_meas_sleep);
361 steps.extend(measure_steps(I2C_ADDRESS_SECONDARY, ctrl_meas_sleep | 0x01));
362 let mut sensor = Bmp280::i2c(
363 I2cScript::new(steps),
364 I2C_ADDRESS_SECONDARY,
365 DelayLog::new(),
366 )
367 .with_oversampling(Oversampling::X2, Oversampling::X16)
368 .with_filter(0b100);
369 sensor.measure().unwrap();
370 let (bus, delay) = sensor.release();
371 assert!(bus.release().done());
372 let expected = max_measurement_micros(Oversampling::X2, Oversampling::X16);
373 assert_eq!(delay.waits_ns()[1], expected * 1_000);
374 assert_eq!(
375 expected, 43_225,
376 "the ultra high resolution row of Table 13, 43.2 ms"
377 );
378 }
379
380 #[test]
381 fn init_waits_while_the_trimming_image_is_still_loading() {
382 let mut steps = vec![
383 I2cStep::write(0x76, [register::RESET, RESET_WORD]),
384 I2cStep::write_read(0x76, [register::STATUS], [0x01]),
385 I2cStep::write_read(0x76, [register::STATUS], [0x01]),
386 ];
387 steps.extend(init_steps(0x76, 0x00, 0x24).into_iter().skip(1));
388 let mut sensor = Bmp280::i2c(I2cScript::new(steps), 0x76, DelayLog::new());
389 sensor.init().unwrap();
390 let (bus, delay) = sensor.release();
391 assert!(bus.release().done());
392 assert_eq!(
393 delay.waits_ns(),
394 [STARTUP_MICROS * 1_000, 1_000_000, 1_000_000]
395 );
396
397 let mut steps = vec![I2cStep::write(0x76, [register::RESET, RESET_WORD])];
398 for _ in 0..STATUS_POLLS {
399 steps.push(I2cStep::write_read(0x76, [register::STATUS], [0x01]));
400 }
401 let mut sensor = Bmp280::i2c(I2cScript::new(steps), 0x76, DelayLog::new());
402 assert_eq!(sensor.init(), Err(DriverError::Timeout));
403 assert!(sensor.calibration().is_none());
404 assert!(sensor.release().0.release().done());
405 }
406
407 #[test]
408 fn a_part_that_is_not_a_bmp280_is_refused_before_anything_else() {
409 let steps = [
410 I2cStep::write(0x76, [register::RESET, RESET_WORD]),
411 I2cStep::write_read(0x76, [register::STATUS], [0x00]),
412 I2cStep::write_read(0x76, [register::CHIP_ID], [0x60]),
413 ];
414 let mut sensor = Bmp280::i2c(I2cScript::new(steps), 0x76, DelayLog::new());
415 assert_eq!(
416 sensor.init(),
417 Err(DriverError::Sensor(SensorError::Identity))
418 );
419 assert!(sensor.calibration().is_none());
420 assert!(sensor.release().0.release().done());
421 }
422
423 #[test]
424 fn a_conversion_that_never_finishes_is_a_timeout() {
425 let mut steps = init_steps(0x76, 0x00, 0x24);
426 steps.push(I2cStep::write(0x76, [register::CTRL_MEAS, 0x25]));
427 for _ in 0..STATUS_POLLS {
428 steps.push(I2cStep::write_read(0x76, [register::STATUS], [0x08]));
429 }
430 let mut sensor = Bmp280::i2c(I2cScript::new(steps), 0x76, DelayLog::new());
431 assert_eq!(sensor.measure(), Err(DriverError::Timeout));
432 assert!(sensor.release().0.release().done());
433 }
434
435 #[test]
436 fn a_bus_fault_surfaces_as_a_bus_error_and_maps_to_the_core_io_error() {
437 let kind = ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address);
438 let steps = [I2cStep::fault(0x76, kind)];
439 let mut sensor = Bmp280::i2c(I2cScript::new(steps), 0x76, DelayLog::new());
440 let error = sensor.init().unwrap_err();
441 assert!(matches!(error, DriverError::Bus(_)));
442 let core: pamoja_core::Error = error.into();
443 assert!(matches!(core, pamoja_core::Error::Io(_)));
444 }
445
446 #[test]
447 fn as_a_sensor_it_reads_and_maps_to_one_channel() {
448 let mut steps = init_steps(0x76, 0x00, 0x24);
449 steps.extend(measure_steps(0x76, 0x25));
450 let sensor = Bmp280::i2c(I2cScript::new(steps), 0x76, DelayLog::new());
451 let mut pascals = sensor.map(|reading| reading.pascals());
452 assert_eq!(block_on(pascals.read()).unwrap(), 100_653);
453 assert!(pascals.into_inner().release().0.release().done());
454 }
455
456 #[test]
457 fn over_spi_the_same_sequence_uses_the_bosch_control_bytes() {
458 assert_eq!(register::DATA & SPI_ADDRESS_MASK, 0x77);
461 assert_eq!(register::DATA | SPI_READ, 0xF7);
462 assert_eq!(register::CTRL_MEAS & SPI_ADDRESS_MASK, 0x74);
463 let steps = [
464 SpiStep::write([register::RESET & SPI_ADDRESS_MASK, RESET_WORD]),
465 SpiStep::write([register::STATUS | SPI_READ]),
466 SpiStep::read([0x00]),
467 SpiStep::write([register::CHIP_ID | SPI_READ]),
468 SpiStep::read([CHIP_ID]),
469 SpiStep::write([register::CALIBRATION | SPI_READ]),
470 SpiStep::read(CALIBRATION),
471 SpiStep::write([register::CONFIG & SPI_ADDRESS_MASK, 0x00]),
472 SpiStep::write([register::CTRL_MEAS & SPI_ADDRESS_MASK, 0x24]),
473 SpiStep::write([register::CTRL_MEAS & SPI_ADDRESS_MASK, 0x25]),
474 SpiStep::write([register::STATUS | SPI_READ]),
475 SpiStep::read([0x00]),
476 SpiStep::write([register::DATA | SPI_READ]),
477 SpiStep::read(DATA),
478 ];
479 let mut sensor = Bmp280::spi(SpiScript::new(steps), DelayLog::new());
480 let reading = sensor.measure().unwrap();
481 assert_eq!(reading.temperature_centi_celsius, 2508);
482 assert!(sensor.release().0.release().done());
483 }
484
485 #[test]
486 fn init_and_a_forced_measurement_make_the_transfers_the_datasheet_gives() {
487 const PART: u8 = crate::bmp280::I2C_ADDRESS_PRIMARY;
488 let trimming = [
489 0x70, 0x6B, 0x43, 0x67, 0x18, 0xFC, 0x7D, 0x8E, 0x43, 0xD6, 0xD0, 0x0B, 0x27, 0x0B,
490 0x8C, 0x00, 0xF9, 0xFF, 0x8C, 0x3C, 0xF8, 0xC6, 0x70, 0x17,
491 ];
492 let bus = I2cScript::new([
493 I2cStep::write(PART, [0xE0, 0xB6]),
494 I2cStep::write_read(PART, [0xF3], [0x00]),
495 I2cStep::write_read(PART, [0xD0], [0x58]),
496 I2cStep::write_read(PART, [0x88], trimming),
497 I2cStep::write(PART, [0xF5, 0x00]),
498 I2cStep::write(PART, [0xF4, 0x24]),
499 I2cStep::write(PART, [0xF4, 0x25]),
500 I2cStep::write_read(PART, [0xF3], [0x00]),
501 I2cStep::write_read(PART, [0xF7], [0x65, 0x5A, 0xC0, 0x7E, 0xED, 0x00]),
502 ]);
503
504 let mut sensor = Bmp280::i2c(bus, PART, DelayLog::new());
505 let reading = block_on(Sensor::read(&mut sensor)).expect("the scripted part answers");
506 assert_eq!(reading.temperature_centi_celsius, 2508);
507 assert_eq!(reading.pascals(), 100_653);
508
509 let (registers, delay) = sensor.release();
510 assert!(registers.release().done());
511 assert!(delay.total_micros() >= 2_000 + 6_425);
512 }
513}