icm20602 allow skipping full reset and configure if already configured

This commit is contained in:
Daniel Agar
2021-11-12 13:37:33 -05:00
parent 17ad7071c3
commit 03ccef180d
3 changed files with 85 additions and 98 deletions
@@ -47,6 +47,11 @@ ICM20602::ICM20602(const I2CSPIDriverConfig &config) :
_px4_accel(get_device_id(), config.rotation), _px4_accel(get_device_id(), config.rotation),
_px4_gyro(get_device_id(), config.rotation) _px4_gyro(get_device_id(), config.rotation)
{ {
_px4_accel.set_scale(CONSTANTS_ONE_G / 2048.f);
_px4_accel.set_range(16.f * CONSTANTS_ONE_G);
_px4_gyro.set_scale(math::radians(2000.f / 32768.f));
_px4_gyro.set_range(math::radians(2000.f));
if (_drdy_gpio != 0) { if (_drdy_gpio != 0) {
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed"); _drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
} }
@@ -56,6 +61,7 @@ ICM20602::ICM20602(const I2CSPIDriverConfig &config) :
ICM20602::~ICM20602() ICM20602::~ICM20602()
{ {
perf_free(_configure_perf);
perf_free(_bad_register_perf); perf_free(_bad_register_perf);
perf_free(_bad_transfer_perf); perf_free(_bad_transfer_perf);
perf_free(_fifo_empty_perf); perf_free(_fifo_empty_perf);
@@ -73,7 +79,21 @@ int ICM20602::init()
return ret; return ret;
} }
return Reset() ? 0 : -1; _state = STATE::CHECK_CONFIGURATION;
ScheduleNow();
return 0;
}
int ICM20602::probe()
{
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
if (whoami != WHOAMI) {
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
return PX4_ERROR;
}
return PX4_OK;
} }
bool ICM20602::Reset() bool ICM20602::Reset()
@@ -97,6 +117,7 @@ void ICM20602::print_status()
PX4_INFO("FIFO empty interval: %d us (%.1f Hz)", _fifo_empty_interval_us, 1e6 / _fifo_empty_interval_us); PX4_INFO("FIFO empty interval: %d us (%.1f Hz)", _fifo_empty_interval_us, 1e6 / _fifo_empty_interval_us);
perf_print_counter(_configure_perf);
perf_print_counter(_bad_register_perf); perf_print_counter(_bad_register_perf);
perf_print_counter(_bad_transfer_perf); perf_print_counter(_bad_transfer_perf);
perf_print_counter(_fifo_empty_perf); perf_print_counter(_fifo_empty_perf);
@@ -129,18 +150,6 @@ bool ICM20602::StoreCheckedRegisterValue(Register reg)
return false; return false;
} }
int ICM20602::probe()
{
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
if (whoami != WHOAMI) {
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
return PX4_ERROR;
}
return PX4_OK;
}
void ICM20602::RunImpl() void ICM20602::RunImpl()
{ {
const hrt_abstime now = hrt_absolute_time(); const hrt_abstime now = hrt_absolute_time();
@@ -163,21 +172,6 @@ void ICM20602::RunImpl()
&& (RegisterRead(Register::PWR_MGMT_1) == 0x41) && (RegisterRead(Register::PWR_MGMT_1) == 0x41)
&& (RegisterRead(Register::CONFIG) == 0x80)) { && (RegisterRead(Register::CONFIG) == 0x80)) {
// offset registers (factory calibration) should not change during normal operation
StoreCheckedRegisterValue(Register::XG_OFFS_TC_H);
StoreCheckedRegisterValue(Register::XG_OFFS_TC_L);
StoreCheckedRegisterValue(Register::YG_OFFS_TC_H);
StoreCheckedRegisterValue(Register::YG_OFFS_TC_L);
StoreCheckedRegisterValue(Register::ZG_OFFS_TC_H);
StoreCheckedRegisterValue(Register::ZG_OFFS_TC_L);
StoreCheckedRegisterValue(Register::XA_OFFSET_H);
StoreCheckedRegisterValue(Register::XA_OFFSET_L);
StoreCheckedRegisterValue(Register::YA_OFFSET_H);
StoreCheckedRegisterValue(Register::YA_OFFSET_L);
StoreCheckedRegisterValue(Register::ZA_OFFSET_H);
StoreCheckedRegisterValue(Register::ZA_OFFSET_L);
// Disable I2C, wakeup, and reset digital signal path // Disable I2C, wakeup, and reset digital signal path
RegisterWrite(Register::I2C_IF, I2C_IF_BIT::I2C_IF_DIS); // set immediately to prevent switching into I2C mode RegisterWrite(Register::I2C_IF, I2C_IF_BIT::I2C_IF_DIS); // set immediately to prevent switching into I2C mode
RegisterWrite(Register::PWR_MGMT_1, PWR_MGMT_1_BIT::CLKSEL_0); RegisterWrite(Register::PWR_MGMT_1, PWR_MGMT_1_BIT::CLKSEL_0);
@@ -206,6 +200,27 @@ void ICM20602::RunImpl()
case STATE::CONFIGURE: case STATE::CONFIGURE:
if (Configure()) { if (Configure()) {
// if configure succeeded then start reading from FIFO // if configure succeeded then start reading from FIFO
_state = STATE::CHECK_CONFIGURATION;
ScheduleDelayed(10_ms);
} else {
// CONFIGURE not complete
if (hrt_elapsed_time(&_reset_timestamp) > 1000_ms) {
PX4_DEBUG("Configure failed, resetting");
_state = STATE::RESET;
} else {
PX4_DEBUG("Configure failed, retrying");
}
ScheduleDelayed(10_ms);
}
break;
case STATE::CHECK_CONFIGURATION:
if (CheckConfiguration()) {
// if configuration is correct then start reading from FIFO
_state = STATE::FIFO_READ; _state = STATE::FIFO_READ;
if (DataReadyInterruptConfigure()) { if (DataReadyInterruptConfigure()) {
@@ -222,16 +237,9 @@ void ICM20602::RunImpl()
FIFOReset(); FIFOReset();
} else { } else {
// CONFIGURE not complete // not fully configured, try again
if (hrt_elapsed_time(&_reset_timestamp) > 1000_ms) { _state = STATE::CONFIGURE;
PX4_DEBUG("Configure failed, resetting"); ScheduleDelayed(10_ms);
_state = STATE::RESET;
} else {
PX4_DEBUG("Configure failed, retrying");
}
ScheduleDelayed(100_ms);
} }
break; break;
@@ -333,59 +341,22 @@ void ICM20602::RunImpl()
} }
} }
void ICM20602::ConfigureAccel() void ICM20602::RecordSensorOffsets()
{ {
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::ACCEL_CONFIG) & (Bit4 | Bit3); // [4:3] ACCEL_FS_SEL[1:0] // offset registers (factory calibration) should not change during normal operation
StoreCheckedRegisterValue(Register::XG_OFFS_TC_H);
StoreCheckedRegisterValue(Register::XG_OFFS_TC_L);
StoreCheckedRegisterValue(Register::YG_OFFS_TC_H);
StoreCheckedRegisterValue(Register::YG_OFFS_TC_L);
StoreCheckedRegisterValue(Register::ZG_OFFS_TC_H);
StoreCheckedRegisterValue(Register::ZG_OFFS_TC_L);
switch (ACCEL_FS_SEL) { StoreCheckedRegisterValue(Register::XA_OFFSET_H);
case ACCEL_FS_SEL_2G: StoreCheckedRegisterValue(Register::XA_OFFSET_L);
_px4_accel.set_scale(CONSTANTS_ONE_G / 16384.f); StoreCheckedRegisterValue(Register::YA_OFFSET_H);
_px4_accel.set_range(2.f * CONSTANTS_ONE_G); StoreCheckedRegisterValue(Register::YA_OFFSET_L);
break; StoreCheckedRegisterValue(Register::ZA_OFFSET_H);
StoreCheckedRegisterValue(Register::ZA_OFFSET_L);
case ACCEL_FS_SEL_4G:
_px4_accel.set_scale(CONSTANTS_ONE_G / 8192.f);
_px4_accel.set_range(4.f * CONSTANTS_ONE_G);
break;
case ACCEL_FS_SEL_8G:
_px4_accel.set_scale(CONSTANTS_ONE_G / 4096.f);
_px4_accel.set_range(8.f * CONSTANTS_ONE_G);
break;
case ACCEL_FS_SEL_16G:
_px4_accel.set_scale(CONSTANTS_ONE_G / 2048.f);
_px4_accel.set_range(16.f * CONSTANTS_ONE_G);
break;
}
}
void ICM20602::ConfigureGyro()
{
const uint8_t FS_SEL = RegisterRead(Register::GYRO_CONFIG) & (Bit4 | Bit3); // [4:3] FS_SEL[1:0]
float range_dps = 0.f;
switch (FS_SEL) {
case FS_SEL_250_DPS:
range_dps = 250.f;
break;
case FS_SEL_500_DPS:
range_dps = 500.f;
break;
case FS_SEL_1000_DPS:
range_dps = 1000.f;
break;
case FS_SEL_2000_DPS:
range_dps = 2000.f;
break;
}
_px4_gyro.set_scale(math::radians(range_dps / 32768.f));
_px4_gyro.set_range(math::radians(range_dps));
} }
void ICM20602::ConfigureSampleRate(int sample_rate) void ICM20602::ConfigureSampleRate(int sample_rate)
@@ -422,11 +393,11 @@ void ICM20602::ConfigureFIFOWatermark(uint8_t samples)
} }
} }
bool ICM20602::Configure() bool ICM20602::CheckConfiguration()
{ {
// first set and clear all configured register bits // store sensor's offsets if we've never run before
for (const auto &reg_cfg : _register_cfg) { if (_reset_timestamp == 0) {
RegisterSetAndClearBits(reg_cfg.reg, reg_cfg.set_bits, reg_cfg.clear_bits); RecordSensorOffsets();
} }
// now check that all are configured // now check that all are configured
@@ -438,12 +409,24 @@ bool ICM20602::Configure()
} }
} }
ConfigureAccel();
ConfigureGyro();
return success; return success;
} }
bool ICM20602::Configure()
{
perf_count(_configure_perf);
// first set and clear all configured register bits
for (const auto &reg_cfg : _register_cfg) {
RegisterSetAndClearBits(reg_cfg.reg, reg_cfg.set_bits, reg_cfg.clear_bits);
}
// store sensor side offsets for runtime verification
RecordSensorOffsets();
return CheckConfiguration();
}
int ICM20602::DataReadyInterruptCallback(int irq, void *context, void *arg) int ICM20602::DataReadyInterruptCallback(int irq, void *context, void *arg)
{ {
static_cast<ICM20602 *>(arg)->DataReady(); static_cast<ICM20602 *>(arg)->DataReady();
@@ -98,12 +98,13 @@ private:
bool Reset(); bool Reset();
bool CheckConfiguration();
bool Configure(); bool Configure();
void ConfigureAccel();
void ConfigureGyro();
void ConfigureSampleRate(int sample_rate); void ConfigureSampleRate(int sample_rate);
void ConfigureFIFOWatermark(uint8_t samples); void ConfigureFIFOWatermark(uint8_t samples);
void RecordSensorOffsets();
static int DataReadyInterruptCallback(int irq, void *context, void *arg); static int DataReadyInterruptCallback(int irq, void *context, void *arg);
void DataReady(); void DataReady();
bool DataReadyInterruptConfigure(); bool DataReadyInterruptConfigure();
@@ -129,6 +130,7 @@ private:
PX4Accelerometer _px4_accel; PX4Accelerometer _px4_accel;
PX4Gyroscope _px4_gyro; PX4Gyroscope _px4_gyro;
perf_counter_t _configure_perf{perf_alloc(PC_COUNT, MODULE_NAME": configured")};
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME": bad register")}; perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME": bad register")};
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME": bad transfer")}; perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME": bad transfer")};
perf_counter_t _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")}; perf_counter_t _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")};
@@ -147,6 +149,7 @@ private:
RESET, RESET,
WAIT_FOR_RESET, WAIT_FOR_RESET,
CONFIGURE, CONFIGURE,
CHECK_CONFIGURATION,
FIFO_READ, FIFO_READ,
} _state{STATE::RESET}; } _state{STATE::RESET};
@@ -215,6 +215,7 @@ struct DATA {
uint8_t GYRO_ZOUT_H; uint8_t GYRO_ZOUT_H;
uint8_t GYRO_ZOUT_L; uint8_t GYRO_ZOUT_L;
}; };
static constexpr uint8_t MAX_SAMPLES{SIZE / sizeof(DATA)};
} }
} // namespace InvenSense_ICM20602 } // namespace InvenSense_ICM20602