diff --git a/conf/firmwares/subsystems/shared/imu_mpu9250_i2c.makefile b/conf/firmwares/subsystems/shared/imu_mpu9250_i2c.makefile
new file mode 100644
index 00000000000..e08d442631c
--- /dev/null
+++ b/conf/firmwares/subsystems/shared/imu_mpu9250_i2c.makefile
@@ -0,0 +1,54 @@
+# Hey Emacs, this is a -*- makefile -*-
+#
+# MPU9250 IMU via I2C
+#
+
+# for fixedwing firmware and ap only
+ifeq ($(TARGET), ap)
+ IMU_MPU9250_CFLAGS = -DUSE_IMU
+endif
+
+IMU_MPU9250_CFLAGS += -DIMU_TYPE_H=\"imu/imu_mpu9250_i2c.h\"
+IMU_MPU9250_SRCS = $(SRC_SUBSYSTEMS)/imu.c
+IMU_MPU9250_SRCS += $(SRC_SUBSYSTEMS)/imu/imu_mpu9250_i2c.c
+IMU_MPU9250_SRCS += peripherals/mpu9250.c
+IMU_MPU9250_SRCS += peripherals/mpu9250_i2c.c
+
+# Magnetometer
+IMU_MPU9250_SRCS += peripherals/ak8963.c
+
+
+# set default i2c bus
+ifeq ($(ARCH), lpc21)
+MPU9250_I2C_DEV ?= i2c0
+else ifeq ($(ARCH), stm32)
+MPU9250_I2C_DEV ?= i2c2
+endif
+
+ifeq ($(TARGET), ap)
+ifndef MPU9250_I2C_DEV
+$(error Error: MPU9250_I2C_DEV not configured!)
+endif
+endif
+
+# convert i2cx to upper/lower case
+MPU9250_I2C_DEV_UPPER=$(shell echo $(MPU9250_I2C_DEV) | tr a-z A-Z)
+MPU9250_I2C_DEV_LOWER=$(shell echo $(MPU9250_I2C_DEV) | tr A-Z a-z)
+
+IMU_MPU9250_CFLAGS += -DIMU_MPU9250_I2C_DEV=$(MPU9250_I2C_DEV_LOWER)
+IMU_MPU9250_CFLAGS += -DUSE_$(MPU9250_I2C_DEV_UPPER)
+
+
+# Keep CFLAGS/Srcs for imu in separate expression so we can assign it to other targets
+
+ap.CFLAGS += $(IMU_MPU9250_CFLAGS)
+ap.srcs += $(IMU_MPU9250_SRCS)
+
+test_imu.CFLAGS += $(IMU_MPU9250_CFLAGS)
+test_imu.srcs += $(IMU_MPU9250_SRCS)
+
+
+#
+# NPS simulator
+#
+include $(CFG_SHARED)/imu_nps.makefile
diff --git a/conf/modules/imu_mpu9250.xml b/conf/modules/imu_mpu9250.xml
new file mode 100644
index 00000000000..c1b39854ed7
--- /dev/null
+++ b/conf/modules/imu_mpu9250.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+ Test module for the mpu9250 with I2C
+ Report RAW values on telemetry
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sw/airborne/modules/sensors/imu_mpu9250.c b/sw/airborne/modules/sensors/imu_mpu9250.c
new file mode 100644
index 00000000000..1d72446d4fe
--- /dev/null
+++ b/sw/airborne/modules/sensors/imu_mpu9250.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 Gautier Hattenberger
+ *
+ * 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, see
+ * .
+ */
+
+/**
+ * @file "modules/sensors/imu_mpu9250.c"
+ * @author Gautier Hattenberger
+ *
+ * Test module for the mpu9250
+ */
+
+#include "modules/sensors/imu_mpu9250.h"
+
+// Default I2C address
+#ifndef IMU_MPU9250_ADDR
+#define IMU_MPU9250_ADDR MPU9250_ADDR
+#endif
+
+struct Mpu9250_I2c mpu9250;
+
+void imu_mpu9250_init(void)
+{
+ mpu9250_i2c_init(&mpu9250, &(IMU_MPU9250_I2C_DEV), IMU_MPU9250_ADDR);
+}
+
+void imu_mpu9250_periodic(void)
+{
+ mpu9250_i2c_periodic(&mpu9250);
+}
+
+void imu_mpu9250_event(void)
+{
+ mpu9250_i2c_event(&mpu9250);
+}
+
+#include "math/pprz_algebra_int.h"
+#include "subsystems/datalink/downlink.h"
+
+void imu_mpu9250_report(void)
+{
+ struct Int32Vect3 accel = {
+ (int32_t)(mpu9250.data_accel.vect.x),
+ (int32_t)(mpu9250.data_accel.vect.y),
+ (int32_t)(mpu9250.data_accel.vect.z)
+ };
+ DOWNLINK_SEND_IMU_ACCEL_RAW(DefaultChannel, DefaultDevice, &accel.x, &accel.y, &accel.z);
+
+ struct Int32Rates rates = {
+ (int32_t)(mpu9250.data_rates.rates.p),
+ (int32_t)(mpu9250.data_rates.rates.q),
+ (int32_t)(mpu9250.data_rates.rates.r)
+ };
+ DOWNLINK_SEND_IMU_GYRO_RAW(DefaultChannel, DefaultDevice, &rates.p, &rates.q, &rates.r);
+
+ struct Int32Vect3 mag = {
+ (int32_t)(mpu9250.akm.data.vect.x),
+ (int32_t)(mpu9250.akm.data.vect.y),
+ (int32_t)(mpu9250.akm.data.vect.z)
+ };
+ DOWNLINK_SEND_IMU_MAG_RAW(DefaultChannel, DefaultDevice, &mag.x, &mag.y, &mag.z);
+}
+
diff --git a/sw/airborne/modules/sensors/imu_mpu9250.h b/sw/airborne/modules/sensors/imu_mpu9250.h
new file mode 100644
index 00000000000..a5c272cf751
--- /dev/null
+++ b/sw/airborne/modules/sensors/imu_mpu9250.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 Gautier Hattenberger
+ *
+ * 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, see
+ * .
+ */
+
+/**
+ * @file "modules/sensors/imu_mpu9250.h"
+ * @author Gautier Hattenberger
+ *
+ * Test module for the mpu9250
+ */
+
+#ifndef IMU_MPU9250_H
+#define IMU_MPU9250_H
+
+#include "peripherals/mpu9250_i2c.h"
+
+extern struct Mpu9250_I2c mpu9250;
+
+extern void imu_mpu9250_init(void);
+extern void imu_mpu9250_periodic(void);
+extern void imu_mpu9250_event(void);
+extern void imu_mpu9250_report(void);
+
+#endif
+
diff --git a/sw/airborne/peripherals/ak8963.c b/sw/airborne/peripherals/ak8963.c
new file mode 100644
index 00000000000..f029394ec82
--- /dev/null
+++ b/sw/airborne/peripherals/ak8963.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 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/ak8963.c
+ *
+ * Driver for the AKM AK8963 magnetometer.
+ */
+
+#include "peripherals/ak8963.h"
+#include "std.h"
+
+/**
+ * Initialize AK8963 struct
+ */
+void ak8963_init(struct Ak8963 *ak, struct i2c_periph *i2c_p, uint8_t addr)
+{
+ /* set i2c_peripheral */
+ ak->i2c_p = i2c_p;
+ /* set i2c address */
+ ak->i2c_trans.slave_addr = addr;
+ ak->i2c_trans.status = I2CTransDone;
+ ak->initialized = FALSE;
+ ak->init_status = AK_CONF_UNINIT;
+ ak->data_available = FALSE;
+}
+
+void ak8963_configure(struct Ak8963 *ak)
+{
+ // Only configure when not busy
+ if (ak->i2c_trans.status != I2CTransSuccess && ak->i2c_trans.status != I2CTransFailed && ak->i2c_trans.status != I2CTransDone) {
+ return;
+ }
+
+ // Only when succesfull continue with next
+ if (ak->i2c_trans.status == I2CTransSuccess) {
+ ak->init_status++;
+ }
+
+ ak->i2c_trans.status = I2CTransDone;
+ switch (ak->init_status) {
+
+ // Soft Reset the device
+ case AK_CONF_UNINIT:
+ ak->i2c_trans.buf[0] = AK8963_REG_CNTL2;
+ ak->i2c_trans.buf[1] = 1;
+ i2c_transmit(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 2);
+ break;
+
+ // Set it to continious measuring mode 2
+ case AK_CONF_MODE:
+ ak->i2c_trans.buf[0] = AK8963_REG_CNTL1;
+ ak->i2c_trans.buf[1] = AK8963_CNTL1_CM_2;
+ i2c_transmit(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 2);
+ break;
+
+ // Initialization done
+ default:
+ ak->initialized = TRUE;
+ break;
+ }
+}
+
+void ak8963_read(struct Ak8963 *ak)
+{
+ if (ak->status != AK_STATUS_IDLE) {
+ return;
+ }
+
+ // Read the status register
+ ak->i2c_trans.buf[0] = AK8963_REG_ST1;
+ i2c_transceive(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 1, 1);
+}
+
+#define Int16FromBuf(_buf,_idx) ((int16_t)(_buf[_idx] | (_buf[_idx+1] << 8)))
+void ak8963_event(struct Ak8963 *ak)
+{
+ if (!ak->initialized) {
+ return;
+ }
+
+ switch (ak->status) {
+ case AK_STATUS_IDLE:
+ // When DRDY start reading
+ if (ak->i2c_trans.status == I2CTransSuccess && ak->i2c_trans.buf[0] & 1) {
+ ak->i2c_trans.buf[0] = AK8963_REG_HXL;
+ i2c_transceive(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 1, 6);
+ ak->status++;
+ }
+ break;
+
+ case AK_STATUS_READ:
+ if (ak->i2c_trans.status == I2CTransSuccess) {
+ // Copy the data
+ ak->data.vect.x = Int16FromBuf(ak->i2c_trans.buf, 0);
+ ak->data.vect.y = Int16FromBuf(ak->i2c_trans.buf, 2);
+ ak->data.vect.z = Int16FromBuf(ak->i2c_trans.buf, 4);
+ ak->data_available = TRUE;
+
+ // Read second status register to be ready for reading again
+ ak->i2c_trans.buf[0] = AK8963_REG_ST2;
+ i2c_transceive(ak->i2c_p, &(ak->i2c_trans), ak->i2c_trans.slave_addr, 1, 1);
+ ak->status++;
+ break;
+ }
+
+ break;
+
+ default:
+ if (ak->i2c_trans.status == I2CTransSuccess || ak->i2c_trans.status == I2CTransFailed) {
+ // Goto idle
+ ak->i2c_trans.status = I2CTransDone;
+ ak->status = AK_STATUS_IDLE;
+ // check overrun
+ //if (bit_is_set(ak->i2c_trans.buf[0], 3)) {
+ // ak->data_available = FALSE;
+ //} else {
+ // ak->data_available = TRUE;
+ //}
+ }
+ break;
+ }
+}
+
diff --git a/sw/airborne/peripherals/ak8963.h b/sw/airborne/peripherals/ak8963.h
new file mode 100644
index 00000000000..92db595306a
--- /dev/null
+++ b/sw/airborne/peripherals/ak8963.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 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/ak8963.c
+ *
+ * Driver for the AKM AK8963 magnetometer.
+ */
+
+#ifndef AK8963_H
+#define AK8963_H
+
+#include "std.h"
+#include "mcu_periph/i2c.h"
+#include "math/pprz_algebra_int.h"
+
+/* Address and register definitions */
+#include "peripherals/ak8963_regs.h"
+
+/** Config status states */
+enum Ak8963ConfStatus {
+ AK_CONF_UNINIT,
+ AK_CONF_MODE,
+ AK_CONF_DONE
+};
+
+/** Normal status states */
+enum Ak8963Status {
+ AK_STATUS_IDLE,
+ AK_STATUS_READ,
+ AK_STATUS_DONE
+};
+
+/** Default Ak8963 structure */
+struct Ak8963 {
+ struct i2c_periph *i2c_p; ///< peripheral used for communcation
+ struct i2c_transaction i2c_trans; ///< i2c transaction used for communication with the ak8936
+ bool_t initialized; ///< config done flag
+
+ enum Ak8963Status status; ///< main status
+ enum Ak8963ConfStatus init_status; ///< init status
+
+ volatile bool_t data_available; ///< data ready flag
+ union {
+ struct Int16Vect3 vect; ///< data vector in mag coordinate system
+ int16_t value[3]; ///< data values accessible by channel index
+ } data;
+};
+
+// Functions
+extern void ak8963_init(struct Ak8963 *ak, struct i2c_periph *i2c_p, uint8_t addr);
+extern void ak8963_configure(struct Ak8963 *ak);
+extern void ak8963_event(struct Ak8963 *ak);
+extern void ak8963_read(struct Ak8963 *ak);
+
+/// convenience function: read or start configuration if not already initialized
+static inline void ak8963_periodic(struct Ak8963 *ak)
+{
+ if (ak->initialized) {
+ ak8963_read(ak);
+ } else {
+ ak8963_configure(ak);
+ }
+}
+
+#endif /* AK8963_H */
diff --git a/sw/airborne/peripherals/ak8963_regs.h b/sw/airborne/peripherals/ak8963_regs.h
new file mode 100644
index 00000000000..dbb926a2fc1
--- /dev/null
+++ b/sw/airborne/peripherals/ak8963_regs.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 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/ak8963.h
+ *
+ * Register and address definitions for AK8963 magnetometer.
+ */
+
+#ifndef AK8963_REGS_H
+#define AK8963_REGS_H
+
+#define AK8963_ADDR 0x1A
+
+/* Compass device dependent definition */
+#define AK8963_CNTL1_POWER_DOWN 0x10
+#define AK8963_CNTL1_SNG_MEASURE 0x11
+#define AK8963_CNTL1_CM_1 0x12
+#define AK8963_CNTL1_CM_2 0x16
+#define AK8963_CNTL1_EXT_TRIG 0x14
+#define AK8963_CNTL1_SELF_TEST 0x18
+#define AK8963_CNTL1_FUSE_ACCESS 0x1F
+
+/* AK8963 register address */
+#define AK8963_REG_WIA 0x00
+#define AK8963_REG_INFO 0x01
+#define AK8963_REG_ST1 0x02
+#define AK8963_REG_HXL 0x03
+#define AK8963_REG_HXH 0x04
+#define AK8963_REG_HYL 0x05
+#define AK8963_REG_HYH 0x06
+#define AK8963_REG_HZL 0x07
+#define AK8963_REG_HZH 0x08
+#define AK8963_REG_ST2 0x09
+#define AK8963_REG_CNTL1 0x0A
+#define AK8963_REG_CNTL2 0x0B
+#define AK8963_REG_ASTC 0x0C
+#define AK8963_REG_TS1 0x0D
+#define AK8963_REG_TS2 0x0E
+#define AK8963_REG_I2CDIS 0x0F
+
+/* AK8963 fuse-rom address */
+#define AK8963_FUSE_ASAX 0x10
+#define AK8963_FUSE_ASAY 0x11
+#define AK8963_FUSE_ASAZ 0x12
+
+#endif /* AK8963_REGS_H */
diff --git a/sw/airborne/peripherals/mpu9250.c b/sw/airborne/peripherals/mpu9250.c
new file mode 100644
index 00000000000..9a3df5c7793
--- /dev/null
+++ b/sw/airborne/peripherals/mpu9250.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013 Felix Ruess
+ *
+ * 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/mpu9250.c
+ *
+ * MPU-9250 driver common functions (I2C and SPI).
+ *
+ * Still needs the either the I2C or SPI specific implementation.
+ */
+
+#include "peripherals/mpu9250.h"
+
+void mpu9250_set_default_config(struct Mpu9250Config *c)
+{
+ c->clk_sel = MPU9250_DEFAULT_CLK_SEL;
+ c->smplrt_div = MPU9250_DEFAULT_SMPLRT_DIV;
+ c->dlpf_gyro_cfg = MPU9250_DEFAULT_DLPF_GYRO_CFG;
+ c->dlpf_accel_cfg = MPU9250_DEFAULT_DLPF_ACCEL_CFG;
+ c->gyro_range = MPU9250_DEFAULT_FS_SEL;
+ c->accel_range = MPU9250_DEFAULT_AFS_SEL;
+ c->drdy_int_enable = FALSE;
+
+ /* Number of bytes to read starting with MPU9250_REG_INT_STATUS
+ * By default read only gyro and accel data -> 15 bytes.
+ * Increase to include slave data.
+ */
+ c->nb_bytes = 15;
+ c->nb_slaves = 0;
+
+ c->i2c_bypass = FALSE;
+}
+
+void mpu9250_send_config(Mpu9250ConfigSet mpu_set, void* mpu, struct Mpu9250Config* config)
+{
+ switch (config->init_status) {
+ case MPU9250_CONF_RESET:
+ /* device reset, set register values to defaults */
+ mpu_set(mpu, MPU9250_REG_PWR_MGMT_1, (1<<6));
+ config->init_status++;
+ break;
+ case MPU9250_CONF_USER_RESET:
+ /* trigger FIFO, I2C_MST and SIG_COND resets */
+ mpu_set(mpu, MPU9250_REG_USER_CTRL, ((1 << MPU9250_FIFO_RESET) |
+ (1 << MPU9250_I2C_MST_RESET) |
+ (1 << MPU9250_SIG_COND_RESET)));
+ config->init_status++;
+ break;
+ case MPU9250_CONF_PWR:
+ /* switch to gyroX clock by default */
+ mpu_set(mpu, MPU9250_REG_PWR_MGMT_1, ((config->clk_sel)|(0<<6)));
+ config->init_status++;
+ break;
+ case MPU9250_CONF_SD:
+ /* configure sample rate divider */
+ mpu_set(mpu, MPU9250_REG_SMPLRT_DIV, config->smplrt_div);
+ config->init_status++;
+ break;
+ case MPU9250_CONF_DLPF_GYRO:
+ /* configure digital low pass filter for gyroscope */
+ mpu_set(mpu, MPU9250_REG_CONFIG, config->dlpf_gyro_cfg);
+ config->init_status++;
+ break;
+ case MPU9250_CONF_DLPF_ACCEL:
+ /* configure digital low pass filter fir accelerometer */
+ mpu_set(mpu, MPU9250_REG_ACCEL_CONFIG_2, config->dlpf_accel_cfg);
+ config->init_status++;
+ break;
+ case MPU9250_CONF_GYRO:
+ /* configure gyro range */
+ mpu_set(mpu, MPU9250_REG_GYRO_CONFIG, (config->gyro_range<<3));
+ config->init_status++;
+ break;
+ case MPU9250_CONF_ACCEL:
+ /* configure accelerometer range */
+ mpu_set(mpu, MPU9250_REG_ACCEL_CONFIG, (config->accel_range<<3));
+ config->init_status++;
+ break;
+ case MPU9250_CONF_I2C_SLAVES:
+ /* if any, set MPU for I2C slaves and configure them*/
+ if (config->nb_slaves > 0) {
+ /* returns TRUE when all slaves are configured */
+ if (mpu9250_configure_i2c_slaves(mpu_set, mpu))
+ config->init_status++;
+ }
+ else
+ config->init_status++;
+ break;
+ case MPU9250_CONF_INT_ENABLE:
+ /* configure data ready interrupt */
+ mpu_set(mpu, MPU9250_REG_INT_ENABLE, (config->drdy_int_enable<<0));
+ config->init_status++;
+ break;
+ case MPU9250_CONF_DONE:
+ config->initialized = TRUE;
+ break;
+ default:
+ break;
+ }
+}
diff --git a/sw/airborne/peripherals/mpu9250.h b/sw/airborne/peripherals/mpu9250.h
new file mode 100644
index 00000000000..70330b3e810
--- /dev/null
+++ b/sw/airborne/peripherals/mpu9250.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 Gautier Hattenberger
+ *
+ * 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, see
+ * .
+ */
+
+/**
+ * @file peripherals/mpu9250.h
+ *
+ * MPU-60X0 driver common interface (I2C and SPI).
+ */
+
+#ifndef MPU9250_H
+#define MPU9250_H
+
+#include "std.h"
+
+/* Include address and register definition */
+#include "peripherals/mpu9250_regs.h"
+
+/// Default sample rate divider
+#define MPU9250_DEFAULT_SMPLRT_DIV 0
+/// Default gyro full scale range +- 2000°/s
+#define MPU9250_DEFAULT_FS_SEL MPU9250_GYRO_RANGE_1000
+/// Default accel full scale range +- 16g
+#define MPU9250_DEFAULT_AFS_SEL MPU9250_ACCEL_RANGE_8G
+/// Default internal sampling (1kHz, 42Hz LP Bandwidth)
+#define MPU9250_DEFAULT_DLPF_ACCEL_CFG MPU9250_DLPF_ACCEL_41HZ
+/// Default internal sampling (1kHz, 42Hz LP Bandwidth)
+#define MPU9250_DEFAULT_DLPF_GYRO_CFG MPU9250_DLPF_GYRO_41HZ
+/// Default interrupt config: DATA_RDY_EN
+#define MPU9250_DEFAULT_INT_CFG 1
+/// Default clock: PLL with X gyro reference
+#define MPU9250_DEFAULT_CLK_SEL 1
+
+enum Mpu9250ConfStatus {
+ MPU9250_CONF_UNINIT,
+ MPU9250_CONF_RESET,
+ MPU9250_CONF_USER_RESET,
+ MPU9250_CONF_PWR,
+ MPU9250_CONF_SD,
+ MPU9250_CONF_DLPF_ACCEL,
+ MPU9250_CONF_DLPF_GYRO,
+ MPU9250_CONF_GYRO,
+ MPU9250_CONF_ACCEL,
+ MPU9250_CONF_I2C_SLAVES,
+ MPU9250_CONF_INT_ENABLE,
+ MPU9250_CONF_DONE
+};
+
+/// Configuration function prototype
+typedef void (*Mpu9250ConfigSet)(void* mpu, uint8_t _reg, uint8_t _val);
+
+/// function prototype for configuration of a single I2C slave
+typedef bool_t (*Mpu9250I2cSlaveConfigure)(Mpu9250ConfigSet mpu_set, void* mpu);
+
+struct Mpu9250I2cSlave {
+ Mpu9250I2cSlaveConfigure configure;
+};
+
+struct Mpu9250Config {
+ uint8_t smplrt_div; ///< Sample rate divider
+ enum Mpu9250DLPFAccel dlpf_accel_cfg; ///< Digital Low Pass Filter for accelerometer
+ enum Mpu9250DLPFGyro dlpf_gyro_cfg; ///< Digital Low Pass Filter for gyroscope
+ enum Mpu9250GyroRanges gyro_range; ///< deg/s Range
+ enum Mpu9250AccelRanges accel_range; ///< g Range
+ bool_t drdy_int_enable; ///< Enable Data Ready Interrupt
+ uint8_t clk_sel; ///< Clock select
+ uint8_t nb_bytes; ///< number of bytes to read starting with MPU9250_REG_INT_STATUS
+ enum Mpu9250ConfStatus init_status; ///< init status
+ bool_t initialized; ///< config done flag
+
+ /** Bypass MPU I2C.
+ * Only effective if using the I2C implementation.
+ */
+ bool_t i2c_bypass;
+
+ uint8_t nb_slaves; ///< number of used I2C slaves
+ struct Mpu9250I2cSlave slaves[5]; ///< I2C slaves
+ enum Mpu9250MstClk i2c_mst_clk; ///< MPU I2C master clock speed
+ uint8_t i2c_mst_delay; ///< MPU I2C slaves delayed sample rate
+};
+
+extern void mpu9250_set_default_config(struct Mpu9250Config *c);
+
+/// Configuration sequence called once before normal use
+extern void mpu9250_send_config(Mpu9250ConfigSet mpu_set, void* mpu, struct Mpu9250Config* config);
+
+/**
+ * Configure I2C slaves of the MPU.
+ * This is I2C/SPI implementation specific.
+ * @param mpu_set configuration function
+ * @param mpu Mpu9250Spi or Mpu9250I2c peripheral
+ * @return TRUE when all slaves are configured
+ */
+extern bool_t mpu9250_configure_i2c_slaves(Mpu9250ConfigSet mpu_set, void* mpu);
+
+#endif // MPU9250_H
diff --git a/sw/airborne/peripherals/mpu9250_i2c.c b/sw/airborne/peripherals/mpu9250_i2c.c
new file mode 100644
index 00000000000..3237c35224b
--- /dev/null
+++ b/sw/airborne/peripherals/mpu9250_i2c.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2014 Gautier Hattenberger
+ *
+ * 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, see
+ * .
+ */
+
+/**
+ * @file peripherals/mpu9250_i2c.c
+ *
+ * Driver for the MPU-9250 using I2C.
+ *
+ */
+
+#include "peripherals/mpu9250_i2c.h"
+
+bool_t imu_mpu9250_configure_mag_slave(Mpu9250ConfigSet mpu_set __attribute__ ((unused)), void* mpu __attribute__ ((unused)));
+
+void mpu9250_i2c_init(struct Mpu9250_I2c *mpu, struct i2c_periph *i2c_p, uint8_t addr)
+{
+ /* set i2c_peripheral */
+ mpu->i2c_p = i2c_p;
+
+ /* slave address */
+ mpu->i2c_trans.slave_addr = addr;
+ /* set inital status: Success or Done */
+ mpu->i2c_trans.status = I2CTransDone;
+
+ /* set default MPU9250 config options */
+ mpu9250_set_default_config(&(mpu->config));
+
+ mpu->data_available = FALSE;
+ mpu->config.initialized = FALSE;
+ mpu->config.init_status = MPU9250_CONF_UNINIT;
+
+ /* "internal" ak8963 magnetometer */
+ ak8963_init(&mpu->akm, i2c_p, MPU9250_MAG_ADDR);
+ /* mag is declared as slave to call the configure function,
+ * regardless if it is an actual MPU slave or passthrough
+ */
+ mpu->config.nb_slaves = 1;
+ /* set callback function to configure mag */
+ mpu->config.slaves[0].configure = &imu_mpu9250_configure_mag_slave;
+ /* read the mag directly for now */
+ mpu->config.i2c_bypass = TRUE;
+
+ mpu->slave_init_status = MPU9250_I2C_CONF_UNINIT;
+}
+
+
+static void mpu9250_i2c_write_to_reg(void* mpu, uint8_t _reg, uint8_t _val) {
+ struct Mpu9250_I2c* mpu_i2c = (struct Mpu9250_I2c*)(mpu);
+ mpu_i2c->i2c_trans.buf[0] = _reg;
+ mpu_i2c->i2c_trans.buf[1] = _val;
+ i2c_transmit(mpu_i2c->i2c_p, &(mpu_i2c->i2c_trans), mpu_i2c->i2c_trans.slave_addr, 2);
+}
+
+// Configuration function called once before normal use
+void mpu9250_i2c_start_configure(struct Mpu9250_I2c *mpu)
+{
+ if (mpu->config.init_status == MPU9250_CONF_UNINIT) {
+ mpu->config.init_status++;
+ if (mpu->i2c_trans.status == I2CTransSuccess || mpu->i2c_trans.status == I2CTransDone) {
+ mpu9250_send_config(mpu9250_i2c_write_to_reg, (void*)mpu, &(mpu->config));
+ }
+ }
+}
+
+void mpu9250_i2c_read(struct Mpu9250_I2c *mpu)
+{
+ if (mpu->config.initialized && mpu->i2c_trans.status == I2CTransDone) {
+ /* set read bit and multiple byte bit, then address */
+ mpu->i2c_trans.buf[0] = MPU9250_REG_INT_STATUS;
+ i2c_transceive(mpu->i2c_p, &(mpu->i2c_trans), mpu->i2c_trans.slave_addr, 1, mpu->config.nb_bytes);
+ /* read mag */
+#ifdef MPU9250_MAG_PRESCALER
+ RunOnceEvery(MPU9250_MAG_PRESCALER, ak8963_read(&mpu->akm));
+#else
+ ak8963_read(&mpu->akm);
+#endif
+ }
+}
+
+#define Int16FromBuf(_buf,_idx) ((int16_t)((_buf[_idx]<<8) | _buf[_idx+1]))
+
+void mpu9250_i2c_event(struct Mpu9250_I2c *mpu)
+{
+ if (mpu->config.initialized) {
+ if (mpu->i2c_trans.status == I2CTransFailed) {
+ mpu->i2c_trans.status = I2CTransDone;
+ }
+ else if (mpu->i2c_trans.status == I2CTransSuccess) {
+ // Successfull reading
+ if (bit_is_set(mpu->i2c_trans.buf[0], 0)) {
+ // new data
+ mpu->data_accel.vect.x = Int16FromBuf(mpu->i2c_trans.buf, 1);
+ mpu->data_accel.vect.y = Int16FromBuf(mpu->i2c_trans.buf, 3);
+ mpu->data_accel.vect.z = Int16FromBuf(mpu->i2c_trans.buf, 5);
+ mpu->data_rates.rates.p = Int16FromBuf(mpu->i2c_trans.buf, 9);
+ mpu->data_rates.rates.q = Int16FromBuf(mpu->i2c_trans.buf, 11);
+ mpu->data_rates.rates.r = Int16FromBuf(mpu->i2c_trans.buf, 13);
+
+ // if we are reading slaves through the mpu, copy the ext_sens_data
+ if ((mpu->config.i2c_bypass == FALSE) && (mpu->config.nb_slaves > 0))
+ memcpy(mpu->data_ext, (void *) &(mpu->i2c_trans.buf[15]), mpu->config.nb_bytes - 15);
+
+ mpu->data_available = TRUE;
+ }
+ mpu->i2c_trans.status = I2CTransDone;
+ }
+ }
+ else if (mpu->config.init_status != MPU9250_CONF_UNINIT) { // Configuring but not yet initialized
+ switch (mpu->i2c_trans.status) {
+ case I2CTransFailed:
+ mpu->config.init_status--; // Retry config (TODO max retry)
+ case I2CTransSuccess:
+ case I2CTransDone:
+ mpu9250_send_config(mpu9250_i2c_write_to_reg, (void*)mpu, &(mpu->config));
+ if (mpu->config.initialized)
+ mpu->i2c_trans.status = I2CTransDone;
+ break;
+ default:
+ break;
+ }
+ }
+ // Ak8963 event function
+ ak8963_event(&mpu->akm);
+}
+
+/** callback function to configure ak8963 mag
+ * @return TRUE if mag configuration finished
+ */
+bool_t imu_mpu9250_configure_mag_slave(Mpu9250ConfigSet mpu_set __attribute__ ((unused)), void* mpu)
+{
+ struct Mpu9250_I2c* mpu_i2c = (struct Mpu9250_I2c*)(mpu);
+
+ ak8963_configure(&mpu_i2c->akm);
+ if (mpu_i2c->akm.initialized)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/** @todo: only one slave so far. */
+bool_t mpu9250_configure_i2c_slaves(Mpu9250ConfigSet mpu_set, void* mpu)
+{
+ struct Mpu9250_I2c* mpu_i2c = (struct Mpu9250_I2c*)(mpu);
+
+ if (mpu_i2c->slave_init_status == MPU9250_I2C_CONF_UNINIT)
+ mpu_i2c->slave_init_status++;
+
+ switch (mpu_i2c->slave_init_status) {
+ case MPU9250_I2C_CONF_I2C_MST_DIS:
+ mpu_set(mpu, MPU9250_REG_USER_CTRL, 0);
+ mpu_i2c->slave_init_status++;
+ break;
+ case MPU9250_I2C_CONF_I2C_BYPASS_EN:
+ /* switch to I2C passthrough */
+ mpu_set(mpu, MPU9250_REG_INT_PIN_CFG, (1<<1));
+ mpu_i2c->slave_init_status++;
+ break;
+ case MPU9250_I2C_CONF_SLAVES_CONFIGURE:
+ /* configure each slave. TODO: currently only one */
+ if (mpu_i2c->config.slaves[0].configure(mpu_set, mpu))
+ mpu_i2c->slave_init_status++;
+ break;
+ case MPU9250_I2C_CONF_I2C_BYPASS_DIS:
+ if (mpu_i2c->config.i2c_bypass) {
+ /* if bypassing I2C skip MPU I2C master setup */
+ mpu_i2c->slave_init_status = MPU9250_I2C_CONF_DONE;
+ }
+ else {
+ /* disable I2C passthrough again */
+ mpu_set(mpu, MPU9250_REG_INT_PIN_CFG, (0<<1));
+ mpu_i2c->slave_init_status++;
+ }
+ break;
+ case MPU9250_I2C_CONF_I2C_MST_CLK:
+ /* configure MPU I2C master clock and stop/start between slave reads */
+ mpu_set(mpu, MPU9250_REG_I2C_MST_CTRL,
+ ((1<<4) | mpu_i2c->config.i2c_mst_clk));
+ mpu_i2c->slave_init_status++;
+ break;
+ case MPU9250_I2C_CONF_I2C_MST_DELAY:
+ /* Set I2C slaves delayed sample rate */
+ mpu_set(mpu, MPU9250_REG_I2C_MST_DELAY, mpu_i2c->config.i2c_mst_delay);
+ mpu_i2c->slave_init_status++;
+ break;
+ case MPU9250_I2C_CONF_I2C_SMPLRT:
+ /* I2C slave0 sample rate/2 = 100/2 = 50Hz */
+ mpu_set(mpu, MPU9250_REG_I2C_SLV4_CTRL, 0);
+ mpu_i2c->slave_init_status++;
+ break;
+ case MPU9250_I2C_CONF_I2C_MST_EN:
+ /* enable internal I2C master */
+ mpu_set(mpu, MPU9250_REG_USER_CTRL, (1 << MPU9250_I2C_MST_EN));
+ mpu_i2c->slave_init_status++;
+ break;
+ case MPU9250_I2C_CONF_DONE:
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
diff --git a/sw/airborne/peripherals/mpu9250_i2c.h b/sw/airborne/peripherals/mpu9250_i2c.h
new file mode 100644
index 00000000000..a826e818e1a
--- /dev/null
+++ b/sw/airborne/peripherals/mpu9250_i2c.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 Gautier Hattenberger
+ *
+ * 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/mpu9250_i2c.h
+ *
+ * Driver for the MPU-9250 using I2C.
+ */
+
+#ifndef MPU9250_I2C_H
+#define MPU9250_I2C_H
+
+#include "std.h"
+#include "math/pprz_algebra_int.h"
+#include "mcu_periph/i2c.h"
+
+/* Include common MPU9250 options and definitions */
+#include "peripherals/mpu9250.h"
+#include "peripherals/ak8963.h"
+
+
+#define MPU9250_BUFFER_EXT_LEN 16
+
+enum Mpu9250I2cSlaveInitStatus {
+ MPU9250_I2C_CONF_UNINIT,
+ MPU9250_I2C_CONF_I2C_MST_DIS,
+ MPU9250_I2C_CONF_I2C_BYPASS_EN,
+ MPU9250_I2C_CONF_SLAVES_CONFIGURE,
+ MPU9250_I2C_CONF_I2C_BYPASS_DIS,
+ MPU9250_I2C_CONF_I2C_MST_CLK,
+ MPU9250_I2C_CONF_I2C_MST_DELAY,
+ MPU9250_I2C_CONF_I2C_SMPLRT,
+ MPU9250_I2C_CONF_I2C_MST_EN,
+ MPU9250_I2C_CONF_DONE
+};
+
+struct Mpu9250_I2c {
+ struct i2c_periph *i2c_p;
+ struct i2c_transaction i2c_trans;
+ volatile bool_t data_available; ///< data ready flag
+ union {
+ struct Int16Vect3 vect; ///< accel data vector in accel coordinate system
+ int16_t value[3]; ///< accel data values accessible by channel index
+ } data_accel;
+ union {
+ struct Int16Rates rates; ///< rates data as angular rates in gyro coordinate system
+ int16_t value[3]; ///< rates data values accessible by channel index
+ } data_rates;
+ uint8_t data_ext[MPU9250_BUFFER_EXT_LEN];
+ struct Mpu9250Config config;
+ enum Mpu9250I2cSlaveInitStatus slave_init_status;
+ struct Ak8963 akm; ///< "internal" magnetometer
+};
+
+// Functions
+extern void mpu9250_i2c_init(struct Mpu9250_I2c *mpu, struct i2c_periph *i2c_p, uint8_t addr);
+extern void mpu9250_i2c_start_configure(struct Mpu9250_I2c *mpu);
+extern void mpu9250_i2c_read(struct Mpu9250_I2c *mpu);
+extern void mpu9250_i2c_event(struct Mpu9250_I2c *mpu);
+
+/// convenience function: read or start configuration if not already initialized
+static inline void mpu9250_i2c_periodic(struct Mpu9250_I2c *mpu) {
+ if (mpu->config.initialized)
+ mpu9250_i2c_read(mpu);
+ else
+ mpu9250_i2c_start_configure(mpu);
+}
+
+#endif // MPU9250_I2C_H
diff --git a/sw/airborne/peripherals/mpu9250_regs.h b/sw/airborne/peripherals/mpu9250_regs.h
new file mode 100644
index 00000000000..d680e8ecf4b
--- /dev/null
+++ b/sw/airborne/peripherals/mpu9250_regs.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2010-2013 The Paparazzi Team
+ *
+ * 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/mpu9250_regs.h
+ *
+ * Register and address definitions for MPU-9250.
+ */
+
+#ifndef MPU9250_REGS_H
+#define MPU9250_REGS_H
+
+/* default I2C address */
+#define MPU9250_ADDR 0xD0
+#define MPU9250_ADDR_ALT 0xD2
+
+#define MPU9250_MAG_ADDR 0x18
+
+#define MPU9250_SPI_READ 0x80
+
+// Power and Interface
+#define MPU9250_REG_AUX_VDDIO 0x01 // Must be set to 0 on MPU6000
+#define MPU9250_REG_USER_CTRL 0x6A
+#define MPU9250_REG_PWR_MGMT_1 0x6B
+#define MPU9250_REG_PWR_MGMT_2 0x6C
+
+// FIFO
+#define MPU9250_REG_FIFO_EN 0x23
+#define MPU9250_REG_FIFO_COUNT_H 0x72
+#define MPU9250_REG_FIFO_COUNT_L 0x73
+#define MPU9250_REG_FIFO_R_W 0x74
+
+// Measurement Settings
+#define MPU9250_REG_SMPLRT_DIV 0x19
+#define MPU9250_REG_CONFIG 0x1A
+#define MPU9250_REG_GYRO_CONFIG 0x1B
+#define MPU9250_REG_ACCEL_CONFIG 0x1C
+#define MPU9250_REG_ACCEL_CONFIG_2 0x1D
+
+
+// I2C Slave settings
+#define MPU9250_REG_I2C_MST_CTRL 0x24
+#define MPU9250_REG_I2C_MST_STATUS 0x36
+#define MPU9250_REG_I2C_MST_DELAY 0x67
+// Slave 0
+#define MPU9250_REG_I2C_SLV0_ADDR 0X25 // i2c addr
+#define MPU9250_REG_I2C_SLV0_REG 0X26 // slave reg
+#define MPU9250_REG_I2C_SLV0_CTRL 0X27 // set-bits
+#define MPU9250_REG_I2C_SLV0_DO 0X63 // DO
+// Slave 1
+#define MPU9250_REG_I2C_SLV1_ADDR 0X28 // i2c addr
+#define MPU9250_REG_I2C_SLV1_REG 0X29 // slave reg
+#define MPU9250_REG_I2C_SLV1_CTRL 0X2A // set-bits
+#define MPU9250_REG_I2C_SLV1_DO 0X64 // DO
+// Slave 2
+#define MPU9250_REG_I2C_SLV2_ADDR 0X2B // i2c addr
+#define MPU9250_REG_I2C_SLV2_REG 0X2C // slave reg
+#define MPU9250_REG_I2C_SLV2_CTRL 0X2D // set-bits
+#define MPU9250_REG_I2C_SLV2_DO 0X65 // DO
+// Slave 3
+#define MPU9250_REG_I2C_SLV3_ADDR 0X2E // i2c addr
+#define MPU9250_REG_I2C_SLV3_REG 0X2F // slave reg
+#define MPU9250_REG_I2C_SLV3_CTRL 0X30 // set-bits
+#define MPU9250_REG_I2C_SLV3_DO 0X66 // DO
+// Slave 4 - special
+#define MPU9250_REG_I2C_SLV4_ADDR 0X31 // i2c addr
+#define MPU9250_REG_I2C_SLV4_REG 0X32 // slave reg
+#define MPU9250_REG_I2C_SLV4_DO 0X33 // DO
+#define MPU9250_REG_I2C_SLV4_CTRL 0X34 // set-bits
+#define MPU9250_REG_I2C_SLV4_DI 0X35 // DI
+
+// Interrupt
+#define MPU9250_REG_INT_PIN_CFG 0x37
+#define MPU9250_REG_INT_ENABLE 0x38
+#define MPU9250_REG_INT_STATUS 0x3A
+
+// Accelero
+#define MPU9250_REG_ACCEL_XOUT_H 0x3B
+#define MPU9250_REG_ACCEL_XOUT_L 0x3C
+#define MPU9250_REG_ACCEL_YOUT_H 0x3D
+#define MPU9250_REG_ACCEL_YOUT_L 0x3E
+#define MPU9250_REG_ACCEL_ZOUT_H 0x3F
+#define MPU9250_REG_ACCEL_ZOUT_L 0x40
+
+// Temperature
+#define MPU9250_REG_TEMP_OUT_H 0x41
+#define MPU9250_REG_TEMP_OUT_L 0x42
+
+// Gyro
+#define MPU9250_REG_GYRO_XOUT_H 0x43
+#define MPU9250_REG_GYRO_XOUT_L 0x44
+#define MPU9250_REG_GYRO_YOUT_H 0x45
+#define MPU9250_REG_GYRO_YOUT_L 0x46
+#define MPU9250_REG_GYRO_ZOUT_H 0x47
+#define MPU9250_REG_GYRO_ZOUT_L 0x48
+
+// External Sensor Data
+#define MPU9250_EXT_SENS_DATA 0x49
+#define MPU9250_EXT_SENS_DATA_SIZE 24
+
+
+#define MPU9250_REG_WHO_AM_I 0x75
+#define MPU9250_WHOAMI_REPLY 0x68
+
+// Bit positions
+#define MPU9250_I2C_BYPASS_EN 1
+
+// in MPU9250_REG_USER_CTRL
+#define MPU9250_SIG_COND_RESET 0
+#define MPU9250_I2C_MST_RESET 1
+#define MPU9250_FIFO_RESET 2
+#define MPU9250_I2C_IF_DIS 4
+#define MPU9250_I2C_MST_EN 5
+#define MPU9250_FIFO_EN 6
+
+// in MPU9250_REG_I2C_MST_STATUS
+#define MPU9250_I2C_SLV4_DONE 6
+
+/** Digital Low Pass Filter Options
+ */
+enum Mpu9250DLPFGyro {
+ MPU9250_DLPF_GYRO_250HZ = 0x0, // internal sampling rate 8kHz
+ MPU9250_DLPF_GYRO_184HZ = 0x1, // internal sampling rate 1kHz
+ MPU9250_DLPF_GYRO_92HZ = 0x2,
+ MPU9250_DLPF_GYRO_41HZ = 0x3,
+ MPU9250_DLPF_GYRO_20HZ = 0x4,
+ MPU9250_DLPF_GYRO_10HZ = 0x5,
+ MPU9250_DLPF_GYRO_05HZ = 0x6
+};
+
+enum Mpu9250DLPFAccel {
+ MPU9250_DLPF_ACCEL_460HZ = 0x0, // internal sampling rate 8kHz
+ MPU9250_DLPF_ACCEL_184HZ = 0x1, // internal sampling rate 1kHz
+ MPU9250_DLPF_ACCEL_92HZ = 0x2,
+ MPU9250_DLPF_ACCEL_41HZ = 0x3,
+ MPU9250_DLPF_ACCEL_20HZ = 0x4,
+ MPU9250_DLPF_ACCEL_10HZ = 0x5,
+ MPU9250_DLPF_ACCEL_05HZ = 0x6
+};
+
+/**
+ * Selectable gyro range
+ */
+enum Mpu9250GyroRanges {
+ MPU9250_GYRO_RANGE_250 = 0x00,
+ MPU9250_GYRO_RANGE_500 = 0x01,
+ MPU9250_GYRO_RANGE_1000 = 0x02,
+ MPU9250_GYRO_RANGE_2000 = 0x03
+};
+
+/**
+ * Selectable accel range
+ */
+enum Mpu9250AccelRanges {
+ MPU9250_ACCEL_RANGE_2G = 0x00,
+ MPU9250_ACCEL_RANGE_4G = 0x01,
+ MPU9250_ACCEL_RANGE_8G = 0x02,
+ MPU9250_ACCEL_RANGE_16G = 0x03
+};
+
+/**
+ * I2C Master clock
+ */
+enum Mpu9250MstClk {
+ MPU9250_MST_CLK_500KHZ = 0x9,
+ MPU9250_MST_CLK_471KHZ = 0xA,
+ MPU9250_MST_CLK_444KHZ = 0xB,
+ MPU9250_MST_CLK_421KHZ = 0xC,
+ MPU9250_MST_CLK_400KHZ = 0xD,
+ MPU9250_MST_CLK_381KHZ = 0xE,
+ MPU9250_MST_CLK_364KHZ = 0xF,
+ MPU9250_MST_CLK_348KHZ = 0x0,
+ MPU9250_MST_CLK_333KHZ = 0x1,
+ MPU9250_MST_CLK_320KHZ = 0x2,
+ MPU9250_MST_CLK_308KHZ = 0x3,
+ MPU9250_MST_CLK_296KHZ = 0x4,
+ MPU9250_MST_CLK_286KHZ = 0x5,
+ MPU9250_MST_CLK_276KHZ = 0x6,
+ MPU9250_MST_CLK_267KHZ = 0x7,
+ MPU9250_MST_CLK_258KHZ = 0x8
+};
+
+#endif /* MPU9250_REGS_H */
diff --git a/sw/airborne/peripherals/mpu9250_spi.c b/sw/airborne/peripherals/mpu9250_spi.c
new file mode 100644
index 00000000000..0fff4d53305
--- /dev/null
+++ b/sw/airborne/peripherals/mpu9250_spi.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2013 Gautier Hattenberger
+ *
+ * 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/mpu9250_spi.c
+ *
+ * Driver for the MPU-9250 using SPI.
+ *
+ */
+
+#include "peripherals/mpu9250_spi.h"
+
+void mpu9250_spi_init(struct Mpu9250_Spi *mpu, struct spi_periph *spi_p, uint8_t slave_idx)
+{
+ /* set spi_peripheral */
+ mpu->spi_p = spi_p;
+
+ /* configure spi transaction */
+ mpu->spi_trans.cpol = SPICpolIdleHigh;
+ mpu->spi_trans.cpha = SPICphaEdge2;
+ mpu->spi_trans.dss = SPIDss8bit;
+ mpu->spi_trans.bitorder = SPIMSBFirst;
+ mpu->spi_trans.cdiv = SPIDiv64;
+
+ mpu->spi_trans.select = SPISelectUnselect;
+ mpu->spi_trans.slave_idx = slave_idx;
+ mpu->spi_trans.output_length = 2;
+ mpu->spi_trans.input_length = MPU9250_BUFFER_LEN;
+ mpu->spi_trans.before_cb = NULL;
+ mpu->spi_trans.after_cb = NULL;
+ mpu->spi_trans.input_buf = &(mpu->rx_buf[0]);
+ mpu->spi_trans.output_buf = &(mpu->tx_buf[0]);
+
+ /* set inital status: Success or Done */
+ mpu->spi_trans.status = SPITransDone;
+
+ /* set default MPU9250 config options */
+ mpu9250_set_default_config(&(mpu->config));
+
+ mpu->data_available = FALSE;
+ mpu->config.initialized = FALSE;
+ mpu->config.init_status = MPU9250_CONF_UNINIT;
+
+ mpu->slave_init_status = MPU9250_SPI_CONF_UNINIT;
+}
+
+
+static void mpu9250_spi_write_to_reg(void* mpu, uint8_t _reg, uint8_t _val) {
+ struct Mpu9250_Spi* mpu_spi = (struct Mpu9250_Spi*)(mpu);
+ mpu_spi->spi_trans.output_length = 2;
+ mpu_spi->spi_trans.input_length = 0;
+ mpu_spi->tx_buf[0] = _reg;
+ mpu_spi->tx_buf[1] = _val;
+ spi_submit(mpu_spi->spi_p, &(mpu_spi->spi_trans));
+}
+
+// Configuration function called once before normal use
+void mpu9250_spi_start_configure(struct Mpu9250_Spi *mpu)
+{
+ if (mpu->config.init_status == MPU9250_CONF_UNINIT) {
+ mpu->config.init_status++;
+ if (mpu->spi_trans.status == SPITransSuccess || mpu->spi_trans.status == SPITransDone) {
+ mpu9250_send_config(mpu9250_spi_write_to_reg, (void*)mpu, &(mpu->config));
+ }
+ }
+}
+
+void mpu9250_spi_read(struct Mpu9250_Spi *mpu)
+{
+ if (mpu->config.initialized && mpu->spi_trans.status == SPITransDone) {
+ mpu->spi_trans.output_length = 1;
+ mpu->spi_trans.input_length = 1 + mpu->config.nb_bytes;
+ /* set read bit and multiple byte bit, then address */
+ mpu->tx_buf[0] = MPU9250_REG_INT_STATUS | MPU9250_SPI_READ;
+ spi_submit(mpu->spi_p, &(mpu->spi_trans));
+ }
+}
+
+#define Int16FromBuf(_buf,_idx) ((int16_t)((_buf[_idx]<<8) | _buf[_idx+1]))
+
+void mpu9250_spi_event(struct Mpu9250_Spi *mpu)
+{
+ if (mpu->config.initialized) {
+ if (mpu->spi_trans.status == SPITransFailed) {
+ mpu->spi_trans.status = SPITransDone;
+ }
+ else if (mpu->spi_trans.status == SPITransSuccess) {
+ // Successfull reading
+ if (bit_is_set(mpu->rx_buf[1], 0)) {
+ // new data
+ mpu->data_accel.vect.x = Int16FromBuf(mpu->rx_buf, 2);
+ mpu->data_accel.vect.y = Int16FromBuf(mpu->rx_buf, 4);
+ mpu->data_accel.vect.z = Int16FromBuf(mpu->rx_buf, 6);
+ mpu->data_rates.rates.p = Int16FromBuf(mpu->rx_buf, 10);
+ mpu->data_rates.rates.q = Int16FromBuf(mpu->rx_buf, 12);
+ mpu->data_rates.rates.r = Int16FromBuf(mpu->rx_buf, 14);
+
+ // if we are reading slaves, copy the ext_sens_data
+ if (mpu->config.nb_slaves > 0)
+ memcpy(mpu->data_ext, (void *) &(mpu->rx_buf[16]), mpu->config.nb_bytes - 15);
+
+ mpu->data_available = TRUE;
+ }
+ mpu->spi_trans.status = SPITransDone;
+ }
+ }
+ else if (mpu->config.init_status != MPU9250_CONF_UNINIT) { // Configuring but not yet initialized
+ switch (mpu->spi_trans.status) {
+ case SPITransFailed:
+ mpu->config.init_status--; // Retry config (TODO max retry)
+ case SPITransSuccess:
+ case SPITransDone:
+ mpu9250_send_config(mpu9250_spi_write_to_reg, (void*)mpu, &(mpu->config));
+ if (mpu->config.initialized)
+ mpu->spi_trans.status = SPITransDone;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/** @todo: only one slave so far. */
+bool_t mpu9250_configure_i2c_slaves(Mpu9250ConfigSet mpu_set, void* mpu)
+{
+ struct Mpu9250_Spi* mpu_spi = (struct Mpu9250_Spi*)(mpu);
+
+ if (mpu_spi->slave_init_status == MPU9250_SPI_CONF_UNINIT)
+ mpu_spi->slave_init_status++;
+
+ switch (mpu_spi->slave_init_status) {
+ case MPU9250_SPI_CONF_I2C_MST_CLK:
+ /* configure MPU I2C master clock and stop/start between slave reads */
+ mpu_set(mpu, MPU9250_REG_I2C_MST_CTRL, ((1<<4) | mpu_spi->config.i2c_mst_clk));
+ mpu_spi->slave_init_status++;
+ break;
+ case MPU9250_SPI_CONF_I2C_MST_DELAY:
+ /* Set I2C slaves delayed sample rate */
+ mpu_set(mpu, MPU9250_REG_I2C_MST_DELAY, mpu_spi->config.i2c_mst_delay);
+ mpu_spi->slave_init_status++;
+ break;
+ case MPU9250_SPI_CONF_I2C_MST_EN:
+ /* enable internal I2C master and disable primary I2C interface */
+ mpu_set(mpu, MPU9250_REG_USER_CTRL, ((1 << MPU9250_I2C_IF_DIS) |
+ (1 << MPU9250_I2C_MST_EN)));
+ mpu_spi->slave_init_status++;
+ break;
+ case MPU9250_SPI_CONF_SLAVES_CONFIGURE:
+ /* configure first slave, only one slave supported so far */
+ if (mpu_spi->config.slaves[0].configure(mpu_set, mpu))
+ mpu_spi->slave_init_status++;
+ break;
+ case MPU9250_SPI_CONF_DONE:
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
diff --git a/sw/airborne/peripherals/mpu9250_spi.h b/sw/airborne/peripherals/mpu9250_spi.h
new file mode 100644
index 00000000000..d8135ba41be
--- /dev/null
+++ b/sw/airborne/peripherals/mpu9250_spi.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2013 Gautier Hattenberger
+ *
+ * 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/mpu9250_spi.h
+ *
+ * Driver for the MPU-9250 using SPI.
+ */
+
+#ifndef MPU9250_SPI_H
+#define MPU9250_SPI_H
+
+#include "std.h"
+#include "math/pprz_algebra_int.h"
+#include "mcu_periph/spi.h"
+
+/* Include common MPU9250 options and definitions */
+#include "peripherals/mpu9250.h"
+
+
+#define MPU9250_BUFFER_LEN 32
+#define MPU9250_BUFFER_EXT_LEN 16
+
+enum Mpu9250SpiSlaveInitStatus {
+ MPU9250_SPI_CONF_UNINIT,
+ MPU9250_SPI_CONF_I2C_MST_CLK,
+ MPU9250_SPI_CONF_I2C_MST_DELAY,
+ MPU9250_SPI_CONF_I2C_MST_EN,
+ MPU9250_SPI_CONF_SLAVES_CONFIGURE,
+ MPU9250_SPI_CONF_DONE
+};
+
+struct Mpu9250_Spi {
+ struct spi_periph *spi_p;
+ struct spi_transaction spi_trans;
+ volatile uint8_t tx_buf[2];
+ volatile uint8_t rx_buf[MPU9250_BUFFER_LEN];
+ volatile bool_t data_available; ///< data ready flag
+ union {
+ struct Int16Vect3 vect; ///< accel data vector in accel coordinate system
+ int16_t value[3]; ///< accel data values accessible by channel index
+ } data_accel;
+ union {
+ struct Int16Rates rates; ///< rates data as angular rates in gyro coordinate system
+ int16_t value[3]; ///< rates data values accessible by channel index
+ } data_rates;
+ uint8_t data_ext[MPU9250_BUFFER_EXT_LEN];
+ struct Mpu9250Config config;
+ enum Mpu9250SpiSlaveInitStatus slave_init_status;
+};
+
+// Functions
+extern void mpu9250_spi_init(struct Mpu9250_Spi *mpu, struct spi_periph *spi_p, uint8_t addr);
+extern void mpu9250_spi_start_configure(struct Mpu9250_Spi *mpu);
+extern void mpu9250_spi_read(struct Mpu9250_Spi *mpu);
+extern void mpu9250_spi_event(struct Mpu9250_Spi *mpu);
+
+/// convenience function: read or start configuration if not already initialized
+static inline void mpu9250_spi_periodic(struct Mpu9250_Spi *mpu) {
+ if (mpu->config.initialized)
+ mpu9250_spi_read(mpu);
+ else
+ mpu9250_spi_start_configure(mpu);
+}
+
+#endif // MPU9250_SPI_H
diff --git a/sw/airborne/subsystems/imu/imu_mpu9250_i2c.c b/sw/airborne/subsystems/imu/imu_mpu9250_i2c.c
new file mode 100644
index 00000000000..24a49708c8d
--- /dev/null
+++ b/sw/airborne/subsystems/imu/imu_mpu9250_i2c.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2014 Gautier Hattenberger
+ *
+ * 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, see
+ * .
+ */
+
+/**
+ * @file subsystems/imu/imu_mpu9250_i2c.c
+ *
+ * IMU driver for the MPU9250 using I2C
+ *
+ */
+
+#include "subsystems/imu.h"
+
+#include "mcu_periph/i2c.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)
+/* Accelerometer: Bandwidth 41Hz, Delay 5.9ms
+ * Gyroscope: Bandwidth 41Hz, Delay 5.9ms sampling 1kHz
+ * Output rate: 100Hz
+ */
+#define IMU_MPU9250_GYRO_LOWPASS_FILTER MPU9250_DLPF_GYRO_41HZ
+#define IMU_MPU9250_ACCEL_LOWPASS_FILTER MPU9250_DLPF_ACCEL_41HZ
+#define IMU_MPU9250_SMPLRT_DIV 9
+PRINT_CONFIG_MSG("Gyro/Accel output rate is 100Hz at 1kHz internal sampling")
+#elif PERIODIC_FREQUENCY == 512
+/* Accelerometer: Bandwidth 184Hz, Delay 5.8ms
+ * Gyroscope: Bandwidth 250Hz, Delay 0.97ms sampling 8kHz
+ * Output rate: 2kHz
+ */
+#define IMU_MPU9250_GYRO_LOWPASS_FILTER MPU9250_DLPF_GYRO_250HZ
+#define IMU_MPU9250_ACCEL_LOWPASS_FILTER MPU9250_DLPF_ACCEL_184HZ
+#define IMU_MPU9250_SMPLRT_DIV 3
+PRINT_CONFIG_MSG("Gyro/Accel output rate is 2kHz at 8kHz internal sampling")
+#else
+/* By default, don't go too fast */
+#define IMU_MPU9250_SMPLRT_DIV 9
+#define IMU_MPU9250_GYRO_LOWPASS_FILTER MPU9250_DLPF_GYRO_41HZ
+#define IMU_MPU9250_ACCEL_LOWPASS_FILTER MPU9250_DLPF_ACCEL_41HZ
+PRINT_CONFIG_MSG("Gyro/Accel output rate is 100Hz at 1kHz internal sampling")
+#endif
+#endif
+PRINT_CONFIG_VAR(IMU_MPU9250_SMPLRT_DIV)
+PRINT_CONFIG_VAR(IMU_MPU9250_GYRO_LOWPASS_FILTER)
+PRINT_CONFIG_VAR(IMU_MPU9250_ACCEL_LOWPASS_FILTER)
+
+#ifndef IMU_MPU9250_GYRO_RANGE
+#define IMU_MPU9250_GYRO_RANGE MPU9250_GYRO_RANGE_1000
+#endif
+PRINT_CONFIG_VAR(IMU_MPU9250_GYRO_RANGE)
+
+#ifndef IMU_MPU9250_ACCEL_RANGE
+#define IMU_MPU9250_ACCEL_RANGE MPU9250_ACCEL_RANGE_8G
+#endif
+PRINT_CONFIG_VAR(IMU_MPU9250_ACCEL_RANGE)
+
+#ifndef IMU_MPU9250_I2C_ADDR
+#define IMU_MPU9250_I2C_ADDR MPU9250_ADDR_ALT
+#endif
+PRINT_CONFIG_VAR(IMU_MPU9250_I2C_ADDR)
+
+// Default channels order
+#ifndef IMU_MPU9250_CHAN_X
+#define IMU_MPU9250_CHAN_X 0
+#endif
+PRINT_CONFIG_VAR(IMU_MPU9250_CHAN_X)
+#ifndef IMU_MPU9250_CHAN_Y
+#define IMU_MPU9250_CHAN_Y 1
+#endif
+PRINT_CONFIG_VAR(IMU_MPU9250_CHAN_Y)
+#ifndef IMU_MPU9250_CHAN_Z
+#define IMU_MPU9250_CHAN_Z 2
+#endif
+PRINT_CONFIG_VAR(IMU_MPU9250_CHAN_Z)
+
+
+struct ImuMpu9250 imu_mpu9250;
+
+void imu_impl_init(void)
+{
+ /* MPU9250 */
+ mpu9250_i2c_init(&imu_mpu9250.mpu, &(IMU_MPU9250_I2C_DEV), IMU_MPU9250_I2C_ADDR);
+ // change the default configuration
+ imu_mpu9250.mpu.config.smplrt_div = IMU_MPU9250_SMPLRT_DIV;
+ imu_mpu9250.mpu.config.dlpf_gyro_cfg = IMU_MPU9250_GYRO_LOWPASS_FILTER;
+ imu_mpu9250.mpu.config.dlpf_accel_cfg = IMU_MPU9250_ACCEL_LOWPASS_FILTER;
+ imu_mpu9250.mpu.config.gyro_range = IMU_MPU9250_GYRO_RANGE;
+ imu_mpu9250.mpu.config.accel_range = IMU_MPU9250_ACCEL_RANGE;
+
+ imu_mpu9250.gyro_valid = FALSE;
+ imu_mpu9250.accel_valid = FALSE;
+ imu_mpu9250.mag_valid = FALSE;
+}
+
+void imu_periodic(void)
+{
+ mpu9250_i2c_periodic(&imu_mpu9250.mpu);
+}
+
+void imu_mpu9250_event(void)
+{
+ // If the MPU9250 I2C transaction has succeeded: convert the data
+ mpu9250_i2c_event(&imu_mpu9250.mpu);
+
+ if (imu_mpu9250.mpu.data_available) {
+ // set channel order
+ struct Int32Vect3 accel = {
+ (int32_t)(imu_mpu9250.mpu.data_accel.value[IMU_MPU9250_CHAN_X]),
+ (int32_t)(imu_mpu9250.mpu.data_accel.value[IMU_MPU9250_CHAN_Y]),
+ (int32_t)(imu_mpu9250.mpu.data_accel.value[IMU_MPU9250_CHAN_Z])
+ };
+ struct Int32Rates rates = {
+ (int32_t)(imu_mpu9250.mpu.data_rates.value[IMU_MPU9250_CHAN_X]),
+ (int32_t)(imu_mpu9250.mpu.data_rates.value[IMU_MPU9250_CHAN_Y]),
+ (int32_t)(imu_mpu9250.mpu.data_rates.value[IMU_MPU9250_CHAN_Z])
+ };
+ // unscaled vector
+ VECT3_COPY(imu.accel_unscaled, accel);
+ RATES_COPY(imu.gyro_unscaled, rates);
+
+ imu_mpu9250.mpu.data_available = FALSE;
+ imu_mpu9250.gyro_valid = TRUE;
+ imu_mpu9250.accel_valid = TRUE;
+ }
+ // Test if mag data are updated
+ if (imu_mpu9250.mpu.akm.data_available) {
+ struct Int32Vect3 mag = {
+ (int32_t)(imu_mpu9250.mpu.akm.data.value[IMU_MPU9250_CHAN_X]),
+ (int32_t)(imu_mpu9250.mpu.akm.data.value[IMU_MPU9250_CHAN_Y]),
+ (int32_t)(imu_mpu9250.mpu.akm.data.value[IMU_MPU9250_CHAN_Z])
+ };
+ VECT3_COPY(imu.mag_unscaled, mag);
+ imu_mpu9250.mag_valid = TRUE;
+ imu_mpu9250.mpu.akm.data_available = FALSE;
+ }
+
+}
+
diff --git a/sw/airborne/subsystems/imu/imu_mpu9250_i2c.h b/sw/airborne/subsystems/imu/imu_mpu9250_i2c.h
new file mode 100644
index 00000000000..2a39b804f7a
--- /dev/null
+++ b/sw/airborne/subsystems/imu/imu_mpu9250_i2c.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 Gautier Hattenberger
+ *
+ * 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, see
+ * .
+ */
+
+/**
+ * @file subsystems/imu/imu_mpu9250_i2c.h
+ *
+ * IMU driver for the MPU9250 using I2C
+ *
+ */
+
+#ifndef IMU_MPU9250_I2C_H
+#define IMU_MPU9250_I2C_H
+
+#include "std.h"
+#include "generated/airframe.h"
+#include "subsystems/imu.h"
+
+#include "peripherals/mpu9250_i2c.h"
+
+
+/** default gyro sensitivy and neutral from the datasheet
+ * MPU with 1000 deg/s has 32.8 LSB/(deg/s)
+ * sens = 1/32.8 * pi/180 * 2^INT32_RATE_FRAC
+ * sens = 1/32.8 * pi/180 * 4096 = 2.17953
+ I*/
+#if !defined IMU_GYRO_P_SENS & !defined IMU_GYRO_Q_SENS & !defined IMU_GYRO_R_SENS
+// FIXME
+#define IMU_GYRO_P_SENS 2.17953
+#define IMU_GYRO_P_SENS_NUM 18271
+#define IMU_GYRO_P_SENS_DEN 8383
+#define IMU_GYRO_Q_SENS 2.17953
+#define IMU_GYRO_Q_SENS_NUM 18271
+#define IMU_GYRO_Q_SENS_DEN 8383
+#define IMU_GYRO_R_SENS 2.17953
+#define IMU_GYRO_R_SENS_NUM 18271
+#define IMU_GYRO_R_SENS_DEN 8383
+#endif
+
+/** default accel sensitivy from the datasheet
+ * MPU with 8g has 4096 LSB/g
+ * sens = 9.81 [m/s^2] / 4096 [LSB/g] * 2^INT32_ACCEL_FRAC = 2.4525
+ */
+#if !defined IMU_ACCEL_X_SENS & !defined IMU_ACCEL_Y_SENS & !defined IMU_ACCEL_Z_SENS
+// FIXME
+#define IMU_ACCEL_X_SENS 2.4525
+#define IMU_ACCEL_X_SENS_NUM 981
+#define IMU_ACCEL_X_SENS_DEN 400
+#define IMU_ACCEL_Y_SENS 2.4525
+#define IMU_ACCEL_Y_SENS_NUM 981
+#define IMU_ACCEL_Y_SENS_DEN 400
+#define IMU_ACCEL_Z_SENS 2.4525
+#define IMU_ACCEL_Z_SENS_NUM 981
+#define IMU_ACCEL_Z_SENS_DEN 400
+#endif
+
+
+struct ImuMpu9250 {
+ volatile bool_t gyro_valid;
+ volatile bool_t accel_valid;
+ volatile bool_t mag_valid;
+ struct Mpu9250_I2c mpu;
+};
+
+extern struct ImuMpu9250 imu_mpu9250;
+
+extern void imu_mpu9250_event(void);
+
+static inline void ImuEvent(void (* _gyro_handler)(void), void (* _accel_handler)(void), void (* _mag_handler)(void)) {
+ imu_mpu9250_event();
+ if (imu_mpu9250.accel_valid) {
+ imu_mpu9250.accel_valid = FALSE;
+ _accel_handler();
+ }
+ if (imu_mpu9250.mag_valid) {
+ imu_mpu9250.mag_valid = FALSE;
+ _mag_handler();
+ }
+ if (imu_mpu9250.gyro_valid) {
+ imu_mpu9250.gyro_valid = FALSE;
+ _gyro_handler();
+ }
+}
+
+#endif /* IMU_MPU9250_I2C_H */