#[cfg(feature = "async")]
use embedded_hal_async::delay::DelayNs;
#[cfg(not(feature = "async"))]
use embedded_hal::delay::DelayNs;
use crate::{Error, Ready, Uninitialized, ICM42688};
pub enum InterruptMode {
Pulsed,
Latched,
}
pub enum InterruptPolarity {
ActiveHigh,
ActiveLow,
}
#[derive(Copy, Clone)]
pub enum OutputDataRate {
Hz32000,
Hz16000,
Hz8000,
Hz4000,
Hz2000,
Hz1000,
Hz500,
Hz200,
Hz100,
Hz50,
Hz25,
Hz12_5,
}
struct AafConfig {
delt: u8,
delt_sqr: u16,
bitshift: u8,
}
pub struct Config {
pub int1_mode: InterruptMode,
pub int1_polarity: InterruptPolarity,
pub rate: OutputDataRate,
pub timestamps_are_absolute: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
int1_mode: InterruptMode::Latched,
int1_polarity: InterruptPolarity::ActiveHigh,
rate: OutputDataRate::Hz200,
timestamps_are_absolute: false,
}
}
}
impl<SPI> ICM42688<SPI, Uninitialized> {
pub fn new(spi: SPI) -> Self {
ICM42688 {
ll: crate::ll::ICM42688::new(spi),
_state: Uninitialized,
}
}
fn int_config_bits(config: &Config) -> (u8, u8) {
let mode = match config.int1_mode {
InterruptMode::Pulsed => 0,
InterruptMode::Latched => 1,
};
let polarity = match config.int1_polarity {
InterruptPolarity::ActiveHigh => 1,
InterruptPolarity::ActiveLow => 0,
};
(mode, polarity)
}
fn gyro_accel_odr(odr: OutputDataRate) -> u8 {
match odr {
OutputDataRate::Hz32000 => 0b0001,
OutputDataRate::Hz16000 => 0b0010,
OutputDataRate::Hz8000 => 0b0011,
OutputDataRate::Hz4000 => 0b0100,
OutputDataRate::Hz2000 => 0b0101,
OutputDataRate::Hz1000 => 0b0110,
OutputDataRate::Hz500 => 0b1111,
OutputDataRate::Hz200 => 0b0111,
OutputDataRate::Hz100 => 0b1000,
OutputDataRate::Hz50 => 0b1001,
OutputDataRate::Hz25 => 0b1010,
OutputDataRate::Hz12_5 => 0b1011,
}
}
fn get_aaf_config(odr: OutputDataRate) -> AafConfig {
let create_config = |delt: u8, delt_sqr: u16, bitshift: u8| -> AafConfig {
AafConfig {
delt,
delt_sqr,
bitshift,
}
};
match odr {
OutputDataRate::Hz32000 | OutputDataRate::Hz16000 | OutputDataRate::Hz8000 => {
create_config(63, 3968, 3)
}
OutputDataRate::Hz4000 => create_config(37, 1376, 4),
OutputDataRate::Hz2000 => create_config(21, 440, 6),
OutputDataRate::Hz1000 => create_config(11, 122, 8),
OutputDataRate::Hz500 => create_config(5, 25, 10),
OutputDataRate::Hz200 => create_config(2, 4, 13),
OutputDataRate::Hz100
| OutputDataRate::Hz50
| OutputDataRate::Hz25
| OutputDataRate::Hz12_5 => create_config(1, 1, 15),
}
}
#[cfg(feature = "async")]
pub async fn initialize(
mut self,
mut delay: impl DelayNs,
config: Config,
) -> Result<ICM42688<SPI, Ready>, Error<SPI::Error>>
where
SPI: embedded_hal_async::spi::SpiDevice,
{
use crate::Ready;
let mut bank0 = self.ll.bank::<0>();
bank0
.device_config()
.async_modify(|_, w| w.soft_reset_config(1))
.await?;
delay.delay_ms(1).await;
let who_am_i = bank0.who_am_i().async_read().await?.value();
if who_am_i != 0x47 {
return Err(Error::WhoAmIMismatch(who_am_i));
}
let (int1_mode, int1_polarity) = Self::int_config_bits(&config);
bank0
.int_config()
.async_modify(|_, w| {
w.int1_drive_circuit(1)
.int1_mode(int1_mode)
.int1_polarity(int1_polarity)
})
.await?;
bank0
.fifo_config()
.async_modify(|_, w| w.fifo_mode(11))
.await?;
bank0
.intf_config0()
.async_modify(|_, w| w.fifo_count_endian(1).sensor_data_endian(1).ui_sifs_cfg(11))
.await?;
bank0
.intf_config1()
.async_modify(|_, w| w.afsr(0b01))
.await?;
let odr = Self::gyro_accel_odr(config.rate);
bank0
.gyro_config0()
.async_modify(|_, w| w.gyro_fs_sel(0b000).gyro_odr(odr))
.await?;
bank0
.accel_config0()
.async_modify(|_, w| w.accel_fs_sel(0b000).accel_odr(odr))
.await?;
bank0
.gyro_config1()
.async_modify(|_, w| w.gyro_ui_filt_ord(0b0))
.await?;
bank0
.gyro_accel_config0()
.async_modify(|_, w| w.accel_ui_filt_bw(0b00).gyro_ui_filt_bw(0b00))
.await?;
bank0
.accel_config1()
.async_modify(|_, w| w.accel_ui_filt_ord(0b0))
.await?;
bank0
.tmst_config()
.async_modify(|_, w| {
w.tmst_en(1)
.tmst_delta_en((!config.timestamps_are_absolute) as u8)
.tmst_to_regs_en(1)
.tmst_res(1)
.tmst_fsync_en(0)
})
.await?;
bank0
.fifo_config1()
.async_modify(|_, w| {
w.fifo_wm_gt_th(1)
.fifo_hires_en(1)
.fifo_temp_en(1)
.fifo_gyro_en(1)
.fifo_accel_en(1)
.fifo_tmst_fsync_en(0)
})
.await?;
bank0
.fifo_config2()
.async_modify(|_, w| w.fifo_wm_7_0(20))
.await?;
bank0
.fifo_config3()
.async_modify(|_, w| w.fifo_wm_11_8(0))
.await?;
bank0
.int_config0()
.async_modify(|_, w| w.fifo_ths_int_clear(0b10))
.await?;
bank0
.int_config1()
.async_modify(|_, w| w.int_async_reset(0))
.await?;
bank0
.int_source0()
.async_modify(|_, w| w.fifo_ths_int1_en(1))
.await?;
let aaf = Self::get_aaf_config(config.rate);
bank0.reg_bank_sel().async_write(|r| r.bank_sel(1)).await?;
self.ll.set_bank(1);
let mut bank1 = self.ll.bank::<1>();
bank1
.gyro_config_static2()
.async_modify(|_, w| w.gyro_nf_dis(0).gyro_aaf_dis(0))
.await?;
bank1
.gyro_config_static3()
.async_modify(|_, w| w.gyro_aaf_delt(aaf.delt))
.await?;
bank1
.gyro_config_static4()
.async_modify(|_, w| w.gyro_aaf_deltsqr_7_0(aaf.delt_sqr as u8))
.await?;
bank1
.gyro_config_static5()
.async_modify(|_, w| {
w.gyro_aaf_deltsqr_11_8((aaf.delt_sqr >> 8) as u8)
.gyro_aaf_bitshift(aaf.bitshift)
})
.await?;
bank1
.intf_config5()
.async_modify(|_, w| w.pin9_function(0b00)) .await?;
bank1.reg_bank_sel().async_write(|r| r.bank_sel(2)).await?;
self.ll.set_bank(2);
let mut bank2 = self.ll.bank::<2>();
bank2
.accel_config_static2()
.async_modify(|_, w| w.accel_aaf_dis(0).accel_aaf_delt(aaf.delt))
.await?;
bank2
.accel_config_static3()
.async_modify(|_, w| w.accel_aaf_deltsqr_7_0(aaf.delt_sqr as u8))
.await?;
bank2
.accel_config_static4()
.async_modify(|_, w| {
w.accel_aaf_deltsqr_11_8((aaf.delt_sqr >> 8) as u8)
.accel_aaf_bitshift(aaf.bitshift)
})
.await?;
bank2.reg_bank_sel().async_write(|r| r.bank_sel(0)).await?;
self.ll.set_bank(0);
self.ll
.bank::<0>()
.pwr_mgmt0()
.async_modify(|_, w| w.gyro_mode(0b11).accel_mode(0b11).temp_dis(0))
.await?;
delay.delay_us(200).await;
Ok(ICM42688 {
ll: self.ll,
_state: Ready,
})
}
#[cfg(not(feature = "async"))]
pub fn initialize(
mut self,
mut delay: impl DelayNs,
config: Config,
) -> Result<ICM42688<SPI, Ready>, Error<SPI::Error>>
where
SPI: embedded_hal::spi::SpiDevice,
{
use crate::Ready;
let mut bank0 = self.ll.bank::<0>();
bank0
.device_config()
.modify(|_, w| w.soft_reset_config(1))?;
delay.delay_ms(1);
let who_am_i = bank0.who_am_i().read()?.value();
if who_am_i != 0x47 {
return Err(Error::WhoAmIMismatch(who_am_i));
}
let (int1_mode, int1_polarity) = Self::int_config_bits(&config);
bank0.int_config().modify(|_, w| {
w.int1_drive_circuit(1)
.int1_polarity(int1_polarity)
.int1_mode(int1_mode)
})?;
bank0.fifo_config().modify(|_, w| w.fifo_mode(11))?;
bank0
.intf_config0()
.modify(|_, w| w.fifo_count_endian(1).sensor_data_endian(1).ui_sifs_cfg(11))?;
bank0.intf_config1().modify(|_, w| w.afsr(0b01))?;
let odr = Self::gyro_accel_odr(config.rate);
bank0
.gyro_config0()
.modify(|_, w| w.gyro_fs_sel(0b000).gyro_odr(odr))?;
bank0
.accel_config0()
.modify(|_, w| w.accel_fs_sel(0b000).accel_odr(odr))?;
bank0
.gyro_config1()
.modify(|_, w| w.gyro_ui_filt_ord(0b0))?;
bank0
.gyro_accel_config0()
.modify(|_, w| w.accel_ui_filt_bw(0b00).gyro_ui_filt_bw(0b00))?;
bank0
.accel_config1()
.modify(|_, w| w.accel_ui_filt_ord(0b0))?;
bank0.tmst_config().modify(|_, w| {
w.tmst_en(1)
.tmst_delta_en((!config.timestamps_are_absolute) as u8)
.tmst_to_regs_en(1)
.tmst_res(1)
.tmst_fsync_en(0)
})?;
bank0.fifo_config1().modify(|_, w| {
w.fifo_wm_gt_th(1)
.fifo_hires_en(1)
.fifo_temp_en(1)
.fifo_gyro_en(1)
.fifo_accel_en(1)
.fifo_tmst_fsync_en(0)
})?;
bank0.fifo_config2().modify(|_, w| w.fifo_wm_7_0(20))?;
bank0.fifo_config3().modify(|_, w| w.fifo_wm_11_8(0))?;
bank0
.int_config0()
.modify(|_, w| w.fifo_ths_int_clear(0b10))?;
bank0.int_config1().modify(|_, w| w.int_async_reset(0))?;
bank0.int_source0().modify(|_, w| w.fifo_ths_int1_en(1))?;
let aaf = Self::get_aaf_config(config.rate);
bank0.reg_bank_sel().write(|r| r.bank_sel(1))?;
self.ll.set_bank(1);
let mut bank1 = self.ll.bank::<1>();
bank1
.gyro_config_static2()
.modify(|_, w| w.gyro_nf_dis(0).gyro_aaf_dis(0))?;
bank1
.gyro_config_static3()
.modify(|_, w| w.gyro_aaf_delt(aaf.delt))?;
bank1
.gyro_config_static4()
.modify(|_, w| w.gyro_aaf_deltsqr_7_0(aaf.delt_sqr as u8))?;
bank1.gyro_config_static5().modify(|_, w| {
w.gyro_aaf_deltsqr_11_8((aaf.delt_sqr >> 8) as u8)
.gyro_aaf_bitshift(aaf.bitshift)
})?;
bank1.intf_config5().modify(|_, w| w.pin9_function(0b00))?;
bank1.reg_bank_sel().write(|r| r.bank_sel(2))?;
self.ll.set_bank(2);
let mut bank2 = self.ll.bank::<2>();
bank2
.accel_config_static2()
.modify(|_, w| w.accel_aaf_dis(0).accel_aaf_delt(aaf.delt))?;
bank2
.accel_config_static3()
.modify(|_, w| w.accel_aaf_deltsqr_7_0(aaf.delt_sqr as u8))?;
bank2.accel_config_static4().modify(|_, w| {
w.accel_aaf_deltsqr_11_8((aaf.delt_sqr >> 8) as u8)
.accel_aaf_bitshift(aaf.bitshift)
})?;
bank2.reg_bank_sel().write(|r| r.bank_sel(0))?;
self.ll.set_bank(0);
self.ll
.bank::<0>()
.pwr_mgmt0()
.modify(|_, w| w.gyro_mode(0b11).accel_mode(0b11).temp_dis(0))?;
delay.delay_us(200);
Ok(ICM42688 {
ll: self.ll,
_state: Ready,
})
}
pub fn ll(&mut self) -> &mut crate::ll::ICM42688<SPI> {
&mut self.ll
}
}