{"id":50102379,"url":"https://github.com/snabb/bmi323-driver","last_synced_at":"2026-05-23T08:05:09.811Z","repository":{"id":352240720,"uuid":"1214403934","full_name":"snabb/bmi323-driver","owner":"snabb","description":"Rust no_std driver for the Bosch Sensortec BMI323 IMU","archived":false,"fork":false,"pushed_at":"2026-05-05T20:16:57.000Z","size":365,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-05T20:37:44.757Z","etag":null,"topics":["accelerometer","bmi323","driver","embassy","embedded","gyroscope","imu","rust","sensor"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/snabb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-18T14:29:36.000Z","updated_at":"2026-05-05T20:17:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/snabb/bmi323-driver","commit_stats":null,"previous_names":["snabb/bmi323-driver"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/snabb/bmi323-driver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snabb%2Fbmi323-driver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snabb%2Fbmi323-driver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snabb%2Fbmi323-driver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snabb%2Fbmi323-driver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snabb","download_url":"https://codeload.github.com/snabb/bmi323-driver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snabb%2Fbmi323-driver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33387661,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["accelerometer","bmi323","driver","embassy","embedded","gyroscope","imu","rust","sensor"],"created_at":"2026-05-23T08:05:09.077Z","updated_at":"2026-05-23T08:05:09.797Z","avatar_url":"https://github.com/snabb.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bmi323-driver\n\n[![crates.io](https://img.shields.io/crates/v/bmi323-driver.svg)](https://crates.io/crates/bmi323-driver)\n[![docs.rs](https://img.shields.io/docsrs/bmi323-driver)](https://docs.rs/bmi323-driver)\n[![CI](https://github.com/snabb/bmi323-driver/actions/workflows/ci.yml/badge.svg)](https://github.com/snabb/bmi323-driver/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/snabb/bmi323-driver/graph/badge.svg)](https://codecov.io/gh/snabb/bmi323-driver)\n[![license](https://img.shields.io/crates/l/bmi323-driver.svg)](https://github.com/snabb/bmi323-driver/blob/main/LICENSE)\n[![rust-version](https://img.shields.io/badge/rust-1.85%2B-93450a.svg)](https://www.rust-lang.org/)\n\n`bmi323-driver` is a `no_std` Rust driver for the Bosch Sensortec BMI323 6-DoF IMU.\n\nThe datasheet is available at Bosch Sensortec web site: \u003chttps://www.bosch-sensortec.com/en/products/motion-sensors/imus/bmi323\u003e\n\nThis driver is designed to be transport-agnostic, small, and usable both\nin generic embedded-hal applications and in async Embassy-based firmware.\n\n`init()` performs a soft reset, so the driver starts from a known sensor state.\nAfter `init()`, configure the accelerometer and gyroscope explicitly before\ndepending on sample reads. The driver does not promise application-ready accel\nor gyro settings immediately after initialization.\n\nThe API is built on top of `embedded-hal` 1.0 and `embedded-hal-async` 1.0.\nThe driver does not own the external interrupt GPIO, which keeps it transport\nagnostic and easy to integrate with Embassy or platform-specific interrupt\nhandling.\n\n## Features\n\n- `embedded-hal` 1.0 blocking API support\n- `embedded-hal-async` 1.0 async API support\n- I2C and SPI transports\n- accelerometer and gyroscope configuration\n- burst accel/gyro reads\n- FIFO configuration and reads\n- interrupt pin electrical configuration and interrupt routing\n- feature-engine enable sequence\n- any-motion and no-motion configuration\n- tap and orientation/flat configuration\n- significant-motion and tilt configuration\n- step detector and step counter support\n- alternate accel/gyro configuration switching\n- built-in accelerometer and gyroscope self-test\n\n## Feature flags\n\nAsync mode is the default when no feature flags are set. The `blocking` feature\nopts into the synchronous `embedded-hal` API. Enabling both simultaneously\ncauses a compile error.\n\n- `async`: no-op marker; async is the default behavior without `blocking`\n- `blocking`: synchronous driver using `embedded-hal` traits\n- `defmt`: derives `defmt::Format` for public value types\n\n## Transport model\n\nThe BMI323 uses 8-bit register addresses with 16-bit register payloads. Reads\ninclude interface-specific dummy bytes, which this crate handles internally for\nboth I2C and SPI.\n\n## Interrupt model\n\nBMI323 interrupt sources are routed to `INT1`, `INT2`, or I3C IBI inside the\nsensor. The driver configures the sensor-side routing, but the external GPIO\nline is managed by the application:\n\n- in blocking applications, poll the GPIO or an MCU interrupt flag yourself,\n  then call `read_interrupt_status()`\n- in async applications, either wait on the GPIO yourself or use\n  `wait_for_interrupt()` with a pin implementing\n  `embedded_hal_async::digital::Wait`\n\n## Feature engine notes\n\nAdvanced features such as any-motion and no-motion depend on the BMI323 feature\nengine. The datasheet requires the feature engine to be enabled before sensors\nare re-enabled for these features. The helper methods in this crate follow that\nmodel, but application code should still keep the order in mind when building\nits configuration sequence.\n\nFor motion-feature timing and threshold fields, prefer the conversion helpers\non `AnyMotionConfig` and `NoMotionConfig` instead of hand-coding raw register\nvalues.\n\nThe `report_mode` and `interrupt_hold` fields are written to a single shared\nBMI323 register (`EXT_GEN_SET_1`). When multiple feature-engine blocks are\nconfigured, the last `configure_*` call's values win for both fields. Use the\nsame values across all `configure_*` calls, or set them in the intended final\norder.\n\nThe driver tracks local range fields initialized to `AccelRange::G2` and\n`GyroRange::Dps125` to match the BMI323 power-on reset defaults\n(`ACC_CONF`/`GYR_CONF = 0x0000`).\n\n### Blocking I2C example\n\n```rust,no_run\n# #[cfg(not(feature = \"blocking\"))] fn main() {}\n# #[cfg(feature = \"blocking\")]\n# fn main() {\nuse bmi323_driver::{\n    AccelConfig, AccelRange, Bmi323, GyroConfig, GyroRange, I2C_ADDRESS_PRIMARY,\n    OutputDataRate,\n};\nuse embedded_hal::delay::DelayNs;\nuse embedded_hal::i2c::I2c;\n\nfn example\u003cI2C, D\u003e(i2c: I2C, delay: \u0026mut D) -\u003e Result\u003c(), bmi323_driver::Error\u003cI2C::Error\u003e\u003e\nwhere\n    I2C: I2c,\n    D: DelayNs,\n{\n    let mut imu = Bmi323::new_i2c(i2c, I2C_ADDRESS_PRIMARY);\n    let state = imu.init(delay)?;\n    let _ = state;\n\n    imu.set_accel_config(AccelConfig {\n        odr: OutputDataRate::Hz100,\n        ..Default::default()\n    })?;\n\n    imu.set_gyro_config(GyroConfig {\n        odr: OutputDataRate::Hz100,\n        ..Default::default()\n    })?;\n\n    let sample = imu.read_imu_data()?;\n    let accel_g = sample.accel.as_g(imu.accel_range());\n    let gyro_dps = sample.gyro.as_dps(imu.gyro_range());\n    let _ = (accel_g, gyro_dps);\n    Ok(())\n}\n# }\n```\n\n### Async interrupt-driven advanced example\n\n```rust,no_run\n# #[cfg(feature = \"blocking\")] fn main() {}\n# #[cfg(not(feature = \"blocking\"))]\n# fn main() {\nuse bmi323_driver::{\n    AccelConfig, ActiveLevel, AnyMotionConfig, Bmi323, EventReportMode,\n    I2C_ADDRESS_PRIMARY, InterruptChannel, InterruptPinConfig, InterruptRoute,\n    InterruptSource, MotionAxes, OutputDataRate, OutputMode, ReferenceUpdate,\n};\nuse embedded_hal_async::delay::DelayNs;\nuse embedded_hal_async::digital::Wait;\nuse embedded_hal_async::i2c::I2c;\n\nasync fn example\u003cI2C, D, P\u003e(\n    i2c: I2C,\n    delay: \u0026mut D,\n    int1_pin: \u0026mut P,\n) -\u003e Result\u003c(), bmi323_driver::Error\u003cI2C::Error\u003e\u003e\nwhere\n    I2C: I2c,\n    D: DelayNs,\n    P: Wait,\n{\n    let mut imu = Bmi323::new_i2c(i2c, I2C_ADDRESS_PRIMARY);\n    imu.init(delay).await?;\n    imu.enable_feature_engine(delay).await?;\n    imu.set_accel_config(AccelConfig {\n        mode: bmi323_driver::AccelMode::HighPerformance,\n        odr: OutputDataRate::Hz100,\n        ..Default::default()\n    })\n    .await?;\n    imu.configure_any_motion(AnyMotionConfig {\n        axes: MotionAxes::XYZ,\n        threshold: AnyMotionConfig::threshold_from_g(0.08),\n        hysteresis: AnyMotionConfig::hysteresis_from_g(0.02),\n        duration: 5, // 5 / 50 s = 100 ms above threshold before event\n        wait_time: 1, // 1 / 50 s = 20 ms clear delay after slope drops\n        reference_update: ReferenceUpdate::EverySample,\n        report_mode: EventReportMode::AllEvents,\n        interrupt_hold: 3, // 0.625 ms * 2^3 = 5 ms interrupt hold\n    })\n    .await?;\n    imu.set_interrupt_latching(true).await?;\n    imu.configure_interrupt_pin(\n        InterruptChannel::Int1,\n        InterruptPinConfig {\n            active_level: ActiveLevel::High,\n            output_mode: OutputMode::PushPull,\n            enabled: true,\n        },\n    )\n    .await?;\n    imu.map_interrupt(InterruptSource::AnyMotion, InterruptRoute::Int1)\n        .await?;\n\n    let status = imu\n        .wait_for_interrupt(int1_pin, InterruptChannel::Int1)\n        .await?;\n    if status.any_motion() {\n        let accel = imu.read_accel().await?;\n        let _ = accel;\n    }\n    Ok(())\n}\n# }\n```\n\n## Repository examples\n\n- [`examples/blocking_i2c_basic.rs`](./examples/blocking_i2c_basic.rs)\n  Blocking I2C configuration and sample reads.\n- [`examples/async_i2c_basic.rs`](./examples/async_i2c_basic.rs)\n  Async I2C configuration and sample reads using `embedded-hal-async`.\n- [`examples/async_i2c_any_motion.rs`](./examples/async_i2c_any_motion.rs)\n  Generic async any-motion detection setup using `embedded-hal-async`.\n- [`examples/async_i2c_no_motion.rs`](./examples/async_i2c_no_motion.rs)\n  Generic async no-motion detection setup using `embedded-hal-async`.\n- [`examples/async_i2c_tap.rs`](./examples/async_i2c_tap.rs)\n  Generic async tap-detection setup using `embedded-hal-async`.\n- [`examples/async_i2c_orientation.rs`](./examples/async_i2c_orientation.rs)\n  Generic async orientation-detection setup using `embedded-hal-async`.\n- [`examples/async_i2c_flat.rs`](./examples/async_i2c_flat.rs)\n  Generic async flat-detection setup using `embedded-hal-async`.\n- [`examples/async_i2c_significant_motion.rs`](./examples/async_i2c_significant_motion.rs)\n  Generic async significant-motion detection setup using `embedded-hal-async`.\n- [`examples/async_i2c_tilt.rs`](./examples/async_i2c_tilt.rs)\n  Generic async tilt-detection setup using `embedded-hal-async`.\n- [`examples/async_i2c_step_counter.rs`](./examples/async_i2c_step_counter.rs)\n  Generic async step-detector and step-counter setup using `embedded-hal-async`.\n- [`examples/async_i2c_alt_config.rs`](./examples/async_i2c_alt_config.rs)\n  Generic async alternate accel-configuration switching using any-motion and no-motion.\n- [`examples/async_i2c_self_test.rs`](./examples/async_i2c_self_test.rs)\n  Generic async built-in accelerometer and gyroscope self-test.\n\nHardware-specific [STM32G030F6](https://www.st.com/en/microcontrollers-microprocessors/stm32g030f6.html) [Embassy](https://embassy.dev/) examples are in the separate\nsub-crate [embassy-stm32g030f6-examples](./embassy-stm32g030f6-examples).\n\n### STM32 Motion Detection Example\n\nThis screenshot shows the [`embassy-stm32g030f6-examples/src/bin/motion.rs`](./embassy-stm32g030f6-examples/src/bin/motion.rs)\nexample running on an STM32G030F6 and printing detected accelerometer samples\nafter BMI323 motion interrupts fire.\n\n![STM32 BMI323 motion detection example run](./assets/motion-detection-example-stm32g030f6.png)\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnabb%2Fbmi323-driver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnabb%2Fbmi323-driver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnabb%2Fbmi323-driver/lists"}