Skip to main content

bmi323_driver/
driver.rs

1use core::fmt;
2
3#[cfg(feature = "blocking")]
4use embedded_hal::i2c::I2c as HalI2c;
5#[cfg(feature = "blocking")]
6use embedded_hal::spi::SpiDevice as HalSpiDevice;
7#[cfg(not(feature = "blocking"))]
8use embedded_hal_async::i2c::I2c as HalI2c;
9#[cfg(not(feature = "blocking"))]
10use embedded_hal_async::spi::SpiDevice as HalSpiDevice;
11
12use crate::registers::TransportKind;
13use crate::types::Error;
14use crate::{AccelRange, GyroRange, I2cTransport, SpiTransport};
15
16/// BMI323 driver.
17///
18/// Async mode (the default) exposes all methods as `async fn`. Add
19/// `features = ["blocking"]` (with `default-features = false`) to get the
20/// synchronous embedded-hal API instead. Create with [`Bmi323::new_i2c`] or
21/// [`Bmi323::new_spi`].
22pub struct Bmi323<T> {
23    pub(crate) transport: T,
24    pub(crate) kind: TransportKind,
25    pub(crate) accel_range: AccelRange,
26    pub(crate) gyro_range: GyroRange,
27}
28
29impl<T> fmt::Debug for Bmi323<T> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.debug_struct("Bmi323")
32            .field("kind", &self.kind)
33            .field("accel_range", &self.accel_range)
34            .field("gyro_range", &self.gyro_range)
35            .finish_non_exhaustive()
36    }
37}
38
39impl<I2C: HalI2c> Bmi323<I2cTransport<I2C>> {
40    /// Create a BMI323 driver over an I2C bus.
41    ///
42    /// `address` is the 7-bit BMI323 I2C address selected by hardware.
43    pub fn new_i2c(i2c: I2C, address: u8) -> Self {
44        Self {
45            transport: I2cTransport { bus: i2c, address },
46            kind: TransportKind::I2c,
47            accel_range: AccelRange::G2,
48            gyro_range: GyroRange::Dps125,
49        }
50    }
51
52    /// Consume the driver and return ownership of the underlying I2C bus.
53    pub fn destroy(self) -> I2C {
54        self.transport.bus
55    }
56}
57
58impl<SPI: HalSpiDevice<u8>> Bmi323<SpiTransport<SPI>> {
59    /// Create a BMI323 driver over an SPI device.
60    pub fn new_spi(spi: SPI) -> Self {
61        Self {
62            transport: SpiTransport { bus: spi },
63            kind: TransportKind::Spi,
64            accel_range: AccelRange::G2,
65            gyro_range: GyroRange::Dps125,
66        }
67    }
68
69    /// Consume the driver and return ownership of the underlying SPI device.
70    pub fn destroy(self) -> SPI {
71        self.transport.bus
72    }
73}
74
75/// Convert a raw TEMP_DATA register value to degrees Celsius.
76///
77/// Returns `Err(Error::InvalidTemperature)` when the raw value is 0x8000,
78/// the BMI323 "invalid temperature" sentinel
79/// (§6.1.2, Register (0x09) temp_data; §5.6.3).
80///
81/// The conversion formula `T = raw / 512 + 23` is defined in §5.6.3.
82pub(crate) fn temperature_raw_to_celsius<E>(raw: i16) -> Result<f32, Error<E>> {
83    if raw == i16::MIN {
84        return Err(Error::InvalidTemperature);
85    }
86    Ok(raw as f32 / 512.0 + 23.0)
87}