2018-05-28 11:17:01 +00:00
|
|
|
/*
|
2018-07-16 14:39:19 +00:00
|
|
|
* Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
|
2018-05-28 11:17:01 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the copyright holder nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \addtogroup sensortag-mpu
|
2018-05-28 11:17:01 +00:00
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* \file
|
2018-07-16 14:39:19 +00:00
|
|
|
* Driver for the Sensortag Invensense MPU9250 motion processing unit
|
|
|
|
* \author
|
|
|
|
* Edvard Pettersen <e.pettersen@ti.com>
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#include "contiki.h"
|
|
|
|
#include "lib/sensors.h"
|
|
|
|
#include "sys/rtimer.h"
|
2018-07-24 15:24:06 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#include "board-conf.h"
|
2018-05-31 15:17:07 +00:00
|
|
|
#include "mpu-9250-sensor.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#include <Board.h>
|
2018-07-16 14:39:19 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
#include <ti/devices/DeviceFamily.h>
|
2018-07-26 14:39:37 +00:00
|
|
|
#include DeviceFamily_constructPath(driverlib/cpu.h)
|
2018-07-16 14:39:19 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
#include <ti/drivers/PIN.h>
|
|
|
|
#include <ti/drivers/I2C.h>
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-28 11:17:01 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#define DEBUG 0
|
|
|
|
#if DEBUG
|
|
|
|
#define PRINTF(...) printf(__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define PRINTF(...)
|
|
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-07-24 15:24:06 +00:00
|
|
|
/*
|
|
|
|
* Disable the entire file if sensors are disabled, as it could potentially
|
|
|
|
* create compile errors with missing defines from either the Board file or
|
|
|
|
* configuration defines.
|
|
|
|
*/
|
|
|
|
#if BOARD_SENSORS_ENABLE
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
#ifndef Board_MPU9250_ADDR
|
2018-07-25 16:16:27 +00:00
|
|
|
#error "Board file doesn't define I2C address Board_MPU9250_ADDR"
|
2018-05-31 15:17:07 +00:00
|
|
|
#endif
|
|
|
|
#ifndef Board_MPU9250_MAG_ADDR
|
2018-07-25 16:16:27 +00:00
|
|
|
#error "Board file doesn't define I2C address Board_MPU9250_MAG_ADDR"
|
2018-05-31 15:17:07 +00:00
|
|
|
#endif
|
2018-07-16 14:39:19 +00:00
|
|
|
|
2018-05-28 11:17:01 +00:00
|
|
|
/* Sensor I2C address */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define MPU_9250_I2C_ADDRESS Board_MPU9250_ADDR
|
|
|
|
#define MPU_9250_MAG_I2C_ADDRESS Board_MPU9250_MAG_ADDR
|
|
|
|
/*-------------a--------------------------------------------------------------*/
|
2018-07-16 14:39:19 +00:00
|
|
|
/* Self Test Registers */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define REG_SELF_TEST_X_GYRO 0x00 /* R/W */
|
|
|
|
#define REG_SELF_TEST_Y_GYRO 0x01 /* R/W */
|
|
|
|
#define REG_SELF_TEST_Z_GYRO 0x02 /* R/W */
|
|
|
|
#define REG_SELF_TEST_X_ACCEL 0x0D /* R/W */
|
|
|
|
#define REG_SELF_TEST_Z_ACCEL 0x0E /* R/W */
|
|
|
|
#define REG_SELF_TEST_Y_ACCEL 0x0F /* R/W */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-07-16 14:39:19 +00:00
|
|
|
/* Axis Registers */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define REG_XG_OFFSET_H 0x13 /* R/W */
|
|
|
|
#define REG_XG_OFFSET_L 0x14 /* R/W */
|
|
|
|
#define REG_YG_OFFSET_H 0x15 /* R/W */
|
|
|
|
#define REG_YG_OFFSET_L 0x16 /* R/W */
|
|
|
|
#define REG_ZG_OFFSET_H 0x17 /* R/W */
|
|
|
|
#define REG_ZG_OFFSET_L 0x18 /* R/W */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-07-16 14:39:19 +00:00
|
|
|
/* Control Registers */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define REG_SMPLRT_DIV 0x19 /* R/W */
|
|
|
|
#define REG_CONFIG 0x1A /* R/W */
|
|
|
|
#define REG_GYRO_CONFIG 0x1B /* R/W */
|
|
|
|
#define REG_ACCEL_CONFIG 0x1C /* R/W */
|
|
|
|
#define REG_ACCEL_CONFIG_2 0x1D /* R/W */
|
|
|
|
#define REG_LP_ACCEL_ODR 0x1E /* R/W */
|
|
|
|
#define REG_WOM_THR 0x1F /* R/W */
|
|
|
|
#define REG_FIFO_EN 0x23 /* R/W */
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
|
|
* Registers 0x24 - 0x36 are not applicable to the SensorTag HW configuration
|
|
|
|
* (IC2 Master)
|
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
#define REG_INT_PIN_CFG 0x37 /* R/W */
|
|
|
|
#define REG_INT_ENABLE 0x38 /* R/W */
|
|
|
|
#define REG_INT_STATUS 0x3A /* R */
|
|
|
|
#define REG_ACCEL_XOUT_H 0x3B /* R */
|
|
|
|
#define REG_ACCEL_XOUT_L 0x3C /* R */
|
|
|
|
#define REG_ACCEL_YOUT_H 0x3D /* R */
|
|
|
|
#define REG_ACCEL_YOUT_L 0x3E /* R */
|
|
|
|
#define REG_ACCEL_ZOUT_H 0x3F /* R */
|
|
|
|
#define REG_ACCEL_ZOUT_L 0x40 /* R */
|
|
|
|
#define REG_TEMP_OUT_H 0x41 /* R */
|
|
|
|
#define REG_TEMP_OUT_L 0x42 /* R */
|
|
|
|
#define REG_GYRO_XOUT_H 0x43 /* R */
|
|
|
|
#define REG_GYRO_XOUT_L 0x44 /* R */
|
|
|
|
#define REG_GYRO_YOUT_H 0x45 /* R */
|
|
|
|
#define REG_GYRO_YOUT_L 0x46 /* R */
|
|
|
|
#define REG_GYRO_ZOUT_H 0x47 /* R */
|
|
|
|
#define REG_GYRO_ZOUT_L 0x48 /* R */
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
|
|
* Registers 0x49 - 0x60 are not applicable to the SensorTag HW configuration
|
|
|
|
* (external sensor data)
|
|
|
|
*
|
|
|
|
* Registers 0x63 - 0x67 are not applicable to the SensorTag HW configuration
|
|
|
|
* (I2C master)
|
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
#define REG_SIG_PATH_RST 0x68 /* R/W */
|
|
|
|
#define REG_ACC_INTEL_CTRL 0x69 /* R/W */
|
|
|
|
#define REG_USER_CTRL 0x6A /* R/W */
|
|
|
|
#define REG_PWR_MGMT_1 0x6B /* R/W */
|
|
|
|
#define REG_PWR_MGMT_2 0x6C /* R/W */
|
|
|
|
#define REG_FIFO_COUNT_H 0x72 /* R/W */
|
|
|
|
#define REG_FIFO_COUNT_L 0x73 /* R/W */
|
|
|
|
#define REG_FIFO_R_W 0x74 /* R/W */
|
|
|
|
#define REG_WHO_AM_I 0x75 /* R/W */
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Masks is mpuConfig valiable */
|
|
|
|
#define ACC_CONFIG_MASK 0x38
|
|
|
|
#define GYRO_CONFIG_MASK 0x07
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Values PWR_MGMT_1 */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define PWR_MGMT_1_VAL_MPU_SLEEP 0x4F /* Sleep + stop all clocks */
|
|
|
|
#define PWR_MGMT_1_VAL_MPU_WAKE_UP 0x09 /* Disable temp. + intern osc */
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Values PWR_MGMT_2 */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define PWR_MGMT_2_VAL_ALL_AXES 0x3F
|
|
|
|
#define PWR_MGMT_2_VAL_GYRO_AXES 0x07
|
|
|
|
#define PWR_MGMT_2_VAL_ACC_AXES 0x38
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Output data rates */
|
|
|
|
#define INV_LPA_0_3125HZ 0
|
|
|
|
#define INV_LPA_0_625HZ 1
|
|
|
|
#define INV_LPA_1_25HZ 2
|
|
|
|
#define INV_LPA_2_5HZ 3
|
|
|
|
#define INV_LPA_5HZ 4
|
|
|
|
#define INV_LPA_10HZ 5
|
|
|
|
#define INV_LPA_20HZ 6
|
|
|
|
#define INV_LPA_40HZ 7
|
|
|
|
#define INV_LPA_80HZ 8
|
|
|
|
#define INV_LPA_160HZ 9
|
|
|
|
#define INV_LPA_320HZ 10
|
|
|
|
#define INV_LPA_640HZ 11
|
|
|
|
#define INV_LPA_STOPPED 255
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Bit values */
|
|
|
|
#define BIT_ANY_RD_CLR 0x10
|
|
|
|
#define BIT_RAW_RDY_EN 0x01
|
|
|
|
#define BIT_WOM_EN 0x40
|
|
|
|
#define BIT_LPA_CYCLE 0x20
|
|
|
|
#define BIT_STBY_XA 0x20
|
|
|
|
#define BIT_STBY_YA 0x10
|
|
|
|
#define BIT_STBY_ZA 0x08
|
|
|
|
#define BIT_STBY_XG 0x04
|
|
|
|
#define BIT_STBY_YG 0x02
|
|
|
|
#define BIT_STBY_ZG 0x01
|
|
|
|
#define BIT_STBY_XYZA (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA)
|
|
|
|
#define BIT_STBY_XYZG (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static PIN_Config mpu_9250_pin_table[] = {
|
2018-07-25 16:16:27 +00:00
|
|
|
Board_MPU_INT | PIN_INPUT_EN | PIN_PULLDOWN | PIN_HYSTERESIS,
|
2018-05-31 15:17:07 +00:00
|
|
|
Board_MPU_POWER | PIN_GPIO_OUTPUT_EN | PIN_DRVSTR_MAX | PIN_GPIO_LOW,
|
|
|
|
PIN_TERMINATE
|
|
|
|
};
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-07-25 16:16:27 +00:00
|
|
|
static PIN_State pin_state;
|
2018-07-16 14:39:19 +00:00
|
|
|
static PIN_Handle pin_handle;
|
|
|
|
static I2C_Handle i2c_handle;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
typedef struct {
|
2018-07-25 16:16:27 +00:00
|
|
|
volatile MPU_9250_SENSOR_STATUS status;
|
|
|
|
volatile MPU_9250_SENSOR_TYPE type;
|
|
|
|
MPU_9250_SENSOR_ACC_RANGE acc_range;
|
2018-05-31 15:17:07 +00:00
|
|
|
} MPU_9250_Object;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
static MPU_9250_Object mpu_9250;
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* 3 16-byte words for all sensor readings */
|
|
|
|
#define SENSOR_DATA_BUF_SIZE 3
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Data sizes */
|
|
|
|
#define DATA_SIZE 6
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
|
|
* Wait SENSOR_BOOT_DELAY ticks for the sensor to boot and
|
|
|
|
* SENSOR_STARTUP_DELAY for readings to be ready
|
|
|
|
* Gyro is a little slower than Acc
|
|
|
|
*/
|
|
|
|
#define SENSOR_BOOT_DELAY 8
|
|
|
|
#define SENSOR_STARTUP_DELAY 5
|
|
|
|
|
|
|
|
static struct ctimer startup_timer;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait timeout in rtimer ticks. This is just a random low number, since the
|
|
|
|
* first time we read the sensor status, it should be ready to return data
|
|
|
|
*/
|
|
|
|
#define READING_WAIT_TIMEOUT 10
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Code in flash, cache disabled: 7 cycles per loop */
|
|
|
|
/* ui32Count = [delay in us] * [CPU clock in MHz] / [cycles per loop] */
|
|
|
|
#define delay_ms(ms) CPUdelay((ms) * 1000 * 48 / 7)
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-07-16 14:39:19 +00:00
|
|
|
/**
|
|
|
|
* \brief Setup and peform an I2C transaction.
|
|
|
|
* \param wbuf Output buffer during the I2C transation.
|
|
|
|
* \param wcount How many bytes in the wbuf.
|
|
|
|
* \param rbuf Input buffer during the I2C transation.
|
|
|
|
* \param rcount How many bytes to read into rbuf.
|
|
|
|
* \return true if the I2C operation was successful;
|
|
|
|
* else, return false.
|
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static bool
|
2018-07-16 14:39:19 +00:00
|
|
|
i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount)
|
2018-05-31 15:17:07 +00:00
|
|
|
{
|
2018-07-16 14:39:19 +00:00
|
|
|
I2C_Transaction i2c_transaction = {
|
2018-07-25 16:16:27 +00:00
|
|
|
.writeBuf = wbuf,
|
|
|
|
.writeCount = wcount,
|
|
|
|
.readBuf = rbuf,
|
|
|
|
.readCount = rcount,
|
2018-05-31 15:17:07 +00:00
|
|
|
.slaveAddress = MPU_9250_I2C_ADDRESS,
|
|
|
|
};
|
|
|
|
|
2018-07-16 14:39:19 +00:00
|
|
|
return I2C_transfer(i2c_handle, &i2c_transaction);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* \brief Peform a write only I2C transaction.
|
|
|
|
* \param wbuf Output buffer during the I2C transation.
|
|
|
|
* \param wcount How many bytes in the wbuf.
|
|
|
|
* \return true if the I2C operation was successful;
|
|
|
|
* else, return false.
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
i2c_write(void *wbuf, size_t wcount)
|
|
|
|
{
|
|
|
|
return i2c_write_read(wbuf, wcount, NULL, 0);
|
2018-05-31 15:17:07 +00:00
|
|
|
}
|
2018-07-16 14:39:19 +00:00
|
|
|
/**
|
|
|
|
* \brief Peform a read only I2C transaction.
|
|
|
|
* \param rbuf Input buffer during the I2C transation.
|
|
|
|
* \param rcount How many bytes to read into rbuf.
|
|
|
|
* \return true if the I2C operation was successful;
|
|
|
|
* else, return false.
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
i2c_read(void *rbuf, size_t rcount)
|
|
|
|
{
|
|
|
|
return i2c_write_read(NULL, 0, rbuf, rcount);
|
|
|
|
}
|
2018-05-31 15:17:07 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-07-16 14:39:19 +00:00
|
|
|
/**
|
|
|
|
* \brief Initialize the MPU-9250 sensor driver.
|
|
|
|
* \return true if I2C operation successful; else, return false.
|
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static bool
|
|
|
|
sensor_init(void)
|
|
|
|
{
|
2018-07-16 14:39:19 +00:00
|
|
|
pin_handle = PIN_open(&pin_state, mpu_9250_pin_table);
|
2018-07-23 15:49:18 +00:00
|
|
|
if(pin_handle == NULL) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
I2C_Params i2cParams;
|
|
|
|
I2C_Params_init(&i2cParams);
|
|
|
|
i2cParams.transferMode = I2C_MODE_BLOCKING;
|
|
|
|
i2cParams.bitRate = I2C_400kHz;
|
|
|
|
|
2018-07-16 14:39:19 +00:00
|
|
|
i2c_handle = I2C_open(Board_I2C0, &i2cParams);
|
2018-07-23 15:49:18 +00:00
|
|
|
if(i2c_handle == NULL) {
|
2018-07-16 14:39:19 +00:00
|
|
|
PIN_close(&pin_state);
|
2018-05-31 15:17:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mpu_9250.type = MPU_9250_SENSOR_TYPE_NONE;
|
|
|
|
mpu_9250.status = MPU_9250_SENSOR_STATUS_DISABLED;
|
|
|
|
mpu_9250.acc_range = MPU_9250_SENSOR_ACC_RANGE_ARG;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-28 11:17:01 +00:00
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Place the sensor in low-power mode.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sensor_sleep(void)
|
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
{
|
|
|
|
uint8_t all_axes_data[] = { REG_PWR_MGMT_2, PWR_MGMT_2_VAL_ALL_AXES };
|
|
|
|
i2c_write(all_axes_data, sizeof(all_axes_data));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
uint8_t mpu_sleep_data[] = { REG_PWR_MGMT_1, PWR_MGMT_1_VAL_MPU_SLEEP };
|
|
|
|
i2c_write(mpu_sleep_data, sizeof(mpu_sleep_data));
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Wakeup the sensor from low-power mode.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sensor_wakeup(void)
|
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
{
|
|
|
|
uint8_t mpu_wakeup_data[] = { REG_PWR_MGMT_1, PWR_MGMT_1_VAL_MPU_WAKE_UP };
|
|
|
|
i2c_write(mpu_wakeup_data, sizeof(mpu_wakeup_data));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
/* All axis initially disabled */
|
|
|
|
uint8_t all_axes_data[] = { REG_PWR_MGMT_2, PWR_MGMT_2_VAL_ALL_AXES };
|
|
|
|
i2c_write(all_axes_data, sizeof(all_axes_data));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
/* Restore the range */
|
|
|
|
uint8_t accel_cfg_data[] = { REG_ACCEL_CONFIG, mpu_9250.acc_range };
|
|
|
|
i2c_write(accel_cfg_data, sizeof(accel_cfg_data));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
/* Clear interrupts */
|
|
|
|
uint8_t int_status_data[] = { REG_INT_STATUS };
|
|
|
|
uint8_t dummy;
|
|
|
|
i2c_write_read(int_status_data, sizeof(int_status_data), &dummy, 1);
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void
|
2018-05-31 15:17:07 +00:00
|
|
|
sensor_set_acc_range(MPU_9250_SENSOR_ACC_RANGE acc_range)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Apply the range */
|
|
|
|
uint8_t accel_cfg_data[] = { REG_ACCEL_CONFIG, acc_range };
|
|
|
|
i2c_write(accel_cfg_data, sizeof(accel_cfg_data));
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
|
|
sensor_set_axes(MPU_9250_SENSOR_TYPE sensor_type)
|
|
|
|
{
|
|
|
|
uint8_t _data[] = { REG_PWR_MGMT_2, ~(uint8_t)sensor_type };
|
|
|
|
i2c_write(_data, sizeof(_data));
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
|
|
convert_to_le(uint8_t *data, uint8_t len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < len; i += 2) {
|
|
|
|
uint8_t tmp;
|
|
|
|
tmp = data[i];
|
|
|
|
data[i] = data[i + 1];
|
|
|
|
data[i + 1] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Check whether a data or wake on motion interrupt has occurred.
|
|
|
|
* \return Return the interrupt status.
|
2018-05-28 11:17:01 +00:00
|
|
|
*
|
2018-07-16 14:39:19 +00:00
|
|
|
* This driver does not use interrupts, however this function allows
|
|
|
|
* us to determine whether a new sensor reading is available.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static bool
|
2018-07-25 16:16:27 +00:00
|
|
|
sensor_data_ready(uint8_t *int_status)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
uint8_t int_status_data[] = { REG_INT_STATUS };
|
|
|
|
const bool spi_ok = i2c_write_read(int_status_data, sizeof(int_status_data), int_status, 1);
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
return spi_ok && (*int_status != 0);
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Read data from the accelerometer, total of 3 words (X, Y, Z).
|
|
|
|
* \return true if a valid reading could be taken; otherwise, false.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
|
|
|
static bool
|
2018-05-31 15:17:07 +00:00
|
|
|
acc_read(uint8_t int_status, uint16_t *data)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-07-23 15:49:18 +00:00
|
|
|
if(!(int_status & BIT_RAW_RDY_EN)) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Burst read of all accelerometer values */
|
|
|
|
uint8_t accel_xout_h[] = { REG_ACCEL_XOUT_H };
|
|
|
|
bool spi_ok = i2c_write_read(accel_xout_h, sizeof(accel_xout_h), data, DATA_SIZE);
|
2018-07-23 15:49:18 +00:00
|
|
|
if(!spi_ok) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return false;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-25 16:16:27 +00:00
|
|
|
convert_to_le((uint8_t *)data, DATA_SIZE);
|
2018-05-31 15:17:07 +00:00
|
|
|
|
|
|
|
return true;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Read data from the accelerometer, total of 3 words (X, Y, Z).
|
|
|
|
* \return true if a valid reading could be taken; otherwise, false.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
|
|
|
static bool
|
2018-05-31 15:17:07 +00:00
|
|
|
gyro_read(uint8_t int_status, uint16_t *data)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-07-23 15:49:18 +00:00
|
|
|
if(!(int_status & BIT_RAW_RDY_EN)) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Burst read of all accelerometer values */
|
|
|
|
uint8_t gyro_xout_h[] = { REG_GYRO_XOUT_H };
|
|
|
|
bool spi_ok = i2c_write_read(gyro_xout_h, sizeof(gyro_xout_h), data, DATA_SIZE);
|
2018-07-23 15:49:18 +00:00
|
|
|
if(!spi_ok) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return false;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-25 16:16:27 +00:00
|
|
|
convert_to_le((uint8_t *)data, DATA_SIZE);
|
2018-05-31 15:17:07 +00:00
|
|
|
|
|
|
|
return true;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Convert accelerometer raw reading to a value in G.
|
|
|
|
* \param raw_data The raw accelerometer reading.
|
|
|
|
* \return The converted value.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static int32_t
|
|
|
|
acc_convert(int32_t raw_data)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-07-23 15:49:18 +00:00
|
|
|
switch(mpu_9250.acc_range) {
|
2018-07-25 16:16:27 +00:00
|
|
|
case MPU_9250_SENSOR_ACC_RANGE_2G: return raw_data * 100 * 2 / 32768;
|
|
|
|
case MPU_9250_SENSOR_ACC_RANGE_4G: return raw_data * 100 * 4 / 32768;
|
|
|
|
case MPU_9250_SENSOR_ACC_RANGE_8G: return raw_data * 100 * 8 / 32768;
|
2018-05-31 15:17:07 +00:00
|
|
|
case MPU_9250_SENSOR_ACC_RANGE_16G: return raw_data * 100 * 16 / 32768;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
2018-05-31 15:17:07 +00:00
|
|
|
return 0;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Convert gyro raw reading to a value in deg/sec.
|
|
|
|
* \param raw_data The raw accelerometer reading.
|
|
|
|
* \return The converted value.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static int32_t
|
|
|
|
gyro_convert(int32_t raw_data)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
|
|
|
/* calculate rotation, unit deg/s, range -250, +250 */
|
2018-05-31 15:17:07 +00:00
|
|
|
return raw_data * 100 * 500 / 65536;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void
|
2018-05-31 15:17:07 +00:00
|
|
|
notify_ready_cb(void *unused)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
(void)unused;
|
|
|
|
|
|
|
|
mpu_9250.status = MPU_9250_SENSOR_STATUS_READY;
|
2018-05-28 11:17:01 +00:00
|
|
|
sensors_changed(&mpu_9250_sensor);
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void
|
2018-05-31 15:17:07 +00:00
|
|
|
initialise_cb(void *unused)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
(void)unused;
|
|
|
|
|
2018-07-23 15:49:18 +00:00
|
|
|
if(mpu_9250.type == MPU_9250_SENSOR_TYPE_NONE) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Wake up the sensor */
|
|
|
|
sensor_wakeup();
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Configure the accelerometer range */
|
2018-07-23 15:49:18 +00:00
|
|
|
if((mpu_9250.type & MPU_9250_SENSOR_TYPE_ACC) != 0) {
|
2018-05-31 15:17:07 +00:00
|
|
|
sensor_set_acc_range(mpu_9250.acc_range);
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Enable gyro + accelerometer readout */
|
|
|
|
sensor_set_axes(mpu_9250.type);
|
|
|
|
delay_ms(10);
|
|
|
|
|
|
|
|
ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL);
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Returns a reading from the sensor.
|
|
|
|
* \param type MPU_9250_SENSOR_TYPE_ACC_[XYZ] or
|
|
|
|
* MPU_9250_SENSOR_TYPE_GYRO_[XYZ].
|
|
|
|
* \return Centi-G (ACC) or centi-Deg/Sec (Gyro).
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
value(int type)
|
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
if(mpu_9250.status == MPU_9250_SENSOR_STATUS_DISABLED) {
|
2018-05-28 11:17:01 +00:00
|
|
|
PRINTF("MPU: Sensor Disabled\n");
|
2018-05-31 15:17:07 +00:00
|
|
|
return MPU_9250_READING_ERROR;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-23 15:49:18 +00:00
|
|
|
if(mpu_9250.type == MPU_9250_SENSOR_TYPE_NONE) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return MPU_9250_READING_ERROR;
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
uint8_t int_status = 0;
|
|
|
|
const rtimer_clock_t t0 = RTIMER_NOW();
|
2018-07-23 15:49:18 +00:00
|
|
|
while(!sensor_data_ready(&int_status)) {
|
|
|
|
if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + READING_WAIT_TIMEOUT))) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return MPU_9250_READING_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
uint16_t sensor_value[SENSOR_DATA_BUF_SIZE];
|
|
|
|
memset(sensor_value, 0, sizeof(sensor_value));
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Read accel data */
|
2018-07-23 15:49:18 +00:00
|
|
|
if((type & MPU_9250_SENSOR_TYPE_ACC) != 0) {
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-07-23 15:49:18 +00:00
|
|
|
if(!acc_read(int_status, sensor_value)) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return MPU_9250_READING_ERROR;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PRINTF("MPU: ACC = 0x%04x 0x%04x 0x%04x = ",
|
|
|
|
sensor_value[0], sensor_value[1], sensor_value[2]);
|
|
|
|
|
|
|
|
/* Convert */
|
2018-07-23 15:49:18 +00:00
|
|
|
switch(type) {
|
2018-05-31 15:17:07 +00:00
|
|
|
case MPU_9250_SENSOR_TYPE_ACC_X: return acc_convert(sensor_value[0]);
|
|
|
|
case MPU_9250_SENSOR_TYPE_ACC_Y: return acc_convert(sensor_value[1]);
|
|
|
|
case MPU_9250_SENSOR_TYPE_ACC_Z: return acc_convert(sensor_value[2]);
|
|
|
|
default: return MPU_9250_READING_ERROR;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-25 16:16:27 +00:00
|
|
|
/* Read gyro data */
|
2018-05-31 15:17:07 +00:00
|
|
|
} else if((type & MPU_9250_SENSOR_TYPE_GYRO) != 0) {
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-07-23 15:49:18 +00:00
|
|
|
if(!gyro_read(int_status, sensor_value)) {
|
2018-05-31 15:17:07 +00:00
|
|
|
return MPU_9250_READING_ERROR;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PRINTF("MPU: Gyro = 0x%04x 0x%04x 0x%04x = ",
|
|
|
|
sensor_value[0], sensor_value[1], sensor_value[2]);
|
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Convert */
|
2018-07-23 15:49:18 +00:00
|
|
|
switch(type) {
|
2018-05-31 15:17:07 +00:00
|
|
|
case MPU_9250_SENSOR_TYPE_GYRO_X: return gyro_convert(sensor_value[0]);
|
|
|
|
case MPU_9250_SENSOR_TYPE_GYRO_Y: return gyro_convert(sensor_value[1]);
|
|
|
|
case MPU_9250_SENSOR_TYPE_GYRO_Z: return gyro_convert(sensor_value[2]);
|
|
|
|
default: return MPU_9250_READING_ERROR;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
2018-05-31 15:17:07 +00:00
|
|
|
|
2018-07-25 16:16:27 +00:00
|
|
|
/* Invalid sensor type */
|
2018-05-28 11:17:01 +00:00
|
|
|
} else {
|
|
|
|
PRINTF("MPU: Invalid type\n");
|
2018-05-31 15:17:07 +00:00
|
|
|
return MPU_9250_READING_ERROR;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Configuration function for the MPU9250 sensor.
|
|
|
|
* \param type Activate, enable or disable the sensor. See below.
|
|
|
|
* \param enable Enable or disable sensor.
|
|
|
|
* When type == SENSORS_HW_INIT we turn on the hardware.
|
|
|
|
* When type == SENSORS_ACTIVE and enable==1 we enable the sensor.
|
|
|
|
* When type == SENSORS_ACTIVE and enable==0 we disable the sensor.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
configure(int type, int enable)
|
|
|
|
{
|
2018-07-25 16:16:27 +00:00
|
|
|
/* Mask enable */
|
2018-05-31 15:17:07 +00:00
|
|
|
const MPU_9250_SENSOR_TYPE enable_type = enable & MPU_9250_SENSOR_TYPE_ALL;
|
|
|
|
|
2018-05-28 11:17:01 +00:00
|
|
|
switch(type) {
|
|
|
|
case SENSORS_HW_INIT:
|
2018-07-23 15:49:18 +00:00
|
|
|
if(sensor_init()) {
|
2018-05-31 15:17:07 +00:00
|
|
|
mpu_9250.status = MPU_9250_SENSOR_STATUS_ENABLED;
|
|
|
|
} else {
|
|
|
|
mpu_9250.status = MPU_9250_SENSOR_STATUS_DISABLED;
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
break;
|
2018-05-31 15:17:07 +00:00
|
|
|
|
2018-05-28 11:17:01 +00:00
|
|
|
case SENSORS_ACTIVE:
|
2018-07-23 15:49:18 +00:00
|
|
|
if(enable_type != MPU_9250_SENSOR_TYPE_NONE) {
|
2018-05-28 11:17:01 +00:00
|
|
|
PRINTF("MPU: Enabling\n");
|
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
mpu_9250.type = enable_type;
|
|
|
|
mpu_9250.status = MPU_9250_SENSOR_STATUS_BOOTING;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-07-16 14:39:19 +00:00
|
|
|
PIN_setOutputValue(pin_handle, Board_MPU_POWER, 1);
|
2018-05-31 15:17:07 +00:00
|
|
|
|
|
|
|
ctimer_set(&startup_timer, SENSOR_BOOT_DELAY, initialise_cb, NULL);
|
2018-05-28 11:17:01 +00:00
|
|
|
} else {
|
|
|
|
PRINTF("MPU: Disabling\n");
|
2018-05-31 15:17:07 +00:00
|
|
|
|
|
|
|
ctimer_stop(&startup_timer);
|
|
|
|
|
2018-07-23 15:49:18 +00:00
|
|
|
if(PIN_getOutputValue(Board_MPU_POWER)) {
|
2018-05-28 11:17:01 +00:00
|
|
|
sensor_sleep();
|
2018-05-31 15:17:07 +00:00
|
|
|
|
2018-07-16 14:39:19 +00:00
|
|
|
I2C_cancel(i2c_handle);
|
|
|
|
PIN_setOutputValue(pin_handle, Board_MPU_POWER, 0);
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
2018-05-31 15:17:07 +00:00
|
|
|
|
|
|
|
mpu_9250.type = MPU_9250_SENSOR_TYPE_NONE;
|
|
|
|
mpu_9250.status = MPU_9250_SENSOR_STATUS_DISABLED;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
break;
|
2018-05-31 15:17:07 +00:00
|
|
|
|
2018-05-28 11:17:01 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2018-05-31 15:17:07 +00:00
|
|
|
return mpu_9250.status;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
2018-07-16 14:39:19 +00:00
|
|
|
* \brief Returns the status of the sensor
|
|
|
|
* \param type SENSORS_ACTIVE or SENSORS_READY
|
|
|
|
* \return 1 if the sensor is enabled, else 0.
|
2018-05-28 11:17:01 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
status(int type)
|
|
|
|
{
|
2018-07-23 15:49:18 +00:00
|
|
|
switch(type) {
|
2018-05-28 11:17:01 +00:00
|
|
|
case SENSORS_ACTIVE:
|
|
|
|
case SENSORS_READY:
|
2018-05-31 15:17:07 +00:00
|
|
|
return mpu_9250.status;
|
|
|
|
|
2018-05-28 11:17:01 +00:00
|
|
|
default:
|
2018-05-31 15:17:07 +00:00
|
|
|
return MPU_9250_SENSOR_STATUS_DISABLED;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
SENSORS_SENSOR(mpu_9250_sensor, "MPU9250", value, configure, status);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-07-24 15:24:06 +00:00
|
|
|
#endif /* BOARD_SENSORS_ENABLE */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-28 11:17:01 +00:00
|
|
|
/** @} */
|