embedded_devices/devices/bosch/bmp390/
mod.rs1use embedded_devices_derive::{forward_register_fns, sensor};
77use embedded_interfaces::TransportError;
78use uom::si::f64::{Pressure, ThermodynamicTemperature};
79use uom::si::pressure::pascal;
80use uom::si::thermodynamic_temperature::degree_celsius;
81
82pub mod address;
83pub mod registers;
84
85use self::address::Address;
86use self::registers::{
87 BurstMeasurements, ChipId, Cmd, Config, DataRateControl, IIRFilter, Oversampling, OversamplingControl,
88 PowerControl, SensorMode, TrimmingCoefficients, TrimmingCoefficientsUnpacked,
89};
90
91#[cfg_attr(feature = "defmt", derive(defmt::Format))]
92#[derive(Debug, thiserror::Error)]
93pub enum InitError<BusError> {
94 #[error("transport error")]
96 Transport(#[from] TransportError<(), BusError>),
97 #[error("invalid chip id {0:#02x}")]
99 InvalidChip(u8),
100}
101
102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103#[derive(Debug, thiserror::Error)]
104pub enum MeasurementError<BusError> {
105 #[error("transport error")]
107 Transport(#[from] TransportError<(), BusError>),
108 #[error("not yet calibrated")]
110 NotCalibrated,
111}
112
113#[derive(Debug, embedded_devices_derive::Measurement)]
115pub struct Measurement {
116 #[measurement(Temperature)]
118 pub temperature: Option<ThermodynamicTemperature>,
119 #[measurement(Pressure)]
121 pub pressure: Option<Pressure>,
122}
123
124#[derive(Debug, Clone)]
128pub struct Configuration {
129 pub temperature_oversampling: Option<Oversampling>,
131 pub pressure_oversampling: Option<Oversampling>,
133 pub iir_filter: IIRFilter,
135}
136
137impl Default for Configuration {
138 fn default() -> Self {
139 Self {
140 temperature_oversampling: Some(Oversampling::X_1),
141 pressure_oversampling: Some(Oversampling::X_1),
142 iir_filter: IIRFilter::Disabled,
143 }
144 }
145}
146
147#[derive(Debug, Clone, Copy)]
150pub(super) struct TFine(i32);
151
152#[derive(Debug)]
153pub(super) struct CalibrationData(TrimmingCoefficientsUnpacked);
154
155impl CalibrationData {
156 pub(super) fn compensate_temperature(&self, uncompensated: u32) -> (ThermodynamicTemperature, TFine) {
157 let v1: u64 = (uncompensated as u64) - ((self.0.par_t1 as u64) << 8);
158 let v2: u64 = self.0.par_t2 as u64 * v1;
159 let v3: u64 = v1 * v1;
160 let v4: i64 = (v3 as i64) * (self.0.par_t3 as i64);
161 let v5: i64 = ((v2 as i64) << 18) + v4;
162 let t_fine: i32 = (v5 >> 32) as i32;
163 let temperature = (t_fine * 25) as f64 / (100 << 14) as f64;
164
165 (
166 ThermodynamicTemperature::new::<degree_celsius>(temperature),
167 TFine(t_fine),
168 )
169 }
170
171 pub(super) fn compensate_pressure(&self, uncompensated: u32, t_fine: TFine) -> Pressure {
172 let t_fine = t_fine.0;
173
174 let v1 = t_fine as i64 * t_fine as i64;
175 let v3 = ((v1 >> 6) * t_fine as i64) >> 8;
176 let v4 = (self.0.par_p8 as i64 * v3) >> 5;
177 let v5 = (self.0.par_p7 as i64 * v1) << 4;
178 let v6 = (self.0.par_p6 as i64 * t_fine as i64) << 22;
179 let offset = ((self.0.par_p5 as i64) << 47) + v4 + v5 + v6;
180 let v2 = ((self.0.par_p4 as i64) * v3) >> 5;
181 let v4 = (self.0.par_p3 as i64 * v1) << 2;
182 let v5 = ((self.0.par_p2 as i64 - 16384) * t_fine as i64) << 21;
183 let sensitivity = (((self.0.par_p1 as i64 - 16384) << 46) + v2 + v4 + v5) >> 24;
184 let v1 = (sensitivity * uncompensated as i64) >> 13;
185 let v2 = (self.0.par_p10 as i64) * (t_fine as i64);
186 let v3 = v2 + ((self.0.par_p9 as i64) << 16);
187 let v4 = (v3 * uncompensated as i64) >> 13;
188 let v5 = (v4 * uncompensated as i64) >> 9;
189 let v6 = uncompensated as i64 * uncompensated as i64;
190 let v2 = ((self.0.par_p11 as i64) * v6) >> 16;
191 let v3 = (v2 * uncompensated as i64) >> 7;
192 let v4 = (offset / 4) + v1 + v5 + v3;
193 let pressure = ((v4 >> 32) * 25) as i32;
194 let pressure = pressure as f64 / (100 << 8) as f64;
195 Pressure::new::<pascal>(pressure)
196 }
197}
198
199#[maybe_async_cfg::maybe(
204 idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), RegisterInterface),
205 sync(feature = "sync"),
206 async(feature = "async")
207)]
208pub struct BMP390<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> {
209 delay: D,
211 interface: I,
213 pub(super) calibration_data: Option<CalibrationData>,
215}
216
217pub trait BMP390Register {}
218
219#[maybe_async_cfg::maybe(
220 idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), I2cDevice),
221 sync(feature = "sync"),
222 async(feature = "async")
223)]
224impl<D, I> BMP390<D, embedded_interfaces::i2c::I2cDevice<I, hal::i2c::SevenBitAddress>>
225where
226 I: hal::i2c::I2c<hal::i2c::SevenBitAddress> + hal::i2c::ErrorType,
227 D: hal::delay::DelayNs,
228{
229 #[inline]
235 pub fn new_i2c(delay: D, interface: I, address: Address) -> Self {
236 Self {
237 delay,
238 interface: embedded_interfaces::i2c::I2cDevice::new(interface, address.into()),
239 calibration_data: None,
240 }
241 }
242}
243
244#[maybe_async_cfg::maybe(
245 idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), SpiDevice),
246 sync(feature = "sync"),
247 async(feature = "async")
248)]
249impl<D, I> BMP390<D, embedded_interfaces::spi::SpiDevice<I>>
250where
251 I: hal::spi::r#SpiDevice,
252 D: hal::delay::DelayNs,
253{
254 #[inline]
260 pub fn new_spi(delay: D, interface: I) -> Self {
261 Self {
262 delay,
263 interface: embedded_interfaces::spi::SpiDevice::new(interface),
264 calibration_data: None,
265 }
266 }
267}
268
269#[forward_register_fns]
270#[sensor(Temperature, Pressure)]
271#[maybe_async_cfg::maybe(
272 idents(
273 hal(sync = "embedded_hal", async = "embedded_hal_async"),
274 RegisterInterface,
275 ResettableDevice
276 ),
277 sync(feature = "sync"),
278 async(feature = "async")
279)]
280impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> BMP390<D, I> {
281 pub async fn init(&mut self) -> Result<(), InitError<I::BusError>> {
288 use crate::device::ResettableDevice;
289
290 self.reset().await?;
292
293 let chip = self.read_register::<ChipId>().await?.read_chip();
295 if let self::registers::Chip::Invalid(x) = chip {
296 return Err(InitError::InvalidChip(x));
297 }
298
299 self.calibrate().await?;
301 Ok(())
302 }
303
304 pub async fn calibrate(&mut self) -> Result<(), TransportError<(), I::BusError>> {
309 let coefficients = self.read_register::<TrimmingCoefficients>().await?.unpack();
310 self.calibration_data = Some(CalibrationData(coefficients));
311
312 Ok(())
313 }
314
315 pub async fn configure(&mut self, config: Configuration) -> Result<(), TransportError<(), I::BusError>> {
318 self.write_register(
319 PowerControl::default()
320 .with_temperature_enable(config.temperature_oversampling.is_some())
321 .with_pressure_enable(config.pressure_oversampling.is_some()),
322 )
323 .await?;
324
325 let mut oversampling = OversamplingControl::default();
326 if let Some(ov) = config.temperature_oversampling {
327 oversampling.write_temperature_oversampling(ov);
328 }
329 if let Some(ov) = config.pressure_oversampling {
330 oversampling.write_pressure_oversampling(ov);
331 }
332 self.write_register(oversampling).await?;
333 self.write_register(Config::default().with_iir_filter(config.iir_filter))
334 .await?;
335
336 Ok(())
337 }
338}
339
340#[maybe_async_cfg::maybe(
341 idents(
342 hal(sync = "embedded_hal", async = "embedded_hal_async"),
343 RegisterInterface,
344 ResettableDevice
345 ),
346 sync(feature = "sync"),
347 async(feature = "async")
348)]
349impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::device::ResettableDevice
350 for BMP390<D, I>
351{
352 type Error = TransportError<(), I::BusError>;
353
354 async fn reset(&mut self) -> Result<(), Self::Error> {
357 self.write_register(self::registers::Command::default().with_command(Cmd::Reset))
358 .await?;
359 self.delay.delay_ms(10).await;
360 Ok(())
361 }
362}
363
364#[maybe_async_cfg::maybe(
365 idents(
366 hal(sync = "embedded_hal", async = "embedded_hal_async"),
367 RegisterInterface,
368 OneshotSensor
369 ),
370 sync(feature = "sync"),
371 async(feature = "async")
372)]
373impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::OneshotSensor
374 for BMP390<D, I>
375{
376 type Error = MeasurementError<I::BusError>;
377 type Measurement = Measurement;
378
379 async fn measure(&mut self) -> Result<Self::Measurement, Self::Error> {
385 let power_ctrl = self.read_register::<PowerControl>().await?;
386 self.write_register(power_ctrl.with_sensor_mode(SensorMode::Forced))
387 .await?;
388
389 let temperature_enable = power_ctrl.read_temperature_enable();
390 let pressure_enable = power_ctrl.read_pressure_enable();
391
392 if !temperature_enable && !pressure_enable {
393 return Ok(Measurement {
394 temperature: None,
395 pressure: None,
396 });
397 }
398
399 let reg_ctrl_m = self.read_register::<OversamplingControl>().await?;
401 let o_t = reg_ctrl_m.read_temperature_oversampling();
402 let o_p = reg_ctrl_m.read_pressure_oversampling();
403
404 let max_measurement_delay_us = 234 + (392 + 2020 * o_p.factor()) + (163 + o_t.factor() * 2020);
407 self.delay.delay_us(max_measurement_delay_us).await;
408
409 let raw_data = self.read_register::<BurstMeasurements>().await?;
410 let Some(ref cal) = self.calibration_data else {
411 return Err(MeasurementError::NotCalibrated);
412 };
413
414 let temperature_enable = power_ctrl.read_temperature_enable();
415 let pressure_enable = power_ctrl.read_pressure_enable();
416
417 let (temperature, pressure) = if temperature_enable {
418 let (temp, t_fine) = cal.compensate_temperature(raw_data.read_temperature_value());
419 let press = pressure_enable.then(|| cal.compensate_pressure(raw_data.read_pressure_value(), t_fine));
420 (Some(temp), press)
421 } else {
422 (None, None)
423 };
424
425 Ok(Measurement { temperature, pressure })
426 }
427}
428
429#[maybe_async_cfg::maybe(
430 idents(
431 hal(sync = "embedded_hal", async = "embedded_hal_async"),
432 RegisterInterface,
433 ContinuousSensor
434 ),
435 sync(feature = "sync"),
436 async(feature = "async")
437)]
438impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::ContinuousSensor
439 for BMP390<D, I>
440{
441 type Error = MeasurementError<I::BusError>;
442 type Measurement = Measurement;
443
444 async fn start_measuring(&mut self) -> Result<(), Self::Error> {
446 let power_ctrl = self.read_register::<PowerControl>().await?;
447 self.write_register(power_ctrl.with_sensor_mode(SensorMode::Normal))
448 .await?;
449 Ok(())
450 }
451
452 async fn stop_measuring(&mut self) -> Result<(), Self::Error> {
454 let power_ctrl = self.read_register::<PowerControl>().await?;
455 self.write_register(power_ctrl.with_sensor_mode(SensorMode::Sleep))
456 .await?;
457 Ok(())
458 }
459
460 async fn measurement_interval_us(&mut self) -> Result<u32, Self::Error> {
462 let reg_ctrl_m = self.read_register::<OversamplingControl>().await?;
464 let o_t = reg_ctrl_m.read_temperature_oversampling();
465 let o_p = reg_ctrl_m.read_pressure_oversampling();
466
467 let t_measure_us = 234 + (392 + 2020 * o_p.factor()) + (163 + o_t.factor() * 2020);
470
471 let data_rate_ctrl = self.read_register::<DataRateControl>().await?;
472 let t_standby_us = data_rate_ctrl.read_data_rate().interval_us();
473 Ok(t_measure_us + t_standby_us)
474 }
475
476 async fn current_measurement(&mut self) -> Result<Option<Self::Measurement>, Self::Error> {
478 let raw_data = self.read_register::<BurstMeasurements>().await?;
479 let power_ctrl = self.read_register::<PowerControl>().await?;
480 let Some(ref cal) = self.calibration_data else {
481 return Err(MeasurementError::NotCalibrated);
482 };
483
484 let temperature_enable = power_ctrl.read_temperature_enable();
485 let pressure_enable = power_ctrl.read_pressure_enable();
486
487 let (temperature, pressure) = if temperature_enable {
488 let (temp, t_fine) = cal.compensate_temperature(raw_data.read_temperature_value());
489 let press = pressure_enable.then(|| cal.compensate_pressure(raw_data.read_pressure_value(), t_fine));
490 (Some(temp), press)
491 } else {
492 (None, None)
493 };
494
495 Ok(Some(Measurement { temperature, pressure }))
496 }
497
498 async fn is_measurement_ready(&mut self) -> Result<bool, Self::Error> {
500 Ok(true)
501 }
502
503 async fn next_measurement(&mut self) -> Result<Self::Measurement, Self::Error> {
505 let interval = self.measurement_interval_us().await?;
506 self.delay.delay_us(interval).await;
507 self.current_measurement().await?.ok_or_else(|| {
508 MeasurementError::Transport(TransportError::Unexpected(
509 "measurement was not ready even though we expected it to be",
510 ))
511 })
512 }
513}