mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-05-26 11:30:04 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 52e98f99f4 |
@@ -903,12 +903,11 @@ void printTopics() {
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener rate_ctrl_status" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener safety" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_accel" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_accel_fifo" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_imu_fifo" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_baro" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_combined" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_gyro" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_gyro_fft" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_gyro_fifo" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_mag" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_preflight_mag" || true'
|
||||
sh './Tools/HIL/run_nsh_cmd.py --device `find /dev/serial -name *usb-*` --cmd "listener sensor_selection" || true'
|
||||
|
||||
+1
-2
@@ -144,7 +144,6 @@ set(msg_files
|
||||
rtl_time_estimate.msg
|
||||
satellite_info.msg
|
||||
sensor_accel.msg
|
||||
sensor_accel_fifo.msg
|
||||
sensor_baro.msg
|
||||
sensor_combined.msg
|
||||
sensor_correction.msg
|
||||
@@ -152,8 +151,8 @@ set(msg_files
|
||||
sensor_gps.msg
|
||||
sensor_gyro.msg
|
||||
sensor_gyro_fft.msg
|
||||
sensor_gyro_fifo.msg
|
||||
sensor_hygrometer.msg
|
||||
sensor_imu_fifo.msg
|
||||
sensor_mag.msg
|
||||
sensor_optical_flow.msg
|
||||
sensor_preflight_mag.msg
|
||||
|
||||
@@ -7,12 +7,10 @@ float32 x # acceleration in the FRD board frame X-axis in m/s^2
|
||||
float32 y # acceleration in the FRD board frame Y-axis in m/s^2
|
||||
float32 z # acceleration in the FRD board frame Z-axis in m/s^2
|
||||
|
||||
float32 range # TODO
|
||||
|
||||
float32 temperature # temperature in degrees Celsius
|
||||
|
||||
uint32 error_count
|
||||
|
||||
uint8[3] clip_counter # clip count per axis in the sample period
|
||||
|
||||
uint8 samples # number of raw samples that went into this message
|
||||
|
||||
uint8 ORB_QUEUE_LENGTH = 8
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
uint64 timestamp # time since system start (microseconds)
|
||||
uint64 timestamp_sample
|
||||
|
||||
uint32 device_id # unique device ID for the sensor that does not change between power cycles
|
||||
|
||||
float32 dt # delta time between samples (microseconds)
|
||||
float32 scale
|
||||
|
||||
uint8 samples # number of valid samples
|
||||
|
||||
int16[32] x # acceleration in the FRD board frame X-axis in m/s^2
|
||||
int16[32] y # acceleration in the FRD board frame Y-axis in m/s^2
|
||||
int16[32] z # acceleration in the FRD board frame Z-axis in m/s^2
|
||||
+2
-4
@@ -7,12 +7,10 @@ float32 x # angular velocity in the FRD board frame X-axis in ra
|
||||
float32 y # angular velocity in the FRD board frame Y-axis in rad/s
|
||||
float32 z # angular velocity in the FRD board frame Z-axis in rad/s
|
||||
|
||||
float32 range # dynamic range in rad/s
|
||||
|
||||
float32 temperature # temperature in degrees Celsius
|
||||
|
||||
uint32 error_count
|
||||
|
||||
uint8[3] clip_counter # clip count per axis in the sample period
|
||||
|
||||
uint8 samples # number of raw samples that went into this message
|
||||
|
||||
uint8 ORB_QUEUE_LENGTH = 8
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
uint64 timestamp # time since system start (microseconds)
|
||||
uint64 timestamp_sample
|
||||
|
||||
uint32 device_id # unique device ID for the sensor that does not change between power cycles
|
||||
|
||||
float32 dt # delta time between samples (microseconds)
|
||||
float32 scale
|
||||
|
||||
uint8 samples # number of valid samples
|
||||
|
||||
int16[32] x # angular velocity in the FRD board frame X-axis in rad/s
|
||||
int16[32] y # angular velocity in the FRD board frame Y-axis in rad/s
|
||||
int16[32] z # angular velocity in the FRD board frame Z-axis in rad/s
|
||||
|
||||
uint8 ORB_QUEUE_LENGTH = 4
|
||||
@@ -0,0 +1,26 @@
|
||||
uint64 timestamp # time since system start (microseconds)
|
||||
uint64 timestamp_sample
|
||||
|
||||
uint32 device_id # unique device ID for the sensor that does not change between power cycles
|
||||
|
||||
float32 dt # delta time between samples (microseconds)
|
||||
uint8 samples # number of valid samples
|
||||
|
||||
float32 accel_scale
|
||||
float32 gyro_scale
|
||||
|
||||
uint8 FIFO_SIZE = 24
|
||||
|
||||
int16[24] accel_x # gyro in the FRD board frame X-axis
|
||||
int16[24] accel_y # gyro in the FRD board frame Y-axis
|
||||
int16[24] accel_z # gyro in the FRD board frame Z-axis
|
||||
|
||||
int16[24] gyro_x # gyro in the FRD board frame X-axis
|
||||
int16[24] gyro_y # gyro in the FRD board frame Y-axis
|
||||
int16[24] gyro_z # gyro in the FRD board frame Z-axis
|
||||
|
||||
float32 temperature # temperature in degrees Celsius
|
||||
|
||||
uint32 error_count
|
||||
|
||||
uint8 ORB_QUEUE_LENGTH = 8
|
||||
@@ -49,7 +49,7 @@ logger off
|
||||
|
||||
sensors status
|
||||
listener sensor_gyro
|
||||
listener sensor_gyro_fifo
|
||||
listener sensor_imu_fifo
|
||||
listener sensor_gyro_fft
|
||||
perf
|
||||
|
||||
|
||||
@@ -56,8 +56,7 @@ using namespace time_literals;
|
||||
ADIS16477::ADIS16477(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation),
|
||||
_rotation(config.rotation),
|
||||
_sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": read")),
|
||||
_bad_transfers(perf_alloc(PC_COUNT, MODULE_NAME": bad transfers")),
|
||||
_drdy_gpio(config.drdy_gpio)
|
||||
@@ -67,8 +66,8 @@ ADIS16477::ADIS16477(const I2CSPIDriverConfig &config) :
|
||||
px4_arch_configgpio(GPIO_SPI1_RESET_ADIS16477);
|
||||
#endif // GPIO_SPI1_RESET_ADIS16477
|
||||
|
||||
_px4_accel.set_scale(1.25f * CONSTANTS_ONE_G / 1000.0f); // accel 1.25 mg/LSB
|
||||
_px4_gyro.set_scale(math::radians(0.025f)); // gyro 0.025 °/sec/LSB
|
||||
_accel_scale = 1.25f * CONSTANTS_ONE_G / 1000.0f; // accel 1.25 mg/LSB
|
||||
_gyro_scale = math::radians(0.025f); // gyro 0.025 °/sec/LSB
|
||||
}
|
||||
|
||||
ADIS16477::~ADIS16477()
|
||||
@@ -366,11 +365,31 @@ ADIS16477::measure()
|
||||
|
||||
// temperature 1 LSB = 0.1°C
|
||||
const float temperature = adis_report.temp * 0.1f;
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_px4_gyro.set_temperature(temperature);
|
||||
|
||||
_px4_accel.update(timestamp_sample, adis_report.accel_x, adis_report.accel_y, adis_report.accel_z);
|
||||
_px4_gyro.update(timestamp_sample, adis_report.gyro_x, adis_report.gyro_y, adis_report.gyro_z);
|
||||
|
||||
// sensor_accel
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
sensor_accel.x = adis_report.accel_x;
|
||||
sensor_accel.y = adis_report.accel_y;
|
||||
sensor_accel.z = adis_report.accel_z;
|
||||
sensor_accel.range = 16.f * CONSTANTS_ONE_G;
|
||||
sensor_accel.temperature = temperature;
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
|
||||
// sensor_gyro
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = timestamp_sample;
|
||||
sensor_gyro.device_id = get_device_id();
|
||||
sensor_gyro.x = adis_report.gyro_x;
|
||||
sensor_gyro.y = adis_report.gyro_y;
|
||||
sensor_gyro.z = adis_report.gyro_z;
|
||||
sensor_gyro.range = math::radians(2000.f);
|
||||
sensor_gyro.temperature = temperature;
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
|
||||
perf_end(_sample_perf);
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#include <drivers/device/spi.h>
|
||||
#include <geo/geo.h>
|
||||
#include <lib/conversion/rotation.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <perf/perf_counter.h>
|
||||
#include <px4_platform_common/getopt.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
@@ -66,9 +64,6 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
|
||||
perf_counter_t _sample_perf;
|
||||
perf_counter_t _bad_transfers;
|
||||
|
||||
|
||||
@@ -40,6 +40,4 @@ px4_add_module(
|
||||
adis16477_main.cpp
|
||||
DEPENDS
|
||||
px4_work_queue
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
)
|
||||
|
||||
@@ -73,8 +73,7 @@ using namespace time_literals;
|
||||
ADIS16497::ADIS16497(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation),
|
||||
_rotation(config.rotation),
|
||||
_sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": read")),
|
||||
_bad_transfers(perf_alloc(PC_COUNT, MODULE_NAME": bad transfers")),
|
||||
_drdy_gpio(config.drdy_gpio)
|
||||
@@ -308,23 +307,23 @@ ADIS16497::self_test()
|
||||
bool
|
||||
ADIS16497::set_measurement_range(uint16_t model)
|
||||
{
|
||||
_px4_accel.set_scale(1.25f * CONSTANTS_ONE_G / 1000.0f); // 1.25 mg/LSB
|
||||
_px4_accel.set_range(40.0f * CONSTANTS_ONE_G); // 40g
|
||||
_accel_scale = 1.25f * CONSTANTS_ONE_G / 1000.0f; // 1.25 mg/LSB
|
||||
_accel_range = 40.0f * CONSTANTS_ONE_G; // 40g
|
||||
|
||||
switch (model) {
|
||||
case RANG_MDL_1BMLZ:
|
||||
_px4_gyro.set_scale(math::radians(0.00625f)); // 0.00625 °/sec/LSB
|
||||
_px4_gyro.set_range(math::radians(125.0f)); // 125 °/s
|
||||
_gyro_scale = math::radians(0.00625f); // 0.00625 °/sec/LSB
|
||||
_gyro_range = math::radians(125.0f); // 125 °/s
|
||||
break;
|
||||
|
||||
case RANG_MDL_2BMLZ:
|
||||
_px4_gyro.set_scale(math::radians(0.025f)); // 0.025 °/sec/LSB
|
||||
_px4_gyro.set_range(math::radians(450.0f)); // 450 °/s
|
||||
_gyro_scale = math::radians(0.025f); // 0.025 °/sec/LSB
|
||||
_gyro_range = math::radians(450.0f); // 450 °/s
|
||||
break;
|
||||
|
||||
case RANG_MDL_3BMLZ:
|
||||
_px4_gyro.set_scale(math::radians(0.1f)); // 0.1 °/sec/LSB
|
||||
_px4_gyro.set_range(math::radians(2000.0f)); // 2000 °/s
|
||||
_gyro_scale = math::radians(0.1f); // 0.1 °/sec/LSB
|
||||
_gyro_range = math::radians(2000.0f); // 2000 °/s
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -470,26 +469,44 @@ ADIS16497::measure()
|
||||
}
|
||||
|
||||
const uint64_t error_count = perf_event_count(_bad_transfers);
|
||||
_px4_accel.set_error_count(error_count);
|
||||
_px4_gyro.set_error_count(error_count);
|
||||
|
||||
const float temperature = (int16_t(adis_report.TEMP_OUT) * 0.0125f) + 25.0f; // 1 LSB = 0.0125°C, 0x0000 at 25°C
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_px4_gyro.set_temperature(temperature);
|
||||
|
||||
|
||||
// TODO check data counter here to see if we're missing samples/getting repeated samples
|
||||
{
|
||||
float xraw_f = (int32_t(adis_report.X_ACCEL_OUT) << 16 | adis_report.X_ACCEL_LOW) / 65536.0f;
|
||||
float yraw_f = (int32_t(adis_report.Y_ACCEL_OUT) << 16 | adis_report.Y_ACCEL_LOW) / 65536.0f;
|
||||
float zraw_f = (int32_t(adis_report.Z_ACCEL_OUT) << 16 | adis_report.Z_ACCEL_LOW) / 65536.0f;
|
||||
_px4_accel.update(timestamp_sample, xraw_f, yraw_f, zraw_f);
|
||||
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
sensor_accel.x = xraw_f;
|
||||
sensor_accel.y = yraw_f;
|
||||
sensor_accel.z = zraw_f;
|
||||
sensor_accel.range = 16.f * CONSTANTS_ONE_G;
|
||||
sensor_accel.temperature = temperature;
|
||||
sensor_accel.error_count = error_count;
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
}
|
||||
|
||||
{
|
||||
float xraw_f = (int32_t(adis_report.X_GYRO_OUT) << 16 | adis_report.X_GYRO_LOW) / 65536.0f;
|
||||
float yraw_f = (int32_t(adis_report.Y_GYRO_OUT) << 16 | adis_report.Y_GYRO_LOW) / 65536.0f;
|
||||
float zraw_f = (int32_t(adis_report.Z_GYRO_OUT) << 16 | adis_report.Z_GYRO_LOW) / 65536.0f;
|
||||
_px4_gyro.update(timestamp_sample, xraw_f, yraw_f, zraw_f);
|
||||
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = timestamp_sample;
|
||||
sensor_gyro.device_id = get_device_id();
|
||||
sensor_gyro.x = xraw_f;
|
||||
sensor_gyro.y = yraw_f;
|
||||
sensor_gyro.z = zraw_f;
|
||||
sensor_gyro.range = math::radians(2000.f);
|
||||
sensor_gyro.temperature = temperature;
|
||||
sensor_gyro.error_count = error_count;
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
}
|
||||
|
||||
perf_end(_sample_perf);
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#include <drivers/device/spi.h>
|
||||
#include <geo/geo.h>
|
||||
#include <lib/conversion/rotation.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <perf/perf_counter.h>
|
||||
#include <px4_platform_common/getopt.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
@@ -102,9 +100,6 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
|
||||
perf_counter_t _sample_perf;
|
||||
perf_counter_t _bad_transfers;
|
||||
|
||||
|
||||
@@ -40,6 +40,5 @@ px4_add_module(
|
||||
ADIS16497.hpp
|
||||
adis16497_main.cpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2021-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -99,9 +99,8 @@ ADIS16448::ADIS16448(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio), // TODO: DRDY disabled
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation),
|
||||
_px4_mag(get_device_id(), config.rotation)
|
||||
_px4_mag(get_device_id(), config.rotation),
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
@@ -392,15 +391,10 @@ void ADIS16448::RunImpl()
|
||||
if (publish_data) {
|
||||
|
||||
const uint32_t error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf);
|
||||
_px4_accel.set_error_count(error_count);
|
||||
_px4_gyro.set_error_count(error_count);
|
||||
|
||||
// temperature 0.07386°C/LSB, 31°C = 0x000
|
||||
const float temperature = (convert12BitToINT16(buffer.TEMP_OUT) * 0.07386f) + 31.f;
|
||||
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_px4_gyro.set_temperature(temperature);
|
||||
|
||||
bool imu_updated = false;
|
||||
|
||||
// sensor's frame is +x forward, +y left, +z up
|
||||
@@ -430,8 +424,29 @@ void ADIS16448::RunImpl()
|
||||
}
|
||||
|
||||
if (imu_updated) {
|
||||
_px4_accel.update(timestamp_sample, accel_x, accel_y, accel_z);
|
||||
_px4_gyro.update(timestamp_sample, gyro_x, gyro_y, gyro_z);
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
sensor_accel.x = accel_x;
|
||||
sensor_accel.y = accel_y;
|
||||
sensor_accel.z = accel_z;
|
||||
sensor_accel.range = 16.f * CONSTANTS_ONE_G;
|
||||
sensor_accel.temperature = temperature;
|
||||
sensor_accel.error_count = error_count;
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = timestamp_sample;
|
||||
sensor_gyro.device_id = get_device_id();
|
||||
sensor_gyro.x = gyro_x;
|
||||
sensor_gyro.y = gyro_y;
|
||||
sensor_gyro.z = gyro_z;
|
||||
sensor_gyro.range = math::radians(2000.f);
|
||||
sensor_gyro.temperature = temperature;
|
||||
sensor_gyro.error_count = error_count;
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
}
|
||||
|
||||
// DIAG_STAT bit 7: New data, xMAGN_OUT/BARO_OUT
|
||||
@@ -534,12 +549,12 @@ bool ADIS16448::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
_px4_accel.set_scale(0.833f * 1e-3f * CONSTANTS_ONE_G); // 0.833 mg/LSB
|
||||
_px4_gyro.set_scale(math::radians(0.04f)); // 0.04 °/sec/LSB
|
||||
_accel_scale = 0.833f * 1e-3f * CONSTANTS_ONE_G; // 0.833 mg/LSB
|
||||
_gyro_scale = math::radians(0.04f); // 0.04 °/sec/LSB
|
||||
_px4_mag.set_scale(142.9f * 1e-6f); // μgauss/LSB
|
||||
|
||||
_px4_accel.set_range(18.f * CONSTANTS_ONE_G);
|
||||
_px4_gyro.set_range(math::radians(1000.f));
|
||||
_accel_range = 18.f * CONSTANTS_ONE_G;
|
||||
_gyro_range = math::radians(1000.f);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2021-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -44,16 +44,17 @@
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/drivers/magnetometer/PX4Magnetometer.hpp>
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_baro.h>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_accel.h>
|
||||
#include <uORB/topics/sensor_baro.h>
|
||||
#include <uORB/topics/sensor_gyro.h>
|
||||
|
||||
using namespace Analog_Devices_ADIS16448;
|
||||
|
||||
class ADIS16448 : public device::SPI, public I2CSPIDriver<ADIS16448>
|
||||
@@ -98,11 +99,17 @@ private:
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
PX4Magnetometer _px4_mag;
|
||||
|
||||
uORB::PublicationMulti<sensor_accel_s> _sensor_accel_pub{ORB_ID(sensor_accel)};
|
||||
uORB::PublicationMulti<sensor_baro_s> _sensor_baro_pub{ORB_ID(sensor_baro)};
|
||||
uORB::PublicationMulti<sensor_gyro_s> _sensor_gyro_pub{ORB_ID(sensor_gyro)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _accel_scale{0.f};
|
||||
float _accel_range{0.f};
|
||||
float _gyro_scale{0.f};
|
||||
float _gyro_range{0.f};
|
||||
|
||||
perf_counter_t _reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": reset")};
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME": bad register")};
|
||||
|
||||
@@ -43,8 +43,6 @@ px4_add_module(
|
||||
adis16448_main.cpp
|
||||
Analog_Devices_ADIS16448_registers.hpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
drivers_magnetometer
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -44,8 +44,7 @@ ADIS16470::ADIS16470(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
@@ -296,8 +295,6 @@ void ADIS16470::RunImpl()
|
||||
|
||||
// temperature 1 LSB = 0.1°C
|
||||
const float temperature = buffer.TEMP_OUT * 0.1f;
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_px4_gyro.set_temperature(temperature);
|
||||
|
||||
|
||||
int16_t accel_x = buffer.X_ACCL_OUT;
|
||||
@@ -306,10 +303,17 @@ void ADIS16470::RunImpl()
|
||||
|
||||
// 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)
|
||||
accel_y = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel_z = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
|
||||
_px4_accel.update(timestamp_sample, accel_x, accel_y, accel_z);
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
sensor_accel.x = accel_x;
|
||||
sensor_accel.y = math::negate(accel_y);
|
||||
sensor_accel.z = math::negate(accel_z);
|
||||
sensor_accel.range = 16.f * CONSTANTS_ONE_G;
|
||||
sensor_accel.temperature = temperature;
|
||||
sensor_accel.error_count = error_count;
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
|
||||
|
||||
int16_t gyro_x = buffer.X_GYRO_OUT;
|
||||
@@ -317,9 +321,17 @@ void ADIS16470::RunImpl()
|
||||
int16_t gyro_z = buffer.Z_GYRO_OUT;
|
||||
// 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)
|
||||
gyro_y = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro_z = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
_px4_gyro.update(timestamp_sample, gyro_x, gyro_y, gyro_z);
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = timestamp_sample;
|
||||
sensor_gyro.device_id = get_device_id();
|
||||
sensor_gyro.x = gyro_x;
|
||||
sensor_gyro.y = math::negate(gyro_y);
|
||||
sensor_gyro.z = math::negate(gyro_z);
|
||||
sensor_gyro.range = math::radians(2000.f);
|
||||
sensor_gyro.temperature = temperature;
|
||||
sensor_gyro.error_count = error_count;
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
|
||||
success = true;
|
||||
|
||||
@@ -376,12 +388,12 @@ bool ADIS16470::Configure()
|
||||
}
|
||||
|
||||
// accel: ±40 g, 800 LSB/g (16-bit format)
|
||||
_px4_accel.set_range(40.f * CONSTANTS_ONE_G);
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 800.f); // scaling 800 LSB/g -> m/s^2 per LSB
|
||||
//_accel_range = 40.f * CONSTANTS_ONE_G;
|
||||
_accel_scale = CONSTANTS_ONE_G / 800.f; // scaling 800 LSB/g -> m/s^2 per LSB
|
||||
|
||||
// gyro: ±2000 °/sec, 10 LSB/°/sec (16-bit format)
|
||||
_px4_gyro.set_range(math::radians(2000.f));
|
||||
_px4_gyro.set_scale(math::radians(1.f / 10.f)); // scaling 10 LSB/°/sec -> rad/s per LSB
|
||||
//_gyro_range = math::radians(2000.f);
|
||||
_gyro_scale = math::radians(1.f / 10.f); // scaling 10 LSB/°/sec -> rad/s per LSB
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2021-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "Analog_Devices_ADIS16470_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace Analog_Devices_ADIS16470;
|
||||
|
||||
class ADIS16470 : public device::SPI, public I2CSPIDriver<ADIS16470>
|
||||
@@ -94,8 +95,11 @@ private:
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _accel_scale{0.f};
|
||||
float _gyro_scale{0.f};
|
||||
|
||||
perf_counter_t _reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": reset")};
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME": bad register")};
|
||||
|
||||
@@ -35,13 +35,12 @@ px4_add_module(
|
||||
MODULE drivers__imu__analog_devices__adis16470
|
||||
MAIN adis16470
|
||||
COMPILE_FLAGS
|
||||
-Wno-error
|
||||
SRCS
|
||||
ADIS16470.cpp
|
||||
ADIS16470.hpp
|
||||
adis16470_main.cpp
|
||||
Analog_Devices_ADIS16470_registers.hpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -42,13 +42,13 @@ namespace Bosch::BMI055::Accelerometer
|
||||
|
||||
BMI055_Accelerometer::BMI055_Accelerometer(const I2CSPIDriverConfig &config) :
|
||||
BMI055(config),
|
||||
_px4_accel(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME"_accel: DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_accel.get_max_rate_hz());
|
||||
ConfigureSampleRate(RATE);
|
||||
}
|
||||
|
||||
BMI055_Accelerometer::~BMI055_Accelerometer()
|
||||
@@ -121,8 +121,8 @@ void BMI055_Accelerometer::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,62 +162,78 @@ void BMI055_Accelerometer::RunImpl()
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
hrt_abstime timestamp_sample = 0;
|
||||
hrt_abstime timestamp_sample = now;
|
||||
uint8_t samples = 0;
|
||||
|
||||
if (_data_ready_interrupt_enabled) {
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if ((drdy_timestamp_sample != 0) && (now < drdy_timestamp_sample + _fifo_empty_interval_us)) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_samples;
|
||||
|
||||
} else {
|
||||
perf_count(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
// push backup schedule back
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 3);
|
||||
}
|
||||
|
||||
// always check current FIFO status/count
|
||||
bool success = false;
|
||||
const uint8_t FIFO_STATUS = RegisterRead(Register::FIFO_STATUS);
|
||||
if (samples == 0) {
|
||||
// always check current FIFO status/count
|
||||
const uint8_t FIFO_STATUS = RegisterRead(Register::FIFO_STATUS);
|
||||
|
||||
if (FIFO_STATUS & FIFO_STATUS_BIT::fifo_overrun) {
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else {
|
||||
const uint8_t fifo_frame_counter = FIFO_STATUS & FIFO_STATUS_BIT::fifo_frame_counter;
|
||||
|
||||
if (fifo_frame_counter > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
if (FIFO_STATUS & FIFO_STATUS_BIT::fifo_overrun) {
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else if (fifo_frame_counter == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
} else {
|
||||
const uint8_t fifo_frame_counter = FIFO_STATUS & FIFO_STATUS_BIT::fifo_frame_counter;
|
||||
|
||||
} else if (fifo_frame_counter >= 1) {
|
||||
if (fifo_frame_counter > FIFO_MAX_SAMPLES) {
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
uint8_t samples = fifo_frame_counter;
|
||||
} else if (fifo_frame_counter == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_samples + 1) {
|
||||
// sample timestamp set from data ready already corresponds to _fifo_samples
|
||||
if (timestamp_sample == 0) {
|
||||
timestamp_sample = now - static_cast<int>(FIFO_SAMPLE_DT);
|
||||
} else if (fifo_frame_counter >= 1) {
|
||||
|
||||
samples = fifo_frame_counter;
|
||||
|
||||
if (samples > _fifo_samples) {
|
||||
// grab desired number of samples, but reschedule next cycle sooner
|
||||
const int extra_samples = samples - _fifo_samples;
|
||||
samples = _fifo_samples;
|
||||
|
||||
if (_fifo_samples > extra_samples) {
|
||||
// reschedule to run when a total of _fifo_gyro_samples should be available in the FIFO
|
||||
const uint32_t reschedule_delay_us = (_fifo_samples - extra_samples) * static_cast<int>(FIFO_SAMPLE_DT);
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, reschedule_delay_us);
|
||||
|
||||
} else {
|
||||
// otherwise reschedule to run immediately
|
||||
ScheduleOnInterval(_fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
} else if (samples < _fifo_samples) {
|
||||
// reschedule next cycle to catch the desired number of samples
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, (_fifo_samples - samples) * static_cast<int>(FIFO_SAMPLE_DT));
|
||||
}
|
||||
|
||||
samples--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FIFORead((timestamp_sample == 0) ? now : timestamp_sample, samples)) {
|
||||
success = true;
|
||||
bool success = false;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
if (samples == _fifo_samples) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,13 +243,14 @@ void BMI055_Accelerometer::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_cfg[_checked_register])) {
|
||||
_last_config_check_timestamp = now;
|
||||
_checked_register = (_checked_register + 1) % size_register_cfg;
|
||||
@@ -241,6 +258,7 @@ void BMI055_Accelerometer::RunImpl()
|
||||
} else {
|
||||
// register check failed, force reset
|
||||
perf_count(_bad_register_perf);
|
||||
PX4_DEBUG("Force reset because register 0x%02hhX check failed ", (uint8_t)_register_cfg[_checked_register].reg);
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -263,23 +281,23 @@ void BMI055_Accelerometer::ConfigureAccel()
|
||||
|
||||
switch (PMU_RANGE) {
|
||||
case range_2g_set:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 1024.f); // 1024 LSB/g, 0.98mg/LSB
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G / 1024.f; // 1024 LSB/g, 0.98mg/LSB
|
||||
_accel_range = 2.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case range_4g_set:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 512.f); // 512 LSB/g, 1.95mg/LSB
|
||||
_px4_accel.set_range(4.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G / 512.f; // 512 LSB/g, 1.95mg/LSB
|
||||
_accel_range = 4.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case range_8g_set:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 256.f); // 256 LSB/g, 3.91mg/LSB
|
||||
_px4_accel.set_range(8.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G / 256.f; // 256 LSB/g, 3.91mg/LSB
|
||||
_accel_range = 8.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case range_16g_set:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 128.f); // 128 LSB/g, 7.81mg/LSB
|
||||
_px4_accel.set_range(16.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G / 128.f; // 128 LSB/g, 7.81mg/LSB
|
||||
_accel_range = 16.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -349,7 +367,7 @@ bool BMI055_Accelerometer::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool BMI055_Accelerometer::DataReadyInterruptDisable()
|
||||
@@ -358,7 +376,7 @@ bool BMI055_Accelerometer::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
bool BMI055_Accelerometer::RegisterCheck(const register_config_t ®_cfg)
|
||||
@@ -407,40 +425,66 @@ void BMI055_Accelerometer::RegisterSetAndClearBits(Register reg, uint8_t setbits
|
||||
|
||||
bool BMI055_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 1, FIFO::SIZE);
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_DATA) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + (samples * FIFO::DATA)
|
||||
const size_t transfer_size = 1 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = samples;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
if (samples > 0) {
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const FIFO::DATA &fifo_sample = buffer.f[i];
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
|
||||
// acc_x_msb<11:4> + acc_x_lsb<3:0>
|
||||
const int16_t accel_x = combine(fifo_sample.ACCD_X_MSB, fifo_sample.ACCD_X_LSB) >> 4;
|
||||
const int16_t accel_y = combine(fifo_sample.ACCD_Y_MSB, fifo_sample.ACCD_Y_LSB) >> 4;
|
||||
const int16_t accel_z = combine(fifo_sample.ACCD_Z_MSB, fifo_sample.ACCD_Z_LSB) >> 4;
|
||||
float accel_sum[3] {};
|
||||
|
||||
// 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)
|
||||
accel.x[i] = accel_x;
|
||||
accel.y[i] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[i] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const FIFO::DATA &fifo_sample = buffer.f[i];
|
||||
|
||||
// acc_x_msb<11:4> + acc_x_lsb<3:0>
|
||||
int16_t accel_x = combine(fifo_sample.ACCD_X_MSB, fifo_sample.ACCD_X_LSB) >> 4;
|
||||
int16_t accel_y = combine(fifo_sample.ACCD_Y_MSB, fifo_sample.ACCD_Y_LSB) >> 4;
|
||||
int16_t accel_z = combine(fifo_sample.ACCD_Z_MSB, fifo_sample.ACCD_Z_LSB) >> 4;
|
||||
|
||||
// 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)
|
||||
// accel_x = accel_x;
|
||||
accel_y = math::negate(accel_y);
|
||||
accel_z = math::negate(accel_z);
|
||||
|
||||
accel_sum[0] += accel_x;
|
||||
accel_sum[1] += accel_y;
|
||||
accel_sum[2] += accel_z;
|
||||
}
|
||||
|
||||
|
||||
sensor_accel.x = (accel_sum[0] / samples) * _accel_scale;
|
||||
sensor_accel.y = (accel_sum[1] / samples) * _accel_scale;
|
||||
sensor_accel.z = (accel_sum[2] / samples) * _accel_scale;
|
||||
|
||||
rotate_3f(_rotation, sensor_accel.x, sensor_accel.y, sensor_accel.z);
|
||||
|
||||
sensor_accel.range = _accel_range;
|
||||
sensor_accel.temperature = _temperature;
|
||||
sensor_accel.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_accel.updateFIFO(accel);
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void BMI055_Accelerometer::FIFOReset()
|
||||
@@ -472,7 +516,7 @@ void BMI055_Accelerometer::UpdateTemperature()
|
||||
float temperature = static_cast<int8_t>(RegisterRead(Register::ACCD_TEMP)) * 0.5f + 23.f;
|
||||
|
||||
if (PX4_ISFINITE(temperature)) {
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_temperature = temperature;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,10 +35,11 @@
|
||||
|
||||
#include "BMI055.hpp"
|
||||
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
|
||||
#include "Bosch_BMI055_Accelerometer_Registers.hpp"
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_accel.h>
|
||||
|
||||
namespace Bosch::BMI055::Accelerometer
|
||||
{
|
||||
|
||||
@@ -58,15 +59,7 @@ private:
|
||||
static constexpr uint32_t RATE{2000}; // 2000 Hz
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / RATE};
|
||||
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]))};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_DATA) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (1 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{FIFO::SIZE / sizeof(FIFO::DATA)};
|
||||
|
||||
struct register_config_t {
|
||||
Register reg;
|
||||
@@ -97,7 +90,13 @@ private:
|
||||
|
||||
void UpdateTemperature();
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
uORB::PublicationMulti<sensor_accel_s> _sensor_accel_pub{ORB_ID(sensor_accel)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _accel_scale{0.f};
|
||||
float _accel_range{0.f};
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME"_accel: bad register")};
|
||||
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME"_accel: bad transfer")};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
#include "BMI055_Gyroscope.hpp"
|
||||
|
||||
#include <px4_platform/board_dma_alloc.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
namespace Bosch::BMI055::Gyroscope
|
||||
@@ -42,13 +40,13 @@ namespace Bosch::BMI055::Gyroscope
|
||||
|
||||
BMI055_Gyroscope::BMI055_Gyroscope(const I2CSPIDriverConfig &config) :
|
||||
BMI055(config),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME"_gyro: DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
ConfigureSampleRate(RATE);
|
||||
}
|
||||
|
||||
BMI055_Gyroscope::~BMI055_Gyroscope()
|
||||
@@ -121,8 +119,8 @@ void BMI055_Gyroscope::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,62 +160,78 @@ void BMI055_Gyroscope::RunImpl()
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
hrt_abstime timestamp_sample = 0;
|
||||
hrt_abstime timestamp_sample = now;
|
||||
uint8_t samples = 0;
|
||||
|
||||
if (_data_ready_interrupt_enabled) {
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if ((drdy_timestamp_sample != 0) && (now < drdy_timestamp_sample + _fifo_empty_interval_us)) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_samples;
|
||||
|
||||
} else {
|
||||
perf_count(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
// push backup schedule back
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 3);
|
||||
}
|
||||
|
||||
// always check current FIFO status/count
|
||||
bool success = false;
|
||||
const uint8_t FIFO_STATUS = RegisterRead(Register::FIFO_STATUS);
|
||||
if (samples == 0) {
|
||||
// always check current FIFO status/count
|
||||
const uint8_t FIFO_STATUS = RegisterRead(Register::FIFO_STATUS);
|
||||
|
||||
if (FIFO_STATUS & FIFO_STATUS_BIT::fifo_overrun) {
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else {
|
||||
const uint8_t fifo_frame_counter = FIFO_STATUS & FIFO_STATUS_BIT::fifo_frame_counter;
|
||||
|
||||
if (fifo_frame_counter > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
if (FIFO_STATUS & FIFO_STATUS_BIT::fifo_overrun) {
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else if (fifo_frame_counter == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
} else {
|
||||
const uint8_t fifo_frame_counter = FIFO_STATUS & FIFO_STATUS_BIT::fifo_frame_counter;
|
||||
|
||||
} else if (fifo_frame_counter >= 1) {
|
||||
if (fifo_frame_counter > FIFO_MAX_SAMPLES) {
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
uint8_t samples = fifo_frame_counter;
|
||||
} else if (fifo_frame_counter == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_samples + 1) {
|
||||
// sample timestamp set from data ready already corresponds to _fifo_samples
|
||||
if (timestamp_sample == 0) {
|
||||
timestamp_sample = now - static_cast<int>(FIFO_SAMPLE_DT);
|
||||
} else if (fifo_frame_counter >= 1) {
|
||||
|
||||
samples = fifo_frame_counter;
|
||||
|
||||
if (samples > _fifo_samples) {
|
||||
// grab desired number of samples, but reschedule next cycle sooner
|
||||
const int extra_samples = samples - _fifo_samples;
|
||||
samples = _fifo_samples;
|
||||
|
||||
if (_fifo_samples > extra_samples) {
|
||||
// reschedule to run when a total of _fifo_gyro_samples should be available in the FIFO
|
||||
const uint32_t reschedule_delay_us = (_fifo_samples - extra_samples) * static_cast<int>(FIFO_SAMPLE_DT);
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, reschedule_delay_us);
|
||||
|
||||
} else {
|
||||
// otherwise reschedule to run immediately
|
||||
ScheduleOnInterval(_fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
} else if (samples < _fifo_samples) {
|
||||
// reschedule next cycle to catch the desired number of samples
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, (_fifo_samples - samples) * static_cast<int>(FIFO_SAMPLE_DT));
|
||||
}
|
||||
|
||||
samples--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FIFORead((timestamp_sample == 0) ? now : timestamp_sample, samples)) {
|
||||
success = true;
|
||||
bool success = false;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
if (samples == _fifo_samples) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,13 +241,14 @@ void BMI055_Gyroscope::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_cfg[_checked_register])) {
|
||||
_last_config_check_timestamp = now;
|
||||
_checked_register = (_checked_register + 1) % size_register_cfg;
|
||||
@@ -241,6 +256,7 @@ void BMI055_Gyroscope::RunImpl()
|
||||
} else {
|
||||
// register check failed, force reset
|
||||
perf_count(_bad_register_perf);
|
||||
PX4_DEBUG("Force reset because register 0x%02hhX check failed ", (uint8_t)_register_cfg[_checked_register].reg);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
@@ -256,28 +272,28 @@ void BMI055_Gyroscope::ConfigureGyro()
|
||||
|
||||
switch (RANGE) {
|
||||
case gyro_range_2000_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 16.384f));
|
||||
_px4_gyro.set_range(math::radians(2000.f));
|
||||
_gyro_scale = math::radians(1.f / 16.384f);
|
||||
_gyro_range = math::radians(2000.f);
|
||||
break;
|
||||
|
||||
case gyro_range_1000_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 32.768f));
|
||||
_px4_gyro.set_range(math::radians(1000.f));
|
||||
_gyro_scale = math::radians(1.f / 32.768f);
|
||||
_gyro_range = math::radians(1000.f);
|
||||
break;
|
||||
|
||||
case gyro_range_500_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 65.536f));
|
||||
_px4_gyro.set_range(math::radians(500.f));
|
||||
_gyro_scale = math::radians(1.f / 65.536f);
|
||||
_gyro_range = math::radians(500.f);
|
||||
break;
|
||||
|
||||
case gyro_range_250_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 131.072f));
|
||||
_px4_gyro.set_range(math::radians(250.f));
|
||||
_gyro_scale = math::radians(1.f / 131.072f);
|
||||
_gyro_range = math::radians(250.f);
|
||||
break;
|
||||
|
||||
case gyro_range_125_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 262.144f));
|
||||
_px4_gyro.set_range(math::radians(125.f));
|
||||
_gyro_scale = math::radians(1.f / 262.144f);
|
||||
_gyro_range = math::radians(125.f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -347,7 +363,7 @@ bool BMI055_Gyroscope::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool BMI055_Gyroscope::DataReadyInterruptDisable()
|
||||
@@ -356,7 +372,7 @@ bool BMI055_Gyroscope::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
bool BMI055_Gyroscope::RegisterCheck(const register_config_t ®_cfg)
|
||||
@@ -405,37 +421,57 @@ void BMI055_Gyroscope::RegisterSetAndClearBits(Register reg, uint8_t setbits, ui
|
||||
|
||||
bool BMI055_Gyroscope::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 1, FIFO::SIZE);
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_DATA) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + samples * FIFO::DATA
|
||||
const size_t transfer_size = 1 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = timestamp_sample;
|
||||
sensor_gyro.device_id = get_device_id();
|
||||
|
||||
float gyro_sum[3] {};
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const FIFO::DATA &fifo_sample = buffer.f[i];
|
||||
|
||||
const int16_t gyro_x = combine(fifo_sample.RATE_X_MSB, fifo_sample.RATE_X_LSB);
|
||||
const int16_t gyro_y = combine(fifo_sample.RATE_Y_MSB, fifo_sample.RATE_Y_LSB);
|
||||
const int16_t gyro_z = combine(fifo_sample.RATE_Z_MSB, fifo_sample.RATE_Z_LSB);
|
||||
int16_t gyro_x = combine(fifo_sample.RATE_X_MSB, fifo_sample.RATE_X_LSB);
|
||||
int16_t gyro_y = combine(fifo_sample.RATE_Y_MSB, fifo_sample.RATE_Y_LSB);
|
||||
int16_t gyro_z = combine(fifo_sample.RATE_Z_MSB, fifo_sample.RATE_Z_LSB);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
//gyro.x[i] = gyro_x;
|
||||
gyro_y = math::negate(gyro_y);
|
||||
gyro_z = math::negate(gyro_z);
|
||||
|
||||
gyro_sum[0] += gyro_x;
|
||||
gyro_sum[1] += gyro_y;
|
||||
gyro_sum[2] += gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
sensor_gyro.x = gyro_sum[0] * _gyro_scale / samples;
|
||||
sensor_gyro.y = gyro_sum[1] * _gyro_scale / samples;
|
||||
sensor_gyro.z = gyro_sum[2] * _gyro_scale / samples;
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
rotate_3f(_rotation, sensor_gyro.x, sensor_gyro.y, sensor_gyro.z);
|
||||
|
||||
sensor_gyro.range = _gyro_range;
|
||||
sensor_gyro.temperature = NAN;
|
||||
sensor_gyro.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,10 +35,11 @@
|
||||
|
||||
#include "BMI055.hpp"
|
||||
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
|
||||
#include "Bosch_BMI055_Gyroscope_Registers.hpp"
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_gyro.h>
|
||||
|
||||
namespace Bosch::BMI055::Gyroscope
|
||||
{
|
||||
|
||||
@@ -58,15 +59,7 @@ private:
|
||||
static constexpr uint32_t RATE{2000}; // 2000 Hz
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / RATE};
|
||||
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]))};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_DATA) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (1 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{FIFO::SIZE / sizeof(FIFO::DATA)};
|
||||
|
||||
struct register_config_t {
|
||||
Register reg;
|
||||
@@ -95,7 +88,11 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_gyro_s> _sensor_gyro_pub{ORB_ID(sensor_gyro)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _gyro_scale{0.f};
|
||||
float _gyro_range{0.f};
|
||||
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME"_gyro: bad register")};
|
||||
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME"_gyro: bad transfer")};
|
||||
|
||||
@@ -35,6 +35,7 @@ px4_add_module(
|
||||
MODULE drivers__imu__bosch__bmi055
|
||||
MAIN bmi055
|
||||
COMPILE_FLAGS
|
||||
-O0
|
||||
SRCS
|
||||
Bosch_BMI055_Accelerometer_Registers.hpp
|
||||
Bosch_BMI055_Gyroscope_Registers.hpp
|
||||
@@ -48,7 +49,5 @@ px4_add_module(
|
||||
|
||||
bmi055_main.cpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -42,13 +42,13 @@ namespace Bosch::BMI085::Accelerometer
|
||||
|
||||
BMI085_Accelerometer::BMI085_Accelerometer(const I2CSPIDriverConfig &config) :
|
||||
BMI085(config),
|
||||
_px4_accel(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME"_accel: DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_accel.get_max_rate_hz());
|
||||
ConfigureSampleRate(RATE);
|
||||
}
|
||||
|
||||
BMI085_Accelerometer::~BMI085_Accelerometer()
|
||||
@@ -280,23 +280,23 @@ void BMI085_Accelerometer::ConfigureAccel()
|
||||
|
||||
switch (ACC_RANGE) {
|
||||
case acc_range_2g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1)) / 32768.f);
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1)) / 32768.f;
|
||||
_accel_range = 2.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_4g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1)) / 32768.f);
|
||||
_px4_accel.set_range(4.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1)) / 32768.f;
|
||||
_accel_range = 4.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_8g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1)) / 32768.f);
|
||||
_px4_accel.set_range(8.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1)) / 32768.f;
|
||||
_accel_range = 8.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_16g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1)) / 32768.f);
|
||||
_px4_accel.set_range(16.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1)) / 32768.f;
|
||||
_accel_range = 16.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -452,7 +452,7 @@ uint16_t BMI085_Accelerometer::FIFOReadCount()
|
||||
const uint8_t FIFO_LENGTH_0 = fifo_len_buf[2]; // fifo_byte_counter[7:0]
|
||||
const uint8_t FIFO_LENGTH_1 = fifo_len_buf[3] & 0x3F; // fifo_byte_counter[13:8]
|
||||
|
||||
return combine(FIFO_LENGTH_1, FIFO_LENGTH_0);
|
||||
return (FIFO_LENGTH_1 << 8) + FIFO_LENGTH_0;
|
||||
}
|
||||
|
||||
bool BMI085_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
@@ -465,7 +465,7 @@ bool BMI085_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t fifo_byte_counter = combine(buffer.FIFO_LENGTH_1 & 0x3F, buffer.FIFO_LENGTH_0);
|
||||
const size_t fifo_byte_counter = ((buffer.FIFO_LENGTH_1 & 0x3F) << 8) + buffer.FIFO_LENGTH_0;
|
||||
|
||||
// An empty FIFO corresponds to 0x8000
|
||||
if (fifo_byte_counter == 0x8000) {
|
||||
@@ -477,15 +477,17 @@ bool BMI085_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
|
||||
// first find all sensor data frames in the buffer
|
||||
uint8_t *data_buffer = (uint8_t *)&buffer.f[0];
|
||||
unsigned fifo_buffer_index = 0; // start of buffer
|
||||
|
||||
float accel_sum[3] {};
|
||||
int accel_samples = 0;
|
||||
|
||||
while (fifo_buffer_index < math::min(fifo_byte_counter, transfer_size - 4)) {
|
||||
// look for header signature (first 6 bits) followed by two bits indicating the status of INT1 and INT2
|
||||
switch (data_buffer[fifo_buffer_index] & 0xFC) {
|
||||
@@ -494,16 +496,23 @@ bool BMI085_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
// Frame length: 7 bytes (1 byte header + 6 bytes payload)
|
||||
|
||||
FIFO::DATA *fifo_sample = (FIFO::DATA *)&data_buffer[fifo_buffer_index];
|
||||
const int16_t accel_x = combine(fifo_sample->ACC_X_MSB, fifo_sample->ACC_X_LSB);
|
||||
const int16_t accel_y = combine(fifo_sample->ACC_Y_MSB, fifo_sample->ACC_Y_LSB);
|
||||
const int16_t accel_z = combine(fifo_sample->ACC_Z_MSB, fifo_sample->ACC_Z_LSB);
|
||||
int16_t accel_x = combine(fifo_sample->ACC_X_MSB, fifo_sample->ACC_X_LSB);
|
||||
int16_t accel_y = combine(fifo_sample->ACC_Y_MSB, fifo_sample->ACC_Y_LSB);
|
||||
int16_t accel_z = combine(fifo_sample->ACC_Z_MSB, fifo_sample->ACC_Z_LSB);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = math::negate(accel_y);
|
||||
accel.z[accel.samples] = math::negate(accel_z);
|
||||
accel.samples++;
|
||||
// accel_x = accel_x;
|
||||
accel_y = math::negate(accel_y);
|
||||
accel_z = math::negate(accel_z);
|
||||
|
||||
rotate_3i(_rotation, accel_x, accel_y, accel_z);
|
||||
|
||||
accel_sum[0] += accel_x;
|
||||
accel_sum[1] += accel_y;
|
||||
accel_sum[2] += accel_z;
|
||||
|
||||
accel_samples++;
|
||||
|
||||
fifo_buffer_index += 7; // move forward to next record
|
||||
}
|
||||
@@ -543,11 +552,19 @@ bool BMI085_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
}
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
if (accel_samples > 0) {
|
||||
sensor_accel.x = (accel_sum[0] / accel_samples) * _accel_scale;
|
||||
sensor_accel.y = (accel_sum[1] / accel_samples) * _accel_scale;
|
||||
sensor_accel.z = (accel_sum[2] / accel_samples) * _accel_scale;
|
||||
|
||||
sensor_accel.range = _accel_range;
|
||||
sensor_accel.temperature = _temperature;
|
||||
sensor_accel.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -594,7 +611,7 @@ void BMI085_Accelerometer::UpdateTemperature()
|
||||
float temperature = (Temp_int11 * 0.125f) + 23.f; // Temp_int11 * 0.125°C/LSB + 23°C
|
||||
|
||||
if (PX4_ISFINITE(temperature)) {
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_temperature = temperature;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
|
||||
@@ -35,10 +35,11 @@
|
||||
|
||||
#include "BMI085.hpp"
|
||||
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
|
||||
#include "Bosch_BMI085_Accelerometer_Registers.hpp"
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_accel.h>
|
||||
|
||||
namespace Bosch::BMI085::Accelerometer
|
||||
{
|
||||
|
||||
@@ -58,7 +59,7 @@ private:
|
||||
static constexpr uint32_t RATE{1600}; // 1600 Hz
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / RATE};
|
||||
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{FIFO::SIZE / sizeof(FIFO::DATA)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
@@ -101,7 +102,13 @@ private:
|
||||
|
||||
void UpdateTemperature();
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
uORB::PublicationMulti<sensor_accel_s> _sensor_accel_pub{ORB_ID(sensor_accel)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _accel_scale{0.f};
|
||||
float _accel_range{0.f};
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME"_accel: bad register")};
|
||||
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME"_accel: bad transfer")};
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
#include "BMI085_Gyroscope.hpp"
|
||||
|
||||
#include <px4_platform/board_dma_alloc.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
namespace Bosch::BMI085::Gyroscope
|
||||
@@ -42,13 +40,13 @@ namespace Bosch::BMI085::Gyroscope
|
||||
|
||||
BMI085_Gyroscope::BMI085_Gyroscope(const I2CSPIDriverConfig &config) :
|
||||
BMI085(config),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME"_gyro: DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
ConfigureSampleRate(RATE);
|
||||
}
|
||||
|
||||
BMI085_Gyroscope::~BMI085_Gyroscope()
|
||||
@@ -257,28 +255,28 @@ void BMI085_Gyroscope::ConfigureGyro()
|
||||
|
||||
switch (GYRO_RANGE) {
|
||||
case gyro_range_2000_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 16.384f));
|
||||
_px4_gyro.set_range(math::radians(2000.f));
|
||||
_gyro_scale = math::radians(1.f / 16.384f);
|
||||
_gyro_range = math::radians(2000.f);
|
||||
break;
|
||||
|
||||
case gyro_range_1000_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 32.768f));
|
||||
_px4_gyro.set_range(math::radians(1000.f));
|
||||
_gyro_scale = math::radians(1.f / 32.768f);
|
||||
_gyro_range = math::radians(1000.f);
|
||||
break;
|
||||
|
||||
case gyro_range_500_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 65.536f));
|
||||
_px4_gyro.set_range(math::radians(500.f));
|
||||
_gyro_scale = math::radians(1.f / 65.536f);
|
||||
_gyro_range = math::radians(500.f);
|
||||
break;
|
||||
|
||||
case gyro_range_250_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 131.072f));
|
||||
_px4_gyro.set_range(math::radians(250.f));
|
||||
_gyro_scale = math::radians(1.f / 131.072f);
|
||||
_gyro_range = math::radians(250.f);
|
||||
break;
|
||||
|
||||
case gyro_range_125_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 262.144f));
|
||||
_px4_gyro.set_range(math::radians(125.f));
|
||||
_gyro_scale = math::radians(1.f / 262.144f);
|
||||
_gyro_range = math::radians(125.f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -414,29 +412,43 @@ bool BMI085_Gyroscope::FIFORead(const hrt_abstime ×tamp_sample, uint8_t sam
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = timestamp_sample;
|
||||
sensor_gyro.device_id = get_device_id();
|
||||
|
||||
float gyro_sum[3] {};
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const FIFO::DATA &fifo_sample = buffer.f[i];
|
||||
|
||||
const int16_t gyro_x = combine(fifo_sample.RATE_X_MSB, fifo_sample.RATE_X_LSB);
|
||||
const int16_t gyro_y = combine(fifo_sample.RATE_Y_MSB, fifo_sample.RATE_Y_LSB);
|
||||
const int16_t gyro_z = combine(fifo_sample.RATE_Z_MSB, fifo_sample.RATE_Z_LSB);
|
||||
int16_t gyro_x = combine(fifo_sample.RATE_X_MSB, fifo_sample.RATE_X_LSB);
|
||||
int16_t gyro_y = combine(fifo_sample.RATE_Y_MSB, fifo_sample.RATE_Y_LSB);
|
||||
int16_t gyro_z = combine(fifo_sample.RATE_Z_MSB, fifo_sample.RATE_Z_LSB);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
//gyro.x[i] = gyro_x;
|
||||
gyro_y = math::negate(gyro_y);
|
||||
gyro_z = math::negate(gyro_z);
|
||||
|
||||
rotate_3i(_rotation, gyro_x, gyro_y, gyro_z);
|
||||
|
||||
gyro_sum[0] += gyro_x * _gyro_scale;
|
||||
gyro_sum[1] += gyro_y * _gyro_scale;
|
||||
gyro_sum[2] += gyro_z * _gyro_scale;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
sensor_gyro.x = gyro_sum[0] / samples;
|
||||
sensor_gyro.y = gyro_sum[1] / samples;
|
||||
sensor_gyro.z = gyro_sum[2] / samples;
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
sensor_gyro.range = _gyro_range;
|
||||
sensor_gyro.temperature = NAN;
|
||||
sensor_gyro.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,10 +35,11 @@
|
||||
|
||||
#include "BMI085.hpp"
|
||||
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
|
||||
#include "Bosch_BMI085_Gyroscope_Registers.hpp"
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_gyro.h>
|
||||
|
||||
namespace Bosch::BMI085::Gyroscope
|
||||
{
|
||||
|
||||
@@ -58,7 +59,7 @@ private:
|
||||
static constexpr uint32_t RATE{2000}; // 2000 Hz
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / RATE};
|
||||
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{FIFO::SIZE / sizeof(FIFO::DATA)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
@@ -95,7 +96,11 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_gyro_s> _sensor_gyro_pub{ORB_ID(sensor_gyro)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _gyro_scale{0.f};
|
||||
float _gyro_range{0.f};
|
||||
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME"_gyro: bad register")};
|
||||
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME"_gyro: bad transfer")};
|
||||
|
||||
@@ -48,7 +48,5 @@ px4_add_module(
|
||||
|
||||
bmi085_main.cpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -42,13 +42,13 @@ namespace Bosch::BMI088::Accelerometer
|
||||
|
||||
BMI088_Accelerometer::BMI088_Accelerometer(const I2CSPIDriverConfig &config) :
|
||||
BMI088(config),
|
||||
_px4_accel(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME"_accel: DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_accel.get_max_rate_hz());
|
||||
ConfigureSampleRate(RATE);
|
||||
}
|
||||
|
||||
BMI088_Accelerometer::~BMI088_Accelerometer()
|
||||
@@ -286,23 +286,23 @@ void BMI088_Accelerometer::ConfigureAccel()
|
||||
|
||||
switch (ACC_RANGE) {
|
||||
case acc_range_3g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f);
|
||||
_px4_accel.set_range(3.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f;
|
||||
_accel_range = 3.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_6g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f);
|
||||
_px4_accel.set_range(6.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f;
|
||||
_accel_range = 6.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_12g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f);
|
||||
_px4_accel.set_range(12.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f;
|
||||
_accel_range = 12.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_24g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f);
|
||||
_px4_accel.set_range(24.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f;
|
||||
_accel_range = 24.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -458,7 +458,7 @@ uint16_t BMI088_Accelerometer::FIFOReadCount()
|
||||
const uint8_t FIFO_LENGTH_0 = fifo_len_buf[2]; // fifo_byte_counter[7:0]
|
||||
const uint8_t FIFO_LENGTH_1 = fifo_len_buf[3] & 0x3F; // fifo_byte_counter[13:8]
|
||||
|
||||
return combine(FIFO_LENGTH_1, FIFO_LENGTH_0);
|
||||
return (FIFO_LENGTH_1 << 8) + FIFO_LENGTH_0;
|
||||
}
|
||||
|
||||
bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
@@ -471,7 +471,7 @@ bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t fifo_byte_counter = combine(buffer.FIFO_LENGTH_1 & 0x3F, buffer.FIFO_LENGTH_0);
|
||||
const size_t fifo_byte_counter = ((buffer.FIFO_LENGTH_1 & 0x3F) << 8) + buffer.FIFO_LENGTH_0;
|
||||
|
||||
// An empty FIFO corresponds to 0x8000
|
||||
if (fifo_byte_counter == 0x8000) {
|
||||
@@ -483,15 +483,17 @@ bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
|
||||
// first find all sensor data frames in the buffer
|
||||
uint8_t *data_buffer = (uint8_t *)&buffer.f[0];
|
||||
unsigned fifo_buffer_index = 0; // start of buffer
|
||||
|
||||
float accel_sum[3] {};
|
||||
int accel_samples = 0;
|
||||
|
||||
while (fifo_buffer_index < math::min(fifo_byte_counter, transfer_size - 4)) {
|
||||
// look for header signature (first 6 bits) followed by two bits indicating the status of INT1 and INT2
|
||||
switch (data_buffer[fifo_buffer_index] & 0xFC) {
|
||||
@@ -500,16 +502,23 @@ bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
// Frame length: 7 bytes (1 byte header + 6 bytes payload)
|
||||
|
||||
FIFO::DATA *fifo_sample = (FIFO::DATA *)&data_buffer[fifo_buffer_index];
|
||||
const int16_t accel_x = combine(fifo_sample->ACC_X_MSB, fifo_sample->ACC_X_LSB);
|
||||
const int16_t accel_y = combine(fifo_sample->ACC_Y_MSB, fifo_sample->ACC_Y_LSB);
|
||||
const int16_t accel_z = combine(fifo_sample->ACC_Z_MSB, fifo_sample->ACC_Z_LSB);
|
||||
int16_t accel_x = combine(fifo_sample->ACC_X_MSB, fifo_sample->ACC_X_LSB);
|
||||
int16_t accel_y = combine(fifo_sample->ACC_Y_MSB, fifo_sample->ACC_Y_LSB);
|
||||
int16_t accel_z = combine(fifo_sample->ACC_Z_MSB, fifo_sample->ACC_Z_LSB);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
// accel_x = accel_x;
|
||||
accel_y = math::negate(accel_y);
|
||||
accel_z = math::negate(accel_z);
|
||||
|
||||
rotate_3i(_rotation, accel_x, accel_y, accel_z);
|
||||
|
||||
accel_sum[0] += accel_x;
|
||||
accel_sum[1] += accel_y;
|
||||
accel_sum[2] += accel_z;
|
||||
|
||||
accel_samples++;
|
||||
|
||||
fifo_buffer_index += 7; // move forward to next record
|
||||
}
|
||||
@@ -549,11 +558,19 @@ bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
}
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
if (accel_samples > 0) {
|
||||
sensor_accel.x = (accel_sum[0] / accel_samples) * _accel_scale;
|
||||
sensor_accel.y = (accel_sum[1] / accel_samples) * _accel_scale;
|
||||
sensor_accel.z = (accel_sum[2] / accel_samples) * _accel_scale;
|
||||
|
||||
sensor_accel.range = _accel_range;
|
||||
sensor_accel.temperature = _temperature;
|
||||
sensor_accel.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -600,7 +617,7 @@ void BMI088_Accelerometer::UpdateTemperature()
|
||||
float temperature = (Temp_int11 * 0.125f) + 23.f; // Temp_int11 * 0.125°C/LSB + 23°C
|
||||
|
||||
if (PX4_ISFINITE(temperature)) {
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_temperature = temperature;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,10 +35,11 @@
|
||||
|
||||
#include "BMI088.hpp"
|
||||
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
|
||||
#include "Bosch_BMI088_Accelerometer_Registers.hpp"
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_accel.h>
|
||||
|
||||
namespace Bosch::BMI088::Accelerometer
|
||||
{
|
||||
|
||||
@@ -58,7 +59,7 @@ private:
|
||||
static constexpr uint32_t RATE{1600}; // 1600 Hz
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / RATE};
|
||||
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{FIFO::SIZE / sizeof(FIFO::DATA)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
@@ -101,7 +102,13 @@ private:
|
||||
|
||||
void UpdateTemperature();
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
uORB::PublicationMulti<sensor_accel_s> _sensor_accel_pub{ORB_ID(sensor_accel)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _accel_scale{0.f};
|
||||
float _accel_range{0.f};
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME"_accel: bad register")};
|
||||
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME"_accel: bad transfer")};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
#include "BMI088_Gyroscope.hpp"
|
||||
|
||||
#include <px4_platform/board_dma_alloc.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
namespace Bosch::BMI088::Gyroscope
|
||||
@@ -42,13 +40,13 @@ namespace Bosch::BMI088::Gyroscope
|
||||
|
||||
BMI088_Gyroscope::BMI088_Gyroscope(const I2CSPIDriverConfig &config) :
|
||||
BMI088(config),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME"_gyro: DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
ConfigureSampleRate(RATE);
|
||||
}
|
||||
|
||||
BMI088_Gyroscope::~BMI088_Gyroscope()
|
||||
@@ -257,28 +255,28 @@ void BMI088_Gyroscope::ConfigureGyro()
|
||||
|
||||
switch (GYRO_RANGE) {
|
||||
case gyro_range_2000_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 16.384f));
|
||||
_px4_gyro.set_range(math::radians(2000.f));
|
||||
_gyro_scale = math::radians(1.f / 16.384f);
|
||||
_gyro_range = math::radians(2000.f);
|
||||
break;
|
||||
|
||||
case gyro_range_1000_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 32.768f));
|
||||
_px4_gyro.set_range(math::radians(1000.f));
|
||||
_gyro_scale = math::radians(1.f / 32.768f);
|
||||
_gyro_range = math::radians(1000.f);
|
||||
break;
|
||||
|
||||
case gyro_range_500_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 65.536f));
|
||||
_px4_gyro.set_range(math::radians(500.f));
|
||||
_gyro_scale = math::radians(1.f / 65.536f);
|
||||
_gyro_range = math::radians(500.f);
|
||||
break;
|
||||
|
||||
case gyro_range_250_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 131.072f));
|
||||
_px4_gyro.set_range(math::radians(250.f));
|
||||
_gyro_scale = math::radians(1.f / 131.072f);
|
||||
_gyro_range = math::radians(250.f);
|
||||
break;
|
||||
|
||||
case gyro_range_125_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 262.144f));
|
||||
_px4_gyro.set_range(math::radians(125.f));
|
||||
_gyro_scale = math::radians(1.f / 262.144f);
|
||||
_gyro_range = math::radians(125.f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -414,29 +412,43 @@ bool BMI088_Gyroscope::FIFORead(const hrt_abstime ×tamp_sample, uint8_t sam
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = timestamp_sample;
|
||||
sensor_gyro.device_id = get_device_id();
|
||||
|
||||
float gyro_sum[3] {};
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const FIFO::DATA &fifo_sample = buffer.f[i];
|
||||
|
||||
const int16_t gyro_x = combine(fifo_sample.RATE_X_MSB, fifo_sample.RATE_X_LSB);
|
||||
const int16_t gyro_y = combine(fifo_sample.RATE_Y_MSB, fifo_sample.RATE_Y_LSB);
|
||||
const int16_t gyro_z = combine(fifo_sample.RATE_Z_MSB, fifo_sample.RATE_Z_LSB);
|
||||
int16_t gyro_x = combine(fifo_sample.RATE_X_MSB, fifo_sample.RATE_X_LSB);
|
||||
int16_t gyro_y = combine(fifo_sample.RATE_Y_MSB, fifo_sample.RATE_Y_LSB);
|
||||
int16_t gyro_z = combine(fifo_sample.RATE_Z_MSB, fifo_sample.RATE_Z_LSB);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
//gyro.x[i] = gyro_x;
|
||||
gyro_y = math::negate(gyro_y);
|
||||
gyro_z = math::negate(gyro_z);
|
||||
|
||||
rotate_3i(_rotation, gyro_x, gyro_y, gyro_z);
|
||||
|
||||
gyro_sum[0] += gyro_x * _gyro_scale;
|
||||
gyro_sum[1] += gyro_y * _gyro_scale;
|
||||
gyro_sum[2] += gyro_z * _gyro_scale;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
sensor_gyro.x = gyro_sum[0] / samples;
|
||||
sensor_gyro.y = gyro_sum[1] / samples;
|
||||
sensor_gyro.z = gyro_sum[2] / samples;
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
sensor_gyro.range = _gyro_range;
|
||||
sensor_gyro.temperature = NAN;
|
||||
sensor_gyro.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,10 +35,11 @@
|
||||
|
||||
#include "BMI088.hpp"
|
||||
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
|
||||
#include "Bosch_BMI088_Gyroscope_Registers.hpp"
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_gyro.h>
|
||||
|
||||
namespace Bosch::BMI088::Gyroscope
|
||||
{
|
||||
|
||||
@@ -58,7 +59,7 @@ private:
|
||||
static constexpr uint32_t RATE{2000}; // 2000 Hz
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / RATE};
|
||||
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{FIFO::SIZE / sizeof(FIFO::DATA)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
@@ -95,7 +96,11 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_gyro_s> _sensor_gyro_pub{ORB_ID(sensor_gyro)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _gyro_scale{0.f};
|
||||
float _gyro_range{0.f};
|
||||
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME"_gyro: bad register")};
|
||||
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME"_gyro: bad transfer")};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2019-2020 PX4 Development Team. All rights reserved.
|
||||
# Copyright (c) 2019-2022 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
@@ -48,7 +48,5 @@ px4_add_module(
|
||||
|
||||
bmi088_main.cpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -76,10 +76,7 @@ int BMI088::init()
|
||||
return ret;
|
||||
}
|
||||
|
||||
int res = Reset() ? 0 : -1;
|
||||
_state = STATE::SELFTEST;
|
||||
|
||||
return res;
|
||||
return Reset() ? 0 : -1;
|
||||
}
|
||||
|
||||
bool BMI088::Reset()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -65,23 +65,16 @@ protected:
|
||||
hrt_abstime _last_config_check_timestamp{0};
|
||||
hrt_abstime _temperature_update_timestamp{0};
|
||||
int _failure_count{0};
|
||||
int _overflow_data_size_count{0};
|
||||
int _overflow_fifo_max_samples_count{0};
|
||||
int _fifo_read_error_count{0};
|
||||
int _empty_count{0};
|
||||
int _total_failure_count{0};
|
||||
|
||||
|
||||
px4::atomic<hrt_abstime> _drdy_timestamp_sample{0};
|
||||
bool _data_ready_interrupt_enabled{false};
|
||||
|
||||
enum class STATE : uint8_t {
|
||||
SELFTEST,
|
||||
RESET,
|
||||
WAIT_FOR_RESET,
|
||||
CONFIGURE,
|
||||
FIFO_READ,
|
||||
} _state{STATE::SELFTEST};
|
||||
} _state{STATE::RESET};
|
||||
|
||||
uint16_t _fifo_empty_interval_us{2500}; // 2500 us / 400 Hz transfer interval
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -39,15 +39,16 @@ using namespace time_literals;
|
||||
|
||||
namespace Bosch::BMI088::Accelerometer
|
||||
{
|
||||
|
||||
BMI088_Accelerometer::BMI088_Accelerometer(const I2CSPIDriverConfig &config) :
|
||||
BMI088(config),
|
||||
_px4_accel(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME"_accel: DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(1600);
|
||||
ConfigureSampleRate(RATE);
|
||||
}
|
||||
|
||||
BMI088_Accelerometer::~BMI088_Accelerometer()
|
||||
@@ -80,32 +81,21 @@ void BMI088_Accelerometer::print_status()
|
||||
perf_print_counter(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
uint8_t BMI088_Accelerometer::RegisterRead(Register reg)
|
||||
{
|
||||
uint8_t add = static_cast<uint8_t>(reg);
|
||||
uint8_t cmd[2] = {add, 0};
|
||||
transfer(&cmd[0], 1, &cmd[1], 1);
|
||||
return cmd[1];
|
||||
}
|
||||
|
||||
uint8_t BMI088_Accelerometer::RegisterWrite(Register reg, uint8_t value)
|
||||
{
|
||||
uint8_t add = static_cast<uint8_t>(reg);
|
||||
uint8_t cmd[2] = { add, value};
|
||||
return transfer(cmd, sizeof(cmd), nullptr, 0);
|
||||
}
|
||||
|
||||
int BMI088_Accelerometer::probe()
|
||||
{
|
||||
const uint8_t ACC_CHIP_ID = RegisterRead(Register::ACC_CHIP_ID);
|
||||
|
||||
if (ACC_CHIP_ID != ID) {
|
||||
if (ACC_CHIP_ID == ID_088) {
|
||||
DEVICE_DEBUG("BMI088 Accel");
|
||||
|
||||
} else if (ACC_CHIP_ID == ID_090L) {
|
||||
DEVICE_DEBUG("BMI090L Accel");
|
||||
|
||||
} else {
|
||||
DEVICE_DEBUG("unexpected ACC_CHIP_ID 0x%02x", ACC_CHIP_ID);
|
||||
return PX4_ERROR;
|
||||
}
|
||||
|
||||
PX4_WARN("Probe success, ACC_CHIP_ID: 0x%02x", ACC_CHIP_ID);
|
||||
|
||||
return PX4_OK;
|
||||
}
|
||||
|
||||
@@ -114,27 +104,17 @@ void BMI088_Accelerometer::RunImpl()
|
||||
const hrt_abstime now = hrt_absolute_time();
|
||||
|
||||
switch (_state) {
|
||||
case STATE::SELFTEST:
|
||||
//PX4_WARN("Selftest state");
|
||||
//SelfTest();
|
||||
_state = STATE::RESET;
|
||||
ScheduleDelayed(10_ms);
|
||||
break;
|
||||
|
||||
case STATE::RESET:
|
||||
// ACC_SOFTRESET: Writing a value of 0xB6 to this register resets the sensor
|
||||
RegisterWrite(Register::ACC_SOFTRESET, 0xB6);
|
||||
_reset_timestamp = now;
|
||||
_failure_count = 0;
|
||||
_state = STATE::WAIT_FOR_RESET;
|
||||
|
||||
|
||||
ScheduleDelayed(1_ms); // Following a delay of 1 ms, all configuration settings are overwritten with their reset value.
|
||||
|
||||
break;
|
||||
|
||||
case STATE::WAIT_FOR_RESET:
|
||||
if (RegisterRead(Register::ACC_CHIP_ID) == ID) {
|
||||
if ((RegisterRead(Register::ACC_CHIP_ID) == ID_088) || (RegisterRead(Register::ACC_CHIP_ID) == ID_090L)) {
|
||||
// ACC_PWR_CONF: Power on sensor
|
||||
RegisterWrite(Register::ACC_PWR_CONF, 0);
|
||||
|
||||
@@ -191,36 +171,125 @@ void BMI088_Accelerometer::RunImpl()
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
SimpleFIFORead(now);
|
||||
hrt_abstime timestamp_sample = now;
|
||||
uint8_t samples = 0;
|
||||
|
||||
if (_data_ready_interrupt_enabled) {
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_samples;
|
||||
|
||||
} else {
|
||||
perf_count(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
// push backup schedule back
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
}
|
||||
|
||||
if (samples == 0) {
|
||||
// check current FIFO count
|
||||
const uint16_t fifo_byte_counter = FIFOReadCount();
|
||||
|
||||
if (fifo_byte_counter >= FIFO::SIZE) {
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else if ((fifo_byte_counter == 0) || (fifo_byte_counter == 0x8000)) {
|
||||
// An empty FIFO corresponds to 0x8000
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
} else {
|
||||
samples = fifo_byte_counter / sizeof(FIFO::DATA);
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_samples + 1) {
|
||||
timestamp_sample -= static_cast<int>(FIFO_SAMPLE_DT);
|
||||
samples--;
|
||||
}
|
||||
|
||||
if (samples > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
samples = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples >= 1) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
_failure_count++;
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_cfg[_checked_register])) {
|
||||
_last_config_check_timestamp = now;
|
||||
_checked_register = (_checked_register + 1) % size_register_cfg;
|
||||
|
||||
} else {
|
||||
// register check failed, force reset
|
||||
perf_count(_bad_register_perf);
|
||||
Reset();
|
||||
}
|
||||
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BMI088_Accelerometer::ConfigureAccel()
|
||||
{
|
||||
//PX4_WARN("ConfigureAccel");
|
||||
const uint8_t ACC_RANGE = RegisterRead(Register::ACC_RANGE) & (Bit1 | Bit0);
|
||||
|
||||
switch (ACC_RANGE) {
|
||||
case acc_range_3g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f);
|
||||
_px4_accel.set_range(3.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f;
|
||||
_accel_range = 3.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_6g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f);
|
||||
_px4_accel.set_range(6.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f;
|
||||
_accel_range = 6.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_12g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f);
|
||||
_px4_accel.set_range(12.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f;
|
||||
_accel_range = 12.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
|
||||
case acc_range_24g:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f);
|
||||
_px4_accel.set_range(24.f * CONSTANTS_ONE_G);
|
||||
_accel_scale = CONSTANTS_ONE_G * (powf(2, ACC_RANGE + 1) * 1.5f) / 32768.f;
|
||||
_accel_range = 24.f * CONSTANTS_ONE_G;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -231,15 +300,11 @@ void BMI088_Accelerometer::ConfigureSampleRate(int sample_rate)
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
PX4_WARN("_fifo_empty_interval_us %d", _fifo_empty_interval_us);
|
||||
_fifo_samples = math::min((float)_fifo_empty_interval_us / (1e6f / RATE), (float)FIFO_MAX_SAMPLES);
|
||||
|
||||
PX4_WARN("_fifo_samples %d", _fifo_samples);
|
||||
// recompute FIFO empty interval (us) with actual sample limit
|
||||
_fifo_empty_interval_us = _fifo_samples * (1e6f / RATE);
|
||||
|
||||
PX4_WARN("_fifo_empty_interval_us %d", _fifo_empty_interval_us);
|
||||
//PX4_WARN("_fifo_samples %d", _fifo_samples);
|
||||
ConfigureFIFOWatermark(_fifo_samples);
|
||||
}
|
||||
|
||||
@@ -265,7 +330,6 @@ void BMI088_Accelerometer::ConfigureFIFOWatermark(uint8_t samples)
|
||||
|
||||
bool BMI088_Accelerometer::Configure()
|
||||
{
|
||||
|
||||
// first set and clear all configured register bits
|
||||
for (const auto ®_cfg : _register_cfg) {
|
||||
RegisterSetAndClearBits(reg_cfg.reg, reg_cfg.set_bits, reg_cfg.clear_bits);
|
||||
@@ -293,6 +357,7 @@ int BMI088_Accelerometer::DataReadyInterruptCallback(int irq, void *context, voi
|
||||
|
||||
void BMI088_Accelerometer::DataReady()
|
||||
{
|
||||
_drdy_timestamp_sample.store(hrt_absolute_time());
|
||||
ScheduleNow();
|
||||
}
|
||||
|
||||
@@ -334,6 +399,20 @@ bool BMI088_Accelerometer::RegisterCheck(const register_config_t ®_cfg)
|
||||
return success;
|
||||
}
|
||||
|
||||
uint8_t BMI088_Accelerometer::RegisterRead(Register reg)
|
||||
{
|
||||
uint8_t cmd = static_cast<uint8_t>(reg);
|
||||
uint8_t value = 0;
|
||||
transfer(&cmd, 1, &value, 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
void BMI088_Accelerometer::RegisterWrite(Register reg, uint8_t value)
|
||||
{
|
||||
uint8_t cmd[2] { (uint8_t)reg, value };
|
||||
transfer(cmd, sizeof(cmd), nullptr, 0);
|
||||
}
|
||||
|
||||
void BMI088_Accelerometer::RegisterSetAndClearBits(Register reg, uint8_t setbits, uint8_t clearbits)
|
||||
{
|
||||
const uint8_t orig_val = RegisterRead(reg);
|
||||
@@ -349,10 +428,9 @@ uint16_t BMI088_Accelerometer::FIFOReadCount()
|
||||
{
|
||||
// FIFO length registers FIFO_LENGTH_1 and FIFO_LENGTH_0 contain the 14 bit FIFO byte
|
||||
uint8_t fifo_len_buf[2] {};
|
||||
fifo_len_buf[0] = static_cast<uint8_t>(Register::FIFO_LENGTH_0) | DIR_READ;
|
||||
// fifo_len_buf[1] dummy byte
|
||||
uint8_t cmd = static_cast<uint8_t>(Register::FIFO_LENGTH_0);
|
||||
|
||||
if (transfer(&fifo_len_buf[0], 1, &fifo_len_buf[0], 2) != PX4_OK) {
|
||||
if (transfer(&cmd, 1, fifo_len_buf, sizeof(fifo_len_buf)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
@@ -360,21 +438,20 @@ uint16_t BMI088_Accelerometer::FIFOReadCount()
|
||||
const uint8_t FIFO_LENGTH_0 = fifo_len_buf[0]; // fifo_byte_counter[7:0]
|
||||
const uint8_t FIFO_LENGTH_1 = fifo_len_buf[1] & 0x3F; // fifo_byte_counter[13:8]
|
||||
|
||||
return combine(FIFO_LENGTH_1, FIFO_LENGTH_0);
|
||||
return (FIFO_LENGTH_1 << 8) + FIFO_LENGTH_0;
|
||||
}
|
||||
|
||||
bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 4, FIFO::SIZE);
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 2, FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, 1, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
if (transfer(&buffer.cmd, 1, (uint8_t *)&buffer.FIFO_LENGTH_0, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
//PX4_WARN("Accel transfer success");
|
||||
const size_t fifo_byte_counter = combine(buffer.FIFO_LENGTH_1 & 0x3F, buffer.FIFO_LENGTH_0);
|
||||
const size_t fifo_byte_counter = ((buffer.FIFO_LENGTH_1 & 0x3F) << 8) + buffer.FIFO_LENGTH_0;
|
||||
|
||||
// An empty FIFO corresponds to 0x8000
|
||||
if (fifo_byte_counter == 0x8000) {
|
||||
@@ -386,15 +463,17 @@ bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
|
||||
// first find all sensor data frames in the buffer
|
||||
uint8_t *data_buffer = (uint8_t *)&buffer.f[0];
|
||||
unsigned fifo_buffer_index = 0; // start of buffer
|
||||
|
||||
float accel_sum[3] {};
|
||||
int accel_samples = 0;
|
||||
|
||||
while (fifo_buffer_index < math::min(fifo_byte_counter, transfer_size - 4)) {
|
||||
// look for header signature (first 6 bits) followed by two bits indicating the status of INT1 and INT2
|
||||
switch (data_buffer[fifo_buffer_index] & 0xFC) {
|
||||
@@ -403,16 +482,23 @@ bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
// Frame length: 7 bytes (1 byte header + 6 bytes payload)
|
||||
|
||||
FIFO::DATA *fifo_sample = (FIFO::DATA *)&data_buffer[fifo_buffer_index];
|
||||
const int16_t accel_x = combine(fifo_sample->ACC_X_MSB, fifo_sample->ACC_X_LSB);
|
||||
const int16_t accel_y = combine(fifo_sample->ACC_Y_MSB, fifo_sample->ACC_Y_LSB);
|
||||
const int16_t accel_z = combine(fifo_sample->ACC_Z_MSB, fifo_sample->ACC_Z_LSB);
|
||||
int16_t accel_x = combine(fifo_sample->ACC_X_MSB, fifo_sample->ACC_X_LSB);
|
||||
int16_t accel_y = combine(fifo_sample->ACC_Y_MSB, fifo_sample->ACC_Y_LSB);
|
||||
int16_t accel_z = combine(fifo_sample->ACC_Z_MSB, fifo_sample->ACC_Z_LSB);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
// accel_x = accel_x;
|
||||
accel_y = math::negate(accel_y);
|
||||
accel_z = math::negate(accel_z);
|
||||
|
||||
rotate_3i(_rotation, accel_x, accel_y, accel_z);
|
||||
|
||||
accel_sum[0] += accel_x;
|
||||
accel_sum[1] += accel_y;
|
||||
accel_sum[2] += accel_z;
|
||||
|
||||
accel_samples++;
|
||||
|
||||
fifo_buffer_index += 7; // move forward to next record
|
||||
}
|
||||
@@ -452,130 +538,25 @@ bool BMI088_Accelerometer::FIFORead(const hrt_abstime ×tamp_sample, uint8_t
|
||||
}
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
if (accel_samples > 0) {
|
||||
sensor_accel.x = (accel_sum[0] / accel_samples) * _accel_scale;
|
||||
sensor_accel.y = (accel_sum[1] / accel_samples) * _accel_scale;
|
||||
sensor_accel.z = (accel_sum[2] / accel_samples) * _accel_scale;
|
||||
|
||||
sensor_accel.range = _accel_range;
|
||||
sensor_accel.temperature = _temperature;
|
||||
sensor_accel.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BMI088_Accelerometer::SimpleFIFORead(const hrt_abstime ×tamp_sample)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
int fifo_fill_level = 0;
|
||||
|
||||
uint8_t data_o[2] = { 0, 0 };
|
||||
uint8_t data_i[1] = {static_cast<uint8_t>(Register::FIFO_LENGTH_0)};
|
||||
data_i[0] = static_cast<uint8_t>(Register::FIFO_LENGTH_0);
|
||||
|
||||
transfer(&data_i[0], 1, &data_o[0], 2);
|
||||
fifo_fill_level = data_o[0] + (data_o[1] << 8);
|
||||
|
||||
if (fifo_fill_level & 0x8000) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int n_frames_to_read = 6;
|
||||
|
||||
// don't read more than 6 frames at a time
|
||||
if (fifo_fill_level > n_frames_to_read * 7) {
|
||||
fifo_fill_level = n_frames_to_read * 7;
|
||||
}
|
||||
|
||||
if (fifo_fill_level == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t data[fifo_fill_level];
|
||||
|
||||
data[0] = static_cast<uint8_t>(Register::FIFO_DATA);
|
||||
|
||||
if (transfer(&data[0], 1, &data[0], fifo_fill_level) != PX4_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t *p = &data[0];
|
||||
|
||||
while (fifo_fill_level >= 7) {
|
||||
uint8_t frame_len = 2;
|
||||
|
||||
switch (p[0] & 0xFC) {
|
||||
case 0x84: {
|
||||
// accel frame
|
||||
frame_len = 7;
|
||||
const uint8_t *d = p + 1;
|
||||
int16_t xyz[3] {
|
||||
int16_t(uint16_t(d[0] | (d[1] << 8))),
|
||||
int16_t(uint16_t(d[2] | (d[3] << 8))),
|
||||
int16_t(uint16_t(d[4] | (d[5] << 8)))
|
||||
};
|
||||
|
||||
|
||||
const int16_t tX[3] = {1, 0, 0};
|
||||
const int16_t tY[3] = {0, -1, 0};
|
||||
const int16_t tZ[3] = {0, 0, -1};
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float z = 0;
|
||||
|
||||
x = xyz[0] * tX[0] + xyz[1] * tX[1] + xyz[2] * tX[2];
|
||||
y = xyz[0] * tY[0] + xyz[1] * tY[1] + xyz[2] * tY[2];
|
||||
z = xyz[0] * tZ[0] + xyz[1] * tZ[1] + xyz[2] * tZ[2];
|
||||
|
||||
accel.x[accel.samples] = x;
|
||||
accel.y[accel.samples] = y;
|
||||
accel.z[accel.samples] = z;
|
||||
accel.samples++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x40:
|
||||
// skip frame
|
||||
frame_len = 2;
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
// sensortime frame
|
||||
frame_len = 4;
|
||||
break;
|
||||
|
||||
case 0x48:
|
||||
// fifo config frame
|
||||
frame_len = 2;
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
// sample drop frame
|
||||
frame_len = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
p += frame_len;
|
||||
fifo_fill_level -= frame_len;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
//PX4_WARN("accel.samples: %d", accel.samples);
|
||||
_px4_accel.updateFIFO(accel);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BMI088_Accelerometer::FIFOReset()
|
||||
{
|
||||
perf_count(_fifo_reset_perf);
|
||||
@@ -590,17 +571,17 @@ void BMI088_Accelerometer::FIFOReset()
|
||||
void BMI088_Accelerometer::UpdateTemperature()
|
||||
{
|
||||
// stored in an 11-bit value in 2’s complement format
|
||||
uint8_t temperature_buf[4] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::TEMP_MSB) | ACC_I2C_ADDR_PRIMARY;
|
||||
uint8_t temperature_buf[2] {};
|
||||
uint8_t cmd = static_cast<uint8_t>(Register::TEMP_MSB);
|
||||
// temperature_buf[1] dummy byte
|
||||
|
||||
if (transfer(&temperature_buf[0], 1, &temperature_buf[0], sizeof(temperature_buf)) != PX4_OK) {
|
||||
if (transfer(&cmd, 1, &temperature_buf[0], sizeof(temperature_buf)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t TEMP_MSB = temperature_buf[2];
|
||||
const uint8_t TEMP_LSB = temperature_buf[3];
|
||||
const uint8_t TEMP_MSB = temperature_buf[0];
|
||||
const uint8_t TEMP_LSB = temperature_buf[1];
|
||||
|
||||
// Datasheet 5.3.7: Register 0x22 – 0x23: Temperature sensor data
|
||||
uint16_t Temp_uint11 = (TEMP_MSB * 8) + (TEMP_LSB / 32);
|
||||
@@ -616,308 +597,11 @@ void BMI088_Accelerometer::UpdateTemperature()
|
||||
float temperature = (Temp_int11 * 0.125f) + 23.f; // Temp_int11 * 0.125°C/LSB + 23°C
|
||||
|
||||
if (PX4_ISFINITE(temperature)) {
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_temperature = temperature;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
}
|
||||
}
|
||||
|
||||
bool BMI088_Accelerometer::SelfTest()
|
||||
{
|
||||
PX4_WARN("Running self-test with datasheet recomended steps(page 17)");
|
||||
// Reset
|
||||
PX4_WARN("Reseting the sensor");
|
||||
|
||||
if (RegisterWrite(Register::ACC_SOFTRESET, 0xB6) == PX4_OK) {
|
||||
PX4_WARN("Reset success");
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
PX4_WARN("Accel on");
|
||||
|
||||
if (RegisterWrite(Register::ACC_PWR_CTRL, 0x04) == PX4_OK) {
|
||||
PX4_WARN("Accel on success");
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
Configure();
|
||||
usleep(1000000);
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
const uint8_t ACC_CHIP_ID = RegisterRead(Register::ACC_CHIP_ID);
|
||||
PX4_WARN("ACC_CHIP_ID: 0x%02x", ACC_CHIP_ID);
|
||||
usleep(30000);
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
|
||||
if (RegisterWrite(Register::ACC_PWR_CONF, 0) == PX4_OK) {
|
||||
PX4_WARN("Start sensor success");
|
||||
PX4_WARN("ACC_PWR_CONF(0): 0x%02x", RegisterRead(Register::ACC_PWR_CONF));
|
||||
}
|
||||
|
||||
usleep(2000000);
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
|
||||
if (RegisterWrite(Register::ACC_RANGE, 0x03) == PX4_OK) {
|
||||
PX4_WARN("Range set success");
|
||||
PX4_WARN("ACC_RANGE(0x03): 0x%02x", RegisterRead(Register::ACC_RANGE));
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
|
||||
if (RegisterWrite(Register::ACC_CONF, 0xA7) == PX4_OK) {
|
||||
PX4_WARN("Conf set success");
|
||||
PX4_WARN("ACC_CONF(0xA7): 0x%02x", RegisterRead(Register::ACC_CONF));
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
|
||||
// Positive sel-test polarity
|
||||
if (RegisterWrite(Register::ACC_SELF_TEST, 0x0D) == PX4_OK) {
|
||||
PX4_WARN("Self-test positive mode set success");
|
||||
PX4_WARN("ACC_SELF_TEST(0x0D): 0x%02x", RegisterRead(Register::ACC_SELF_TEST));
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
|
||||
float *accel_mss = ReadAccelDataFIFO();
|
||||
PX4_WARN("Positive value");
|
||||
PX4_WARN("X %f", (double)accel_mss[0]);
|
||||
PX4_WARN("Y %f", (double)accel_mss[1]);
|
||||
PX4_WARN("Z %f", (double)accel_mss[2]);
|
||||
|
||||
// Negative sel-test polarity
|
||||
if (RegisterWrite(Register::ACC_SELF_TEST, 0x09) == PX4_OK) {
|
||||
PX4_WARN("Self-test negative mode set success");
|
||||
PX4_WARN("ACC_SELF_TEST(0x09): 0x%02x", RegisterRead(Register::ACC_SELF_TEST));
|
||||
}
|
||||
|
||||
usleep(600000);
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
float *accel_mss2 = ReadAccelDataFIFO();
|
||||
PX4_WARN("Negative value");
|
||||
PX4_WARN("X %f", (double)accel_mss2[0]);
|
||||
PX4_WARN("Y %f", (double)accel_mss2[1]);
|
||||
PX4_WARN("Z %f", (double)accel_mss2[2]);
|
||||
|
||||
// Calculate difference between positive and negative sef-test response
|
||||
float diff_x = accel_mss[0] - accel_mss2[0];
|
||||
float diff_y = accel_mss[1] - accel_mss2[1];
|
||||
float diff_z = accel_mss[2] - accel_mss2[2];
|
||||
|
||||
PX4_WARN("Diff value");
|
||||
PX4_WARN("diff_x %f", (double)diff_x);
|
||||
PX4_WARN("diff_y %f", (double)diff_y);
|
||||
PX4_WARN("diff_z %f", (double)diff_z);
|
||||
|
||||
|
||||
if (diff_x >= 1000) {
|
||||
PX4_WARN("X Axis self-test success");
|
||||
}
|
||||
|
||||
if (diff_y >= 1000) {
|
||||
PX4_WARN("Y Axis self-test success");
|
||||
}
|
||||
|
||||
if (diff_z >= 500) {
|
||||
PX4_WARN("Z Axis self-test success");
|
||||
}
|
||||
|
||||
|
||||
// Disable self-test
|
||||
RegisterWrite(Register::ACC_SELF_TEST, 0x00);
|
||||
usleep(60000);
|
||||
|
||||
PX4_WARN("Sensor ErrReg: 0x%02x", CheckSensorErrReg());
|
||||
// Reset
|
||||
//PX4_WARN("Reseting the sensor again");
|
||||
//RegisterWrite(Register::ACC_SOFTRESET, 0xB6);
|
||||
//usleep(100000);
|
||||
return true;
|
||||
}
|
||||
|
||||
float *BMI088_Accelerometer::ReadAccelData()
|
||||
{
|
||||
uint8_t cmd[1] = {0x12};
|
||||
|
||||
uint8_t buf[6] = {0, 0, 0, 0, 0, 0};
|
||||
uint8_t *buffer = buf;
|
||||
|
||||
int16_t accel[3];
|
||||
|
||||
if (transfer(&cmd[0], 1, buffer, sizeof(buf)) == PX4_OK) {
|
||||
PX4_WARN("ReadAccelData transfer success");
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(buf); i++) {
|
||||
PX4_WARN("buf[%d]: %f", i, (double)buf[i]);
|
||||
}
|
||||
|
||||
accel[0] = (buf[1] << 8) | buf[0];
|
||||
accel[1] = (buf[3] << 8) | buf[2];
|
||||
accel[2] = (buf[5] << 8) | buf[4];
|
||||
|
||||
float *accel_mss = new float[3];
|
||||
|
||||
accel_mss[0] = (float) accel[0] / 32768.0f * 1000.0f * powf(2.0f, 24.0f + 1.0f) * 1.50f;
|
||||
accel_mss[1] = (float) accel[1] / 32768.0f * 1000.0f * powf(2.0f, 24.0f + 1.0f) * 1.50f;
|
||||
accel_mss[2] = (float) accel[2] / 32768.0f * 1000.0f * powf(2.0f, 24.0f + 1.0f) * 1.50f;
|
||||
|
||||
return accel_mss;
|
||||
}
|
||||
|
||||
float *BMI088_Accelerometer::ReadAccelDataFIFO()
|
||||
{
|
||||
float *accel_mg = new float[3];
|
||||
struct FIFO::bmi08x_sensor_data bmi08x_accel;
|
||||
uint8_t buffer[50] = {0};
|
||||
|
||||
PX4_WARN("FIFO mode is stop-at-full");
|
||||
/* Desired FIFO mode is stop-at-full: set bit #0 to 1 in 0x48. Bit #1 must always be one! */
|
||||
buffer[0] = 0x00 | 0x02;
|
||||
RegisterWrite(Register::FIFO_CONFIG_0, buffer[0]);
|
||||
PX4_WARN("FIFO_CONFIG_0(0x%02x): 0x%02x", buffer[0], RegisterRead(Register::FIFO_CONFIG_0));
|
||||
|
||||
PX4_WARN("Downsampling factor 2**4 = 16");
|
||||
/* Downsampling factor 2**4 = 16: write 4 into bit #4-6 of reg. 0x45. Bit #7 must always be one! */
|
||||
buffer[0] = 0x10 | 0x80;
|
||||
RegisterWrite(Register::FIFO_DOWN_SAMPLING, buffer[0]);
|
||||
PX4_WARN("FIFO_DOWN_SAMPLING(0x%02x): 0x%02x", buffer[0], RegisterRead(Register::FIFO_DOWN_SAMPLING));
|
||||
|
||||
/* Set water mark to 42 bytes (aka 6 frames, each 7 bytes: 1 byte header + 6 bytes accel data) */
|
||||
// uint16_t wml = 42;
|
||||
// buffer[0] = (uint8_t) wml & 0xff;
|
||||
// buffer[1] = (uint8_t) (wml >> 8) & 0xff;
|
||||
// uint8_t add = static_cast<uint8_t>(Register::FIFO_WTM_0);
|
||||
// uint8_t cmd[3] = { add, buffer[0], buffer[1]};
|
||||
// transfer(cmd, sizeof(cmd), nullptr, 0);
|
||||
// PX4_WARN("FIFO_WTM_0(0x%02x): 0x%02x",cmd[0], RegisterRead(Register::FIFO_WTM_0));
|
||||
|
||||
/* Enable the actual FIFO functionality: write 0x50 to 0x49. Bit #4 must always be one! */
|
||||
buffer[0] = 0x10 | 0x40;
|
||||
RegisterWrite(Register::FIFO_CONFIG_1, buffer[0]);
|
||||
PX4_WARN("FIFO_CONFIG_1(0x%02x): 0x%02x", buffer[0], RegisterRead(Register::FIFO_CONFIG_1));
|
||||
usleep(1000000);
|
||||
|
||||
int fifo_fill_level = 0;
|
||||
|
||||
uint8_t data_o[2] = { 0, 0 };
|
||||
uint8_t data_i[1] = {static_cast<uint8_t>(Register::FIFO_LENGTH_0)};
|
||||
data_i[0] = static_cast<uint8_t>(Register::FIFO_LENGTH_0);
|
||||
|
||||
transfer(&data_i[0], 1, &data_o[0], 2);
|
||||
fifo_fill_level = data_o[0] + 256 * data_o[1];
|
||||
PX4_WARN("fifo_fill_level %d", fifo_fill_level);
|
||||
|
||||
// while(fifo_fill_level < wml)
|
||||
// {
|
||||
// transfer(&data_i[0], 1, &data_o[0], 2);
|
||||
// fifo_fill_level = data_o[0] + 256 * data_o[1];
|
||||
// PX4_WARN("fifo_fill_level %d", fifo_fill_level);
|
||||
// }
|
||||
|
||||
uint8_t custom_size = 42;
|
||||
uint8_t buffer_data[custom_size] = {0};
|
||||
buffer[0] = static_cast<uint8_t>(Register::FIFO_DATA);
|
||||
bmi08x_accel.x = 10;
|
||||
PX4_WARN("bmi08x_accel %d", bmi08x_accel.x);
|
||||
transfer(&buffer[0], 1, &buffer_data[0], custom_size);
|
||||
|
||||
/* This is a super-simple FIFO parsing loop, hoping it will only find valid accel data packets */
|
||||
for (int i = 1; i < custom_size;) {
|
||||
/* Header of acceleration sensor data frame: 100001xxb, where x is INT1/INT2 tag, ignored here */
|
||||
if (buffer_data[i] == (0x84 & 0x8c)) {
|
||||
UnpackSensorData(&bmi08x_accel, &buffer_data[i + 1]);
|
||||
PX4_WARN("Frame: %03d ax:%f ay:%f az:%f", i / 6, (double)bmi08x_accel.x, (double)bmi08x_accel.y,
|
||||
(double)bmi08x_accel.z);
|
||||
accel_mg[0] = bmi08x_accel.x;
|
||||
accel_mg[1] = bmi08x_accel.y;
|
||||
accel_mg[2] = bmi08x_accel.z;
|
||||
float *data_in_mg = SensorDataTomg(accel_mg);
|
||||
PX4_WARN("Frame mg: %03d ax:%f ay:%f az:%f", i / 6, (double)data_in_mg[0], (double)data_in_mg[1],
|
||||
(double)data_in_mg[2]);
|
||||
i += 7;
|
||||
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return accel_mg;
|
||||
}
|
||||
|
||||
uint8_t BMI088_Accelerometer::CheckSensorErrReg()
|
||||
{
|
||||
return RegisterRead(Register::ACC_ERR_REG);
|
||||
}
|
||||
|
||||
void BMI088_Accelerometer::UnpackSensorData(struct FIFO::bmi08x_sensor_data *sens_data, uint8_t *buffer)
|
||||
{
|
||||
uint16_t data_lsb;
|
||||
uint16_t data_msb;
|
||||
uint16_t start_idx = 0;
|
||||
/* Gyro raw x data */
|
||||
data_lsb = buffer[start_idx++];
|
||||
data_msb = buffer[start_idx++];
|
||||
sens_data->x = (int16_t)((data_msb << 8) | data_lsb);
|
||||
/* Gyro raw y data */
|
||||
data_lsb = buffer[start_idx++];
|
||||
data_msb = buffer[start_idx++];
|
||||
sens_data->y = (int16_t)((data_msb << 8) | data_lsb);
|
||||
/* Gyro raw z data */
|
||||
data_lsb = buffer[start_idx++];
|
||||
data_msb = buffer[start_idx++];
|
||||
sens_data->z = (int16_t)((data_msb << 8) | data_lsb);
|
||||
}
|
||||
|
||||
float *BMI088_Accelerometer::SensorDataTomg(float *data)
|
||||
{
|
||||
data[0] = (float) data[0] / 32768.0f * 1000.0f * powf(2.0f, 24.0f + 1.0f) * 1.50f;
|
||||
data[1] = (float) data[1] / 32768.0f * 1000.0f * powf(2.0f, 24.0f + 1.0f) * 1.50f;
|
||||
data[2] = (float) data[2] / 32768.0f * 1000.0f * powf(2.0f, 24.0f + 1.0f) * 1.50f;
|
||||
return data;
|
||||
}
|
||||
|
||||
bool BMI088_Accelerometer::NormalRead(const hrt_abstime ×tamp_sample)
|
||||
{
|
||||
const int16_t tX[3] = {1, 0, 0};
|
||||
const int16_t tY[3] = {0, -1, 0};
|
||||
const int16_t tZ[3] = {0, 0, -1};
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float z = 0;
|
||||
uint8_t buffer[6] = {0};
|
||||
uint8_t cmd[1] = {static_cast<uint8_t>(Register::ACC_READ)};
|
||||
|
||||
transfer(&cmd[0], 1, &buffer[0], 6);
|
||||
|
||||
uint8_t RATE_X_LSB = buffer[0];
|
||||
uint8_t RATE_X_MSB = buffer[1];
|
||||
|
||||
uint8_t RATE_Y_LSB = buffer[2];
|
||||
uint8_t RATE_Y_MSB = buffer[3];
|
||||
|
||||
uint8_t RATE_Z_LSB = buffer[4];
|
||||
uint8_t RATE_Z_MSB = buffer[5];
|
||||
|
||||
const int16_t accel_x = combine(RATE_X_MSB, RATE_X_LSB);
|
||||
const int16_t accel_y = combine(RATE_Y_MSB, RATE_Y_LSB);
|
||||
const int16_t accel_z = combine(RATE_Z_MSB, RATE_Z_LSB);
|
||||
|
||||
// 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)
|
||||
x = accel_x * tX[0] + accel_y * tX[1] + accel_z * tX[2];
|
||||
y = accel_x * tY[0] + accel_y * tY[1] + accel_z * tY[2];
|
||||
z = accel_x * tZ[0] + accel_y * tZ[1] + accel_z * tZ[2];
|
||||
|
||||
//PX4_WARN("x: %f | y: %f | z: %f", (double)x, (double)y ,(double)z);
|
||||
_px4_accel.update(timestamp_sample, x, y, z);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Bosch::BMI088::Accelerometer
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,10 +35,11 @@
|
||||
|
||||
#include "BMI088.hpp"
|
||||
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
|
||||
#include "Bosch_BMI088_Accelerometer_Registers.hpp"
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_accel.h>
|
||||
|
||||
namespace Bosch::BMI088::Accelerometer
|
||||
{
|
||||
|
||||
@@ -55,11 +56,10 @@ private:
|
||||
void exit_and_cleanup() override;
|
||||
|
||||
// Sensor Configuration
|
||||
// static constexpr uint32_t RATE{1600}; // 1600 Hz
|
||||
static constexpr uint32_t RATE{1600}; // 1600 Hz
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / RATE};
|
||||
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{FIFO::SIZE / sizeof(FIFO::DATA)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
@@ -69,10 +69,6 @@ private:
|
||||
uint8_t FIFO_LENGTH_1{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// Transfer data without length
|
||||
struct FIFOTransferBufferWithoutLength {
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (4 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
|
||||
@@ -97,7 +93,7 @@ private:
|
||||
bool RegisterCheck(const register_config_t ®_cfg);
|
||||
|
||||
uint8_t RegisterRead(Register reg);
|
||||
uint8_t RegisterWrite(Register reg, uint8_t value);
|
||||
void RegisterWrite(Register reg, uint8_t value);
|
||||
void RegisterSetAndClearBits(Register reg, uint8_t setbits, uint8_t clearbits);
|
||||
|
||||
uint16_t FIFOReadCount();
|
||||
@@ -105,16 +101,14 @@ private:
|
||||
void FIFOReset();
|
||||
|
||||
void UpdateTemperature();
|
||||
void UnpackSensorData(struct FIFO::bmi08x_sensor_data *sens_data, uint8_t *buffer);
|
||||
bool SelfTest();
|
||||
float *ReadAccelData();
|
||||
float *ReadAccelDataFIFO();
|
||||
float *SensorDataTomg(float *data);
|
||||
uint8_t CheckSensorErrReg();
|
||||
bool SimpleFIFORead(const hrt_abstime ×tamp_sample);
|
||||
bool NormalRead(const hrt_abstime ×tamp_sample);
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
uORB::PublicationMulti<sensor_accel_s> _sensor_accel_pub{ORB_ID(sensor_accel)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _accel_scale{0.f};
|
||||
float _accel_range{0.f};
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME"_accel: bad register")};
|
||||
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME"_accel: bad transfer")};
|
||||
@@ -129,7 +123,7 @@ private:
|
||||
static constexpr uint8_t size_register_cfg{10};
|
||||
register_config_t _register_cfg[size_register_cfg] {
|
||||
// Register | Set bits, Clear bits
|
||||
{ Register::ACC_PWR_CONF, 0, ACC_PWR_CONF_BIT::acc_pwr_save }, //
|
||||
{ Register::ACC_PWR_CONF, 0, ACC_PWR_CONF_BIT::acc_pwr_save },
|
||||
{ Register::ACC_PWR_CTRL, ACC_PWR_CTRL_BIT::acc_enable, 0 },
|
||||
{ Register::ACC_CONF, ACC_CONF_BIT::acc_bwp_Normal | ACC_CONF_BIT::acc_odr_1600, Bit1 | Bit0 },
|
||||
{ Register::ACC_RANGE, ACC_RANGE_BIT::acc_range_24g, 0 },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
#include "BMI088_Gyroscope.hpp"
|
||||
|
||||
#include <px4_platform/board_dma_alloc.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
namespace Bosch::BMI088::Gyroscope
|
||||
@@ -42,13 +40,13 @@ namespace Bosch::BMI088::Gyroscope
|
||||
|
||||
BMI088_Gyroscope::BMI088_Gyroscope(const I2CSPIDriverConfig &config) :
|
||||
BMI088(config),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME"_gyro: DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(2000);
|
||||
ConfigureSampleRate(RATE);
|
||||
}
|
||||
|
||||
BMI088_Gyroscope::~BMI088_Gyroscope()
|
||||
@@ -98,13 +96,6 @@ void BMI088_Gyroscope::RunImpl()
|
||||
const hrt_abstime now = hrt_absolute_time();
|
||||
|
||||
switch (_state) {
|
||||
|
||||
case STATE::SELFTEST:
|
||||
//SelfTest();
|
||||
_state = STATE::RESET;
|
||||
ScheduleDelayed(1_ms);
|
||||
break;
|
||||
|
||||
case STATE::RESET:
|
||||
// GYRO_SOFTRESET: Writing a value of 0xB6 to this register resets the sensor.
|
||||
// Following a delay of 30 ms, all configuration settings are overwritten with their reset value.
|
||||
@@ -170,8 +161,90 @@ void BMI088_Gyroscope::RunImpl()
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
SimpleFIFORead(now);
|
||||
hrt_abstime timestamp_sample = 0;
|
||||
|
||||
if (_data_ready_interrupt_enabled) {
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
|
||||
} else {
|
||||
perf_count(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
// push backup schedule back
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
}
|
||||
|
||||
// always check current FIFO status/count
|
||||
bool success = false;
|
||||
const uint8_t FIFO_STATUS = RegisterRead(Register::FIFO_STATUS);
|
||||
|
||||
if (FIFO_STATUS & FIFO_STATUS_BIT::Fifo_overrun) {
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else {
|
||||
const uint8_t fifo_frame_counter = FIFO_STATUS & FIFO_STATUS_BIT::Fifo_frame_counter;
|
||||
|
||||
if (fifo_frame_counter > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else if (fifo_frame_counter == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
} else if (fifo_frame_counter >= 1) {
|
||||
|
||||
uint8_t samples = fifo_frame_counter;
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_samples + 1) {
|
||||
// sample timestamp set from data ready already corresponds to _fifo_samples
|
||||
if (timestamp_sample == 0) {
|
||||
timestamp_sample = now - static_cast<int>(FIFO_SAMPLE_DT);
|
||||
}
|
||||
|
||||
samples--;
|
||||
}
|
||||
|
||||
if (FIFORead((timestamp_sample == 0) ? now : timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
_failure_count++;
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_cfg[_checked_register])) {
|
||||
_last_config_check_timestamp = now;
|
||||
_checked_register = (_checked_register + 1) % size_register_cfg;
|
||||
|
||||
} else {
|
||||
// register check failed, force reset
|
||||
perf_count(_bad_register_perf);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -182,28 +255,28 @@ void BMI088_Gyroscope::ConfigureGyro()
|
||||
|
||||
switch (GYRO_RANGE) {
|
||||
case gyro_range_2000_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 16.384f));
|
||||
_px4_gyro.set_range(math::radians(2000.f));
|
||||
_gyro_scale = math::radians(1.f / 16.384f);
|
||||
_gyro_range = math::radians(2000.f);
|
||||
break;
|
||||
|
||||
case gyro_range_1000_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 32.768f));
|
||||
_px4_gyro.set_range(math::radians(1000.f));
|
||||
_gyro_scale = math::radians(1.f / 32.768f);
|
||||
_gyro_range = math::radians(1000.f);
|
||||
break;
|
||||
|
||||
case gyro_range_500_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 65.536f));
|
||||
_px4_gyro.set_range(math::radians(500.f));
|
||||
_gyro_scale = math::radians(1.f / 65.536f);
|
||||
_gyro_range = math::radians(500.f);
|
||||
break;
|
||||
|
||||
case gyro_range_250_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 131.072f));
|
||||
_px4_gyro.set_range(math::radians(250.f));
|
||||
_gyro_scale = math::radians(1.f / 131.072f);
|
||||
_gyro_range = math::radians(250.f);
|
||||
break;
|
||||
|
||||
case gyro_range_125_dps:
|
||||
_px4_gyro.set_scale(math::radians(1.f / 262.144f));
|
||||
_px4_gyro.set_range(math::radians(125.f));
|
||||
_gyro_scale = math::radians(1.f / 262.144f);
|
||||
_gyro_range = math::radians(125.f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -306,16 +379,15 @@ bool BMI088_Gyroscope::RegisterCheck(const register_config_t ®_cfg)
|
||||
|
||||
uint8_t BMI088_Gyroscope::RegisterRead(Register reg)
|
||||
{
|
||||
uint8_t add = static_cast<uint8_t>(reg);
|
||||
uint8_t cmd[2] = {add, 0};
|
||||
transfer(&cmd[0], 1, &cmd[1], 1);
|
||||
return cmd[1];
|
||||
uint8_t cmd = static_cast<uint8_t>(reg);
|
||||
uint8_t value = 0;
|
||||
transfer(&cmd, 1, &value, 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
void BMI088_Gyroscope::RegisterWrite(Register reg, uint8_t value)
|
||||
{
|
||||
uint8_t add = static_cast<uint8_t>(reg);
|
||||
uint8_t cmd[2] = {add, value};
|
||||
uint8_t cmd[2] { (uint8_t)reg, value };
|
||||
transfer(cmd, sizeof(cmd), nullptr, 0);
|
||||
}
|
||||
|
||||
@@ -333,37 +405,50 @@ void BMI088_Gyroscope::RegisterSetAndClearBits(Register reg, uint8_t setbits, ui
|
||||
bool BMI088_Gyroscope::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 1, FIFO::SIZE);
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
//PX4_WARN("Estimated transfer size: %d", transfer_size);
|
||||
if (transfer((uint8_t *)&buffer, 1, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
if (transfer((uint8_t *)&buffer.cmd, 1, (uint8_t *)&buffer.f, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = timestamp_sample;
|
||||
sensor_gyro.device_id = get_device_id();
|
||||
|
||||
float gyro_sum[3] {};
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const FIFO::DATA &fifo_sample = buffer.f[i];
|
||||
|
||||
const int16_t gyro_x = combine(fifo_sample.RATE_X_MSB, fifo_sample.RATE_X_LSB);
|
||||
const int16_t gyro_y = combine(fifo_sample.RATE_Y_MSB, fifo_sample.RATE_Y_LSB);
|
||||
const int16_t gyro_z = combine(fifo_sample.RATE_Z_MSB, fifo_sample.RATE_Z_LSB);
|
||||
int16_t gyro_x = combine(fifo_sample.RATE_X_MSB, fifo_sample.RATE_X_LSB);
|
||||
int16_t gyro_y = combine(fifo_sample.RATE_Y_MSB, fifo_sample.RATE_Y_LSB);
|
||||
int16_t gyro_z = combine(fifo_sample.RATE_Z_MSB, fifo_sample.RATE_Z_LSB);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
//gyro.x[i] = gyro_x;
|
||||
gyro_y = math::negate(gyro_y);
|
||||
gyro_z = math::negate(gyro_z);
|
||||
|
||||
rotate_3i(_rotation, gyro_x, gyro_y, gyro_z);
|
||||
|
||||
gyro_sum[0] += gyro_x * _gyro_scale;
|
||||
gyro_sum[1] += gyro_y * _gyro_scale;
|
||||
gyro_sum[2] += gyro_z * _gyro_scale;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
sensor_gyro.x = gyro_sum[0] / samples;
|
||||
sensor_gyro.y = gyro_sum[1] / samples;
|
||||
sensor_gyro.z = gyro_sum[2] / samples;
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
sensor_gyro.range = _gyro_range;
|
||||
sensor_gyro.temperature = NAN;
|
||||
sensor_gyro.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -390,125 +475,4 @@ void BMI088_Gyroscope::FIFOReset()
|
||||
}
|
||||
}
|
||||
|
||||
bool BMI088_Gyroscope::SelfTest()
|
||||
{
|
||||
//Datasheet page 17 self test
|
||||
|
||||
//Set bit0 to enable built in self test
|
||||
RegisterWrite(Register::SELF_TEST, 0x01);
|
||||
usleep(10000);
|
||||
uint8_t res = 0;
|
||||
uint8_t test_res = false;
|
||||
|
||||
while (true) {
|
||||
res = RegisterRead(Register::SELF_TEST);
|
||||
|
||||
if ((res & 0x02) == 0x02) {
|
||||
if ((res & 0x04) == 0x00) {
|
||||
PX4_WARN("Gyro Self-test success");
|
||||
test_res = true;
|
||||
|
||||
} else {
|
||||
PX4_WARN("Gyro Self-test error");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RegisterWrite(Register::SELF_TEST, 0x00);
|
||||
return test_res;
|
||||
}
|
||||
|
||||
bool BMI088_Gyroscope::NormalRead(const hrt_abstime ×tamp_sample)
|
||||
{
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float z = 0;
|
||||
uint8_t buffer[6] = {0};
|
||||
uint8_t cmd[1] = {static_cast<uint8_t>(Register::READ_GYRO)};
|
||||
|
||||
transfer(&cmd[0], 1, &buffer[0], 6);
|
||||
|
||||
uint8_t RATE_X_LSB = buffer[0];
|
||||
uint8_t RATE_X_MSB = buffer[1];
|
||||
uint8_t RATE_Y_LSB = buffer[2];
|
||||
uint8_t RATE_Y_MSB = buffer[3];
|
||||
uint8_t RATE_Z_LSB = buffer[4];
|
||||
uint8_t RATE_Z_MSB = buffer[5];
|
||||
|
||||
const int16_t gyro_x = combine(RATE_X_MSB, RATE_X_LSB);
|
||||
const int16_t gyro_y = combine(RATE_Y_MSB, RATE_Y_LSB);
|
||||
const int16_t gyro_z = combine(RATE_Z_MSB, RATE_Z_LSB);
|
||||
|
||||
// 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)
|
||||
x = gyro_x;
|
||||
y = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
z = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
|
||||
_px4_gyro.update(timestamp_sample, x, y, z);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BMI088_Gyroscope::SimpleFIFORead(const hrt_abstime ×tamp_sample)
|
||||
{
|
||||
uint8_t n_frames;
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = 0;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
uint8_t data_i[1] = {static_cast<uint8_t>(Register::FIFO_STATUS)};
|
||||
|
||||
transfer(&data_i[0], 1, &n_frames, 1);
|
||||
|
||||
n_frames &= 0x7F;
|
||||
|
||||
int n_frames_to_read = 6;
|
||||
|
||||
// don't read more than 8 frames at a time
|
||||
if (n_frames > n_frames_to_read) {
|
||||
n_frames = n_frames_to_read;
|
||||
}
|
||||
|
||||
if (n_frames == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t data[6 * n_frames];
|
||||
data[0] = static_cast<uint8_t>(Register::FIFO_DATA);
|
||||
|
||||
if (transfer(&data[0], 1, &data[0], 6 * n_frames) != PX4_OK) {
|
||||
//PX4_WARN("transfer(&data[0], 1, &data[0], fifo_fill_level) != PX4_OK");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < n_frames; i++) {
|
||||
const uint8_t *d = &data[i * 6];
|
||||
int16_t xyz[3] {
|
||||
int16_t(uint16_t(d[0] | d[1] << 8)),
|
||||
int16_t(uint16_t(d[2] | d[3] << 8)),
|
||||
int16_t(uint16_t(d[4] | d[5] << 8))
|
||||
};
|
||||
|
||||
gyro.x[i] = xyz[0];
|
||||
gyro.y[i] = (xyz[1] == INT16_MIN) ? INT16_MAX : -xyz[1];
|
||||
gyro.z[i] = (xyz[2] == INT16_MIN) ? INT16_MAX : -xyz[2];
|
||||
gyro.samples++;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (gyro.samples > 0) {
|
||||
//PX4_WARN("accel.samples: %d", accel.samples);
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
} // namespace Bosch::BMI088::Gyroscope
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,10 +35,11 @@
|
||||
|
||||
#include "BMI088.hpp"
|
||||
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
|
||||
#include "Bosch_BMI088_Gyroscope_Registers.hpp"
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_gyro.h>
|
||||
|
||||
namespace Bosch::BMI088::Gyroscope
|
||||
{
|
||||
|
||||
@@ -55,10 +56,10 @@ private:
|
||||
void exit_and_cleanup() override;
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr uint32_t RATE{400}; // 2000 Hz
|
||||
static constexpr uint32_t RATE{2000}; // 2000 Hz
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / RATE};
|
||||
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{FIFO::SIZE / sizeof(FIFO::DATA)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
@@ -95,10 +96,11 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
bool SelfTest();
|
||||
bool NormalRead(const hrt_abstime ×tamp_sample);
|
||||
bool SimpleFIFORead(const hrt_abstime ×tamp_sample);
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_gyro_s> _sensor_gyro_pub{ORB_ID(sensor_gyro)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
float _gyro_scale{0.f};
|
||||
float _gyro_range{0.f};
|
||||
|
||||
perf_counter_t _bad_register_perf{perf_alloc(PC_COUNT, MODULE_NAME"_gyro: bad register")};
|
||||
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME"_gyro: bad transfer")};
|
||||
@@ -114,13 +116,13 @@ private:
|
||||
register_config_t _register_cfg[size_register_cfg] {
|
||||
// Register | Set bits, Clear bits
|
||||
{ Register::GYRO_RANGE, GYRO_RANGE_BIT::gyro_range_2000_dps, 0 },
|
||||
{ Register::GYRO_BANDWIDTH, 0, GYRO_BANDWIDTH_BIT::gyro_bw_2000_Hz},
|
||||
{ Register::GYRO_BANDWIDTH, 0, GYRO_BANDWIDTH_BIT::gyro_bw_532_Hz },
|
||||
{ Register::GYRO_INT_CTRL, GYRO_INT_CTRL_BIT::fifo_en, 0 },
|
||||
{ Register::INT3_INT4_IO_CONF, 0, INT3_INT4_IO_CONF_BIT::Int3_od | INT3_INT4_IO_CONF_BIT::Int3_lvl },
|
||||
{ Register::INT3_INT4_IO_MAP, INT3_INT4_IO_MAP_BIT::Int3_fifo, 0 },
|
||||
{ Register::FIFO_WM_ENABLE, FIFO_WM_ENABLE_BIT::fifo_wm_enable, 0 },
|
||||
{ Register::FIFO_CONFIG_0, 0, 0 }, // fifo_water_mark_level_trigger_retain<6:0>
|
||||
{ Register::FIFO_CONFIG_1, FIFO_CONFIG_1_BIT::FIFO_MODE_STREAM, 0 },
|
||||
{ Register::FIFO_CONFIG_1, FIFO_CONFIG_1_BIT::FIFO_MODE, 0 },
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -48,15 +48,14 @@ static constexpr uint8_t Bit7 = (1 << 7);
|
||||
|
||||
static constexpr uint32_t SPI_SPEED = 10 * 1000 * 1000; // 10MHz SPI serial interface
|
||||
|
||||
static constexpr uint32_t I2C_400_SPEED = 400 * 1000; // 400kHz I2C interface
|
||||
static constexpr uint32_t I2C_200_SPEED = 200 * 1000; // 200kHz I2C interface
|
||||
static constexpr uint32_t I2C_100_SPEED = 100 * 1000; // 100kHz I2C interface
|
||||
static constexpr uint32_t I2C_SPEED = 400 * 1000; // 400kHz I2C interface
|
||||
|
||||
static constexpr uint8_t DIR_READ = 0x80;
|
||||
|
||||
static constexpr uint8_t ID = 0x1E;
|
||||
static constexpr uint8_t ID_088 = 0x1E;
|
||||
static constexpr uint8_t ID_090L = 0x1A;
|
||||
|
||||
static constexpr uint8_t ACC_I2C_ADDR_PRIMARY = 0x18;
|
||||
static constexpr uint8_t ACC_I2C_ADDR_PRIMARY = 0x18;
|
||||
static constexpr uint8_t ACC_I2C_ADDR_SECONDARY = 0x19;
|
||||
|
||||
enum class Register : uint8_t {
|
||||
@@ -74,7 +73,7 @@ enum class Register : uint8_t {
|
||||
ACC_CONF = 0x40,
|
||||
ACC_RANGE = 0x41,
|
||||
|
||||
FIFO_DOWN_SAMPLING = 0x45,
|
||||
FIFO_DOWNS = 0x45,
|
||||
FIFO_WTM_0 = 0x46,
|
||||
FIFO_WTM_1 = 0x47,
|
||||
FIFO_CONFIG_0 = 0x48,
|
||||
@@ -87,24 +86,15 @@ enum class Register : uint8_t {
|
||||
ACC_PWR_CONF = 0x7C,
|
||||
ACC_PWR_CTRL = 0x7D,
|
||||
ACC_SOFTRESET = 0x7E,
|
||||
ACC_SELF_TEST = 0x6D,
|
||||
ACC_I2C_ADDR_PRIMARY_REG = 0x6D,
|
||||
ACC_I2C_ADDR_SECONDARY_REG = 0x19,
|
||||
ACC_READ = 0x12
|
||||
};
|
||||
|
||||
// ACC_CONF
|
||||
enum ACC_CONF_BIT : uint8_t {
|
||||
// [7:4] acc_bwp
|
||||
acc_bwp_Normal = Bit7 | Bit5, // Filter setting normal
|
||||
// [7:4] acc_bwp
|
||||
acc_bwp_osr_4 = Bit7, // OSR4
|
||||
|
||||
// [3:0] acc_odr
|
||||
acc_odr_1600 = Bit3 | Bit2, // ODR 1600 Hz
|
||||
// [3:0] acc_odr
|
||||
acc_odr_12_5 = Bit2 | Bit0, // ODR 12.5 Hz
|
||||
// [3:0] acc_odr
|
||||
acc_odr_100 = Bit3, // ODR 100 Hz
|
||||
};
|
||||
|
||||
// ACC_RANGE
|
||||
@@ -158,7 +148,7 @@ enum ACC_PWR_CTRL_BIT : uint8_t {
|
||||
|
||||
namespace FIFO
|
||||
{
|
||||
|
||||
static constexpr size_t SIZE = 1024;
|
||||
|
||||
// 1. Acceleration sensor data frame - Frame length: 7 bytes (1 byte header + 6 bytes payload)
|
||||
// Payload: the next bytes contain the sensor data in the same order as defined in the register map (addresses 0x12 – 0x17).
|
||||
@@ -176,8 +166,6 @@ struct DATA {
|
||||
uint8_t ACC_Z_LSB;
|
||||
uint8_t ACC_Z_MSB;
|
||||
};
|
||||
static constexpr size_t SIZE = 1024;
|
||||
//static constexpr size_t SIZE = sizeof(DATA) * 10;
|
||||
static_assert(sizeof(DATA) == 7);
|
||||
|
||||
enum header : uint8_t {
|
||||
@@ -187,15 +175,6 @@ enum header : uint8_t {
|
||||
FIFO_input_config_frame = 0b01001000,
|
||||
sample_drop_frame = 0b01010000,
|
||||
};
|
||||
struct bmi08x_sensor_data {
|
||||
/*! X-axis sensor data */
|
||||
int16_t x;
|
||||
|
||||
/*! Y-axis sensor data */
|
||||
int16_t y;
|
||||
|
||||
/*! Z-axis sensor data */
|
||||
int16_t z;
|
||||
};
|
||||
} // namespace FIFO
|
||||
} // namespace Bosch::BMI088::Accelerometer
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -48,9 +48,7 @@ static constexpr uint8_t Bit7 = (1 << 7);
|
||||
|
||||
static constexpr uint32_t SPI_SPEED = 10 * 1000 * 1000; // 10MHz SPI serial interface
|
||||
|
||||
static constexpr uint32_t I2C_400_SPEED = 400 * 1000; // 400kHz I2C interface
|
||||
static constexpr uint32_t I2C_200_SPEED = 200 * 1000; // 200kHz I2C interface
|
||||
static constexpr uint32_t I2C_100_SPEED = 100 * 1000; // 100kHz I2C interface
|
||||
static constexpr uint32_t I2C_SPEED = 400 * 1000; // 400kHz I2C interface
|
||||
|
||||
static constexpr uint8_t DIR_READ = 0x80;
|
||||
|
||||
@@ -76,8 +74,6 @@ enum class Register : uint8_t {
|
||||
FIFO_CONFIG_0 = 0x3D,
|
||||
FIFO_CONFIG_1 = 0x3E,
|
||||
FIFO_DATA = 0x3F,
|
||||
SELF_TEST = 0x3C,
|
||||
READ_GYRO = 0x02,
|
||||
};
|
||||
|
||||
// FIFO_STATUS
|
||||
@@ -97,9 +93,7 @@ enum GYRO_RANGE_BIT : uint8_t {
|
||||
|
||||
// GYRO_BANDWIDTH
|
||||
enum GYRO_BANDWIDTH_BIT : uint8_t {
|
||||
gyro_bw_100_Hz = Bit2 | Bit1 | Bit0,
|
||||
gyro_bw_200_Hz = Bit4,
|
||||
gyro_bw_2000_Hz = 0x00,
|
||||
gyro_bw_532_Hz = Bit2 | Bit1 | Bit0
|
||||
};
|
||||
|
||||
// GYRO_INT_CTRL
|
||||
@@ -131,7 +125,6 @@ enum FIFO_WM_ENABLE_BIT : uint8_t {
|
||||
// FIFO_CONFIG_1
|
||||
enum FIFO_CONFIG_1_BIT : uint8_t {
|
||||
FIFO_MODE = Bit6,
|
||||
FIFO_MODE_STREAM = Bit7,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2019-2020 PX4 Development Team. All rights reserved.
|
||||
# Copyright (c) 2019-2022 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
@@ -48,7 +48,5 @@ px4_add_module(
|
||||
|
||||
bmi088_i2c_main.cpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020, 2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -60,19 +60,20 @@ extern "C" int bmi088_i2c_main(int argc, char *argv[])
|
||||
uint16_t type = 0;
|
||||
const char *name = MODULE_NAME;
|
||||
|
||||
|
||||
while ((ch = cli.getOpt(argc, argv, "AGR:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'A':
|
||||
type = DRV_ACC_DEVTYPE_BMI088;
|
||||
name = MODULE_NAME "_accel";
|
||||
cli.i2c_address = 0x18;
|
||||
cli.default_i2c_frequency = 400 * 1000;
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
type = DRV_GYR_DEVTYPE_BMI088;
|
||||
name = MODULE_NAME "_gyro";
|
||||
cli.i2c_address = 0x69;
|
||||
cli.default_i2c_frequency = 400 * 1000;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
@@ -92,17 +93,14 @@ extern "C" int bmi088_i2c_main(int argc, char *argv[])
|
||||
|
||||
if (!strcmp(verb, "start")) {
|
||||
return ThisDriver::module_start(cli, iterator);
|
||||
}
|
||||
|
||||
if (!strcmp(verb, "stop")) {
|
||||
} else if (!strcmp(verb, "stop")) {
|
||||
return ThisDriver::module_stop(iterator);
|
||||
}
|
||||
|
||||
if (!strcmp(verb, "status")) {
|
||||
} else if (!strcmp(verb, "status")) {
|
||||
return ThisDriver::module_status(iterator);
|
||||
}
|
||||
|
||||
PX4_WARN("print_usage1");
|
||||
ThisDriver::print_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ using namespace time_literals;
|
||||
FXAS21002C::FXAS21002C(device::Device *interface, const I2CSPIDriverConfig &config) :
|
||||
I2CSPIDriver(config),
|
||||
_interface(interface),
|
||||
_px4_gyro(_interface->get_device_id(), config.rotation),
|
||||
_rotation(config.rotation),
|
||||
_sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": read")),
|
||||
_errors(perf_alloc(PC_COUNT, MODULE_NAME": err")),
|
||||
_bad_registers(perf_alloc(PC_COUNT, MODULE_NAME": bad register")),
|
||||
@@ -186,7 +186,7 @@ int FXAS21002C::set_range(unsigned max_dps)
|
||||
|
||||
set_standby(_current_rate, true);
|
||||
|
||||
_px4_gyro.set_scale(new_range_scale_dps_digit / 180.0f * M_PI_F);
|
||||
_gyro_scale = new_range_scale_dps_digit / 180.0f * M_PI_F);
|
||||
|
||||
modify_reg(FXAS21002C_CTRL_REG0, CTRL_REG0_FS_MASK, bits);
|
||||
set_standby(_current_rate, false);
|
||||
@@ -378,9 +378,6 @@ void FXAS21002C::RunImpl()
|
||||
}
|
||||
|
||||
// report the error count as the number of bad register reads. This allows the higher level
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_registers));
|
||||
_px4_gyro.update(timestamp_sample, x_raw, y_raw, z_raw);
|
||||
|
||||
if (hrt_elapsed_time(&_last_temperature_update) > 100_ms) {
|
||||
/*
|
||||
* The TEMP register contains an 8-bit 2's complement temperature value with a range
|
||||
@@ -389,10 +386,23 @@ void FXAS21002C::RunImpl()
|
||||
* mode and actively measuring the angular rate.
|
||||
*/
|
||||
const float temperature = read_reg(FXAS21002C_TEMP) * 1.0f;
|
||||
_px4_gyro.set_temperature(temperature);
|
||||
_last_temperature = temperature;
|
||||
_last_temperature_update = timestamp_sample;
|
||||
}
|
||||
|
||||
// sensor_gyro
|
||||
sensor_gyro_s sensor_gyro{};
|
||||
sensor_gyro.timestamp_sample = time_now_us;
|
||||
sensor_gyro.device_id = 1;
|
||||
sensor_gyro.x = gyro(0);
|
||||
sensor_gyro.y = gyro(1);
|
||||
sensor_gyro.z = gyro(2);
|
||||
sensor_gyro.range = math::radians(2000.f);
|
||||
sensor_gyro.temperature = NAN;
|
||||
sensor_gyro.error_count = perf_event_count(_bad_registers);
|
||||
sensor_gyro.timestamp = hrt_absolute_time();
|
||||
_sensor_gyro_pub.publish(sensor_gyro);
|
||||
|
||||
/* stop the perf counter */
|
||||
perf_end(_sample_perf);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <drivers/device/Device.hpp>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <perf/perf_counter.h>
|
||||
#include <px4_platform_common/getopt.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
@@ -211,7 +210,6 @@ protected:
|
||||
|
||||
private:
|
||||
device::Device *_interface;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
|
||||
unsigned _current_rate{800};
|
||||
|
||||
|
||||
@@ -56,18 +56,13 @@ const uint8_t FXOS8701CQ::_checked_registers[FXOS8701C_NUM_CHECKED_REGISTERS] =
|
||||
FXOS8701CQ::FXOS8701CQ(device::Device *interface, const I2CSPIDriverConfig &config) :
|
||||
I2CSPIDriver(config),
|
||||
_interface(interface),
|
||||
_px4_accel(interface->get_device_id(), config.rotation),
|
||||
#if !defined(BOARD_HAS_NOISY_FXOS8700_MAG)
|
||||
_px4_mag(interface->get_device_id(), config.rotation),
|
||||
_mag_sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": mag read")),
|
||||
#endif
|
||||
_accel_sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": acc read")),
|
||||
_bad_registers(perf_alloc(PC_COUNT, MODULE_NAME": bad reg")),
|
||||
_accel_duplicates(perf_alloc(PC_COUNT, MODULE_NAME": acc dupe"))
|
||||
{
|
||||
#if !defined(BOARD_HAS_NOISY_FXOS8700_MAG)
|
||||
_px4_mag.set_scale(0.001f);
|
||||
#endif
|
||||
}
|
||||
|
||||
FXOS8701CQ::~FXOS8701CQ()
|
||||
@@ -195,7 +190,7 @@ FXOS8701CQ::accel_set_range(unsigned max_g)
|
||||
|
||||
modify_reg(FXOS8701CQ_XYZ_DATA_CFG, XYZ_DATA_CFG_FS_MASK, setbits);
|
||||
|
||||
_px4_accel.set_scale(accel_range_scale);
|
||||
_accel_scale = accel_range_scale;
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -335,9 +330,6 @@ void FXOS8701CQ::RunImpl()
|
||||
}
|
||||
|
||||
// report the error count as the sum of the number of bad register reads and bad values.
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_registers));
|
||||
_px4_accel.update(timestamp_sample, x, y, z);
|
||||
|
||||
if (hrt_elapsed_time(&_last_temperature_update) > 100_ms) {
|
||||
/*
|
||||
* Eight-bit 2’s complement sensor temperature value with 0.96 °C/LSB sensitivity.
|
||||
@@ -349,9 +341,21 @@ void FXOS8701CQ::RunImpl()
|
||||
_last_temperature_update = timestamp_sample;
|
||||
float temperature = (read_reg(FXOS8701CQ_TEMP)) * 0.96f;
|
||||
|
||||
_px4_accel.set_temperature(temperature);
|
||||
_last_temperature = temperature;
|
||||
}
|
||||
|
||||
sensor_accel_s sensor_accel{};
|
||||
sensor_accel.timestamp_sample = timestamp_sample;
|
||||
sensor_accel.device_id = get_device_id();
|
||||
sensor_accel.x = x;
|
||||
sensor_accel.y = y;
|
||||
sensor_accel.z = z;
|
||||
sensor_accel.range = 16.f * CONSTANTS_ONE_G;
|
||||
sensor_accel.temperature = _last_temperature;
|
||||
sensor_accel.error_count = perf_event_count(_bad_registers);
|
||||
sensor_accel.timestamp = hrt_absolute_time();
|
||||
_sensor_accel_pub.publish(sensor_accel);
|
||||
|
||||
|
||||
#if !defined(BOARD_HAS_NOISY_FXOS8700_MAG)
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
|
||||
#include <drivers/device/i2c.h>
|
||||
#include <drivers/device/spi.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
@@ -231,9 +230,6 @@ private:
|
||||
*/
|
||||
int accel_set_samplerate(unsigned frequency);
|
||||
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
|
||||
#if !defined(BOARD_HAS_NOISY_FXOS8700_MAG)
|
||||
PX4Magnetometer _px4_mag;
|
||||
hrt_abstime _mag_last_measure{0};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2019-2021 PX4 Development Team. All rights reserved.
|
||||
# Copyright (c) 2019-2022 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
@@ -35,13 +35,12 @@ px4_add_module(
|
||||
MODULE drivers__imu__invensense__icm20602
|
||||
MAIN icm20602
|
||||
COMPILE_FLAGS
|
||||
${MAX_CUSTOM_OPT_LEVEL}
|
||||
SRCS
|
||||
icm20602_main.cpp
|
||||
ICM20602.cpp
|
||||
ICM20602.hpp
|
||||
icm20602_main.cpp
|
||||
InvenSense_ICM20602_registers.hpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2019-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM20602.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ ICM20602::ICM20602(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
ICM20602::~ICM20602()
|
||||
@@ -131,14 +135,19 @@ bool ICM20602::StoreCheckedRegisterValue(Register reg)
|
||||
|
||||
int ICM20602::probe()
|
||||
{
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
|
||||
if (whoami != WHOAMI) {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
return PX4_ERROR;
|
||||
if (whoami == WHOAMI) {
|
||||
return PX4_OK;
|
||||
|
||||
} else {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
}
|
||||
}
|
||||
|
||||
return PX4_OK;
|
||||
return PX4_ERROR;
|
||||
}
|
||||
|
||||
void ICM20602::RunImpl()
|
||||
@@ -196,8 +205,8 @@ void ICM20602::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +253,7 @@ void ICM20602::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
@@ -310,13 +319,14 @@ void ICM20602::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_cfg[_checked_register])) {
|
||||
_last_config_check_timestamp = now;
|
||||
_checked_register = (_checked_register + 1) % size_register_cfg;
|
||||
@@ -324,6 +334,7 @@ void ICM20602::RunImpl()
|
||||
} else {
|
||||
// register check failed, force reset
|
||||
perf_count(_bad_register_perf);
|
||||
PX4_DEBUG("Force reset because register 0x%02hhX check failed ", (uint8_t)_register_cfg[_checked_register].reg);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
@@ -333,65 +344,10 @@ void ICM20602::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void ICM20602::ConfigureAccel()
|
||||
{
|
||||
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::ACCEL_CONFIG) & (Bit4 | Bit3); // [4:3] ACCEL_FS_SEL[1:0]
|
||||
|
||||
switch (ACCEL_FS_SEL) {
|
||||
case ACCEL_FS_SEL_2G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 16384.f);
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
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)
|
||||
{
|
||||
// round down to nearest FIFO sample dt * SAMPLES_PER_TRANSFER
|
||||
const float min_interval = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
@@ -438,9 +394,6 @@ bool ICM20602::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -463,7 +416,7 @@ bool ICM20602::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool ICM20602::DataReadyInterruptDisable()
|
||||
@@ -472,7 +425,7 @@ bool ICM20602::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
bool ICM20602::RegisterCheck(const register_config_t ®_cfg)
|
||||
@@ -521,32 +474,46 @@ void ICM20602::RegisterSetAndClearBits(Register reg, uint8_t setbits, uint8_t cl
|
||||
|
||||
uint16_t ICM20602::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ;
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool ICM20602::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 3, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + FIFO_COUNTH + FIFO_COUNTL + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 3 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = combine(buffer.FIFO_COUNTH, buffer.FIFO_COUNTL);
|
||||
const uint16_t fifo_count_bytes = (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
if ((fifo_count_bytes >= FIFO::SIZE) || (fifo_count_samples > FIFO_MAX_SAMPLES)) {
|
||||
const uint8_t valid_samples = math::min(samples, fifo_count_samples);
|
||||
|
||||
if ((fifo_count_bytes >= FIFO::SIZE) || (valid_samples > FIFO_MAX_SAMPLES)) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
@@ -556,17 +523,45 @@ bool ICM20602::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t valid_samples = math::min(samples, fifo_count_samples);
|
||||
|
||||
if (valid_samples > 0) {
|
||||
// use raw temperature to first validate FIFO transfer
|
||||
if (ProcessTemperature(buffer.f, valid_samples)) {
|
||||
ProcessGyro(timestamp_sample, buffer.f, valid_samples);
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
sensor_imu_fifo.accel_scale = ACCEL_SCALE;
|
||||
sensor_imu_fifo.gyro_scale = GYRO_SCALE;
|
||||
|
||||
if (ProcessAccel(timestamp_sample, buffer.f, valid_samples)) {
|
||||
return true;
|
||||
}
|
||||
float temperature_sum{0};
|
||||
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// 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)
|
||||
sensor_imu_fifo.accel_x[i] = combine(buffer.f[i].ACCEL_XOUT_H, buffer.f[i].ACCEL_XOUT_L);
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(combine(buffer.f[i].ACCEL_YOUT_H, buffer.f[i].ACCEL_YOUT_L));
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(combine(buffer.f[i].ACCEL_ZOUT_H, buffer.f[i].ACCEL_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(buffer.f[i].GYRO_XOUT_H, buffer.f[i].GYRO_XOUT_L);
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(combine(buffer.f[i].GYRO_YOUT_H, buffer.f[i].GYRO_YOUT_L));
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(combine(buffer.f[i].GYRO_ZOUT_H, buffer.f[i].GYRO_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
|
||||
temperature_sum += combine(buffer.f[i].TEMP_OUT_H, buffer.f[i].TEMP_OUT_L);
|
||||
}
|
||||
|
||||
// use average temperature reading
|
||||
const float temperature_avg = temperature_sum / valid_samples;
|
||||
const float temperature_C = (temperature_avg / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
sensor_imu_fifo.temperature = temperature_C;
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf)
|
||||
+ perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -594,124 +589,29 @@ void ICM20602::FIFOReset()
|
||||
}
|
||||
}
|
||||
|
||||
static bool fifo_accel_equal(const FIFO::DATA &f0, const FIFO::DATA &f1)
|
||||
float ICM20602::ReadTemperature()
|
||||
{
|
||||
return (memcmp(&f0.ACCEL_XOUT_H, &f1.ACCEL_XOUT_H, 6) == 0);
|
||||
}
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ};
|
||||
uint8_t TEMP_OUT_H{0};
|
||||
uint8_t TEMP_OUT_L{0};
|
||||
} buffer{};
|
||||
|
||||
bool ICM20602::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
|
||||
bool bad_data = false;
|
||||
|
||||
// accel data is doubled in FIFO, but might be shifted
|
||||
int accel_first_sample = 1;
|
||||
|
||||
if (samples >= 4) {
|
||||
if (fifo_accel_equal(fifo[0], fifo[1]) && fifo_accel_equal(fifo[2], fifo[3])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0==A1, A2==A3
|
||||
accel_first_sample = 1;
|
||||
|
||||
} else if (fifo_accel_equal(fifo[1], fifo[2])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0, A1==A2, A3
|
||||
accel_first_sample = 0;
|
||||
|
||||
} else {
|
||||
// no matching accel samples is an error
|
||||
bad_data = true;
|
||||
perf_count(_bad_transfer_perf);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = accel_first_sample; i < samples; i = i + SAMPLES_PER_TRANSFER) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_XOUT_H, fifo[i].ACCEL_XOUT_L);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_YOUT_H, fifo[i].ACCEL_YOUT_L);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_ZOUT_H, fifo[i].ACCEL_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
|
||||
return !bad_data;
|
||||
}
|
||||
|
||||
void ICM20602::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_XOUT_H, fifo[i].GYRO_XOUT_L);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_YOUT_H, fifo[i].GYRO_YOUT_L);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_ZOUT_H, fifo[i].GYRO_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
bool ICM20602::ProcessTemperature(const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
int16_t temperature[FIFO_MAX_SAMPLES];
|
||||
float temperature_sum{0};
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t t = combine(fifo[i].TEMP_OUT_H, fifo[i].TEMP_OUT_L);
|
||||
temperature_sum += t;
|
||||
temperature[i] = t;
|
||||
}
|
||||
|
||||
const float temperature_avg = temperature_sum / samples;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
// temperature changing wildly is an indication of a transfer error
|
||||
if (fabsf(temperature[i] - temperature_avg) > 1000) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// use average temperature reading
|
||||
const float temperature_C = (temperature_avg / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(temperature_C)
|
||||
&& (temperature_C >= TEMPERATURE_SENSOR_MIN)
|
||||
&& (temperature_C <= TEMPERATURE_SENSOR_MAX)) {
|
||||
|
||||
_px4_accel.set_temperature(temperature_C);
|
||||
_px4_gyro.set_temperature(temperature_C);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return NAN;;
|
||||
}
|
||||
|
||||
return false;
|
||||
const int16_t TEMP_OUT = combine(buffer.TEMP_OUT_H, buffer.TEMP_OUT_L);
|
||||
const float TEMP_degC = (TEMP_OUT / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)
|
||||
&& (TEMP_degC >= TEMPERATURE_SENSOR_MIN)
|
||||
&& (TEMP_degC <= TEMPERATURE_SENSOR_MAX)) {
|
||||
|
||||
return TEMP_degC;
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2019-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_ICM20602_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_ICM20602;
|
||||
|
||||
class ICM20602 : public device::SPI, public I2CSPIDriver<ICM20602>
|
||||
@@ -71,22 +72,13 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f};
|
||||
static constexpr int32_t SAMPLES_PER_TRANSFER{2}; // ensure at least 1 new accel sample per transfer
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT}; // 8000 Hz gyro
|
||||
static constexpr float ACCEL_RATE{GYRO_RATE / SAMPLES_PER_TRANSFER}; // 4000 Hz accel
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (3 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr float ACCEL_SCALE{CONSTANTS_ONE_G / 2048.f}; // ACCEL_FS_SEL_16G:
|
||||
static constexpr float GYRO_SCALE{math::radians(2000.f / 32768.f)}; // FS_SEL_2000_DPS:
|
||||
|
||||
struct register_config_t {
|
||||
Register reg;
|
||||
@@ -99,8 +91,6 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
void ConfigureFIFOWatermark(uint8_t samples);
|
||||
|
||||
@@ -120,14 +110,13 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
bool ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
bool ProcessTemperature(const FIFO::DATA fifo[], const uint8_t samples);
|
||||
float ReadTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
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")};
|
||||
|
||||
@@ -41,7 +41,5 @@ px4_add_module(
|
||||
icm20608g_main.cpp
|
||||
InvenSense_ICM20608G_registers.hpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2019-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM20608G.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ ICM20608G::ICM20608G(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
ICM20608G::~ICM20608G()
|
||||
@@ -108,7 +112,7 @@ void ICM20608G::print_status()
|
||||
bool ICM20608G::StoreCheckedRegisterValue(Register reg)
|
||||
{
|
||||
// 3 retries
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
uint8_t read1 = RegisterRead(reg);
|
||||
uint8_t read2 = RegisterRead(reg);
|
||||
|
||||
@@ -131,14 +135,19 @@ bool ICM20608G::StoreCheckedRegisterValue(Register reg)
|
||||
|
||||
int ICM20608G::probe()
|
||||
{
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
|
||||
if (whoami != WHOAMI) {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
return PX4_ERROR;
|
||||
if (whoami == WHOAMI) {
|
||||
return PX4_OK;
|
||||
|
||||
} else {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
}
|
||||
}
|
||||
|
||||
return PX4_OK;
|
||||
return PX4_ERROR;
|
||||
}
|
||||
|
||||
void ICM20608G::RunImpl()
|
||||
@@ -187,8 +196,8 @@ void ICM20608G::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +205,8 @@ void ICM20608G::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
_temperature = ReadTemperature();
|
||||
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
@@ -234,7 +245,7 @@ void ICM20608G::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
|
||||
} else {
|
||||
@@ -271,7 +282,7 @@ void ICM20608G::RunImpl()
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else if (samples >= SAMPLES_PER_TRANSFER) {
|
||||
} else if (samples >= 1) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
@@ -287,6 +298,7 @@ void ICM20608G::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
@@ -301,13 +313,14 @@ void ICM20608G::RunImpl()
|
||||
} else {
|
||||
// register check failed, force reset
|
||||
perf_count(_bad_register_perf);
|
||||
PX4_DEBUG("Force reset because register 0x%02hhX check failed ", (uint8_t)_register_cfg[_checked_register].reg);
|
||||
Reset();
|
||||
}
|
||||
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature = ReadTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
@@ -317,65 +330,10 @@ void ICM20608G::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void ICM20608G::ConfigureAccel()
|
||||
{
|
||||
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::ACCEL_CONFIG) & (Bit4 | Bit3); // [4:3] ACCEL_FS_SEL[1:0]
|
||||
|
||||
switch (ACCEL_FS_SEL) {
|
||||
case ACCEL_FS_SEL_2G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 16384.f);
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
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 ICM20608G::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 ICM20608G::ConfigureSampleRate(int sample_rate)
|
||||
{
|
||||
// round down to nearest FIFO sample dt * SAMPLES_PER_TRANSFER
|
||||
const float min_interval = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
@@ -400,9 +358,6 @@ bool ICM20608G::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -429,7 +384,7 @@ bool ICM20608G::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool ICM20608G::DataReadyInterruptDisable()
|
||||
@@ -438,7 +393,7 @@ bool ICM20608G::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
bool ICM20608G::RegisterCheck(const register_config_t ®_cfg)
|
||||
@@ -487,31 +442,75 @@ void ICM20608G::RegisterSetAndClearBits(Register reg, uint8_t setbits, uint8_t c
|
||||
|
||||
uint16_t ICM20608G::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ;
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool ICM20608G::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 1, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_R_W) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 1 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t valid_samples = samples;
|
||||
|
||||
ProcessGyro(timestamp_sample, buffer.f, samples);
|
||||
return ProcessAccel(timestamp_sample, buffer.f, samples);
|
||||
if (valid_samples > 0) {
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
sensor_imu_fifo.accel_scale = ACCEL_SCALE;
|
||||
sensor_imu_fifo.gyro_scale = GYRO_SCALE;
|
||||
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// 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)
|
||||
sensor_imu_fifo.accel_x[i] = combine(buffer.f[i].ACCEL_XOUT_H, buffer.f[i].ACCEL_XOUT_L);
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(combine(buffer.f[i].ACCEL_YOUT_H, buffer.f[i].ACCEL_YOUT_L));
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(combine(buffer.f[i].ACCEL_ZOUT_H, buffer.f[i].ACCEL_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(buffer.f[i].GYRO_XOUT_H, buffer.f[i].GYRO_XOUT_L);
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(combine(buffer.f[i].GYRO_YOUT_H, buffer.f[i].GYRO_YOUT_L));
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(combine(buffer.f[i].GYRO_ZOUT_H, buffer.f[i].GYRO_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
sensor_imu_fifo.temperature = (hrt_elapsed_time(&_temperature_update_timestamp) < 5_s) ? _temperature : NAN;
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf)
|
||||
+ perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ICM20608G::FIFOReset()
|
||||
@@ -537,105 +536,30 @@ void ICM20608G::FIFOReset()
|
||||
}
|
||||
}
|
||||
|
||||
static bool fifo_accel_equal(const FIFO::DATA &f0, const FIFO::DATA &f1)
|
||||
float ICM20608G::ReadTemperature()
|
||||
{
|
||||
return (memcmp(&f0.ACCEL_XOUT_H, &f1.ACCEL_XOUT_H, 6) == 0);
|
||||
}
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ};
|
||||
uint8_t TEMP_OUT_H{0};
|
||||
uint8_t TEMP_OUT_L{0};
|
||||
} buffer{};
|
||||
|
||||
bool ICM20608G::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
|
||||
bool bad_data = false;
|
||||
|
||||
// accel data is doubled in FIFO, but might be shifted
|
||||
int accel_first_sample = 1;
|
||||
|
||||
if (samples >= 4) {
|
||||
if (fifo_accel_equal(fifo[0], fifo[1]) && fifo_accel_equal(fifo[2], fifo[3])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0==A1, A2==A3
|
||||
accel_first_sample = 1;
|
||||
|
||||
} else if (fifo_accel_equal(fifo[1], fifo[2])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0, A1==A2, A3
|
||||
accel_first_sample = 0;
|
||||
|
||||
} else {
|
||||
// no matching accel samples is an error
|
||||
bad_data = true;
|
||||
perf_count(_bad_transfer_perf);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = accel_first_sample; i < samples; i = i + SAMPLES_PER_TRANSFER) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_XOUT_H, fifo[i].ACCEL_XOUT_L);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_YOUT_H, fifo[i].ACCEL_YOUT_L);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_ZOUT_H, fifo[i].ACCEL_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
|
||||
return !bad_data;
|
||||
}
|
||||
|
||||
void ICM20608G::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_XOUT_H, fifo[i].GYRO_XOUT_L);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_YOUT_H, fifo[i].GYRO_YOUT_L);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_ZOUT_H, fifo[i].GYRO_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void ICM20608G::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
uint8_t temperature_buf[3] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ;
|
||||
|
||||
if (transfer(temperature_buf, temperature_buf, sizeof(temperature_buf)) != PX4_OK) {
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
return NAN;
|
||||
}
|
||||
|
||||
const int16_t TEMP_OUT = combine(temperature_buf[1], temperature_buf[2]);
|
||||
const int16_t TEMP_OUT = combine(buffer.TEMP_OUT_H, buffer.TEMP_OUT_L);
|
||||
const float TEMP_degC = (TEMP_OUT / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
if (PX4_ISFINITE(TEMP_degC)
|
||||
&& (TEMP_degC >= TEMPERATURE_SENSOR_MIN)
|
||||
&& (TEMP_degC <= TEMPERATURE_SENSOR_MAX)) {
|
||||
|
||||
return TEMP_degC;
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2019-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_ICM20608G_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_ICM20608G;
|
||||
|
||||
class ICM20608G : public device::SPI, public I2CSPIDriver<ICM20608G>
|
||||
@@ -71,20 +72,13 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f};
|
||||
static constexpr int32_t SAMPLES_PER_TRANSFER{2}; // ensure at least 1 new accel sample per transfer
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT}; // 8000 Hz gyro
|
||||
static constexpr float ACCEL_RATE{GYRO_RATE / SAMPLES_PER_TRANSFER}; // 4000 Hz accel
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0])), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_R_W) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (1 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr float ACCEL_SCALE{CONSTANTS_ONE_G / 2048.f}; // ACCEL_FS_SEL_16G
|
||||
static constexpr float GYRO_SCALE{math::radians(2000.f / 32768.f)}; // FS_SEL
|
||||
|
||||
struct register_config_t {
|
||||
Register reg;
|
||||
@@ -97,8 +91,6 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
|
||||
static int DataReadyInterruptCallback(int irq, void *context, void *arg);
|
||||
@@ -117,14 +109,15 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
bool ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
float ReadTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
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")};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2019-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace InvenSense_ICM20608G
|
||||
{
|
||||
// TODO: move to a central header
|
||||
static constexpr uint8_t Bit0 = (1 << 0);
|
||||
static constexpr uint8_t Bit1 = (1 << 1);
|
||||
@@ -52,8 +54,6 @@ static constexpr uint8_t Bit5 = (1 << 5);
|
||||
static constexpr uint8_t Bit6 = (1 << 6);
|
||||
static constexpr uint8_t Bit7 = (1 << 7);
|
||||
|
||||
namespace InvenSense_ICM20608G
|
||||
{
|
||||
static constexpr uint32_t SPI_SPEED = 8 * 1000 * 1000; // 8MHz SPI serial interface
|
||||
static constexpr uint8_t DIR_READ = 0x80;
|
||||
|
||||
@@ -61,8 +61,11 @@ static constexpr uint8_t WHOAMI = 0xAF;
|
||||
|
||||
static constexpr float TEMPERATURE_SENSITIVITY = 326.8f; // LSB/C
|
||||
static constexpr float TEMPERATURE_OFFSET = 25.f; // C
|
||||
static constexpr float TEMPERATURE_SENSOR_MIN = -40.f; // °C
|
||||
static constexpr float TEMPERATURE_SENSOR_MAX = 85.f; // °C
|
||||
|
||||
enum class Register : uint8_t {
|
||||
|
||||
CONFIG = 0x1A,
|
||||
GYRO_CONFIG = 0x1B,
|
||||
ACCEL_CONFIG = 0x1C,
|
||||
|
||||
@@ -34,6 +34,7 @@ px4_add_module(
|
||||
MODULE drivers__imu__invensense__icm20649
|
||||
MAIN icm20649
|
||||
COMPILE_FLAGS
|
||||
${MAX_CUSTOM_OPT_LEVEL}
|
||||
SRCS
|
||||
ICM20649.cpp
|
||||
ICM20649.hpp
|
||||
@@ -41,6 +42,4 @@ px4_add_module(
|
||||
InvenSense_ICM20649_registers.hpp
|
||||
DEPENDS
|
||||
px4_work_queue
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM20649.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -43,15 +45,12 @@ static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
ICM20649::ICM20649(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
ICM20649::~ICM20649()
|
||||
@@ -61,7 +60,6 @@ ICM20649::~ICM20649()
|
||||
perf_free(_fifo_empty_perf);
|
||||
perf_free(_fifo_overflow_perf);
|
||||
perf_free(_fifo_reset_perf);
|
||||
perf_free(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
int ICM20649::init()
|
||||
@@ -79,18 +77,11 @@ int ICM20649::init()
|
||||
bool ICM20649::Reset()
|
||||
{
|
||||
_state = STATE::RESET;
|
||||
DataReadyInterruptDisable();
|
||||
ScheduleClear();
|
||||
ScheduleNow();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ICM20649::exit_and_cleanup()
|
||||
{
|
||||
DataReadyInterruptDisable();
|
||||
I2CSPIDriverBase::exit_and_cleanup();
|
||||
}
|
||||
|
||||
void ICM20649::print_status()
|
||||
{
|
||||
I2CSPIDriverBase::print_status();
|
||||
@@ -102,13 +93,13 @@ void ICM20649::print_status()
|
||||
perf_print_counter(_fifo_empty_perf);
|
||||
perf_print_counter(_fifo_overflow_perf);
|
||||
perf_print_counter(_fifo_reset_perf);
|
||||
perf_print_counter(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
int ICM20649::probe()
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
const uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
|
||||
if (whoami == WHOAMI) {
|
||||
return PX4_OK;
|
||||
@@ -175,19 +166,12 @@ void ICM20649::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
_temperature = ReadTemperature();
|
||||
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
|
||||
FIFOReset();
|
||||
|
||||
@@ -207,23 +191,6 @@ void ICM20649::RunImpl()
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
hrt_abstime timestamp_sample = now;
|
||||
|
||||
if (_data_ready_interrupt_enabled) {
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
|
||||
} else {
|
||||
perf_count(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
// push backup schedule back
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
}
|
||||
|
||||
// always check current FIFO count
|
||||
bool success = false;
|
||||
const uint16_t fifo_count = FIFOReadCount();
|
||||
@@ -241,7 +208,7 @@ void ICM20649::RunImpl()
|
||||
|
||||
if (samples > _fifo_gyro_samples) {
|
||||
// grab desired number of samples, but reschedule next cycle sooner
|
||||
int extra_samples = samples - _fifo_gyro_samples;
|
||||
const int extra_samples = samples - _fifo_gyro_samples;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
if (_fifo_gyro_samples > extra_samples) {
|
||||
@@ -260,7 +227,7 @@ void ICM20649::RunImpl()
|
||||
}
|
||||
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
if (FIFORead(now, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
@@ -275,13 +242,14 @@ void ICM20649::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_bank0_cfg[_checked_register_bank0])
|
||||
&& RegisterCheck(_register_bank2_cfg[_checked_register_bank2])
|
||||
) {
|
||||
@@ -298,7 +266,7 @@ void ICM20649::RunImpl()
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature = ReadTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
@@ -308,65 +276,10 @@ void ICM20649::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void ICM20649::ConfigureAccel()
|
||||
{
|
||||
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::BANK_2::ACCEL_CONFIG) & (Bit2 | Bit1); // 2:1 ACCEL_FS_SEL[1:0]
|
||||
|
||||
switch (ACCEL_FS_SEL) {
|
||||
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;
|
||||
|
||||
case ACCEL_FS_SEL_30G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 1024.f);
|
||||
_px4_accel.set_range(30.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ICM20649::ConfigureGyro()
|
||||
{
|
||||
const uint8_t GYRO_FS_SEL = RegisterRead(Register::BANK_2::GYRO_CONFIG_1) & (Bit2 | Bit1); // 2:1 GYRO_FS_SEL[1:0]
|
||||
|
||||
float range_dps = 0.f;
|
||||
|
||||
switch (GYRO_FS_SEL) {
|
||||
case GYRO_FS_SEL_500_DPS:
|
||||
range_dps = 500.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_1000_DPS:
|
||||
range_dps = 1000.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_2000_DPS:
|
||||
range_dps = 2000.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_4000_DPS:
|
||||
range_dps = 4000.f;
|
||||
break;
|
||||
}
|
||||
|
||||
_px4_gyro.set_scale(math::radians(range_dps / 32768.f));
|
||||
_px4_gyro.set_range(math::radians(range_dps));
|
||||
}
|
||||
|
||||
void ICM20649::ConfigureSampleRate(int sample_rate)
|
||||
{
|
||||
// round down to nearest FIFO sample dt * SAMPLES_PER_TRANSFER
|
||||
const float min_interval = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
@@ -415,57 +328,9 @@ bool ICM20649::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
int ICM20649::DataReadyInterruptCallback(int irq, void *context, void *arg)
|
||||
{
|
||||
static_cast<ICM20649 *>(arg)->DataReady();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ICM20649::DataReady()
|
||||
{
|
||||
// at least the required number of samples in the FIFO
|
||||
if (++_drdy_count >= _fifo_gyro_samples) {
|
||||
_drdy_timestamp_sample.store(hrt_absolute_time());
|
||||
_drdy_count -= _fifo_gyro_samples;
|
||||
ScheduleNow();
|
||||
}
|
||||
}
|
||||
|
||||
bool ICM20649::DataReadyInterruptConfigure()
|
||||
{
|
||||
// TODO: enable data ready interrupt
|
||||
return false;
|
||||
#if 0
|
||||
|
||||
if (_drdy_gpio == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ICM20649::DataReadyInterruptDisable()
|
||||
{
|
||||
// TODO: enable data ready interrupt
|
||||
return false;
|
||||
#if 0
|
||||
|
||||
if (_drdy_gpio == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ICM20649::RegisterCheck(const T ®_cfg)
|
||||
{
|
||||
@@ -520,54 +385,89 @@ uint16_t ICM20649::FIFOReadCount()
|
||||
{
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ;
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool ICM20649::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 3, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + FIFO_COUNTH + FIFO_COUNTL + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 3 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
const uint16_t fifo_count_bytes = combine(buffer.FIFO_COUNTH, buffer.FIFO_COUNTL);
|
||||
const uint8_t valid_samples = math::min(samples, fifo_count_samples);
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
if ((fifo_count_bytes >= FIFO::SIZE) || (valid_samples > FIFO_MAX_SAMPLES)) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
if (fifo_count_samples == 0) {
|
||||
} else if (fifo_count_samples == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t valid_samples = math::min(samples, fifo_count_samples);
|
||||
|
||||
if (valid_samples > 0) {
|
||||
ProcessGyro(timestamp_sample, buffer.f, valid_samples);
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
sensor_imu_fifo.accel_scale = ACCEL_SCALE;
|
||||
sensor_imu_fifo.gyro_scale = GYRO_SCALE;
|
||||
|
||||
if (ProcessAccel(timestamp_sample, buffer.f, valid_samples)) {
|
||||
return true;
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// 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)
|
||||
sensor_imu_fifo.accel_x[i] = combine(buffer.f[i].ACCEL_XOUT_H, buffer.f[i].ACCEL_XOUT_L);
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(combine(buffer.f[i].ACCEL_YOUT_H, buffer.f[i].ACCEL_YOUT_L));
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(combine(buffer.f[i].ACCEL_ZOUT_H, buffer.f[i].ACCEL_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(buffer.f[i].GYRO_XOUT_H, buffer.f[i].GYRO_XOUT_L);
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(combine(buffer.f[i].GYRO_YOUT_H, buffer.f[i].GYRO_YOUT_L));
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(combine(buffer.f[i].GYRO_ZOUT_H, buffer.f[i].GYRO_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
sensor_imu_fifo.temperature = (hrt_elapsed_time(&_temperature_update_timestamp) < 5_s) ? _temperature : NAN;
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf)
|
||||
+ perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -580,112 +480,34 @@ void ICM20649::FIFOReset()
|
||||
// FIFO_RST: reset FIFO
|
||||
RegisterSetBits(Register::BANK_0::FIFO_RST, FIFO_RST_BIT::FIFO_RESET);
|
||||
RegisterClearBits(Register::BANK_0::FIFO_RST, FIFO_RST_BIT::FIFO_RESET);
|
||||
|
||||
// reset while FIFO is disabled
|
||||
_drdy_count = 0;
|
||||
_drdy_timestamp_sample.store(0);
|
||||
}
|
||||
|
||||
static bool fifo_accel_equal(const FIFO::DATA &f0, const FIFO::DATA &f1)
|
||||
float ICM20649::ReadTemperature()
|
||||
{
|
||||
return (memcmp(&f0.ACCEL_XOUT_H, &f1.ACCEL_XOUT_H, 6) == 0);
|
||||
}
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::TEMP_OUT_H) | DIR_READ};
|
||||
uint8_t TEMP_OUT_H{0};
|
||||
uint8_t TEMP_OUT_L{0};
|
||||
} buffer{};
|
||||
|
||||
bool ICM20649::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
|
||||
bool bad_data = false;
|
||||
|
||||
// accel data is doubled in FIFO, but might be shifted
|
||||
int accel_first_sample = 1;
|
||||
|
||||
if (samples >= 4) {
|
||||
if (fifo_accel_equal(fifo[0], fifo[1]) && fifo_accel_equal(fifo[2], fifo[3])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0==A1, A2==A3
|
||||
accel_first_sample = 1;
|
||||
|
||||
} else if (fifo_accel_equal(fifo[1], fifo[2])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0, A1==A2, A3
|
||||
accel_first_sample = 0;
|
||||
|
||||
} else {
|
||||
// no matching accel samples is an error
|
||||
bad_data = true;
|
||||
perf_count(_bad_transfer_perf);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = accel_first_sample; i < samples; i = i + SAMPLES_PER_TRANSFER) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_XOUT_H, fifo[i].ACCEL_XOUT_L);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_YOUT_H, fifo[i].ACCEL_YOUT_L);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_ZOUT_H, fifo[i].ACCEL_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
|
||||
return !bad_data;
|
||||
}
|
||||
|
||||
void ICM20649::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_XOUT_H, fifo[i].GYRO_XOUT_L);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_YOUT_H, fifo[i].GYRO_YOUT_L);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_ZOUT_H, fifo[i].GYRO_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void ICM20649::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
uint8_t temperature_buf[3] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::BANK_0::TEMP_OUT_H) | DIR_READ;
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
if (transfer(temperature_buf, temperature_buf, sizeof(temperature_buf)) != PX4_OK) {
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
return NAN;
|
||||
}
|
||||
|
||||
const int16_t TEMP_OUT = combine(temperature_buf[1], temperature_buf[2]);
|
||||
const int16_t TEMP_OUT = combine(buffer.TEMP_OUT_H, buffer.TEMP_OUT_L);
|
||||
const float TEMP_degC = (TEMP_OUT / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
if (PX4_ISFINITE(TEMP_degC)
|
||||
&& (TEMP_degC >= TEMPERATURE_SENSOR_MIN)
|
||||
&& (TEMP_degC <= TEMPERATURE_SENSOR_MAX)) {
|
||||
|
||||
return TEMP_degC;
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_ICM20649_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_ICM20649;
|
||||
|
||||
class ICM20649 : public device::SPI, public I2CSPIDriver<ICM20649>
|
||||
@@ -67,26 +68,15 @@ public:
|
||||
void print_status() override;
|
||||
|
||||
private:
|
||||
void exit_and_cleanup() override;
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 9000.f};
|
||||
static constexpr int32_t SAMPLES_PER_TRANSFER{2}; // ensure at least 1 new accel sample per transfer
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT}; // 9000 Hz gyro
|
||||
static constexpr float ACCEL_RATE{GYRO_RATE / SAMPLES_PER_TRANSFER}; // 4500 Hz accel
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (3 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr float ACCEL_SCALE{CONSTANTS_ONE_G / 1024.f}; // ACCEL_FS_SEL_30G:
|
||||
static constexpr float GYRO_SCALE{math::radians(4000.f / 32768.f)}; // GYRO_FS_SEL_4000_DPS:
|
||||
|
||||
struct register_bank0_config_t {
|
||||
Register::BANK_0 reg;
|
||||
@@ -105,19 +95,12 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
|
||||
void SelectRegisterBank(enum REG_BANK_SEL_BIT bank, bool force = false);
|
||||
void SelectRegisterBank(Register::BANK_0 reg) { SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0); }
|
||||
void SelectRegisterBank(Register::BANK_2 reg) { SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_2); }
|
||||
|
||||
static int DataReadyInterruptCallback(int irq, void *context, void *arg);
|
||||
void DataReady();
|
||||
bool DataReadyInterruptConfigure();
|
||||
bool DataReadyInterruptDisable();
|
||||
|
||||
template <typename T> bool RegisterCheck(const T ®_cfg);
|
||||
template <typename T> uint8_t RegisterRead(T reg);
|
||||
template <typename T> void RegisterWrite(T reg, uint8_t value);
|
||||
@@ -129,21 +112,19 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
bool ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
float ReadTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
const enum Rotation _rotation;
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
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 _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")};
|
||||
perf_counter_t _fifo_overflow_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO overflow")};
|
||||
perf_counter_t _fifo_reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO reset")};
|
||||
perf_counter_t _drdy_missed_perf{nullptr};
|
||||
|
||||
hrt_abstime _reset_timestamp{0};
|
||||
hrt_abstime _last_config_check_timestamp{0};
|
||||
@@ -152,10 +133,6 @@ private:
|
||||
|
||||
enum REG_BANK_SEL_BIT _last_register_bank {REG_BANK_SEL_BIT::USER_BANK_0};
|
||||
|
||||
px4::atomic<hrt_abstime> _drdy_timestamp_sample{0};
|
||||
int32_t _drdy_count{0};
|
||||
bool _data_ready_interrupt_enabled{false};
|
||||
|
||||
enum class STATE : uint8_t {
|
||||
RESET,
|
||||
WAIT_FOR_RESET,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -61,6 +61,8 @@ static constexpr uint8_t WHOAMI = 0xE1;
|
||||
|
||||
static constexpr float TEMPERATURE_SENSITIVITY = 333.87f; // LSB/C
|
||||
static constexpr float TEMPERATURE_OFFSET = 21.f; // C
|
||||
static constexpr float TEMPERATURE_SENSOR_MIN = -40.f; // °C
|
||||
static constexpr float TEMPERATURE_SENSOR_MAX = 85.f; // °C
|
||||
|
||||
namespace Register
|
||||
{
|
||||
|
||||
@@ -41,7 +41,5 @@ px4_add_module(
|
||||
icm20689_main.cpp
|
||||
InvenSense_ICM20689_registers.hpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM20689.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ ICM20689::ICM20689(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
ICM20689::~ICM20689()
|
||||
@@ -108,7 +112,7 @@ void ICM20689::print_status()
|
||||
bool ICM20689::StoreCheckedRegisterValue(Register reg)
|
||||
{
|
||||
// 3 retries
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
uint8_t read1 = RegisterRead(reg);
|
||||
uint8_t read2 = RegisterRead(reg);
|
||||
|
||||
@@ -131,14 +135,19 @@ bool ICM20689::StoreCheckedRegisterValue(Register reg)
|
||||
|
||||
int ICM20689::probe()
|
||||
{
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
|
||||
if (whoami != WHOAMI) {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
return PX4_ERROR;
|
||||
if (whoami == WHOAMI) {
|
||||
return PX4_OK;
|
||||
|
||||
} else {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
}
|
||||
}
|
||||
|
||||
return PX4_OK;
|
||||
return PX4_ERROR;
|
||||
}
|
||||
|
||||
void ICM20689::RunImpl()
|
||||
@@ -187,8 +196,8 @@ void ICM20689::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +205,8 @@ void ICM20689::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
_temperature = ReadTemperature();
|
||||
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
@@ -234,7 +245,7 @@ void ICM20689::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
|
||||
} else {
|
||||
@@ -271,7 +282,7 @@ void ICM20689::RunImpl()
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else if (samples >= SAMPLES_PER_TRANSFER) {
|
||||
} else if (samples >= 1) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
@@ -287,6 +298,7 @@ void ICM20689::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
@@ -301,13 +313,14 @@ void ICM20689::RunImpl()
|
||||
} else {
|
||||
// register check failed, force reset
|
||||
perf_count(_bad_register_perf);
|
||||
PX4_DEBUG("Force reset because register 0x%02hhX check failed ", (uint8_t)_register_cfg[_checked_register].reg);
|
||||
Reset();
|
||||
}
|
||||
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature = ReadTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
@@ -317,65 +330,10 @@ void ICM20689::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void ICM20689::ConfigureAccel()
|
||||
{
|
||||
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::ACCEL_CONFIG) & (Bit4 | Bit3); // [4:3] ACCEL_FS_SEL[1:0]
|
||||
|
||||
switch (ACCEL_FS_SEL) {
|
||||
case ACCEL_FS_SEL_2G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 16384.f);
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
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 ICM20689::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 ICM20689::ConfigureSampleRate(int sample_rate)
|
||||
{
|
||||
// round down to nearest FIFO sample dt * SAMPLES_PER_TRANSFER
|
||||
const float min_interval = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
@@ -400,9 +358,6 @@ bool ICM20689::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -429,7 +384,7 @@ bool ICM20689::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool ICM20689::DataReadyInterruptDisable()
|
||||
@@ -438,7 +393,7 @@ bool ICM20689::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
bool ICM20689::RegisterCheck(const register_config_t ®_cfg)
|
||||
@@ -487,31 +442,75 @@ void ICM20689::RegisterSetAndClearBits(Register reg, uint8_t setbits, uint8_t cl
|
||||
|
||||
uint16_t ICM20689::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ;
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool ICM20689::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 1, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_R_W) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 1 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t valid_samples = samples;
|
||||
|
||||
ProcessGyro(timestamp_sample, buffer.f, samples);
|
||||
return ProcessAccel(timestamp_sample, buffer.f, samples);
|
||||
if (valid_samples > 0) {
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
sensor_imu_fifo.accel_scale = ACCEL_SCALE;
|
||||
sensor_imu_fifo.gyro_scale = GYRO_SCALE;
|
||||
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// 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)
|
||||
sensor_imu_fifo.accel_x[i] = combine(buffer.f[i].ACCEL_XOUT_H, buffer.f[i].ACCEL_XOUT_L);
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(combine(buffer.f[i].ACCEL_YOUT_H, buffer.f[i].ACCEL_YOUT_L));
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(combine(buffer.f[i].ACCEL_ZOUT_H, buffer.f[i].ACCEL_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(buffer.f[i].GYRO_XOUT_H, buffer.f[i].GYRO_XOUT_L);
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(combine(buffer.f[i].GYRO_YOUT_H, buffer.f[i].GYRO_YOUT_L));
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(combine(buffer.f[i].GYRO_ZOUT_H, buffer.f[i].GYRO_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
sensor_imu_fifo.temperature = (hrt_elapsed_time(&_temperature_update_timestamp) < 5_s) ? _temperature : NAN;
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf)
|
||||
+ perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ICM20689::FIFOReset()
|
||||
@@ -537,105 +536,30 @@ void ICM20689::FIFOReset()
|
||||
}
|
||||
}
|
||||
|
||||
static bool fifo_accel_equal(const FIFO::DATA &f0, const FIFO::DATA &f1)
|
||||
float ICM20689::ReadTemperature()
|
||||
{
|
||||
return (memcmp(&f0.ACCEL_XOUT_H, &f1.ACCEL_XOUT_H, 6) == 0);
|
||||
}
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ};
|
||||
uint8_t TEMP_OUT_H{0};
|
||||
uint8_t TEMP_OUT_L{0};
|
||||
} buffer{};
|
||||
|
||||
bool ICM20689::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
|
||||
bool bad_data = false;
|
||||
|
||||
// accel data is doubled in FIFO, but might be shifted
|
||||
int accel_first_sample = 1;
|
||||
|
||||
if (samples >= 4) {
|
||||
if (fifo_accel_equal(fifo[0], fifo[1]) && fifo_accel_equal(fifo[2], fifo[3])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0==A1, A2==A3
|
||||
accel_first_sample = 1;
|
||||
|
||||
} else if (fifo_accel_equal(fifo[1], fifo[2])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0, A1==A2, A3
|
||||
accel_first_sample = 0;
|
||||
|
||||
} else {
|
||||
// no matching accel samples is an error
|
||||
bad_data = true;
|
||||
perf_count(_bad_transfer_perf);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = accel_first_sample; i < samples; i = i + SAMPLES_PER_TRANSFER) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_XOUT_H, fifo[i].ACCEL_XOUT_L);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_YOUT_H, fifo[i].ACCEL_YOUT_L);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_ZOUT_H, fifo[i].ACCEL_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
|
||||
return !bad_data;
|
||||
}
|
||||
|
||||
void ICM20689::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_XOUT_H, fifo[i].GYRO_XOUT_L);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_YOUT_H, fifo[i].GYRO_YOUT_L);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_ZOUT_H, fifo[i].GYRO_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void ICM20689::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
uint8_t temperature_buf[3] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ;
|
||||
|
||||
if (transfer(temperature_buf, temperature_buf, sizeof(temperature_buf)) != PX4_OK) {
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
return NAN;
|
||||
}
|
||||
|
||||
const int16_t TEMP_OUT = combine(temperature_buf[1], temperature_buf[2]);
|
||||
const int16_t TEMP_OUT = combine(buffer.TEMP_OUT_H, buffer.TEMP_OUT_L);
|
||||
const float TEMP_degC = (TEMP_OUT / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
if (PX4_ISFINITE(TEMP_degC)
|
||||
&& (TEMP_degC >= TEMPERATURE_SENSOR_MIN)
|
||||
&& (TEMP_degC <= TEMPERATURE_SENSOR_MAX)) {
|
||||
|
||||
return TEMP_degC;
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_ICM20689_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_ICM20689;
|
||||
|
||||
class ICM20689 : public device::SPI, public I2CSPIDriver<ICM20689>
|
||||
@@ -71,20 +72,13 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f};
|
||||
static constexpr int32_t SAMPLES_PER_TRANSFER{2}; // ensure at least 1 new accel sample per transfer
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT}; // 8000 Hz gyro
|
||||
static constexpr float ACCEL_RATE{GYRO_RATE / SAMPLES_PER_TRANSFER}; // 4000 Hz accel
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0])), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_R_W) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (1 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr float ACCEL_SCALE{CONSTANTS_ONE_G / 2048.f}; // ACCEL_FS_SEL
|
||||
static constexpr float GYRO_SCALE{math::radians(2000.f / 32768.f)}; // FS_SEL
|
||||
|
||||
struct register_config_t {
|
||||
Register reg;
|
||||
@@ -97,8 +91,6 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
|
||||
static int DataReadyInterruptCallback(int irq, void *context, void *arg);
|
||||
@@ -117,14 +109,15 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
bool ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
float ReadTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
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")};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,6 +43,8 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace InvenSense_ICM20689
|
||||
{
|
||||
// TODO: move to a central header
|
||||
static constexpr uint8_t Bit0 = (1 << 0);
|
||||
static constexpr uint8_t Bit1 = (1 << 1);
|
||||
@@ -53,8 +55,6 @@ static constexpr uint8_t Bit5 = (1 << 5);
|
||||
static constexpr uint8_t Bit6 = (1 << 6);
|
||||
static constexpr uint8_t Bit7 = (1 << 7);
|
||||
|
||||
namespace InvenSense_ICM20689
|
||||
{
|
||||
static constexpr uint32_t SPI_SPEED = 8 * 1000 * 1000; // 8MHz SPI serial interface
|
||||
static constexpr uint8_t DIR_READ = 0x80;
|
||||
|
||||
@@ -62,8 +62,11 @@ static constexpr uint8_t WHOAMI = 0x98;
|
||||
|
||||
static constexpr float TEMPERATURE_SENSITIVITY = 326.8f; // LSB/C
|
||||
static constexpr float TEMPERATURE_OFFSET = 25.f; // C
|
||||
static constexpr float TEMPERATURE_SENSOR_MIN = -40.f; // °C
|
||||
static constexpr float TEMPERATURE_SENSOR_MAX = 85.f; // °C
|
||||
|
||||
enum class Register : uint8_t {
|
||||
|
||||
CONFIG = 0x1A,
|
||||
GYRO_CONFIG = 0x1B,
|
||||
ACCEL_CONFIG = 0x1C,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2020 PX4 Development Team. All rights reserved.
|
||||
# Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
@@ -34,6 +34,7 @@ px4_add_module(
|
||||
MODULE drivers__imu__invensense__icm20948
|
||||
MAIN icm20948
|
||||
COMPILE_FLAGS
|
||||
-Wno-error
|
||||
SRCS
|
||||
AKM_AK09916_registers.hpp
|
||||
ICM20948.cpp
|
||||
@@ -44,8 +45,6 @@ px4_add_module(
|
||||
InvenSense_ICM20948_registers.hpp
|
||||
DEPENDS
|
||||
px4_work_queue
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
drivers_magnetometer
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM20948.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
#include "AKM_AK09916_registers.hpp"
|
||||
|
||||
using namespace time_literals;
|
||||
@@ -46,14 +48,16 @@ ICM20948::ICM20948(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
|
||||
bool enable_magnetometer = config.custom1 == 1;
|
||||
|
||||
@@ -136,8 +140,9 @@ void ICM20948::print_status()
|
||||
|
||||
int ICM20948::probe()
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
const uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
|
||||
if (whoami == WHOAMI) {
|
||||
return PX4_OK;
|
||||
@@ -249,7 +254,7 @@ void ICM20948::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
|
||||
} else {
|
||||
@@ -311,6 +316,7 @@ void ICM20948::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
@@ -346,65 +352,10 @@ void ICM20948::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void ICM20948::ConfigureAccel()
|
||||
{
|
||||
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::BANK_2::ACCEL_CONFIG) & (Bit2 | Bit1); // 2:1 ACCEL_FS_SEL[1:0]
|
||||
|
||||
switch (ACCEL_FS_SEL) {
|
||||
case ACCEL_FS_SEL_2G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 16384.f);
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
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 ICM20948::ConfigureGyro()
|
||||
{
|
||||
const uint8_t GYRO_FS_SEL = RegisterRead(Register::BANK_2::GYRO_CONFIG_1) & (Bit2 | Bit1); // 2:1 GYRO_FS_SEL[1:0]
|
||||
|
||||
float range_dps = 0.f;
|
||||
|
||||
switch (GYRO_FS_SEL) {
|
||||
case GYRO_FS_SEL_250_DPS:
|
||||
range_dps = 250.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_500_DPS:
|
||||
range_dps = 500.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_1000_DPS:
|
||||
range_dps = 1000.f;
|
||||
break;
|
||||
|
||||
case GYRO_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 ICM20948::ConfigureSampleRate(int sample_rate)
|
||||
{
|
||||
// round down to nearest FIFO sample dt * SAMPLES_PER_TRANSFER
|
||||
const float min_interval = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
@@ -462,9 +413,6 @@ bool ICM20948::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -567,54 +515,89 @@ uint16_t ICM20948::FIFOReadCount()
|
||||
{
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ;
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool ICM20948::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 3, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + FIFO_COUNTH + FIFO_COUNTL + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 3 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
const uint16_t fifo_count_bytes = combine(buffer.FIFO_COUNTH, buffer.FIFO_COUNTL);
|
||||
const uint8_t valid_samples = math::min(samples, fifo_count_samples);
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
if ((fifo_count_bytes >= FIFO::SIZE) || (valid_samples > FIFO_MAX_SAMPLES)) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
if (fifo_count_samples == 0) {
|
||||
} else if (fifo_count_samples == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t valid_samples = math::min(samples, fifo_count_samples);
|
||||
|
||||
if (valid_samples > 0) {
|
||||
ProcessGyro(timestamp_sample, buffer.f, valid_samples);
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
sensor_imu_fifo.accel_scale = ACCEL_SCALE;
|
||||
sensor_imu_fifo.gyro_scale = GYRO_SCALE;
|
||||
|
||||
if (ProcessAccel(timestamp_sample, buffer.f, valid_samples)) {
|
||||
return true;
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// 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)
|
||||
sensor_imu_fifo.accel_x[i] = combine(buffer.f[i].ACCEL_XOUT_H, buffer.f[i].ACCEL_XOUT_L);
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(combine(buffer.f[i].ACCEL_YOUT_H, buffer.f[i].ACCEL_YOUT_L));
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(combine(buffer.f[i].ACCEL_ZOUT_H, buffer.f[i].ACCEL_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(buffer.f[i].GYRO_XOUT_H, buffer.f[i].GYRO_XOUT_L);
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(combine(buffer.f[i].GYRO_YOUT_H, buffer.f[i].GYRO_YOUT_L));
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(combine(buffer.f[i].GYRO_ZOUT_H, buffer.f[i].GYRO_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
sensor_imu_fifo.temperature = (hrt_elapsed_time(&_temperature_update_timestamp) < 5_s) ? _temperature : NAN;
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf)
|
||||
+ perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -633,89 +616,6 @@ void ICM20948::FIFOReset()
|
||||
_drdy_timestamp_sample.store(0);
|
||||
}
|
||||
|
||||
static bool fifo_accel_equal(const FIFO::DATA &f0, const FIFO::DATA &f1)
|
||||
{
|
||||
return (memcmp(&f0.ACCEL_XOUT_H, &f1.ACCEL_XOUT_H, 6) == 0);
|
||||
}
|
||||
|
||||
bool ICM20948::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
|
||||
bool bad_data = false;
|
||||
|
||||
// accel data is doubled in FIFO, but might be shifted
|
||||
int accel_first_sample = 1;
|
||||
|
||||
if (samples >= 4) {
|
||||
if (fifo_accel_equal(fifo[0], fifo[1]) && fifo_accel_equal(fifo[2], fifo[3])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0==A1, A2==A3
|
||||
accel_first_sample = 1;
|
||||
|
||||
} else if (fifo_accel_equal(fifo[1], fifo[2])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0, A1==A2, A3
|
||||
accel_first_sample = 0;
|
||||
|
||||
} else {
|
||||
// no matching accel samples is an error
|
||||
bad_data = true;
|
||||
perf_count(_bad_transfer_perf);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = accel_first_sample; i < samples; i = i + SAMPLES_PER_TRANSFER) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_XOUT_H, fifo[i].ACCEL_XOUT_L);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_YOUT_H, fifo[i].ACCEL_YOUT_L);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_ZOUT_H, fifo[i].ACCEL_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
|
||||
return !bad_data;
|
||||
}
|
||||
|
||||
void ICM20948::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_XOUT_H, fifo[i].GYRO_XOUT_L);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_YOUT_H, fifo[i].GYRO_YOUT_L);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_ZOUT_H, fifo[i].GYRO_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void ICM20948::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
@@ -732,8 +632,7 @@ void ICM20948::UpdateTemperature()
|
||||
const float TEMP_degC = (TEMP_OUT / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
_temperature = TEMP_degC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_ICM20948_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
#include "ICM20948_AK09916.hpp"
|
||||
|
||||
using namespace InvenSense_ICM20948;
|
||||
@@ -73,22 +74,13 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 9000.f};
|
||||
static constexpr int32_t SAMPLES_PER_TRANSFER{2}; // ensure at least 1 new accel sample per transfer
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT}; // 9000 Hz gyro
|
||||
static constexpr float ACCEL_RATE{GYRO_RATE / SAMPLES_PER_TRANSFER}; // 4500 Hz accel
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (3 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr float ACCEL_SCALE{CONSTANTS_ONE_G / 2048.f}; // ACCEL_FS_SEL_16G:
|
||||
static constexpr float GYRO_SCALE{math::radians(2000.f / 32768.f)}; // GYRO_FS_SEL_2000_DPS:
|
||||
|
||||
struct register_bank0_config_t {
|
||||
Register::BANK_0 reg;
|
||||
@@ -113,8 +105,6 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
|
||||
void SelectRegisterBank(enum REG_BANK_SEL_BIT bank, bool force = false);
|
||||
@@ -138,12 +128,16 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
bool ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
// I2C AUX interface (slave 1 - 4)
|
||||
AKM_AK09916::ICM20948_AK09916 *_slave_ak09916_magnetometer{nullptr};
|
||||
friend class AKM_AK09916::ICM20948_AK09916;
|
||||
@@ -152,9 +146,6 @@ private:
|
||||
void I2CSlaveExternalSensorDataEnable(uint8_t slave_i2c_addr, uint8_t reg, uint8_t size);
|
||||
bool I2CSlaveExternalSensorDataRead(uint8_t *buffer, uint8_t length);
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
|
||||
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 _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")};
|
||||
|
||||
@@ -41,6 +41,4 @@ px4_add_module(
|
||||
InvenSense_ICM40609D_registers.hpp
|
||||
DEPENDS
|
||||
px4_work_queue
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM40609D.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ ICM40609D::ICM40609D(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
ICM40609D::~ICM40609D()
|
||||
@@ -61,6 +65,7 @@ ICM40609D::~ICM40609D()
|
||||
perf_free(_fifo_empty_perf);
|
||||
perf_free(_fifo_overflow_perf);
|
||||
perf_free(_fifo_reset_perf);
|
||||
perf_free(_fifo_timestamp_error_perf);
|
||||
perf_free(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
@@ -102,12 +107,14 @@ void ICM40609D::print_status()
|
||||
perf_print_counter(_fifo_empty_perf);
|
||||
perf_print_counter(_fifo_overflow_perf);
|
||||
perf_print_counter(_fifo_reset_perf);
|
||||
perf_print_counter(_fifo_timestamp_error_perf);
|
||||
perf_print_counter(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
int ICM40609D::probe()
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
|
||||
if (whoami == WHOAMI) {
|
||||
@@ -161,8 +168,8 @@ void ICM40609D::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,21 +177,9 @@ void ICM40609D::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
FIFOReset();
|
||||
// if configure succeeded then reset the FIFO
|
||||
_state = STATE::FIFO_RESET;
|
||||
ScheduleDelayed(1_ms);
|
||||
|
||||
} else {
|
||||
// CONFIGURE not complete
|
||||
@@ -201,6 +196,24 @@ void ICM40609D::RunImpl()
|
||||
|
||||
break;
|
||||
|
||||
case STATE::FIFO_RESET:
|
||||
|
||||
_state = STATE::FIFO_READ;
|
||||
FIFOReset();
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
hrt_abstime timestamp_sample = now;
|
||||
uint8_t samples = 0;
|
||||
@@ -209,7 +222,7 @@ void ICM40609D::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
@@ -221,6 +234,8 @@ void ICM40609D::RunImpl()
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples == 0) {
|
||||
// check current FIFO count
|
||||
const uint16_t fifo_count = FIFOReadCount();
|
||||
@@ -233,27 +248,42 @@ void ICM40609D::RunImpl()
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
} else {
|
||||
// FIFO count (size in bytes)
|
||||
samples = (fifo_count / sizeof(FIFO::DATA));
|
||||
// FIFO count (size in bytes) should be a multiple of the FIFO::DATA structure
|
||||
samples = fifo_count / sizeof(FIFO::DATA);
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_gyro_samples + 1) {
|
||||
timestamp_sample -= static_cast<int>(FIFO_SAMPLE_DT);
|
||||
samples--;
|
||||
if (samples > _fifo_gyro_samples) {
|
||||
// grab desired number of samples, but reschedule next cycle sooner
|
||||
const int extra_samples = samples - _fifo_gyro_samples;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
if (_fifo_gyro_samples > extra_samples) {
|
||||
// reschedule to run when a total of _fifo_gyro_samples should be available in the FIFO
|
||||
const uint32_t reschedule_delay_us = (_fifo_gyro_samples - extra_samples) * static_cast<int>(FIFO_SAMPLE_DT);
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, reschedule_delay_us);
|
||||
|
||||
} else {
|
||||
// otherwise reschedule to run immediately
|
||||
ScheduleOnInterval(_fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
} else if (samples < _fifo_gyro_samples) {
|
||||
// reschedule next cycle to catch the desired number of samples
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, (_fifo_gyro_samples - samples) * static_cast<int>(FIFO_SAMPLE_DT));
|
||||
}
|
||||
|
||||
if (samples > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
samples = 0;
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(now, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples >= 1) {
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
@@ -268,13 +298,14 @@ void ICM40609D::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_bank0_cfg[_checked_register_bank0])
|
||||
) {
|
||||
_last_config_check_timestamp = now;
|
||||
@@ -285,13 +316,6 @@ void ICM40609D::RunImpl()
|
||||
perf_count(_bad_register_perf);
|
||||
Reset();
|
||||
}
|
||||
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,75 +323,16 @@ void ICM40609D::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void ICM40609D::ConfigureAccel()
|
||||
{
|
||||
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::BANK_0::ACCEL_CONFIG0) & (Bit7 | Bit6 | Bit5); // 7:5 ACCEL_FS_SEL
|
||||
|
||||
switch (ACCEL_FS_SEL) {
|
||||
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;
|
||||
|
||||
case ACCEL_FS_SEL_32G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 1024.f);
|
||||
_px4_accel.set_range(32.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ICM40609D::ConfigureGyro()
|
||||
{
|
||||
const uint8_t GYRO_FS_SEL = RegisterRead(Register::BANK_0::GYRO_CONFIG0) & (Bit7 | Bit6 | Bit5); // 7:5 GYRO_FS_SEL
|
||||
|
||||
float range_dps = 0.f;
|
||||
|
||||
switch (GYRO_FS_SEL) {
|
||||
case GYRO_FS_SEL_125_DPS:
|
||||
range_dps = 125.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_250_DPS:
|
||||
range_dps = 250.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_500_DPS:
|
||||
range_dps = 500.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_1000_DPS:
|
||||
range_dps = 1000.f;
|
||||
break;
|
||||
|
||||
case GYRO_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 ICM40609D::ConfigureSampleRate(int sample_rate)
|
||||
{
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / RATE), (float)FIFO_MAX_SAMPLES));
|
||||
|
||||
// recompute FIFO empty interval (us) with actual gyro sample limit
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / GYRO_RATE);
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / RATE);
|
||||
|
||||
ConfigureFIFOWatermark(_fifo_gyro_samples);
|
||||
}
|
||||
@@ -418,9 +383,6 @@ bool ICM40609D::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -443,7 +405,7 @@ bool ICM40609D::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool ICM40609D::DataReadyInterruptDisable()
|
||||
@@ -452,7 +414,7 @@ bool ICM40609D::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -507,23 +469,36 @@ void ICM40609D::RegisterSetAndClearBits(T reg, uint8_t setbits, uint8_t clearbit
|
||||
|
||||
uint16_t ICM40609D::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ;
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool ICM40609D::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 4, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + INT_STATUS + FIFO_COUNTH + FIFO_COUNTL + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 4 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
@@ -537,7 +512,7 @@ bool ICM40609D::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = combine(buffer.FIFO_COUNTH, buffer.FIFO_COUNTL);
|
||||
const uint16_t fifo_count_bytes = (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
@@ -552,40 +527,151 @@ bool ICM40609D::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = 0;
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 8192.f; // highres accel data 8192 LSB/g
|
||||
sensor_imu_fifo.gyro_scale = math::radians(1.f / 131.f); // highres gyro data 131 LSB/dps
|
||||
|
||||
// check FIFO header in every sample
|
||||
uint8_t valid_samples = 0;
|
||||
|
||||
float temperature_sum = 0;
|
||||
|
||||
float timestamp_interval_sum = 0;
|
||||
int timestamp_interval_sum_count = 0;
|
||||
|
||||
bool accel_scale_16bit = false; // 18-bits of accelerometer data
|
||||
bool gyro_scale_16bit = false; // 20-bits of gyroscope data
|
||||
|
||||
for (int i = 0; i < math::min(samples, fifo_count_samples); i++) {
|
||||
bool valid = true;
|
||||
const FIFO::DATA &fifo = buffer.f[i];
|
||||
|
||||
// With FIFO_ACCEL_EN and FIFO_GYRO_EN header should be 8’b_0110_10xx
|
||||
const uint8_t FIFO_HEADER = buffer.f[i].FIFO_Header;
|
||||
const uint8_t FIFO_HEADER = fifo.FIFO_Header;
|
||||
|
||||
if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG) {
|
||||
// FIFO sample empty if HEADER_MSG set
|
||||
valid = false;
|
||||
const bool HEADER_MSG = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG; // FIFO is empty
|
||||
const bool HEADER_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL;
|
||||
const bool HEADER_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO;
|
||||
// 3:2 HEADER_TIMESTAMP_FSYNC
|
||||
const bool HEADER_ODR_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_ACCEL; // ODR for accel is different
|
||||
const bool HEADER_ODR_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_GYRO; // ODR for gyro is different
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL)) {
|
||||
// accel bit not set
|
||||
valid = false;
|
||||
if (!HEADER_MSG && HEADER_ACCEL && HEADER_GYRO && HEADER_20 && !HEADER_ODR_ACCEL && !HEADER_ODR_GYRO) {
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO)) {
|
||||
// gyro bit not set
|
||||
valid = false;
|
||||
}
|
||||
// 20 bit data scaled to 16 bit
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 2048.f;
|
||||
|
||||
sensor_imu_fifo.accel_x[valid_samples] = combine(fifo.ACCEL_DATA_X1, fifo.ACCEL_DATA_X0);
|
||||
sensor_imu_fifo.accel_y[valid_samples] = combine(fifo.ACCEL_DATA_Y1, fifo.ACCEL_DATA_Y0);
|
||||
sensor_imu_fifo.accel_z[valid_samples] = combine(fifo.ACCEL_DATA_Z1, fifo.ACCEL_DATA_Z0);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(fifo.GYRO_DATA_X1, fifo.GYRO_DATA_X0);
|
||||
sensor_imu_fifo.gyro_y[i] = combine(fifo.GYRO_DATA_Y1, fifo.GYRO_DATA_Y0);
|
||||
sensor_imu_fifo.gyro_z[i] = combine(fifo.GYRO_DATA_Z1, fifo.GYRO_DATA_Z0);
|
||||
|
||||
// temperature
|
||||
const int16_t TEMP_DATA = combine(fifo.TEMP_DATA1, fifo.TEMP_DATA0);
|
||||
|
||||
// sample invalid if -32768
|
||||
if (TEMP_DATA != -32768) {
|
||||
temperature_sum += TEMP_DATA;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// HEADER_TIMESTAMP_FSYNC - 0b10: Packet contains ODR Timestamp
|
||||
if (FIFO_HEADER & Bit3) {
|
||||
const uint16_t timestamp = (fifo.TimeStamp_h << 8) + fifo.TimeStamp_l;
|
||||
|
||||
if (_timestamp_prev != 0) {
|
||||
// If TMST_RES = 0 (corresponding to timestamp resolution of 1µs), timestamp interval reported in FIFO requires scaling by a factor of 32/30.
|
||||
// Document Number: DS-000347 Revision: 1.5 Page 59 of 110
|
||||
static constexpr float FIFO_DT_SCALE = 32.f / 30.f;
|
||||
|
||||
float dt = 0;
|
||||
|
||||
if (timestamp > _timestamp_prev) {
|
||||
dt = static_cast<float>(timestamp - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
|
||||
} else if (timestamp < _timestamp_prev) {
|
||||
// uint16_t rollover
|
||||
uint32_t timestamp_new = UINT16_MAX + timestamp;
|
||||
dt = static_cast<float>(timestamp_new - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
}
|
||||
|
||||
timestamp_interval_sum += dt;
|
||||
timestamp_interval_sum_count++;
|
||||
|
||||
// check dt is within +=2% of expected value
|
||||
if ((dt < (FIFO_SAMPLE_DT * 0.98f)) || (dt > (FIFO_SAMPLE_DT * 1.02f))) {
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
}
|
||||
}
|
||||
|
||||
_timestamp_prev = timestamp;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
valid_samples++;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_samples > 0) {
|
||||
ProcessGyro(timestamp_sample, buffer.f, valid_samples);
|
||||
ProcessAccel(timestamp_sample, buffer.f, valid_samples);
|
||||
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
|
||||
for (int i = 0; i < sensor_imu_fifo.samples; i++) {
|
||||
// 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)
|
||||
|
||||
// sensor_imu_fifo.accel_x[i]
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(sensor_imu_fifo.accel_y[i]);
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(sensor_imu_fifo.accel_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
// sensor_imu_fifo.gyro_x[i]
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(sensor_imu_fifo.gyro_y[i]);
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(sensor_imu_fifo.gyro_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
const float temperature_avg = temperature_sum / valid_samples;
|
||||
|
||||
// use average temperature reading
|
||||
const float TEMP_degC = (temperature_avg / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
sensor_imu_fifo.temperature = TEMP_degC;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timestamp_interval_sum > 0) {
|
||||
const float dt_avg = (timestamp_interval_sum / timestamp_interval_sum_count);
|
||||
|
||||
// check dt is within +=1% of expected value
|
||||
if ((dt_avg < (FIFO_SAMPLE_DT * 0.99f)) || (dt_avg > (FIFO_SAMPLE_DT * 1.01f))) {
|
||||
PX4_ERR("DT error %.6f", (double)dt_avg);
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.dt = dt_avg;
|
||||
}
|
||||
}
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -601,80 +687,6 @@ void ICM40609D::FIFOReset()
|
||||
|
||||
// reset while FIFO is disabled
|
||||
_drdy_timestamp_sample.store(0);
|
||||
}
|
||||
|
||||
void ICM40609D::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_DATA_X1, fifo[i].ACCEL_DATA_X0);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_DATA_Y1, fifo[i].ACCEL_DATA_Y0);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_DATA_Z1, fifo[i].ACCEL_DATA_Z0);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
}
|
||||
|
||||
void ICM40609D::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_DATA_X1, fifo[i].GYRO_DATA_X0);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_DATA_Y1, fifo[i].GYRO_DATA_Y0);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_DATA_Z1, fifo[i].GYRO_DATA_Z0);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void ICM40609D::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
uint8_t temperature_buf[3] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::BANK_0::TEMP_DATA1) | DIR_READ;
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
if (transfer(temperature_buf, temperature_buf, sizeof(temperature_buf)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
const int16_t TEMP_DATA = combine(temperature_buf[1], temperature_buf[2]);
|
||||
|
||||
// Temperature in Degrees Centigrade
|
||||
const float TEMP_degC = (TEMP_DATA / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
}
|
||||
|
||||
_timestamp_prev = 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_ICM40609D_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_ICM40609D;
|
||||
|
||||
class ICM40609D : public device::SPI, public I2CSPIDriver<ICM40609D>
|
||||
@@ -71,22 +72,10 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f}; // 8000 Hz accel & gyro ODR configured
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float ACCEL_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0])), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (4 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
struct register_bank0_config_t {
|
||||
Register::BANK_0 reg;
|
||||
@@ -99,8 +88,6 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
void ConfigureFIFOWatermark(uint8_t samples);
|
||||
|
||||
@@ -123,20 +110,18 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
void ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
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 _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")};
|
||||
perf_counter_t _fifo_overflow_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO overflow")};
|
||||
perf_counter_t _fifo_reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO reset")};
|
||||
perf_counter_t _fifo_timestamp_error_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO timestamp error")};
|
||||
perf_counter_t _drdy_missed_perf{nullptr};
|
||||
|
||||
hrt_abstime _reset_timestamp{0};
|
||||
@@ -144,6 +129,8 @@ private:
|
||||
hrt_abstime _temperature_update_timestamp{0};
|
||||
int _failure_count{0};
|
||||
|
||||
uint16_t _timestamp_prev{0};
|
||||
|
||||
enum REG_BANK_SEL_BIT _last_register_bank {REG_BANK_SEL_BIT::USER_BANK_0};
|
||||
|
||||
px4::atomic<hrt_abstime> _drdy_timestamp_sample{0};
|
||||
@@ -153,11 +140,12 @@ private:
|
||||
RESET,
|
||||
WAIT_FOR_RESET,
|
||||
CONFIGURE,
|
||||
FIFO_RESET,
|
||||
FIFO_READ,
|
||||
} _state{STATE::RESET};
|
||||
|
||||
uint16_t _fifo_empty_interval_us{1250}; // default 1250 us / 800 Hz transfer interval
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / GYRO_RATE))};
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / RATE))};
|
||||
|
||||
uint8_t _checked_register_bank0{0};
|
||||
static constexpr uint8_t size_register_bank0_cfg{10};
|
||||
|
||||
@@ -41,6 +41,4 @@ px4_add_module(
|
||||
InvenSense_ICM42605_registers.hpp
|
||||
DEPENDS
|
||||
px4_work_queue
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM42605.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ ICM42605::ICM42605(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
ICM42605::~ICM42605()
|
||||
@@ -61,6 +65,7 @@ ICM42605::~ICM42605()
|
||||
perf_free(_fifo_empty_perf);
|
||||
perf_free(_fifo_overflow_perf);
|
||||
perf_free(_fifo_reset_perf);
|
||||
perf_free(_fifo_timestamp_error_perf);
|
||||
perf_free(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
@@ -102,12 +107,14 @@ void ICM42605::print_status()
|
||||
perf_print_counter(_fifo_empty_perf);
|
||||
perf_print_counter(_fifo_overflow_perf);
|
||||
perf_print_counter(_fifo_reset_perf);
|
||||
perf_print_counter(_fifo_timestamp_error_perf);
|
||||
perf_print_counter(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
int ICM42605::probe()
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
|
||||
if (whoami == WHOAMI) {
|
||||
@@ -162,8 +169,8 @@ void ICM42605::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,21 +178,9 @@ void ICM42605::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
FIFOReset();
|
||||
// if configure succeeded then reset the FIFO
|
||||
_state = STATE::FIFO_RESET;
|
||||
ScheduleDelayed(1_ms);
|
||||
|
||||
} else {
|
||||
// CONFIGURE not complete
|
||||
@@ -202,6 +197,24 @@ void ICM42605::RunImpl()
|
||||
|
||||
break;
|
||||
|
||||
case STATE::FIFO_RESET:
|
||||
|
||||
_state = STATE::FIFO_READ;
|
||||
FIFOReset();
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
hrt_abstime timestamp_sample = now;
|
||||
uint8_t samples = 0;
|
||||
@@ -210,7 +223,7 @@ void ICM42605::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
@@ -222,6 +235,8 @@ void ICM42605::RunImpl()
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples == 0) {
|
||||
// check current FIFO count
|
||||
const uint16_t fifo_count = FIFOReadCount();
|
||||
@@ -234,27 +249,42 @@ void ICM42605::RunImpl()
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
} else {
|
||||
// FIFO count (size in bytes)
|
||||
samples = (fifo_count / sizeof(FIFO::DATA));
|
||||
// FIFO count (size in bytes) should be a multiple of the FIFO::DATA structure
|
||||
samples = fifo_count / sizeof(FIFO::DATA);
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_gyro_samples + 1) {
|
||||
timestamp_sample -= static_cast<int>(FIFO_SAMPLE_DT);
|
||||
samples--;
|
||||
if (samples > _fifo_gyro_samples) {
|
||||
// grab desired number of samples, but reschedule next cycle sooner
|
||||
const int extra_samples = samples - _fifo_gyro_samples;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
if (_fifo_gyro_samples > extra_samples) {
|
||||
// reschedule to run when a total of _fifo_gyro_samples should be available in the FIFO
|
||||
const uint32_t reschedule_delay_us = (_fifo_gyro_samples - extra_samples) * static_cast<int>(FIFO_SAMPLE_DT);
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, reschedule_delay_us);
|
||||
|
||||
} else {
|
||||
// otherwise reschedule to run immediately
|
||||
ScheduleOnInterval(_fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
} else if (samples < _fifo_gyro_samples) {
|
||||
// reschedule next cycle to catch the desired number of samples
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, (_fifo_gyro_samples - samples) * static_cast<int>(FIFO_SAMPLE_DT));
|
||||
}
|
||||
|
||||
if (samples > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
samples = 0;
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(now, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples >= 1) {
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
@@ -269,13 +299,14 @@ void ICM42605::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_bank0_cfg[_checked_register_bank0])
|
||||
) {
|
||||
_last_config_check_timestamp = now;
|
||||
@@ -286,13 +317,6 @@ void ICM42605::RunImpl()
|
||||
perf_count(_bad_register_perf);
|
||||
Reset();
|
||||
}
|
||||
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,75 +324,16 @@ void ICM42605::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void ICM42605::ConfigureAccel()
|
||||
{
|
||||
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::BANK_0::ACCEL_CONFIG0) & (Bit7 | Bit6 | Bit5); // 7:5 ACCEL_FS_SEL
|
||||
|
||||
switch (ACCEL_FS_SEL) {
|
||||
case ACCEL_FS_SEL_2G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 16384.f);
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
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 ICM42605::ConfigureGyro()
|
||||
{
|
||||
const uint8_t GYRO_FS_SEL = RegisterRead(Register::BANK_0::GYRO_CONFIG0) & (Bit7 | Bit6 | Bit5); // 7:5 GYRO_FS_SEL
|
||||
|
||||
float range_dps = 0.f;
|
||||
|
||||
switch (GYRO_FS_SEL) {
|
||||
case GYRO_FS_SEL_125_DPS:
|
||||
range_dps = 125.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_250_DPS:
|
||||
range_dps = 250.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_500_DPS:
|
||||
range_dps = 500.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_1000_DPS:
|
||||
range_dps = 1000.f;
|
||||
break;
|
||||
|
||||
case GYRO_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 ICM42605::ConfigureSampleRate(int sample_rate)
|
||||
{
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / RATE), (float)FIFO_MAX_SAMPLES));
|
||||
|
||||
// recompute FIFO empty interval (us) with actual gyro sample limit
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / GYRO_RATE);
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / RATE);
|
||||
|
||||
ConfigureFIFOWatermark(_fifo_gyro_samples);
|
||||
}
|
||||
@@ -419,9 +384,6 @@ bool ICM42605::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -444,7 +406,7 @@ bool ICM42605::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool ICM42605::DataReadyInterruptDisable()
|
||||
@@ -453,7 +415,7 @@ bool ICM42605::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -508,23 +470,36 @@ void ICM42605::RegisterSetAndClearBits(T reg, uint8_t setbits, uint8_t clearbits
|
||||
|
||||
uint16_t ICM42605::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ;
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool ICM42605::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 4, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + INT_STATUS + FIFO_COUNTH + FIFO_COUNTL + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 4 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
@@ -538,7 +513,7 @@ bool ICM42605::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = combine(buffer.FIFO_COUNTH, buffer.FIFO_COUNTL);
|
||||
const uint16_t fifo_count_bytes = (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
@@ -553,40 +528,151 @@ bool ICM42605::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = 0;
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 8192.f; // highres accel data 8192 LSB/g
|
||||
sensor_imu_fifo.gyro_scale = math::radians(1.f / 131.f); // highres gyro data 131 LSB/dps
|
||||
|
||||
// check FIFO header in every sample
|
||||
uint8_t valid_samples = 0;
|
||||
|
||||
float temperature_sum = 0;
|
||||
|
||||
float timestamp_interval_sum = 0;
|
||||
int timestamp_interval_sum_count = 0;
|
||||
|
||||
bool accel_scale_16bit = false; // 18-bits of accelerometer data
|
||||
bool gyro_scale_16bit = false; // 20-bits of gyroscope data
|
||||
|
||||
for (int i = 0; i < math::min(samples, fifo_count_samples); i++) {
|
||||
bool valid = true;
|
||||
const FIFO::DATA &fifo = buffer.f[i];
|
||||
|
||||
// With FIFO_ACCEL_EN and FIFO_GYRO_EN header should be 8’b_0110_10xx
|
||||
const uint8_t FIFO_HEADER = buffer.f[i].FIFO_Header;
|
||||
const uint8_t FIFO_HEADER = fifo.FIFO_Header;
|
||||
|
||||
if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG) {
|
||||
// FIFO sample empty if HEADER_MSG set
|
||||
valid = false;
|
||||
const bool HEADER_MSG = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG; // FIFO is empty
|
||||
const bool HEADER_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL;
|
||||
const bool HEADER_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO;
|
||||
// 3:2 HEADER_TIMESTAMP_FSYNC
|
||||
const bool HEADER_ODR_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_ACCEL; // ODR for accel is different
|
||||
const bool HEADER_ODR_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_GYRO; // ODR for gyro is different
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL)) {
|
||||
// accel bit not set
|
||||
valid = false;
|
||||
if (!HEADER_MSG && HEADER_ACCEL && HEADER_GYRO && HEADER_20 && !HEADER_ODR_ACCEL && !HEADER_ODR_GYRO) {
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO)) {
|
||||
// gyro bit not set
|
||||
valid = false;
|
||||
}
|
||||
// 20 bit data scaled to 16 bit
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 2048.f;
|
||||
|
||||
sensor_imu_fifo.accel_x[valid_samples] = combine(fifo.ACCEL_DATA_X1, fifo.ACCEL_DATA_X0);
|
||||
sensor_imu_fifo.accel_y[valid_samples] = combine(fifo.ACCEL_DATA_Y1, fifo.ACCEL_DATA_Y0);
|
||||
sensor_imu_fifo.accel_z[valid_samples] = combine(fifo.ACCEL_DATA_Z1, fifo.ACCEL_DATA_Z0);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(fifo.GYRO_DATA_X1, fifo.GYRO_DATA_X0);
|
||||
sensor_imu_fifo.gyro_y[i] = combine(fifo.GYRO_DATA_Y1, fifo.GYRO_DATA_Y0);
|
||||
sensor_imu_fifo.gyro_z[i] = combine(fifo.GYRO_DATA_Z1, fifo.GYRO_DATA_Z0);
|
||||
|
||||
// temperature
|
||||
const int16_t TEMP_DATA = combine(fifo.TEMP_DATA1, fifo.TEMP_DATA0);
|
||||
|
||||
// sample invalid if -32768
|
||||
if (TEMP_DATA != -32768) {
|
||||
temperature_sum += TEMP_DATA;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// HEADER_TIMESTAMP_FSYNC - 0b10: Packet contains ODR Timestamp
|
||||
if (FIFO_HEADER & Bit3) {
|
||||
const uint16_t timestamp = (fifo.TimeStamp_h << 8) + fifo.TimeStamp_l;
|
||||
|
||||
if (_timestamp_prev != 0) {
|
||||
// If TMST_RES = 0 (corresponding to timestamp resolution of 1µs), timestamp interval reported in FIFO requires scaling by a factor of 32/30.
|
||||
// Document Number: DS-000347 Revision: 1.5 Page 59 of 110
|
||||
static constexpr float FIFO_DT_SCALE = 32.f / 30.f;
|
||||
|
||||
float dt = 0;
|
||||
|
||||
if (timestamp > _timestamp_prev) {
|
||||
dt = static_cast<float>(timestamp - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
|
||||
} else if (timestamp < _timestamp_prev) {
|
||||
// uint16_t rollover
|
||||
uint32_t timestamp_new = UINT16_MAX + timestamp;
|
||||
dt = static_cast<float>(timestamp_new - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
}
|
||||
|
||||
timestamp_interval_sum += dt;
|
||||
timestamp_interval_sum_count++;
|
||||
|
||||
// check dt is within +=2% of expected value
|
||||
if ((dt < (FIFO_SAMPLE_DT * 0.98f)) || (dt > (FIFO_SAMPLE_DT * 1.02f))) {
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
}
|
||||
}
|
||||
|
||||
_timestamp_prev = timestamp;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
valid_samples++;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_samples > 0) {
|
||||
ProcessGyro(timestamp_sample, buffer.f, valid_samples);
|
||||
ProcessAccel(timestamp_sample, buffer.f, valid_samples);
|
||||
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
|
||||
for (int i = 0; i < sensor_imu_fifo.samples; i++) {
|
||||
// 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)
|
||||
|
||||
// sensor_imu_fifo.accel_x[i]
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(sensor_imu_fifo.accel_y[i]);
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(sensor_imu_fifo.accel_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
// sensor_imu_fifo.gyro_x[i]
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(sensor_imu_fifo.gyro_y[i]);
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(sensor_imu_fifo.gyro_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
const float temperature_avg = temperature_sum / valid_samples;
|
||||
|
||||
// use average temperature reading
|
||||
const float TEMP_degC = (temperature_avg / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
sensor_imu_fifo.temperature = TEMP_degC;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timestamp_interval_sum > 0) {
|
||||
const float dt_avg = (timestamp_interval_sum / timestamp_interval_sum_count);
|
||||
|
||||
// check dt is within +=1% of expected value
|
||||
if ((dt_avg < (FIFO_SAMPLE_DT * 0.99f)) || (dt_avg > (FIFO_SAMPLE_DT * 1.01f))) {
|
||||
PX4_ERR("DT error %.6f", (double)dt_avg);
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.dt = dt_avg;
|
||||
}
|
||||
}
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -602,80 +688,6 @@ void ICM42605::FIFOReset()
|
||||
|
||||
// reset while FIFO is disabled
|
||||
_drdy_timestamp_sample.store(0);
|
||||
}
|
||||
|
||||
void ICM42605::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_DATA_X1, fifo[i].ACCEL_DATA_X0);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_DATA_Y1, fifo[i].ACCEL_DATA_Y0);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_DATA_Z1, fifo[i].ACCEL_DATA_Z0);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
}
|
||||
|
||||
void ICM42605::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_DATA_X1, fifo[i].GYRO_DATA_X0);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_DATA_Y1, fifo[i].GYRO_DATA_Y0);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_DATA_Z1, fifo[i].GYRO_DATA_Z0);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void ICM42605::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
uint8_t temperature_buf[3] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::BANK_0::TEMP_DATA1) | DIR_READ;
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
if (transfer(temperature_buf, temperature_buf, sizeof(temperature_buf)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
const int16_t TEMP_DATA = combine(temperature_buf[1], temperature_buf[2]);
|
||||
|
||||
// Temperature in Degrees Centigrade
|
||||
const float TEMP_degC = (TEMP_DATA / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
}
|
||||
|
||||
_timestamp_prev = 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_ICM42605_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_ICM42605;
|
||||
|
||||
class ICM42605 : public device::SPI, public I2CSPIDriver<ICM42605>
|
||||
@@ -71,22 +72,10 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f}; // 8000 Hz accel & gyro ODR configured
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float ACCEL_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (4 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
struct register_bank0_config_t {
|
||||
Register::BANK_0 reg;
|
||||
@@ -99,8 +88,6 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
void ConfigureFIFOWatermark(uint8_t samples);
|
||||
|
||||
@@ -123,20 +110,18 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
void ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
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 _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")};
|
||||
perf_counter_t _fifo_overflow_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO overflow")};
|
||||
perf_counter_t _fifo_reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO reset")};
|
||||
perf_counter_t _fifo_timestamp_error_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO timestamp error")};
|
||||
perf_counter_t _drdy_missed_perf{nullptr};
|
||||
|
||||
hrt_abstime _reset_timestamp{0};
|
||||
@@ -144,6 +129,8 @@ private:
|
||||
hrt_abstime _temperature_update_timestamp{0};
|
||||
int _failure_count{0};
|
||||
|
||||
uint16_t _timestamp_prev{0};
|
||||
|
||||
enum REG_BANK_SEL_BIT _last_register_bank {REG_BANK_SEL_BIT::USER_BANK_0};
|
||||
|
||||
px4::atomic<hrt_abstime> _drdy_timestamp_sample{0};
|
||||
@@ -153,11 +140,12 @@ private:
|
||||
RESET,
|
||||
WAIT_FOR_RESET,
|
||||
CONFIGURE,
|
||||
FIFO_RESET,
|
||||
FIFO_READ,
|
||||
} _state{STATE::RESET};
|
||||
|
||||
uint16_t _fifo_empty_interval_us{1250}; // default 1250 us / 800 Hz transfer interval
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / GYRO_RATE))};
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / RATE))};
|
||||
|
||||
uint8_t _checked_register_bank0{0};
|
||||
static constexpr uint8_t size_register_bank0_cfg{10};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -242,7 +242,7 @@ enum FIFO_HEADER_BIT : uint8_t {
|
||||
HEADER_MSG = Bit7, // 1: FIFO is empty
|
||||
HEADER_ACCEL = Bit6,
|
||||
HEADER_GYRO = Bit5,
|
||||
HEADER_20 = Bit4,
|
||||
|
||||
HEADER_TIMESTAMP_FSYNC = Bit3 | Bit2,
|
||||
HEADER_ODR_ACCEL = Bit1,
|
||||
HEADER_ODR_GYRO = Bit0,
|
||||
|
||||
@@ -41,6 +41,4 @@ px4_add_module(
|
||||
InvenSense_ICM42670P_registers.hpp
|
||||
DEPENDS
|
||||
px4_work_queue
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
)
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM42670P.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ ICM42670P::ICM42670P(const I2CSPIDriverConfig &config):
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
ICM42670P::~ICM42670P()
|
||||
@@ -61,6 +65,7 @@ ICM42670P::~ICM42670P()
|
||||
perf_free(_fifo_empty_perf);
|
||||
perf_free(_fifo_overflow_perf);
|
||||
perf_free(_fifo_reset_perf);
|
||||
perf_free(_fifo_timestamp_error_perf);
|
||||
perf_free(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
@@ -102,19 +107,25 @@ void ICM42670P::print_status()
|
||||
perf_print_counter(_fifo_empty_perf);
|
||||
perf_print_counter(_fifo_overflow_perf);
|
||||
perf_print_counter(_fifo_reset_perf);
|
||||
perf_print_counter(_fifo_timestamp_error_perf);
|
||||
perf_print_counter(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
int ICM42670P::probe()
|
||||
{
|
||||
const uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
|
||||
if (whoami != WHOAMI) {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
return PX4_ERROR;
|
||||
if (whoami == WHOAMI) {
|
||||
return PX4_OK;
|
||||
|
||||
} else {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
}
|
||||
}
|
||||
|
||||
return PX4_OK;
|
||||
return PX4_ERROR;
|
||||
}
|
||||
|
||||
void ICM42670P::RunImpl()
|
||||
@@ -149,8 +160,8 @@ void ICM42670P::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,21 +169,9 @@ void ICM42670P::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
FIFOReset();
|
||||
// if configure succeeded then reset the FIFO
|
||||
_state = STATE::FIFO_RESET;
|
||||
ScheduleDelayed(1_ms);
|
||||
|
||||
} else {
|
||||
// CONFIGURE not complete
|
||||
@@ -189,6 +188,24 @@ void ICM42670P::RunImpl()
|
||||
|
||||
break;
|
||||
|
||||
case STATE::FIFO_RESET:
|
||||
|
||||
_state = STATE::FIFO_READ;
|
||||
FIFOReset();
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
hrt_abstime timestamp_sample = now;
|
||||
uint8_t samples = 0;
|
||||
@@ -197,7 +214,7 @@ void ICM42670P::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
@@ -209,6 +226,8 @@ void ICM42670P::RunImpl()
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples == 0) {
|
||||
// check current FIFO count
|
||||
const uint16_t fifo_count = FIFOReadCount();
|
||||
@@ -221,27 +240,42 @@ void ICM42670P::RunImpl()
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
} else {
|
||||
// FIFO count (size in bytes)
|
||||
samples = (fifo_count / sizeof(FIFO::DATA));
|
||||
// FIFO count (size in bytes) should be a multiple of the FIFO::DATA structure
|
||||
samples = fifo_count / sizeof(FIFO::DATA);
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_gyro_samples + 1) {
|
||||
timestamp_sample -= static_cast<int>(FIFO_SAMPLE_DT);
|
||||
samples--;
|
||||
if (samples > _fifo_gyro_samples) {
|
||||
// grab desired number of samples, but reschedule next cycle sooner
|
||||
const int extra_samples = samples - _fifo_gyro_samples;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
if (_fifo_gyro_samples > extra_samples) {
|
||||
// reschedule to run when a total of _fifo_gyro_samples should be available in the FIFO
|
||||
const uint32_t reschedule_delay_us = (_fifo_gyro_samples - extra_samples) * static_cast<int>(FIFO_SAMPLE_DT);
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, reschedule_delay_us);
|
||||
|
||||
} else {
|
||||
// otherwise reschedule to run immediately
|
||||
ScheduleOnInterval(_fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
} else if (samples < _fifo_gyro_samples) {
|
||||
// reschedule next cycle to catch the desired number of samples
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, (_fifo_gyro_samples - samples) * static_cast<int>(FIFO_SAMPLE_DT));
|
||||
}
|
||||
|
||||
if (samples > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
samples = 0;
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(now, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples >= 1) {
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
@@ -256,13 +290,14 @@ void ICM42670P::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_bank0_cfg[_checked_register_bank0])
|
||||
&& RegisterCheck(_register_mreg1_cfg[_checked_register_mreg1])
|
||||
) {
|
||||
@@ -275,13 +310,6 @@ void ICM42670P::RunImpl()
|
||||
perf_count(_bad_register_perf);
|
||||
Reset();
|
||||
}
|
||||
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,10 +323,10 @@ void ICM42670P::ConfigureSampleRate(int sample_rate)
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / RATE), (float)FIFO_MAX_SAMPLES));
|
||||
|
||||
// recompute FIFO empty interval (us) with actual gyro sample limit
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / GYRO_RATE);
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / RATE);
|
||||
|
||||
ConfigureFIFOWatermark(_fifo_gyro_samples);
|
||||
}
|
||||
@@ -346,12 +374,6 @@ bool ICM42670P::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
_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));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -374,7 +396,7 @@ bool ICM42670P::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool ICM42670P::DataReadyInterruptDisable()
|
||||
@@ -383,7 +405,7 @@ bool ICM42670P::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -457,7 +479,6 @@ void ICM42670P::RegisterWrite(Register::MREG1 reg, uint8_t value)
|
||||
px4_udelay(10);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void ICM42670P::RegisterSetAndClearBits(T reg, uint8_t setbits, uint8_t clearbits)
|
||||
{
|
||||
@@ -472,22 +493,35 @@ void ICM42670P::RegisterSetAndClearBits(T reg, uint8_t setbits, uint8_t clearbit
|
||||
|
||||
uint16_t ICM42670P::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ;
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool ICM42670P::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 6, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + INT_STATUS + FIFO_COUNTH + FIFO_COUNTL + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 4 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
@@ -500,7 +534,7 @@ bool ICM42670P::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = combine(buffer.FIFO_COUNTH, buffer.FIFO_COUNTL);
|
||||
const uint16_t fifo_count_bytes = (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
@@ -515,52 +549,151 @@ bool ICM42670P::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = 0;
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 8192.f; // highres accel data 8192 LSB/g
|
||||
sensor_imu_fifo.gyro_scale = math::radians(1.f / 131.f); // highres gyro data 131 LSB/dps
|
||||
|
||||
// check FIFO header in every sample
|
||||
uint8_t valid_samples = 0;
|
||||
|
||||
float temperature_sum = 0;
|
||||
|
||||
float timestamp_interval_sum = 0;
|
||||
int timestamp_interval_sum_count = 0;
|
||||
|
||||
bool accel_scale_16bit = false; // 18-bits of accelerometer data
|
||||
bool gyro_scale_16bit = false; // 20-bits of gyroscope data
|
||||
|
||||
for (int i = 0; i < math::min(samples, fifo_count_samples); i++) {
|
||||
bool valid = true;
|
||||
const FIFO::DATA &fifo = buffer.f[i];
|
||||
|
||||
// With FIFO_ACCEL_EN and FIFO_GYRO_EN header should be 8’b_0110_10xx
|
||||
const uint8_t FIFO_HEADER = buffer.f[i].FIFO_Header;
|
||||
const uint8_t FIFO_HEADER = fifo.FIFO_Header;
|
||||
|
||||
if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG) {
|
||||
// FIFO sample empty if HEADER_MSG set
|
||||
valid = false;
|
||||
const bool HEADER_MSG = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG; // FIFO is empty
|
||||
const bool HEADER_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL;
|
||||
const bool HEADER_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO;
|
||||
// 3:2 HEADER_TIMESTAMP_FSYNC
|
||||
const bool HEADER_ODR_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_ACCEL; // ODR for accel is different
|
||||
const bool HEADER_ODR_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_GYRO; // ODR for gyro is different
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL)) {
|
||||
// accel bit not set
|
||||
valid = false;
|
||||
if (!HEADER_MSG && HEADER_ACCEL && HEADER_GYRO && !HEADER_ODR_ACCEL && !HEADER_ODR_GYRO) {
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO)) {
|
||||
// gyro bit not set
|
||||
valid = false;
|
||||
// 20 bit data scaled to 16 bit
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 2048.f;
|
||||
|
||||
} else if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_20) {
|
||||
// Packet does not contain a new and valid extended 20-bit data
|
||||
valid = false;
|
||||
sensor_imu_fifo.accel_x[valid_samples] = combine(fifo.ACCEL_DATA_X1, fifo.ACCEL_DATA_X0);
|
||||
sensor_imu_fifo.accel_y[valid_samples] = combine(fifo.ACCEL_DATA_Y1, fifo.ACCEL_DATA_Y0);
|
||||
sensor_imu_fifo.accel_z[valid_samples] = combine(fifo.ACCEL_DATA_Z1, fifo.ACCEL_DATA_Z0);
|
||||
|
||||
} else if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_ACCEL) {
|
||||
// accel ODR changed
|
||||
valid = false;
|
||||
sensor_imu_fifo.gyro_x[i] = combine(fifo.GYRO_DATA_X1, fifo.GYRO_DATA_X0);
|
||||
sensor_imu_fifo.gyro_y[i] = combine(fifo.GYRO_DATA_Y1, fifo.GYRO_DATA_Y0);
|
||||
sensor_imu_fifo.gyro_z[i] = combine(fifo.GYRO_DATA_Z1, fifo.GYRO_DATA_Z0);
|
||||
|
||||
} else if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_GYRO) {
|
||||
// gyro ODR changed
|
||||
valid = false;
|
||||
}
|
||||
// temperature
|
||||
const int16_t TEMP_DATA = combine(fifo.TEMP_DATA1, fifo.TEMP_DATA0);
|
||||
|
||||
// sample invalid if -32768
|
||||
if (TEMP_DATA != -32768) {
|
||||
temperature_sum += TEMP_DATA;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// HEADER_TIMESTAMP_FSYNC - 0b10: Packet contains ODR Timestamp
|
||||
if (FIFO_HEADER & Bit3) {
|
||||
const uint16_t timestamp = (fifo.TimeStamp_h << 8) + fifo.TimeStamp_l;
|
||||
|
||||
if (_timestamp_prev != 0) {
|
||||
// If TMST_RES = 0 (corresponding to timestamp resolution of 1µs), timestamp interval reported in FIFO requires scaling by a factor of 32/30.
|
||||
// Document Number: DS-000347 Revision: 1.5 Page 59 of 110
|
||||
static constexpr float FIFO_DT_SCALE = 32.f / 30.f;
|
||||
|
||||
float dt = 0;
|
||||
|
||||
if (timestamp > _timestamp_prev) {
|
||||
dt = static_cast<float>(timestamp - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
|
||||
} else if (timestamp < _timestamp_prev) {
|
||||
// uint16_t rollover
|
||||
uint32_t timestamp_new = UINT16_MAX + timestamp;
|
||||
dt = static_cast<float>(timestamp_new - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
}
|
||||
|
||||
timestamp_interval_sum += dt;
|
||||
timestamp_interval_sum_count++;
|
||||
|
||||
// check dt is within +=2% of expected value
|
||||
if ((dt < (FIFO_SAMPLE_DT * 0.98f)) || (dt > (FIFO_SAMPLE_DT * 1.02f))) {
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
}
|
||||
}
|
||||
|
||||
_timestamp_prev = timestamp;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
valid_samples++;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_samples > 0) {
|
||||
ProcessGyro(timestamp_sample, buffer.f, valid_samples);
|
||||
ProcessAccel(timestamp_sample, buffer.f, valid_samples);
|
||||
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
|
||||
for (int i = 0; i < sensor_imu_fifo.samples; i++) {
|
||||
// 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)
|
||||
|
||||
// sensor_imu_fifo.accel_x[i]
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(sensor_imu_fifo.accel_y[i]);
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(sensor_imu_fifo.accel_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
// sensor_imu_fifo.gyro_x[i]
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(sensor_imu_fifo.gyro_y[i]);
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(sensor_imu_fifo.gyro_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
const float temperature_avg = temperature_sum / valid_samples;
|
||||
|
||||
// use average temperature reading
|
||||
const float TEMP_degC = (temperature_avg / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
sensor_imu_fifo.temperature = TEMP_degC;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timestamp_interval_sum > 0) {
|
||||
const float dt_avg = (timestamp_interval_sum / timestamp_interval_sum_count);
|
||||
|
||||
// check dt is within +=1% of expected value
|
||||
if ((dt_avg < (FIFO_SAMPLE_DT * 0.99f)) || (dt_avg > (FIFO_SAMPLE_DT * 1.01f))) {
|
||||
PX4_ERR("DT error %.6f", (double)dt_avg);
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.dt = dt_avg;
|
||||
}
|
||||
}
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -571,93 +704,11 @@ void ICM42670P::FIFOReset()
|
||||
{
|
||||
perf_count(_fifo_reset_perf);
|
||||
|
||||
// FIFO flush requires the following programming sequence:
|
||||
// Write FIFO_FLUSH = 1
|
||||
// Wait for 1.5 µs
|
||||
// Read FIFO_FLUSH, it should now be 0
|
||||
|
||||
// SIGNAL_PATH_RESET: FIFO flush
|
||||
RegisterSetBits(Register::BANK_0::SIGNAL_PATH_RESET, SIGNAL_PATH_RESET_BIT::FIFO_FLUSH);
|
||||
px4_udelay(2); // Wait for 1.5 µs
|
||||
|
||||
const uint8_t SIGNAL_PATH_RESET = RegisterRead(Register::BANK_0::SIGNAL_PATH_RESET);
|
||||
|
||||
if ((SIGNAL_PATH_RESET & SIGNAL_PATH_RESET_BIT::FIFO_FLUSH) != 0) {
|
||||
PX4_DEBUG("SIGNAL_PATH_RESET FIFO_FLUSH failed");
|
||||
}
|
||||
|
||||
// reset while FIFO is disabled
|
||||
_drdy_timestamp_sample.store(0);
|
||||
}
|
||||
|
||||
void ICM42670P::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = samples;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_DATA_X1, fifo[i].ACCEL_DATA_X0);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_DATA_Y1, fifo[i].ACCEL_DATA_Y0);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_DATA_Z1, fifo[i].ACCEL_DATA_Z0);
|
||||
|
||||
// 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)
|
||||
accel.x[i] = accel_x;
|
||||
accel.y[i] = math::negate(accel_y);
|
||||
accel.z[i] = math::negate(accel_z);
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
|
||||
void ICM42670P::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_DATA_X1, fifo[i].GYRO_DATA_X0);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_DATA_Y1, fifo[i].GYRO_DATA_Y0);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_DATA_Z1, fifo[i].GYRO_DATA_Z0);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = math::negate(gyro_y);
|
||||
gyro.z[i] = math::negate(gyro_z);
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void ICM42670P::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
uint8_t temperature_buf[3] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::BANK_0::TEMP_DATA1) | DIR_READ;
|
||||
|
||||
if (transfer(temperature_buf, temperature_buf, sizeof(temperature_buf)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
const int16_t TEMP_DATA = combine(temperature_buf[1], temperature_buf[2]);
|
||||
|
||||
// Temperature in Degrees Centigrade
|
||||
const float TEMP_degC = (TEMP_DATA / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
}
|
||||
|
||||
_timestamp_prev = 0;
|
||||
}
|
||||
|
||||
@@ -43,13 +43,15 @@
|
||||
#include "InvenSense_ICM42670P_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_ICM42670P;
|
||||
|
||||
class ICM42670P : public device::SPI, public I2CSPIDriver<ICM42670P>
|
||||
@@ -70,24 +72,10 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 1600.f}; // 1600 Hz accel & gyro ODR configured
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float ACCEL_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t INT_STATUS2{0};
|
||||
uint8_t INT_STATUS3{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (6 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
struct register_bank0_config_t {
|
||||
Register::BANK_0 reg;
|
||||
@@ -129,20 +117,18 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
void ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
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 _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")};
|
||||
perf_counter_t _fifo_overflow_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO overflow")};
|
||||
perf_counter_t _fifo_reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO reset")};
|
||||
perf_counter_t _fifo_timestamp_error_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO timestamp error")};
|
||||
perf_counter_t _drdy_missed_perf{nullptr};
|
||||
|
||||
hrt_abstime _reset_timestamp{0};
|
||||
@@ -150,6 +136,8 @@ private:
|
||||
hrt_abstime _temperature_update_timestamp{0};
|
||||
int _failure_count{0};
|
||||
|
||||
uint16_t _timestamp_prev{0};
|
||||
|
||||
px4::atomic<hrt_abstime> _drdy_timestamp_sample{0};
|
||||
bool _data_ready_interrupt_enabled{false};
|
||||
|
||||
@@ -157,11 +145,12 @@ private:
|
||||
RESET,
|
||||
WAIT_FOR_RESET,
|
||||
CONFIGURE,
|
||||
FIFO_RESET,
|
||||
FIFO_READ,
|
||||
} _state{STATE::RESET};
|
||||
|
||||
uint16_t _fifo_empty_interval_us{1250}; // default 1250 us / 800 Hz transfer interval
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / GYRO_RATE))};
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / RATE))};
|
||||
|
||||
uint8_t _checked_register_bank0{0};
|
||||
static constexpr uint8_t size_register_bank0_cfg{10};
|
||||
|
||||
@@ -231,7 +231,7 @@ enum FIFO_HEADER_BIT : uint8_t {
|
||||
HEADER_MSG = Bit7, // 1: FIFO is empty
|
||||
HEADER_ACCEL = Bit6, // 1: Packet is sized so that accel data have location in the packet, FIFO_ACCEL_EN must be 1
|
||||
HEADER_GYRO = Bit5, // 1: Packet is sized so that gyro data have location in the packet, FIFO_GYRO_EN must be1
|
||||
HEADER_20 = Bit4, // 1: Packet has a new and valid sample of extended 20-bit data for gyro and/or accel
|
||||
|
||||
HEADER_TIMESTAMP_FSYNC = Bit3 | Bit2,
|
||||
HEADER_ODR_ACCEL = Bit1, // 1: The ODR for accel is different for this accel data packet compared to the previous accel packet
|
||||
HEADER_ODR_GYRO = Bit0, // 1: The ODR for gyro is different for this gyro data packet compared to the previous gyro packet
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2020 PX4 Development Team. All rights reserved.
|
||||
# Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
@@ -42,6 +42,4 @@ px4_add_module(
|
||||
InvenSense_ICM42688P_registers.hpp
|
||||
DEPENDS
|
||||
px4_work_queue
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
)
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "ICM42688P.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ ICM42688P::ICM42688P(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
ICM42688P::~ICM42688P()
|
||||
@@ -61,6 +65,7 @@ ICM42688P::~ICM42688P()
|
||||
perf_free(_fifo_empty_perf);
|
||||
perf_free(_fifo_overflow_perf);
|
||||
perf_free(_fifo_reset_perf);
|
||||
perf_free(_fifo_timestamp_error_perf);
|
||||
perf_free(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
@@ -102,12 +107,14 @@ void ICM42688P::print_status()
|
||||
perf_print_counter(_fifo_empty_perf);
|
||||
perf_print_counter(_fifo_overflow_perf);
|
||||
perf_print_counter(_fifo_reset_perf);
|
||||
perf_print_counter(_fifo_timestamp_error_perf);
|
||||
perf_print_counter(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
int ICM42688P::probe()
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
|
||||
if (whoami == WHOAMI) {
|
||||
@@ -162,8 +169,8 @@ void ICM42688P::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +223,7 @@ void ICM42688P::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
@@ -228,6 +235,8 @@ void ICM42688P::RunImpl()
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples == 0) {
|
||||
// check current FIFO count
|
||||
const uint16_t fifo_count = FIFOReadCount();
|
||||
@@ -240,27 +249,42 @@ void ICM42688P::RunImpl()
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
} else {
|
||||
// FIFO count (size in bytes)
|
||||
samples = (fifo_count / sizeof(FIFO::DATA));
|
||||
// FIFO count (size in bytes) should be a multiple of the FIFO::DATA structure
|
||||
samples = fifo_count / sizeof(FIFO::DATA);
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_gyro_samples + 1) {
|
||||
timestamp_sample -= static_cast<int>(FIFO_SAMPLE_DT);
|
||||
samples--;
|
||||
if (samples > _fifo_gyro_samples) {
|
||||
// grab desired number of samples, but reschedule next cycle sooner
|
||||
const int extra_samples = samples - _fifo_gyro_samples;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
if (_fifo_gyro_samples > extra_samples) {
|
||||
// reschedule to run when a total of _fifo_gyro_samples should be available in the FIFO
|
||||
const uint32_t reschedule_delay_us = (_fifo_gyro_samples - extra_samples) * static_cast<int>(FIFO_SAMPLE_DT);
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, reschedule_delay_us);
|
||||
|
||||
} else {
|
||||
// otherwise reschedule to run immediately
|
||||
ScheduleOnInterval(_fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
} else if (samples < _fifo_gyro_samples) {
|
||||
// reschedule next cycle to catch the desired number of samples
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, (_fifo_gyro_samples - samples) * static_cast<int>(FIFO_SAMPLE_DT));
|
||||
}
|
||||
|
||||
if (samples > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
samples = 0;
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(now, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples >= 1) {
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
@@ -275,13 +299,14 @@ void ICM42688P::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_bank0_cfg[_checked_register_bank0])
|
||||
&& RegisterCheck(_register_bank1_cfg[_checked_register_bank1])
|
||||
&& RegisterCheck(_register_bank2_cfg[_checked_register_bank2])
|
||||
@@ -309,10 +334,10 @@ void ICM42688P::ConfigureSampleRate(int sample_rate)
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / RATE), (float)FIFO_MAX_SAMPLES));
|
||||
|
||||
// recompute FIFO empty interval (us) with actual gyro sample limit
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / GYRO_RATE);
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / RATE);
|
||||
|
||||
ConfigureFIFOWatermark(_fifo_gyro_samples);
|
||||
}
|
||||
@@ -362,6 +387,7 @@ bool ICM42688P::Configure()
|
||||
RegisterSetAndClearBits(reg_cfg.reg, reg_cfg.set_bits, reg_cfg.clear_bits);
|
||||
}
|
||||
|
||||
|
||||
// now check that all are configured
|
||||
bool success = true;
|
||||
|
||||
@@ -383,11 +409,6 @@ bool ICM42688P::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
// 20-bits data format used
|
||||
// the only FSR settings that are operational are ±2000dps for gyroscope and ±16g for accelerometer
|
||||
_px4_accel.set_range(16.f * CONSTANTS_ONE_G);
|
||||
_px4_gyro.set_range(math::radians(2000.f));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -410,7 +431,7 @@ bool ICM42688P::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool ICM42688P::DataReadyInterruptDisable()
|
||||
@@ -419,7 +440,7 @@ bool ICM42688P::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -474,114 +495,20 @@ void ICM42688P::RegisterSetAndClearBits(T reg, uint8_t setbits, uint8_t clearbit
|
||||
|
||||
uint16_t ICM42688P::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ;
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
}
|
||||
|
||||
bool ICM42688P::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 4, FIFO::SIZE);
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer.INT_STATUS & INT_STATUS_BIT::FIFO_FULL_INT) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = combine(buffer.FIFO_COUNTH, buffer.FIFO_COUNTL);
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
if (fifo_count_samples == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check FIFO header in every sample
|
||||
uint8_t valid_samples = 0;
|
||||
|
||||
for (int i = 0; i < math::min(samples, fifo_count_samples); i++) {
|
||||
bool valid = true;
|
||||
|
||||
// With FIFO_ACCEL_EN and FIFO_GYRO_EN header should be 8’b_0110_10xx
|
||||
const uint8_t FIFO_HEADER = buffer.f[i].FIFO_Header;
|
||||
|
||||
if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG) {
|
||||
// FIFO sample empty if HEADER_MSG set
|
||||
valid = false;
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL)) {
|
||||
// accel bit not set
|
||||
valid = false;
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO)) {
|
||||
// gyro bit not set
|
||||
valid = false;
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_20)) {
|
||||
// Packet does not contain a new and valid extended 20-bit data
|
||||
valid = false;
|
||||
|
||||
} else if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_ACCEL) {
|
||||
// accel ODR changed
|
||||
valid = false;
|
||||
|
||||
} else if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_GYRO) {
|
||||
// gyro ODR changed
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
valid_samples++;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_samples > 0) {
|
||||
if (ProcessTemperature(buffer.f, valid_samples)) {
|
||||
ProcessGyro(timestamp_sample, buffer.f, valid_samples);
|
||||
ProcessAccel(timestamp_sample, buffer.f, valid_samples);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ICM42688P::FIFOReset()
|
||||
{
|
||||
perf_count(_fifo_reset_perf);
|
||||
|
||||
// SIGNAL_PATH_RESET: FIFO flush
|
||||
RegisterSetBits(Register::BANK_0::SIGNAL_PATH_RESET, SIGNAL_PATH_RESET_BIT::FIFO_FLUSH);
|
||||
|
||||
// reset while FIFO is disabled
|
||||
_drdy_timestamp_sample.store(0);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
static constexpr int32_t reassemble_20bit(const uint32_t a, const uint32_t b, const uint32_t c)
|
||||
@@ -601,206 +528,288 @@ static constexpr int32_t reassemble_20bit(const uint32_t a, const uint32_t b, co
|
||||
return static_cast<int32_t>(x);
|
||||
}
|
||||
|
||||
void ICM42688P::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
bool ICM42688P::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// 18-bits of accelerometer data
|
||||
bool scale_20bit = false;
|
||||
// cmd + INT_STATUS + FIFO_COUNTH + FIFO_COUNTL + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 4 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
// first pass
|
||||
for (int i = 0; i < samples; i++) {
|
||||
// 20 bit hires mode
|
||||
// Sign extension + Accel [19:12] + Accel [11:4] + Accel [3:2] (20 bit extension byte)
|
||||
// Accel data is 18 bit ()
|
||||
int32_t accel_x = reassemble_20bit(fifo[i].ACCEL_DATA_X1, fifo[i].ACCEL_DATA_X0,
|
||||
fifo[i].Ext_Accel_X_Gyro_X & 0xF0 >> 4);
|
||||
int32_t accel_y = reassemble_20bit(fifo[i].ACCEL_DATA_Y1, fifo[i].ACCEL_DATA_Y0,
|
||||
fifo[i].Ext_Accel_Y_Gyro_Y & 0xF0 >> 4);
|
||||
int32_t accel_z = reassemble_20bit(fifo[i].ACCEL_DATA_Z1, fifo[i].ACCEL_DATA_Z0,
|
||||
fifo[i].Ext_Accel_Z_Gyro_Z & 0xF0 >> 4);
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
// sample invalid if -524288
|
||||
if (accel_x != -524288 && accel_y != -524288 && accel_z != -524288) {
|
||||
// check if any values are going to exceed int16 limits
|
||||
static constexpr int16_t max_accel = INT16_MAX;
|
||||
static constexpr int16_t min_accel = INT16_MIN;
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (accel_x >= max_accel || accel_x <= min_accel) {
|
||||
scale_20bit = true;
|
||||
if (buffer.INT_STATUS & INT_STATUS_BIT::FIFO_FULL_INT) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
if (fifo_count_samples == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = 0;
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 8192.f; // highres accel data 8192 LSB/g
|
||||
sensor_imu_fifo.gyro_scale = math::radians(1.f / 131.f); // highres gyro data 131 LSB/dps
|
||||
|
||||
// check FIFO header in every sample
|
||||
uint8_t valid_samples = 0;
|
||||
|
||||
float temperature_sum = 0;
|
||||
|
||||
float timestamp_interval_sum = 0;
|
||||
int timestamp_interval_sum_count = 0;
|
||||
|
||||
bool accel_scale_16bit = false; // 18-bits of accelerometer data
|
||||
bool gyro_scale_16bit = false; // 20-bits of gyroscope data
|
||||
|
||||
for (int i = 0; i < math::min(samples, fifo_count_samples); i++) {
|
||||
const FIFO::DATA &fifo = buffer.f[i];
|
||||
|
||||
// With FIFO_ACCEL_EN and FIFO_GYRO_EN header should be 8’b_0110_10xx
|
||||
const uint8_t FIFO_HEADER = fifo.FIFO_Header;
|
||||
|
||||
const bool HEADER_MSG = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG; // FIFO is empty
|
||||
const bool HEADER_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL;
|
||||
const bool HEADER_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO;
|
||||
const bool HEADER_20 = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_20; // valid sample of extended 20-bit data
|
||||
// 3:2 HEADER_TIMESTAMP_FSYNC
|
||||
const bool HEADER_ODR_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_ACCEL; // ODR for accel is different
|
||||
const bool HEADER_ODR_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_GYRO; // ODR for gyro is different
|
||||
|
||||
if (!HEADER_MSG && HEADER_ACCEL && HEADER_GYRO && HEADER_20 && !HEADER_ODR_ACCEL && !HEADER_ODR_GYRO) {
|
||||
|
||||
if (!accel_scale_16bit) {
|
||||
// Accel: 20 bit hires mode, Accel data is 18 bit
|
||||
// Sign extension + Accel [19:12] + Accel [11:4] + Accel [3:2] (20 bit extension byte)
|
||||
int32_t accel_x = reassemble_20bit(fifo.ACCEL_DATA_X1, fifo.ACCEL_DATA_X0, fifo.Ext_Accel_X_Gyro_X & 0xF0 >> 4);
|
||||
int32_t accel_y = reassemble_20bit(fifo.ACCEL_DATA_Y1, fifo.ACCEL_DATA_Y0, fifo.Ext_Accel_Y_Gyro_Y & 0xF0 >> 4);
|
||||
int32_t accel_z = reassemble_20bit(fifo.ACCEL_DATA_Z1, fifo.ACCEL_DATA_Z0, fifo.Ext_Accel_Z_Gyro_Z & 0xF0 >> 4);
|
||||
|
||||
// sample invalid if -524288
|
||||
if (accel_x == -524288 || accel_y == -524288 || accel_z == -524288) {
|
||||
break;
|
||||
}
|
||||
|
||||
// shift by 2 (2 least significant bits are always 0)
|
||||
accel_x = accel_x / 4;
|
||||
accel_y = accel_y / 4;
|
||||
accel_z = accel_z / 4;
|
||||
|
||||
// check if any values are going to exceed int16 limits
|
||||
if ((accel_x >= INT16_MAX || accel_x <= INT16_MIN)
|
||||
|| (accel_y >= INT16_MAX || accel_y <= INT16_MIN)
|
||||
|| (accel_z >= INT16_MAX || accel_z <= INT16_MIN)) {
|
||||
|
||||
accel_scale_16bit = true;
|
||||
|
||||
// 20 bit data scaled to 16 bit
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 2048.f;
|
||||
|
||||
// rescale any existing data
|
||||
for (int j = 0; j < valid_samples + 1; j++) {
|
||||
sensor_imu_fifo.accel_x[valid_samples] = combine(buffer.f[j].ACCEL_DATA_X1, buffer.f[j].ACCEL_DATA_X0);
|
||||
sensor_imu_fifo.accel_y[valid_samples] = combine(buffer.f[j].ACCEL_DATA_Y1, buffer.f[j].ACCEL_DATA_Y0);
|
||||
sensor_imu_fifo.accel_z[valid_samples] = combine(buffer.f[j].ACCEL_DATA_Z1, buffer.f[j].ACCEL_DATA_Z0);
|
||||
}
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.accel_x[valid_samples] = accel_x;
|
||||
sensor_imu_fifo.accel_y[valid_samples] = accel_y;
|
||||
sensor_imu_fifo.accel_z[valid_samples] = accel_z;
|
||||
}
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.accel_x[valid_samples] = combine(fifo.ACCEL_DATA_X1, fifo.ACCEL_DATA_X0);
|
||||
sensor_imu_fifo.accel_y[valid_samples] = combine(fifo.ACCEL_DATA_Y1, fifo.ACCEL_DATA_Y0);
|
||||
sensor_imu_fifo.accel_z[valid_samples] = combine(fifo.ACCEL_DATA_Z1, fifo.ACCEL_DATA_Z0);
|
||||
}
|
||||
|
||||
if (accel_y >= max_accel || accel_y <= min_accel) {
|
||||
scale_20bit = true;
|
||||
|
||||
if (!gyro_scale_16bit) {
|
||||
// Gyro: 20 bit hires mode
|
||||
// Gyro [19:12] + Gyro [11:4] + Gyro [3:0] (bottom 4 bits of 20 bit extension byte)
|
||||
int32_t gyro_x = reassemble_20bit(fifo.GYRO_DATA_X1, fifo.GYRO_DATA_X0, fifo.Ext_Accel_X_Gyro_X & 0x0F);
|
||||
int32_t gyro_y = reassemble_20bit(fifo.GYRO_DATA_Y1, fifo.GYRO_DATA_Y0, fifo.Ext_Accel_Y_Gyro_Y & 0x0F);
|
||||
int32_t gyro_z = reassemble_20bit(fifo.GYRO_DATA_Z1, fifo.GYRO_DATA_Z0, fifo.Ext_Accel_Z_Gyro_Z & 0x0F);
|
||||
|
||||
// shift by 1 (least significant bit is always 0)
|
||||
gyro_x = gyro_x / 2;
|
||||
gyro_y = gyro_y / 2;
|
||||
gyro_z = gyro_z / 2;
|
||||
|
||||
// check if any gyro values are going to exceed int16 limits
|
||||
if ((gyro_x >= INT16_MAX || gyro_x <= INT16_MIN)
|
||||
|| (gyro_y >= INT16_MAX || gyro_y <= INT16_MIN)
|
||||
|| (gyro_z >= INT16_MAX || gyro_z <= INT16_MIN)) {
|
||||
|
||||
|
||||
gyro_scale_16bit = true;
|
||||
|
||||
// 20 bit data scaled to 16 bit
|
||||
sensor_imu_fifo.gyro_scale = math::radians(2000.f / 32768.f);
|
||||
|
||||
// rescale any existing data
|
||||
for (int j = 0; j < valid_samples + 1; j++) {
|
||||
sensor_imu_fifo.gyro_x[j] = combine(buffer.f[j].GYRO_DATA_X1, buffer.f[j].GYRO_DATA_X0);
|
||||
sensor_imu_fifo.gyro_y[j] = combine(buffer.f[j].GYRO_DATA_Y1, buffer.f[j].GYRO_DATA_Y0);
|
||||
sensor_imu_fifo.gyro_z[j] = combine(buffer.f[j].GYRO_DATA_Z1, buffer.f[j].GYRO_DATA_Z0);
|
||||
}
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.gyro_x[valid_samples] = gyro_x;
|
||||
sensor_imu_fifo.gyro_y[valid_samples] = gyro_y;
|
||||
sensor_imu_fifo.gyro_z[valid_samples] = gyro_z;
|
||||
}
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.gyro_x[i] = combine(fifo.GYRO_DATA_X1, fifo.GYRO_DATA_X0);
|
||||
sensor_imu_fifo.gyro_y[i] = combine(fifo.GYRO_DATA_Y1, fifo.GYRO_DATA_Y0);
|
||||
sensor_imu_fifo.gyro_z[i] = combine(fifo.GYRO_DATA_Z1, fifo.GYRO_DATA_Z0);
|
||||
}
|
||||
|
||||
if (accel_z >= max_accel || accel_z <= min_accel) {
|
||||
scale_20bit = true;
|
||||
|
||||
// temperature
|
||||
const int16_t TEMP_DATA = combine(fifo.TEMP_DATA1, fifo.TEMP_DATA0);
|
||||
|
||||
// sample invalid if -32768
|
||||
if (TEMP_DATA != -32768) {
|
||||
temperature_sum += TEMP_DATA;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// shift by 2 (2 least significant bits are always 0)
|
||||
accel.x[accel.samples] = accel_x / 4;
|
||||
accel.y[accel.samples] = accel_y / 4;
|
||||
accel.z[accel.samples] = accel_z / 4;
|
||||
accel.samples++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!scale_20bit) {
|
||||
// if highres enabled accel data is always 8192 LSB/g
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 8192.f);
|
||||
// HEADER_TIMESTAMP_FSYNC - 0b10: Packet contains ODR Timestamp
|
||||
if (FIFO_HEADER & Bit3) {
|
||||
const uint16_t timestamp = (fifo.TimeStamp_h << 8) + fifo.TimeStamp_l;
|
||||
|
||||
} else {
|
||||
// 20 bit data scaled to 16 bit (2^4)
|
||||
for (int i = 0; i < samples; i++) {
|
||||
// 20 bit hires mode
|
||||
// Sign extension + Accel [19:12] + Accel [11:4] + Accel [3:2] (20 bit extension byte)
|
||||
// Accel data is 18 bit ()
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_DATA_X1, fifo[i].ACCEL_DATA_X0);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_DATA_Y1, fifo[i].ACCEL_DATA_Y0);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_DATA_Z1, fifo[i].ACCEL_DATA_Z0);
|
||||
if (_timestamp_prev != 0) {
|
||||
// If TMST_RES = 0 (corresponding to timestamp resolution of 1µs), timestamp interval reported in FIFO requires scaling by a factor of 32/30.
|
||||
// Document Number: DS-000347 Revision: 1.5 Page 59 of 110
|
||||
static constexpr float FIFO_DT_SCALE = 32.f / 30.f;
|
||||
|
||||
accel.x[i] = accel_x;
|
||||
accel.y[i] = accel_y;
|
||||
accel.z[i] = accel_z;
|
||||
}
|
||||
float dt = 0;
|
||||
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 2048.f);
|
||||
}
|
||||
if (timestamp > _timestamp_prev) {
|
||||
dt = static_cast<float>(timestamp - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
|
||||
// correct frame for publication
|
||||
for (int i = 0; i < accel.samples; i++) {
|
||||
// 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)
|
||||
accel.x[i] = accel.x[i];
|
||||
accel.y[i] = (accel.y[i] == INT16_MIN) ? INT16_MAX : -accel.y[i];
|
||||
accel.z[i] = (accel.z[i] == INT16_MIN) ? INT16_MAX : -accel.z[i];
|
||||
}
|
||||
} else if (timestamp < _timestamp_prev) {
|
||||
// uint16_t rollover
|
||||
uint32_t timestamp_new = UINT16_MAX + timestamp;
|
||||
dt = static_cast<float>(timestamp_new - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
timestamp_interval_sum += dt;
|
||||
timestamp_interval_sum_count++;
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
}
|
||||
// check dt is within +=2% of expected value
|
||||
if ((dt < (FIFO_SAMPLE_DT * 0.98f)) || (dt > (FIFO_SAMPLE_DT * 1.02f))) {
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
}
|
||||
}
|
||||
|
||||
void ICM42688P::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = 0;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
_timestamp_prev = timestamp;
|
||||
}
|
||||
|
||||
// 20-bits of gyroscope data
|
||||
bool scale_20bit = false;
|
||||
|
||||
// first pass
|
||||
for (int i = 0; i < samples; i++) {
|
||||
// 20 bit hires mode
|
||||
// Gyro [19:12] + Gyro [11:4] + Gyro [3:0] (bottom 4 bits of 20 bit extension byte)
|
||||
int32_t gyro_x = reassemble_20bit(fifo[i].GYRO_DATA_X1, fifo[i].GYRO_DATA_X0, fifo[i].Ext_Accel_X_Gyro_X & 0x0F);
|
||||
int32_t gyro_y = reassemble_20bit(fifo[i].GYRO_DATA_Y1, fifo[i].GYRO_DATA_Y0, fifo[i].Ext_Accel_Y_Gyro_Y & 0x0F);
|
||||
int32_t gyro_z = reassemble_20bit(fifo[i].GYRO_DATA_Z1, fifo[i].GYRO_DATA_Z0, fifo[i].Ext_Accel_Z_Gyro_Z & 0x0F);
|
||||
|
||||
// check if any values are going to exceed int16 limits
|
||||
static constexpr int16_t max_gyro = INT16_MAX;
|
||||
static constexpr int16_t min_gyro = INT16_MIN;
|
||||
|
||||
if (gyro_x >= max_gyro || gyro_x <= min_gyro) {
|
||||
scale_20bit = true;
|
||||
}
|
||||
|
||||
if (gyro_y >= max_gyro || gyro_y <= min_gyro) {
|
||||
scale_20bit = true;
|
||||
}
|
||||
|
||||
if (gyro_z >= max_gyro || gyro_z <= min_gyro) {
|
||||
scale_20bit = true;
|
||||
}
|
||||
|
||||
gyro.x[gyro.samples] = gyro_x / 2;
|
||||
gyro.y[gyro.samples] = gyro_y / 2;
|
||||
gyro.z[gyro.samples] = gyro_z / 2;
|
||||
gyro.samples++;
|
||||
}
|
||||
|
||||
if (!scale_20bit) {
|
||||
// if highres enabled gyro data is always 131 LSB/dps
|
||||
_px4_gyro.set_scale(math::radians(1.f / 131.f));
|
||||
|
||||
} else {
|
||||
// 20 bit data scaled to 16 bit (2^4)
|
||||
for (int i = 0; i < samples; i++) {
|
||||
gyro.x[i] = combine(fifo[i].GYRO_DATA_X1, fifo[i].GYRO_DATA_X0);
|
||||
gyro.y[i] = combine(fifo[i].GYRO_DATA_Y1, fifo[i].GYRO_DATA_Y0);
|
||||
gyro.z[i] = combine(fifo[i].GYRO_DATA_Z1, fifo[i].GYRO_DATA_Z0);
|
||||
}
|
||||
|
||||
_px4_gyro.set_scale(math::radians(2000.f / 32768.f));
|
||||
}
|
||||
|
||||
// correct frame for publication
|
||||
for (int i = 0; i < gyro.samples; i++) {
|
||||
// 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)
|
||||
gyro.x[i] = gyro.x[i];
|
||||
gyro.y[i] = (gyro.y[i] == INT16_MIN) ? INT16_MAX : -gyro.y[i];
|
||||
gyro.z[i] = (gyro.z[i] == INT16_MIN) ? INT16_MAX : -gyro.z[i];
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (gyro.samples > 0) {
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
}
|
||||
|
||||
bool ICM42688P::ProcessTemperature(const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
int16_t temperature[FIFO_MAX_SAMPLES];
|
||||
float temperature_sum{0};
|
||||
|
||||
int valid_samples = 0;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t t = combine(fifo[i].TEMP_DATA1, fifo[i].TEMP_DATA0);
|
||||
|
||||
// sample invalid if -32768
|
||||
if (t != -32768) {
|
||||
temperature_sum += t;
|
||||
temperature[valid_samples] = t;
|
||||
valid_samples++;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_samples > 0) {
|
||||
const float temperature_avg = temperature_sum / valid_samples;
|
||||
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// temperature changing wildly is an indication of a transfer error
|
||||
if (fabsf(temperature[i] - temperature_avg) > 1000) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
|
||||
for (int i = 0; i < sensor_imu_fifo.samples; i++) {
|
||||
// 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)
|
||||
|
||||
// sensor_imu_fifo.accel_x[i]
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(sensor_imu_fifo.accel_y[i]);
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(sensor_imu_fifo.accel_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
// sensor_imu_fifo.gyro_x[i]
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(sensor_imu_fifo.gyro_y[i]);
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(sensor_imu_fifo.gyro_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
const float temperature_avg = temperature_sum / valid_samples;
|
||||
|
||||
// use average temperature reading
|
||||
const float TEMP_degC = (temperature_avg / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
return true;
|
||||
sensor_imu_fifo.temperature = TEMP_degC;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timestamp_interval_sum > 0) {
|
||||
const float dt_avg = (timestamp_interval_sum / timestamp_interval_sum_count);
|
||||
|
||||
// check dt is within +=1% of expected value
|
||||
if ((dt_avg < (FIFO_SAMPLE_DT * 0.99f)) || (dt_avg > (FIFO_SAMPLE_DT * 1.01f))) {
|
||||
PX4_ERR("DT error %.6f", (double)dt_avg);
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.dt = dt_avg;
|
||||
}
|
||||
}
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ICM42688P::FIFOReset()
|
||||
{
|
||||
perf_count(_fifo_reset_perf);
|
||||
|
||||
// SIGNAL_PATH_RESET: FIFO flush
|
||||
RegisterSetBits(Register::BANK_0::SIGNAL_PATH_RESET, SIGNAL_PATH_RESET_BIT::FIFO_FLUSH);
|
||||
|
||||
// reset while FIFO is disabled
|
||||
_drdy_timestamp_sample.store(0);
|
||||
|
||||
_timestamp_prev = 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_ICM42688P_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_ICM42688P;
|
||||
|
||||
class ICM42688P : public device::SPI, public I2CSPIDriver<ICM42688P>
|
||||
@@ -71,22 +72,10 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f}; // 8000 Hz accel & gyro ODR configured
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float ACCEL_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (4 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
struct register_bank0_config_t {
|
||||
Register::BANK_0 reg;
|
||||
@@ -135,20 +124,18 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
void ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
bool ProcessTemperature(const FIFO::DATA fifo[], const uint8_t samples);
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
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 _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")};
|
||||
perf_counter_t _fifo_overflow_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO overflow")};
|
||||
perf_counter_t _fifo_reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO reset")};
|
||||
perf_counter_t _fifo_timestamp_error_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO timestamp error")};
|
||||
perf_counter_t _drdy_missed_perf{nullptr};
|
||||
|
||||
hrt_abstime _reset_timestamp{0};
|
||||
@@ -156,6 +143,8 @@ private:
|
||||
hrt_abstime _temperature_update_timestamp{0};
|
||||
int _failure_count{0};
|
||||
|
||||
uint16_t _timestamp_prev{0};
|
||||
|
||||
enum REG_BANK_SEL_BIT _last_register_bank {REG_BANK_SEL_BIT::USER_BANK_0};
|
||||
|
||||
px4::atomic<hrt_abstime> _drdy_timestamp_sample{0};
|
||||
@@ -170,25 +159,26 @@ private:
|
||||
} _state{STATE::RESET};
|
||||
|
||||
uint16_t _fifo_empty_interval_us{1250}; // default 1250 us / 800 Hz transfer interval
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / GYRO_RATE))};
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / RATE))};
|
||||
|
||||
uint8_t _checked_register_bank0{0};
|
||||
static constexpr uint8_t size_register_bank0_cfg{13};
|
||||
static constexpr uint8_t size_register_bank0_cfg{14};
|
||||
register_bank0_config_t _register_bank0_cfg[size_register_bank0_cfg] {
|
||||
// Register | Set bits, Clear bits
|
||||
{ Register::BANK_0::INT_CONFIG, INT_CONFIG_BIT::INT1_MODE | INT_CONFIG_BIT::INT1_DRIVE_CIRCUIT, INT_CONFIG_BIT::INT1_POLARITY },
|
||||
{ Register::BANK_0::FIFO_CONFIG, FIFO_CONFIG_BIT::FIFO_MODE_STOP_ON_FULL, 0 },
|
||||
{ Register::BANK_0::PWR_MGMT0, PWR_MGMT0_BIT::GYRO_MODE_LOW_NOISE | PWR_MGMT0_BIT::ACCEL_MODE_LOW_NOISE, 0 },
|
||||
{ Register::BANK_0::GYRO_CONFIG0, GYRO_CONFIG0_BIT::GYRO_FS_SEL_2000_DPS | GYRO_CONFIG0_BIT::GYRO_ODR_8KHZ_SET, GYRO_CONFIG0_BIT::GYRO_ODR_8KHZ_CLEAR },
|
||||
{ Register::BANK_0::ACCEL_CONFIG0, ACCEL_CONFIG0_BIT::ACCEL_FS_SEL_16G | ACCEL_CONFIG0_BIT::ACCEL_ODR_8KHZ_SET, ACCEL_CONFIG0_BIT::ACCEL_ODR_8KHZ_CLEAR },
|
||||
{ Register::BANK_0::GYRO_CONFIG1, 0, GYRO_CONFIG1_BIT::GYRO_UI_FILT_ORD },
|
||||
{ Register::BANK_0::GYRO_CONFIG0, GYRO_CONFIG0_BIT::GYRO_ODR_8KHZ_SET, GYRO_CONFIG0_BIT::GYRO_FS_SEL_2000_DPS_CLEAR | GYRO_CONFIG0_BIT::GYRO_ODR_8KHZ_CLEAR },
|
||||
{ Register::BANK_0::ACCEL_CONFIG0, ACCEL_CONFIG0_BIT::ACCEL_ODR_8KHZ_SET, ACCEL_CONFIG0_BIT::ACCEL_FS_SEL_16G_CLEAR | ACCEL_CONFIG0_BIT::ACCEL_ODR_8KHZ_CLEAR },
|
||||
{ Register::BANK_0::GYRO_CONFIG1, 0, GYRO_CONFIG1_BIT::GYRO_UI_FILT_ORD_1ST_CLEAR },
|
||||
{ Register::BANK_0::GYRO_ACCEL_CONFIG0, 0, GYRO_ACCEL_CONFIG0_BIT::ACCEL_UI_FILT_BW | GYRO_ACCEL_CONFIG0_BIT::GYRO_UI_FILT_BW },
|
||||
{ Register::BANK_0::ACCEL_CONFIG1, 0, ACCEL_CONFIG1_BIT::ACCEL_UI_FILT_ORD },
|
||||
{ Register::BANK_0::FIFO_CONFIG1, FIFO_CONFIG1_BIT::FIFO_WM_GT_TH | FIFO_CONFIG1_BIT::FIFO_HIRES_EN | FIFO_CONFIG1_BIT::FIFO_TEMP_EN | FIFO_CONFIG1_BIT::FIFO_GYRO_EN | FIFO_CONFIG1_BIT::FIFO_ACCEL_EN, 0 },
|
||||
{ Register::BANK_0::ACCEL_CONFIG1, 0, ACCEL_CONFIG1_BIT::ACCEL_UI_FILT_ORD_1ST_CLEAR },
|
||||
{ Register::BANK_0::FIFO_CONFIG1, FIFO_CONFIG1_BIT::FIFO_RESUME_PARTIAL_RD | FIFO_CONFIG1_BIT::FIFO_HIRES_EN | FIFO_CONFIG1_BIT::FIFO_TEMP_EN | FIFO_CONFIG1_BIT::FIFO_GYRO_EN | FIFO_CONFIG1_BIT::FIFO_ACCEL_EN, 0 },
|
||||
{ Register::BANK_0::FIFO_CONFIG2, 0, 0 }, // FIFO_WM[7:0] set at runtime
|
||||
{ Register::BANK_0::FIFO_CONFIG3, 0, 0 }, // FIFO_WM[11:8] set at runtime
|
||||
{ Register::BANK_0::INT_CONFIG0, INT_CONFIG0_BIT::CLEAR_ON_FIFO_READ, 0 },
|
||||
{ Register::BANK_0::INT_SOURCE0, INT_SOURCE0_BIT::FIFO_THS_INT1_EN, 0 },
|
||||
{ Register::BANK_0::INT_CONFIG0, INT_CONFIG0_BIT::FIFO_THS_INT_CLEAR, 0 },
|
||||
{ Register::BANK_0::INT_CONFIG1, INT_CONFIG1_BIT::INT_TPULSE_DURATION | INT_CONFIG1_BIT::INT_TDEASSERT_DISABLE, INT_CONFIG1_BIT::INT_ASYNC_RESET },
|
||||
{ Register::BANK_0::INT_SOURCE0, INT_SOURCE0_BIT::FIFO_THS_INT1_EN, INT_SOURCE0_BIT::RESET_DONE_INT1_EN },
|
||||
};
|
||||
|
||||
uint8_t _checked_register_bank1{0};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -82,8 +82,7 @@ enum class BANK_0 : uint8_t {
|
||||
FIFO_DATA = 0x30,
|
||||
|
||||
SIGNAL_PATH_RESET = 0x4B,
|
||||
INTF_CONFIG0 = 0x4C,
|
||||
INTF_CONFIG1 = 0x4D,
|
||||
|
||||
PWR_MGMT0 = 0x4E,
|
||||
GYRO_CONFIG0 = 0x4F,
|
||||
ACCEL_CONFIG0 = 0x50,
|
||||
@@ -96,7 +95,7 @@ enum class BANK_0 : uint8_t {
|
||||
FIFO_CONFIG3 = 0x61,
|
||||
|
||||
INT_CONFIG0 = 0x63,
|
||||
|
||||
INT_CONFIG1 = 0x64,
|
||||
INT_SOURCE0 = 0x65,
|
||||
|
||||
SELF_TEST_CONFIG = 0x70,
|
||||
@@ -121,7 +120,7 @@ enum class BANK_2 : uint8_t {
|
||||
|
||||
// DEVICE_CONFIG
|
||||
enum DEVICE_CONFIG_BIT : uint8_t {
|
||||
SOFT_RESET_CONFIG = Bit0, //
|
||||
SOFT_RESET_CONFIG = Bit0,
|
||||
};
|
||||
|
||||
// INT_CONFIG
|
||||
@@ -140,15 +139,14 @@ enum FIFO_CONFIG_BIT : uint8_t {
|
||||
// INT_STATUS
|
||||
enum INT_STATUS_BIT : uint8_t {
|
||||
RESET_DONE_INT = Bit4,
|
||||
DATA_RDY_INT = Bit3,
|
||||
|
||||
FIFO_THS_INT = Bit2,
|
||||
FIFO_FULL_INT = Bit1,
|
||||
};
|
||||
|
||||
// SIGNAL_PATH_RESET
|
||||
enum SIGNAL_PATH_RESET_BIT : uint8_t {
|
||||
ABORT_AND_RESET = Bit3,
|
||||
FIFO_FLUSH = Bit1,
|
||||
FIFO_FLUSH = Bit1,
|
||||
};
|
||||
|
||||
// PWR_MGMT0
|
||||
@@ -160,55 +158,42 @@ enum PWR_MGMT0_BIT : uint8_t {
|
||||
// GYRO_CONFIG0
|
||||
enum GYRO_CONFIG0_BIT : uint8_t {
|
||||
// 7:5 GYRO_FS_SEL
|
||||
GYRO_FS_SEL_2000_DPS = 0, // 0b000 = ±2000dps (default)
|
||||
GYRO_FS_SEL_1000_DPS = Bit5,
|
||||
GYRO_FS_SEL_500_DPS = Bit6,
|
||||
GYRO_FS_SEL_250_DPS = Bit6 | Bit5,
|
||||
GYRO_FS_SEL_125_DPS = Bit7,
|
||||
|
||||
// 0b000: ±2000dps (default)
|
||||
GYRO_FS_SEL_2000_DPS_CLEAR = Bit7 | Bit6 | Bit5,
|
||||
|
||||
// 3:0 GYRO_ODR
|
||||
// 0001: 32kHz
|
||||
GYRO_ODR_32KHZ_SET = Bit0,
|
||||
GYRO_ODR_32KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0010: 16kHz
|
||||
GYRO_ODR_16KHZ_SET = Bit1,
|
||||
GYRO_ODR_16KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0011: 8kHz
|
||||
GYRO_ODR_8KHZ_SET = Bit1 | Bit0,
|
||||
GYRO_ODR_8KHZ_CLEAR = Bit3 | Bit2,
|
||||
// 0110: 1kHz (default)
|
||||
GYRO_ODR_1KHZ_SET = Bit2 | Bit1,
|
||||
GYRO_ODR_1KHZ_CLEAR = Bit3 | Bit0,
|
||||
// 0b0001: 32kHz (maximum)
|
||||
GYRO_ODR_32KHZ_SET = Bit0,
|
||||
GYRO_ODR_32KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0b0011: 8kHz
|
||||
GYRO_ODR_8KHZ_SET = Bit1 | Bit0,
|
||||
GYRO_ODR_8KHZ_CLEAR = Bit3 | Bit2,
|
||||
// 0b0110: 1kHz (default)
|
||||
GYRO_ODR_1KHZ_SET = Bit2 | Bit1,
|
||||
GYRO_ODR_1KHZ_CLEAR = Bit3 | Bit0,
|
||||
};
|
||||
|
||||
// ACCEL_CONFIG0
|
||||
enum ACCEL_CONFIG0_BIT : uint8_t {
|
||||
// 7:5 ACCEL_FS_SEL
|
||||
ACCEL_FS_SEL_16G = 0, // 000: ±16g (default)
|
||||
ACCEL_FS_SEL_8G = Bit5,
|
||||
ACCEL_FS_SEL_4G = Bit6,
|
||||
ACCEL_FS_SEL_2G = Bit6 | Bit5,
|
||||
|
||||
// 0b000: ±16g (default)
|
||||
ACCEL_FS_SEL_16G_CLEAR = Bit7 | Bit6 | Bit5,
|
||||
|
||||
// 3:0 ACCEL_ODR
|
||||
// 0001: 32kHz
|
||||
ACCEL_ODR_32KHZ_SET = Bit0,
|
||||
ACCEL_ODR_32KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0010: 16kHz
|
||||
ACCEL_ODR_16KHZ_SET = Bit1,
|
||||
ACCEL_ODR_16KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0011: 8kHz
|
||||
ACCEL_ODR_8KHZ_SET = Bit1 | Bit0,
|
||||
ACCEL_ODR_8KHZ_CLEAR = Bit3 | Bit2,
|
||||
// 0110: 1kHz (default)
|
||||
ACCEL_ODR_1KHZ_SET = Bit2 | Bit1,
|
||||
ACCEL_ODR_1KHZ_CLEAR = Bit3 | Bit0,
|
||||
// 0b0001: 32kHz (maximum)
|
||||
ACCEL_ODR_32KHZ_SET = Bit0,
|
||||
ACCEL_ODR_32KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0b0011: 8kHz
|
||||
ACCEL_ODR_8KHZ_SET = Bit1 | Bit0,
|
||||
ACCEL_ODR_8KHZ_CLEAR = Bit3 | Bit2,
|
||||
// 0b0110: 1kHz (default)
|
||||
ACCEL_ODR_1KHZ_SET = Bit2 | Bit1,
|
||||
ACCEL_ODR_1KHZ_CLEAR = Bit3 | Bit0,
|
||||
};
|
||||
|
||||
// GYRO_CONFIG1
|
||||
enum GYRO_CONFIG1_BIT : uint8_t {
|
||||
GYRO_UI_FILT_ORD = Bit3 | Bit2, // 00: 1st Order
|
||||
GYRO_UI_FILT_ORD_1ST_CLEAR = Bit3 | Bit2, // 00: 1st Order UI filter
|
||||
};
|
||||
|
||||
// GYRO_ACCEL_CONFIG0
|
||||
@@ -222,14 +207,15 @@ enum GYRO_ACCEL_CONFIG0_BIT : uint8_t {
|
||||
|
||||
// ACCEL_CONFIG1
|
||||
enum ACCEL_CONFIG1_BIT : uint8_t {
|
||||
ACCEL_UI_FILT_ORD = Bit4 | Bit3, // 00: 1st Order
|
||||
ACCEL_UI_FILT_ORD_1ST_CLEAR = Bit4 | Bit3, // 00: 1st Order UI filter
|
||||
};
|
||||
|
||||
// FIFO_CONFIG1
|
||||
enum FIFO_CONFIG1_BIT : uint8_t {
|
||||
FIFO_RESUME_PARTIAL_RD = Bit6,
|
||||
FIFO_WM_GT_TH = Bit5,
|
||||
|
||||
FIFO_HIRES_EN = Bit4,
|
||||
|
||||
FIFO_TEMP_EN = Bit2,
|
||||
FIFO_GYRO_EN = Bit1,
|
||||
FIFO_ACCEL_EN = Bit0,
|
||||
@@ -238,18 +224,21 @@ enum FIFO_CONFIG1_BIT : uint8_t {
|
||||
// INT_CONFIG0
|
||||
enum INT_CONFIG0_BIT : uint8_t {
|
||||
// 3:2 FIFO_THS_INT_CLEAR
|
||||
CLEAR_ON_FIFO_READ = Bit3,
|
||||
FIFO_THS_INT_CLEAR = Bit3, // 10: Clear on FIFO data 1Byte Read
|
||||
};
|
||||
|
||||
// INT_CONFIG1
|
||||
enum INT_CONFIG1_BIT : uint8_t {
|
||||
INT_TPULSE_DURATION = Bit6, // 1: Interrupt pulse duration is 8 µs. Required if ODR ≥ 4kHz, optional for ODR < 4kHz.
|
||||
INT_TDEASSERT_DISABLE = Bit5, // 1: Disables de-assert duration. Required if ODR ≥ 4kHz, optional for ODR < 4kHz.
|
||||
INT_ASYNC_RESET = Bit4, // User should change setting to 0 from default setting of 1, for proper INT1 and INT2 pin operation
|
||||
};
|
||||
|
||||
// INT_SOURCE0
|
||||
enum INT_SOURCE0_BIT : uint8_t {
|
||||
UI_FSYNC_INT1_EN = Bit6,
|
||||
PLL_RDY_INT1_EN = Bit5,
|
||||
RESET_DONE_INT1_EN = Bit4,
|
||||
UI_DRDY_INT1_EN = Bit3,
|
||||
RESET_DONE_INT1_EN = Bit4, // 1: Reset done interrupt routed to INT1 (enabled by default)
|
||||
|
||||
FIFO_THS_INT1_EN = Bit2, // FIFO threshold interrupt routed to INT1
|
||||
FIFO_FULL_INT1_EN = Bit1,
|
||||
UI_AGC_RDY_INT1_EN = Bit0,
|
||||
};
|
||||
|
||||
// REG_BANK_SEL
|
||||
@@ -277,6 +266,7 @@ enum ACCEL_CONFIG_STATIC2_BIT : uint8_t {
|
||||
ACCEL_AAF_DIS = Bit0,
|
||||
};
|
||||
|
||||
|
||||
namespace FIFO
|
||||
{
|
||||
static constexpr size_t SIZE = 2048;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020, 2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -72,13 +72,11 @@ extern "C" int icm42688p_main(int argc, char *argv[])
|
||||
|
||||
if (!strcmp(verb, "start")) {
|
||||
return ThisDriver::module_start(cli, iterator);
|
||||
}
|
||||
|
||||
if (!strcmp(verb, "stop")) {
|
||||
} else if (!strcmp(verb, "stop")) {
|
||||
return ThisDriver::module_stop(iterator);
|
||||
}
|
||||
|
||||
if (!strcmp(verb, "status")) {
|
||||
} else if (!strcmp(verb, "status")) {
|
||||
return ThisDriver::module_status(iterator);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,4 @@ px4_add_module(
|
||||
InvenSense_IIM42652_registers.hpp
|
||||
DEPENDS
|
||||
px4_work_queue
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
)
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "IIM42652.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ IIM42652::IIM42652(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
IIM42652::~IIM42652()
|
||||
@@ -61,6 +65,7 @@ IIM42652::~IIM42652()
|
||||
perf_free(_fifo_empty_perf);
|
||||
perf_free(_fifo_overflow_perf);
|
||||
perf_free(_fifo_reset_perf);
|
||||
perf_free(_fifo_timestamp_error_perf);
|
||||
perf_free(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
@@ -102,12 +107,14 @@ void IIM42652::print_status()
|
||||
perf_print_counter(_fifo_empty_perf);
|
||||
perf_print_counter(_fifo_overflow_perf);
|
||||
perf_print_counter(_fifo_reset_perf);
|
||||
perf_print_counter(_fifo_timestamp_error_perf);
|
||||
perf_print_counter(_drdy_missed_perf);
|
||||
}
|
||||
|
||||
int IIM42652::probe()
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
uint8_t whoami = RegisterRead(Register::BANK_0::WHO_AM_I);
|
||||
|
||||
if (whoami == WHOAMI) {
|
||||
@@ -162,8 +169,8 @@ void IIM42652::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,21 +178,9 @@ void IIM42652::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
FIFOReset();
|
||||
// if configure succeeded then reset the FIFO
|
||||
_state = STATE::FIFO_RESET;
|
||||
ScheduleDelayed(1_ms);
|
||||
|
||||
} else {
|
||||
// CONFIGURE not complete
|
||||
@@ -202,6 +197,24 @@ void IIM42652::RunImpl()
|
||||
|
||||
break;
|
||||
|
||||
case STATE::FIFO_RESET:
|
||||
|
||||
_state = STATE::FIFO_READ;
|
||||
FIFOReset();
|
||||
|
||||
if (DataReadyInterruptConfigure()) {
|
||||
_data_ready_interrupt_enabled = true;
|
||||
|
||||
// backup schedule as a watchdog timeout
|
||||
ScheduleDelayed(100_ms);
|
||||
|
||||
} else {
|
||||
_data_ready_interrupt_enabled = false;
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STATE::FIFO_READ: {
|
||||
hrt_abstime timestamp_sample = now;
|
||||
uint8_t samples = 0;
|
||||
@@ -210,7 +223,7 @@ void IIM42652::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
@@ -222,6 +235,8 @@ void IIM42652::RunImpl()
|
||||
ScheduleDelayed(_fifo_empty_interval_us * 2);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples == 0) {
|
||||
// check current FIFO count
|
||||
const uint16_t fifo_count = FIFOReadCount();
|
||||
@@ -234,27 +249,42 @@ void IIM42652::RunImpl()
|
||||
perf_count(_fifo_empty_perf);
|
||||
|
||||
} else {
|
||||
// FIFO count (size in bytes)
|
||||
samples = (fifo_count / sizeof(FIFO::DATA));
|
||||
// FIFO count (size in bytes) should be a multiple of the FIFO::DATA structure
|
||||
samples = fifo_count / sizeof(FIFO::DATA);
|
||||
|
||||
// tolerate minor jitter, leave sample to next iteration if behind by only 1
|
||||
if (samples == _fifo_gyro_samples + 1) {
|
||||
timestamp_sample -= static_cast<int>(FIFO_SAMPLE_DT);
|
||||
samples--;
|
||||
if (samples > _fifo_gyro_samples) {
|
||||
// grab desired number of samples, but reschedule next cycle sooner
|
||||
const int extra_samples = samples - _fifo_gyro_samples;
|
||||
samples = _fifo_gyro_samples;
|
||||
|
||||
if (_fifo_gyro_samples > extra_samples) {
|
||||
// reschedule to run when a total of _fifo_gyro_samples should be available in the FIFO
|
||||
const uint32_t reschedule_delay_us = (_fifo_gyro_samples - extra_samples) * static_cast<int>(FIFO_SAMPLE_DT);
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, reschedule_delay_us);
|
||||
|
||||
} else {
|
||||
// otherwise reschedule to run immediately
|
||||
ScheduleOnInterval(_fifo_empty_interval_us);
|
||||
}
|
||||
|
||||
} else if (samples < _fifo_gyro_samples) {
|
||||
// reschedule next cycle to catch the desired number of samples
|
||||
ScheduleOnInterval(_fifo_empty_interval_us, (_fifo_gyro_samples - samples) * static_cast<int>(FIFO_SAMPLE_DT));
|
||||
}
|
||||
|
||||
if (samples > FIFO_MAX_SAMPLES) {
|
||||
// not technically an overflow, but more samples than we expected or can publish
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
samples = 0;
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(now, samples)) {
|
||||
success = true;
|
||||
|
||||
if (_failure_count > 0) {
|
||||
_failure_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (samples >= 1) {
|
||||
if (samples == _fifo_gyro_samples) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
@@ -269,13 +299,14 @@ void IIM42652::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (!success || hrt_elapsed_time(&_last_config_check_timestamp) > 100_ms) {
|
||||
// check configuration registers periodically or immediately following any failure
|
||||
if (RegisterCheck(_register_bank0_cfg[_checked_register_bank0])
|
||||
&& RegisterCheck(_register_bank1_cfg[_checked_register_bank1])
|
||||
&& RegisterCheck(_register_bank2_cfg[_checked_register_bank2])
|
||||
@@ -303,10 +334,10 @@ void IIM42652::ConfigureSampleRate(int sample_rate)
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / RATE), (float)FIFO_MAX_SAMPLES));
|
||||
|
||||
// recompute FIFO empty interval (us) with actual gyro sample limit
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / GYRO_RATE);
|
||||
_fifo_empty_interval_us = _fifo_gyro_samples * (1e6f / RATE);
|
||||
|
||||
ConfigureFIFOWatermark(_fifo_gyro_samples);
|
||||
}
|
||||
@@ -356,6 +387,7 @@ bool IIM42652::Configure()
|
||||
RegisterSetAndClearBits(reg_cfg.reg, reg_cfg.set_bits, reg_cfg.clear_bits);
|
||||
}
|
||||
|
||||
|
||||
// now check that all are configured
|
||||
bool success = true;
|
||||
|
||||
@@ -377,11 +409,6 @@ bool IIM42652::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
// 20-bits data format used
|
||||
// the only FSR settings that are operational are ±2000dps for gyroscope and ±16g for accelerometer
|
||||
_px4_accel.set_range(16.f * CONSTANTS_ONE_G);
|
||||
_px4_gyro.set_range(math::radians(2000.f));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -404,7 +431,7 @@ bool IIM42652::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool IIM42652::DataReadyInterruptDisable()
|
||||
@@ -413,7 +440,7 @@ bool IIM42652::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -468,114 +495,20 @@ void IIM42652::RegisterSetAndClearBits(T reg, uint8_t setbits, uint8_t clearbits
|
||||
|
||||
uint16_t IIM42652::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ;
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
}
|
||||
|
||||
bool IIM42652::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 4, FIFO::SIZE);
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer.INT_STATUS & INT_STATUS_BIT::FIFO_FULL_INT) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = combine(buffer.FIFO_COUNTH, buffer.FIFO_COUNTL);
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
if (fifo_count_samples == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check FIFO header in every sample
|
||||
uint8_t valid_samples = 0;
|
||||
|
||||
for (int i = 0; i < math::min(samples, fifo_count_samples); i++) {
|
||||
bool valid = true;
|
||||
|
||||
// With FIFO_ACCEL_EN and FIFO_GYRO_EN header should be 8’b_0110_10xx
|
||||
const uint8_t FIFO_HEADER = buffer.f[i].FIFO_Header;
|
||||
|
||||
if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG) {
|
||||
// FIFO sample empty if HEADER_MSG set
|
||||
valid = false;
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL)) {
|
||||
// accel bit not set
|
||||
valid = false;
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO)) {
|
||||
// gyro bit not set
|
||||
valid = false;
|
||||
|
||||
} else if (!(FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_20)) {
|
||||
// Packet does not contain a new and valid extended 20-bit data
|
||||
valid = false;
|
||||
|
||||
} else if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_ACCEL) {
|
||||
// accel ODR changed
|
||||
valid = false;
|
||||
|
||||
} else if (FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_GYRO) {
|
||||
// gyro ODR changed
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
valid_samples++;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_samples > 0) {
|
||||
if (ProcessTemperature(buffer.f, valid_samples)) {
|
||||
ProcessGyro(timestamp_sample, buffer.f, valid_samples);
|
||||
ProcessAccel(timestamp_sample, buffer.f, valid_samples);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IIM42652::FIFOReset()
|
||||
{
|
||||
perf_count(_fifo_reset_perf);
|
||||
|
||||
// SIGNAL_PATH_RESET: FIFO flush
|
||||
RegisterSetBits(Register::BANK_0::SIGNAL_PATH_RESET, SIGNAL_PATH_RESET_BIT::FIFO_FLUSH);
|
||||
|
||||
// reset while FIFO is disabled
|
||||
_drdy_timestamp_sample.store(0);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
static constexpr int32_t reassemble_20bit(const uint32_t a, const uint32_t b, const uint32_t c)
|
||||
@@ -595,206 +528,288 @@ static constexpr int32_t reassemble_20bit(const uint32_t a, const uint32_t b, co
|
||||
return static_cast<int32_t>(x);
|
||||
}
|
||||
|
||||
void IIM42652::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
bool IIM42652::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT;
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// 18-bits of accelerometer data
|
||||
bool scale_20bit = false;
|
||||
// cmd + INT_STATUS + FIFO_COUNTH + FIFO_COUNTL + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 4 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
// first pass
|
||||
for (int i = 0; i < samples; i++) {
|
||||
// 20 bit hires mode
|
||||
// Sign extension + Accel [19:12] + Accel [11:4] + Accel [3:2] (20 bit extension byte)
|
||||
// Accel data is 18 bit ()
|
||||
int32_t accel_x = reassemble_20bit(fifo[i].ACCEL_DATA_X1, fifo[i].ACCEL_DATA_X0,
|
||||
fifo[i].Ext_Accel_X_Gyro_X & 0xF0 >> 4);
|
||||
int32_t accel_y = reassemble_20bit(fifo[i].ACCEL_DATA_Y1, fifo[i].ACCEL_DATA_Y0,
|
||||
fifo[i].Ext_Accel_Y_Gyro_Y & 0xF0 >> 4);
|
||||
int32_t accel_z = reassemble_20bit(fifo[i].ACCEL_DATA_Z1, fifo[i].ACCEL_DATA_Z0,
|
||||
fifo[i].Ext_Accel_Z_Gyro_Z & 0xF0 >> 4);
|
||||
SelectRegisterBank(REG_BANK_SEL_BIT::USER_BANK_0);
|
||||
|
||||
// sample invalid if -524288
|
||||
if (accel_x != -524288 && accel_y != -524288 && accel_z != -524288) {
|
||||
// check if any values are going to exceed int16 limits
|
||||
static constexpr int16_t max_accel = INT16_MAX;
|
||||
static constexpr int16_t min_accel = INT16_MIN;
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (accel_x >= max_accel || accel_x <= min_accel) {
|
||||
scale_20bit = true;
|
||||
if (buffer.INT_STATUS & INT_STATUS_BIT::FIFO_FULL_INT) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t fifo_count_bytes = (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
|
||||
if (fifo_count_bytes >= FIFO::SIZE) {
|
||||
perf_count(_fifo_overflow_perf);
|
||||
FIFOReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t fifo_count_samples = fifo_count_bytes / sizeof(FIFO::DATA);
|
||||
|
||||
if (fifo_count_samples == 0) {
|
||||
perf_count(_fifo_empty_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = 0;
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 8192.f; // highres accel data 8192 LSB/g
|
||||
sensor_imu_fifo.gyro_scale = math::radians(1.f / 131.f); // highres gyro data 131 LSB/dps
|
||||
|
||||
// check FIFO header in every sample
|
||||
uint8_t valid_samples = 0;
|
||||
|
||||
float temperature_sum = 0;
|
||||
|
||||
float timestamp_interval_sum = 0;
|
||||
int timestamp_interval_sum_count = 0;
|
||||
|
||||
bool accel_scale_16bit = false; // 18-bits of accelerometer data
|
||||
bool gyro_scale_16bit = false; // 20-bits of gyroscope data
|
||||
|
||||
for (int i = 0; i < math::min(samples, fifo_count_samples); i++) {
|
||||
const FIFO::DATA &fifo = buffer.f[i];
|
||||
|
||||
// With FIFO_ACCEL_EN and FIFO_GYRO_EN header should be 8’b_0110_10xx
|
||||
const uint8_t FIFO_HEADER = fifo.FIFO_Header;
|
||||
|
||||
const bool HEADER_MSG = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_MSG; // FIFO is empty
|
||||
const bool HEADER_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ACCEL;
|
||||
const bool HEADER_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_GYRO;
|
||||
const bool HEADER_20 = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_20; // valid sample of extended 20-bit data
|
||||
// 3:2 HEADER_TIMESTAMP_FSYNC
|
||||
const bool HEADER_ODR_ACCEL = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_ACCEL; // ODR for accel is different
|
||||
const bool HEADER_ODR_GYRO = FIFO_HEADER & FIFO::FIFO_HEADER_BIT::HEADER_ODR_GYRO; // ODR for gyro is different
|
||||
|
||||
if (!HEADER_MSG && HEADER_ACCEL && HEADER_GYRO && HEADER_20 && !HEADER_ODR_ACCEL && !HEADER_ODR_GYRO) {
|
||||
|
||||
if (!accel_scale_16bit) {
|
||||
// Accel: 20 bit hires mode, Accel data is 18 bit
|
||||
// Sign extension + Accel [19:12] + Accel [11:4] + Accel [3:2] (20 bit extension byte)
|
||||
int32_t accel_x = reassemble_20bit(fifo.ACCEL_DATA_X1, fifo.ACCEL_DATA_X0, fifo.Ext_Accel_X_Gyro_X & 0xF0 >> 4);
|
||||
int32_t accel_y = reassemble_20bit(fifo.ACCEL_DATA_Y1, fifo.ACCEL_DATA_Y0, fifo.Ext_Accel_Y_Gyro_Y & 0xF0 >> 4);
|
||||
int32_t accel_z = reassemble_20bit(fifo.ACCEL_DATA_Z1, fifo.ACCEL_DATA_Z0, fifo.Ext_Accel_Z_Gyro_Z & 0xF0 >> 4);
|
||||
|
||||
// sample invalid if -524288
|
||||
if (accel_x == -524288 || accel_y == -524288 || accel_z == -524288) {
|
||||
break;
|
||||
}
|
||||
|
||||
// shift by 2 (2 least significant bits are always 0)
|
||||
accel_x = accel_x / 4;
|
||||
accel_y = accel_y / 4;
|
||||
accel_z = accel_z / 4;
|
||||
|
||||
// check if any values are going to exceed int16 limits
|
||||
if ((accel_x >= INT16_MAX || accel_x <= INT16_MIN)
|
||||
|| (accel_y >= INT16_MAX || accel_y <= INT16_MIN)
|
||||
|| (accel_z >= INT16_MAX || accel_z <= INT16_MIN)) {
|
||||
|
||||
accel_scale_16bit = true;
|
||||
|
||||
// 20 bit data scaled to 16 bit
|
||||
sensor_imu_fifo.accel_scale = CONSTANTS_ONE_G / 2048.f;
|
||||
|
||||
// rescale any existing data
|
||||
for (int j = 0; j < valid_samples + 1; j++) {
|
||||
sensor_imu_fifo.accel_x[valid_samples] = combine(buffer.f[j].ACCEL_DATA_X1, buffer.f[j].ACCEL_DATA_X0);
|
||||
sensor_imu_fifo.accel_y[valid_samples] = combine(buffer.f[j].ACCEL_DATA_Y1, buffer.f[j].ACCEL_DATA_Y0);
|
||||
sensor_imu_fifo.accel_z[valid_samples] = combine(buffer.f[j].ACCEL_DATA_Z1, buffer.f[j].ACCEL_DATA_Z0);
|
||||
}
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.accel_x[valid_samples] = accel_x;
|
||||
sensor_imu_fifo.accel_y[valid_samples] = accel_y;
|
||||
sensor_imu_fifo.accel_z[valid_samples] = accel_z;
|
||||
}
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.accel_x[valid_samples] = combine(fifo.ACCEL_DATA_X1, fifo.ACCEL_DATA_X0);
|
||||
sensor_imu_fifo.accel_y[valid_samples] = combine(fifo.ACCEL_DATA_Y1, fifo.ACCEL_DATA_Y0);
|
||||
sensor_imu_fifo.accel_z[valid_samples] = combine(fifo.ACCEL_DATA_Z1, fifo.ACCEL_DATA_Z0);
|
||||
}
|
||||
|
||||
if (accel_y >= max_accel || accel_y <= min_accel) {
|
||||
scale_20bit = true;
|
||||
|
||||
if (!gyro_scale_16bit) {
|
||||
// Gyro: 20 bit hires mode
|
||||
// Gyro [19:12] + Gyro [11:4] + Gyro [3:0] (bottom 4 bits of 20 bit extension byte)
|
||||
int32_t gyro_x = reassemble_20bit(fifo.GYRO_DATA_X1, fifo.GYRO_DATA_X0, fifo.Ext_Accel_X_Gyro_X & 0x0F);
|
||||
int32_t gyro_y = reassemble_20bit(fifo.GYRO_DATA_Y1, fifo.GYRO_DATA_Y0, fifo.Ext_Accel_Y_Gyro_Y & 0x0F);
|
||||
int32_t gyro_z = reassemble_20bit(fifo.GYRO_DATA_Z1, fifo.GYRO_DATA_Z0, fifo.Ext_Accel_Z_Gyro_Z & 0x0F);
|
||||
|
||||
// shift by 1 (least significant bit is always 0)
|
||||
gyro_x = gyro_x / 2;
|
||||
gyro_y = gyro_y / 2;
|
||||
gyro_z = gyro_z / 2;
|
||||
|
||||
// check if any gyro values are going to exceed int16 limits
|
||||
if ((gyro_x >= INT16_MAX || gyro_x <= INT16_MIN)
|
||||
|| (gyro_y >= INT16_MAX || gyro_y <= INT16_MIN)
|
||||
|| (gyro_z >= INT16_MAX || gyro_z <= INT16_MIN)) {
|
||||
|
||||
|
||||
gyro_scale_16bit = true;
|
||||
|
||||
// 20 bit data scaled to 16 bit
|
||||
sensor_imu_fifo.gyro_scale = math::radians(2000.f / 32768.f);
|
||||
|
||||
// rescale any existing data
|
||||
for (int j = 0; j < valid_samples + 1; j++) {
|
||||
sensor_imu_fifo.gyro_x[j] = combine(buffer.f[j].GYRO_DATA_X1, buffer.f[j].GYRO_DATA_X0);
|
||||
sensor_imu_fifo.gyro_y[j] = combine(buffer.f[j].GYRO_DATA_Y1, buffer.f[j].GYRO_DATA_Y0);
|
||||
sensor_imu_fifo.gyro_z[j] = combine(buffer.f[j].GYRO_DATA_Z1, buffer.f[j].GYRO_DATA_Z0);
|
||||
}
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.gyro_x[valid_samples] = gyro_x;
|
||||
sensor_imu_fifo.gyro_y[valid_samples] = gyro_y;
|
||||
sensor_imu_fifo.gyro_z[valid_samples] = gyro_z;
|
||||
}
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.gyro_x[i] = combine(fifo.GYRO_DATA_X1, fifo.GYRO_DATA_X0);
|
||||
sensor_imu_fifo.gyro_y[i] = combine(fifo.GYRO_DATA_Y1, fifo.GYRO_DATA_Y0);
|
||||
sensor_imu_fifo.gyro_z[i] = combine(fifo.GYRO_DATA_Z1, fifo.GYRO_DATA_Z0);
|
||||
}
|
||||
|
||||
if (accel_z >= max_accel || accel_z <= min_accel) {
|
||||
scale_20bit = true;
|
||||
|
||||
// temperature
|
||||
const int16_t TEMP_DATA = combine(fifo.TEMP_DATA1, fifo.TEMP_DATA0);
|
||||
|
||||
// sample invalid if -32768
|
||||
if (TEMP_DATA != -32768) {
|
||||
temperature_sum += TEMP_DATA;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// shift by 2 (2 least significant bits are always 0)
|
||||
accel.x[accel.samples] = accel_x / 4;
|
||||
accel.y[accel.samples] = accel_y / 4;
|
||||
accel.z[accel.samples] = accel_z / 4;
|
||||
accel.samples++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!scale_20bit) {
|
||||
// if highres enabled accel data is always 8192 LSB/g
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 8192.f);
|
||||
// HEADER_TIMESTAMP_FSYNC - 0b10: Packet contains ODR Timestamp
|
||||
if (FIFO_HEADER & Bit3) {
|
||||
const uint16_t timestamp = (fifo.TimeStamp_h << 8) + fifo.TimeStamp_l;
|
||||
|
||||
} else {
|
||||
// 20 bit data scaled to 16 bit (2^4)
|
||||
for (int i = 0; i < samples; i++) {
|
||||
// 20 bit hires mode
|
||||
// Sign extension + Accel [19:12] + Accel [11:4] + Accel [3:2] (20 bit extension byte)
|
||||
// Accel data is 18 bit ()
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_DATA_X1, fifo[i].ACCEL_DATA_X0);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_DATA_Y1, fifo[i].ACCEL_DATA_Y0);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_DATA_Z1, fifo[i].ACCEL_DATA_Z0);
|
||||
if (_timestamp_prev != 0) {
|
||||
// If TMST_RES = 0 (corresponding to timestamp resolution of 1µs), timestamp interval reported in FIFO requires scaling by a factor of 32/30.
|
||||
// Document Number: DS-000347 Revision: 1.5 Page 59 of 110
|
||||
static constexpr float FIFO_DT_SCALE = 32.f / 30.f;
|
||||
|
||||
accel.x[i] = accel_x;
|
||||
accel.y[i] = accel_y;
|
||||
accel.z[i] = accel_z;
|
||||
}
|
||||
float dt = 0;
|
||||
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 2048.f);
|
||||
}
|
||||
if (timestamp > _timestamp_prev) {
|
||||
dt = static_cast<float>(timestamp - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
|
||||
// correct frame for publication
|
||||
for (int i = 0; i < accel.samples; i++) {
|
||||
// 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)
|
||||
accel.x[i] = accel.x[i];
|
||||
accel.y[i] = (accel.y[i] == INT16_MIN) ? INT16_MAX : -accel.y[i];
|
||||
accel.z[i] = (accel.z[i] == INT16_MIN) ? INT16_MAX : -accel.z[i];
|
||||
}
|
||||
} else if (timestamp < _timestamp_prev) {
|
||||
// uint16_t rollover
|
||||
uint32_t timestamp_new = UINT16_MAX + timestamp;
|
||||
dt = static_cast<float>(timestamp_new - _timestamp_prev) * FIFO_DT_SCALE;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
timestamp_interval_sum += dt;
|
||||
timestamp_interval_sum_count++;
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
}
|
||||
// check dt is within +=2% of expected value
|
||||
if ((dt < (FIFO_SAMPLE_DT * 0.98f)) || (dt > (FIFO_SAMPLE_DT * 1.02f))) {
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
}
|
||||
}
|
||||
|
||||
void IIM42652::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = 0;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
_timestamp_prev = timestamp;
|
||||
}
|
||||
|
||||
// 20-bits of gyroscope data
|
||||
bool scale_20bit = false;
|
||||
|
||||
// first pass
|
||||
for (int i = 0; i < samples; i++) {
|
||||
// 20 bit hires mode
|
||||
// Gyro [19:12] + Gyro [11:4] + Gyro [3:0] (bottom 4 bits of 20 bit extension byte)
|
||||
int32_t gyro_x = reassemble_20bit(fifo[i].GYRO_DATA_X1, fifo[i].GYRO_DATA_X0, fifo[i].Ext_Accel_X_Gyro_X & 0x0F);
|
||||
int32_t gyro_y = reassemble_20bit(fifo[i].GYRO_DATA_Y1, fifo[i].GYRO_DATA_Y0, fifo[i].Ext_Accel_Y_Gyro_Y & 0x0F);
|
||||
int32_t gyro_z = reassemble_20bit(fifo[i].GYRO_DATA_Z1, fifo[i].GYRO_DATA_Z0, fifo[i].Ext_Accel_Z_Gyro_Z & 0x0F);
|
||||
|
||||
// check if any values are going to exceed int16 limits
|
||||
static constexpr int16_t max_gyro = INT16_MAX;
|
||||
static constexpr int16_t min_gyro = INT16_MIN;
|
||||
|
||||
if (gyro_x >= max_gyro || gyro_x <= min_gyro) {
|
||||
scale_20bit = true;
|
||||
}
|
||||
|
||||
if (gyro_y >= max_gyro || gyro_y <= min_gyro) {
|
||||
scale_20bit = true;
|
||||
}
|
||||
|
||||
if (gyro_z >= max_gyro || gyro_z <= min_gyro) {
|
||||
scale_20bit = true;
|
||||
}
|
||||
|
||||
gyro.x[gyro.samples] = gyro_x / 2;
|
||||
gyro.y[gyro.samples] = gyro_y / 2;
|
||||
gyro.z[gyro.samples] = gyro_z / 2;
|
||||
gyro.samples++;
|
||||
}
|
||||
|
||||
if (!scale_20bit) {
|
||||
// if highres enabled gyro data is always 131 LSB/dps
|
||||
_px4_gyro.set_scale(math::radians(1.f / 131.f));
|
||||
|
||||
} else {
|
||||
// 20 bit data scaled to 16 bit (2^4)
|
||||
for (int i = 0; i < samples; i++) {
|
||||
gyro.x[i] = combine(fifo[i].GYRO_DATA_X1, fifo[i].GYRO_DATA_X0);
|
||||
gyro.y[i] = combine(fifo[i].GYRO_DATA_Y1, fifo[i].GYRO_DATA_Y0);
|
||||
gyro.z[i] = combine(fifo[i].GYRO_DATA_Z1, fifo[i].GYRO_DATA_Z0);
|
||||
}
|
||||
|
||||
_px4_gyro.set_scale(math::radians(2000.f / 32768.f));
|
||||
}
|
||||
|
||||
// correct frame for publication
|
||||
for (int i = 0; i < gyro.samples; i++) {
|
||||
// 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)
|
||||
gyro.x[i] = gyro.x[i];
|
||||
gyro.y[i] = (gyro.y[i] == INT16_MIN) ? INT16_MAX : -gyro.y[i];
|
||||
gyro.z[i] = (gyro.z[i] == INT16_MIN) ? INT16_MAX : -gyro.z[i];
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (gyro.samples > 0) {
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
}
|
||||
|
||||
bool IIM42652::ProcessTemperature(const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
int16_t temperature[FIFO_MAX_SAMPLES];
|
||||
float temperature_sum{0};
|
||||
|
||||
int valid_samples = 0;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t t = combine(fifo[i].TEMP_DATA1, fifo[i].TEMP_DATA0);
|
||||
|
||||
// sample invalid if -32768
|
||||
if (t != -32768) {
|
||||
temperature_sum += t;
|
||||
temperature[valid_samples] = t;
|
||||
valid_samples++;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_samples > 0) {
|
||||
const float temperature_avg = temperature_sum / valid_samples;
|
||||
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// temperature changing wildly is an indication of a transfer error
|
||||
if (fabsf(temperature[i] - temperature_avg) > 1000) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
|
||||
for (int i = 0; i < sensor_imu_fifo.samples; i++) {
|
||||
// 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)
|
||||
|
||||
// sensor_imu_fifo.accel_x[i]
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(sensor_imu_fifo.accel_y[i]);
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(sensor_imu_fifo.accel_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
// sensor_imu_fifo.gyro_x[i]
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(sensor_imu_fifo.gyro_y[i]);
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(sensor_imu_fifo.gyro_z[i]);
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
const float temperature_avg = temperature_sum / valid_samples;
|
||||
|
||||
// use average temperature reading
|
||||
const float TEMP_degC = (temperature_avg / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
return true;
|
||||
sensor_imu_fifo.temperature = TEMP_degC;
|
||||
|
||||
} else {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timestamp_interval_sum > 0) {
|
||||
const float dt_avg = (timestamp_interval_sum / timestamp_interval_sum_count);
|
||||
|
||||
// check dt is within +=1% of expected value
|
||||
if ((dt_avg < (FIFO_SAMPLE_DT * 0.99f)) || (dt_avg > (FIFO_SAMPLE_DT * 1.01f))) {
|
||||
PX4_ERR("DT error %.6f", (double)dt_avg);
|
||||
perf_count(_fifo_timestamp_error_perf);
|
||||
|
||||
} else {
|
||||
sensor_imu_fifo.dt = dt_avg;
|
||||
}
|
||||
}
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IIM42652::FIFOReset()
|
||||
{
|
||||
perf_count(_fifo_reset_perf);
|
||||
|
||||
// SIGNAL_PATH_RESET: FIFO flush
|
||||
RegisterSetBits(Register::BANK_0::SIGNAL_PATH_RESET, SIGNAL_PATH_RESET_BIT::FIFO_FLUSH);
|
||||
|
||||
// reset while FIFO is disabled
|
||||
_drdy_timestamp_sample.store(0);
|
||||
|
||||
_timestamp_prev = 0;
|
||||
}
|
||||
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_IIM42652_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_IIM42652;
|
||||
|
||||
class IIM42652 : public device::SPI, public I2CSPIDriver<IIM42652>
|
||||
@@ -71,22 +72,10 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f}; // 8000 Hz accel & gyro ODR configured
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float ACCEL_RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
static constexpr float RATE{1e6f / FIFO_SAMPLE_DT};
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::BANK_0::INT_STATUS) | DIR_READ};
|
||||
uint8_t INT_STATUS{0};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (4 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
struct register_bank0_config_t {
|
||||
Register::BANK_0 reg;
|
||||
@@ -135,20 +124,18 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
void ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
bool ProcessTemperature(const FIFO::DATA fifo[], const uint8_t samples);
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
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 _fifo_empty_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO empty")};
|
||||
perf_counter_t _fifo_overflow_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO overflow")};
|
||||
perf_counter_t _fifo_reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO reset")};
|
||||
perf_counter_t _fifo_timestamp_error_perf{perf_alloc(PC_COUNT, MODULE_NAME": FIFO timestamp error")};
|
||||
perf_counter_t _drdy_missed_perf{nullptr};
|
||||
|
||||
hrt_abstime _reset_timestamp{0};
|
||||
@@ -156,6 +143,9 @@ private:
|
||||
hrt_abstime _temperature_update_timestamp{0};
|
||||
int _failure_count{0};
|
||||
|
||||
|
||||
uint16_t _timestamp_prev{0};
|
||||
|
||||
enum REG_BANK_SEL_BIT _last_register_bank {REG_BANK_SEL_BIT::USER_BANK_0};
|
||||
|
||||
px4::atomic<hrt_abstime> _drdy_timestamp_sample{0};
|
||||
@@ -165,29 +155,31 @@ private:
|
||||
RESET,
|
||||
WAIT_FOR_RESET,
|
||||
CONFIGURE,
|
||||
FIFO_RESET,
|
||||
FIFO_READ,
|
||||
} _state{STATE::RESET};
|
||||
|
||||
uint16_t _fifo_empty_interval_us{1250}; // default 1250 us / 800 Hz transfer interval
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / GYRO_RATE))};
|
||||
int32_t _fifo_gyro_samples{static_cast<int32_t>(_fifo_empty_interval_us / (1000000 / RATE))};
|
||||
|
||||
uint8_t _checked_register_bank0{0};
|
||||
static constexpr uint8_t size_register_bank0_cfg{13};
|
||||
static constexpr uint8_t size_register_bank0_cfg{14};
|
||||
register_bank0_config_t _register_bank0_cfg[size_register_bank0_cfg] {
|
||||
// Register | Set bits, Clear bits
|
||||
{ Register::BANK_0::INT_CONFIG, INT_CONFIG_BIT::INT1_MODE | INT_CONFIG_BIT::INT1_DRIVE_CIRCUIT, INT_CONFIG_BIT::INT1_POLARITY },
|
||||
{ Register::BANK_0::FIFO_CONFIG, FIFO_CONFIG_BIT::FIFO_MODE_STOP_ON_FULL, 0 },
|
||||
{ Register::BANK_0::PWR_MGMT0, PWR_MGMT0_BIT::GYRO_MODE_LOW_NOISE | PWR_MGMT0_BIT::ACCEL_MODE_LOW_NOISE, 0 },
|
||||
{ Register::BANK_0::GYRO_CONFIG0, GYRO_CONFIG0_BIT::GYRO_FS_SEL_2000_DPS | GYRO_CONFIG0_BIT::GYRO_ODR_8KHZ_SET, GYRO_CONFIG0_BIT::GYRO_ODR_8KHZ_CLEAR },
|
||||
{ Register::BANK_0::ACCEL_CONFIG0, ACCEL_CONFIG0_BIT::ACCEL_FS_SEL_16G | ACCEL_CONFIG0_BIT::ACCEL_ODR_8KHZ_SET, ACCEL_CONFIG0_BIT::ACCEL_ODR_8KHZ_CLEAR },
|
||||
{ Register::BANK_0::GYRO_CONFIG1, 0, GYRO_CONFIG1_BIT::GYRO_UI_FILT_ORD },
|
||||
{ Register::BANK_0::GYRO_CONFIG0, GYRO_CONFIG0_BIT::GYRO_ODR_8KHZ_SET, GYRO_CONFIG0_BIT::GYRO_FS_SEL_2000_DPS_CLEAR | GYRO_CONFIG0_BIT::GYRO_ODR_8KHZ_CLEAR },
|
||||
{ Register::BANK_0::ACCEL_CONFIG0, ACCEL_CONFIG0_BIT::ACCEL_ODR_8KHZ_SET, ACCEL_CONFIG0_BIT::ACCEL_FS_SEL_16G_CLEAR | ACCEL_CONFIG0_BIT::ACCEL_ODR_8KHZ_CLEAR },
|
||||
{ Register::BANK_0::GYRO_CONFIG1, 0, GYRO_CONFIG1_BIT::GYRO_UI_FILT_ORD_1ST_CLEAR },
|
||||
{ Register::BANK_0::GYRO_ACCEL_CONFIG0, 0, GYRO_ACCEL_CONFIG0_BIT::ACCEL_UI_FILT_BW | GYRO_ACCEL_CONFIG0_BIT::GYRO_UI_FILT_BW },
|
||||
{ Register::BANK_0::ACCEL_CONFIG1, 0, ACCEL_CONFIG1_BIT::ACCEL_UI_FILT_ORD },
|
||||
{ Register::BANK_0::FIFO_CONFIG1, FIFO_CONFIG1_BIT::FIFO_WM_GT_TH | FIFO_CONFIG1_BIT::FIFO_HIRES_EN | FIFO_CONFIG1_BIT::FIFO_TEMP_EN | FIFO_CONFIG1_BIT::FIFO_GYRO_EN | FIFO_CONFIG1_BIT::FIFO_ACCEL_EN, 0 },
|
||||
{ Register::BANK_0::ACCEL_CONFIG1, 0, ACCEL_CONFIG1_BIT::ACCEL_UI_FILT_ORD_1ST_CLEAR },
|
||||
{ Register::BANK_0::FIFO_CONFIG1, FIFO_CONFIG1_BIT::FIFO_RESUME_PARTIAL_RD | FIFO_CONFIG1_BIT::FIFO_HIRES_EN | FIFO_CONFIG1_BIT::FIFO_TEMP_EN | FIFO_CONFIG1_BIT::FIFO_GYRO_EN | FIFO_CONFIG1_BIT::FIFO_ACCEL_EN, 0 },
|
||||
{ Register::BANK_0::FIFO_CONFIG2, 0, 0 }, // FIFO_WM[7:0] set at runtime
|
||||
{ Register::BANK_0::FIFO_CONFIG3, 0, 0 }, // FIFO_WM[11:8] set at runtime
|
||||
{ Register::BANK_0::INT_CONFIG0, INT_CONFIG0_BIT::CLEAR_ON_FIFO_READ, 0 },
|
||||
{ Register::BANK_0::INT_SOURCE0, INT_SOURCE0_BIT::FIFO_THS_INT1_EN, 0 },
|
||||
{ Register::BANK_0::INT_CONFIG0, INT_CONFIG0_BIT::FIFO_THS_INT_CLEAR, 0 },
|
||||
{ Register::BANK_0::INT_CONFIG1, INT_CONFIG1_BIT::INT_TPULSE_DURATION | INT_CONFIG1_BIT::INT_TDEASSERT_DISABLE, INT_CONFIG1_BIT::INT_ASYNC_RESET },
|
||||
{ Register::BANK_0::INT_SOURCE0, INT_SOURCE0_BIT::FIFO_THS_INT1_EN, INT_SOURCE0_BIT::RESET_DONE_INT1_EN },
|
||||
};
|
||||
|
||||
uint8_t _checked_register_bank1{0};
|
||||
|
||||
@@ -82,8 +82,7 @@ enum class BANK_0 : uint8_t {
|
||||
FIFO_DATA = 0x30,
|
||||
|
||||
SIGNAL_PATH_RESET = 0x4B,
|
||||
INTF_CONFIG0 = 0x4C,
|
||||
INTF_CONFIG1 = 0x4D,
|
||||
|
||||
PWR_MGMT0 = 0x4E,
|
||||
GYRO_CONFIG0 = 0x4F,
|
||||
ACCEL_CONFIG0 = 0x50,
|
||||
@@ -96,7 +95,7 @@ enum class BANK_0 : uint8_t {
|
||||
FIFO_CONFIG3 = 0x61,
|
||||
|
||||
INT_CONFIG0 = 0x63,
|
||||
|
||||
INT_CONFIG1 = 0x64,
|
||||
INT_SOURCE0 = 0x65,
|
||||
|
||||
SELF_TEST_CONFIG = 0x70,
|
||||
@@ -121,7 +120,7 @@ enum class BANK_2 : uint8_t {
|
||||
|
||||
// DEVICE_CONFIG
|
||||
enum DEVICE_CONFIG_BIT : uint8_t {
|
||||
SOFT_RESET_CONFIG = Bit0, //
|
||||
SOFT_RESET_CONFIG = Bit0,
|
||||
};
|
||||
|
||||
// INT_CONFIG
|
||||
@@ -140,15 +139,14 @@ enum FIFO_CONFIG_BIT : uint8_t {
|
||||
// INT_STATUS
|
||||
enum INT_STATUS_BIT : uint8_t {
|
||||
RESET_DONE_INT = Bit4,
|
||||
DATA_RDY_INT = Bit3,
|
||||
|
||||
FIFO_THS_INT = Bit2,
|
||||
FIFO_FULL_INT = Bit1,
|
||||
};
|
||||
|
||||
// SIGNAL_PATH_RESET
|
||||
enum SIGNAL_PATH_RESET_BIT : uint8_t {
|
||||
ABORT_AND_RESET = Bit3,
|
||||
FIFO_FLUSH = Bit1,
|
||||
FIFO_FLUSH = Bit1,
|
||||
};
|
||||
|
||||
// PWR_MGMT0
|
||||
@@ -160,55 +158,42 @@ enum PWR_MGMT0_BIT : uint8_t {
|
||||
// GYRO_CONFIG0
|
||||
enum GYRO_CONFIG0_BIT : uint8_t {
|
||||
// 7:5 GYRO_FS_SEL
|
||||
GYRO_FS_SEL_2000_DPS = 0, // 0b000 = ±2000dps (default)
|
||||
GYRO_FS_SEL_1000_DPS = Bit5,
|
||||
GYRO_FS_SEL_500_DPS = Bit6,
|
||||
GYRO_FS_SEL_250_DPS = Bit6 | Bit5,
|
||||
GYRO_FS_SEL_125_DPS = Bit7,
|
||||
|
||||
// 0b000: ±2000dps (default)
|
||||
GYRO_FS_SEL_2000_DPS_CLEAR = Bit7 | Bit6 | Bit5,
|
||||
|
||||
// 3:0 GYRO_ODR
|
||||
// 0001: 32kHz
|
||||
GYRO_ODR_32KHZ_SET = Bit0,
|
||||
GYRO_ODR_32KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0010: 16kHz
|
||||
GYRO_ODR_16KHZ_SET = Bit1,
|
||||
GYRO_ODR_16KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0011: 8kHz
|
||||
GYRO_ODR_8KHZ_SET = Bit1 | Bit0,
|
||||
GYRO_ODR_8KHZ_CLEAR = Bit3 | Bit2,
|
||||
// 0110: 1kHz (default)
|
||||
GYRO_ODR_1KHZ_SET = Bit2 | Bit1,
|
||||
GYRO_ODR_1KHZ_CLEAR = Bit3 | Bit0,
|
||||
// 0b0001: 32kHz (maximum)
|
||||
GYRO_ODR_32KHZ_SET = Bit0,
|
||||
GYRO_ODR_32KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0b0011: 8kHz
|
||||
GYRO_ODR_8KHZ_SET = Bit1 | Bit0,
|
||||
GYRO_ODR_8KHZ_CLEAR = Bit3 | Bit2,
|
||||
// 0b0110: 1kHz (default)
|
||||
GYRO_ODR_1KHZ_SET = Bit2 | Bit1,
|
||||
GYRO_ODR_1KHZ_CLEAR = Bit3 | Bit0,
|
||||
};
|
||||
|
||||
// ACCEL_CONFIG0
|
||||
enum ACCEL_CONFIG0_BIT : uint8_t {
|
||||
// 7:5 ACCEL_FS_SEL
|
||||
ACCEL_FS_SEL_16G = 0, // 000: ±16g (default)
|
||||
ACCEL_FS_SEL_8G = Bit5,
|
||||
ACCEL_FS_SEL_4G = Bit6,
|
||||
ACCEL_FS_SEL_2G = Bit6 | Bit5,
|
||||
|
||||
// 0b000: ±16g (default)
|
||||
ACCEL_FS_SEL_16G_CLEAR = Bit7 | Bit6 | Bit5,
|
||||
|
||||
// 3:0 ACCEL_ODR
|
||||
// 0001: 32kHz
|
||||
ACCEL_ODR_32KHZ_SET = Bit0,
|
||||
ACCEL_ODR_32KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0010: 16kHz
|
||||
ACCEL_ODR_16KHZ_SET = Bit1,
|
||||
ACCEL_ODR_16KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0011: 8kHz
|
||||
ACCEL_ODR_8KHZ_SET = Bit1 | Bit0,
|
||||
ACCEL_ODR_8KHZ_CLEAR = Bit3 | Bit2,
|
||||
// 0110: 1kHz (default)
|
||||
ACCEL_ODR_1KHZ_SET = Bit2 | Bit1,
|
||||
ACCEL_ODR_1KHZ_CLEAR = Bit3 | Bit0,
|
||||
// 0b0001: 32kHz (maximum)
|
||||
ACCEL_ODR_32KHZ_SET = Bit0,
|
||||
ACCEL_ODR_32KHZ_CLEAR = Bit3 | Bit2 | Bit0,
|
||||
// 0b0011: 8kHz
|
||||
ACCEL_ODR_8KHZ_SET = Bit1 | Bit0,
|
||||
ACCEL_ODR_8KHZ_CLEAR = Bit3 | Bit2,
|
||||
// 0b0110: 1kHz (default)
|
||||
ACCEL_ODR_1KHZ_SET = Bit2 | Bit1,
|
||||
ACCEL_ODR_1KHZ_CLEAR = Bit3 | Bit0,
|
||||
};
|
||||
|
||||
// GYRO_CONFIG1
|
||||
enum GYRO_CONFIG1_BIT : uint8_t {
|
||||
GYRO_UI_FILT_ORD = Bit3 | Bit2, // 00: 1st Order
|
||||
GYRO_UI_FILT_ORD_1ST_CLEAR = Bit3 | Bit2, // 00: 1st Order UI filter
|
||||
};
|
||||
|
||||
// GYRO_ACCEL_CONFIG0
|
||||
@@ -222,14 +207,15 @@ enum GYRO_ACCEL_CONFIG0_BIT : uint8_t {
|
||||
|
||||
// ACCEL_CONFIG1
|
||||
enum ACCEL_CONFIG1_BIT : uint8_t {
|
||||
ACCEL_UI_FILT_ORD = Bit4 | Bit3, // 00: 1st Order
|
||||
ACCEL_UI_FILT_ORD_1ST_CLEAR = Bit4 | Bit3, // 00: 1st Order UI filter
|
||||
};
|
||||
|
||||
// FIFO_CONFIG1
|
||||
enum FIFO_CONFIG1_BIT : uint8_t {
|
||||
FIFO_RESUME_PARTIAL_RD = Bit6,
|
||||
FIFO_WM_GT_TH = Bit5,
|
||||
|
||||
FIFO_HIRES_EN = Bit4,
|
||||
|
||||
FIFO_TEMP_EN = Bit2,
|
||||
FIFO_GYRO_EN = Bit1,
|
||||
FIFO_ACCEL_EN = Bit0,
|
||||
@@ -238,18 +224,21 @@ enum FIFO_CONFIG1_BIT : uint8_t {
|
||||
// INT_CONFIG0
|
||||
enum INT_CONFIG0_BIT : uint8_t {
|
||||
// 3:2 FIFO_THS_INT_CLEAR
|
||||
CLEAR_ON_FIFO_READ = Bit3,
|
||||
FIFO_THS_INT_CLEAR = Bit3, // 10: Clear on FIFO data 1Byte Read
|
||||
};
|
||||
|
||||
// INT_CONFIG1
|
||||
enum INT_CONFIG1_BIT : uint8_t {
|
||||
INT_TPULSE_DURATION = Bit6, // 1: Interrupt pulse duration is 8 µs. Required if ODR ≥ 4kHz, optional for ODR < 4kHz.
|
||||
INT_TDEASSERT_DISABLE = Bit5, // 1: Disables de-assert duration. Required if ODR ≥ 4kHz, optional for ODR < 4kHz.
|
||||
INT_ASYNC_RESET = Bit4, // User should change setting to 0 from default setting of 1, for proper INT1 and INT2 pin operation
|
||||
};
|
||||
|
||||
// INT_SOURCE0
|
||||
enum INT_SOURCE0_BIT : uint8_t {
|
||||
UI_FSYNC_INT1_EN = Bit6,
|
||||
PLL_RDY_INT1_EN = Bit5,
|
||||
RESET_DONE_INT1_EN = Bit4,
|
||||
UI_DRDY_INT1_EN = Bit3,
|
||||
RESET_DONE_INT1_EN = Bit4, // 1: Reset done interrupt routed to INT1 (enabled by default)
|
||||
|
||||
FIFO_THS_INT1_EN = Bit2, // FIFO threshold interrupt routed to INT1
|
||||
FIFO_FULL_INT1_EN = Bit1,
|
||||
UI_AGC_RDY_INT1_EN = Bit0,
|
||||
};
|
||||
|
||||
// REG_BANK_SEL
|
||||
@@ -277,6 +266,7 @@ enum ACCEL_CONFIG_STATIC2_BIT : uint8_t {
|
||||
ACCEL_AAF_DIS = Bit0,
|
||||
};
|
||||
|
||||
|
||||
namespace FIFO
|
||||
{
|
||||
static constexpr size_t SIZE = 2048;
|
||||
|
||||
@@ -72,13 +72,11 @@ extern "C" int iim42652_main(int argc, char *argv[])
|
||||
|
||||
if (!strcmp(verb, "start")) {
|
||||
return ThisDriver::module_start(cli, iterator);
|
||||
}
|
||||
|
||||
if (!strcmp(verb, "stop")) {
|
||||
} else if (!strcmp(verb, "stop")) {
|
||||
return ThisDriver::module_stop(iterator);
|
||||
}
|
||||
|
||||
if (!strcmp(verb, "status")) {
|
||||
} else if (!strcmp(verb, "status")) {
|
||||
return ThisDriver::module_status(iterator);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,5 @@ px4_add_module(
|
||||
mpu6000_main.cpp
|
||||
InvenSense_MPU6000_registers.hpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -62,6 +62,8 @@ static constexpr uint8_t WHOAMI = 0x68;
|
||||
|
||||
static constexpr float TEMPERATURE_SENSITIVITY = 340.f; // LSB/C
|
||||
static constexpr float TEMPERATURE_OFFSET = 36.53f; // C
|
||||
static constexpr float TEMPERATURE_SENSOR_MIN = -40.f; // °C
|
||||
static constexpr float TEMPERATURE_SENSOR_MAX = 85.f; // °C
|
||||
|
||||
enum class Register : uint8_t {
|
||||
CONFIG = 0x1A,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "MPU6000.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ MPU6000::MPU6000(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
MPU6000::~MPU6000()
|
||||
@@ -107,14 +111,19 @@ void MPU6000::print_status()
|
||||
|
||||
int MPU6000::probe()
|
||||
{
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
|
||||
if (whoami != WHOAMI) {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
return PX4_ERROR;
|
||||
if (whoami == WHOAMI) {
|
||||
return PX4_OK;
|
||||
|
||||
} else {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
}
|
||||
}
|
||||
|
||||
return PX4_OK;
|
||||
return PX4_ERROR;
|
||||
}
|
||||
|
||||
void MPU6000::RunImpl()
|
||||
@@ -156,8 +165,8 @@ void MPU6000::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +174,8 @@ void MPU6000::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
_temperature = ReadTemperature();
|
||||
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
@@ -203,7 +214,7 @@ void MPU6000::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
|
||||
} else {
|
||||
@@ -278,7 +289,7 @@ void MPU6000::RunImpl()
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature = ReadTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
@@ -288,65 +299,10 @@ void MPU6000::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void MPU6000::ConfigureAccel()
|
||||
{
|
||||
const uint8_t AFS_SEL = RegisterRead(Register::ACCEL_CONFIG) & (Bit4 | Bit3); // [4:3] AFS_SEL[1:0]
|
||||
|
||||
switch (AFS_SEL) {
|
||||
case AFS_SEL_2G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 16384.f);
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
case AFS_SEL_4G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 8192.f);
|
||||
_px4_accel.set_range(4.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
case AFS_SEL_8G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 4096.f);
|
||||
_px4_accel.set_range(8.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
case AFS_SEL_16G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 2048.f);
|
||||
_px4_accel.set_range(16.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MPU6000::ConfigureGyro()
|
||||
{
|
||||
const uint8_t GYRO_FS_SEL = RegisterRead(Register::GYRO_CONFIG) & (Bit4 | Bit3); // [4:3] FS_SEL[1:0]
|
||||
|
||||
float range_dps = 0.f;
|
||||
|
||||
switch (GYRO_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 MPU6000::ConfigureSampleRate(int sample_rate)
|
||||
{
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT * 4; // limit to 2 kHz (500 us interval)
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
@@ -371,9 +327,6 @@ bool MPU6000::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -400,7 +353,7 @@ bool MPU6000::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool MPU6000::DataReadyInterruptDisable()
|
||||
@@ -409,7 +362,7 @@ bool MPU6000::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
bool MPU6000::RegisterCheck(const register_config_t ®_cfg)
|
||||
@@ -462,23 +415,33 @@ void MPU6000::RegisterSetAndClearBits(Register reg, uint8_t setbits, uint8_t cle
|
||||
|
||||
uint16_t MPU6000::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ;
|
||||
set_frequency(SPI_SPEED_SENSOR);
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool MPU6000::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 1, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_R_W) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 1 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
set_frequency(SPI_SPEED_SENSOR);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
@@ -486,9 +449,43 @@ bool MPU6000::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t valid_samples = samples;
|
||||
|
||||
ProcessGyro(timestamp_sample, buffer.f, samples);
|
||||
return ProcessAccel(timestamp_sample, buffer.f, samples);
|
||||
if (valid_samples > 0) {
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
sensor_imu_fifo.accel_scale = ACCEL_SCALE;
|
||||
sensor_imu_fifo.gyro_scale = GYRO_SCALE;
|
||||
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// 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)
|
||||
sensor_imu_fifo.accel_x[i] = combine(buffer.f[i].ACCEL_XOUT_H, buffer.f[i].ACCEL_XOUT_L);
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(combine(buffer.f[i].ACCEL_YOUT_H, buffer.f[i].ACCEL_YOUT_L));
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(combine(buffer.f[i].ACCEL_ZOUT_H, buffer.f[i].ACCEL_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(buffer.f[i].GYRO_XOUT_H, buffer.f[i].GYRO_XOUT_L);
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(combine(buffer.f[i].GYRO_YOUT_H, buffer.f[i].GYRO_YOUT_L));
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(combine(buffer.f[i].GYRO_ZOUT_H, buffer.f[i].GYRO_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
sensor_imu_fifo.temperature = (hrt_elapsed_time(&_temperature_update_timestamp) < 5_s) ? _temperature : NAN;
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf)
|
||||
+ perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MPU6000::FIFOReset()
|
||||
@@ -514,105 +511,32 @@ void MPU6000::FIFOReset()
|
||||
}
|
||||
}
|
||||
|
||||
static bool fifo_accel_equal(const FIFO::DATA &f0, const FIFO::DATA &f1)
|
||||
float MPU6000::ReadTemperature()
|
||||
{
|
||||
return (memcmp(&f0.ACCEL_XOUT_H, &f1.ACCEL_XOUT_H, 6) == 0);
|
||||
}
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ};
|
||||
uint8_t TEMP_OUT_H{0};
|
||||
uint8_t TEMP_OUT_L{0};
|
||||
} buffer{};
|
||||
|
||||
bool MPU6000::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
|
||||
bool bad_data = false;
|
||||
|
||||
// FIFO contains 8 duplicated accel samples per gyro sample
|
||||
for (int i = 0; i < samples; i++) {
|
||||
_fifo_accel_samples_count++;
|
||||
|
||||
// only process new FIFO samples (1 every 8 samples expected)
|
||||
const bool new_sample = !fifo_accel_equal(fifo[i], _fifo_sample_last_new_accel);
|
||||
|
||||
// process every 8th sample
|
||||
if (_fifo_accel_samples_count == SAMPLES_PER_TRANSFER) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_XOUT_H, fifo[i].ACCEL_XOUT_L);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_YOUT_H, fifo[i].ACCEL_YOUT_L);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_ZOUT_H, fifo[i].ACCEL_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
|
||||
} else if (new_sample && (_fifo_accel_samples_count > 1)) {
|
||||
// a new unique sample after fewer than 8 samples is an error
|
||||
bad_data = true;
|
||||
perf_count(_bad_transfer_perf);
|
||||
}
|
||||
|
||||
// reset previous unique sample and counter
|
||||
if (new_sample || (_fifo_accel_samples_count == SAMPLES_PER_TRANSFER)) {
|
||||
_fifo_accel_samples_count = 0;
|
||||
_fifo_sample_last_new_accel = fifo[i];
|
||||
}
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
|
||||
return !bad_data;
|
||||
}
|
||||
|
||||
void MPU6000::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_XOUT_H, fifo[i].GYRO_XOUT_L);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_YOUT_H, fifo[i].GYRO_YOUT_L);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_ZOUT_H, fifo[i].GYRO_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void MPU6000::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
uint8_t temperature_buf[3] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ;
|
||||
set_frequency(SPI_SPEED_SENSOR);
|
||||
|
||||
if (transfer(temperature_buf, temperature_buf, sizeof(temperature_buf)) != PX4_OK) {
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
return NAN;;
|
||||
}
|
||||
|
||||
const int16_t TEMP_OUT = combine(temperature_buf[1], temperature_buf[2]);
|
||||
const int16_t TEMP_OUT = combine(buffer.TEMP_OUT_H, buffer.TEMP_OUT_L);
|
||||
const float TEMP_degC = (TEMP_OUT / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
if (PX4_ISFINITE(TEMP_degC)
|
||||
&& (TEMP_degC >= TEMPERATURE_SENSOR_MIN)
|
||||
&& (TEMP_degC <= TEMPERATURE_SENSOR_MAX)) {
|
||||
|
||||
return TEMP_degC;
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_MPU6000_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_MPU6000;
|
||||
|
||||
class MPU6000 : public device::SPI, public I2CSPIDriver<MPU6000>
|
||||
@@ -71,20 +72,13 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f};
|
||||
static constexpr int32_t SAMPLES_PER_TRANSFER{8}; // ensure at least 1 new accel sample per transfer
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT}; // 8000 Hz gyro
|
||||
static constexpr float ACCEL_RATE{GYRO_RATE / SAMPLES_PER_TRANSFER}; // 1000 Hz accel
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0])), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_R_W) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (1 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr float ACCEL_SCALE{CONSTANTS_ONE_G / 2048.f}; // AFS_SEL_16G:
|
||||
static constexpr float GYRO_SCALE{math::radians(2000.f / 32768.f)}; // FS_SEL_2000_DPS:
|
||||
|
||||
struct register_config_t {
|
||||
Register reg;
|
||||
@@ -97,8 +91,6 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
|
||||
static int DataReadyInterruptCallback(int irq, void *context, void *arg);
|
||||
@@ -116,14 +108,15 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
bool ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
float ReadTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
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")};
|
||||
@@ -137,9 +130,6 @@ private:
|
||||
hrt_abstime _temperature_update_timestamp{0};
|
||||
int _failure_count{0};
|
||||
|
||||
FIFO::DATA _fifo_sample_last_new_accel{};
|
||||
uint32_t _fifo_accel_samples_count{0};
|
||||
|
||||
px4::atomic<hrt_abstime> _drdy_timestamp_sample{0};
|
||||
int32_t _drdy_count{0};
|
||||
bool _data_ready_interrupt_enabled{false};
|
||||
|
||||
@@ -40,7 +40,5 @@ px4_add_module(
|
||||
MPU6500.hpp
|
||||
mpu6500_main.cpp
|
||||
DEPENDS
|
||||
drivers_accelerometer
|
||||
drivers_gyroscope
|
||||
px4_work_queue
|
||||
)
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace InvenSense_MPU6500
|
||||
{
|
||||
// TODO: move to a central header
|
||||
static constexpr uint8_t Bit0 = (1 << 0);
|
||||
static constexpr uint8_t Bit1 = (1 << 1);
|
||||
@@ -52,8 +54,6 @@ static constexpr uint8_t Bit5 = (1 << 5);
|
||||
static constexpr uint8_t Bit6 = (1 << 6);
|
||||
static constexpr uint8_t Bit7 = (1 << 7);
|
||||
|
||||
namespace InvenSense_MPU6500
|
||||
{
|
||||
static constexpr uint32_t SPI_SPEED = 1 * 1000 * 1000;
|
||||
static constexpr uint32_t SPI_SPEED_SENSOR = 10 * 1000 * 1000; // 20MHz for reading sensor and interrupt registers
|
||||
static constexpr uint8_t DIR_READ = 0x80;
|
||||
@@ -62,6 +62,8 @@ static constexpr uint8_t WHOAMI = 0x70;
|
||||
|
||||
static constexpr float TEMPERATURE_SENSITIVITY = 333.87f; // LSB/C
|
||||
static constexpr float TEMPERATURE_OFFSET = 21.f; // C
|
||||
static constexpr float TEMPERATURE_SENSOR_MIN = -40.f; // °C
|
||||
static constexpr float TEMPERATURE_SENSOR_MAX = 85.f; // °C
|
||||
|
||||
enum class Register : uint8_t {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "MPU6500.hpp"
|
||||
|
||||
#include <lib/parameters/param.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
|
||||
@@ -44,14 +46,16 @@ MPU6500::MPU6500(const I2CSPIDriverConfig &config) :
|
||||
SPI(config),
|
||||
I2CSPIDriver(config),
|
||||
_drdy_gpio(config.drdy_gpio),
|
||||
_px4_accel(get_device_id(), config.rotation),
|
||||
_px4_gyro(get_device_id(), config.rotation)
|
||||
_rotation(config.rotation)
|
||||
{
|
||||
if (config.drdy_gpio != 0) {
|
||||
if (_drdy_gpio != 0) {
|
||||
_drdy_missed_perf = perf_alloc(PC_COUNT, MODULE_NAME": DRDY missed");
|
||||
}
|
||||
|
||||
ConfigureSampleRate(_px4_gyro.get_max_rate_hz());
|
||||
int32_t imu_gyro_rate_max = 400;
|
||||
param_get(param_find("IMU_GYRO_RATEMAX"), &imu_gyro_rate_max);
|
||||
|
||||
ConfigureSampleRate(imu_gyro_rate_max);
|
||||
}
|
||||
|
||||
MPU6500::~MPU6500()
|
||||
@@ -131,14 +135,19 @@ bool MPU6500::StoreCheckedRegisterValue(Register reg)
|
||||
|
||||
int MPU6500::probe()
|
||||
{
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
// 3 retries
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
|
||||
|
||||
if (whoami != WHOAMI) {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
return PX4_ERROR;
|
||||
if (whoami == WHOAMI) {
|
||||
return PX4_OK;
|
||||
|
||||
} else {
|
||||
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
|
||||
}
|
||||
}
|
||||
|
||||
return PX4_OK;
|
||||
return PX4_ERROR;
|
||||
}
|
||||
|
||||
void MPU6500::RunImpl()
|
||||
@@ -188,8 +197,8 @@ void MPU6500::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +206,8 @@ void MPU6500::RunImpl()
|
||||
|
||||
case STATE::CONFIGURE:
|
||||
if (Configure()) {
|
||||
_temperature = ReadTemperature();
|
||||
|
||||
// if configure succeeded then start reading from FIFO
|
||||
_state = STATE::FIFO_READ;
|
||||
|
||||
@@ -235,7 +246,7 @@ void MPU6500::RunImpl()
|
||||
// scheduled from interrupt if _drdy_timestamp_sample was set as expected
|
||||
const hrt_abstime drdy_timestamp_sample = _drdy_timestamp_sample.fetch_and(0);
|
||||
|
||||
if ((now - drdy_timestamp_sample) < _fifo_empty_interval_us) {
|
||||
if (now < drdy_timestamp_sample + _fifo_empty_interval_us) {
|
||||
timestamp_sample = drdy_timestamp_sample;
|
||||
|
||||
} else {
|
||||
@@ -272,7 +283,7 @@ void MPU6500::RunImpl()
|
||||
FIFOReset();
|
||||
perf_count(_fifo_overflow_perf);
|
||||
|
||||
} else if (samples >= SAMPLES_PER_TRANSFER) {
|
||||
} else if (samples >= 1) {
|
||||
if (FIFORead(timestamp_sample, samples)) {
|
||||
success = true;
|
||||
|
||||
@@ -288,6 +299,7 @@ void MPU6500::RunImpl()
|
||||
|
||||
// full reset if things are failing consistently
|
||||
if (_failure_count > 10) {
|
||||
PX4_DEBUG("Full reset because things are failing consistently");
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
@@ -302,13 +314,14 @@ void MPU6500::RunImpl()
|
||||
} else {
|
||||
// register check failed, force reset
|
||||
perf_count(_bad_register_perf);
|
||||
PX4_DEBUG("Force reset because register 0x%02hhX check failed ", (uint8_t)_register_cfg[_checked_register].reg);
|
||||
Reset();
|
||||
}
|
||||
|
||||
} else {
|
||||
// periodically update temperature (~1 Hz)
|
||||
if (hrt_elapsed_time(&_temperature_update_timestamp) >= 1_s) {
|
||||
UpdateTemperature();
|
||||
_temperature = ReadTemperature();
|
||||
_temperature_update_timestamp = now;
|
||||
}
|
||||
}
|
||||
@@ -318,65 +331,10 @@ void MPU6500::RunImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void MPU6500::ConfigureAccel()
|
||||
{
|
||||
const uint8_t ACCEL_FS_SEL = RegisterRead(Register::ACCEL_CONFIG) & (Bit4 | Bit3); // [4:3] ACCEL_FS_SEL[1:0]
|
||||
|
||||
switch (ACCEL_FS_SEL) {
|
||||
case ACCEL_FS_SEL_2G:
|
||||
_px4_accel.set_scale(CONSTANTS_ONE_G / 16384.f);
|
||||
_px4_accel.set_range(2.f * CONSTANTS_ONE_G);
|
||||
break;
|
||||
|
||||
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 MPU6500::ConfigureGyro()
|
||||
{
|
||||
const uint8_t GYRO_FS_SEL = RegisterRead(Register::GYRO_CONFIG) & (Bit4 | Bit3); // [4:3] GYRO_FS_SEL[1:0]
|
||||
|
||||
float range_dps = 0.f;
|
||||
|
||||
switch (GYRO_FS_SEL) {
|
||||
case GYRO_FS_SEL_250_DPS:
|
||||
range_dps = 250.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_500_DPS:
|
||||
range_dps = 500.f;
|
||||
break;
|
||||
|
||||
case GYRO_FS_SEL_1000_DPS:
|
||||
range_dps = 1000.f;
|
||||
break;
|
||||
|
||||
case GYRO_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 MPU6500::ConfigureSampleRate(int sample_rate)
|
||||
{
|
||||
// round down to nearest FIFO sample dt * SAMPLES_PER_TRANSFER
|
||||
const float min_interval = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
// round down to nearest FIFO sample dt
|
||||
const float min_interval = FIFO_SAMPLE_DT;
|
||||
_fifo_empty_interval_us = math::max(roundf((1e6f / (float)sample_rate) / min_interval) * min_interval, min_interval);
|
||||
|
||||
_fifo_gyro_samples = roundf(math::min((float)_fifo_empty_interval_us / (1e6f / GYRO_RATE), (float)FIFO_MAX_SAMPLES));
|
||||
@@ -401,9 +359,6 @@ bool MPU6500::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAccel();
|
||||
ConfigureGyro();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -430,7 +385,7 @@ bool MPU6500::DataReadyInterruptConfigure()
|
||||
}
|
||||
|
||||
// Setup data ready on falling edge
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, true, true, &DataReadyInterruptCallback, this) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, true, false, &DataReadyInterruptCallback, this) == 0);
|
||||
}
|
||||
|
||||
bool MPU6500::DataReadyInterruptDisable()
|
||||
@@ -439,7 +394,7 @@ bool MPU6500::DataReadyInterruptDisable()
|
||||
return false;
|
||||
}
|
||||
|
||||
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
|
||||
return (px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0);
|
||||
}
|
||||
|
||||
bool MPU6500::RegisterCheck(const register_config_t ®_cfg)
|
||||
@@ -490,23 +445,33 @@ void MPU6500::RegisterSetAndClearBits(Register reg, uint8_t setbits, uint8_t cle
|
||||
|
||||
uint16_t MPU6500::FIFOReadCount()
|
||||
{
|
||||
// read FIFO count
|
||||
uint8_t fifo_count_buf[3] {};
|
||||
fifo_count_buf[0] = static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ;
|
||||
set_frequency(SPI_SPEED_SENSOR);
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_COUNTH) | DIR_READ};
|
||||
uint8_t FIFO_COUNTH{0};
|
||||
uint8_t FIFO_COUNTL{0};
|
||||
} buffer{};
|
||||
|
||||
if (transfer(fifo_count_buf, fifo_count_buf, sizeof(fifo_count_buf)) != PX4_OK) {
|
||||
// read FIFO count
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return combine(fifo_count_buf[1], fifo_count_buf[2]);
|
||||
return (buffer.FIFO_COUNTH << 8) + buffer.FIFO_COUNTL;
|
||||
}
|
||||
|
||||
bool MPU6500::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
{
|
||||
FIFOTransferBuffer buffer{};
|
||||
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 1, FIFO::SIZE);
|
||||
// FIFO transfer buffer
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_R_W) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
} buffer{};
|
||||
|
||||
// cmd + samples (FIFO::DATA)
|
||||
const size_t transfer_size = 1 + math::min(samples * sizeof(FIFO::DATA), FIFO::SIZE);
|
||||
|
||||
set_frequency(SPI_SPEED_SENSOR);
|
||||
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
|
||||
@@ -514,9 +479,43 @@ bool MPU6500::FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples)
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t valid_samples = samples;
|
||||
|
||||
ProcessGyro(timestamp_sample, buffer.f, samples);
|
||||
return ProcessAccel(timestamp_sample, buffer.f, samples);
|
||||
if (valid_samples > 0) {
|
||||
sensor_imu_fifo_s sensor_imu_fifo{};
|
||||
sensor_imu_fifo.timestamp_sample = timestamp_sample;
|
||||
sensor_imu_fifo.device_id = get_device_id();
|
||||
sensor_imu_fifo.dt = FIFO_SAMPLE_DT;
|
||||
sensor_imu_fifo.samples = valid_samples;
|
||||
sensor_imu_fifo.accel_scale = ACCEL_SCALE;
|
||||
sensor_imu_fifo.gyro_scale = GYRO_SCALE;
|
||||
|
||||
for (int i = 0; i < valid_samples; i++) {
|
||||
// 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)
|
||||
sensor_imu_fifo.accel_x[i] = combine(buffer.f[i].ACCEL_XOUT_H, buffer.f[i].ACCEL_XOUT_L);
|
||||
sensor_imu_fifo.accel_y[i] = math::negate(combine(buffer.f[i].ACCEL_YOUT_H, buffer.f[i].ACCEL_YOUT_L));
|
||||
sensor_imu_fifo.accel_z[i] = math::negate(combine(buffer.f[i].ACCEL_ZOUT_H, buffer.f[i].ACCEL_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.accel_x[i], sensor_imu_fifo.accel_y[i], sensor_imu_fifo.accel_z[i]);
|
||||
|
||||
sensor_imu_fifo.gyro_x[i] = combine(buffer.f[i].GYRO_XOUT_H, buffer.f[i].GYRO_XOUT_L);
|
||||
sensor_imu_fifo.gyro_y[i] = math::negate(combine(buffer.f[i].GYRO_YOUT_H, buffer.f[i].GYRO_YOUT_L));
|
||||
sensor_imu_fifo.gyro_z[i] = math::negate(combine(buffer.f[i].GYRO_ZOUT_H, buffer.f[i].GYRO_ZOUT_L));
|
||||
rotate_3i(_rotation, sensor_imu_fifo.gyro_x[i], sensor_imu_fifo.gyro_y[i], sensor_imu_fifo.gyro_z[i]);
|
||||
}
|
||||
|
||||
sensor_imu_fifo.temperature = (hrt_elapsed_time(&_temperature_update_timestamp) < 5_s) ? _temperature : NAN;
|
||||
|
||||
sensor_imu_fifo.error_count = perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf)
|
||||
+ perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf);
|
||||
|
||||
sensor_imu_fifo.timestamp = hrt_absolute_time();
|
||||
_sensor_imu_fifo_pub.publish(sensor_imu_fifo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MPU6500::FIFOReset()
|
||||
@@ -542,106 +541,32 @@ void MPU6500::FIFOReset()
|
||||
}
|
||||
}
|
||||
|
||||
static bool fifo_accel_equal(const FIFO::DATA &f0, const FIFO::DATA &f1)
|
||||
float MPU6500::ReadTemperature()
|
||||
{
|
||||
return (memcmp(&f0.ACCEL_XOUT_H, &f1.ACCEL_XOUT_H, 6) == 0);
|
||||
}
|
||||
// transfer buffer
|
||||
struct TransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ};
|
||||
uint8_t TEMP_OUT_H{0};
|
||||
uint8_t TEMP_OUT_L{0};
|
||||
} buffer{};
|
||||
|
||||
bool MPU6500::ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_accel_fifo_s accel{};
|
||||
accel.timestamp_sample = timestamp_sample;
|
||||
accel.samples = 0;
|
||||
accel.dt = FIFO_SAMPLE_DT * SAMPLES_PER_TRANSFER;
|
||||
|
||||
bool bad_data = false;
|
||||
|
||||
// accel data is doubled in FIFO, but might be shifted
|
||||
int accel_first_sample = 1;
|
||||
|
||||
if (samples >= 4) {
|
||||
if (fifo_accel_equal(fifo[0], fifo[1]) && fifo_accel_equal(fifo[2], fifo[3])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0==A1, A2==A3
|
||||
accel_first_sample = 1;
|
||||
|
||||
} else if (fifo_accel_equal(fifo[1], fifo[2])) {
|
||||
// [A0, A1, A2, A3]
|
||||
// A0, A1==A2, A3
|
||||
accel_first_sample = 0;
|
||||
|
||||
} else {
|
||||
// no matching accel samples is an error
|
||||
bad_data = true;
|
||||
perf_count(_bad_transfer_perf);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = accel_first_sample; i < samples; i = i + SAMPLES_PER_TRANSFER) {
|
||||
int16_t accel_x = combine(fifo[i].ACCEL_XOUT_H, fifo[i].ACCEL_XOUT_L);
|
||||
int16_t accel_y = combine(fifo[i].ACCEL_YOUT_H, fifo[i].ACCEL_YOUT_L);
|
||||
int16_t accel_z = combine(fifo[i].ACCEL_ZOUT_H, fifo[i].ACCEL_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
accel.x[accel.samples] = accel_x;
|
||||
accel.y[accel.samples] = (accel_y == INT16_MIN) ? INT16_MAX : -accel_y;
|
||||
accel.z[accel.samples] = (accel_z == INT16_MIN) ? INT16_MAX : -accel_z;
|
||||
accel.samples++;
|
||||
}
|
||||
|
||||
_px4_accel.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
if (accel.samples > 0) {
|
||||
_px4_accel.updateFIFO(accel);
|
||||
}
|
||||
|
||||
return !bad_data;
|
||||
}
|
||||
|
||||
void MPU6500::ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples)
|
||||
{
|
||||
sensor_gyro_fifo_s gyro{};
|
||||
gyro.timestamp_sample = timestamp_sample;
|
||||
gyro.samples = samples;
|
||||
gyro.dt = FIFO_SAMPLE_DT;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
const int16_t gyro_x = combine(fifo[i].GYRO_XOUT_H, fifo[i].GYRO_XOUT_L);
|
||||
const int16_t gyro_y = combine(fifo[i].GYRO_YOUT_H, fifo[i].GYRO_YOUT_L);
|
||||
const int16_t gyro_z = combine(fifo[i].GYRO_ZOUT_H, fifo[i].GYRO_ZOUT_L);
|
||||
|
||||
// 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)
|
||||
gyro.x[i] = gyro_x;
|
||||
gyro.y[i] = (gyro_y == INT16_MIN) ? INT16_MAX : -gyro_y;
|
||||
gyro.z[i] = (gyro_z == INT16_MIN) ? INT16_MAX : -gyro_z;
|
||||
}
|
||||
|
||||
_px4_gyro.set_error_count(perf_event_count(_bad_register_perf) + perf_event_count(_bad_transfer_perf) +
|
||||
perf_event_count(_fifo_empty_perf) + perf_event_count(_fifo_overflow_perf));
|
||||
|
||||
_px4_gyro.updateFIFO(gyro);
|
||||
}
|
||||
|
||||
void MPU6500::UpdateTemperature()
|
||||
{
|
||||
// read current temperature
|
||||
uint8_t temperature_buf[3] {};
|
||||
temperature_buf[0] = static_cast<uint8_t>(Register::TEMP_OUT_H) | DIR_READ;
|
||||
set_frequency(SPI_SPEED_SENSOR);
|
||||
|
||||
if (transfer(temperature_buf, temperature_buf, sizeof(temperature_buf)) != PX4_OK) {
|
||||
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, sizeof(buffer)) != PX4_OK) {
|
||||
perf_count(_bad_transfer_perf);
|
||||
return;
|
||||
return NAN;
|
||||
}
|
||||
|
||||
const int16_t TEMP_OUT = combine(temperature_buf[1], temperature_buf[2]);
|
||||
const int16_t TEMP_OUT = combine(buffer.TEMP_OUT_H, buffer.TEMP_OUT_L);
|
||||
const float TEMP_degC = (TEMP_OUT / TEMPERATURE_SENSITIVITY) + TEMPERATURE_OFFSET;
|
||||
|
||||
if (PX4_ISFINITE(TEMP_degC)) {
|
||||
_px4_accel.set_temperature(TEMP_degC);
|
||||
_px4_gyro.set_temperature(TEMP_degC);
|
||||
if (PX4_ISFINITE(TEMP_degC)
|
||||
&& (TEMP_degC >= TEMPERATURE_SENSOR_MIN)
|
||||
&& (TEMP_degC <= TEMPERATURE_SENSOR_MAX)) {
|
||||
|
||||
return TEMP_degC;
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2020-2022 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -43,14 +43,15 @@
|
||||
#include "InvenSense_MPU6500_registers.hpp"
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
|
||||
#include <lib/drivers/device/spi.h>
|
||||
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
|
||||
#include <lib/geo/geo.h>
|
||||
#include <lib/perf/perf_counter.h>
|
||||
#include <px4_platform_common/atomic.h>
|
||||
#include <px4_platform_common/i2c_spi_buses.h>
|
||||
|
||||
#include <uORB/PublicationMulti.hpp>
|
||||
#include <uORB/topics/sensor_imu_fifo.h>
|
||||
|
||||
using namespace InvenSense_MPU6500;
|
||||
|
||||
class MPU6500 : public device::SPI, public I2CSPIDriver<MPU6500>
|
||||
@@ -71,20 +72,13 @@ private:
|
||||
|
||||
// Sensor Configuration
|
||||
static constexpr float FIFO_SAMPLE_DT{1e6f / 8000.f};
|
||||
static constexpr int32_t SAMPLES_PER_TRANSFER{2}; // ensure at least 1 new accel sample per transfer
|
||||
static constexpr float GYRO_RATE{1e6f / FIFO_SAMPLE_DT}; // 8000 Hz gyro
|
||||
static constexpr float ACCEL_RATE{GYRO_RATE / SAMPLES_PER_TRANSFER}; // 4000 Hz accel
|
||||
|
||||
// maximum FIFO samples per transfer is limited to the size of sensor_accel_fifo/sensor_gyro_fifo
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), sizeof(sensor_gyro_fifo_s::x) / sizeof(sensor_gyro_fifo_s::x[0]), sizeof(sensor_accel_fifo_s::x) / sizeof(sensor_accel_fifo_s::x[0]) * (int)(GYRO_RATE / ACCEL_RATE))};
|
||||
static constexpr int32_t FIFO_MAX_SAMPLES{math::min(FIFO::SIZE / sizeof(FIFO::DATA), (size_t)sensor_imu_fifo_s::FIFO_SIZE)};
|
||||
|
||||
// Transfer data
|
||||
struct FIFOTransferBuffer {
|
||||
uint8_t cmd{static_cast<uint8_t>(Register::FIFO_R_W) | DIR_READ};
|
||||
FIFO::DATA f[FIFO_MAX_SAMPLES] {};
|
||||
};
|
||||
// ensure no struct padding
|
||||
static_assert(sizeof(FIFOTransferBuffer) == (1 + FIFO_MAX_SAMPLES *sizeof(FIFO::DATA)));
|
||||
static constexpr float ACCEL_SCALE{CONSTANTS_ONE_G / 2048.f}; // ACCEL_FS_SEL_16G
|
||||
static constexpr float GYRO_SCALE{math::radians(2000.f / 32768.f)}; // GYRO_FS_SEL_2000_DPS
|
||||
|
||||
struct register_config_t {
|
||||
Register reg;
|
||||
@@ -97,8 +91,6 @@ private:
|
||||
bool Reset();
|
||||
|
||||
bool Configure();
|
||||
void ConfigureAccel();
|
||||
void ConfigureGyro();
|
||||
void ConfigureSampleRate(int sample_rate);
|
||||
|
||||
static int DataReadyInterruptCallback(int irq, void *context, void *arg);
|
||||
@@ -117,14 +109,15 @@ private:
|
||||
bool FIFORead(const hrt_abstime ×tamp_sample, uint8_t samples);
|
||||
void FIFOReset();
|
||||
|
||||
bool ProcessAccel(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void ProcessGyro(const hrt_abstime ×tamp_sample, const FIFO::DATA fifo[], const uint8_t samples);
|
||||
void UpdateTemperature();
|
||||
float ReadTemperature();
|
||||
|
||||
const spi_drdy_gpio_t _drdy_gpio;
|
||||
|
||||
PX4Accelerometer _px4_accel;
|
||||
PX4Gyroscope _px4_gyro;
|
||||
uORB::PublicationMulti<sensor_imu_fifo_s> _sensor_imu_fifo_pub{ORB_ID(sensor_imu_fifo)};
|
||||
|
||||
const enum Rotation _rotation;
|
||||
|
||||
float _temperature{NAN};
|
||||
|
||||
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")};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user