Skip to main content

ph_qmi8658/
lib.rs

1//! Async `#![no_std]` driver for the
2//! [QMI8658C](https://www.qstcorp.com/en_comp_prod/QMI8658C) 6-axis IMU
3//! (accelerometer + gyroscope + temperature) from QST Corporation.
4//!
5//! This crate provides a lightweight, `embedded-hal-async` based driver for the
6//! QMI8658 6-axis IMU. It intentionally avoids any core-ports dependencies so
7//! it can be reused in adapter or BSP layers.
8//!
9//! # Quick start (I2C)
10//!
11//! ```rust,no_run
12//! use ph_qmi8658::{Config, I2cConfig, Qmi8658Address, Qmi8658I2c};
13//! # use embedded_hal_async::delay::DelayNs;
14//! # use embedded_hal_async::i2c::I2c;
15//! #
16//! # async fn example<I2C: I2c, D: DelayNs>(i2c: I2C, delay: &mut D) -> Result<(), ph_qmi8658::Error> {
17//! let config = Config::new();
18//! let i2c_config = I2cConfig::new(Qmi8658Address::Primary.addr());
19//! let mut imu: Qmi8658I2c<I2C> =
20//!     Qmi8658I2c::with_i2c_config(i2c, None, None, config, i2c_config);
21//! imu.init(delay).await?;
22//! # Ok(())
23//! # }
24//! ```
25//!
26//! # FIFO
27//!
28//! FIFO parsing helpers are available for burst-mode reads. See [`FifoFrameIterator`].
29//!
30//! # CTRL9 handshake
31//!
32//! By default CTRL8.bit7 = 0 and CmdDone is routed to INT1/STATUS1.bit0.
33//! Set [`InterruptConfig::with_ctrl9_handshake_statusint(true)`](InterruptConfig::with_ctrl9_handshake_statusint)
34//! to route CmdDone to STATUSINT.bit7. The driver polls the correct source automatically.
35//!
36//! # Sync sample locking
37//!
38//! Enable with `set_sync_sample(true)`; use `read_sync_sample(delay)` to follow
39//! the STATUSINT data-lock flow and data-read delay.
40//! For I2C/I3C, disable AHB clock gating via
41//! `set_ahb_clock_gating_with_delay(delay, false)` while sync sample is active.
42//!
43//! # Not yet supported
44//!
45//! - External magnetometer integration (mag raw types and FIFO mag frame parsing
46//!   are included for future support).
47//! - AttitudeEngine configuration and Motion-on-Demand.
48//! - Motion detection engines (tap/any/no/sig motion, pedometer) &mdash; these are
49//!   QMI8658A-only and are not applicable to the QMI8658C.
50//!
51//! # Scaling helpers
52//!
53//! Use [`accel_lsb_per_g`], [`gyro_lsb_per_dps`], and [`temperature_lsb_per_celsius`]
54//! (or the milli-unit ratios [`accel_mg_per_lsb`] / [`gyro_mdps_per_lsb`]) to
55//! convert raw counts to physical units without floating-point math.
56//!
57//! # Fixed-point conversions
58//!
59//! Enable the `fixed` feature to access fixed-point helpers that convert raw
60//! readings into g, dps, and degrees C using `I32F32` integer math.
61
62#![no_std]
63#![deny(missing_docs)]
64#![allow(unsafe_code)]
65#![deny(unsafe_op_in_unsafe_fn)]
66// Clippy lint levels live here; thresholds and config are in clippy.toml.
67#![deny(clippy::correctness)]
68#![warn(
69    clippy::suspicious,
70    clippy::style,
71    clippy::complexity,
72    clippy::perf,
73    clippy::cloned_instead_of_copied,
74    clippy::explicit_iter_loop,
75    clippy::implicit_clone,
76    clippy::inconsistent_struct_constructor,
77    clippy::manual_assert,
78    clippy::manual_let_else,
79    clippy::match_same_arms,
80    clippy::needless_pass_by_value,
81    clippy::semicolon_if_nothing_returned,
82    clippy::uninlined_format_args,
83    clippy::unnested_or_patterns,
84    clippy::std_instead_of_core,
85    clippy::std_instead_of_alloc,
86    clippy::alloc_instead_of_core
87)]
88#![allow(
89    clippy::mod_module_files,
90    clippy::self_named_module_files,
91    clippy::similar_names,
92    clippy::too_many_arguments,
93    clippy::struct_excessive_bools,
94    clippy::fn_params_excessive_bools,
95    clippy::type_complexity,
96    clippy::must_use_candidate,
97    clippy::assertions_on_constants,
98    clippy::cast_possible_truncation,
99    clippy::cast_possible_wrap,
100    clippy::cast_sign_loss,
101    clippy::cast_precision_loss,
102    clippy::cast_lossless,
103    clippy::panic_in_result_fn,
104    clippy::unwrap_used,
105    clippy::expect_used,
106    clippy::module_name_repetitions,
107    clippy::wildcard_imports,
108    clippy::items_after_statements,
109    clippy::let_underscore_future
110)]
111
112#[cfg(feature = "fixed")]
113extern crate fixed as fixed_crate;
114
115mod config;
116mod data;
117mod device;
118mod driver;
119mod error;
120mod interface;
121mod interrupt;
122mod macros;
123mod register;
124mod self_test;
125mod wom;
126
127#[cfg(test)]
128mod testing;
129
130// Interface layer
131pub use interface::Qmi8658Address;
132pub use interface::{I2cConfig, I2cInterface};
133pub use interface::{SpiConfig, SpiInterface};
134
135// Configuration
136pub use config::{AccelConfig, AccelOutputDataRate, AccelRange, LowPassFilterMode};
137pub use config::{Config, OperatingMode};
138pub use config::{GyroConfig, GyroOutputDataRate, GyroRange};
139
140// Driver
141pub use driver::{Qmi8658, Qmi8658I2c, Qmi8658Spi};
142
143// Data types
144pub use data::{AccelRaw, GyroRaw, MagRaw, RawBlock, Sample, TemperatureRaw, Timestamp};
145pub use data::{
146    FifoConfig,
147    FifoFrame,
148    FifoFrameFormat,
149    FifoFrameIterator,
150    FifoMode,
151    FifoReadout,
152    FifoSize,
153    FifoStatus,
154    ScaleFactor,
155    accel_lsb_per_g,
156    accel_mg_per_lsb,
157    gyro_lsb_per_dps,
158    gyro_mdps_per_lsb,
159    temperature_lsb_per_celsius,
160    temperature_mdegc_per_lsb,
161};
162
163// Features
164pub use error::Error;
165pub use interrupt::{InterruptConfig, InterruptPin, InterruptStatus, InterruptWaitError};
166pub use self_test::{SelfTestAxis, SelfTestError, SelfTestReport};
167pub use wom::{WomConfig, WomInterruptLevel};
168
169// Fixed-point conversions (feature-gated)
170#[cfg(feature = "fixed")]
171pub use data::fixed::{
172    AccelFixed, Fixed, GyroFixed, TemperatureFixed, accel_sample_to_g, accel_to_g,
173    gyro_sample_to_dps, gyro_to_dps, temperature_celsius, temperature_sample_celsius,
174};