#![allow(async_fn_in_trait)]
#![no_std]
pub mod config;
pub mod errors;
pub mod interface;
pub mod registers;
pub mod types;
pub use config::*;
pub use errors::Error;
pub use interface::*;
pub use registers::{
AccelBandwidth,
AccelDataRate,
AccelHpfMode,
AccelMagRegisters,
AccelScale,
AccelSelfTest,
ActiveLevel,
ActiveLevelInverted,
BlockDataUpdate,
ClickSign,
ClickSrc,
Enable,
Endianness,
FifoMode,
FifoSrcReg,
FifoSrcRegG,
GyroBandwidth,
GyroDataRate,
GyroHpfCutoff,
GyroHpfMode,
GyroOutputSel,
GyroPowerMode,
GyroRegisters,
GyroScale,
GyroSelfTest,
Int1SrcG,
IntGenSrc,
IntSrcRegM,
InterruptCombination,
LatchInterrupt,
MagDataRate,
MagLowPower,
MagMode,
MagResolution,
MagScale,
OutputType,
PowerMode,
SpiMode,
StatusRegA,
StatusRegG,
StatusRegM,
device_constants,
};
pub use types::*;
use embedded_hal_async::delay::DelayNs;
pub struct Lsm9ds0<I>
where
I: Interface,
{
interface: I,
config: Lsm9ds0Config,
}
impl<I> Lsm9ds0<I>
where
I: Interface,
{
pub fn new(interface: I) -> Self {
Self {
interface,
config: Lsm9ds0Config::default(),
}
}
pub fn new_with_config(interface: I, config: Lsm9ds0Config) -> Self {
Self { interface, config }
}
pub async fn init<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), Error<I::BusError>> {
self.verify_device_ids().await?;
self.apply_configs().await?;
if let Some(orientation) = self.config.auto_calibration {
self.calibrate_bias(delay, orientation).await?;
}
Ok(())
}
pub async fn begin<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), Error<I::BusError>> {
self.init(delay).await
}
pub async fn software_reset<D: DelayNs>(
&mut self,
delay: &mut D,
) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg5_g.set_boot(Enable::Enabled);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG5_G.addr(),
self.config.ctrl_reg5_g.into(),
)
.await?;
self.config.ctrl_reg0_xm.set_boot(Enable::Enabled);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG0_XM.addr(),
self.config.ctrl_reg0_xm.into(),
)
.await?;
delay.delay_ms(50).await;
self.config = Lsm9ds0Config::default();
self.verify_device_ids().await?;
Ok(())
}
pub async fn set_config(&mut self, config: Lsm9ds0Config) -> Result<(), Error<I::BusError>> {
self.config = config;
self.apply_configs().await
}
pub fn config(&self) -> &Lsm9ds0Config {
&self.config
}
pub async fn reapply_config(&mut self) -> Result<(), Error<I::BusError>> {
self.apply_configs().await
}
pub async fn verify_config(&mut self) -> Result<(), Error<I::BusError>> {
fn find_mismatch(base_addr: u8, expected: &[u8], actual: &[u8]) -> Option<(u8, u8, u8)> {
for (i, (&exp, &act)) in expected.iter().zip(actual.iter()).enumerate() {
if exp != act {
return Some((base_addr + i as u8, exp, act));
}
}
None
}
let expected_g_ctrl: [u8; 5] = [
self.config.ctrl_reg1_g.into(),
self.config.ctrl_reg2_g.into(),
self.config.ctrl_reg3_g.into(),
self.config.ctrl_reg4_g.into(),
self.config.ctrl_reg5_g.into(),
];
let mut actual_g_ctrl = [0u8; 5];
self.interface
.read_gyro(GyroRegisters::CTRL_REG1_G.addr(), &mut actual_g_ctrl)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
GyroRegisters::CTRL_REG1_G.addr(),
&expected_g_ctrl,
&actual_g_ctrl,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
let mut actual = [0u8; 1];
self.interface
.read_gyro(GyroRegisters::FIFO_CTRL_REG_G.addr(), &mut actual)
.await?;
let expected_val: u8 = self.config.fifo_ctrl_reg_g.into();
if actual[0] != expected_val {
return Err(Error::ConfigMismatch {
register: GyroRegisters::FIFO_CTRL_REG_G.addr(),
expected: expected_val,
actual: actual[0],
});
}
self.interface
.read_gyro(GyroRegisters::INT1_CFG_G.addr(), &mut actual)
.await?;
let expected_val: u8 = self.config.int1_cfg_g.into();
if actual[0] != expected_val {
return Err(Error::ConfigMismatch {
register: GyroRegisters::INT1_CFG_G.addr(),
expected: expected_val,
actual: actual[0],
});
}
let expected_g_int: [u8; 7] = [
((self.config.gyro_int_ths_x >> 8) & 0x7F) as u8,
(self.config.gyro_int_ths_x & 0xFF) as u8,
((self.config.gyro_int_ths_y >> 8) & 0x7F) as u8,
(self.config.gyro_int_ths_y & 0xFF) as u8,
((self.config.gyro_int_ths_z >> 8) & 0x7F) as u8,
(self.config.gyro_int_ths_z & 0xFF) as u8,
self.config.int1_duration_g.into(),
];
let mut actual_g_int = [0u8; 7];
self.interface
.read_gyro(GyroRegisters::INT1_THS_XH_G.addr(), &mut actual_g_int)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
GyroRegisters::INT1_THS_XH_G.addr(),
&expected_g_int,
&actual_g_int,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
self.interface
.read_xm(AccelMagRegisters::INT_CTRL_REG_M.addr(), &mut actual)
.await?;
let expected_val: u8 = self.config.int_ctrl_reg_m.into();
if actual[0] != expected_val {
return Err(Error::ConfigMismatch {
register: AccelMagRegisters::INT_CTRL_REG_M.addr(),
expected: expected_val,
actual: actual[0],
});
}
let expected_mag_ths: [u8; 2] = [
(self.config.mag_int_ths & 0xFF) as u8,
((self.config.mag_int_ths >> 8) & 0x7F) as u8,
];
let mut actual_mag_ths = [0u8; 2];
self.interface
.read_xm(AccelMagRegisters::INT_THS_L_M.addr(), &mut actual_mag_ths)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
AccelMagRegisters::INT_THS_L_M.addr(),
&expected_mag_ths,
&actual_mag_ths,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
let expected_mag_off: [u8; 6] = [
(self.config.mag_offset_x & 0xFF) as u8,
((self.config.mag_offset_x >> 8) & 0xFF) as u8,
(self.config.mag_offset_y & 0xFF) as u8,
((self.config.mag_offset_y >> 8) & 0xFF) as u8,
(self.config.mag_offset_z & 0xFF) as u8,
((self.config.mag_offset_z >> 8) & 0xFF) as u8,
];
let mut actual_mag_off = [0u8; 6];
self.interface
.read_xm(AccelMagRegisters::OFFSET_X_L_M.addr(), &mut actual_mag_off)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
AccelMagRegisters::OFFSET_X_L_M.addr(),
&expected_mag_off,
&actual_mag_off,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
let expected_xm_ctrl: [u8; 8] = [
self.config.ctrl_reg0_xm.into(),
self.config.ctrl_reg1_xm.into(),
self.config.ctrl_reg2_xm.into(),
self.config.ctrl_reg3_xm.into(),
self.config.ctrl_reg4_xm.into(),
self.config.ctrl_reg5_xm.into(),
self.config.ctrl_reg6_xm.into(),
self.config.ctrl_reg7_xm.into(),
];
let mut actual_xm_ctrl = [0u8; 8];
self.interface
.read_xm(AccelMagRegisters::CTRL_REG0_XM.addr(), &mut actual_xm_ctrl)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
AccelMagRegisters::CTRL_REG0_XM.addr(),
&expected_xm_ctrl,
&actual_xm_ctrl,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
self.interface
.read_xm(AccelMagRegisters::FIFO_CTRL_REG.addr(), &mut actual)
.await?;
let expected_val: u8 = self.config.fifo_ctrl_reg.into();
if actual[0] != expected_val {
return Err(Error::ConfigMismatch {
register: AccelMagRegisters::FIFO_CTRL_REG.addr(),
expected: expected_val,
actual: actual[0],
});
}
self.interface
.read_xm(AccelMagRegisters::INT_GEN_1_REG.addr(), &mut actual)
.await?;
let expected_val: u8 = self.config.int_gen_1_reg.into();
if actual[0] != expected_val {
return Err(Error::ConfigMismatch {
register: AccelMagRegisters::INT_GEN_1_REG.addr(),
expected: expected_val,
actual: actual[0],
});
}
let expected_gen1: [u8; 2] = [
self.config.int_gen_1_ths & 0x7F,
self.config.int_gen_1_duration & 0x7F,
];
let mut actual_gen1 = [0u8; 2];
self.interface
.read_xm(AccelMagRegisters::INT_GEN_1_THS.addr(), &mut actual_gen1)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
AccelMagRegisters::INT_GEN_1_THS.addr(),
&expected_gen1,
&actual_gen1,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
self.interface
.read_xm(AccelMagRegisters::INT_GEN_2_REG.addr(), &mut actual)
.await?;
let expected_val: u8 = self.config.int_gen_2_reg.into();
if actual[0] != expected_val {
return Err(Error::ConfigMismatch {
register: AccelMagRegisters::INT_GEN_2_REG.addr(),
expected: expected_val,
actual: actual[0],
});
}
let expected_gen2: [u8; 2] = [
self.config.int_gen_2_ths & 0x7F,
self.config.int_gen_2_duration & 0x7F,
];
let mut actual_gen2 = [0u8; 2];
self.interface
.read_xm(AccelMagRegisters::INT_GEN_2_THS.addr(), &mut actual_gen2)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
AccelMagRegisters::INT_GEN_2_THS.addr(),
&expected_gen2,
&actual_gen2,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
self.interface
.read_xm(AccelMagRegisters::CLICK_CFG.addr(), &mut actual)
.await?;
let expected_val: u8 = self.config.click_cfg.into();
if actual[0] != expected_val {
return Err(Error::ConfigMismatch {
register: AccelMagRegisters::CLICK_CFG.addr(),
expected: expected_val,
actual: actual[0],
});
}
let expected_click: [u8; 4] = [
self.config.click_ths & 0x7F,
self.config.time_limit_ms,
self.config.time_latency_ms,
self.config.time_window_ms,
];
let mut actual_click = [0u8; 4];
self.interface
.read_xm(AccelMagRegisters::CLICK_THS.addr(), &mut actual_click)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
AccelMagRegisters::CLICK_THS.addr(),
&expected_click,
&actual_click,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
let expected_act: [u8; 2] = [self.config.act_ths & 0x7F, self.config.act_dur];
let mut actual_act = [0u8; 2];
self.interface
.read_xm(AccelMagRegisters::ACT_THS.addr(), &mut actual_act)
.await?;
if let Some((reg, exp, act)) = find_mismatch(
AccelMagRegisters::ACT_THS.addr(),
&expected_act,
&actual_act,
) {
return Err(Error::ConfigMismatch {
register: reg,
expected: exp,
actual: act,
});
}
Ok(())
}
async fn verify_device_ids(&mut self) -> Result<(), Error<I::BusError>> {
let mut id = [0u8];
self.interface
.read_gyro(GyroRegisters::WHO_AM_I_G.addr(), &mut id)
.await?;
if id[0] != registers::device_constants::gyro::DEVICE_ID {
return Err(Error::InvalidGyroId {
expected: registers::device_constants::gyro::DEVICE_ID,
actual: id[0],
});
}
self.interface
.read_xm(AccelMagRegisters::WHO_AM_I_XM.addr(), &mut id)
.await?;
if id[0] != registers::device_constants::xm::DEVICE_ID {
return Err(Error::InvalidXmId {
expected: registers::device_constants::xm::DEVICE_ID,
actual: id[0],
});
}
Ok(())
}
async fn apply_configs(&mut self) -> Result<(), Error<I::BusError>> {
self.interface
.write_gyro(
GyroRegisters::CTRL_REG1_G.addr(),
&[
self.config.ctrl_reg1_g.into(),
self.config.ctrl_reg2_g.into(),
self.config.ctrl_reg3_g.into(),
self.config.ctrl_reg4_g.into(),
self.config.ctrl_reg5_g.into(),
],
)
.await?;
self.interface
.write_byte_gyro(
GyroRegisters::FIFO_CTRL_REG_G.addr(),
self.config.fifo_ctrl_reg_g.into(),
)
.await?;
self.interface
.write_byte_gyro(
GyroRegisters::INT1_CFG_G.addr(),
self.config.int1_cfg_g.into(),
)
.await?;
self.interface
.write_gyro(
GyroRegisters::INT1_THS_XH_G.addr(),
&[
((self.config.gyro_int_ths_x >> 8) & 0x7F) as u8,
(self.config.gyro_int_ths_x & 0xFF) as u8,
((self.config.gyro_int_ths_y >> 8) & 0x7F) as u8,
(self.config.gyro_int_ths_y & 0xFF) as u8,
((self.config.gyro_int_ths_z >> 8) & 0x7F) as u8,
(self.config.gyro_int_ths_z & 0xFF) as u8,
self.config.int1_duration_g.into(),
],
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::INT_CTRL_REG_M.addr(),
self.config.int_ctrl_reg_m.into(),
)
.await?;
self.interface
.write_xm(
AccelMagRegisters::INT_THS_L_M.addr(),
&[
(self.config.mag_int_ths & 0xFF) as u8,
((self.config.mag_int_ths >> 8) & 0x7F) as u8,
],
)
.await?;
self.interface
.write_xm(
AccelMagRegisters::OFFSET_X_L_M.addr(),
&[
(self.config.mag_offset_x & 0xFF) as u8,
((self.config.mag_offset_x >> 8) & 0xFF) as u8,
(self.config.mag_offset_y & 0xFF) as u8,
((self.config.mag_offset_y >> 8) & 0xFF) as u8,
(self.config.mag_offset_z & 0xFF) as u8,
((self.config.mag_offset_z >> 8) & 0xFF) as u8,
],
)
.await?;
self.interface
.write_xm(
AccelMagRegisters::CTRL_REG0_XM.addr(),
&[
self.config.ctrl_reg0_xm.into(),
self.config.ctrl_reg1_xm.into(),
self.config.ctrl_reg2_xm.into(),
self.config.ctrl_reg3_xm.into(),
self.config.ctrl_reg4_xm.into(),
self.config.ctrl_reg5_xm.into(),
self.config.ctrl_reg6_xm.into(),
self.config.ctrl_reg7_xm.into(),
],
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::FIFO_CTRL_REG.addr(),
self.config.fifo_ctrl_reg.into(),
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::INT_GEN_1_REG.addr(),
self.config.int_gen_1_reg.into(),
)
.await?;
self.interface
.write_xm(
AccelMagRegisters::INT_GEN_1_THS.addr(),
&[
self.config.int_gen_1_ths & 0x7F,
self.config.int_gen_1_duration & 0x7F,
],
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::INT_GEN_2_REG.addr(),
self.config.int_gen_2_reg.into(),
)
.await?;
self.interface
.write_xm(
AccelMagRegisters::INT_GEN_2_THS.addr(),
&[
self.config.int_gen_2_ths & 0x7F,
self.config.int_gen_2_duration & 0x7F,
],
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::CLICK_CFG.addr(),
self.config.click_cfg.into(),
)
.await?;
self.interface
.write_xm(
AccelMagRegisters::CLICK_THS.addr(),
&[
self.config.click_ths & 0x7F,
self.config.time_limit_ms,
self.config.time_latency_ms,
self.config.time_window_ms,
],
)
.await?;
self.interface
.write_xm(
AccelMagRegisters::ACT_THS.addr(),
&[self.config.act_ths & 0x7F, self.config.act_dur],
)
.await?;
Ok(())
}
pub async fn read_gyro_fifo_level(&mut self) -> Result<u8, Error<I::BusError>> {
let status = self.read_gyro_fifo_status().await?;
Ok(status.fss())
}
pub async fn read_gyro_fifo(&mut self) -> Result<(i16, i16, i16), Error<I::BusError>> {
self.read_gyro_raw().await
}
pub async fn read_gyro_raw(&mut self) -> Result<(i16, i16, i16), Error<I::BusError>> {
let mut bytes = [0u8; 6];
self.interface
.read_gyro(GyroRegisters::OUT_X_L_G.addr(), &mut bytes)
.await?;
let x = i16::from_le_bytes([bytes[0], bytes[1]]);
let y = i16::from_le_bytes([bytes[2], bytes[3]]);
let z = i16::from_le_bytes([bytes[4], bytes[5]]);
Ok((x, y, z))
}
pub async fn read_gyro(
&mut self,
) -> Result<
(
types::DegreesPerSecond,
types::DegreesPerSecond,
types::DegreesPerSecond,
),
Error<I::BusError>,
> {
let (x, y, z) = self.read_gyro_raw().await?;
let sensitivity = self.config.gyro_sensitivity() / 1000.0;
let (bias_x, bias_y, bias_z) = self.config.gyro_bias;
Ok((
types::DegreesPerSecond::new(x as f32 * sensitivity - bias_x),
types::DegreesPerSecond::new(y as f32 * sensitivity - bias_y),
types::DegreesPerSecond::new(z as f32 * sensitivity - bias_z),
))
}
pub async fn read_accel_fifo_level(&mut self) -> Result<u8, Error<I::BusError>> {
let status = self.read_accel_fifo_status().await?;
Ok(status.fss())
}
pub async fn read_accel_fifo(&mut self) -> Result<(i16, i16, i16), Error<I::BusError>> {
self.read_accel_raw().await
}
pub async fn read_accel_raw(&mut self) -> Result<(i16, i16, i16), Error<I::BusError>> {
let mut bytes = [0u8; 6];
self.interface
.read_xm(AccelMagRegisters::OUT_X_L_A.addr(), &mut bytes)
.await?;
let x = i16::from_le_bytes([bytes[0], bytes[1]]);
let y = i16::from_le_bytes([bytes[2], bytes[3]]);
let z = i16::from_le_bytes([bytes[4], bytes[5]]);
Ok((x, y, z))
}
pub async fn read_accel(
&mut self,
) -> Result<(types::GForce, types::GForce, types::GForce), Error<I::BusError>> {
let (x, y, z) = self.read_accel_raw().await?;
let sensitivity = self.config.accel_sensitivity() / 1000.0;
let (bias_x, bias_y, bias_z) = self.config.accel_bias;
Ok((
types::GForce::new(x as f32 * sensitivity - bias_x),
types::GForce::new(y as f32 * sensitivity - bias_y),
types::GForce::new(z as f32 * sensitivity - bias_z),
))
}
pub async fn read_mag_raw(&mut self) -> Result<(i16, i16, i16), Error<I::BusError>> {
let mut bytes = [0u8; 6];
self.interface
.read_xm(AccelMagRegisters::OUT_X_L_M.addr(), &mut bytes)
.await?;
let x = i16::from_le_bytes([bytes[0], bytes[1]]);
let y = i16::from_le_bytes([bytes[2], bytes[3]]);
let z = i16::from_le_bytes([bytes[4], bytes[5]]);
Ok((x, y, z))
}
pub async fn read_mag(
&mut self,
) -> Result<(types::Gauss, types::Gauss, types::Gauss), Error<I::BusError>> {
let (x, y, z) = self.read_mag_raw().await?;
let sensitivity = self.config.mag_sensitivity() / 1000.0;
Ok((
types::Gauss::new(x as f32 * sensitivity),
types::Gauss::new(y as f32 * sensitivity),
types::Gauss::new(z as f32 * sensitivity),
))
}
pub async fn read_temp(&mut self) -> Result<types::Celsius, Error<I::BusError>> {
let mut bytes = [0u8; 2];
self.interface
.read_xm(AccelMagRegisters::OUT_TEMP_L_XM.addr(), &mut bytes)
.await?;
let raw = i16::from_le_bytes([bytes[0], bytes[1]]);
let result: i16 = (raw << 4) >> 4;
Ok(types::Celsius::new(
(result as f32) / TEMP_SCALE + self.config.temp_offset,
))
}
pub async fn read_all(&mut self) -> Result<types::SensorData, Error<I::BusError>> {
let gyro = self.read_gyro().await?;
let accel = self.read_accel().await?;
let mag = self.read_mag().await?;
let temp = self.read_temp().await?;
Ok(types::SensorData {
gyro,
accel,
mag,
temp,
})
}
pub async fn set_gyro_scale(&mut self, scale: GyroScale) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg4_g.set_fs(scale);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG4_G.addr(),
self.config.ctrl_reg4_g.into(),
)
.await?;
Ok(())
}
pub async fn set_gyro_data_rate(
&mut self,
rate: GyroDataRate,
) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg1_g.set_dr(rate);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG1_G.addr(),
self.config.ctrl_reg1_g.into(),
)
.await?;
Ok(())
}
pub async fn set_gyro_enabled(&mut self, enabled: bool) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg1_g.set_pd(if enabled {
PowerMode::Normal
} else {
PowerMode::PowerDown
});
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG1_G.addr(),
self.config.ctrl_reg1_g.into(),
)
.await?;
Ok(())
}
pub async fn set_gyro_power_mode(
&mut self,
mode: GyroPowerMode,
) -> Result<(), Error<I::BusError>> {
match mode {
GyroPowerMode::PowerDown => {
self.config.ctrl_reg1_g.set_pd(PowerMode::PowerDown);
}
GyroPowerMode::Sleep => {
self.config.ctrl_reg1_g.set_pd(PowerMode::Normal);
self.config.ctrl_reg1_g.set_xen(Enable::Disabled);
self.config.ctrl_reg1_g.set_yen(Enable::Disabled);
self.config.ctrl_reg1_g.set_zen(Enable::Disabled);
}
GyroPowerMode::Normal => {
self.config.ctrl_reg1_g.set_pd(PowerMode::Normal);
let (x, y, z) = self.config.gyro_axes_enabled;
self.config.ctrl_reg1_g.set_xen(Enable::from(x));
self.config.ctrl_reg1_g.set_yen(Enable::from(y));
self.config.ctrl_reg1_g.set_zen(Enable::from(z));
}
}
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG1_G.addr(),
self.config.ctrl_reg1_g.into(),
)
.await?;
Ok(())
}
pub async fn set_gyro_axes(
&mut self,
x: bool,
y: bool,
z: bool,
) -> Result<(), Error<I::BusError>> {
self.config.gyro_axes_enabled = (x, y, z);
self.config.ctrl_reg1_g.set_xen(Enable::from(x));
self.config.ctrl_reg1_g.set_yen(Enable::from(y));
self.config.ctrl_reg1_g.set_zen(Enable::from(z));
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG1_G.addr(),
self.config.ctrl_reg1_g.into(),
)
.await?;
Ok(())
}
pub async fn set_gyro_bandwidth(
&mut self,
bw: GyroBandwidth,
) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg1_g.set_bw(bw);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG1_G.addr(),
self.config.ctrl_reg1_g.into(),
)
.await?;
Ok(())
}
pub async fn set_gyro_reference(&mut self, value: u8) -> Result<(), Error<I::BusError>> {
self.interface
.write_byte_gyro(GyroRegisters::REFERENCE_G.addr(), value)
.await?;
Ok(())
}
pub async fn set_accel_reference(
&mut self,
x: u8,
y: u8,
z: u8,
) -> Result<(), Error<I::BusError>> {
self.interface
.write_xm(AccelMagRegisters::REFERENCE_X.addr(), &[x, y, z])
.await?;
Ok(())
}
pub async fn set_accel_scale(&mut self, scale: AccelScale) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg2_xm.set_afs(scale);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG2_XM.addr(),
self.config.ctrl_reg2_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_accel_data_rate(
&mut self,
rate: AccelDataRate,
) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg1_xm.set_aodr(rate);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG1_XM.addr(),
self.config.ctrl_reg1_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_accel_axes(
&mut self,
x: bool,
y: bool,
z: bool,
) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg1_xm.set_axen(Enable::from(x));
self.config.ctrl_reg1_xm.set_ayen(Enable::from(y));
self.config.ctrl_reg1_xm.set_azen(Enable::from(z));
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG1_XM.addr(),
self.config.ctrl_reg1_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_accel_bandwidth(
&mut self,
bw: AccelBandwidth,
) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg2_xm.set_abw(bw);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG2_XM.addr(),
self.config.ctrl_reg2_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_mag_scale(&mut self, scale: MagScale) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg6_xm.set_mfs(scale);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG6_XM.addr(),
self.config.ctrl_reg6_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_mag_data_rate(&mut self, rate: MagDataRate) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg5_xm.set_m_odr(rate);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG5_XM.addr(),
self.config.ctrl_reg5_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_mag_mode(&mut self, mode: MagMode) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg7_xm.set_md(mode);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG7_XM.addr(),
self.config.ctrl_reg7_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_mag_resolution(
&mut self,
res: MagResolution,
) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg5_xm.set_m_res(res);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG5_XM.addr(),
self.config.ctrl_reg5_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_temperature_enabled(
&mut self,
enabled: bool,
) -> Result<(), Error<I::BusError>> {
self.config.ctrl_reg5_xm.set_temp_en(if enabled {
Enable::Enabled
} else {
Enable::Disabled
});
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG5_XM.addr(),
self.config.ctrl_reg5_xm.into(),
)
.await?;
Ok(())
}
pub async fn set_block_data_update(&mut self, enabled: bool) -> Result<(), Error<I::BusError>> {
let bdu = if enabled {
BlockDataUpdate::WaitForRead
} else {
BlockDataUpdate::Continuous
};
self.config.ctrl_reg4_g.set_bdu(bdu);
self.config.ctrl_reg1_xm.set_bdu(bdu);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG4_G.addr(),
self.config.ctrl_reg4_g.into(),
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG1_XM.addr(),
self.config.ctrl_reg1_xm.into(),
)
.await?;
Ok(())
}
pub fn get_gyro_hpf_cutoff_hz(&self) -> f32 {
self.config.gyro_hpf_cutoff_hz()
}
pub fn get_gyro_lpf_cutoff_hz(&self) -> f32 {
self.config.gyro_lpf_cutoff_hz()
}
pub async fn read_gyro_fifo_status(&mut self) -> Result<FifoSrcRegG, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_gyro(GyroRegisters::FIFO_SRC_REG_G.addr(), &mut data)
.await?;
Ok(FifoSrcRegG::from(data[0]))
}
pub async fn read_accel_fifo_status(&mut self) -> Result<FifoSrcReg, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_xm(AccelMagRegisters::FIFO_SRC_REG.addr(), &mut data)
.await?;
Ok(FifoSrcReg::from(data[0]))
}
pub async fn read_gyro_status(&mut self) -> Result<StatusRegG, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_gyro(GyroRegisters::STATUS_REG_G.addr(), &mut data)
.await?;
Ok(StatusRegG::from(data[0]))
}
pub async fn read_accel_status(&mut self) -> Result<StatusRegA, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_xm(AccelMagRegisters::STATUS_REG_A.addr(), &mut data)
.await?;
Ok(StatusRegA::from(data[0]))
}
pub async fn read_mag_status(&mut self) -> Result<StatusRegM, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_xm(AccelMagRegisters::STATUS_REG_M.addr(), &mut data)
.await?;
Ok(StatusRegM::from(data[0]))
}
pub async fn gyro_data_ready(&mut self) -> Result<bool, Error<I::BusError>> {
let status = self.read_gyro_status().await?;
Ok(status.zyxda())
}
pub async fn accel_data_ready(&mut self) -> Result<bool, Error<I::BusError>> {
let status = self.read_accel_status().await?;
Ok(status.zyxada())
}
pub async fn mag_data_ready(&mut self) -> Result<bool, Error<I::BusError>> {
let status = self.read_mag_status().await?;
Ok(status.zyxmda())
}
pub async fn gyro_data_overrun(&mut self) -> Result<bool, Error<I::BusError>> {
let status = self.read_gyro_status().await?;
Ok(status.zyxor())
}
pub async fn accel_data_overrun(&mut self) -> Result<bool, Error<I::BusError>> {
let status = self.read_accel_status().await?;
Ok(status.zyxaor())
}
pub async fn mag_data_overrun(&mut self) -> Result<bool, Error<I::BusError>> {
let status = self.read_mag_status().await?;
Ok(status.zyxmor())
}
pub async fn read_gyro_interrupt_source(&mut self) -> Result<Int1SrcG, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_gyro(GyroRegisters::INT1_SRC_G.addr(), &mut data)
.await?;
Ok(Int1SrcG::from(data[0]))
}
pub async fn read_accel_int1_source(&mut self) -> Result<IntGenSrc, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_xm(AccelMagRegisters::INT_GEN_1_SRC.addr(), &mut data)
.await?;
Ok(IntGenSrc::from(data[0]))
}
pub async fn read_accel_int2_source(&mut self) -> Result<IntGenSrc, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_xm(AccelMagRegisters::INT_GEN_2_SRC.addr(), &mut data)
.await?;
Ok(IntGenSrc::from(data[0]))
}
pub async fn read_mag_interrupt_source(&mut self) -> Result<IntSrcRegM, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_xm(AccelMagRegisters::INT_SRC_REG_M.addr(), &mut data)
.await?;
Ok(IntSrcRegM::from(data[0]))
}
pub async fn read_click_source(&mut self) -> Result<ClickSrc, Error<I::BusError>> {
let mut data = [0u8];
self.interface
.read_xm(AccelMagRegisters::CLICK_SRC.addr(), &mut data)
.await?;
Ok(ClickSrc::from(data[0]))
}
pub async fn self_test<D: DelayNs>(
&mut self,
delay: &mut D,
) -> Result<types::SelfTestResult, Error<I::BusError>> {
const GYRO_ST_MIN_DPS: f32 = 20.0;
const GYRO_ST_MAX_DPS: f32 = 250.0;
const ACCEL_ST_MIN_MG: f32 = 60.0;
const ACCEL_ST_MAX_MG: f32 = 1700.0;
const NUM_SAMPLES: u32 = 10;
let saved_gyro_scale = self.config.ctrl_reg4_g.fs();
let saved_gyro_st = self.config.ctrl_reg4_g.st();
let saved_accel_scale = self.config.ctrl_reg2_xm.afs();
let saved_accel_st = self.config.ctrl_reg2_xm.ast();
self.config.ctrl_reg4_g.set_fs(GyroScale::Dps245);
self.config.ctrl_reg4_g.set_st(GyroSelfTest::Disabled);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG4_G.addr(),
self.config.ctrl_reg4_g.into(),
)
.await?;
self.config.ctrl_reg2_xm.set_afs(AccelScale::G2);
self.config.ctrl_reg2_xm.set_ast(AccelSelfTest::Normal);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG2_XM.addr(),
self.config.ctrl_reg2_xm.into(),
)
.await?;
delay.delay_ms(100).await;
let _ = self.read_gyro_raw().await?;
let _ = self.read_accel_raw().await?;
let mut gyro_baseline: (i32, i32, i32) = (0, 0, 0);
let mut accel_baseline: (i32, i32, i32) = (0, 0, 0);
for _ in 0..NUM_SAMPLES {
delay.delay_ms(20).await;
let (gx, gy, gz) = self.read_gyro_raw().await?;
gyro_baseline.0 += gx as i32;
gyro_baseline.1 += gy as i32;
gyro_baseline.2 += gz as i32;
let (ax, ay, az) = self.read_accel_raw().await?;
accel_baseline.0 += ax as i32;
accel_baseline.1 += ay as i32;
accel_baseline.2 += az as i32;
}
self.config.ctrl_reg4_g.set_st(GyroSelfTest::Mode0);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG4_G.addr(),
self.config.ctrl_reg4_g.into(),
)
.await?;
self.config
.ctrl_reg2_xm
.set_ast(AccelSelfTest::PositiveSign);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG2_XM.addr(),
self.config.ctrl_reg2_xm.into(),
)
.await?;
delay.delay_ms(100).await;
let _ = self.read_gyro_raw().await?;
let _ = self.read_accel_raw().await?;
let mut gyro_st: (i32, i32, i32) = (0, 0, 0);
let mut accel_st: (i32, i32, i32) = (0, 0, 0);
for _ in 0..NUM_SAMPLES {
delay.delay_ms(20).await;
let (gx, gy, gz) = self.read_gyro_raw().await?;
gyro_st.0 += gx as i32;
gyro_st.1 += gy as i32;
gyro_st.2 += gz as i32;
let (ax, ay, az) = self.read_accel_raw().await?;
accel_st.0 += ax as i32;
accel_st.1 += ay as i32;
accel_st.2 += az as i32;
}
self.config.ctrl_reg4_g.set_fs(saved_gyro_scale);
self.config.ctrl_reg4_g.set_st(saved_gyro_st);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG4_G.addr(),
self.config.ctrl_reg4_g.into(),
)
.await?;
self.config.ctrl_reg2_xm.set_afs(saved_accel_scale);
self.config.ctrl_reg2_xm.set_ast(saved_accel_st);
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG2_XM.addr(),
self.config.ctrl_reg2_xm.into(),
)
.await?;
let n = NUM_SAMPLES as f32;
let gyro_sensitivity_dps = GyroScale::Dps245.sensitivity() / 1000.0;
let gyro_delta = (
((gyro_st.0 as f32 - gyro_baseline.0 as f32) / n * gyro_sensitivity_dps).abs(),
((gyro_st.1 as f32 - gyro_baseline.1 as f32) / n * gyro_sensitivity_dps).abs(),
((gyro_st.2 as f32 - gyro_baseline.2 as f32) / n * gyro_sensitivity_dps).abs(),
);
let accel_sensitivity_mg = AccelScale::G2.sensitivity();
let accel_delta = (
((accel_st.0 as f32 - accel_baseline.0 as f32) / n * accel_sensitivity_mg).abs(),
((accel_st.1 as f32 - accel_baseline.1 as f32) / n * accel_sensitivity_mg).abs(),
((accel_st.2 as f32 - accel_baseline.2 as f32) / n * accel_sensitivity_mg).abs(),
);
let gyro_passed = gyro_delta.0 >= GYRO_ST_MIN_DPS
&& gyro_delta.0 <= GYRO_ST_MAX_DPS
&& gyro_delta.1 >= GYRO_ST_MIN_DPS
&& gyro_delta.1 <= GYRO_ST_MAX_DPS
&& gyro_delta.2 >= GYRO_ST_MIN_DPS
&& gyro_delta.2 <= GYRO_ST_MAX_DPS;
let accel_passed = accel_delta.0 >= ACCEL_ST_MIN_MG
&& accel_delta.0 <= ACCEL_ST_MAX_MG
&& accel_delta.1 >= ACCEL_ST_MIN_MG
&& accel_delta.1 <= ACCEL_ST_MAX_MG
&& accel_delta.2 >= ACCEL_ST_MIN_MG
&& accel_delta.2 <= ACCEL_ST_MAX_MG;
Ok(types::SelfTestResult {
gyro_passed,
gyro_delta,
accel_passed,
accel_delta,
})
}
pub async fn calibrate_bias<D: DelayNs>(
&mut self,
delay: &mut D,
orientation: types::Orientation,
) -> Result<(), Error<I::BusError>> {
let saved_gyro_fifo_en = self.config.ctrl_reg5_g.fifo_en();
let saved_gyro_fifo_mode = self.config.fifo_ctrl_reg_g.fm();
let saved_gyro_fifo_wtm = self.config.fifo_ctrl_reg_g.wtm();
let saved_accel_fifo_en = self.config.ctrl_reg0_xm.fifo_en();
let saved_accel_fifo_mode = self.config.fifo_ctrl_reg.fm();
let saved_accel_fifo_wtm = self.config.fifo_ctrl_reg.fth();
self.config.ctrl_reg5_g.set_fifo_en(Enable::Enabled);
self.config.fifo_ctrl_reg_g.set_wtm(0x1F);
self.config.ctrl_reg0_xm.set_fifo_en(Enable::Enabled);
self.config.fifo_ctrl_reg.set_fth(0x1F);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG5_G.addr(),
self.config.ctrl_reg5_g.into(),
)
.await?;
self.config.fifo_ctrl_reg_g.set_fm(FifoMode::Bypass);
self.interface
.write_byte_gyro(
GyroRegisters::FIFO_CTRL_REG_G.addr(),
self.config.fifo_ctrl_reg_g.into(),
)
.await?;
self.config.fifo_ctrl_reg_g.set_fm(FifoMode::Stream);
self.interface
.write_byte_gyro(
GyroRegisters::FIFO_CTRL_REG_G.addr(),
self.config.fifo_ctrl_reg_g.into(),
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG0_XM.addr(),
self.config.ctrl_reg0_xm.into(),
)
.await?;
self.config.fifo_ctrl_reg.set_fm(FifoMode::Bypass);
self.interface
.write_byte_xm(
AccelMagRegisters::FIFO_CTRL_REG.addr(),
self.config.fifo_ctrl_reg.into(),
)
.await?;
self.config.fifo_ctrl_reg.set_fm(FifoMode::Stream);
self.interface
.write_byte_xm(
AccelMagRegisters::FIFO_CTRL_REG.addr(),
self.config.fifo_ctrl_reg.into(),
)
.await?;
const NUM_FIFO_SAMPLES: f32 = 32.0;
const MARGIN: f32 = 1.1;
const MIN_DELAY_MS: u32 = 10;
let gyro_hz = self.config.ctrl_reg1_g.dr().hz();
let accel_hz = self.config.ctrl_reg1_xm.aodr().hz();
let gyro_fill_ms = NUM_FIFO_SAMPLES * 1000.0 / gyro_hz;
let accel_fill_ms = if accel_hz > 0.0 {
NUM_FIFO_SAMPLES * 1000.0 / accel_hz
} else {
0.0
};
let fill_ms = gyro_fill_ms.max(accel_fill_ms);
let delay_ms = ((fill_ms * MARGIN) as u32).max(MIN_DELAY_MS);
delay.delay_ms(delay_ms).await;
let gyro_samples = self.read_gyro_fifo_level().await?;
let accel_samples = self.read_accel_fifo_level().await?;
let mut gyro_sum: (i32, i32, i32) = (0, 0, 0);
for _ in 0..gyro_samples {
let (x, y, z) = self.read_gyro_fifo().await?;
gyro_sum.0 += x as i32;
gyro_sum.1 += y as i32;
gyro_sum.2 += z as i32;
}
let mut accel_sum: (i32, i32, i32) = (0, 0, 0);
for _ in 0..accel_samples {
let (x, y, z) = self.read_accel_fifo().await?;
accel_sum.0 += x as i32;
accel_sum.1 += y as i32;
accel_sum.2 += z as i32;
}
let gyro_sensitivity = self.config.gyro_sensitivity() / 1000.0;
let gyro_bias = if gyro_samples > 0 {
let n = gyro_samples as f32;
(
(gyro_sum.0 as f32 / n) * gyro_sensitivity,
(gyro_sum.1 as f32 / n) * gyro_sensitivity,
(gyro_sum.2 as f32 / n) * gyro_sensitivity,
)
} else {
(0.0, 0.0, 0.0)
};
let accel_sensitivity = self.config.accel_sensitivity() / 1000.0;
let (grav_x, grav_y, grav_z) = orientation.gravity_vector();
let accel_bias = if accel_samples > 0 {
let n = accel_samples as f32;
(
(accel_sum.0 as f32 / n) * accel_sensitivity - grav_x,
(accel_sum.1 as f32 / n) * accel_sensitivity - grav_y,
(accel_sum.2 as f32 / n) * accel_sensitivity - grav_z,
)
} else {
(0.0, 0.0, 0.0)
};
self.config.gyro_bias = gyro_bias;
self.config.accel_bias = accel_bias;
self.config.ctrl_reg5_g.set_fifo_en(saved_gyro_fifo_en);
self.config.fifo_ctrl_reg_g.set_fm(saved_gyro_fifo_mode);
self.config.fifo_ctrl_reg_g.set_wtm(saved_gyro_fifo_wtm);
self.config.ctrl_reg0_xm.set_fifo_en(saved_accel_fifo_en);
self.config.fifo_ctrl_reg.set_fm(saved_accel_fifo_mode);
self.config.fifo_ctrl_reg.set_fth(saved_accel_fifo_wtm);
self.interface
.write_byte_gyro(
GyroRegisters::CTRL_REG5_G.addr(),
self.config.ctrl_reg5_g.into(),
)
.await?;
self.interface
.write_byte_gyro(
GyroRegisters::FIFO_CTRL_REG_G.addr(),
self.config.fifo_ctrl_reg_g.into(),
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::CTRL_REG0_XM.addr(),
self.config.ctrl_reg0_xm.into(),
)
.await?;
self.interface
.write_byte_xm(
AccelMagRegisters::FIFO_CTRL_REG.addr(),
self.config.fifo_ctrl_reg.into(),
)
.await?;
Ok(())
}
pub fn gyro_bias(&self) -> (f32, f32, f32) {
self.config.gyro_bias
}
pub fn accel_bias(&self) -> (f32, f32, f32) {
self.config.accel_bias
}
pub fn set_gyro_bias(&mut self, x: f32, y: f32, z: f32) {
self.config.gyro_bias = (x, y, z);
}
pub fn set_accel_bias(&mut self, x: f32, y: f32, z: f32) {
self.config.accel_bias = (x, y, z);
}
pub fn release(self) -> I {
self.interface
}
}
#[cfg(test)]
mod tests;