1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//! Generic `no_std` driver for the Bosch BMI323 IMU.
//!
//! This crate provides:
//!
//! - blocking and async drivers
//! - I2C and SPI transport support
//! - accelerometer and gyroscope configuration
//! - burst sample reads
//! - FIFO configuration and reads
//! - interrupt pin electrical configuration and interrupt routing
//! - feature-engine enable flow
//! - 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
//!
//! The API is built on top of `embedded-hal` 1.0 and `embedded-hal-async` 1.0.
//! It does not own the external interrupt GPIO. This keeps the driver generic and
//! makes it easy to use with Embassy or with a platform-specific interrupt layer.
//!
//! # Driver variants
//!
//! - [`Bmi323`] is the blocking driver.
//! - [`Bmi323Async`] is the async driver.
//!
//! Both expose the same high-level BMI323 operations where practical.
//!
//! # 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 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 [`Bmi323::read_interrupt_status`]
//! - in async applications, either wait on the GPIO yourself or use
//! [`Bmi323Async::wait_for_interrupt`] with a pin implementing
//! [`embedded_hal_async::digital::Wait`]
//!
//! # Feature engine note
//!
//! 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.
//!
//! # Startup configuration
//!
//! [`Bmi323::init`] and [`Bmi323Async::init`] perform a soft reset so the
//! sensor starts from a known state. After that reset, this driver does not
//! assume the accelerometer or gyroscope are configured for your application.
//! In practice, you should call [`Bmi323::set_accel_config`] and
//! [`Bmi323::set_gyro_config`] or their async equivalents before relying on
//! accelerometer or gyroscope sample reads.
//!
//! The driver tracks local range fields initialized to `AccelRange::G8` and
//! `GyroRange::Dps2000`, but those are only fallback bookkeeping values until
//! you explicitly configure the sensor through the driver.
//!
//! # Example: blocking I2C
//!
//! ```no_run
//! use bmi323_driver::{
//! AccelConfig, AccelMode, AccelRange, AverageSamples, Bandwidth, Bmi323,
//! GyroConfig, GyroMode, 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(())
//! }
//! ```
//!
//! # Example: async interrupt-driven usage
//!
//! ```no_run
//! use bmi323_driver::{
//! AccelConfig, AccelMode, AccelRange, ActiveLevel, AnyMotionConfig,
//! AverageSamples, Bandwidth, Bmi323Async, 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 = Bmi323Async::new_i2c(i2c, I2C_ADDRESS_PRIMARY);
//! imu.init(delay).await?;
//! imu.enable_feature_engine().await?;
//! imu.set_accel_config(AccelConfig {
//! mode: 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(())
//! }
//! ```
extern crate std;
pub use ;
pub use ;
pub use *;