diff --git a/Cargo.lock b/Cargo.lock index facd416..8e0dccb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,19 +1,61 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "autocfg" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bmi323" version = "0.1.0" dependencies = [ + "defmt", "embedded-hal 1.0.0", "embedded-hal-mock", + "num-derive", + "num-traits", + "serde", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", ] [[package]] @@ -102,6 +144,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -142,6 +195,113 @@ dependencies = [ "autocfg", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + [[package]] name = "void" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index 24dc5d0..24ee149 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,15 @@ include = [ [dependencies] embedded-hal = "1.0.0" +num-derive = "0.4.2" +num-traits = {version = "0.2.19", default-features = false} +serde = {version = "1.0", default-features = false, features = ["derive"], optional = true} +defmt ={version = "1.0", optional = true} [dev-dependencies] embedded-hal-mock = { version = "0.11.1", features = ["eh1"] } + +[features] +serde = ["dep:serde"] +defmt = ["dep:defmt"] +debug = [] diff --git a/examples/peripheral-crate-implementation/Cargo.toml b/examples/peripheral-crate-implementation/Cargo.toml index 6f7c60a..d06794d 100644 --- a/examples/peripheral-crate-implementation/Cargo.toml +++ b/examples/peripheral-crate-implementation/Cargo.toml @@ -10,7 +10,7 @@ cortex-m = "0.7.7" cortex-m-rt = "0.7.3" # cortex-m-semihosting = "0.5.0" panic-halt = "0.2.0" -bmi323= { git = "https://github.com/wyatt-mattas/bmi323-rs/", branch = "main"} +bmi323= { path = "../../"} embedded-hal = "1.0.0" # heapless = "0.8.0" # rtt-target = "0.4.0" diff --git a/examples/peripheral-crate-implementation/src/main.rs b/examples/peripheral-crate-implementation/src/main.rs index c40edef..e8aed08 100644 --- a/examples/peripheral-crate-implementation/src/main.rs +++ b/examples/peripheral-crate-implementation/src/main.rs @@ -6,13 +6,13 @@ use cortex_m_rt::entry; use stm32h5::stm32h563; use bmi323::{ - Bmi323, AccelConfig, GyroConfig, OutputDataRate, AccelerometerRange, GyroscopeRange, - Bandwidth, AverageNum, AccelerometerPowerMode, GyroscopePowerMode, + AccelConfig, AccelerometerPowerMode, AccelerometerRange, AverageNum, Bandwidth, Bmi323, GyroConfig, GyroscopePowerMode, GyroscopeRange, OutputDataRate }; use embedded_hal::delay::DelayNs; use embedded_hal::i2c::{ErrorKind, ErrorType, Error as OtherError, SevenBitAddress}; use embedded_hal::i2c::Operation; +use stm32h5::stm32h563::i2c1::icr::STOPCF; #[derive(Debug)] pub enum I2cError { @@ -84,6 +84,7 @@ impl DelayNs for Delay { } + #[entry] fn main() -> ! { let peripherals = unsafe { stm32h563::Peripherals::steal() }; @@ -177,7 +178,7 @@ impl I2C1 { // Wait until STOP flag is set while i2c.isr().read().stopf().bit_is_clear() {} // Clear the STOP flag - i2c.icr().write(|w| w.stopcf().set_bit()); + i2c.icr().write(|w| w.stopcf().variant(STOPCF::Clear)); Ok(()) } @@ -205,7 +206,7 @@ impl I2C1 { // Wait until STOP flag is set while i2c.isr().read().stopf().bit_is_clear() {} // Clear the STOP flag - i2c.icr().write(|w| w.stopcf().set_bit()); + i2c.icr().write(|w| w.stopcf().variant(STOPCF::Clear)); // Check for NACK if i2c.isr().read().nackf().bit_is_set() { diff --git a/src/device.rs b/src/device.rs index ebe4c90..3ade5ac 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,7 +1,7 @@ use crate::{ - interface::{I2cInterface, ReadData, SpiInterface, WriteData}, - types::{AccelerometerRange, GyroscopeRange, Sensor3DData, Sensor3DDataScaled, SensorType}, - AccelConfig, Bmi323, Error, GyroConfig, Register, + AccelConfig, AccelerometerPowerMode, Bmi323, Error, FifoConfig, GyroConfig, GyroscopePowerMode, IOInterruptConfig, InterruptMapConfig, InterruptSource, Register, interface::{I2cInterface, ReadData, SpiInterface, WriteData}, types::{ + AccelerometerRange, FifoData, GyroscopeRange, InterruptLatch, InterruptPin, Sensor3DData, Sensor3DDataScaled, SensorType, get_sensor3d_data + } }; use embedded_hal::delay::DelayNs; @@ -21,6 +21,8 @@ where delay, accel_range: AccelerometerRange::default(), gyro_range: GyroscopeRange::default(), + fifo_config: Default::default(), + fifo_message_len :0, } } } @@ -41,6 +43,8 @@ where delay, accel_range: AccelerometerRange::default(), gyro_range: GyroscopeRange::default(), + fifo_config: Default::default(), + fifo_message_len :0, } } } @@ -81,7 +85,9 @@ where self.accel_range = config.range; // Wait for accelerometer data to be ready - self.wait_for_data_ready(SensorType::Accelerometer)?; + if config.mode != AccelerometerPowerMode::Disable{ + self.wait_for_data_ready(SensorType::Accelerometer)?; + } Ok(()) } @@ -97,11 +103,47 @@ where self.gyro_range = config.range; // Wait for gyroscope data to be ready - self.wait_for_data_ready(SensorType::Gyroscope)?; - + if config.mode != GyroscopePowerMode::Disable{ + self.wait_for_data_ready(SensorType::Gyroscope)?; + } Ok(()) } + /// Set interrupt register configuration + /// Note: Interrupt pins are disabled by default use set_io_interrupt_config to configure them + /// + /// # Arguments + /// + /// * `config` - The interruptMap configuration + pub fn set_interrupt_mapping_config( + &mut self, + config: InterruptMapConfig, + ) -> Result<(), Error> { + self.write_register_16bit(Register::INT_MAP1, config.map1())?; + self.write_register_16bit(Register::INT_MAP2, config.map2()) + } + + /// Set IO interrupt register configuration + /// + /// # Arguments + /// + /// * `config` - The IOinterrupt configuration + pub fn set_io_interrupt_config(&mut self, config: IOInterruptConfig) -> Result<(), Error> { + self.write_register_16bit(Register::INT_CTRL, u16::from(config)) + } + + /// Set latching interrupt register configuration + /// + /// # Arguments + /// + /// * `config` - The interrupt latching configuration + pub fn set_interrupt_lachting_config( + &mut self, + config: InterruptLatch, + ) -> Result<(), Error> { + self.write_register_16bit(Register::INT_CTRL, config as u16) + } + fn config_to_reg_data(&self, config: T) -> u16 where T: Into + Copy, @@ -112,8 +154,8 @@ where fn read_sensor_data(&mut self, sensor_type: SensorType) -> Result> { let (base_reg, data_size) = match sensor_type { - SensorType::Accelerometer => (Register::ACC_DATA_X, 21), - SensorType::Gyroscope => (Register::GYR_DATA_X, 15), + SensorType::Accelerometer => (Register::ACC_DATA_X, 1 + 6), + SensorType::Gyroscope => (Register::GYR_DATA_X, 1 + 6), }; let mut data = [0u8; 21]; // Use the larger size @@ -162,8 +204,8 @@ where self.iface.read_data(data) } - fn wait_for_data_ready(&mut self, sensor_type: SensorType) -> Result<(), Error> { - const MAX_RETRIES: u8 = 100; + pub fn wait_for_data_ready(&mut self, sensor_type: SensorType) -> Result<(), Error> { + const MAX_RETRIES: u16 = 1200; let mut retries = 0; while !self.is_data_ready(sensor_type)? { @@ -184,12 +226,113 @@ where SensorType::Gyroscope => Ok((status & 0b0100_0000) != 0), // Check bit 6 (drdy_gyr) } } + + /// Read the Timestamp from the device + pub fn read_sensor_timestamp(&mut self) -> Result> { + let mut data = [Register::SENSOR_TIME_0, 0u8, 0u8, 0u8, 0u8]; + self.read_data(&mut data)?; + Ok(u32::from_le_bytes([data[1], data[2], data[3], data[4]])) + } + + ///configures the FIFO + pub fn set_fifo_config(&mut self, config: &FifoConfig) -> Result<(), Error> { + if *config == self.fifo_config { + return Ok(()); + } + self.write_register_16bit(Register::FIFO_CONF, config.to_register_value())?; + if let Some(watermark) = config.watermark_level { + // convert number of messages to number of 16 bit words while keeping to max value + let watermark = (watermark * (config.fifo_message_len()) as u16).min(0x3FF); + self.write_register_16bit(Register::FIFO_WATERMARK, watermark)?; + } + self.fifo_config = *config; + self.fifo_message_len = config.fifo_message_len(); + Ok(()) + } + + ///flushes the FIFO + pub fn flush_fifo(&mut self) -> Result<(), Error> { + self.write_register_16bit(Register::FIFO_CTRL, 0x01) + } + + ///reads the number of words in the fifo + fn get_fifo_fill_state(&mut self) -> Result> { + let mut data = [Register::FIFO_FILL_LEVEL, 0, 0]; + let res = self.read_data(&mut data)?; + Ok(u16::from_le_bytes([res[0], res[1]])) + } + + /// reads the number of entries in the FIFO + pub fn get_fifo_entry_count(&mut self) -> Result>{ + Ok(self.get_fifo_fill_state()?/self.fifo_message_len) + } + + /// reads one entry from the Fifo + pub fn read_fifo_entry(&mut self) -> Result> { + const FIFO_MESSAGE_LEN_MAX: usize = 22; + let message_len = self.fifo_message_len; + if message_len > self.get_fifo_fill_state()? { + return Err(Error::FifoEmpty); + } + let mut buffer = [0u8; FIFO_MESSAGE_LEN_MAX + 1]; + buffer[0] = Register::FIFO_DATA; + let fifo_data = self.read_data(&mut buffer[..(message_len as usize * 2) + 1])?; + let mut index = 0; + let mut ret = FifoData::default(); + if self.fifo_config.accel_enabled { + let sensor_data = get_sensor3d_data(&fifo_data[index..]); + // fill data for invalid data + if sensor_data.x != 0x7f01 { + ret.accel = Some(sensor_data.to_mps2(self.accel_range.to_g())); + } + index += 6; + } + if self.fifo_config.gyro_enabled { + let sensor_data = get_sensor3d_data(&fifo_data[index..]); + if sensor_data.x != 0x7f02 { + ret.gyro = + Some(get_sensor3d_data(&fifo_data[index..]).to_mps2(self.accel_range.to_g())); + } + index += 6; + } + if self.fifo_config.temp_enabled { + ret.temp = Some(u16::from_le_bytes([fifo_data[index], fifo_data[index + 1]])); + index += 2 + } + if self.fifo_config.timestamp_enabled { + ret.timestamp = Some(u16::from_le_bytes([fifo_data[index], fifo_data[index + 1]])); + } + Ok(ret) + } + + /// reads the interrupt source for the given pin. This resets the interrupt. + pub fn get_int_status(&mut self, pin: InterruptPin) -> Result> { + let reg = match pin { + InterruptPin::Int1 => Register::INT_STATUS_INT1, + InterruptPin::Int2 => Register::INT_STATUS_INT2, + InterruptPin::IC3IBI => Register::INT_STATUS_INT_IBI, + }; + let mut data = [reg, 0, 0]; + let res = self.read_data(&mut data)?; + Ok(InterruptSource::from(u16::from_le_bytes([res[0], res[1]]))) + } + + #[cfg(feature = "debug")] + pub fn debug_read(&mut self, register:u8)->Result>{ + let mut data = [register,0,0]; + let res = self.read_data(&mut data)?; + Ok(u16::from_le_bytes([res[0], res[1]])) + } + #[cfg(feature = "debug")] + pub fn debug_write(&mut self, register:u8, value: u16)->Result<(), Error>{ + self.write_register_16bit(register, value)?; + Ok(()) + } } #[cfg(test)] mod tests { use super::*; - fn get_sensor3d_data(data: &[u8]) -> Sensor3DData { Sensor3DData { x: i16::from_le_bytes([data[0], data[1]]), @@ -197,7 +340,6 @@ mod tests { z: i16::from_le_bytes([data[4], data[5]]), } } - mod sensor3d_data { use super::*; diff --git a/src/interface.rs b/src/interface.rs index b1ed5a1..760056b 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -82,17 +82,14 @@ impl ReadData for I2cInterface where I2C: i2c::I2c, { + // I2C has to read 2 dummy bytes first type Error = Error; fn read_register(&mut self, register: u8) -> Result { - let mut temp_data = [0u8; 128]; - let mut data = [0u8; 2]; + let mut temp_data = [0u8; 3]; self.i2c .write_read(self.address, &[register], &mut temp_data) .map_err(Error::Comm)?; - for i in 0..data.len() { - data[i] = temp_data[i + 2]; - } - Ok(data[0]) + Ok(temp_data[2]) } fn read_data<'a>(&mut self, payload: &'a mut [u8]) -> Result<&'a [u8], Error> { @@ -118,6 +115,7 @@ impl ReadData for SpiInterface where SPI: SpiDevice, { + //spi reads one dummy byte first type Error = Error; fn read_register(&mut self, register: u8) -> Result { let mut data = [register | 0x80, 0, 0]; // Add read bit and 1 dummy byte diff --git a/src/lib.rs b/src/lib.rs index 8c92323..19b1366 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,16 +5,25 @@ /// This module provides a high-level interface for interacting with the Bosch BMI323 IMU. /// It supports both I2C and SPI interfaces and allows for configuration of accelerometer /// and gyroscope settings. +use num_traits::FromPrimitive; + pub mod device; mod interface; mod registers; pub use registers::Register; mod types; +#[cfg(feature = "defmt")] +use defmt::Format; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + pub use types::{ - AccelerometerPowerMode, AccelerometerRange, AverageNum, Bandwidth, Error, GyroscopePowerMode, - GyroscopeRange, OutputDataRate, Sensor3DData, Sensor3DDataScaled, + AccelerometerPowerMode, AccelerometerRange, AverageNum, Bandwidth, Error, FifoConfig, FifoData, + GyroscopePowerMode, GyroscopeRange, InterruptEnable, InterruptLatch, InterruptLevel,InterruptPin, + InterruptMapping, InterruptOd, OutputDataRate, Sensor3DData, Sensor3DDataScaled, SensorType, }; mod sensor_data; +pub use interface::{I2cInterface, SpiInterface}; pub use sensor_data::*; /// Main struct representing the BMI323 device @@ -27,10 +36,14 @@ pub struct Bmi323 { accel_range: AccelerometerRange, /// Current gyroscope range gyro_range: GyroscopeRange, + fifo_config: FifoConfig, + fifo_message_len: u16, } /// Configuration for the accelerometer -#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq)] pub struct AccelConfig { /// Output data rate pub odr: OutputDataRate, @@ -117,7 +130,9 @@ impl AccelConfigBuilder { } /// Configuration for the gyroscope -#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq)] pub struct GyroConfig { /// Output data rate pub odr: OutputDataRate, @@ -214,6 +229,34 @@ impl From for u16 { } } +impl From for AccelConfig { + /// Converts back to a AccelConfig + fn from(value: u16) -> Self { + AccelConfig { + odr: FromPrimitive::from_u16(value & 0xF).unwrap_or(OutputDataRate::Odr100hz), + range: FromPrimitive::from_u16((value >> 4) & 0x7).unwrap_or(AccelerometerRange::G2), + bw: FromPrimitive::from_u16((value >> 7) & 0x1).unwrap_or(Bandwidth::OdrHalf), + avg_num: FromPrimitive::from_u16((value >> 8) & 0x7).unwrap_or(AverageNum::Avg1), + mode: FromPrimitive::from_u16((value >> 12) & 0x7) + .unwrap_or(AccelerometerPowerMode::Normal), + } + } +} + +impl From for GyroConfig { + /// Converts back to a GyroConfig + fn from(value: u16) -> Self { + GyroConfig { + odr: FromPrimitive::from_u16(value & 0xF).unwrap_or(OutputDataRate::Odr100hz), + range: FromPrimitive::from_u16((value >> 4) & 0x7).unwrap_or(GyroscopeRange::DPS2000), + bw: FromPrimitive::from_u16((value >> 7) & 0x1).unwrap_or(Bandwidth::OdrHalf), + avg_num: FromPrimitive::from_u16((value >> 8) & 0x7).unwrap_or(AverageNum::Avg1), + mode: FromPrimitive::from_u16((value >> 12) & 0x7) + .unwrap_or(GyroscopePowerMode::Normal), + } + } +} + impl From for u16 { /// Convert GyroConfig to a 16-bit register value fn from(config: GyroConfig) -> Self { @@ -224,3 +267,264 @@ impl From for u16 { | ((config.mode as u16 & 0x07) << 12) } } + +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct InterruptMapConfig { + pub no_motion: InterruptMapping, + pub any_motion: InterruptMapping, + pub flat: InterruptMapping, + pub orientation: InterruptMapping, + pub step_detector: InterruptMapping, + pub step_counter: InterruptMapping, + pub sig_motion: InterruptMapping, + pub tilt_out: InterruptMapping, + pub tap: InterruptMapping, + pub i3c: InterruptMapping, + pub err_status: InterruptMapping, + pub temp_drdy: InterruptMapping, + pub gyr_drdy: InterruptMapping, + pub acc_drdy: InterruptMapping, + pub fifo_watermark: InterruptMapping, + pub fifo_full: InterruptMapping, +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct InterruptMapConfigBuilder { + no_motion: Option, + any_motion: Option, + flat: Option, + orientation: Option, + step_detector: Option, + step_counter: Option, + sig_motion: Option, + tilt_out: Option, + tap: Option, + i3c: Option, + err_status: Option, + temp_drdy: Option, + gyr_drdy: Option, + acc_drdy: Option, + fifo_watermark: Option, + fifo_full: Option, +} + +impl InterruptMapConfigBuilder { + pub fn no_motion(mut self, mapping: InterruptMapping) -> Self { + self.no_motion = Some(mapping); + self + } + pub fn any_motion(mut self, mapping: InterruptMapping) -> Self { + self.any_motion = Some(mapping); + self + } + pub fn flat(mut self, mapping: InterruptMapping) -> Self { + self.flat = Some(mapping); + self + } + pub fn orientation(mut self, mapping: InterruptMapping) -> Self { + self.orientation = Some(mapping); + self + } + pub fn step_detector(mut self, mapping: InterruptMapping) -> Self { + self.step_detector = Some(mapping); + self + } + pub fn step_counter(mut self, mapping: InterruptMapping) -> Self { + self.step_counter = Some(mapping); + self + } + pub fn sig_motion(mut self, mapping: InterruptMapping) -> Self { + self.sig_motion = Some(mapping); + self + } + pub fn tilt_out(mut self, mapping: InterruptMapping) -> Self { + self.tilt_out = Some(mapping); + self + } + pub fn tap(mut self, mapping: InterruptMapping) -> Self { + self.tap = Some(mapping); + self + } + pub fn i3c(mut self, mapping: InterruptMapping) -> Self { + self.i3c = Some(mapping); + self + } + pub fn err_status(mut self, mapping: InterruptMapping) -> Self { + self.err_status = Some(mapping); + self + } + pub fn temp_drdy(mut self, mapping: InterruptMapping) -> Self { + self.temp_drdy = Some(mapping); + self + } + pub fn gyr_drdy(mut self, mapping: InterruptMapping) -> Self { + self.gyr_drdy = Some(mapping); + self + } + pub fn acc_drdy(mut self, mapping: InterruptMapping) -> Self { + self.acc_drdy = Some(mapping); + self + } + pub fn fifo_watermark(mut self, mapping: InterruptMapping) -> Self { + self.fifo_watermark = Some(mapping); + self + } + pub fn fifo_full(mut self, mapping: InterruptMapping) -> Self { + self.fifo_full = Some(mapping); + self + } + pub fn build(self) -> InterruptMapConfig { + InterruptMapConfig { + no_motion: self.no_motion.unwrap_or(InterruptMapping::Disabled), + any_motion: self.any_motion.unwrap_or(InterruptMapping::Disabled), + flat: self.flat.unwrap_or(InterruptMapping::Disabled), + orientation: self.orientation.unwrap_or(InterruptMapping::Disabled), + step_detector: self.step_detector.unwrap_or(InterruptMapping::Disabled), + step_counter: self.step_counter.unwrap_or(InterruptMapping::Disabled), + sig_motion: self.sig_motion.unwrap_or(InterruptMapping::Disabled), + tilt_out: self.tilt_out.unwrap_or(InterruptMapping::Disabled), + tap: self.tap.unwrap_or(InterruptMapping::Disabled), + i3c: self.i3c.unwrap_or(InterruptMapping::Disabled), + err_status: self.err_status.unwrap_or(InterruptMapping::Disabled), + temp_drdy: self.temp_drdy.unwrap_or(InterruptMapping::Disabled), + gyr_drdy: self.gyr_drdy.unwrap_or(InterruptMapping::Disabled), + acc_drdy: self.acc_drdy.unwrap_or(InterruptMapping::Disabled), + fifo_watermark: self.fifo_watermark.unwrap_or(InterruptMapping::Disabled), + fifo_full: self.fifo_full.unwrap_or(InterruptMapping::Disabled), + } + } +} + +impl InterruptMapConfig { + pub fn builder() -> InterruptMapConfigBuilder { + InterruptMapConfigBuilder::default() + } + pub const fn map1(&self) -> u16 { + self.no_motion as u16 & 0x03 + | (self.any_motion as u16 & 0x03) << 2 + | (self.flat as u16 & 0x03) << 4 + | (self.orientation as u16 & 0x03) << 6 + | (self.step_detector as u16 & 0x03) << 8 + | (self.step_counter as u16 & 0x03) << 10 + | (self.sig_motion as u16 & 0x03) << 12 + | (self.tilt_out as u16 & 0x03) << 14 + } + + pub const fn map2(&self) -> u16 { + self.tap as u16 & 0x03 + | (self.i3c as u16 & 0x03) << 2 + | (self.err_status as u16 & 0x03) << 4 + | (self.temp_drdy as u16 & 0x03) << 6 + | (self.gyr_drdy as u16 & 0x03) << 8 + | (self.acc_drdy as u16 & 0x03) << 10 + | (self.fifo_watermark as u16 & 0x03) << 12 + | (self.fifo_full as u16 & 0x03) << 14 + } +} + +impl Default for InterruptMapConfig { + fn default() -> Self { + InterruptMapConfigBuilder::default().build() + } +} + +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy)] +pub struct IOInterruptConfig { + int1_lvl: InterruptLevel, + int1_od: InterruptOd, + int1_en: InterruptEnable, + int2_lvl: InterruptLevel, + int2_od: InterruptOd, + int2_en: InterruptEnable, +} + +impl IOInterruptConfig { + pub fn builder() -> IOInterruptConfigBuilder { + IOInterruptConfigBuilder::default() + } +} + +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, Default)] +pub struct IOInterruptConfigBuilder { + int1_lvl: Option, + int1_od: Option, + int1_en: Option, + int2_lvl: Option, + int2_od: Option, + int2_en: Option, +} + +impl IOInterruptConfigBuilder { + pub fn int1_lvl(mut self, level: InterruptLevel) -> Self { + self.int1_lvl = Some(level); + self + } + pub fn int1_od(mut self, od: InterruptOd) -> Self { + self.int1_od = Some(od); + self + } + pub fn int1_enable(mut self, enable: InterruptEnable) -> Self { + self.int1_en = Some(enable); + self + } + pub fn int2_lvl(mut self, level: InterruptLevel) -> Self { + self.int2_lvl = Some(level); + self + } + pub fn int2_od(mut self, od: InterruptOd) -> Self { + self.int1_od = Some(od); + self + } + pub fn int2_enable(mut self, enable: InterruptEnable) -> Self { + self.int2_en = Some(enable); + self + } + pub fn build(self) -> IOInterruptConfig { + IOInterruptConfig { + int1_lvl: self.int1_lvl.unwrap_or(InterruptLevel::ActiveLow), + int1_od: self.int1_od.unwrap_or(InterruptOd::PushPull), + int1_en: self.int1_en.unwrap_or(InterruptEnable::Disabled), + int2_lvl: self.int2_lvl.unwrap_or(InterruptLevel::ActiveLow), + int2_od: self.int2_od.unwrap_or(InterruptOd::PushPull), + int2_en: self.int2_en.unwrap_or(InterruptEnable::Disabled), + } + } +} + +impl From for u16 { + fn from(config: IOInterruptConfig) -> Self { + (config.int1_lvl as u16 & 0x1) + | (config.int1_od as u16 & 0x1) << 1 + | (config.int1_en as u16 & 0x1) << 2 + | (config.int2_lvl as u16 & 0x1) << 7 + | (config.int2_od as u16 & 0x1) << 8 + | (config.int2_en as u16 & 0x1) << 9 + } +} + +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct InterruptSource { + pub gyr_drdy: bool, + pub acc_drdy: bool, + pub fifo_watermark: bool, + pub fifo_full: bool, +} + +impl From for InterruptSource { + fn from(value: u16) -> Self { + Self { + gyr_drdy: (value & 1 << 12) != 0, + acc_drdy: (value & 1 << 13) != 0, + fifo_watermark: (value & 1 << 14) != 0, + fifo_full: (value & 1 << 15) != 0, + } + } +} diff --git a/src/registers.rs b/src/registers.rs index ef63864..82432b8 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -11,12 +11,37 @@ impl Register { pub const ACC_DATA_X: u8 = 0x03; /// Gyroscope X-axis data register address pub const GYR_DATA_X: u8 = 0x06; + /// Lower time Register + pub const SENSOR_TIME_0: u8 = 0x0A; + /// Upper time Register + pub const SENSOR_TIME_1: u8 = 0x0B; + ///amounts of bytes in FIFO + pub const FIFO_FILL_LEVEL: u8 = 0x15; + ///Data in FIFO, reads as 0x8000 when over read + pub const FIFO_DATA: u8 = 0x16; /// Accelerometer configuration register address pub const ACC_CONF: u8 = 0x20; /// Gyroscope configuration register address pub const GYR_CONF: u8 = 0x21; + /// FIFO watermark level in bytes Register + pub const FIFO_WATERMARK: u8 = 0x35; + /// FIFO configuration Register + pub const FIFO_CONF: u8 = 0x36; + /// FIFO control Register + pub const FIFO_CTRL: u8 = 0x37; /// Command register address pub const CMD: u8 = 0x7E; + /// IO interrupt control register address + pub const INT_CTRL: u8 = 0x38; + /// Interrupt configuration register address + pub const INT_CONF: u8 = 0x39; + /// Interrupt Map 1 register address + pub const INT_MAP1: u8 = 0x3A; + /// Interrupt Map 2 register address + pub const INT_MAP2: u8 = 0x3B; + pub const INT_STATUS_INT1: u8 = 0x0D; + pub const INT_STATUS_INT2: u8 = 0x0E; + pub const INT_STATUS_INT_IBI: u8 = 0x0F; /// Expected chip ID for BMI323 pub const BMI323_CHIP_ID: u8 = 0x43; /// Soft reset command value diff --git a/src/sensor_data.rs b/src/sensor_data.rs index 5795bca..7003925 100644 --- a/src/sensor_data.rs +++ b/src/sensor_data.rs @@ -2,7 +2,7 @@ use crate::types::{Sensor3DData, Sensor3DDataScaled}; /// Standard gravity in m/s^2 pub const GRAVITY: f32 = 9.8; -/// Alias for accelormeter data +/// Alias for accelerometer data pub type AccelerometerData = Sensor3DData; /// Alias for gyroscope data pub type GyroscopeData = Sensor3DData; diff --git a/src/types.rs b/src/types.rs index 7d21c96..0a85397 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,14 @@ use core::fmt::Debug; +#[cfg(feature = "defmt")] +use defmt::Format; +use num_derive::FromPrimitive; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// Possible errors that can occur when interacting with the BMI323 +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug)] pub enum Error { /// Communication error @@ -11,25 +19,33 @@ pub enum Error { InvalidConfig, /// Timeout error Timeout, + ///FIFO empty + FifoEmpty, } /// Accelerometer power modes -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq, FromPrimitive)] pub enum AccelerometerPowerMode { /// Accelerometer disabled Disable = 0x00, /// Low power mode LowPower = 0x03, /// Normal power mode + #[default] Normal = 0x04, /// High performance mode HighPerf = 0x07, } -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq, FromPrimitive)] pub enum AccelerometerRange { G2 = 0, G4 = 1, + #[default] G8 = 2, G16 = 3, } @@ -45,29 +61,28 @@ impl AccelerometerRange { } } -impl Default for AccelerometerRange { - fn default() -> Self { - AccelerometerRange::G8 - } -} - /// Gyroscope power mode -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq, FromPrimitive)] pub enum GyroscopePowerMode { /// Gyroscope disabled Disable = 0x00, - /// Supend mode + /// Suspend mode Suspend = 0x01, /// Low power mode LowPower = 0x03, /// Normal power mode + #[default] Normal = 0x04, - /// High perfomance mode + /// High performance mode HighPerf = 0x07, } /// Gyroscope measurement ranges -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq, FromPrimitive)] pub enum GyroscopeRange { /// ±125 degrees per second DPS125 = 0, @@ -78,6 +93,7 @@ pub enum GyroscopeRange { /// ±1000 degrees per second DPS1000 = 3, /// ±2000 degrees per second + #[default] DPS2000 = 4, } @@ -93,13 +109,9 @@ impl GyroscopeRange { } } -impl Default for GyroscopeRange { - fn default() -> Self { - GyroscopeRange::DPS2000 - } -} - /// 3D sensor data (raw values) +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone, Copy, PartialEq)] pub struct Sensor3DData { /// X-axis value @@ -110,8 +122,18 @@ pub struct Sensor3DData { pub z: i16, } +pub fn get_sensor3d_data(data: &[u8]) -> Sensor3DData { + Sensor3DData { + x: i16::from_le_bytes([data[0], data[1]]), + y: i16::from_le_bytes([data[2], data[3]]), + z: i16::from_le_bytes([data[4], data[5]]), + } +} + /// Scaled 3D sensor data -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, Default, PartialEq)] pub struct Sensor3DDataScaled { /// X-axis scaled value pub x: f32, @@ -121,8 +143,62 @@ pub struct Sensor3DDataScaled { pub z: f32, } +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, Default)] +pub struct FifoData { + pub accel: Option, + pub gyro: Option, + pub temp: Option, + pub timestamp: Option, +} + +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, Default, PartialEq)] +pub struct FifoConfig { + pub stop_on_full: bool, + pub accel_enabled: bool, + pub gyro_enabled: bool, + pub temp_enabled: bool, + pub timestamp_enabled: bool, + ///watermark level in messages + pub watermark_level: Option, +} + +impl FifoConfig { + /// converts to the value as to write into the register + pub fn to_register_value(&self) -> u16 { + self.stop_on_full as u16 + | (self.timestamp_enabled as u16) << 8 + | (self.accel_enabled as u16) << 9 + | (self.gyro_enabled as u16) << 10 + | (self.temp_enabled as u16) << 11 + } + + /// length of each fifo entry in 16 bit words + pub const fn fifo_message_len(&self) -> u16 { + let mut len = 0; + if self.accel_enabled { + len += 3; + } + if self.gyro_enabled { + len += 3; + } + if self.temp_enabled { + len += 1; + } + if self.timestamp_enabled { + len += 1; + } + len + } +} + /// Output data rates for sensors -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq, FromPrimitive)] pub enum OutputDataRate { /// 0.78 Hz Odr0_78hz = 0x01, @@ -139,6 +215,7 @@ pub enum OutputDataRate { /// 50 Hz Odr50hz = 0x07, /// 100 Hz + #[default] Odr100hz = 0x08, /// 200 Hz Odr200hz = 0x09, @@ -155,9 +232,12 @@ pub enum OutputDataRate { } /// Number of samples to average -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq, FromPrimitive)] pub enum AverageNum { /// No averaging + #[default] Avg1 = 0x00, /// Average 2 samples Avg2 = 0x01, @@ -174,16 +254,96 @@ pub enum AverageNum { } /// Sensor bandwidth settings -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone, Copy, PartialEq, FromPrimitive)] pub enum Bandwidth { /// Half of the output data rate + #[default] OdrHalf = 0, /// Quarter of the output data rate OdrQuarter = 1, } -#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)] pub enum SensorType { Accelerometer, Gyroscope, } + +/// Mapping of interrupt to specific pin +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Default, FromPrimitive)] +pub enum InterruptMapping { + ///Interrupt is not mapped to any Pin + #[default] + Disabled = 0x0, + ///Interrupt is mapped to Int1 pin + Int1 = 0x1, + ///Interrupt is mapped to Int2 pin + Int2 = 0x2, + ///Interrupt is mapped to I3C IBI pin + IC3IBI = 0x3, +} +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)] +pub enum InterruptPin { + ///Interrupt is mapped to Int1 pin + Int1 = 0x00, + ///Interrupt is mapped to Int2 pin + Int2 = 0x01, + ///Interrupt is mapped to I3C IBI pin + IC3IBI = 0x02, +} + +/// Level of interrupt pin when driven +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Default, FromPrimitive)] +pub enum InterruptLevel { + /// Low when active + #[default] + ActiveLow = 0x0, + /// High when active + ActiveHigh = 0x1, +} + +///Type of output +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Default, FromPrimitive)] +pub enum InterruptOd { + /// Push pull + #[default] + PushPull = 0x0, + /// Open drain + OpenDrain = 0x1, +} + +/// Enable interrupt pin +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Default, FromPrimitive)] +pub enum InterruptEnable { + ///Disabled + #[default] + Disabled = 0x0, + ///Enabled + Enabled = 0x1, +} + +/// Latching type of Interrupt +#[cfg_attr(feature = "defmt", derive(Format))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Default, FromPrimitive)] +pub enum InterruptLatch { + /// Non Latched + #[default] + NonLatched = 0x0, + /// Permanent Latched + PermanentLatched = 0x1, +} diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 146af46..9729b87 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,15 +1,44 @@ use bmi323::{ AccelConfig, AccelerometerPowerMode, AccelerometerRange, AverageNum, Bandwidth, Bmi323, - GyroConfig, GyroscopePowerMode, GyroscopeRange, OutputDataRate, + GyroConfig, GyroscopePowerMode, GyroscopeRange, OutputDataRate, InterruptSource }; use embedded_hal_mock::eh1::delay::NoopDelay as MockDelay; use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTransaction}; +#[test] +fn test_conversion() { + let accel_config = AccelConfig::builder() + .odr(OutputDataRate::Odr100hz) + .range(AccelerometerRange::G16) + .bw(Bandwidth::OdrQuarter) // ODR/4 + .avg_num(AverageNum::Avg64) + .mode(AccelerometerPowerMode::Normal) + .build(); + assert_eq!( + accel_config, + AccelConfig::from(u16::from(accel_config.clone())) + ); + + let gyro_config = GyroConfig::builder() + .odr(OutputDataRate::Odr100hz) + .range(GyroscopeRange::DPS2000) + .bw(Bandwidth::OdrQuarter) + .avg_num(AverageNum::Avg64) + .mode(GyroscopePowerMode::Normal) + .build(); + assert_eq!( + gyro_config, + GyroConfig::from(u16::from(gyro_config.clone())) + ); +} + +//I2C has two dummy bytes at the start of read #[test] fn test_bmi323_init() { let expectations = [ - I2cTransaction::write(0x68, vec![0x7E, 0xAF, 0xDE]), - I2cTransaction::write_read(0x68, vec![0x00], vec![0x43]), + I2cTransaction::write(0x68, vec![0x7E, 0xAF, 0xDE]), //soft reset + I2cTransaction::write_read(0x68, vec![0x01], vec![0x00, 0x00, 0x00]), //state after reset + I2cTransaction::write_read(0x68, vec![0x00], vec![0x00, 0x00, 0x43]), //chip ID ]; let mut i2c = I2cMock::new(&expectations); @@ -25,7 +54,9 @@ fn test_bmi323_init() { fn test_bmi323_set_sensor_config() { let expectations = [ I2cTransaction::write(0x68, vec![0x20, 0xB8, 0x46]), // Accelerometer config + I2cTransaction::write_read(0x68, vec![0x02], vec![0x00, 0x00, 0x80]), //check for data ready I2cTransaction::write(0x68, vec![0x21, 0x48, 0x46]), // Gyroscope config + I2cTransaction::write_read(0x68, vec![0x02], vec![0x00, 0x00, 0x40]), //check for data ready ]; let mut i2c = I2cMock::new(&expectations); @@ -59,7 +90,7 @@ fn test_bmi323_read_sensor_data() { let expectations = [I2cTransaction::write_read( 0x68, vec![0x03], - vec![0, 0, 0, 0, 0, 0], + vec![0x00, 0x00, 0, 0, 0, 0, 0, 0], )]; let mut i2c = I2cMock::new(&expectations); @@ -73,3 +104,23 @@ fn test_bmi323_read_sensor_data() { i2c.done(); } +#[test] +fn test_bmi323_read_int_source() { + let expectations = [I2cTransaction::write_read( + 0x68, + vec![0x0D], + vec![0x00, 0x00, 0x00, 0x30], + )]; + + let mut i2c = I2cMock::new(&expectations); + let delay = MockDelay::new(); + let mut bmi323 = Bmi323::new_with_i2c(i2c.clone(), 0x68, delay); + + let source = bmi323.get_int_status(bmi323::InterruptPin::Int1).unwrap(); + assert!(source.gyr_drdy); + assert!(source.acc_drdy); + assert!(!source.fifo_full); + assert!(!source.fifo_watermark); + + i2c.done(); +} diff --git a/tests/unit_tests_types.rs b/tests/unit_tests_types.rs index ab2f106..494b3f5 100644 --- a/tests/unit_tests_types.rs +++ b/tests/unit_tests_types.rs @@ -1,4 +1,7 @@ -use bmi323::{AccelerometerRange, GyroscopeRange}; +use bmi323::{ + AccelConfig, AccelerometerRange, FifoConfig, GyroConfig, GyroscopeRange, + InterruptMapConfigBuilder, InterruptSource, +}; #[test] fn test_accelerometer_range_to_g() { @@ -26,3 +29,58 @@ fn test_accelerometer_range_default() { fn test_gyroscope_range_default() { assert_eq!(GyroscopeRange::default(), GyroscopeRange::DPS2000); } + +#[test] +fn test_accelerometer_default() { + println!("{:x?}", u16::from(AccelConfig::default())); + assert_eq!(u16::from(AccelConfig::default()), 0x4028); +} + +#[test] +fn test_gyroscope_default() { + println!("{:x?}", u16::from(GyroConfig::default())); + assert_eq!(u16::from(GyroConfig::default()), 0x4048); +} + +#[test] +fn test_fifo_message_len() { + let mut config = FifoConfig::default(); + assert_eq!(config.fifo_message_len(), 0); + config.accel_enabled = true; + assert_eq!(config.fifo_message_len(), 3); + config.gyro_enabled = true; + assert_eq!(config.fifo_message_len(), 6); + config.timestamp_enabled = true; + assert_eq!(config.fifo_message_len(), 7); + config.temp_enabled = true; + assert_eq!(config.fifo_message_len(), 8); + config.stop_on_full = true; + assert_eq!(config.fifo_message_len(), 8); +} + +#[test] +fn test_interrupt_config_values() { + let mut config = InterruptMapConfigBuilder::default().build(); + assert_eq!(config.map1(), 0u16); + assert_eq!(config.map2(), 0u16); + config = InterruptMapConfigBuilder::default() + .fifo_watermark(bmi323::InterruptMapping::Int1) + .build(); + assert_eq!(config.map1(), 0u16); + assert_eq!(config.map2(), 1u16 << 12); + config = InterruptMapConfigBuilder::default() + .acc_drdy(bmi323::InterruptMapping::Int1) + .gyr_drdy(bmi323::InterruptMapping::Int2) + .build(); + assert_eq!(config.map1(), 0u16); + assert_eq!(config.map2(), (2u16 << 8) | (1u16 << 10)); +} + +#[test] +fn test_interrupt_source(){ + assert_eq!(InterruptSource::from(1<<12), InterruptSource{gyr_drdy:true, ..Default::default()}); + assert_eq!(InterruptSource::from(1<<13), InterruptSource{acc_drdy:true, ..Default::default()}); + assert_eq!(InterruptSource::from(1<<14), InterruptSource{fifo_watermark:true, ..Default::default()}); + assert_eq!(InterruptSource::from(1<<15), InterruptSource{fifo_full:true, ..Default::default()}); + assert_eq!(InterruptSource::from(1<<12|1<<13), InterruptSource{gyr_drdy:true,acc_drdy:true, ..Default::default()}); +}