Skip to main content

Crate bmi323_driver

Crate bmi323_driver 

Source
Expand description

§bmi323-driver

crates.io docs.rs CI codecov license rust-version

bmi323-driver is a no_std Rust driver for the Bosch Sensortec BMI323 6-DoF IMU.

The datasheet is available at Bosch Sensortec web site: https://www.bosch-sensortec.com/en/products/motion-sensors/imus/bmi323

This driver is designed to be transport-agnostic, small, and usable both in generic embedded-hal applications and in async Embassy-based firmware.

init() performs a soft reset, so the driver starts from a known sensor state. After init(), configure the accelerometer and gyroscope explicitly before depending on sample reads. The driver does not promise application-ready accel or gyro settings immediately after initialization.

The API is built on top of embedded-hal 1.0 and embedded-hal-async 1.0. The driver does not own the external interrupt GPIO, which keeps it transport agnostic and easy to integrate with Embassy or platform-specific interrupt handling.

§Features

  • embedded-hal 1.0 blocking API support
  • embedded-hal-async 1.0 async API support
  • I2C and SPI transports
  • accelerometer and gyroscope configuration
  • burst accel/gyro reads
  • FIFO configuration and reads
  • interrupt pin electrical configuration and interrupt routing
  • feature-engine enable sequence
  • any-motion and no-motion configuration
  • tap and orientation/flat configuration
  • significant-motion and tilt configuration
  • step detector and step counter support
  • alternate accel/gyro configuration switching
  • built-in accelerometer and gyroscope self-test

§Feature flags

Async mode is the default when no feature flags are set. The blocking feature opts into the synchronous embedded-hal API. Enabling both simultaneously causes a compile error.

  • async: no-op marker; async is the default behavior without blocking
  • blocking: synchronous driver using embedded-hal traits
  • defmt: derives defmt::Format for public value types

§Transport model

The BMI323 uses 8-bit register addresses with 16-bit register payloads. Reads include interface-specific dummy bytes, which this crate handles internally for both I2C and SPI.

§Interrupt model

BMI323 interrupt sources are routed to INT1, INT2, or I3C IBI inside the sensor. The driver configures the sensor-side routing, but the external GPIO line is managed by the application:

  • in blocking applications, poll the GPIO or an MCU interrupt flag yourself, then call read_interrupt_status()
  • in async applications, either wait on the GPIO yourself or use wait_for_interrupt() with a pin implementing embedded_hal_async::digital::Wait

§Feature engine notes

Advanced features such as any-motion and no-motion depend on the BMI323 feature engine. The datasheet requires the feature engine to be enabled before sensors are re-enabled for these features. The helper methods in this crate follow that model, but application code should still keep the order in mind when building its configuration sequence.

For motion-feature timing and threshold fields, prefer the conversion helpers on AnyMotionConfig and NoMotionConfig instead of hand-coding raw register values.

The report_mode and interrupt_hold fields are written to a single shared BMI323 register (EXT_GEN_SET_1). When multiple feature-engine blocks are configured, the last configure_* call’s values win for both fields. Use the same values across all configure_* calls, or set them in the intended final order.

The driver tracks local range fields initialized to AccelRange::G2 and GyroRange::Dps125 to match the BMI323 power-on reset defaults (ACC_CONF/GYR_CONF = 0x0000).

§Blocking I2C example

use bmi323_driver::{
    AccelConfig, AccelRange, Bmi323, GyroConfig, GyroRange, I2C_ADDRESS_PRIMARY,
    OutputDataRate,
};
use embedded_hal::delay::DelayNs;
use embedded_hal::i2c::I2c;

fn example<I2C, D>(i2c: I2C, delay: &mut D) -> Result<(), bmi323_driver::Error<I2C::Error>>
where
    I2C: I2c,
    D: DelayNs,
{
    let mut imu = Bmi323::new_i2c(i2c, I2C_ADDRESS_PRIMARY);
    let state = imu.init(delay)?;
    let _ = state;

    imu.set_accel_config(AccelConfig {
        odr: OutputDataRate::Hz100,
        ..Default::default()
    })?;

    imu.set_gyro_config(GyroConfig {
        odr: OutputDataRate::Hz100,
        ..Default::default()
    })?;

    let sample = imu.read_imu_data()?;
    let accel_g = sample.accel.as_g(imu.accel_range());
    let gyro_dps = sample.gyro.as_dps(imu.gyro_range());
    let _ = (accel_g, gyro_dps);
    Ok(())
}

§Async interrupt-driven advanced example

use bmi323_driver::{
    AccelConfig, ActiveLevel, AnyMotionConfig, Bmi323, EventReportMode,
    I2C_ADDRESS_PRIMARY, InterruptChannel, InterruptPinConfig, InterruptRoute,
    InterruptSource, MotionAxes, OutputDataRate, OutputMode, ReferenceUpdate,
};
use embedded_hal_async::delay::DelayNs;
use embedded_hal_async::digital::Wait;
use embedded_hal_async::i2c::I2c;

async fn example<I2C, D, P>(
    i2c: I2C,
    delay: &mut D,
    int1_pin: &mut P,
) -> Result<(), bmi323_driver::Error<I2C::Error>>
where
    I2C: I2c,
    D: DelayNs,
    P: Wait,
{
    let mut imu = Bmi323::new_i2c(i2c, I2C_ADDRESS_PRIMARY);
    imu.init(delay).await?;
    imu.enable_feature_engine(delay).await?;
    imu.set_accel_config(AccelConfig {
        mode: bmi323_driver::AccelMode::HighPerformance,
        odr: OutputDataRate::Hz100,
        ..Default::default()
    })
    .await?;
    imu.configure_any_motion(AnyMotionConfig {
        axes: MotionAxes::XYZ,
        threshold: AnyMotionConfig::threshold_from_g(0.08),
        hysteresis: AnyMotionConfig::hysteresis_from_g(0.02),
        duration: 5, // 5 / 50 s = 100 ms above threshold before event
        wait_time: 1, // 1 / 50 s = 20 ms clear delay after slope drops
        reference_update: ReferenceUpdate::EverySample,
        report_mode: EventReportMode::AllEvents,
        interrupt_hold: 3, // 0.625 ms * 2^3 = 5 ms interrupt hold
    })
    .await?;
    imu.set_interrupt_latching(true).await?;
    imu.configure_interrupt_pin(
        InterruptChannel::Int1,
        InterruptPinConfig {
            active_level: ActiveLevel::High,
            output_mode: OutputMode::PushPull,
            enabled: true,
        },
    )
    .await?;
    imu.map_interrupt(InterruptSource::AnyMotion, InterruptRoute::Int1)
        .await?;

    let status = imu
        .wait_for_interrupt(int1_pin, InterruptChannel::Int1)
        .await?;
    if status.any_motion() {
        let accel = imu.read_accel().await?;
        let _ = accel;
    }
    Ok(())
}

§Repository examples

Hardware-specific STM32G030F6 Embassy examples are in the separate sub-crate embassy-stm32g030f6-examples.

§STM32 Motion Detection Example

This screenshot shows the embassy-stm32g030f6-examples/src/bin/motion.rs example running on an STM32G030F6 and printing detected accelerometer samples after BMI323 motion interrupts fire.

STM32 BMI323 motion detection example run

§License

MIT. See LICENSE.

Structs§

AccelConfig
High-level accelerometer configuration written to ACC_CONF (§6.1.2, Register (0x20) acc_conf).
AltAccelConfig
Reduced accelerometer configuration used by the BMI323 alternate mode (§6.1.2, Register (0x28) alt_acc_conf; §5.10).
AltAccelSwitchProfile
Convenience bundle for a common accel-only alternate-configuration setup.
AltConfigControl
Automatic switching policy between user and alternate accel/gyro configurations (§6.1.2, Register (0x2A) alt_conf; §5.10).
AltGyroConfig
Reduced gyroscope configuration used by the BMI323 alternate mode (§6.1.2, Register (0x29) alt_gyr_conf; §5.10).
AltStatus
Current active accel/gyro configuration selection reported by the BMI323 (§6.1.2, Register (0x2B) alt_status).
AnyMotionConfig
Configuration for the BMI323 any-motion feature (§6.2.2, Registers (0x05-0x07) anymo_1/anymo_2/anymo_3; §5.8.2).
AxisData
Raw 3-axis sample from the accelerometer or gyroscope.
Bmi323
BMI323 driver.
DeviceState
Result returned by Bmi323::init.
ErrorWord
Decoded contents of the BMI323 ERR_REG register (§6.1.2, Register (0x01) err_reg).
FifoConfig
FIFO enable and behavior configuration (§6.1.2, Register (0x36) fifo_conf).
FlatConfig
Configuration for the BMI323 flat-detection feature (§6.2.2, Registers (0x0B-0x0C) flat_1/flat_2; §5.8.6).
GyroConfig
High-level gyroscope configuration written to GYR_CONF (§6.1.2, Register (0x21) gyr_conf).
I2cTransport
I2C transport wrapper used by Bmi323.
ImuData
Combined accelerometer and gyroscope sample read in one burst.
InterruptPinConfig
Electrical configuration for INT1 or INT2 (§6.1.2, Register (0x38) io_int_ctrl).
InterruptStatus
Decoded interrupt status for INT1, INT2, or I3C IBI (§6.1.2, Registers (0x0D-0x0F) int_status_int1/int2/ibi).
MotionAxes
Per-axis enable mask for motion features (§6.2.2, Register (0x07) anymo_3 axis_sel; Register (0x0A) nomo_3 axis_sel).
NoMotionConfig
Configuration for the BMI323 no-motion feature (§6.2.2, Registers (0x08-0x0A) nomo_1/nomo_2/nomo_3; §5.8.3).
OrientationConfig
Configuration for the BMI323 orientation-detection feature (§6.2.2, Registers (0x1C-0x1D) orient_1/orient_2; §5.8.7).
SelfTestDetail
Detailed self-test result bits read from the BMI323 st_result extended register (§6.2.2, Register (0x24) st_result; §5.14).
SelfTestResult
Result of a completed BMI323 self-test run.
SignificantMotionConfig
Configuration for the BMI323 significant-motion feature (§6.2.2, Registers (0x0D-0x0F) sigmo_1/sigmo_2/sigmo_3; §5.8.4).
SpiTransport
SPI transport wrapper used by Bmi323.
StatusWord
Decoded contents of the BMI323 STATUS register (§6.1.2, Register (0x02) status).
StepCounterConfig
Configuration for the BMI323 feature-engine step counter block (§6.2.2, Register (0x10) sc_1; §5.8.5).
TapConfig
Configuration for the BMI323 tap-detection feature (§6.2.2, Registers (0x1E-0x20) tap_1/tap_2/tap_3; §5.8.8).
TiltConfig
Configuration for the BMI323 tilt-detection feature (§6.2.2, Registers (0x21-0x22) tilt_1/tilt_2; §5.8.9).

Enums§

AccelMode
Accelerometer operating mode (§6.1.2, Register (0x20) acc_conf acc_mode).
AccelRange
Accelerometer full-scale measurement range (§6.1.2, Register (0x20) acc_conf acc_range).
ActiveLevel
Electrical active level for an interrupt output pin (§6.1.2, Register (0x38) io_int_ctrl int1_lvl/int2_lvl).
AltConfigSwitchSource
Supported feature-engine sources that can switch between user and alternate sensor configurations (§6.1.2, Register (0x2A) alt_conf; §5.10).
AverageSamples
Sample averaging depth used in supported sensor modes (§6.1.2, Register (0x20) acc_conf acc_avg_num; Register (0x21) gyr_conf gyr_avg_num).
Bandwidth
Low-pass filter bandwidth relative to output data rate (§6.1.2, Register (0x20) acc_conf acc_bwp; Register (0x21) gyr_conf gyr_bwp).
Error
Driver error type.
EventReportMode
Event reporting policy for supported feature-engine motion detectors (§6.2.2, Register (0x02) gen_set_1 event_report_mode bit 0).
FeatureBlockingMode
Shared blocking behavior used by flat and orientation detection (§6.2.2, Register (0x0B) flat_1 blocking; Register (0x1C) orient_1 blocking).
GyroMode
Gyroscope operating mode (§6.1.2, Register (0x21) gyr_conf gyr_mode).
GyroRange
Gyroscope full-scale measurement range (§6.1.2, Register (0x21) gyr_conf gyr_range).
InterruptChannel
Interrupt output channel inside the BMI323 (§6.1.2, Registers (0x3A-0x3B) int_map1/int_map2).
InterruptRoute
Mapping destination for an interrupt source (§6.1.2, Registers (0x3A-0x3B) int_map1/int_map2, 2-bit routing fields).
InterruptSource
Interrupt source that can be mapped to an output channel (§6.1.2, Registers (0x3A-0x3B) int_map1/int_map2).
OrientationMode
Configuration mode for orientation spread between portrait and landscape (§6.2.2, Register (0x1C) orient_1 mode).
OutputDataRate
Output data rate selection used by accel and gyro configuration (§6.1.2, Register (0x20) acc_conf acc_odr; Register (0x21) gyr_conf gyr_odr).
OutputMode
Electrical driver mode for an interrupt output pin (§6.1.2, Register (0x38) io_int_ctrl int1_od/int2_od).
ReferenceUpdate
Reference update policy for supported motion detectors (§6.2.2, Register (0x05) anymo_1 acc_ref_up; Register (0x08) nomo_1 acc_ref_up).
SelfTestSelection
Self-test selection written to the BMI323 st_select extended register (§6.2.2, Register (0x25) st_select; §5.14).
TapAxis
Dominant accelerometer axis used for tap detection (§6.2.2, Register (0x1E) tap_1 axis_sel).
TapDetectionMode
Detection profile for tap recognition (§6.2.2, Register (0x1E) tap_1 mode).
TapReportingMode
Reporting policy for tap gesture confirmation (§6.2.2, Register (0x1E) tap_1 wait_for_timeout).

Constants§

I2C_ADDRESS_ALTERNATE
Alternate 7-bit BMI323 I2C address (§7.2.4.2).
I2C_ADDRESS_PRIMARY
Primary 7-bit BMI323 I2C address (§7.2.4.2).
MAX_WORDS_PER_READ
Maximum number of 16-bit words that a single read_words call may request.

Traits§

Access