diff --git a/conf/abi.xml b/conf/abi.xml
index 869a205c22..add63110a6 100644
--- a/conf/abi.xml
+++ b/conf/abi.xml
@@ -212,17 +212,19 @@
-
-
-
-
+ Registered timestamp of the measurement
+ Raw gyro samples measured
+ Amount of samples
+ Sampling rate in Hz of the samples
+ Temperature of the sensor
-
-
-
-
+ Registered timestamp of the measurement
+ Raw accelration samples measured
+ Amount of samples
+ Sampling rate in Hz of the samples
+ Temperature of the sensor
diff --git a/conf/airframes/ENAC/conf_enac.xml b/conf/airframes/ENAC/conf_enac.xml
index a7099b7526..5b7722388f 100644
--- a/conf/airframes/ENAC/conf_enac.xml
+++ b/conf/airframes/ENAC/conf_enac.xml
@@ -142,4 +142,15 @@
settings_modules="modules/ahrs_int_cmpl_quat.xml modules/air_data.xml modules/gps.xml modules/guidance_indi.xml modules/guidance_rotorcraft.xml modules/imu_common.xml modules/jevois.xml modules/logger_sd_chibios.xml modules/nav_basic_rotorcraft.xml modules/nav_survey_poly_rotorcraft.xml modules/stabilization_indi.xml modules/switch_servo.xml modules/tag_tracking.xml"
gui_color="#c6d33e3ef958"
/>
+
diff --git a/conf/airframes/examples/cube_orange.xml b/conf/airframes/examples/cube_orange.xml
index 296fb8a0df..ecba76cc44 100644
--- a/conf/airframes/examples/cube_orange.xml
+++ b/conf/airframes/examples/cube_orange.xml
@@ -14,7 +14,7 @@
Neddrone5
-
+
@@ -73,6 +73,7 @@
+
diff --git a/conf/airframes/examples/matek_h743_slim.xml b/conf/airframes/examples/matek_h743_slim.xml
index ae19539305..7f4825cc2b 100644
--- a/conf/airframes/examples/matek_h743_slim.xml
+++ b/conf/airframes/examples/matek_h743_slim.xml
@@ -28,9 +28,11 @@
-
-
-
+
+
+
+
diff --git a/conf/boards/cube_orange.makefile b/conf/boards/cube_orange.makefile
index c078ce00e7..a5c3fe05e7 100644
--- a/conf/boards/cube_orange.makefile
+++ b/conf/boards/cube_orange.makefile
@@ -46,7 +46,7 @@ CHIBIOS_BOARD_STARTUP = startup_stm32h7xx.mk
FLASH_MODE ?= PX4_BOOTLOADER
PX4_TARGET = "ap"
PX4_PROTOTYPE ?= "${PAPARAZZI_HOME}/sw/tools/px4/cube_orange.prototype"
-PX4_BL_PORT ?= "/dev/serial/by-id/usb-Hex_ProfiCNC_CubeOrange*-BL*"
+PX4_BL_PORT ?= "/dev/serial/by-id/*-BL_*,/dev/serial/by-id/*_BL_*"
#
# default LED configuration
diff --git a/conf/boards/cube_orangeplus.makefile b/conf/boards/cube_orangeplus.makefile
new file mode 100644
index 0000000000..262f13e17c
--- /dev/null
+++ b/conf/boards/cube_orangeplus.makefile
@@ -0,0 +1,91 @@
+# Hey Emacs, this is a -*- makefile -*-
+#
+# cube_orange_plus.makefile
+#
+# This is for the main MCU (STM32F767) on the PX4 board
+# See https://pixhawk.org/modules/pixhawk for details
+#
+
+BOARD=cube
+BOARD_VERSION=orange_plus
+BOARD_DIR=$(BOARD)/orange
+BOARD_CFG=\"arch/chibios/common_board.h\"
+
+ARCH=chibios
+$(TARGET).ARCHDIR = $(ARCH)
+
+RTOS=chibios
+MCU=cortex-m7
+
+# FPU on F7
+USE_FPU=hard
+USE_FPU_OPT= -mfpu=fpv5-d16
+
+#USE_LTO=yes
+
+$(TARGET).CFLAGS += -DPPRZLINK_ENABLE_FD
+
+##############################################################################
+# Architecture or project specific options
+#
+# Define project name here (target)
+PROJECT = $(TARGET)
+
+# Project specific files and paths (see Makefile.chibios for details)
+CHIBIOS_BOARD_PLATFORM = STM32H7xx/platform.mk
+CHIBIOS_LINKER_DIR = $(PAPARAZZI_SRC)/sw/airborne/arch/chibios/
+CHIBIOS_BOARD_LINKER = STM32H743xI.ld
+CHIBIOS_BOARD_STARTUP = startup_stm32h7xx.mk
+
+##############################################################################
+# Compiler settings
+#
+
+# default flash mode is the PX4 bootloader
+# possibilities: DFU, SWD, PX4 bootloader
+FLASH_MODE ?= PX4_BOOTLOADER
+PX4_TARGET = "ap"
+PX4_PROTOTYPE ?= "${PAPARAZZI_HOME}/sw/tools/px4/cube_orangeplus.prototype"
+PX4_BL_PORT ?= "/dev/serial/by-id/*-BL_*,/dev/serial/by-id/*_BL_*"
+
+#
+# default LED configuration
+#
+SDLOG_LED ?= none
+RADIO_CONTROL_LED ?= none
+BARO_LED ?= none
+AHRS_ALIGNER_LED ?= none
+GPS_LED ?= none
+SYS_TIME_LED ?= 1
+
+#
+# default UART configuration (modem, gps, spektrum)
+# The TELEM2 port
+SBUS_PORT ?= UART3
+RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT ?= UART3
+
+# The TELEM1 port (UART3 is TELEM2)
+MODEM_PORT ?= UART2
+MODEM_BAUD ?= B57600
+
+# The GPS1 port (UART8 is GPS2)
+GPS_PORT ?= UART4
+GPS_BAUD ?= B57600
+
+# InterMCU port connected to the IO processor
+INTERMCU_PORT ?= UART6
+INTERMCU_BAUD ?= B1500000
+
+# Overwrite default Cube IMU slave ID
+CUBE_IMU2_SPI_SLAVE_IDX ?= SPI_SLAVE5
+
+#
+# default actuator configuration
+#
+# you can use different actuators by adding a configure option to your firmware section
+# e.g.
+#
+ACTUATORS ?= actuators_pwm
+
diff --git a/conf/modules/boards/cube_orangeplus.xml b/conf/modules/boards/cube_orangeplus.xml
new file mode 100644
index 0000000000..d9c9171c3d
--- /dev/null
+++ b/conf/modules/boards/cube_orangeplus.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ Specific configuration for Cube Orange with ChibiOS
+
+
+
+ spi_master,baro_ms5611_spi
+
+
+
+
+
+
+
+
diff --git a/conf/modules/imu_apogee.xml b/conf/modules/imu_apogee.xml
index b24ea741e1..dfb5cd5c38 100644
--- a/conf/modules/imu_apogee.xml
+++ b/conf/modules/imu_apogee.xml
@@ -33,6 +33,7 @@
+
diff --git a/conf/modules/imu_bebop.xml b/conf/modules/imu_bebop.xml
index 5dc38f78b0..4932b34230 100644
--- a/conf/modules/imu_bebop.xml
+++ b/conf/modules/imu_bebop.xml
@@ -43,6 +43,7 @@
+
diff --git a/conf/modules/imu_cube.xml b/conf/modules/imu_cube.xml
index 31d653e42b..fafe54341e 100644
--- a/conf/modules/imu_cube.xml
+++ b/conf/modules/imu_cube.xml
@@ -28,9 +28,9 @@
-
+
-
+
@@ -50,9 +50,30 @@
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/modules/imu_disco.xml b/conf/modules/imu_disco.xml
index c16c84d79f..d01a56e6fb 100644
--- a/conf/modules/imu_disco.xml
+++ b/conf/modules/imu_disco.xml
@@ -38,6 +38,7 @@
+
diff --git a/conf/modules/imu_icm42688.xml b/conf/modules/imu_icm42688.xml
new file mode 100644
index 0000000000..089a1b6bc7
--- /dev/null
+++ b/conf/modules/imu_icm42688.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+ Driver module for the Invensense v3 IMU ICM42688.
+
+
+
+
+
+
+
+
+
+
+
+ i2c,spi_master,imu_common
+ imu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/modules/imu_matek_h743_slim.xml b/conf/modules/imu_matek_h743_slim.xml
index 2bf80f6101..1cb4dc3747 100644
--- a/conf/modules/imu_matek_h743_slim.xml
+++ b/conf/modules/imu_matek_h743_slim.xml
@@ -7,7 +7,9 @@
MPU6000 IMU via SPI.
-
+
+ imu_mpu6000
+
diff --git a/conf/modules/imu_mpu6000.xml b/conf/modules/imu_mpu6000.xml
index 264aa06c80..fff72770e9 100644
--- a/conf/modules/imu_mpu6000.xml
+++ b/conf/modules/imu_mpu6000.xml
@@ -42,6 +42,7 @@
+
diff --git a/conf/modules/imu_mpu6000_hmc5883.xml b/conf/modules/imu_mpu6000_hmc5883.xml
index a71bb47afe..845887f92a 100644
--- a/conf/modules/imu_mpu6000_hmc5883.xml
+++ b/conf/modules/imu_mpu6000_hmc5883.xml
@@ -67,6 +67,7 @@
+
diff --git a/conf/modules/imu_mpu9250_i2c.xml b/conf/modules/imu_mpu9250_i2c.xml
index 7aacf7eb76..9609edbd6d 100644
--- a/conf/modules/imu_mpu9250_i2c.xml
+++ b/conf/modules/imu_mpu9250_i2c.xml
@@ -42,6 +42,7 @@
+
diff --git a/conf/modules/imu_mpu9250_spi.xml b/conf/modules/imu_mpu9250_spi.xml
index 3f47fcbf9e..16e09882f1 100644
--- a/conf/modules/imu_mpu9250_spi.xml
+++ b/conf/modules/imu_mpu9250_spi.xml
@@ -51,6 +51,7 @@
+
diff --git a/conf/modules/imu_px4fmu_v1.7.xml b/conf/modules/imu_px4fmu_v1.7.xml
index 0b2028e01b..0d7d427469 100644
--- a/conf/modules/imu_px4fmu_v1.7.xml
+++ b/conf/modules/imu_px4fmu_v1.7.xml
@@ -39,6 +39,7 @@
+
diff --git a/conf/modules/imu_px4fmu_v2.4.xml b/conf/modules/imu_px4fmu_v2.4.xml
index b1f3ab3f4c..a97311785f 100644
--- a/conf/modules/imu_px4fmu_v2.4.xml
+++ b/conf/modules/imu_px4fmu_v2.4.xml
@@ -49,6 +49,7 @@
+
diff --git a/sw/airborne/boards/apogee/imu_apogee.c b/sw/airborne/boards/apogee/imu_apogee.c
index 071d395d37..c1f2a00851 100644
--- a/sw/airborne/boards/apogee/imu_apogee.c
+++ b/sw/airborne/boards/apogee/imu_apogee.c
@@ -32,6 +32,7 @@
#include "mcu_periph/i2c.h"
#include "led.h"
#include "modules/core/abi.h"
+#include "generated/modules.h"
// Downlink
#include "mcu_periph/uart.h"
@@ -140,13 +141,13 @@ void imu_apogee_event(void)
(int32_t)(-imu_apogee.mpu.data_rates.value[IMU_APOGEE_CHAN_Y]),
(int32_t)(-imu_apogee.mpu.data_rates.value[IMU_APOGEE_CHAN_Z])
};
- AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &rates, 1, imu_apogee.mpu.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &rates, 1, IMU_APOGEE_PERIODIC_FREQ, imu_apogee.mpu.temp);
struct Int32Vect3 accel = {
(int32_t)( imu_apogee.mpu.data_accel.value[IMU_APOGEE_CHAN_X]),
(int32_t)(-imu_apogee.mpu.data_accel.value[IMU_APOGEE_CHAN_Y]),
(int32_t)(-imu_apogee.mpu.data_accel.value[IMU_APOGEE_CHAN_Z])
};
- AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, imu_apogee.mpu.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, IMU_APOGEE_PERIODIC_FREQ, imu_apogee.mpu.temp);
imu_apogee.mpu.data_available = false;
}
diff --git a/sw/airborne/boards/ardrone/navdata.c b/sw/airborne/boards/ardrone/navdata.c
index 893f6eb5f4..cabbb57c11 100644
--- a/sw/airborne/boards/ardrone/navdata.c
+++ b/sw/airborne/boards/ardrone/navdata.c
@@ -367,14 +367,14 @@ static void navdata_publish_imu(void)
-navdata.measure.vy,
-navdata.measure.vz
};
- AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &gyro, 1, navdata.measure.temperature_gyro);
+ AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &gyro, 1, NAN, navdata.measure.temperature_gyro); //FIXME: samplerate?
struct Int32Vect3 accel = {
navdata.measure.ax,
4096 - navdata.measure.ay,
4096 - navdata.measure.az
};
- AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, navdata.measure.temperature_acc);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, NAN, navdata.measure.temperature_acc); //FIXME: samplerate?
struct Int32Vect3 mag = {
-navdata.measure.mx,
diff --git a/sw/airborne/modules/ahrs/ahrs_vectornav.c b/sw/airborne/modules/ahrs/ahrs_vectornav.c
index 70c3dc8313..0db153f9ab 100644
--- a/sw/airborne/modules/ahrs/ahrs_vectornav.c
+++ b/sw/airborne/modules/ahrs/ahrs_vectornav.c
@@ -83,9 +83,9 @@ void ahrs_vectornav_event(void)
uint32_t now_ts = get_sys_time_usec();
// in fixed point for sending as ABI and telemetry msgs
RATES_BFP_OF_REAL(ahrs_vn.gyro_i, ahrs_vn.vn_data.gyro);
- AbiSendMsgIMU_GYRO_RAW(IMU_VECTORNAV_ID, now_ts, &ahrs_vn.gyro_i, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_VECTORNAV_ID, now_ts, &ahrs_vn.gyro_i, 1, ahrs_vn.vn_freq, NAN);
ACCELS_BFP_OF_REAL(ahrs_vn.accel_i, ahrs_vn.vn_data.accel);
- AbiSendMsgIMU_ACCEL_RAW(IMU_VECTORNAV_ID, now_ts, &ahrs_vn.accel_i, 1, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_VECTORNAV_ID, now_ts, &ahrs_vn.accel_i, 1, ahrs_vn.vn_freq, NAN);
}
}
diff --git a/sw/airborne/modules/core/abi_sender_ids.h b/sw/airborne/modules/core/abi_sender_ids.h
index 3421e3ac98..0277744e32 100644
--- a/sw/airborne/modules/core/abi_sender_ids.h
+++ b/sw/airborne/modules/core/abi_sender_ids.h
@@ -387,6 +387,10 @@
#define IMU_NPS_ID 23
#endif
+#ifndef IMU_ICM42688_ID
+#define IMU_ICM42688_ID 24
+#endif
+
// prefiltering with OneEuro filter
#ifndef IMU_F1E_ID
#define IMU_F1E_ID 30
diff --git a/sw/airborne/modules/imu/imu.c b/sw/airborne/modules/imu/imu.c
index 3dc51ac893..533efc4df1 100644
--- a/sw/airborne/modules/imu/imu.c
+++ b/sw/airborne/modules/imu/imu.c
@@ -273,8 +273,8 @@ static void send_mag_current(struct transport_tx *trans, struct link_device *dev
struct Imu imu = {0};
static abi_event imu_gyro_raw_ev, imu_accel_raw_ev, imu_mag_raw_ev;
-static void imu_gyro_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Rates *data, uint8_t samples, float temp);
-static void imu_accel_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Vect3 *data, uint8_t samples, float temp);
+static void imu_gyro_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Rates *data, uint8_t samples, float rate, float temp);
+static void imu_accel_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Vect3 *data, uint8_t samples, float rate, float temp);
static void imu_mag_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Vect3 *data);
static void imu_set_body_to_imu_eulers(struct FloatEulers *body_to_imu_eulers);
@@ -489,7 +489,7 @@ void imu_set_defaults_mag(uint8_t abi_id, const struct Int32RMat *imu_to_sensor,
}
}
-static void imu_gyro_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Rates *data, uint8_t samples, float temp)
+static void imu_gyro_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Rates *data, uint8_t samples, float rate, float temp)
{
// Find the correct gyro
struct imu_gyro_t *gyro = imu_get_gyro(sender_id, true);
@@ -510,9 +510,8 @@ static void imu_gyro_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Rates
#if IMU_INTEGRATION
// Only integrate if we have gotten a previous measurement and didn't overflow the timer
- if(gyro->last_stamp > 0 && stamp > gyro->last_stamp) {
+ if(!isnan(rate) && gyro->last_stamp > 0 && stamp > gyro->last_stamp) {
struct FloatRates integrated;
- uint16_t dt = stamp - gyro->last_stamp;
// Trapezoidal integration (TODO: coning correction)
integrated.p = RATE_FLOAT_OF_BFP(gyro->scaled.p + scaled_rot.p) * 0.5f;
@@ -538,14 +537,17 @@ static void imu_gyro_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Rates
float_rmat_transp_ratemult(&integrated, &body_to_sensor, &integrated_sensor);
}
- // Divide by the amount of samples and multiply by the delta time
- integrated.p = integrated.p / samples * ((float)dt * 1e-6f);
- integrated.q = integrated.q / samples * ((float)dt * 1e-6f);
- integrated.r = integrated.r / samples * ((float)dt * 1e-6f);
+ // Divide by the time of the collected samples
+ integrated.p = integrated.p * (1.f / rate);
+ integrated.q = integrated.q * (1.f / rate);
+ integrated.r = integrated.r * (1.f / rate);
// Send the integrated values
+ uint16_t dt = (1e6 / rate) * samples;
AbiSendMsgIMU_GYRO_INT(sender_id, stamp, &integrated, dt);
}
+#else
+ (void)rate; // Surpress compile warning not used
#endif
// Copy and send
@@ -555,7 +557,7 @@ static void imu_gyro_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Rates
gyro->last_stamp = stamp;
}
-static void imu_accel_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Vect3 *data, uint8_t samples, float temp)
+static void imu_accel_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Vect3 *data, uint8_t samples, float rate, float temp)
{
// Find the correct accel
struct imu_accel_t *accel = imu_get_accel(sender_id, true);
@@ -576,9 +578,8 @@ static void imu_accel_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Vect
#if IMU_INTEGRATION
// Only integrate if we have gotten a previous measurement and didn't overflow the timer
- if(accel->last_stamp > 0 && stamp > accel->last_stamp) {
+ if(!isnan(rate) && accel->last_stamp > 0 && stamp > accel->last_stamp) {
struct FloatVect3 integrated;
- uint16_t dt = stamp - accel->last_stamp;
// Trapezoidal integration
integrated.x = ACCEL_FLOAT_OF_BFP(accel->scaled.x + scaled_rot.x) * 0.5f;
@@ -604,14 +605,17 @@ static void imu_accel_raw_cb(uint8_t sender_id, uint32_t stamp, struct Int32Vect
float_rmat_transp_vmult(&integrated, &body_to_sensor, &integrated_sensor);
}
- // Divide by the amount of samples and multiply by the delta time
- integrated.x = integrated.x / samples * ((float)dt * 1e-6f);
- integrated.y = integrated.y / samples * ((float)dt * 1e-6f);
- integrated.z = integrated.z / samples * ((float)dt * 1e-6f);
+ // Divide by the time of the collected samples
+ integrated.x = integrated.x * (1.f / rate);
+ integrated.y = integrated.y * (1.f / rate);
+ integrated.z = integrated.z * (1.f / rate);
// Send the integrated values
+ uint16_t dt = (1e6 / rate) * samples;
AbiSendMsgIMU_ACCEL_INT(sender_id, stamp, &integrated, dt);
}
+#else
+ (void)rate; // Surpress compile warning not used
#endif
// Copy and send
diff --git a/sw/airborne/modules/imu/imu_aspirin.c b/sw/airborne/modules/imu/imu_aspirin.c
index 8dfe9e4f68..5980d59e6e 100644
--- a/sw/airborne/modules/imu/imu_aspirin.c
+++ b/sw/airborne/modules/imu/imu_aspirin.c
@@ -30,6 +30,7 @@
#include "modules/core/abi.h"
#include "mcu_periph/i2c.h"
#include "mcu_periph/spi.h"
+#include "generated/modules.h"
/* defaults suitable for Lisa */
@@ -141,14 +142,14 @@ void imu_aspirin_event(void)
if (imu_aspirin.acc_adxl.data_available) {
struct Int32Vect3 accel;
VECT3_COPY(accel, imu_aspirin.acc_adxl.data.vect);
- AbiSendMsgIMU_ACCEL_RAW(IMU_ASPIRIN_ID, now_ts, &accel, 1, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_ASPIRIN_ID, now_ts, &accel, 1, IMU_ASPIRIN_PERIODIC_FREQ, NAN);
imu_aspirin.acc_adxl.data_available = false;
}
/* If the itg3200 I2C transaction has succeeded: convert the data */
itg3200_event(&imu_aspirin.gyro_itg);
if (imu_aspirin.gyro_itg.data_available) {
- AbiSendMsgIMU_GYRO_RAW(IMU_ASPIRIN_ID, now_ts, &imu_aspirin.gyro_itg.data.rates, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_ASPIRIN_ID, now_ts, &imu_aspirin.gyro_itg.data.rates, 1, IMU_ASPIRIN_PERIODIC_FREQ, NAN);
imu_aspirin.gyro_itg.data_available = false;
}
diff --git a/sw/airborne/modules/imu/imu_aspirin_2_spi.c b/sw/airborne/modules/imu/imu_aspirin_2_spi.c
index 2d4dc2831f..053f44910f 100644
--- a/sw/airborne/modules/imu/imu_aspirin_2_spi.c
+++ b/sw/airborne/modules/imu/imu_aspirin_2_spi.c
@@ -30,6 +30,7 @@
#include "mcu_periph/sys_time.h"
#include "mcu_periph/spi.h"
#include "peripherals/hmc58xx_regs.h"
+#include "generated/modules.h"
/* defaults suitable for Lisa */
#ifndef ASPIRIN_2_SPI_SLAVE_IDX
@@ -237,8 +238,8 @@ void imu_aspirin2_event(void)
imu_aspirin2.mpu.data_available = false;
- AbiSendMsgIMU_GYRO_RAW(IMU_ASPIRIN2_ID, now_ts, &gyro, 1, imu_aspirin2.mpu.temp);
- AbiSendMsgIMU_ACCEL_RAW(IMU_ASPIRIN2_ID, now_ts, &accel, 1, imu_aspirin2.mpu.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_ASPIRIN2_ID, now_ts, &gyro, 1, IMU_ASPIRIN2_PERIODIC_FREQ, imu_aspirin2.mpu.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_ASPIRIN2_ID, now_ts, &accel, 1, IMU_ASPIRIN2_PERIODIC_FREQ, imu_aspirin2.mpu.temp);
#if !ASPIRIN_2_DISABLE_MAG
AbiSendMsgIMU_MAG_RAW(IMU_ASPIRIN2_ID, now_ts, &mag_rot);
#endif
diff --git a/sw/airborne/modules/imu/imu_aspirin_i2c.c b/sw/airborne/modules/imu/imu_aspirin_i2c.c
index 0ca385f0fe..42ceea35af 100644
--- a/sw/airborne/modules/imu/imu_aspirin_i2c.c
+++ b/sw/airborne/modules/imu/imu_aspirin_i2c.c
@@ -29,6 +29,7 @@
#include "modules/imu/imu.h"
#include "modules/core/abi.h"
#include "mcu_periph/i2c.h"
+#include "generated/modules.h"
// Set SPI_CS High to enable I2C mode of ADXL345
#include "mcu_periph/gpio.h"
@@ -154,14 +155,14 @@ void imu_aspirin_i2c_event(void)
adxl345_i2c_event(&imu_aspirin.acc_adxl);
if (imu_aspirin.acc_adxl.data_available) {
- AbiSendMsgIMU_ACCEL_RAW(IMU_ASPIRIN_ID, now_ts, &imu_aspirin.acc_adxl.data.vect, 1, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_ASPIRIN_ID, now_ts, &imu_aspirin.acc_adxl.data.vect, 1, IMU_ASPIRIN_I2C_PERIODIC_FREQ, NAN);
imu_aspirin.acc_adxl.data_available = false;
}
/* If the itg3200 I2C transaction has succeeded: convert the data */
itg3200_event(&imu_aspirin.gyro_itg);
if (imu_aspirin.gyro_itg.data_available) {
- AbiSendMsgIMU_GYRO_RAW(IMU_ASPIRIN_ID, now_ts, &imu_aspirin.gyro_itg.data.rates, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_ASPIRIN_ID, now_ts, &imu_aspirin.gyro_itg.data.rates, 1, IMU_ASPIRIN_I2C_PERIODIC_FREQ, NAN);
imu_aspirin.gyro_itg.data_available = false;
}
diff --git a/sw/airborne/modules/imu/imu_bebop.c b/sw/airborne/modules/imu/imu_bebop.c
index 9bbd6f6a79..f8e748bb77 100644
--- a/sw/airborne/modules/imu/imu_bebop.c
+++ b/sw/airborne/modules/imu/imu_bebop.c
@@ -28,6 +28,7 @@
#include "modules/imu/imu.h"
#include "modules/core/abi.h"
#include "mcu_periph/i2c.h"
+#include "generated/modules.h"
/* defaults suitable for Bebop */
@@ -131,8 +132,8 @@ void imu_bebop_event(void)
-imu_bebop.mpu.data_accel.vect.z);
imu_bebop.mpu.data_available = false;
- AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &gyro, 1, imu_bebop.mpu.temp);
- AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, imu_bebop.mpu.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &gyro, 1, IMU_BEBOP_PERIODIC_FREQ, imu_bebop.mpu.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, IMU_BEBOP_PERIODIC_FREQ, imu_bebop.mpu.temp);
}
/* AKM8963 event task */
diff --git a/sw/airborne/modules/imu/imu_bmi088_i2c.c b/sw/airborne/modules/imu/imu_bmi088_i2c.c
index 9cb0014049..d8d03d9f66 100644
--- a/sw/airborne/modules/imu/imu_bmi088_i2c.c
+++ b/sw/airborne/modules/imu/imu_bmi088_i2c.c
@@ -125,7 +125,7 @@ void imu_bmi088_event(void)
};
imu_bmi088.bmi.gyro_available = false;
- AbiSendMsgIMU_GYRO_RAW(IMU_BMI088_ID, now_ts, &rates, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_BMI088_ID, now_ts, &rates, 1, imu_bmi088.bmi.config.gyro_samplerate, NAN);
}
if (imu_bmi088.bmi.accel_available) {
// set channel order
@@ -136,7 +136,7 @@ void imu_bmi088_event(void)
};
imu_bmi088.bmi.accel_available = false;
- AbiSendMsgIMU_ACCEL_RAW(IMU_BMI088_ID, now_ts, &accel, 1, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_BMI088_ID, now_ts, &accel, 1, imu_bmi088.bmi.config.accel_samplerate, NAN);
}
}
diff --git a/sw/airborne/modules/imu/imu_cube.c b/sw/airborne/modules/imu/imu_cube.c
index 0292d951e7..75df3cf534 100644
--- a/sw/airborne/modules/imu/imu_cube.c
+++ b/sw/airborne/modules/imu/imu_cube.c
@@ -24,15 +24,21 @@
* Driver for the IMU's in the Cube autopilots.
*/
+#include "generated/modules.h"
#include "modules/imu/imu.h"
#include "modules/core/abi.h"
#include "mcu_periph/spi.h"
#include "peripherals/invensense2.h"
+#include "peripherals/invensense3.h"
#include "peripherals/mpu60x0_spi.h"
static struct invensense2_t imu1;
+#if IMU_CUBE_ORANGEPLUS
+static struct invensense3_t imu2;
+#else
static struct Mpu60x0_Spi imu2;
+#endif
static struct invensense2_t imu3;
void imu_cube_init(void)
@@ -59,6 +65,31 @@ void imu_cube_init(void)
imu_set_defaults_gyro(IMU_CUBE1_ID, &rmat, NULL, NULL);
imu_set_defaults_accel(IMU_CUBE1_ID, &rmat, NULL, NULL);
+#if IMU_CUBE_ORANGEPLUS
+ /* IMU 2 (ICM20602 isolated) */
+ imu2.abi_id = IMU_CUBE2_ID;
+ imu2.parser = INVENSENSE3_PARSER_FIFO;
+ imu2.bus = INVENSENSE3_SPI;
+ imu2.spi.p = &CUBE_IMU2_SPI_DEV;
+ imu2.spi.slave_idx = CUBE_IMU2_SPI_SLAVE_IDX;
+
+ imu2.gyro_odr = INVENSENSE3_GYRO_ODR_4KHZ;
+ imu2.gyro_range = INVENSENSE3_GYRO_RANGE_500DPS;
+ imu2.accel_odr = INVENSENSE3_ACCEL_ODR_4KHZ;
+ imu2.accel_range = INVENSENSE3_ACCEL_RANGE_32G;
+ imu2.gyro_aaf = 977; // ~ODR/4
+ imu2.accel_aaf = 213; // Fixed
+
+ invensense3_init(&imu2);
+
+ // Rotation
+ eulers.phi = ANGLE_BFP_OF_REAL(0),
+ eulers.theta = ANGLE_BFP_OF_REAL(0);
+ eulers.psi = ANGLE_BFP_OF_REAL(RadOfDeg(90));
+ int32_rmat_of_eulers(&rmat, &eulers);
+ imu_set_defaults_gyro(IMU_CUBE2_ID, &rmat, NULL, NULL);
+ imu_set_defaults_accel(IMU_CUBE2_ID, &rmat, NULL, NULL);
+#else
/* IMU 2 (ICM20602 isolated) */
mpu60x0_spi_init(&imu2, &CUBE_IMU2_SPI_DEV, CUBE_IMU2_SPI_SLAVE_IDX);
// change the default configuration
@@ -75,6 +106,7 @@ void imu_cube_init(void)
int32_rmat_of_eulers(&rmat, &eulers);
imu_set_defaults_gyro(IMU_CUBE2_ID, &rmat, NULL, MPU60X0_GYRO_SENS_FRAC[MPU60X0_GYRO_RANGE_2000]);
imu_set_defaults_accel(IMU_CUBE2_ID, &rmat, NULL, MPU60X0_ACCEL_SENS_FRAC[MPU60X0_ACCEL_RANGE_16G]);
+#endif
/* IMU 3 (ICM2094 isolated) */
imu3.abi_id = IMU_CUBE3_ID;
@@ -99,7 +131,11 @@ void imu_cube_init(void)
void imu_cube_periodic(void)
{
invensense2_periodic(&imu1);
+#if IMU_CUBE_ORANGEPLUS
+ invensense3_periodic(&imu2);
+#else
mpu60x0_spi_periodic(&imu2);
+#endif
invensense2_periodic(&imu3);
}
@@ -107,6 +143,9 @@ void imu_cube_event(void)
{
invensense2_event(&imu1);
+#if IMU_CUBE_ORANGEPLUS
+ invensense3_event(&imu2);
+#else
mpu60x0_spi_event(&imu2);
if (imu2.data_available) {
uint32_t now_ts = get_sys_time_usec();
@@ -126,9 +165,10 @@ void imu_cube_event(void)
imu2.data_available = false;
// Send the scaled values over ABI
- AbiSendMsgIMU_GYRO_RAW(IMU_CUBE2_ID, now_ts, &rates, 1, imu2.temp);
- AbiSendMsgIMU_ACCEL_RAW(IMU_CUBE2_ID, now_ts, &accel, 1, imu2.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_CUBE2_ID, now_ts, &rates, 1, IMU_CUBE_PERIODIC_FREQ, imu2.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_CUBE2_ID, now_ts, &accel, 1, IMU_CUBE_PERIODIC_FREQ, imu2.temp);
}
+#endif
invensense2_event(&imu3);
}
diff --git a/sw/airborne/modules/imu/imu_disco.c b/sw/airborne/modules/imu/imu_disco.c
index b3541f749a..9e356ede80 100644
--- a/sw/airborne/modules/imu/imu_disco.c
+++ b/sw/airborne/modules/imu/imu_disco.c
@@ -28,6 +28,7 @@
#include "modules/imu/imu.h"
#include "modules/core/abi.h"
#include "mcu_periph/i2c.h"
+#include "generated/modules.h"
/* I2C is hardwired on Disco autopilot */
@@ -131,8 +132,8 @@ void imu_disco_event(void)
imu_disco.mpu.data_accel.vect.z);
imu_disco.mpu.data_available = false;
- AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &gyro, 1, imu_disco.mpu.temp);
- AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, imu_disco.mpu.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &gyro, 1, IMU_DISCO_PERIODIC_FREQ, imu_disco.mpu.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, IMU_DISCO_PERIODIC_FREQ, imu_disco.mpu.temp);
}
/* AKM8963 event task */
diff --git a/sw/airborne/modules/imu/imu_heater.c b/sw/airborne/modules/imu/imu_heater.c
index 8e1636264c..40bbe04052 100644
--- a/sw/airborne/modules/imu/imu_heater.c
+++ b/sw/airborne/modules/imu/imu_heater.c
@@ -75,7 +75,7 @@ static void send_imu_heater(struct transport_tx *trans, struct link_device *dev)
#endif
#if defined(IMU_HEATER_GYRO_ID)
-static void imu_heater_gyro_raw_cb(uint8_t sender_id __attribute__((unused)), uint32_t stamp __attribute__((unused)), struct Int32Rates *data __attribute__((unused)), uint8_t samples __attribute__((unused)), float temp) {
+static void imu_heater_gyro_raw_cb(uint8_t sender_id __attribute__((unused)), uint32_t stamp __attribute__((unused)), struct Int32Rates *data __attribute__((unused)), uint8_t samples __attribute__((unused)), float rate __attribute__((unused)), float temp) {
if(isnan(temp))
return;
@@ -85,7 +85,7 @@ static void imu_heater_gyro_raw_cb(uint8_t sender_id __attribute__((unused)), ui
#endif
#if defined(IMU_HEATER_ACCEL_ID)
-static void imu_heater_accel_raw_cb(uint8_t sender_id __attribute__((unused)), uint32_t stamp __attribute__((unused)), struct Int32Vect3 *data __attribute__((unused)), uint8_t samples __attribute__((unused)), float temp) {
+static void imu_heater_accel_raw_cb(uint8_t sender_id __attribute__((unused)), uint32_t stamp __attribute__((unused)), struct Int32Vect3 *data __attribute__((unused)), uint8_t samples __attribute__((unused)), float rate __attribute__((unused)), float temp) {
if(isnan(temp))
return;
diff --git a/sw/airborne/modules/imu/imu_icm42688.c b/sw/airborne/modules/imu/imu_icm42688.c
new file mode 100644
index 0000000000..e2ee9025f6
--- /dev/null
+++ b/sw/airborne/modules/imu/imu_icm42688.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 Freek van tieen
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file modules/imu/imu_icm42688.c
+ * Driver module for the Invensense v3 IMU ICM42688.
+ */
+
+#include "modules/imu/imu_icm42688.h"
+#include "modules/imu/imu.h"
+#include "modules/core/abi.h"
+#include "mcu_periph/spi.h"
+#include "peripherals/invensense3.h"
+
+
+#ifndef INVENSENSE3_GYRO_AAF
+#define INVENSENSE3_GYRO_AAF 977
+#endif
+
+#ifndef INVENSENSE3_ACCEL_AAF
+#define INVENSENSE3_ACCEL_AAF 213
+#endif
+
+static struct invensense3_t imu_icm42688;
+
+void imu_icm42688_init(void)
+{
+ imu_icm42688.abi_id = IMU_ICM42688_ID;
+ //imu_icm42688.parser = INVENSENSE3_PARSER_REGISTERS;
+ imu_icm42688.parser = INVENSENSE3_PARSER_FIFO;
+
+ imu_icm42688.bus = INVENSENSE3_SPI;
+ imu_icm42688.spi.p = &IMU_SPI_DEV;
+ imu_icm42688.spi.slave_idx = IMU_SPI_SLAVE_IDX;
+
+ imu_icm42688.gyro_odr = INVENSENSE3_GYRO_ODR;
+ imu_icm42688.gyro_range = INVENSENSE3_GYRO_RANGE;
+ imu_icm42688.accel_odr = INVENSENSE3_ACCEL_ODR;
+ imu_icm42688.accel_range = INVENSENSE3_ACCEL_RANGE;
+
+ // The AAF freq needs to be high enough to avoid group delay and low enough to minimise noise and clipping
+ imu_icm42688.gyro_aaf = INVENSENSE3_GYRO_AAF; // ~ODR/4
+ imu_icm42688.accel_aaf = INVENSENSE3_ACCEL_AAF; // Fixed
+
+ invensense3_init(&imu_icm42688);
+}
+
+void imu_icm42688_periodic(void)
+{
+ invensense3_periodic(&imu_icm42688);
+}
+
+void imu_icm42688_event(void)
+{
+ invensense3_event(&imu_icm42688);
+}
+
+
+
diff --git a/sw/airborne/modules/imu/imu_icm42688.h b/sw/airborne/modules/imu/imu_icm42688.h
new file mode 100644
index 0000000000..6d3cae5f72
--- /dev/null
+++ b/sw/airborne/modules/imu/imu_icm42688.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 Jesús Bautista Villar
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file modules/imu/imu_icm42688.h
+ * Driver for the IMU ICM42688.
+ */
+
+#ifndef IMU_ICM42688_H
+#define IMU_ICM42688_H
+
+#include "std.h"
+
+extern void imu_icm42688_init(void);
+extern void imu_icm42688_periodic(void);
+extern void imu_icm42688_event(void);
+
+#endif /* IMU_ICM42688_H */
diff --git a/sw/airborne/modules/imu/imu_mpu6000.c b/sw/airborne/modules/imu/imu_mpu6000.c
index 66c58a9908..9d38905c88 100644
--- a/sw/airborne/modules/imu/imu_mpu6000.c
+++ b/sw/airborne/modules/imu/imu_mpu6000.c
@@ -29,6 +29,7 @@
#include "modules/imu/imu.h"
#include "modules/core/abi.h"
#include "mcu_periph/spi.h"
+#include "generated/modules.h"
#if IMU_MPU_USE_MEDIAN_FILTER
#include "filters/median_filter.h"
#endif
@@ -165,7 +166,7 @@ void imu_mpu_spi_event(void)
imu_mpu_spi.mpu.data_available = false;
// Send the scaled values over ABI
- AbiSendMsgIMU_GYRO_RAW(IMU_MPU6000_ID, now_ts, &rates, 1, imu_mpu_spi.mpu.temp);
- AbiSendMsgIMU_ACCEL_RAW(IMU_MPU6000_ID, now_ts, &accel, 1, imu_mpu_spi.mpu.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_MPU6000_ID, now_ts, &rates, 1, IMU_MPU_SPI_PERIODIC_FREQ, imu_mpu_spi.mpu.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_MPU6000_ID, now_ts, &accel, 1, IMU_MPU_SPI_PERIODIC_FREQ, imu_mpu_spi.mpu.temp);
}
}
diff --git a/sw/airborne/modules/imu/imu_mpu6000_hmc5883.c b/sw/airborne/modules/imu/imu_mpu6000_hmc5883.c
index 05edd91cd7..17be9e8c80 100644
--- a/sw/airborne/modules/imu/imu_mpu6000_hmc5883.c
+++ b/sw/airborne/modules/imu/imu_mpu6000_hmc5883.c
@@ -29,6 +29,7 @@
#include "modules/core/abi.h"
#include "mcu_periph/spi.h"
#include "peripherals/hmc58xx_regs.h"
+#include "generated/modules.h"
/* SPI/I2C defaults set in subsystem makefile, can be configured from airframe file */
@@ -167,8 +168,8 @@ void imu_mpu_hmc_event(void)
};
imu_mpu_hmc.mpu.data_available = false;
- AbiSendMsgIMU_GYRO_RAW(IMU_MPU6000_HMC_ID, now_ts, &rates, 1, imu_mpu_hmc.mpu.temp);
- AbiSendMsgIMU_ACCEL_RAW(IMU_MPU6000_HMC_ID, now_ts, &accel, 1, imu_mpu_hmc.mpu.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_MPU6000_HMC_ID, now_ts, &rates, 1, IMU_MPU_HMC_PERIODIC_FREQ, imu_mpu_hmc.mpu.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_MPU6000_HMC_ID, now_ts, &accel, 1, IMU_MPU_HMC_PERIODIC_FREQ, imu_mpu_hmc.mpu.temp);
}
/* HMC58XX event task */
diff --git a/sw/airborne/modules/imu/imu_mpu60x0_i2c.c b/sw/airborne/modules/imu/imu_mpu60x0_i2c.c
index 3d2d76eec7..cba9683190 100644
--- a/sw/airborne/modules/imu/imu_mpu60x0_i2c.c
+++ b/sw/airborne/modules/imu/imu_mpu60x0_i2c.c
@@ -30,6 +30,7 @@
#include "modules/core/abi.h"
#include "mcu_periph/i2c.h"
#include "led.h"
+#include "generated/modules.h"
/* MPU60x0 gyro/accel internal lowpass frequency */
#if !defined IMU_MPU60X0_LOWPASS_FILTER && !defined IMU_MPU60X0_SMPLRT_DIV
@@ -89,8 +90,8 @@ void imu_mpu_i2c_event(void)
// If the MPU60X0 I2C transaction has succeeded: convert the data
mpu60x0_i2c_event(&imu_mpu_i2c.mpu);
if (imu_mpu_i2c.mpu.data_available) {
- AbiSendMsgIMU_GYRO_RAW(IMU_MPU60X0_ID, now_ts, &imu_mpu_i2c.mpu.data_rates.rates, 1, imu_mpu_i2c.mpu.temp);
- AbiSendMsgIMU_ACCEL_RAW(IMU_MPU60X0_ID, now_ts, &imu_mpu_i2c.mpu.data_accel.vect, 1, imu_mpu_i2c.mpu.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_MPU60X0_ID, now_ts, &imu_mpu_i2c.mpu.data_rates.rates, 1, IMU_MPU_I2C_PERIODIC_FREQ, imu_mpu_i2c.mpu.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_MPU60X0_ID, now_ts, &imu_mpu_i2c.mpu.data_accel.vect, 1, IMU_MPU_I2C_PERIODIC_FREQ, imu_mpu_i2c.mpu.temp);
imu_mpu_i2c.mpu.data_available = false;
}
}
diff --git a/sw/airborne/modules/imu/imu_mpu9250_i2c.c b/sw/airborne/modules/imu/imu_mpu9250_i2c.c
index 7199592e91..84d0a2dd08 100644
--- a/sw/airborne/modules/imu/imu_mpu9250_i2c.c
+++ b/sw/airborne/modules/imu/imu_mpu9250_i2c.c
@@ -30,6 +30,7 @@
#include "mcu_periph/i2c.h"
#include "mcu_periph/sys_time.h"
#include "modules/core/abi.h"
+#include "generated/modules.h"
#if !defined IMU_MPU9250_GYRO_LOWPASS_FILTER && !defined IMU_MPU9250_ACCEL_LOWPASS_FILTER && !defined IMU_MPU9250_SMPLRT_DIV
#if (PERIODIC_FREQUENCY >= 60) && (PERIODIC_FREQUENCY <= 120)
@@ -142,8 +143,8 @@ void imu_mpu9250_event(void)
};
imu_mpu9250.mpu.data_available = false;
- AbiSendMsgIMU_GYRO_RAW(IMU_MPU9250_ID, now_ts, &rates, 1, NAN);
- AbiSendMsgIMU_ACCEL_RAW(IMU_MPU9250_ID, now_ts, &accel, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_MPU9250_ID, now_ts, &rates, 1, IMU_MPU9250_PERIODIC_FREQ, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_MPU9250_ID, now_ts, &accel, 1, IMU_MPU9250_PERIODIC_FREQ, NAN);
}
#if IMU_MPU9250_READ_MAG
// Test if mag data are updated
diff --git a/sw/airborne/modules/imu/imu_mpu9250_spi.c b/sw/airborne/modules/imu/imu_mpu9250_spi.c
index e73e97639d..a500857116 100644
--- a/sw/airborne/modules/imu/imu_mpu9250_spi.c
+++ b/sw/airborne/modules/imu/imu_mpu9250_spi.c
@@ -31,6 +31,7 @@
#include "mcu_periph/sys_time.h"
#include "mcu_periph/spi.h"
#include "peripherals/ak8963_regs.h"
+#include "generated/modules.h"
/* SPI defaults set in subsystem makefile, can be configured from airframe file */
PRINT_CONFIG_VAR(IMU_MPU9250_SPI_SLAVE_IDX)
@@ -200,8 +201,8 @@ void imu_mpu9250_event(void)
#endif
imu_mpu9250.mpu.data_available = false;
- AbiSendMsgIMU_GYRO_RAW(IMU_MPU9250_ID, now_ts, &rates, 1, NAN);
- AbiSendMsgIMU_ACCEL_RAW(IMU_MPU9250_ID, now_ts, &accel, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_MPU9250_ID, now_ts, &rates, 1, IMU_MPU9250_PERIODIC_FREQ, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_MPU9250_ID, now_ts, &accel, 1, IMU_MPU9250_PERIODIC_FREQ, NAN);
}
}
diff --git a/sw/airborne/modules/imu/imu_nps.c b/sw/airborne/modules/imu/imu_nps.c
index 4abb2ca935..b323b0c3d5 100644
--- a/sw/airborne/modules/imu/imu_nps.c
+++ b/sw/airborne/modules/imu/imu_nps.c
@@ -88,11 +88,11 @@ void imu_nps_event(void)
{
uint32_t now_ts = get_sys_time_usec();
if (imu_nps.gyro_available) {
- AbiSendMsgIMU_GYRO_RAW(IMU_NPS_ID, now_ts, &imu_nps.gyro, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_NPS_ID, now_ts, &imu_nps.gyro, 1, NPS_PROPAGATE, NAN);
imu_nps.gyro_available = false;
}
if (imu_nps.accel_available) {
- AbiSendMsgIMU_ACCEL_RAW(IMU_NPS_ID, now_ts, &imu_nps.accel, 1, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_NPS_ID, now_ts, &imu_nps.accel, 1, NPS_PROPAGATE, NAN);
imu_nps.accel_available = false;
}
if (imu_nps.mag_available) {
diff --git a/sw/airborne/modules/imu/imu_px4fmu.c b/sw/airborne/modules/imu/imu_px4fmu.c
index b3c1000647..5488274d7e 100644
--- a/sw/airborne/modules/imu/imu_px4fmu.c
+++ b/sw/airborne/modules/imu/imu_px4fmu.c
@@ -29,6 +29,7 @@
#include "modules/core/abi.h"
#include "mcu_periph/spi.h"
#include "peripherals/hmc58xx_regs.h"
+#include "generated/modules.h"
/* MPU60x0 gyro/accel internal lowpass frequency */
@@ -103,8 +104,8 @@ void imu_px4fmu_event(void)
-imu_px4fmu.mpu.data_accel.vect.z
};
imu_px4fmu.mpu.data_available = false;
- AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &gyro, 1, imu_px4fmu.mpu.temp);
- AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, imu_px4fmu.mpu.temp);
+ AbiSendMsgIMU_GYRO_RAW(IMU_BOARD_ID, now_ts, &gyro, 1, IMU_PX4FMU_PERIODIC_FREQ, imu_px4fmu.mpu.temp);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_BOARD_ID, now_ts, &accel, 1, IMU_PX4FMU_PERIODIC_FREQ, imu_px4fmu.mpu.temp);
}
/* HMC58XX event task */
diff --git a/sw/airborne/modules/imu/imu_px4fmu_v2.4.c b/sw/airborne/modules/imu/imu_px4fmu_v2.4.c
index 478de45123..3e168250d1 100644
--- a/sw/airborne/modules/imu/imu_px4fmu_v2.4.c
+++ b/sw/airborne/modules/imu/imu_px4fmu_v2.4.c
@@ -29,6 +29,7 @@
#include "modules/imu/imu.h"
#include "modules/core/abi.h"
#include "mcu_periph/spi.h"
+#include "generated/modules.h"
/* SPI defaults set in subsystem makefile, can be configured from airframe file */
PRINT_CONFIG_VAR(IMU_LSM_SPI_SLAVE_IDX)
@@ -90,7 +91,7 @@ void imu_px4_event(void) {
imu_px4.l3g.data_rates.rates.r
};
imu_px4.l3g.data_available = FALSE;
- AbiSendMsgIMU_GYRO_RAW(IMU_PX4_ID, now_ts, &gyro, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_PX4_ID, now_ts, &gyro, 1, IMU_PX4_PERIODIC_FREQ, NAN);
}
/* LSM303d event task */
@@ -98,7 +99,7 @@ void imu_px4_event(void) {
if (imu_px4.lsm_acc.data_available_acc) {
struct Int32Vect3 accel;
VECT3_COPY(accel, imu_px4.lsm_acc.data_accel.vect);
- AbiSendMsgIMU_ACCEL_RAW(IMU_PX4_ID, now_ts, &accel, 1, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_PX4_ID, now_ts, &accel, 1, IMU_PX4_PERIODIC_FREQ, NAN);
imu_px4.lsm_acc.data_available_acc = FALSE;
}
#if !IMU_PX4_DISABLE_MAG
diff --git a/sw/airborne/modules/imu/imu_vectornav.c b/sw/airborne/modules/imu/imu_vectornav.c
index 4987de82a4..e42a52a132 100644
--- a/sw/airborne/modules/imu/imu_vectornav.c
+++ b/sw/airborne/modules/imu/imu_vectornav.c
@@ -148,6 +148,6 @@ void imu_vectornav_propagate(void)
uint32_t now_ts = (uint32_t) tmp;
// Send accel and gyro data separate for other AHRS algorithms
- AbiSendMsgIMU_GYRO_RAW(IMU_VECTORNAV_ID, now_ts, &imu_vn.vn_data.gyro, 1, NAN);
- AbiSendMsgIMU_ACCEL_RAW(IMU_VECTORNAV_ID, now_ts, &imu_vn.vn_data.accel, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_VECTORNAV_ID, now_ts, &imu_vn.vn_data.gyro, 1, imu_vn.vn_freq, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_VECTORNAV_ID, now_ts, &imu_vn.vn_data.accel, 1, imu_vn.vn_freq, NAN);
}
diff --git a/sw/airborne/modules/ins/imu_xsens.c b/sw/airborne/modules/ins/imu_xsens.c
index da4f49872a..b868702ac9 100644
--- a/sw/airborne/modules/ins/imu_xsens.c
+++ b/sw/airborne/modules/ins/imu_xsens.c
@@ -61,7 +61,7 @@ static void handle_ins_msg(void)
RATE_BFP_OF_REAL(xsens.gyro.r)
};
xsens.gyro_available = FALSE
- AbiSendMsgIMU_GYRO_RAW(IMU_XSENS_ID, now_ts, &gyro, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_XSENS_ID, now_ts, &gyro, 1, NAN, NAN); //FIXME: samplerate?
}
if (xsens.accel_available) {
struct Int32Vect3 accel = {
@@ -70,7 +70,7 @@ static void handle_ins_msg(void)
ACCEL_BFP_OF_REAL(xsens.accel.z)
};
xsens.accel_available = FALSE;
- AbiSendMsgIMU_ACCEL_RAW(IMU_XSENS_ID, now_ts, &accel, 1, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_XSENS_ID, now_ts, &accel, 1, NAN, NAN); //FIXME: samplerate?
}
if (xsens.mag_available) {
struct Int32Vect3 mag = {
@@ -88,7 +88,7 @@ static void handle_ins_msg(void)
RATE_BFP_OF_REAL(xsens.gyro.q),
RATE_BFP_OF_REAL(xsens.gyro.r)
};
- AbiSendMsgIMU_GYRO_RAW(IMU_XSENS_ID, now_ts, &gyro, 1, NAN);
+ AbiSendMsgIMU_GYRO_RAW(IMU_XSENS_ID, now_ts, &gyro, 1, NAN, NAN); //FIXME: samplerate?
xsens.gyro_available = FALSE;
}
if (xsens.accel_available) {
@@ -97,7 +97,7 @@ static void handle_ins_msg(void)
ACCEL_BFP_OF_REAL(xsens.accel.y),
ACCEL_BFP_OF_REAL(xsens.accel.z)
};
- AbiSendMsgIMU_ACCEL_RAW(IMU_XSENS_ID, now_ts, &accel, 1, NAN);
+ AbiSendMsgIMU_ACCEL_RAW(IMU_XSENS_ID, now_ts, &accel, 1, NAN, NAN); //FIXME: samplerate?
xsens.accel_available = FALSE;
}
if (xsens.mag_available) {
diff --git a/sw/airborne/peripherals/bmi088.c b/sw/airborne/peripherals/bmi088.c
index 3bd9915683..f428ed52c9 100644
--- a/sw/airborne/peripherals/bmi088.c
+++ b/sw/airborne/peripherals/bmi088.c
@@ -115,6 +115,54 @@ void bmi088_send_config(Bmi088ConfigSet bmi_set, void *bmi, struct Bmi088Config
config->init_status++;
break;
case BMI088_CONF_DONE:
+ /* Set the samplerates from the ODR */
+ switch(config->gyro_odr) {
+ case BMI088_GYRO_ODR_2000_BW_532:
+ case BMI088_GYRO_ODR_2000_BW_230:
+ config->gyro_samplerate = 2000;
+ break;
+ case BMI088_GYRO_ODR_1000_BW_116:
+ config->gyro_samplerate = 1000;
+ break;
+ case BMI088_GYRO_ODR_400_BW_47:
+ config->gyro_samplerate = 400;
+ break;
+ case BMI088_GYRO_ODR_200_BW_23:
+ case BMI088_GYRO_ODR_200_BW_64:
+ config->gyro_samplerate = 200;
+ break;
+ case BMI088_GYRO_ODR_100_BW_12:
+ case BMI088_GYRO_ODR_100_BW_32:
+ config->gyro_samplerate = 100;
+ break;
+ }
+ switch(config->accel_odr) {
+ case BMI088_ACCEL_ODR_1600:
+ config->accel_samplerate = 1600;
+ break;
+ case BMI088_ACCEL_ODR_800:
+ config->accel_samplerate = 800;
+ break;
+ case BMI088_ACCEL_ODR_400:
+ config->accel_samplerate = 400;
+ break;
+ case BMI088_ACCEL_ODR_200:
+ config->accel_samplerate = 200;
+ break;
+ case BMI088_ACCEL_ODR_100:
+ config->accel_samplerate = 100;
+ break;
+ case BMI088_ACCEL_ODR_50:
+ config->accel_samplerate = 50;
+ break;
+ case BMI088_ACCEL_ODR_25:
+ config->accel_samplerate = 25;
+ break;
+ case BMI088_ACCEL_ODR_12:
+ config->accel_samplerate = 12;
+ break;
+ }
+
config->initialized = true;
break;
default:
diff --git a/sw/airborne/peripherals/bmi088.h b/sw/airborne/peripherals/bmi088.h
index a8de841205..fbb20eeac1 100644
--- a/sw/airborne/peripherals/bmi088.h
+++ b/sw/airborne/peripherals/bmi088.h
@@ -119,6 +119,9 @@ struct Bmi088Config {
enum Bmi088AccelBW accel_bw; ///< bandwidth
enum Bmi088ConfStatus init_status; ///< init status
bool initialized; ///< config done flag
+
+ float gyro_samplerate; ///< samplerate in Hz from gyro_odr
+ float accel_samplerate; ///< samplerate in Hz from accel_odr
};
extern void bmi088_set_default_config(struct Bmi088Config *c);
diff --git a/sw/airborne/peripherals/invensense2.c b/sw/airborne/peripherals/invensense2.c
index b89fa44fd8..3a3c6f4e77 100644
--- a/sw/airborne/peripherals/invensense2.c
+++ b/sw/airborne/peripherals/invensense2.c
@@ -74,7 +74,7 @@ static const struct Int32Vect3 invensense2_accel_scale[5][2] = {
/**
* @brief Initialize the invensense v2 sensor instance
*
- * @param inv The structure containing the configuratio of the invensense v2 instance
+ * @param inv The structure containing the configuration of the invensense v2 instance
*/
void invensense2_init(struct invensense2_t *inv) {
/* General setup */
@@ -314,8 +314,8 @@ static void invensense2_parse_data(struct invensense2_t *inv, volatile uint8_t *
// Send the scaled values over ABI
uint32_t now_ts = get_sys_time_usec();
- AbiSendMsgIMU_GYRO_RAW(inv->abi_id, now_ts, gyro, samples, temp_f);
- AbiSendMsgIMU_ACCEL_RAW(inv->abi_id, now_ts, accel, j, temp_f);
+ AbiSendMsgIMU_GYRO_RAW(inv->abi_id, now_ts, gyro, samples, gyro_samplerate, temp_f);
+ AbiSendMsgIMU_ACCEL_RAW(inv->abi_id, now_ts, accel, j, accel_samplerate, temp_f);
}
/**
diff --git a/sw/airborne/peripherals/invensense2.h b/sw/airborne/peripherals/invensense2.h
index 80ab174dff..8d9d0b1f61 100644
--- a/sw/airborne/peripherals/invensense2.h
+++ b/sw/airborne/peripherals/invensense2.h
@@ -139,8 +139,6 @@ struct invensense2_t {
enum invensense2_gyro_range_t gyro_range; ///< Gyro range configuration
enum invensense2_accel_dlpf_t accel_dlpf; ///< Accelerometer DLPF configuration
enum invensense2_accel_range_t accel_range; ///< Accelerometer range configuration
-
- // float temp; ///< temperature in degrees Celcius
};
/* External functions */
diff --git a/sw/airborne/peripherals/invensense3.c b/sw/airborne/peripherals/invensense3.c
new file mode 100644
index 0000000000..c4be3c7a76
--- /dev/null
+++ b/sw/airborne/peripherals/invensense3.c
@@ -0,0 +1,990 @@
+/*
+ * Copyright (C) 2022 Freek van Tienen
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file peripherals/invensense3.c
+ *
+ * Driver for the Invensense v3 IMUs
+ * ICM40605, ICM40609, ICM42605, IIM42652 and ICM42688
+ */
+
+#include "peripherals/invensense3.h"
+#include "peripherals/invensense3_regs.h"
+#include "math/pprz_isa.h"
+#include "math/pprz_algebra_int.h"
+#include "modules/imu/imu.h"
+#include "modules/core/abi.h"
+#include "mcu_periph/gpio_arch.h"
+#include "std.h"
+
+/* Local functions */
+static void invensense3_parse_fifo_data(struct invensense3_t *inv, uint8_t *data, uint16_t samples);
+static void invensense3_parse_reg_data(struct invensense3_t *inv, uint8_t *data);
+static void invensense3_fix_config(struct invensense3_t *inv);
+static bool invensense3_register_write(struct invensense3_t *inv, uint16_t bank_reg, uint8_t value);
+static bool invensense3_register_read(struct invensense3_t *inv, uint16_t bank_reg, uint16_t size);
+static bool invensense3_select_bank(struct invensense3_t *inv, uint8_t bank);
+static bool invensense3_config(struct invensense3_t *inv);
+static bool invensense3_reset_fifo(struct invensense3_t *inv);
+static int samples_from_odr(int odr);
+
+/* Default gyro scalings */
+static const struct Int32Rates invensense3_gyro_scale[8][2] = {
+ { {40147, 40147, 40147},
+ {9210, 9210, 9210} }, // 2000DPS
+ { {40147, 40147, 40147},
+ {18420, 18420, 18420} }, // 1000DPS
+ { {60534, 60534, 60534},
+ {55463, 55463, 55463} }, // 500DPS
+ { {30267, 30267, 30267},
+ {55463, 55463, 55463} }, // 250DPS
+ { {30267, 30267, 30267},
+ {110926, 110926, 110926} }, // 125DPS vvv (TODO: the new scales are not tested yet) vvv
+ { {3292054, 3292054, 3292054},
+ {24144015, 24144015, 24144015} }, // 62.5DPS
+ { {1646027, 1646027, 1646027},
+ {24144015, 24144015, 24144015} }, // 31.25DPS
+ { {1646027, 1646027, 1646027},
+ {48288030, 48288030, 48288030} }, // 15.625DPS
+};
+
+/* Default accel scalings */
+static const struct Int32Vect3 invensense3_accel_scale[5][2] = {
+ { {51024, 51024, 51024},
+ {5203, 5203, 5203} }, // 32G
+ { {25512, 25512, 25512},
+ {5203, 5203, 5203} }, // 16G
+ { {12756, 12756, 12756},
+ {5203, 5203, 5203} }, // 8G
+ { {6378, 6378, 6378},
+ {5203, 5203, 5203} }, // 4G
+ { {3189, 3189, 3189},
+ {5203, 5203, 5203} } // 2G
+};
+
+/* AAF settings (3dB Bandwidth [Hz], AAF_DELT, AAF_DELTSQR, AAF_BITSHIFT) */
+static const uint16_t invensense3_aaf[][4] = {
+ {42, 1, 1, 15},
+ {84, 2, 4, 13},
+ {126, 3, 9, 12},
+ {170, 4, 16, 11},
+ {213, 5, 25, 10},
+ {258, 6, 36, 10},
+ {303, 7, 49, 9},
+ {348, 8, 64, 9},
+ {394, 9, 81, 9},
+ {441, 10, 100, 8},
+ {488, 11, 122, 8},
+ {536, 12, 144, 8},
+ {585, 13, 170, 8},
+ {634, 14, 196, 7},
+ {684, 15, 224, 7},
+ {734, 16, 256, 7},
+ {785, 17, 288, 7},
+ {837, 18, 324, 7},
+ {890, 19, 360, 6},
+ {943, 20, 400, 6},
+ {997, 21, 440, 6},
+ {1051, 22, 488, 6},
+ {1107, 23, 528, 6},
+ {1163, 24, 576, 6},
+ {1220, 25, 624, 6},
+ {1277, 26, 680, 6},
+ {1336, 27, 736, 5},
+ {1395, 28, 784, 5},
+ {1454, 29, 848, 5},
+ {1515, 30, 896, 5},
+ {1577, 31, 960, 5},
+ {1639, 32, 1024, 5},
+ {1702, 33, 1088, 5},
+ {1766, 34, 1152, 5},
+ {1830, 35, 1232, 5},
+ {1896, 36, 1296, 5},
+ {1962, 37, 1376, 4},
+ {2029, 38, 1440, 4},
+ {2097, 39, 1536, 4},
+ {2166, 40, 1600, 4},
+ {2235, 41, 1696, 4},
+ {2306, 42, 1760, 4},
+ {2377, 43, 1856, 4},
+ {2449, 44, 1952, 4},
+ {2522, 45, 2016, 4},
+ {2596, 46, 2112, 4},
+ {2671, 47, 2208, 4},
+ {2746, 48, 2304, 4},
+ {2823, 49, 2400, 4},
+ {2900, 50, 2496, 4},
+ {2978, 51, 2592, 4},
+ {3057, 52, 2720, 4},
+ {3137, 53, 2816, 3},
+ {3217, 54, 2944, 3},
+ {3299, 55, 3008, 3},
+ {3381, 56, 3136, 3},
+ {3464, 57, 3264, 3},
+ {3548, 58, 3392, 3},
+ {3633, 59, 3456, 3},
+ {3718, 60, 3584, 3},
+ {3805, 61, 3712, 3},
+ {3892, 62, 3840, 3},
+ {3979, 63, 3968, 3}
+};
+
+static const uint16_t invensense3_aaf4x605[][4] = {
+ {10, 1, 1, 15},
+ {21, 2, 4, 13},
+ {32, 3, 9, 12},
+ {42, 4, 16, 11},
+ {53, 5, 25, 10},
+ {64, 6, 36, 10},
+ {76, 7, 49, 9},
+ {87, 8, 64, 9},
+ {99, 9, 81, 9},
+ {110, 10, 100, 8},
+ {122, 11, 122, 8},
+ {134, 12, 144, 8},
+ {146, 13, 170, 8},
+ {158, 14, 196, 7},
+ {171, 15, 224, 7},
+ {184, 16, 256, 7},
+ {196, 17, 288, 7},
+ {209, 18, 324, 7},
+ {222, 19, 360, 6},
+ {236, 20, 400, 6},
+ {249, 21, 440, 6},
+ {263, 22, 488, 6},
+ {277, 23, 528, 6},
+ {291, 24, 576, 6},
+ {305, 25, 624, 6},
+ {319, 26, 680, 6},
+ {334, 27, 736, 5},
+ {349, 28, 784, 5},
+ {364, 29, 848, 5},
+ {379, 30, 896, 5},
+ {394, 31, 960, 5},
+ {410, 32, 1024, 5},
+ {425, 33, 1088, 5},
+ {441, 34, 1152, 5},
+ {458, 35, 1232, 5},
+ {474, 36, 1296, 5},
+ {490, 37, 1376, 4},
+ {507, 38, 1440, 4},
+ {524, 39, 1536, 4},
+ {541, 40, 1600, 4},
+ {559, 41, 1696, 4},
+ {576, 42, 1760, 4},
+ {594, 43, 1856, 4},
+ {612, 44, 1952, 4},
+ {631, 45, 2016, 4},
+ {649, 46, 2112, 4},
+ {668, 47, 2208, 4},
+ {687, 48, 2304, 4},
+ {706, 49, 2400, 4},
+ {725, 50, 2496, 4},
+ {745, 51, 2592, 4},
+ {764, 52, 2720, 4},
+ {784, 53, 2816, 3},
+ {804, 54, 2944, 3},
+ {825, 55, 3008, 3},
+ {845, 56, 3136, 3},
+ {866, 57, 3264, 3},
+ {887, 58, 3392, 3},
+ {908, 59, 3456, 3},
+ {930, 60, 3584, 3},
+ {951, 61, 3712, 3},
+ {973, 62, 3840, 3},
+ {995, 63, 3968, 3}
+};
+
+static const uint8_t invensense3_fifo_sample_size[4] = {8,8,16,20};
+
+/**
+ * @brief Initialize the invensense v3 sensor instance
+ *
+ * @param inv The structure containing the configuration of the invensense v3 instance
+ */
+void invensense3_init(struct invensense3_t *inv) {
+ /* General setup */
+ inv->status = INVENSENSE3_IDLE;
+ inv->device = INVENSENSE3_UNKOWN;
+ inv->register_bank = 0xFF;
+ inv->config_idx = 0;
+
+ /* SPI setup */
+ if(inv->bus == INVENSENSE3_SPI) {
+ inv->spi.trans.cpol = SPICpolIdleHigh;
+ inv->spi.trans.cpha = SPICphaEdge2;
+ inv->spi.trans.dss = SPIDss8bit;
+ inv->spi.trans.bitorder = SPIMSBFirst;
+ inv->spi.trans.cdiv = SPIDiv16;
+
+ inv->spi.trans.select = SPISelectUnselect;
+ inv->spi.trans.slave_idx = inv->spi.slave_idx;
+ inv->spi.trans.output_length = 0;
+ inv->spi.trans.input_length = 0;
+ inv->spi.trans.before_cb = NULL;
+ inv->spi.trans.after_cb = NULL;
+ inv->spi.trans.input_buf = inv->spi.rx_buf;
+ inv->spi.trans.output_buf = inv->spi.tx_buf;
+ inv->spi.trans.status = SPITransDone;
+
+ inv->rx_buffer = inv->spi.rx_buf;
+ inv->tx_buffer = inv->spi.tx_buf;
+ inv->rx_length = &inv->spi.trans.input_length;
+ }
+ /* I2C setup */
+ else {
+ inv->i2c.trans.slave_addr = inv->i2c.slave_addr;
+ inv->i2c.trans.status = I2CTransDone;
+
+ inv->rx_buffer = (uint8_t *)inv->i2c.trans.buf;
+ inv->tx_buffer = (uint8_t *)inv->i2c.trans.buf;
+ inv->rx_length = &inv->i2c.trans.len_r;
+ }
+
+ inv->sample_size = INVENSENSE3_SAMPLE_SIZE_PK3;
+
+ inv->sample_numbers = samples_from_odr(Min((int)inv->gyro_odr, (int)inv->accel_odr));
+}
+
+/**
+ * @brief Should be called periodically to request sensor readings
+ * - First detects the sensor using WHO_AM_I reading
+ * - Configures the sensor according the users requested configuration
+ * - Requests a sensor reading by reading the FIFO_COUNT register
+ *
+ * @param inv The invensense v3 instance
+ */
+void invensense3_periodic(struct invensense3_t *inv) {
+ /* Idle */
+ if((inv->bus == INVENSENSE3_SPI && inv->spi.trans.status == SPITransDone) ||
+ (inv->bus == INVENSENSE3_I2C && inv->i2c.trans.status == I2CTransDone)) {
+
+ /* Depending on the status choose what to do */
+ switch(inv->status) {
+ case INVENSENSE3_IDLE:
+ /* Request WHO_AM_I */
+ invensense3_register_read(inv, INV3REG_WHO_AM_I, 1);
+ break;
+
+ case INVENSENSE3_CONFIG:
+ /* Start configuring */
+ if(invensense3_config(inv)) {
+ inv->status = INVENSENSE3_RUNNING;
+ }
+ break;
+
+ case INVENSENSE3_RUNNING:
+ /* Request a sensor reading */
+ switch (inv->parser) {
+ case INVENSENSE3_PARSER_REGISTERS:
+ invensense3_register_read(inv, INV3REG_TEMP_DATA1, 14);
+ break;
+ case INVENSENSE3_PARSER_FIFO:
+ {
+ static const uint16_t max_bytes = sizeof(inv->spi.rx_buf) - 3;
+ int read_bytes = (inv->sample_numbers + inv->timer) * invensense3_fifo_sample_size[inv->sample_size];
+ read_bytes = Min(max_bytes, read_bytes);
+ // round to the packet boundaries
+ read_bytes -= read_bytes % invensense3_fifo_sample_size[inv->sample_size];
+ invensense3_register_read(inv, INV3REG_FIFO_COUNTH, read_bytes + 2);
+ inv->timer = 0; // reset leftover bytes
+ break;
+ }
+ default: break;
+ }
+
+ default: break;
+ }
+ }
+}
+
+/**
+ * @brief Should be called in the event thread
+ * - Checks the response of the WHO_AM_I reading
+ * - Configures the sensor and reads the responses
+ * - Parse and request the sensor data from the FIFO buffers
+ *
+ * @param inv The invensense v3 instance
+ */
+void invensense3_event(struct invensense3_t *inv) {
+
+ /* Successful transfer */
+ if((inv->bus == INVENSENSE3_SPI && inv->spi.trans.status == SPITransSuccess) ||
+ (inv->bus == INVENSENSE3_I2C && inv->i2c.trans.status == I2CTransSuccess)) {
+
+ /* Update the register bank */
+ if(inv->tx_buffer[0] == INV3REG_BANK_SEL)
+ inv->register_bank = inv->tx_buffer[1];
+
+ /* Set the transaction as done and update register bank if needed */
+ if(inv->bus == INVENSENSE3_SPI)
+ inv->spi.trans.status = SPITransDone;
+ else
+ inv->i2c.trans.status = I2CTransDone;
+
+ /* Look at the results */
+ switch(inv->status) {
+ case INVENSENSE3_IDLE:
+ /* Check the response of the WHO_AM_I */
+ inv->status = INVENSENSE3_CONFIG;
+ if(inv->rx_buffer[1] == INV3_WHOAMI_ICM40605) {
+ inv->device = INVENSENSE3_ICM40605;
+ } else if(inv->rx_buffer[1] == INV3_WHOAMI_ICM40609) {
+ inv->device = INVENSENSE3_ICM40609;
+ } else if(inv->rx_buffer[1] == INV3_WHOAMI_ICM42605) {
+ inv->device = INVENSENSE3_ICM42605;
+ } else if(inv->rx_buffer[1] == INV3_WHOAMI_IIM42652) {
+ inv->device = INVENSENSE3_IIM42652;
+ } else if(inv->rx_buffer[1] == INV3_WHOAMI_ICM42688) {
+ inv->device = INVENSENSE3_ICM42688;
+ } else {
+ inv->status = INVENSENSE3_IDLE;
+ }
+
+ /* Fix the configuration and set the scaling */
+ if(inv->status == INVENSENSE3_CONFIG)
+ invensense3_fix_config(inv);
+ break;
+
+ case INVENSENSE3_CONFIG:
+ /* Apply the next configuration register */
+ if(invensense3_config(inv)) {
+ inv->status = INVENSENSE3_RUNNING;
+ }
+ break;
+
+ case INVENSENSE3_RUNNING:
+ /* Select the desired parser */
+ switch (inv->parser) {
+ case INVENSENSE3_PARSER_REGISTERS:
+ invensense3_parse_reg_data(inv, &inv->rx_buffer[1]);
+ break;
+
+ case INVENSENSE3_PARSER_FIFO: {
+ /* Parse the results */
+ uint16_t n_samples = (uint16_t)inv->rx_buffer[1] | inv->rx_buffer[2] << 8;
+ uint16_t fifo_bytes = n_samples * invensense3_fifo_sample_size[inv->sample_size];
+
+ inv->timer = n_samples; // samples left in FIFO
+
+ // Not enough data in FIFO
+ if(n_samples == 0) {
+ return;
+ }
+
+ // We read an incorrect length (try again)
+ if(fifo_bytes > 4096) {
+ invensense3_register_read(inv, INV3REG_FIFO_COUNTH, 2);
+ return;
+ }
+
+ // Parse the data
+ if(*inv->rx_length > 3) {
+ uint16_t nb_packets_read = (*inv->rx_length - 3) / invensense3_fifo_sample_size[inv->sample_size];
+ invensense3_parse_fifo_data(inv, &inv->rx_buffer[3], Min(n_samples, nb_packets_read));
+ inv->timer -= nb_packets_read;
+ }
+
+ break;
+ }
+ default: break;
+ }
+ break;
+
+ default:
+ inv->status = INVENSENSE3_IDLE;
+ break;
+ }
+ }
+
+ /* Failed transaction */
+ if((inv->bus == INVENSENSE3_SPI && inv->spi.trans.status == SPITransFailed) ||
+ (inv->bus == INVENSENSE3_I2C && inv->i2c.trans.status == I2CTransFailed)) {
+
+ /* Set the transaction as done and update register bank if needed */
+ if(inv->bus == INVENSENSE3_SPI) {
+ inv->spi.trans.status = SPITransDone;
+ }
+ else {
+ inv->i2c.trans.status = I2CTransDone;
+ }
+
+ /* Retry or ignore */
+ switch(inv->status) {
+ case INVENSENSE3_CONFIG:
+ /* If was not a bus switch decrease the index */
+ if(inv->config_idx > 0 && inv->tx_buffer[0] != INV3REG_BANK_SEL) {
+ inv->config_idx--;
+ }
+ /* Try again */
+ if(invensense3_config(inv)) {
+ inv->status = INVENSENSE3_RUNNING;
+ }
+ break;
+ case INVENSENSE3_IDLE:
+ case INVENSENSE3_RUNNING:
+ /* Ignore while idle/running */
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * @brief Parse the FIFO buffer data
+ *
+ * @param inv The invensense v3 instance
+ * @param data The FIFO buffer data to parse
+ * @param len The length of the FIFO buffer
+ */
+static void invensense3_parse_fifo_data(struct invensense3_t *inv, uint8_t *data, uint16_t samples) {
+ static struct Int32Vect3 accel[INVENSENSE3_FIFO_BUFFER_LEN] = {0};
+ static struct Int32Rates gyro[INVENSENSE3_FIFO_BUFFER_LEN] = {0};
+
+ samples = Min(samples, INVENSENSE3_FIFO_BUFFER_LEN);
+
+ uint8_t gyro_samplerate = 17 - inv->gyro_odr;
+ uint8_t accel_samplerate = 17 - inv->accel_odr;
+
+ uint8_t faster_odr = gyro_samplerate;
+ if (accel_samplerate > gyro_samplerate)
+ faster_odr = accel_samplerate;
+
+ // Go through the different samples
+ uint8_t i = 0;
+ uint8_t j = 0;
+ int32_t temp = 0;
+ uint16_t gyro_samplerate_count;
+ uint16_t accel_samplerate_count;
+ for(uint8_t sample = 0; sample < samples; sample++) {
+
+ if ((data[0] & 0xFC) != 0x68) {
+ // no or bad data
+ } else {
+
+ gyro_samplerate_count = gyro_samplerate * (sample + 1);
+ if(gyro_samplerate_count % faster_odr == 0) {
+ gyro[i].p = (int16_t)((uint16_t)data[7] | data[8] << 8 );
+ gyro[i].q = (int16_t)((uint16_t)data[9] | data[10] << 8 );
+ gyro[i].r = (int16_t)((uint16_t)data[11] | data[12] << 8 );
+
+ // Temperature sensor register data TEMP_DATA is updated with new data at max(Accelerometer ODR, Gyroscope ODR)
+ if(gyro_samplerate == faster_odr)
+ temp += data[13];
+
+ i++;
+ }
+
+ accel_samplerate_count = accel_samplerate * (sample + 1);
+ if(accel_samplerate_count % faster_odr == 0) {
+ accel[j].x = (int16_t)((uint16_t)data[1] | data[2] << 8 );
+ accel[j].y = (int16_t)((uint16_t)data[3] | data[4] << 8 );
+ accel[j].z = (int16_t)((uint16_t)data[5] | data[6] << 8 );
+
+ if(accel_samplerate == faster_odr)
+ temp += data[13];
+
+ j++;
+ }
+ }
+
+ data += invensense3_fifo_sample_size[inv->sample_size];
+ }
+
+ // ADC temp * temp sensitivity + temp zero
+ float temp_f = ((float)temp / i) / 2.07 + 25.f;
+ if (accel_samplerate == faster_odr)
+ temp_f = ((float)temp / j) / 2.07 + 25.f;
+
+ // Send the scaled values over ABI
+ uint32_t now_ts = get_sys_time_usec();
+ AbiSendMsgIMU_GYRO_RAW(inv->abi_id, now_ts, gyro, i, inv->gyro_samplerate, temp_f);
+ AbiSendMsgIMU_ACCEL_RAW(inv->abi_id, now_ts, accel, j, inv->accel_samplerate, temp_f);
+ AbiSendMsgTEMPERATURE(inv->abi_id, temp_f);
+}
+
+/**
+ * @brief Parse data from registers
+ *
+ * @param inv The invensense v3 instance
+ * @param data The data from all registers (DATA_TEMP, DATA_ACCEL and DATA_GYRO)
+ */
+static void invensense3_parse_reg_data(struct invensense3_t *inv, uint8_t *data) {
+ static struct Int32Vect3 accel[1] = {0};
+ static struct Int32Rates gyro[1] = {0};
+
+ int32_t temp = (int16_t)((uint16_t)data[0] | data[1] << 8);
+ // ADC temp * temp sensitivity + temp zero
+ float temp_f = (float)temp / 132.48 + 25.f;
+
+ accel[0].x = (int16_t)((uint16_t)data[2] | data[3] << 8 );
+ accel[0].y = (int16_t)((uint16_t)data[4] | data[5] << 8 );
+ accel[0].z = (int16_t)((uint16_t)data[6] | data[7] << 8 );
+
+ gyro[0].p = (int16_t)((uint16_t)data[8] | data[9] << 8 );
+ gyro[0].q = (int16_t)((uint16_t)data[10]| data[11] << 8 );
+ gyro[0].r = (int16_t)((uint16_t)data[12]| data[13] << 8 );
+
+ // Send the scaled values over ABI
+ uint32_t now_ts = get_sys_time_usec();
+ AbiSendMsgIMU_GYRO_RAW(inv->abi_id, now_ts, gyro, 1, inv->gyro_samplerate, temp_f);
+ AbiSendMsgIMU_ACCEL_RAW(inv->abi_id, now_ts, accel, 1, inv->accel_samplerate, temp_f);
+ AbiSendMsgTEMPERATURE(inv->abi_id, temp_f);
+}
+
+/**
+ * @brief This fixes the configuration errors and sets the correct scalings
+ *
+ * @param inv The invensense v3 instance
+ */
+static void invensense3_fix_config(struct invensense3_t *inv) {
+ /* Fix wrong configuration settings (prevent user error) */
+ if(inv->gyro_odr > INVENSENSE3_GYRO_ODR_12_5HZ && inv->gyro_odr != INVENSENSE3_GYRO_ODR_500HZ)
+ inv->gyro_odr = INVENSENSE3_GYRO_ODR_12_5HZ;
+
+ if(inv->device == INVENSENSE3_ICM40605 || inv->device == INVENSENSE3_ICM42605) {
+ if(inv->gyro_odr > INVENSENSE3_GYRO_ODR_25HZ && inv->gyro_odr != INVENSENSE3_GYRO_ODR_500HZ)
+ inv->gyro_odr = INVENSENSE3_GYRO_ODR_25HZ;
+ else if(inv->gyro_odr < INVENSENSE3_GYRO_ODR_8KHZ)
+ inv->gyro_odr = INVENSENSE3_GYRO_ODR_8KHZ;
+
+ if(inv->device == INVENSENSE3_ICM40605 && inv->accel_odr > INVENSENSE3_ACCEL_ODR_25HZ && inv->accel_odr != INVENSENSE3_ACCEL_ODR_500HZ)
+ inv->accel_odr = INVENSENSE3_ACCEL_ODR_25HZ;
+ else if(inv->accel_odr < INVENSENSE3_ACCEL_ODR_8KHZ)
+ inv->accel_odr = INVENSENSE3_ACCEL_ODR_8KHZ;
+ }
+
+ if(inv->device != INVENSENSE3_ICM40609 && inv->accel_range < INVENSENSE3_ACCEL_RANGE_16G)
+ inv->accel_range = INVENSENSE3_ACCEL_RANGE_16G;
+ else if(inv->device == INVENSENSE3_ICM40609 && inv->accel_range > INVENSENSE3_ACCEL_RANGE_4G)
+ inv->accel_range = INVENSENSE3_ACCEL_RANGE_4G;
+
+ /* Fix the AAF bandwidth setting */
+ const uint16_t (*aaf_table)[4];
+ uint16_t aaf_len;
+ if(inv->device == INVENSENSE3_ICM40605 || inv->device == INVENSENSE3_ICM42605) {
+ aaf_len = sizeof(invensense3_aaf4x605) / sizeof(invensense3_aaf4x605[0]);
+ aaf_table = invensense3_aaf4x605;
+ }
+ else {
+ aaf_len = sizeof(invensense3_aaf) / sizeof(invensense3_aaf[0]);
+ aaf_table = invensense3_aaf;
+ }
+
+ uint16_t i = 0;
+ for(i = 0; i < aaf_len; i++) {
+ if(inv->gyro_aaf <= aaf_table[i][0]) {
+ inv->gyro_aaf = aaf_table[i][0];
+ RMAT_COPY(inv->gyro_aaf_regs, aaf_table[i]);
+ break;
+ }
+ }
+ if(i >= (aaf_len-1)) {
+ inv->gyro_aaf = aaf_table[aaf_len-1][0];
+ RMAT_COPY(inv->gyro_aaf_regs, aaf_table[aaf_len-1]);
+ }
+
+ for(i = 0; i < aaf_len; i++) {
+ if(inv->accel_aaf <= aaf_table[i][0]) {
+ inv->accel_aaf = aaf_table[i][0];
+ RMAT_COPY(inv->accel_aaf_regs, aaf_table[i]);
+ break;
+ }
+ }
+ if(i >= (aaf_len-1)) {
+ inv->accel_aaf = aaf_table[aaf_len-1][0];
+ RMAT_COPY(inv->accel_aaf_regs, aaf_table[aaf_len-1]);
+ }
+
+ /* Calculate the samplerates in Hz */
+ switch(inv->gyro_odr) {
+ case INVENSENSE3_GYRO_ODR_32KHZ:
+ inv->gyro_samplerate = 32000;
+ break;
+ case INVENSENSE3_GYRO_ODR_16KHZ:
+ inv->gyro_samplerate = 16000;
+ break;
+ case INVENSENSE3_GYRO_ODR_8KHZ:
+ inv->gyro_samplerate = 8000;
+ break;
+ case INVENSENSE3_GYRO_ODR_4KHZ:
+ inv->gyro_samplerate = 4000;
+ break;
+ case INVENSENSE3_GYRO_ODR_2KHZ:
+ inv->gyro_samplerate = 2000;
+ break;
+ case INVENSENSE3_GYRO_ODR_1KHZ:
+ inv->gyro_samplerate = 1000;
+ break;
+ case INVENSENSE3_GYRO_ODR_200HZ:
+ inv->gyro_samplerate = 200;
+ break;
+ case INVENSENSE3_GYRO_ODR_100HZ:
+ inv->gyro_samplerate = 100;
+ break;
+ case INVENSENSE3_GYRO_ODR_50HZ:
+ inv->gyro_samplerate = 50;
+ break;
+ case INVENSENSE3_GYRO_ODR_25HZ:
+ inv->gyro_samplerate = 25;
+ break;
+ case INVENSENSE3_GYRO_ODR_12_5HZ:
+ inv->gyro_samplerate = 12.5;
+ break;
+ case INVENSENSE3_GYRO_ODR_6_25HZ:
+ inv->gyro_samplerate = 6.25;
+ break;
+ case INVENSENSE3_GYRO_ODR_3_125HZ:
+ inv->gyro_samplerate = 3.125;
+ break;
+ case INVENSENSE3_GYRO_ODR_1_5625HZ:
+ inv->gyro_samplerate = 1.5625;
+ break;
+ case INVENSENSE3_GYRO_ODR_500HZ:
+ inv->gyro_samplerate = 500;
+ break;
+ }
+ switch(inv->accel_odr) {
+ case INVENSENSE3_ACCEL_ODR_32KHZ:
+ inv->accel_samplerate = 32000;
+ break;
+ case INVENSENSE3_ACCEL_ODR_16KHZ:
+ inv->accel_samplerate = 16000;
+ break;
+ case INVENSENSE3_ACCEL_ODR_8KHZ:
+ inv->accel_samplerate = 8000;
+ break;
+ case INVENSENSE3_ACCEL_ODR_4KHZ:
+ inv->accel_samplerate = 4000;
+ break;
+ case INVENSENSE3_ACCEL_ODR_2KHZ:
+ inv->accel_samplerate = 2000;
+ break;
+ case INVENSENSE3_ACCEL_ODR_1KHZ:
+ inv->accel_samplerate = 1000;
+ break;
+ case INVENSENSE3_ACCEL_ODR_200HZ:
+ inv->accel_samplerate = 200;
+ break;
+ case INVENSENSE3_ACCEL_ODR_100HZ:
+ inv->accel_samplerate = 100;
+ break;
+ case INVENSENSE3_ACCEL_ODR_50HZ:
+ inv->accel_samplerate = 50;
+ break;
+ case INVENSENSE3_ACCEL_ODR_25HZ:
+ inv->accel_samplerate = 25;
+ break;
+ case INVENSENSE3_ACCEL_ODR_12_5HZ:
+ inv->accel_samplerate = 12.5;
+ break;
+ case INVENSENSE3_ACCEL_ODR_6_25HZ:
+ inv->accel_samplerate = 6.25;
+ break;
+ case INVENSENSE3_ACCEL_ODR_3_125HZ:
+ inv->accel_samplerate = 3.125;
+ break;
+ case INVENSENSE3_ACCEL_ODR_1_5625HZ:
+ inv->accel_samplerate = 1.5625;
+ break;
+ case INVENSENSE3_ACCEL_ODR_500HZ:
+ inv->accel_samplerate = 500;
+ break;
+ }
+
+ /* Set the default values */
+ imu_set_defaults_gyro(inv->abi_id, NULL, NULL, invensense3_gyro_scale[inv->gyro_range]);
+ imu_set_defaults_accel(inv->abi_id, NULL, NULL, invensense3_accel_scale[inv->accel_range]);
+}
+
+/**
+ * @brief Write a register based on a combined bank/regsiter value
+ *
+ * @param inv The invensense v3 instance
+ * @param bank_reg The bank is shifted 8 bits left, adn register is &0xFF
+ * @param value The value to write to the register
+ * @return true Whenever the register write was started
+ * @return false First we are busy switching the register bank
+ */
+static bool invensense3_register_write(struct invensense3_t *inv, uint16_t bank_reg, uint8_t value) {
+ /* Split the register and bank */
+ uint8_t bank = bank_reg >> 8;
+ uint8_t reg = bank_reg & 0xFF;
+
+ /* Switch the register bank if needed */
+ if(invensense3_select_bank(inv, bank)) {
+ return false;
+ }
+
+ inv->tx_buffer[0] = reg;
+ inv->tx_buffer[1] = value;
+
+ /* SPI transaction */
+ if(inv->bus == INVENSENSE3_SPI) {
+ inv->spi.trans.output_length = 2;
+ inv->spi.trans.input_length = 0;
+ spi_submit(inv->spi.p, &(inv->spi.trans));
+ }
+ /* I2C transaction */
+ else {
+ i2c_transmit(inv->i2c.p, &(inv->i2c.trans), inv->i2c.slave_addr, 2);
+ }
+
+ return true;
+}
+
+/**
+ * @brief Read a register based on a combined bank/regsiter value
+ *
+ * @param inv The invensense v3 instance
+ * @param bank_reg The bank is shifted 8 bits left, adn register is &0xFF
+ * @param size The size to read (already 1 is added for the transmission of the register to read)
+ * @return true If we initiated the register read succesfully
+ * @return false First we are busy switching the register bank
+ */
+static bool invensense3_register_read(struct invensense3_t *inv, uint16_t bank_reg, uint16_t size) {
+ /* Split the register and bank */
+ uint8_t bank = bank_reg >> 8;
+ uint8_t reg = bank_reg & 0xFF;
+
+ /* Switch the register bank if needed */
+ if(invensense3_select_bank(inv, bank)) {
+ return false;
+ }
+
+ inv->tx_buffer[0] = reg | INV3_READ_FLAG;
+ /* SPI transaction */
+ if(inv->bus == INVENSENSE3_SPI) {
+ inv->spi.trans.output_length = 2;
+ inv->spi.trans.input_length = 1 + size;
+ inv->tx_buffer[1] = 0;
+ spi_submit(inv->spi.p, &(inv->spi.trans));
+ }
+ /* I2C transaction */
+ else {
+ i2c_transceive(inv->i2c.p, &(inv->i2c.trans), inv->i2c.slave_addr, 1, (1 + size));
+ }
+
+ return true;
+}
+
+/**
+ * @brief Select the correct register bank
+ *
+ * @param inv The invensense v3 instance
+ * @param bank The bank ID to select
+ * @return true The bank change has been requested
+ * @return false The register bank is already correct
+ */
+static bool invensense3_select_bank(struct invensense3_t *inv, uint8_t bank) {
+ /* If we already selected the correct bank continue */
+ if(inv->register_bank == bank)
+ return false;
+
+ inv->tx_buffer[0] = INV3REG_BANK_SEL;
+ inv->tx_buffer[1] = bank;
+ /* SPI transaction */
+ if(inv->bus == INVENSENSE3_SPI) {
+ inv->spi.trans.output_length = 2;
+ inv->spi.trans.input_length = 0;
+ spi_submit(inv->spi.p, &(inv->spi.trans));
+ }
+ /* I2C transaction */
+ else {
+ i2c_transmit(inv->i2c.p, &(inv->i2c.trans), inv->i2c.slave_addr, 2);
+ }
+
+ return true;
+}
+
+/**
+ * @brief Reset FIFO (can be useful in some situations)
+ *
+ * @param inv The invensense v3 instance
+ * @return true When reset is done
+ */
+static bool invensense3_reset_fifo(struct invensense3_t *inv) {
+ if(invensense3_register_write(inv, INV3REG_SIGNAL_PATH_RESET, BIT_SIGNAL_PATH_RESET_FIFO_FLUSH))
+ return true;
+ return false;
+}
+
+/**
+ * @brief Configure the Invensense 3 device register by register
+ *
+ * @param inv The invensense v3 instance
+ * @return true When the configuration is completed
+ * @return false Still busy configuring
+ */
+static bool invensense3_config(struct invensense3_t *inv) {
+ switch(inv->config_idx) {
+ case 0:
+ /* Reset the device */
+ if(invensense3_register_write(inv, INV3REG_DEVICE_CONFIG, BIT_DEVICE_CONFIG_SOFT_RESET_CONFIG))
+ inv->config_idx++;
+ inv->timer = get_sys_time_usec();
+ break;
+
+ case 1:
+ /* Because reset takes time wait ~5ms */
+ if((get_sys_time_usec() - inv->timer) < 5e3)
+ break;
+
+ /* Start the accel en gyro in low noise mode */
+ if(invensense3_register_write(inv, INV3REG_PWR_MGMT0, (ACCEL_MODE_LN << ACCEL_MODE_SHIFT) | (GYRO_MODE_LN << GYRO_MODE_SHIFT)))
+ inv->config_idx++;
+ inv->timer = get_sys_time_usec();
+ break;
+
+ case 2:
+ /* Because starting takes time wait ~1ms */
+ if((get_sys_time_usec() - inv->timer) < 1e3)
+ break;
+
+ /* Configure the gyro ODR/FS */
+ if(invensense3_register_write(inv, INV3REG_GYRO_CONFIG0, (inv->gyro_range << GYRO_FS_SEL_SHIFT) | (inv->gyro_odr << GYRO_ODR_SHIFT)))
+ inv->config_idx++;
+ break;
+
+ case 3: {
+ /* Configure the accel ODR/FS */
+ uint8_t accel_config = (inv->accel_odr << ACCEL_ODR_SHIFT);
+ if(inv->device == INVENSENSE3_ICM40609)
+ accel_config |= inv->accel_range << ACCEL_FS_SEL_SHIFT;
+ else
+ accel_config |= (inv->accel_range - 1) << ACCEL_FS_SEL_SHIFT;
+
+ if(invensense3_register_write(inv, INV3REG_ACCEL_CONFIG0, accel_config))
+ inv->config_idx++;
+ break;
+ }
+
+ case 4:
+ /* Configure gyro AAF enable */
+ if(invensense3_register_write(inv, INV3REG_GYRO_CONFIG_STATIC2, 0x00))
+ inv->config_idx++;
+ break;
+ case 5:
+ /* Configure gyro AAF DELT */
+ if(invensense3_register_write(inv, INV3REG_GYRO_CONFIG_STATIC3, inv->gyro_aaf_regs[1]))
+ inv->config_idx++;
+ break;
+ case 6:
+ /* Configure gyro AAF DELTSQR lower */
+ if(invensense3_register_write(inv, INV3REG_GYRO_CONFIG_STATIC4, (inv->gyro_aaf_regs[2]&0xFF)))
+ inv->config_idx++;
+ break;
+ case 7:
+ /* Configure gyro AAF DELTSQR upper and bitshift */
+ if(invensense3_register_write(inv, INV3REG_GYRO_CONFIG_STATIC5, (inv->gyro_aaf_regs[3] << GYRO_AAF_BITSHIFT_SHIFT) | ((inv->gyro_aaf_regs[2]>>8) & 0x0F)))
+ inv->config_idx++;
+ break;
+ case 8:
+ /* Configure accel AAF enable and DELT */
+ if(invensense3_register_write(inv, INV3REG_ACCEL_CONFIG_STATIC2, (inv->accel_aaf_regs[1] << ACCEL_AAF_DELT_SHIFT)))
+ inv->config_idx++;
+ break;
+ case 9:
+ /* Configure accel AAF DELTSQR lower */
+ if(invensense3_register_write(inv, INV3REG_ACCEL_CONFIG_STATIC3, (inv->accel_aaf_regs[2]&0xFF)))
+ inv->config_idx++;
+ break;
+ case 10:
+ /* Configure accel AAF DELTSQR upper and bitshift */
+ if(invensense3_register_write(inv, INV3REG_ACCEL_CONFIG_STATIC4, (inv->accel_aaf_regs[3] << ACCEL_AAF_BITSHIFT_SHIFT) | ((inv->accel_aaf_regs[2]>>8) & 0x0F)))
+ inv->config_idx++;
+ break;
+
+ case 11:
+ /* FIFO count in records (little-endian data) */
+ if(invensense3_register_write(inv, INV3REG_INTF_CONFIG0, FIFO_COUNT_REC))
+ inv->config_idx++;
+ break;
+ case 12:
+ /* FIFO Stop-on-Full mode (enable the FIFO) */
+ if(invensense3_register_write(inv, INV3REG_FIFO_CONFIG , FIFO_CONFIG_MODE_STOP_ON_FULL << FIFO_CONFIG_MODE_SHIFT))
+ inv->config_idx++;
+ break;
+ case 13:
+ /* FIFO content: enable accel, gyro, temperature */
+ if(invensense3_register_write(inv, INV3REG_FIFO_CONFIG1 , BIT_FIFO_CONFIG1_ACCEL_EN |
+ BIT_FIFO_CONFIG1_GYRO_EN | BIT_FIFO_CONFIG1_TEMP_EN))
+ inv->config_idx++;
+ break;
+ case 14:
+ /* Set FIFO watermark to 1 (so that INT is triggered for each packet) */
+ if(invensense3_register_write(inv, INV3REG_FIFO_CONFIG2, 20))
+ inv->config_idx++;
+ break;
+ case 15:
+ /* Set FIFO watermark to 1 (so that INT is triggered for each packet) */
+ if(invensense3_register_write(inv, INV3REG_FIFO_CONFIG3, 0x00))
+ inv->config_idx++;
+ break;
+ case 16:
+ /* Enable interrupt pin/status */
+ switch(inv->parser) {
+ case INVENSENSE3_PARSER_REGISTERS:
+ if(invensense3_register_write(inv, INV3REG_INT_SOURCE0, BIT_UI_DRDY_INT_EN))
+ inv->config_idx++;
+ break;
+ case INVENSENSE3_PARSER_FIFO:
+ if(invensense3_register_write(inv, INV3REG_INT_SOURCE0, BIT_FIFO_FULL_INT_EN | BIT_FIFO_THS_INT_EN))
+ inv->config_idx++;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 17:
+ /* Interrupt pins ASYNC_RESET configuration */
+ // Datasheet: "User should change setting to 0 from default setting of 1, for proper INT1 and INT2 pin operation"
+ if(invensense3_register_write(inv, INV3REG_INT_CONFIG1, BIT_INT_ASYNC_RESET))
+ inv->config_idx++;
+ break;
+ case 18:
+ /* FIFO flush */
+ if(invensense3_reset_fifo(inv))
+ inv->config_idx++;
+ break;
+
+ default:
+ inv->timer = 0;
+ return true;
+ }
+ return false;
+}
+
+static int samples_from_odr(int odr) {
+ float freq = 0;
+ if(odr < INVENSENSE3_GYRO_ODR_200HZ) {
+ freq = 32000 / pow(2, odr-INVENSENSE3_GYRO_ODR_32KHZ);
+ }
+ else if(odr < INVENSENSE3_GYRO_ODR_500HZ) {
+ freq = 200 / pow(2, odr-INVENSENSE3_GYRO_ODR_200HZ);
+ }
+ else if(odr == INVENSENSE3_GYRO_ODR_500HZ) {
+ freq = 500;
+ } else {
+ // error
+ }
+ return ceilf(freq/PERIODIC_FREQUENCY);
+}
diff --git a/sw/airborne/peripherals/invensense3.h b/sw/airborne/peripherals/invensense3.h
new file mode 100644
index 0000000000..05a1ba2a3f
--- /dev/null
+++ b/sw/airborne/peripherals/invensense3.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 Freek van Tienen
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file peripherals/invensense3.h
+ *
+ * Driver for the Invensense V3 IMUs
+ * ICM40605, ICM40609, ICM42605, IIM42652 and ICM42688
+ */
+
+#ifndef INVENSENSE3_H
+#define INVENSENSE3_H
+
+#include "std.h"
+#include "mcu_periph/spi.h"
+#include "mcu_periph/i2c.h"
+
+/* This sensor has an option to request little-endian data */
+// Hold 22 measurements + 3 for the register address and length
+#define INVENSENSE3_FIFO_BUFFER_LEN 22
+#define INVENSENSE3_BUFFER_SIZE INVENSENSE3_FIFO_BUFFER_LEN * 20 + 3 // 20 bytes is the maximum sample size
+
+/* Invensense v3 SPI peripheral */
+struct invensense3_spi_t {
+ struct spi_periph *p; ///< Peripheral device for communication
+ uint8_t slave_idx; ///< Slave index used for Slave Select
+ struct spi_transaction trans; ///< Transaction used during configuration and measurements
+
+ uint8_t tx_buf[2]; ///< Transmit buffer
+ uint8_t rx_buf[INVENSENSE3_BUFFER_SIZE]; ///< Receive buffer
+};
+
+/* Invensense v3 I2C peripheral */
+struct invensense3_i2c_t {
+ struct i2c_periph *p; ///< Peripheral device for communication
+ uint8_t slave_addr; ///< The I2C slave address on the bus
+ struct i2c_transaction trans; ///< TRansaction used during configuration and measurements
+};
+
+/* Possible communication busses for the invense V3 driver */
+enum invensense3_bus_t {
+ INVENSENSE3_SPI,
+ INVENSENSE3_I2C
+};
+
+/* Different states the invensense v3 driver can be in */
+enum invensense3_status_t {
+ INVENSENSE3_IDLE,
+ INVENSENSE3_CONFIG,
+ INVENSENSE3_RUNNING
+};
+
+/* Different parsers of the invensense v3 driver */
+enum invensense3_parser_t {
+ INVENSENSE3_PARSER_REGISTERS,
+ INVENSENSE3_PARSER_FIFO
+};
+
+enum invensense3_fifo_packet_t {
+ INVENSENSE3_SAMPLE_SIZE_PK1,
+ INVENSENSE3_SAMPLE_SIZE_PK2,
+ INVENSENSE3_SAMPLE_SIZE_PK3,
+ INVENSENSE3_SAMPLE_SIZE_PK4
+};
+
+/* Different device types compatible with the invensense v3 driver */
+enum invensense3_device_t {
+ INVENSENSE3_UNKOWN,
+ INVENSENSE3_ICM40605,
+ INVENSENSE3_ICM40609,
+ INVENSENSE3_ICM42605,
+ INVENSENSE3_IIM42652,
+ INVENSENSE3_ICM42688
+};
+
+/* The gyro output data rate configuration */
+enum invensense3_gyro_odr_t {
+ INVENSENSE3_GYRO_ODR_32KHZ = 1, ///< Not possible for ICM40605 and ICM42605
+ INVENSENSE3_GYRO_ODR_16KHZ, ///< Not possible for ICM40605 and ICM42605
+ INVENSENSE3_GYRO_ODR_8KHZ,
+ INVENSENSE3_GYRO_ODR_4KHZ,
+ INVENSENSE3_GYRO_ODR_2KHZ,
+ INVENSENSE3_GYRO_ODR_1KHZ,
+ INVENSENSE3_GYRO_ODR_200HZ,
+ INVENSENSE3_GYRO_ODR_100HZ,
+ INVENSENSE3_GYRO_ODR_50HZ,
+ INVENSENSE3_GYRO_ODR_25HZ,
+ INVENSENSE3_GYRO_ODR_12_5HZ,
+ INVENSENSE3_GYRO_ODR_6_25HZ,
+ INVENSENSE3_GYRO_ODR_3_125HZ,
+ INVENSENSE3_GYRO_ODR_1_5625HZ,
+ INVENSENSE3_GYRO_ODR_500HZ
+};
+
+/* The gyro range in degrees per second(dps) */
+enum invensense3_gyro_range_t {
+ INVENSENSE3_GYRO_RANGE_2000DPS,
+ INVENSENSE3_GYRO_RANGE_1000DPS,
+ INVENSENSE3_GYRO_RANGE_500DPS,
+ INVENSENSE3_GYRO_RANGE_250DPS,
+ INVENSENSE3_GYRO_RANGE_125DPS,
+ INVENSENSE3_GYRO_RANGE_62_5DPS,
+ INVENSENSE3_GYRO_RANGE_31_25DPS,
+ INVENSENSE3_GYRO_RANGE_15_625DPS
+};
+
+/* The accelerometer output data rate configuration */
+enum invensense3_accel_odr_t {
+ INVENSENSE3_ACCEL_ODR_32KHZ = 1, ///< Not possible for ICM40605 and ICM42605
+ INVENSENSE3_ACCEL_ODR_16KHZ, ///< Not possible for ICM40605 and ICM42605
+ INVENSENSE3_ACCEL_ODR_8KHZ,
+ INVENSENSE3_ACCEL_ODR_4KHZ,
+ INVENSENSE3_ACCEL_ODR_2KHZ,
+ INVENSENSE3_ACCEL_ODR_1KHZ,
+ INVENSENSE3_ACCEL_ODR_200HZ,
+ INVENSENSE3_ACCEL_ODR_100HZ,
+ INVENSENSE3_ACCEL_ODR_50HZ,
+ INVENSENSE3_ACCEL_ODR_25HZ,
+ INVENSENSE3_ACCEL_ODR_12_5HZ,
+ INVENSENSE3_ACCEL_ODR_6_25HZ,
+ INVENSENSE3_ACCEL_ODR_3_125HZ,
+ INVENSENSE3_ACCEL_ODR_1_5625HZ,
+ INVENSENSE3_ACCEL_ODR_500HZ
+};
+
+/* The accelerometer range in G */
+enum invensense3_accel_range_t {
+ INVENSENSE3_ACCEL_RANGE_32G, ///< Only possible for ICM40609
+ INVENSENSE3_ACCEL_RANGE_16G,
+ INVENSENSE3_ACCEL_RANGE_8G,
+ INVENSENSE3_ACCEL_RANGE_4G,
+ INVENSENSE3_ACCEL_RANGE_2G
+};
+
+/* Main invensense v3 device structure */
+struct invensense3_t {
+ uint8_t abi_id; ///< The ABI id used to broadcast the device measurements
+ enum invensense3_status_t status; ///< Status of the invensense v3 device
+ enum invensense3_device_t device; ///< The device type detected
+ enum invensense3_parser_t parser; ///< Parser of the device
+
+ enum invensense3_bus_t bus; ///< The communication bus used to connect the device SPI/I2C
+ union {
+ struct invensense3_spi_t spi; ///< SPI specific configuration
+ struct invensense3_i2c_t i2c; ///< I2C specific configuration
+ };
+ uint8_t* rx_buffer;
+ uint8_t* tx_buffer;
+ uint16_t* rx_length;
+
+ uint8_t register_bank; ///< The current register bank communicating with
+ uint8_t config_idx; ///< The current configuration index
+ uint32_t timer; ///< Used to time operations during configuration (samples left during measuring)
+
+ enum invensense3_gyro_odr_t gyro_odr; ///< Gyro Output Data Rate configuration
+ enum invensense3_gyro_range_t gyro_range; ///< Gyro range configuration
+ uint16_t gyro_aaf; ///< Gyro Anti-alias filter 3dB Bandwidth configuration [Hz]
+ uint16_t gyro_aaf_regs[4]; ///< Gyro Anti-alias filter register values
+ enum invensense3_accel_odr_t accel_odr; ///< Accelerometer Output Data Rate configuration
+ enum invensense3_accel_range_t accel_range; ///< Accelerometer range configuration
+ uint16_t accel_aaf; ///< Accelerometer Anti-alias filter 3dB Bandwidth configuration [Hz]
+ uint16_t accel_aaf_regs[4]; ///< Accelerometer Anti-alias filter register values
+ enum invensense3_fifo_packet_t sample_size; ///< FIFO packet size
+ int sample_numbers; ///< expected FIFO packet number, assuming reading at PERIODIC_FREQUENCY
+ float gyro_samplerate; ///< Sample rate in Hz from the gyro_odr
+ float accel_samplerate; ///< Sample rate in Hz from the accel_odr
+};
+
+/* External functions */
+void invensense3_init(struct invensense3_t *inv);
+void invensense3_periodic(struct invensense3_t *inv);
+void invensense3_event(struct invensense3_t *inv);
+
+#endif // INVENSENSE3_H
diff --git a/sw/airborne/peripherals/invensense3_regs.h b/sw/airborne/peripherals/invensense3_regs.h
new file mode 100644
index 0000000000..5238655910
--- /dev/null
+++ b/sw/airborne/peripherals/invensense3_regs.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2022 Freek van Tienen
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file peripherals/invensense3_regs.h
+ *
+ * Register and address definitions for the Invensense V3 from ardupilot.
+ */
+
+#ifndef INVENSENSE3_REGS_H
+#define INVENSENSE3_REGS_H
+
+#define INV3_BANK0 0x00U
+#define INV3_BANK1 0x01U
+#define INV3_BANK2 0x02U
+#define INV3_BANK3 0x03U
+
+
+#define INV3REG(b, r) ((((uint16_t)b) << 8)|(r))
+#define INV3_READ_FLAG 0x80
+
+//Register Map
+#define INV3REG_DEVICE_CONFIG INV3REG(INV3_BANK0,0x11U)
+# define BIT_DEVICE_CONFIG_SOFT_RESET_CONFIG 0x01
+# define BIT_DEVICE_CONFIG_SPI_MODE 0x10
+#define INV3REG_FIFO_CONFIG INV3REG(INV3_BANK0,0x16U)
+# define FIFO_CONFIG_MODE_BYPASS 0x00
+# define FIFO_CONFIG_MODE_STREAM_TO_FIFO 0x01
+# define FIFO_CONFIG_MODE_STOP_ON_FULL 0x02
+# define FIFO_CONFIG_MODE_SHIFT 0x06
+#define INV3REG_TEMP_DATA1 INV3REG(INV3_BANK0,0x1DU)
+#define INV3REG_ACCEL_DATA_X1 INV3REG(INV3_BANK0,0x1FU)
+#define INV3REG_INT_STATUS INV3REG(INV3_BANK0,0x2DU)
+#define INV3REG_FIFO_COUNTH INV3REG(INV3_BANK0,0x2EU)
+#define INV3REG_FIFO_COUNTL INV3REG(INV3_BANK0,0x2FU)
+#define INV3REG_FIFO_DATA INV3REG(INV3_BANK0,0x30U)
+#define INV3REG_SIGNAL_PATH_RESET INV3REG(INV3_BANK0,0x4BU)
+# define BIT_SIGNAL_PATH_RESET_FIFO_FLUSH 0x02
+# define BIT_SIGNAL_PATH_RESET_TMST_STROBE 0x04
+# define BIT_SIGNAL_PATH_RESET_ABORT_AND_RESET 0x08
+# define BIT_SIGNAL_PATH_RESET_DMP_MEM_RESET_EN 0x20
+# define BIT_SIGNAL_PATH_RESET_DMP_INIT_EN 0x40
+#define INV3REG_INTF_CONFIG0 INV3REG(INV3_BANK0,0x4CU)
+# define UI_SIFS_CFG_SPI_DIS 0x02
+# define UI_SIFS_CFG_I2C_DIS 0x03
+# define UI_SIFS_CFG_SHIFT 0x00
+# define SENSOR_DATA_BIG_ENDIAN 0x10
+# define FIFO_COUNT_BIG_ENDIAN 0x20
+# define FIFO_COUNT_REC 0x40
+# define FIFO_HOLD_LAST_DATA_EN 0x80
+#define INV3REG_PWR_MGMT0 INV3REG(INV3_BANK0,0x4EU)
+# define ACCEL_MODE_OFF 0x00
+# define ACCEL_MODE_LN 0x03
+# define ACCEL_MODE_SHIFT 0x00
+# define GYRO_MODE_OFF 0x00
+# define GYRO_MODE_LN 0x03
+# define GYRO_MODE_SHIFT 0x02
+# define BIT_PWR_MGMT_IDLE 0x08
+# define BIT_PWM_MGMT_TEMP_DIS 0x10
+#define INV3REG_GYRO_CONFIG0 INV3REG(INV3_BANK0,0x4FU)
+# define GYRO_ODR_32KHZ 0x01
+# define GYRO_ODR_16KHZ 0x02
+# define GYRO_ODR_8KHZ 0x03
+# define GYRO_ODR_4KHZ 0x04
+# define GYRO_ODR_2KHZ 0x05
+# define GYRO_ODR_1KHZ 0x06
+# define GYRO_ODR_200HZ 0x07
+# define GYRO_ODR_100HZ 0x08
+# define GYRO_ODR_50HZ 0x09
+# define GYRO_ODR_25HZ 0x0A
+# define GYRO_ODR_12_5HZ 0x0B
+# define GYRO_ODR_500HZ 0x0F
+# define GYRO_ODR_SHIFT 0x00
+# define GYRO_FS_SEL_2000DPS 0x00
+# define GYRO_FS_SEL_1000DPS 0x01
+# define GYRO_FS_SEL_500DPS 0x02
+# define GYRO_FS_SEL_250DPS 0x03
+# define GYRO_FS_SEL_125DPS 0x04
+# define GYRO_FS_SEL_62_5DPS 0x05
+# define GYRO_FS_SEL_31_25DPS 0x06
+# define GYRO_FS_SEL_15_625DPS 0x07
+# define GYRO_FS_SEL_SHIFT 0x05
+#define INV3REG_ACCEL_CONFIG0 INV3REG(INV3_BANK0,0x50U)
+# define ACCEL_ODR_32KHZ 0x01
+# define ACCEL_ODR_16KHZ 0x02
+# define ACCEL_ODR_8KHZ 0x03
+# define ACCEL_ODR_4KHZ 0x04
+# define ACCEL_ODR_2KHZ 0x05
+# define ACCEL_ODR_1KHZ 0x06
+# define ACCEL_ODR_200HZ 0x07
+# define ACCEL_ODR_100HZ 0x08
+# define ACCEL_ODR_50HZ 0x09
+# define ACCEL_ODR_25HZ 0x0A
+# define ACCEL_ODR_12_5HZ 0x0B
+# define ACCEL_ODR_6_25HZ 0x0C
+# define ACCEL_ODR_3_125HZ 0x0D
+# define ACCEL_ODR_1_5625HZ 0x0E
+# define ACCEL_ODR_500HZ 0x0F
+# define ACCEL_ODR_SHIFT 0x00
+# define ACCEL_FS_SEL_16G 0x00
+# define ACCEL_FS_SEL_8G 0x01
+# define ACCEL_FS_SEL_4G 0x02
+# define ACCEL_FS_SEL_2G 0x03
+# define ACCEL_FS_SEL_SHIFT 0x05
+#define INV3REG_GYRO_CONFIG1 INV3REG(INV3_BANK0,0x51U)
+#define INV3REG_GYRO_ACCEL_CONFIG0 INV3REG(INV3_BANK0,0x52U)
+#define INV3REG_ACCEL_CONFIG1 INV3REG(INV3_BANK0,0x53U)
+#define INV3REG_TMST_CONFIG INV3REG(INV3_BANK0,0x54U)
+# define BIT_TMST_CONFIG_TMST_EN 0x01
+#define INV3REG_FIFO_CONFIG1 INV3REG(INV3_BANK0,0x5FU)
+# define BIT_FIFO_CONFIG1_ACCEL_EN 0x01
+# define BIT_FIFO_CONFIG1_GYRO_EN 0x02
+# define BIT_FIFO_CONFIG1_TEMP_EN 0x04
+# define BIT_FIFO_CONFIG1_TMST_FSYNC_EN 0x08
+# define BIT_FIFO_CONFIG1_HIRES_EN 0x10
+# define BIT_FIFO_CONFIG1_WM_GT_TH 0x20
+# define BIT_FIFO_CONFIG1_RESUME_PARTIAL_RD 0x40
+#define INV3REG_FIFO_CONFIG2 INV3REG(INV3_BANK0,0x60U)
+#define INV3REG_FIFO_CONFIG3 INV3REG(INV3_BANK0,0x61U)
+#define INV3REG_INT_SOURCE0 INV3REG(INV3_BANK0,0x65U)
+#define INV3REG_INT_SOURCE3 INV3REG(INV3_BANK0,0x68U)
+# define BIT_FIFO_FULL_INT_EN 0x02
+# define BIT_FIFO_THS_INT_EN 0x04
+# define BIT_UI_DRDY_INT_EN 0x08
+#define INV3REG_INT_CONFIG1 INV3REG(INV3_BANK0,0x64U)
+# define BIT_INT_ASYNC_RESET 0x10
+#define INV3REG_WHO_AM_I INV3REG(INV3_BANK0,0x75U)
+#define INV3REG_GYRO_CONFIG_STATIC2 INV3REG(INV3_BANK1,0x0BU)
+# define BIT_GYRO_NF_DIS 0x01
+# define BIT_GYRO_AAF_DIS 0x02
+#define INV3REG_GYRO_CONFIG_STATIC3 INV3REG(INV3_BANK1,0x0CU)
+# define GYRO_AAF_DELT_SHIFT 0x00
+#define INV3REG_GYRO_CONFIG_STATIC4 INV3REG(INV3_BANK1,0x0DU)
+# define GYRO_AAF_DELTSQR_LOW_SHIFT 0x00 //[0:7]
+#define INV3REG_GYRO_CONFIG_STATIC5 INV3REG(INV3_BANK1,0x0EU)
+# define GYRO_AAF_DELTSQR_HIGH_SHIFT 0x00 //[11:8]
+# define GYRO_AAF_BITSHIFT_SHIFT 0x04
+#define INV3REG_GYRO_CONFIG_STATIC6 INV3REG(INV3_BANK1,0x0FU)
+# define GYRO_X_NF_COSWZ_LOW_SHIFT 0x00 //[0:7]
+#define INV3REG_GYRO_CONFIG_STATIC7 INV3REG(INV3_BANK1,0x10U)
+# define GYRO_Y_NF_COSWZ_LOW_SHIFT 0x00 //[0:7]
+#define INV3REG_GYRO_CONFIG_STATIC8 INV3REG(INV3_BANK1,0x11U)
+# define GYRO_Z_NF_COSWZ_LOW_SHIFT 0x00 //[0:7]
+#define INV3REG_GYRO_CONFIG_STATIC9 INV3REG(INV3_BANK1,0x12U)
+# define GYRO_X_NF_COSWZ_HIGH_SHIFT 0x00 //[8]
+# define GYRO_Y_NF_COSWZ_HIGH_SHIFT 0x01 //[8]
+# define GYRO_Z_NF_COSWZ_HIGH_SHIFT 0x02 //[8]
+# define GYRO_X_NF_COSWZ_SEL_SHIFT 0x03 //[0]
+# define GYRO_Y_NF_COSWZ_SEL_SHIFT 0x04 //[0]
+# define GYRO_Z_NF_COSWZ_SEL_SHIFT 0x05 //[0]
+#define INV3REG_GYRO_CONFIG_STATIC10 INV3REG(INV3_BANK1,0x13U)
+# define GYRO_NF_BW_SEL_SHIFT 0x04
+#define INV3REG_ACCEL_CONFIG_STATIC2 INV3REG(INV3_BANK2,0x03U)
+# define ACCEL_AAF_DIS 0x01
+# define ACCEL_AAF_DELT_SHIFT 0x01
+#define INV3REG_ACCEL_CONFIG_STATIC3 INV3REG(INV3_BANK2,0x04U)
+# define ACCEL_AAF_DELTSQR_LOW_SHIFT 0x00 //[0:7]
+#define INV3REG_ACCEL_CONFIG_STATIC4 INV3REG(INV3_BANK2,0x05U)
+# define ACCEL_AAF_DELTSQR_HIGH_SHIFT 0x00 //[11:8]
+# define ACCEL_AAF_BITSHIFT_SHIFT 0x04
+
+#define INV3REG_BANK_SEL 0x76
+
+// WHOAMI values
+#define INV3_WHOAMI_ICM40605 0x33
+#define INV3_WHOAMI_ICM40609 0x3b
+#define INV3_WHOAMI_ICM42605 0x42
+#define INV3_WHOAMI_ICM42688 0x47
+#define INV3_WHOAMI_IIM42652 0x6f
+#define INV3_WHOAMI_ICM42670 0x67
+
+#endif /* INVENSENSE3_REGS_H */
diff --git a/sw/tools/px4/cube_orangeplus.prototype b/sw/tools/px4/cube_orangeplus.prototype
new file mode 100644
index 0000000000..c53da9aace
--- /dev/null
+++ b/sw/tools/px4/cube_orangeplus.prototype
@@ -0,0 +1,13 @@
+{
+ "board_id": 1063,
+ "magic": "PX4FWv1",
+ "description": "Firmware for the CubePilot CubeOrange+ board",
+ "image": "",
+ "build_time": 0,
+ "summary": "CubeOrange+",
+ "version": "0.1",
+ "image_size": 0,
+ "image_maxsize": 1966080,
+ "git_identity": "",
+ "board_revision": 0
+}
\ No newline at end of file