#![no_std]
use core::fmt::Debug;
pub use accelerometer;
use accelerometer::{
error::Error as AccelerometerError,
vector::{F32x3, I16x3},
Accelerometer,
RawAccelerometer,
};
use embedded_hal::blocking::{
delay::DelayUs,
i2c::{Write, WriteRead},
};
use crate::{
config::Bitfield,
error::SensorError,
register::{Bank0, Register, RegisterBank},
};
pub use crate::{
config::{AccelOdr, AccelRange, Address, GyroOdr, GyroRange, PowerMode},
error::Error,
};
mod config;
mod error;
mod register;
pub mod prelude {
pub use accelerometer::{
Accelerometer as _accelerometer_Accelerometer,
RawAccelerometer as _accelerometer_RawAccelerometer,
};
}
#[derive(Debug, Clone, Copy)]
pub struct Icm42670<I2C> {
i2c: I2C,
address: Address,
}
impl<I2C, E> Icm42670<I2C>
where
I2C: Write<Error = E> + WriteRead<Error = E>,
E: Debug,
{
pub const DEVICE_IDS: [u8; 2] = [
0x60, 0x67, ];
pub fn new(i2c: I2C, address: Address) -> Result<Self, Error<E>> {
let mut me = Self { i2c, address };
if !Self::DEVICE_IDS.contains(&me.device_id()?) {
return Err(Error::SensorError(SensorError::BadChip));
}
me.set_accel_range(AccelRange::default())?;
me.set_gyro_range(GyroRange::default())?;
me.set_power_mode(PowerMode::SixAxisLowNoise)?;
Ok(me)
}
pub fn free(self) -> I2C {
self.i2c
}
pub fn device_id(&mut self) -> Result<u8, Error<E>> {
self.read_reg(&Bank0::WHO_AM_I)
}
pub fn soft_reset(&mut self) -> Result<(), Error<E>> {
self.update_reg(&Bank0::SIGNAL_PATH_RESET, 0x10, 0b0001_0000)
}
pub fn gyro_norm(&mut self) -> Result<F32x3, Error<E>> {
let range = self.gyro_range()?;
let scale = range.scale_factor();
let raw = self.gyro_raw()?;
let x = raw.x as f32 / scale;
let y = raw.y as f32 / scale;
let z = raw.z as f32 / scale;
Ok(F32x3::new(x, y, z))
}
pub fn gyro_raw(&mut self) -> Result<I16x3, Error<E>> {
let x = self.read_reg_i16(&Bank0::GYRO_DATA_X1, &Bank0::GYRO_DATA_X0)?;
let y = self.read_reg_i16(&Bank0::GYRO_DATA_Y1, &Bank0::GYRO_DATA_Y0)?;
let z = self.read_reg_i16(&Bank0::GYRO_DATA_Z1, &Bank0::GYRO_DATA_Z0)?;
Ok(I16x3::new(x, y, z))
}
pub fn temperature(&mut self) -> Result<f32, Error<E>> {
let raw = self.temperature_raw()? as f32;
let deg = (raw / 128.0) + 25.0;
Ok(deg)
}
pub fn temperature_raw(&mut self) -> Result<i16, Error<E>> {
self.read_reg_i16(&Bank0::TEMP_DATA1, &Bank0::TEMP_DATA0)
}
pub fn power_mode(&mut self) -> Result<PowerMode, Error<E>> {
let bits = self.read_reg(&Bank0::PWR_MGMT0)? & 0xF;
let mode = PowerMode::try_from(bits)?;
Ok(mode)
}
pub fn set_power_mode(&mut self, mode: PowerMode) -> Result<(), Error<E>> {
self.update_reg(&Bank0::PWR_MGMT0, mode.bits(), PowerMode::BITMASK)
}
pub fn accel_range(&mut self) -> Result<AccelRange, Error<E>> {
let fs_sel = self.read_reg(&Bank0::ACCEL_CONFIG0)? >> 5;
let range = AccelRange::try_from(fs_sel)?;
Ok(range)
}
pub fn set_accel_range(&mut self, range: AccelRange) -> Result<(), Error<E>> {
self.update_reg(&Bank0::ACCEL_CONFIG0, range.bits(), AccelRange::BITMASK)
}
pub fn gyro_range(&mut self) -> Result<GyroRange, Error<E>> {
let fs_sel = self.read_reg(&Bank0::GYRO_CONFIG0)? >> 5;
let range = GyroRange::try_from(fs_sel)?;
Ok(range)
}
pub fn set_gyro_range(&mut self, range: GyroRange) -> Result<(), Error<E>> {
self.update_reg(&Bank0::GYRO_CONFIG0, range.bits(), GyroRange::BITMASK)
}
pub fn accel_odr(&mut self) -> Result<AccelOdr, Error<E>> {
let odr = self.read_reg(&Bank0::ACCEL_CONFIG0)? & 0xF;
let odr = AccelOdr::try_from(odr)?;
Ok(odr)
}
pub fn set_accel_odr(&mut self, odr: AccelOdr) -> Result<(), Error<E>> {
self.update_reg(&Bank0::ACCEL_CONFIG0, odr.bits(), AccelOdr::BITMASK)
}
pub fn gyro_odr(&mut self) -> Result<GyroOdr, Error<E>> {
let odr = self.read_reg(&Bank0::GYRO_CONFIG0)? & 0xF;
let odr = GyroOdr::try_from(odr)?;
Ok(odr)
}
pub fn set_gyro_odr(&mut self, odr: GyroOdr) -> Result<(), Error<E>> {
self.update_reg(&Bank0::GYRO_CONFIG0, odr.bits(), GyroOdr::BITMASK)
}
#[allow(unused)]
fn read_mreg(
&mut self,
delay: &mut dyn DelayUs<u8>,
bank: RegisterBank,
reg: &dyn Register,
) -> Result<u8, Error<E>> {
while self.read_reg(&Bank0::MCLK_RDY)? != 0x1 {}
self.write_reg(&Bank0::BLK_SEL_R, bank.blk_sel())?;
self.write_reg(&Bank0::MADDR_R, reg.addr())?;
delay.delay_us(10);
let result = self.read_reg(&Bank0::M_R)?;
delay.delay_us(10);
self.write_reg(&Bank0::BLK_SEL_R, 0x00)?;
self.write_reg(&Bank0::BLK_SEL_W, 0x00)?;
Ok(result)
}
#[allow(unused)]
fn write_mreg(
&mut self,
delay: &mut dyn DelayUs<u8>,
bank: RegisterBank,
reg: &dyn Register,
value: u8,
) -> Result<(), Error<E>> {
while self.read_reg(&Bank0::MCLK_RDY)? != 0x1 {}
self.write_reg(&Bank0::BLK_SEL_W, bank.blk_sel())?;
self.write_reg(&Bank0::MADDR_W, reg.addr())?;
self.write_reg(&Bank0::M_W, value)?;
delay.delay_us(10);
self.write_reg(&Bank0::BLK_SEL_R, 0x00)?;
self.write_reg(&Bank0::BLK_SEL_W, 0x00)?;
Ok(())
}
fn read_reg(&mut self, reg: &dyn Register) -> Result<u8, Error<E>> {
let mut buffer = [0u8];
self.i2c
.write_read(self.address as u8, &[reg.addr()], &mut buffer)
.map_err(|e| Error::BusError(e))?;
Ok(buffer[0])
}
fn read_reg_i16(
&mut self,
reg_hi: &dyn Register,
reg_lo: &dyn Register,
) -> Result<i16, Error<E>> {
let data_hi = self.read_reg(reg_hi)?;
let data_lo = self.read_reg(reg_lo)?;
let data = i16::from_be_bytes([data_hi, data_lo]);
Ok(data)
}
fn write_reg(&mut self, reg: &dyn Register, value: u8) -> Result<(), Error<E>> {
if reg.read_only() {
Err(Error::SensorError(SensorError::WriteToReadOnly))
} else {
self.i2c
.write(self.address as u8, &[reg.addr(), value])
.map_err(|e| Error::BusError(e))
}
}
fn update_reg(&mut self, reg: &dyn Register, value: u8, mask: u8) -> Result<(), Error<E>> {
if reg.read_only() {
Err(Error::SensorError(SensorError::WriteToReadOnly))
} else {
let current = self.read_reg(reg)?;
let value = (current & !mask) | (value & mask);
self.write_reg(reg, value)
}
}
}
impl<I2C, E> Accelerometer for Icm42670<I2C>
where
I2C: Write<Error = E> + WriteRead<Error = E>,
E: Debug,
{
type Error = Error<E>;
fn accel_norm(&mut self) -> Result<F32x3, AccelerometerError<Self::Error>> {
let range = self.accel_range()?;
let scale = range.scale_factor();
let raw = self.accel_raw()?;
let x = raw.x as f32 / scale;
let y = raw.y as f32 / scale;
let z = raw.z as f32 / scale;
Ok(F32x3::new(x, y, z))
}
fn sample_rate(&mut self) -> Result<f32, AccelerometerError<Self::Error>> {
let odr = self.accel_odr()?;
let rate = odr.as_f32();
Ok(rate)
}
}
impl<I2C, E> RawAccelerometer<I16x3> for Icm42670<I2C>
where
I2C: Write<Error = E> + WriteRead<Error = E>,
E: Debug,
{
type Error = Error<E>;
fn accel_raw(&mut self) -> Result<I16x3, AccelerometerError<Self::Error>> {
let x = self.read_reg_i16(&Bank0::ACCEL_DATA_X1, &Bank0::ACCEL_DATA_X0)?;
let y = self.read_reg_i16(&Bank0::ACCEL_DATA_Y1, &Bank0::ACCEL_DATA_Y0)?;
let z = self.read_reg_i16(&Bank0::ACCEL_DATA_Z1, &Bank0::ACCEL_DATA_Z0)?;
Ok(I16x3::new(x, y, z))
}
}