drivers/imu/analog_devices/adis16448: minor fixes and compatibility with older model

- increase SPI stall time slightly
 - tolerate mag self test failure (could be due to local magnetic field)
 - register configuration compatible with older ADIS16448AMLZ
 - don't publish duplicate accel/gyro
 - only allocate CRC perf counter if using CRC
This commit is contained in:
Daniel Agar 2021-05-18 12:44:37 -04:00 committed by GitHub
parent eee08601af
commit 820a442fe3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 39 deletions

View File

@ -110,9 +110,9 @@ ADIS16448::ADIS16448(I2CSPIBusOption bus_option, int bus, uint32_t device, enum
ADIS16448::~ADIS16448()
{
perf_free(_reset_perf);
perf_free(_perf_crc_bad);
perf_free(_bad_register_perf);
perf_free(_bad_transfer_perf);
perf_free(_perf_crc_bad);
}
int ADIS16448::init()
@ -147,9 +147,9 @@ void ADIS16448::print_status()
I2CSPIDriverBase::print_status();
perf_print_counter(_reset_perf);
perf_print_counter(_perf_crc_bad);
perf_print_counter(_bad_register_perf);
perf_print_counter(_bad_transfer_perf);
perf_print_counter(_perf_crc_bad);
}
int ADIS16448::probe()
@ -159,25 +159,24 @@ int ADIS16448::probe()
PX4_WARN("Power-On Start-Up Time is 205 ms");
}
const uint16_t PROD_ID = RegisterRead(Register::PROD_ID);
for (int attempt = 0; attempt < 3; attempt++) {
const uint16_t PROD_ID = RegisterRead(Register::PROD_ID);
if (PROD_ID != Product_identification) {
DEVICE_DEBUG("unexpected PROD_ID 0x%02x", PROD_ID);
return PX4_ERROR;
if (PROD_ID == Product_identification) {
const uint16_t SERIAL_NUM = RegisterRead(Register::SERIAL_NUM);
const uint16_t LOT_ID1 = RegisterRead(Register::LOT_ID1);
const uint16_t LOT_ID2 = RegisterRead(Register::LOT_ID2);
PX4_INFO("Serial Number: 0x%02x, Lot ID1: 0x%02x ID2: 0x%02x", SERIAL_NUM, LOT_ID1, LOT_ID2);
return PX4_OK;
} else {
DEVICE_DEBUG("unexpected PROD_ID 0x%02x", PROD_ID);
}
}
const uint16_t SERIAL_NUM = RegisterRead(Register::SERIAL_NUM);
const uint16_t LOT_ID1 = RegisterRead(Register::LOT_ID1);
const uint16_t LOT_ID2 = RegisterRead(Register::LOT_ID2);
PX4_INFO("Serial Number: 0x%02x, Lot ID1: 0x%02x ID2: 0x%02x", SERIAL_NUM, LOT_ID1, LOT_ID2);
// Only enable CRC-16 for verified lots (HACK to support older ADIS16448AMLZ with no explicit detection)
if (LOT_ID1 == 0x1824) {
_check_crc = true;
}
return PX4_OK;
return PX4_ERROR;
}
void ADIS16448::RunImpl()
@ -211,20 +210,40 @@ void ADIS16448::RunImpl()
ScheduleDelayed(100_ms);
} else {
PX4_DEBUG("Reset not complete, check again in 10 ms");
ScheduleDelayed(10_ms);
PX4_DEBUG("Reset not complete, check again in 100 ms");
ScheduleDelayed(100_ms);
}
}
} else {
RegisterWrite(Register::MSC_CTRL, MSC_CTRL_BIT::Internal_self_test);
_state = STATE::SELF_TEST_CHECK;
ScheduleDelayed(45_ms); // Automatic Self-Test Time 45 ms
ScheduleDelayed(90_ms); // Automatic Self-Test Time > 45 ms
}
break;
case STATE::SELF_TEST_CHECK: {
const uint16_t MSC_CTRL = RegisterRead(Register::MSC_CTRL);
if (MSC_CTRL & MSC_CTRL_BIT::Internal_self_test) {
// self test not finished, check again
if (hrt_elapsed_time(&_reset_timestamp) < 1000_ms) {
ScheduleDelayed(45_ms);
PX4_DEBUG("self test not complete, check again in 45 ms");
return;
} else {
// still not cleared, fail self test
_self_test_passed = false;
_state = STATE::RESET;
ScheduleDelayed(1000_ms);
return;
}
}
bool test_passed = true;
const uint16_t DIAG_STAT = RegisterRead(Register::DIAG_STAT);
if (DIAG_STAT & DIAG_STAT_BIT::Self_test_diagnostic_error_flag) {
@ -248,6 +267,7 @@ void ADIS16448::RunImpl()
if (gyro_x_fail || gyro_y_fail || gyro_z_fail) {
PX4_ERR("gyroscope self-test failure");
test_passed = false;
}
// Accelerometer
@ -257,18 +277,20 @@ void ADIS16448::RunImpl()
if (accel_x_fail || accel_y_fail || accel_z_fail) {
PX4_ERR("accelerometer self-test failure");
test_passed = false;
}
}
_self_test_passed = false;
_state = STATE::RESET;
ScheduleDelayed(1000_ms);
} else {
if (test_passed) {
PX4_DEBUG("self test passed");
_self_test_passed = true;
_state = STATE::RESET;
ScheduleNow();
} else {
_self_test_passed = false;
}
_state = STATE::RESET;
ScheduleDelayed(10_ms);
}
break;
@ -364,18 +386,38 @@ void ADIS16448::RunImpl()
_px4_accel.set_temperature(temperature);
_px4_gyro.set_temperature(temperature);
bool imu_updated = false;
// sensor's frame is +x forward, +y left, +z up
// flip y & z to publish right handed with z down (x forward, y right, z down)
const int16_t accel_x = buffer.XACCL_OUT;
const int16_t accel_y = (buffer.YACCL_OUT == INT16_MIN) ? INT16_MAX : -buffer.YACCL_OUT;
const int16_t accel_z = (buffer.ZACCL_OUT == INT16_MIN) ? INT16_MAX : -buffer.ZACCL_OUT;
if (accel_x != _accel_prev[0] || accel_y != _accel_prev[1] || accel_z != _accel_prev[2]) {
imu_updated = true;
_accel_prev[0] = accel_x;
_accel_prev[1] = accel_y;
_accel_prev[2] = accel_z;
}
const int16_t gyro_x = buffer.XGYRO_OUT;
const int16_t gyro_y = (buffer.YGYRO_OUT == INT16_MIN) ? INT16_MAX : -buffer.YGYRO_OUT;
const int16_t gyro_z = (buffer.ZGYRO_OUT == INT16_MIN) ? INT16_MAX : -buffer.ZGYRO_OUT;
_px4_accel.update(now, accel_x, accel_y, accel_z);
_px4_gyro.update(now, gyro_x, gyro_y, gyro_z);
if (gyro_x != _gyro_prev[0] || gyro_y != _gyro_prev[1] || gyro_z != _gyro_prev[2]) {
imu_updated = true;
_gyro_prev[0] = gyro_x;
_gyro_prev[1] = gyro_y;
_gyro_prev[2] = gyro_z;
}
if (imu_updated) {
_px4_accel.update(now, accel_x, accel_y, accel_z);
_px4_gyro.update(now, gyro_x, gyro_y, gyro_z);
}
// DIAG_STAT bit 7: New data, xMAGN_OUT/BARO_OUT
if (buffer.DIAG_STAT & DIAG_STAT_BIT::New_data_xMAGN_OUT_BARO_OUT) {
@ -435,6 +477,27 @@ void ADIS16448::RunImpl()
bool ADIS16448::Configure()
{
const uint16_t LOT_ID1 = RegisterRead(Register::LOT_ID1);
// Only enable CRC-16 for verified lots (HACK to support older ADIS16448AMLZ with no explicit detection)
if (LOT_ID1 == 0x1824) {
_check_crc = true;
if (_perf_crc_bad == nullptr) {
_perf_crc_bad = perf_alloc(PC_COUNT, MODULE_NAME": CRC16 bad");
}
} else {
_check_crc = false;
for (auto &reg_cfg : _register_cfg) {
if (reg_cfg.reg == Register::MSC_CTRL) {
reg_cfg.set_bits = reg_cfg.set_bits & ~MSC_CTRL_BIT::CRC16_for_burst;
break;
}
}
}
// 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);

View File

@ -105,9 +105,9 @@ private:
PX4Magnetometer _px4_mag;
perf_counter_t _reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": reset")};
perf_counter_t _perf_crc_bad{perf_counter_t(perf_alloc(PC_COUNT, MODULE_NAME": CRC16 bad"))};
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 _perf_crc_bad{nullptr};
hrt_abstime _reset_timestamp{0};
hrt_abstime _last_config_check_timestamp{0};
@ -118,6 +118,9 @@ private:
bool _self_test_passed{false};
int16_t _accel_prev[3] {};
int16_t _gyro_prev[3] {};
enum class STATE : uint8_t {
RESET,
WAIT_FOR_RESET,
@ -127,12 +130,11 @@ private:
} _state{STATE::RESET};
uint8_t _checked_register{0};
static constexpr uint8_t size_register_cfg{4};
static constexpr uint8_t size_register_cfg{3};
register_config_t _register_cfg[size_register_cfg] {
// Register | Set bits, Clear bits
{ Register::MSC_CTRL, MSC_CTRL_BIT::CRC16_for_burst, 0 },
{ Register::SMPL_PRD, SMPL_PRD_BIT::internal_sampling_clock, SMPL_PRD_BIT::decimation_rate },
{ Register::SENS_AVG, SENS_AVG_BIT::Measurement_range_1000_set, SENS_AVG_BIT::Measurement_range_1000_clear | SENS_AVG_BIT::Filter_Size_Variable_B },
{ Register::GPIO_CTRL, GPIO_CTRL_BIT::GPIO2_DIRECTION | GPIO_CTRL_BIT::GPIO1_DIRECTION, 0},
{ Register::SENS_AVG, SENS_AVG_BIT::Measurement_range_1000_set | SENS_AVG_BIT::Filter_Size_Variable_B_set, SENS_AVG_BIT::Measurement_range_1000_clear | SENS_AVG_BIT::Filter_Size_Variable_B_clear },
};
};

View File

@ -65,7 +65,7 @@ namespace Analog_Devices_ADIS16448
static constexpr uint32_t SPI_SPEED = 2 * 1000 * 1000; // 2 MHz SPI serial interface
static constexpr uint32_t SPI_SPEED_BURST = 1 * 1000 * 1000; // 1 MHz SPI serial interface for burst read
static constexpr uint32_t SPI_STALL_PERIOD = 9; // 9 us Stall period between data
static constexpr uint32_t SPI_STALL_PERIOD = 10; // 9 us Stall period between data
static constexpr uint16_t DIR_WRITE = 0x80;
@ -128,8 +128,8 @@ enum GLOB_CMD_BIT : uint16_t {
// SMPL_PRD
enum SMPL_PRD_BIT : uint16_t {
// [12:8] D, decimation rate setting, binomial,
decimation_rate = Bit12 | Bit11 | Bit10 | Bit9, // disable
// [12:8] D, decimation rate setting, binomial
decimation_rate = Bit12 | Bit11 | Bit10 | Bit9 | Bit8, // disable
internal_sampling_clock = Bit0, // 1 = internal sampling clock, 819.2 SPS
};
@ -141,8 +141,8 @@ enum SENS_AVG_BIT : uint16_t {
Measurement_range_1000_clear = Bit9 | Bit8,
// [2:0] Filter Size Variable B
Filter_Size_Variable_B = Bit2 | Bit1 | Bit0, // disable
Filter_Size_Variable_B_set = Bit1,
Filter_Size_Variable_B_clear = Bit2 | Bit0,
};
// GPIO_CTRL