mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-05-30 19:47:50 +08:00
@@ -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
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE module SYSTEM "module.dtd">
|
||||
|
||||
<module name="imu_mpu9250" dir="sensors">
|
||||
<doc>
|
||||
<description>
|
||||
Test module for the mpu9250 with I2C
|
||||
Report RAW values on telemetry
|
||||
</description>
|
||||
<configure name="IMU_MPU9250_I2C_DEV" value="i2c1" description="I2C device to use (e.g. i2c1)"/>
|
||||
<define name="IMU_MPU9250_ADDR" value="MPU9250_ADDR|MPU9250_ADDR_ALT" description="Use regular or alternate I2C address"/>
|
||||
</doc>
|
||||
<header>
|
||||
<file name="imu_mpu9250.h"/>
|
||||
</header>
|
||||
<init fun="imu_mpu9250_init()"/>
|
||||
<periodic fun="imu_mpu9250_periodic()"/>
|
||||
<periodic fun="imu_mpu9250_report()" freq="10" autorun="TRUE"/>
|
||||
<event fun="imu_mpu9250_event()"/>
|
||||
<makefile>
|
||||
<file name="imu_mpu9250.c"/>
|
||||
<file name="mpu9250.c" dir="peripherals"/>
|
||||
<file name="mpu9250_i2c.c" dir="peripherals"/>
|
||||
<file name="ak8963.c" dir="peripherals"/>
|
||||
<define name="USE_I2C"/>
|
||||
<define name="IMU_MPU9250_I2C_DEV" value="$(IMU_MPU9250_I2C_DEV)"/>
|
||||
</makefile>
|
||||
</module>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger <gautier.hattenberger@enac.fr>
|
||||
*
|
||||
* 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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger <gautier.hattenberger@enac.fr>
|
||||
*
|
||||
* 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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
|
||||
*
|
||||
* 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 */
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
|
||||
*
|
||||
* 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 */
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Felix Ruess <felix.ruess@gmail.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger <gautier.hattenberger@enac.fr>
|
||||
*
|
||||
* 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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger <gautier.hattenberger@enac.fr>
|
||||
*
|
||||
* 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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger <gautier.hattenberger@enac.fr>
|
||||
*
|
||||
* 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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger <gautier.hattenberger@enac.fr>
|
||||
*
|
||||
* 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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
Reference in New Issue
Block a user