Expand description
§bmi323-driver
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-hal1.0 blocking API supportembedded-hal-async1.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 withoutblockingblocking: synchronous driver usingembedded-haltraitsdefmt: derivesdefmt::Formatfor 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 implementingembedded_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
examples/blocking_i2c_basic.rsBlocking I2C configuration and sample reads.examples/async_i2c_basic.rsAsync I2C configuration and sample reads usingembedded-hal-async.examples/async_i2c_any_motion.rsGeneric async any-motion detection setup usingembedded-hal-async.examples/async_i2c_no_motion.rsGeneric async no-motion detection setup usingembedded-hal-async.examples/async_i2c_tap.rsGeneric async tap-detection setup usingembedded-hal-async.examples/async_i2c_orientation.rsGeneric async orientation-detection setup usingembedded-hal-async.examples/async_i2c_flat.rsGeneric async flat-detection setup usingembedded-hal-async.examples/async_i2c_significant_motion.rsGeneric async significant-motion detection setup usingembedded-hal-async.examples/async_i2c_tilt.rsGeneric async tilt-detection setup usingembedded-hal-async.examples/async_i2c_step_counter.rsGeneric async step-detector and step-counter setup usingembedded-hal-async.examples/async_i2c_alt_config.rsGeneric async alternate accel-configuration switching using any-motion and no-motion.examples/async_i2c_self_test.rsGeneric async built-in accelerometer and gyroscope self-test.
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.

§License
MIT. See LICENSE.
Structs§
- Accel
Config - High-level accelerometer configuration written to
ACC_CONF(§6.1.2, Register (0x20) acc_conf). - AltAccel
Config - Reduced accelerometer configuration used by the BMI323 alternate mode (§6.1.2, Register (0x28) alt_acc_conf; §5.10).
- AltAccel
Switch Profile - Convenience bundle for a common accel-only alternate-configuration setup.
- AltConfig
Control - Automatic switching policy between user and alternate accel/gyro configurations (§6.1.2, Register (0x2A) alt_conf; §5.10).
- AltGyro
Config - 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).
- AnyMotion
Config - Configuration for the BMI323 any-motion feature (§6.2.2, Registers (0x05-0x07) anymo_1/anymo_2/anymo_3; §5.8.2).
- Axis
Data - Raw 3-axis sample from the accelerometer or gyroscope.
- Bmi323
- BMI323 driver.
- Device
State - Result returned by
Bmi323::init. - Error
Word - Decoded contents of the BMI323
ERR_REGregister (§6.1.2, Register (0x01) err_reg). - Fifo
Config - FIFO enable and behavior configuration (§6.1.2, Register (0x36) fifo_conf).
- Flat
Config - Configuration for the BMI323 flat-detection feature (§6.2.2, Registers (0x0B-0x0C) flat_1/flat_2; §5.8.6).
- Gyro
Config - 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.
- Interrupt
PinConfig - Electrical configuration for
INT1orINT2(§6.1.2, Register (0x38) io_int_ctrl). - Interrupt
Status - Decoded interrupt status for
INT1,INT2, or I3C IBI (§6.1.2, Registers (0x0D-0x0F) int_status_int1/int2/ibi). - Motion
Axes - Per-axis enable mask for motion features
(§6.2.2, Register (0x07) anymo_3
axis_sel; Register (0x0A) nomo_3axis_sel). - NoMotion
Config - Configuration for the BMI323 no-motion feature (§6.2.2, Registers (0x08-0x0A) nomo_1/nomo_2/nomo_3; §5.8.3).
- Orientation
Config - Configuration for the BMI323 orientation-detection feature (§6.2.2, Registers (0x1C-0x1D) orient_1/orient_2; §5.8.7).
- Self
Test Detail - Detailed self-test result bits read from the BMI323
st_resultextended register (§6.2.2, Register (0x24) st_result; §5.14). - Self
Test Result - Result of a completed BMI323 self-test run.
- Significant
Motion Config - 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. - Status
Word - Decoded contents of the BMI323
STATUSregister (§6.1.2, Register (0x02) status). - Step
Counter Config - 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).
- Tilt
Config - Configuration for the BMI323 tilt-detection feature (§6.2.2, Registers (0x21-0x22) tilt_1/tilt_2; §5.8.9).
Enums§
- Accel
Mode - Accelerometer operating mode (§6.1.2, Register (0x20) acc_conf
acc_mode). - Accel
Range - Accelerometer full-scale measurement range (§6.1.2, Register (0x20) acc_conf
acc_range). - Active
Level - Electrical active level for an interrupt output pin
(§6.1.2, Register (0x38) io_int_ctrl
int1_lvl/int2_lvl). - AltConfig
Switch Source - Supported feature-engine sources that can switch between user and alternate sensor configurations (§6.1.2, Register (0x2A) alt_conf; §5.10).
- Average
Samples - Sample averaging depth used in supported sensor modes
(§6.1.2, Register (0x20) acc_conf
acc_avg_num; Register (0x21) gyr_confgyr_avg_num). - Bandwidth
- Low-pass filter bandwidth relative to output data rate
(§6.1.2, Register (0x20) acc_conf
acc_bwp; Register (0x21) gyr_confgyr_bwp). - Error
- Driver error type.
- Event
Report Mode - Event reporting policy for supported feature-engine motion detectors
(§6.2.2, Register (0x02) gen_set_1
event_report_modebit 0). - Feature
Blocking Mode - Shared blocking behavior used by flat and orientation detection
(§6.2.2, Register (0x0B) flat_1
blocking; Register (0x1C) orient_1blocking). - Gyro
Mode - Gyroscope operating mode (§6.1.2, Register (0x21) gyr_conf
gyr_mode). - Gyro
Range - Gyroscope full-scale measurement range (§6.1.2, Register (0x21) gyr_conf
gyr_range). - Interrupt
Channel - Interrupt output channel inside the BMI323 (§6.1.2, Registers (0x3A-0x3B) int_map1/int_map2).
- Interrupt
Route - Mapping destination for an interrupt source (§6.1.2, Registers (0x3A-0x3B) int_map1/int_map2, 2-bit routing fields).
- Interrupt
Source - Interrupt source that can be mapped to an output channel (§6.1.2, Registers (0x3A-0x3B) int_map1/int_map2).
- Orientation
Mode - Configuration mode for orientation spread between portrait and landscape
(§6.2.2, Register (0x1C) orient_1
mode). - Output
Data Rate - Output data rate selection used by accel and gyro configuration
(§6.1.2, Register (0x20) acc_conf
acc_odr; Register (0x21) gyr_confgyr_odr). - Output
Mode - Electrical driver mode for an interrupt output pin
(§6.1.2, Register (0x38) io_int_ctrl
int1_od/int2_od). - Reference
Update - Reference update policy for supported motion detectors
(§6.2.2, Register (0x05) anymo_1
acc_ref_up; Register (0x08) nomo_1acc_ref_up). - Self
Test Selection - Self-test selection written to the BMI323
st_selectextended 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). - TapDetection
Mode - Detection profile for tap recognition
(§6.2.2, Register (0x1E) tap_1
mode). - TapReporting
Mode - 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_wordscall may request.