2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_MPU9250 MPU9250 Functions
6 * @brief Deals with the hardware interface to the 9 DOF sensor.
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2014.
11 * @brief MPU9250 9-axis gyro, accel and mag chip
12 * @see The GNU Public License (GPL) Version 3
14 ******************************************************************************
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include <pios_mpu9250.h>
34 #ifdef PIOS_INCLUDE_MPU9250
36 #include <pios_constants.h>
37 #include <pios_sensors.h>
38 /* Global Variables */
40 enum pios_mpu9250_dev_magic
{
41 PIOS_MPU9250_DEV_MAGIC
= 0x9da9b3ed,
48 const struct pios_mpu9250_cfg
*cfg
;
49 enum pios_mpu9250_range gyro_range
;
50 enum pios_mpu9250_accel_range accel_range
;
51 enum pios_mpu9250_filter filter
;
52 enum pios_mpu9250_dev_magic magic
;
53 float mag_sens_adj
[PIOS_MPU9250_MAG_ASA_NB_BYTE
];
56 #ifdef PIOS_MPU9250_ACCEL
57 #define PIOS_MPU9250_ACCEL_SAMPLES_BYTES (6)
59 #define PIOS_MPU9250_ACCEL_SAMPLES_BYTES (0)
62 #ifdef PIOS_MPU9250_MAG
63 #define PIOS_MPU9250_MAG_SAMPLES_BYTES (8)
65 #define PIOS_MPU9250_MAG_SAMPLES_BYTES (0)
68 #define PIOS_MPU9250_GYRO_SAMPLES_BYTES (6)
69 #define PIOS_MPU9250_TEMP_SAMPLES_BYTES (2)
71 #define PIOS_MPU9250_SAMPLES_BYTES \
72 (PIOS_MPU9250_ACCEL_SAMPLES_BYTES + \
73 PIOS_MPU9250_GYRO_SAMPLES_BYTES + \
74 PIOS_MPU9250_TEMP_SAMPLES_BYTES + \
75 PIOS_MPU9250_MAG_SAMPLES_BYTES)
77 #ifdef PIOS_MPU9250_ACCEL
78 #define PIOS_MPU9250_SENSOR_FIRST_REG PIOS_MPU9250_ACCEL_X_OUT_MSB
80 #define PIOS_MPU9250_SENSOR_FIRST_REG PIOS_MPU9250_TEMP_OUT_MSB
83 #if defined(PIOS_MPU9250_MAG) && !defined(PIOS_MPU9250_ACCEL)
84 #error ERROR: PIOS_MPU9250_ACCEL not defined! THIS CONFIGURATION IS NOT SUPPORTED
88 uint8_t buffer
[2 + PIOS_MPU9250_SAMPLES_BYTES
];
91 #ifdef PIOS_MPU9250_ACCEL
99 uint8_t Temperature_h
;
100 uint8_t Temperature_l
;
107 #ifdef PIOS_MPU9250_MAG
118 } __attribute__((__packed__
)) mpu9250_data_t
;
120 #define GET_SENSOR_DATA(mpudataptr, sensor) (mpudataptr.data.sensor##_h << 8 | mpudataptr.data.sensor##_l)
122 static PIOS_SENSORS_3Axis_SensorsWithTemp
*queue_data
= 0;
123 static PIOS_SENSORS_3Axis_SensorsWithTemp
*mag_data
= 0;
124 static volatile bool mag_ready
= false;
125 #define SENSOR_COUNT 2
126 #define SENSOR_DATA_SIZE (sizeof(PIOS_SENSORS_3Axis_SensorsWithTemp) + sizeof(Vector3i16) * SENSOR_COUNT)
127 #define MAG_SENSOR_DATA_SIZE (sizeof(PIOS_SENSORS_3Axis_SensorsWithTemp) + sizeof(Vector3i16))
128 // ! Global structure for this device device
129 static struct mpu9250_dev
*dev
;
130 volatile bool mpu9250_configured
= false;
131 static mpu9250_data_t mpu9250_data
;
133 // ! Private functions
134 static struct mpu9250_dev
*PIOS_MPU9250_alloc(const struct pios_mpu9250_cfg
*cfg
);
135 static int32_t PIOS_MPU9250_Validate(struct mpu9250_dev
*dev
);
136 static void PIOS_MPU9250_Config(struct pios_mpu9250_cfg
const *cfg
);
137 static int32_t PIOS_MPU9250_SetReg(uint8_t address
, uint8_t buffer
);
138 static int32_t PIOS_MPU9250_GetReg(uint8_t address
);
139 static void PIOS_MPU9250_SetSpeed(const bool fast
);
140 static bool PIOS_MPU9250_HandleData(uint32_t gyro_read_timestamp
);
141 static bool PIOS_MPU9250_ReadSensor(bool *woken
);
142 static int32_t PIOS_MPU9250_Test(void);
143 #if defined(PIOS_MPU9250_MAG)
144 static int32_t PIOS_MPU9250_Mag_Test(void);
145 static int32_t PIOS_MPU9250_Mag_Init(void);
148 /* Driver Framework interfaces */
149 // Gyro/accel interface
150 bool PIOS_MPU9250_Main_driver_Test(uintptr_t context
);
151 void PIOS_MPU9250_Main_driver_Reset(uintptr_t context
);
152 void PIOS_MPU9250_Main_driver_get_scale(float *scales
, uint8_t size
, uintptr_t context
);
153 QueueHandle_t
PIOS_MPU9250_Main_driver_get_queue(uintptr_t context
);
155 const PIOS_SENSORS_Driver PIOS_MPU9250_Main_Driver
= {
156 .test
= PIOS_MPU9250_Main_driver_Test
,
159 .reset
= PIOS_MPU9250_Main_driver_Reset
,
160 .get_queue
= PIOS_MPU9250_Main_driver_get_queue
,
161 .get_scale
= PIOS_MPU9250_Main_driver_get_scale
,
165 // mag sensor interface
166 bool PIOS_MPU9250_Mag_driver_Test(uintptr_t context
);
167 void PIOS_MPU9250_Mag_driver_Reset(uintptr_t context
);
168 void PIOS_MPU9250_Mag_driver_get_scale(float *scales
, uint8_t size
, uintptr_t context
);
169 void PIOS_MPU9250_Mag_driver_fetch(void *, uint8_t size
, uintptr_t context
);
170 bool PIOS_MPU9250_Mag_driver_poll(uintptr_t context
);
172 const PIOS_SENSORS_Driver PIOS_MPU9250_Mag_Driver
= {
173 .test
= PIOS_MPU9250_Mag_driver_Test
,
174 .poll
= PIOS_MPU9250_Mag_driver_poll
,
175 .fetch
= PIOS_MPU9250_Mag_driver_fetch
,
176 .reset
= PIOS_MPU9250_Mag_driver_Reset
,
178 .get_scale
= PIOS_MPU9250_Mag_driver_get_scale
,
182 void PIOS_MPU9250_MainRegister()
184 PIOS_SENSORS_Register(&PIOS_MPU9250_Main_Driver
, PIOS_SENSORS_TYPE_3AXIS_GYRO_ACCEL
, 0);
187 void PIOS_MPU9250_MagRegister()
189 PIOS_SENSORS_Register(&PIOS_MPU9250_Mag_Driver
, PIOS_SENSORS_TYPE_3AXIS_MAG
, 0);
192 * @brief Allocate a new device
194 static struct mpu9250_dev
*PIOS_MPU9250_alloc(const struct pios_mpu9250_cfg
*cfg
)
196 struct mpu9250_dev
*mpu9250_dev
;
198 mpu9250_dev
= (struct mpu9250_dev
*)pios_malloc(sizeof(*mpu9250_dev
));
199 PIOS_Assert(mpu9250_dev
);
201 mpu9250_dev
->magic
= PIOS_MPU9250_DEV_MAGIC
;
203 mpu9250_dev
->queue
= xQueueCreate(cfg
->max_downsample
+ 1, SENSOR_DATA_SIZE
);
204 PIOS_Assert(mpu9250_dev
->queue
);
206 queue_data
= (PIOS_SENSORS_3Axis_SensorsWithTemp
*)pios_malloc(SENSOR_DATA_SIZE
);
207 PIOS_Assert(queue_data
);
209 queue_data
->count
= SENSOR_COUNT
;
211 mag_data
= (PIOS_SENSORS_3Axis_SensorsWithTemp
*)pios_malloc(MAG_SENSOR_DATA_SIZE
);
213 PIOS_Assert(mag_data
);
218 * @brief Validate the handle to the spi device
219 * @returns 0 for valid device or -1 otherwise
221 static int32_t PIOS_MPU9250_Validate(struct mpu9250_dev
*vdev
)
226 if (vdev
->magic
!= PIOS_MPU9250_DEV_MAGIC
) {
229 if (vdev
->spi_id
== 0) {
236 * @brief Initialize the MPU9250 3-axis gyro sensor.
237 * @return 0 for success, -1 for failure
239 int32_t PIOS_MPU9250_Init(uint32_t spi_id
, uint32_t slave_num
, const struct pios_mpu9250_cfg
*cfg
)
241 dev
= PIOS_MPU9250_alloc(cfg
);
246 dev
->spi_id
= spi_id
;
247 dev
->slave_num
= slave_num
;
250 /* Configure the MPU9250 Sensor */
251 PIOS_MPU9250_Config(cfg
);
253 /* Set up EXTI line */
254 PIOS_EXTI_Init(cfg
->exti_cfg
);
259 * @brief Initialize the MPU9250 3-axis gyro sensor
261 * \param[in] PIOS_MPU9250_ConfigTypeDef struct to be used to configure sensor.
264 static void PIOS_MPU9250_Config(struct pios_mpu9250_cfg
const *cfg
)
268 while (PIOS_MPU9250_Test() != 0) {
273 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_PWR_MGMT_REG
, PIOS_MPU9250_PWRMGMT_IMU_RST
) != 0) {
277 PIOS_DELAY_WaitmS(100);
280 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_PWR_MGMT_REG
, 0) != 0) {
283 // Reset sensors and fifo
284 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_USER_CTRL_REG
,
285 PIOS_MPU9250_USERCTL_DIS_I2C
|
286 PIOS_MPU9250_USERCTL_SIG_COND
) != 0) {
289 PIOS_DELAY_WaitmS(100);
291 // Power management configuration
292 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_PWR_MGMT_REG
, cfg
->Pwr_mgmt_clk
) != 0) {
296 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_USER_CTRL_REG
, cfg
->User_ctl
) != 0) {
300 // FIFO storage by default, do not include accelerometer and external sense data.
301 power
= PIOS_MPU9250_PWRMGMT2_DISABLE_ACCEL
;
303 #if defined(PIOS_MPU9250_ACCEL)
305 power
&= ~PIOS_MPU9250_PWRMGMT2_DISABLE_ACCEL
;
308 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_FIFO_EN_REG
, cfg
->Fifo_store
) != 0) {
311 PIOS_MPU9250_SetReg(PIOS_MPU9250_PWR_MGMT2_REG
, power
);
313 #if defined(PIOS_MPU9250_ACCEL)
314 PIOS_MPU9250_ConfigureRanges(cfg
->gyro_range
, cfg
->accel_range
, cfg
->filter
);
317 // Interrupt configuration
318 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_INT_CFG_REG
, cfg
->interrupt_cfg
) != 0) {
322 #ifdef PIOS_MPU9250_MAG
323 PIOS_MPU9250_Mag_Init();
327 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_INT_EN_REG
, cfg
->interrupt_en
) != 0) {
330 if ((PIOS_MPU9250_GetReg(PIOS_MPU9250_INT_EN_REG
)) != cfg
->interrupt_en
) {
334 PIOS_MPU9250_GetReg(PIOS_MPU9250_INT_STATUS_REG
);
336 mpu9250_configured
= true;
339 * @brief Configures Gyro, accel and Filter ranges/setings
340 * @return 0 if successful, -1 if device has not been initialized
342 int32_t PIOS_MPU9250_ConfigureRanges(
343 enum pios_mpu9250_range gyroRange
,
344 enum pios_mpu9250_accel_range accelRange
,
345 enum pios_mpu9250_filter filterSetting
)
351 // update filter settings
352 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_DLPF_CFG_REG
, filterSetting
) != 0) {
356 // Sample rate divider, chosen upon digital filtering settings
357 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_SMPLRT_DIV_REG
,
358 filterSetting
== PIOS_MPU9250_LOWPASS_256_HZ
?
359 dev
->cfg
->Smpl_rate_div_no_dlp
: dev
->cfg
->Smpl_rate_div_dlp
) != 0) {
363 dev
->filter
= filterSetting
;
366 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_GYRO_CFG_REG
, gyroRange
) != 0) {
370 dev
->gyro_range
= gyroRange
;
371 #if defined(PIOS_MPU9250_ACCEL)
372 // Set the accel range
373 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_ACCEL_CFG_REG
, accelRange
) != 0) {
377 dev
->accel_range
= accelRange
;
383 * @brief Claim the SPI bus for the accel communications and select this chip
384 * @return 0 if successful, -1 for invalid device, -2 if unable to claim bus
386 static int32_t PIOS_MPU9250_ClaimBus(bool fast_spi
)
388 if (PIOS_MPU9250_Validate(dev
) != 0) {
391 if (PIOS_SPI_ClaimBus(dev
->spi_id
) != 0) {
394 PIOS_MPU9250_SetSpeed(fast_spi
);
395 PIOS_SPI_RC_PinSet(dev
->spi_id
, dev
->slave_num
, 0);
400 static void PIOS_MPU9250_SetSpeed(const bool fast
)
403 PIOS_SPI_SetClockSpeed(dev
->spi_id
, dev
->cfg
->fast_prescaler
);
405 PIOS_SPI_SetClockSpeed(dev
->spi_id
, dev
->cfg
->std_prescaler
);
410 * @brief Claim the SPI bus for the accel communications and select this chip
411 * @return 0 if successful, -1 for invalid device, -2 if unable to claim bus
412 * @param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
413 * task has is now eligible to run, else unchanged
415 static int32_t PIOS_MPU9250_ClaimBusISR(bool *woken
, bool fast_spi
)
417 if (PIOS_MPU9250_Validate(dev
) != 0) {
420 if (PIOS_SPI_ClaimBusISR(dev
->spi_id
, woken
) != 0) {
423 PIOS_MPU9250_SetSpeed(fast_spi
);
424 PIOS_SPI_RC_PinSet(dev
->spi_id
, dev
->slave_num
, 0);
429 * @brief Release the SPI bus for the accel communications and end the transaction
430 * @return 0 if successful
432 static int32_t PIOS_MPU9250_ReleaseBus()
434 if (PIOS_MPU9250_Validate(dev
) != 0) {
437 PIOS_SPI_RC_PinSet(dev
->spi_id
, dev
->slave_num
, 1);
438 return PIOS_SPI_ReleaseBus(dev
->spi_id
);
442 * @brief Release the SPI bus for the accel communications and end the transaction
443 * @return 0 if successful
444 * @param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
445 * task has is now eligible to run, else unchanged
447 static int32_t PIOS_MPU9250_ReleaseBusISR(bool *woken
)
449 if (PIOS_MPU9250_Validate(dev
) != 0) {
452 PIOS_SPI_RC_PinSet(dev
->spi_id
, dev
->slave_num
, 1);
453 return PIOS_SPI_ReleaseBusISR(dev
->spi_id
, woken
);
457 * @brief Read a register from MPU9250
458 * @returns The register value or -1 if failure to get bus
459 * @param reg[in] Register address to be read
461 static int32_t PIOS_MPU9250_GetReg(uint8_t reg
)
465 if (PIOS_MPU9250_ClaimBus(false) != 0) {
469 PIOS_SPI_TransferByte(dev
->spi_id
, (0x80 | reg
)); // request byte
470 data
= PIOS_SPI_TransferByte(dev
->spi_id
, 0); // receive response
472 PIOS_MPU9250_ReleaseBus();
477 * @brief Writes one byte to the MPU9250
478 * \param[in] reg Register address
479 * \param[in] data Byte to write
480 * \return 0 if operation was successful
481 * \return -1 if unable to claim SPI bus
482 * \return -2 if unable to send the command
483 * \return -3 if unable to receive the response
485 static int32_t PIOS_MPU9250_SetReg(uint8_t reg
, uint8_t data
)
489 if (PIOS_MPU9250_ClaimBus(false) != 0) {
493 PIOS_SPI_TransferByte(dev
->spi_id
, 0x7f & reg
);
494 // if (PIOS_SPI_TransferByte(dev->spi_id, 0x7f & reg) != 0) {
495 // PIOS_MPU9250_ReleaseBus();
499 PIOS_SPI_TransferByte(dev
->spi_id
, data
);
500 // if (PIOS_SPI_TransferByte(dev->spi_id, data) != 0) {
501 // PIOS_MPU9250_ReleaseBus();
505 PIOS_MPU9250_ReleaseBus();
512 * @brief Read the identification bytes from the MPU9250 sensor
513 * \return ID read from MPU9250 or -1 if failure
515 int32_t PIOS_MPU9250_ReadID()
517 int32_t mpu9250_id
= PIOS_MPU9250_GetReg(PIOS_MPU9250_WHOAMI
);
519 if (mpu9250_id
< 0) {
525 static float PIOS_MPU9250_GetScale()
527 switch (dev
->gyro_range
) {
528 case PIOS_MPU9250_SCALE_250_DEG
:
529 return 1.0f
/ 131.0f
;
531 case PIOS_MPU9250_SCALE_500_DEG
:
534 case PIOS_MPU9250_SCALE_1000_DEG
:
537 case PIOS_MPU9250_SCALE_2000_DEG
:
543 static float PIOS_MPU9250_GetAccelScale()
545 switch (dev
->accel_range
) {
546 case PIOS_MPU9250_ACCEL_2G
:
547 return PIOS_CONST_MKS_GRAV_ACCEL_F
/ 16384.0f
;
549 case PIOS_MPU9250_ACCEL_4G
:
550 return PIOS_CONST_MKS_GRAV_ACCEL_F
/ 8192.0f
;
552 case PIOS_MPU9250_ACCEL_8G
:
553 return PIOS_CONST_MKS_GRAV_ACCEL_F
/ 4096.0f
;
555 case PIOS_MPU9250_ACCEL_16G
:
556 return PIOS_CONST_MKS_GRAV_ACCEL_F
/ 2048.0f
;
562 * @brief Run self-test operation.
563 * \return 0 if test succeeded
564 * \return non-zero value if test failed
566 static int32_t PIOS_MPU9250_Test(void)
568 /* Verify that ID matches */
569 int32_t mpu9250_id
= PIOS_MPU9250_ReadID();
571 if (mpu9250_id
< 0) {
575 if (mpu9250_id
!= PIOS_MPU9250_GYRO_ACC_ID
) {
582 #if defined(PIOS_MPU9250_MAG)
584 * @brief Read a mag register from MPU9250
585 * @returns The register value or -1 if failure to get bus
586 * @param reg[in] Register address to be read
588 static int32_t PIOS_MPU9250_Mag_GetReg(uint8_t reg
)
592 // Set the I2C slave address and read command.
593 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV4_ADDR
, PIOS_MPU9250_MAG_I2C_ADDR
|
594 PIOS_MPU9250_MAG_I2C_READ_FLAG
) != PIOS_MPU9250_MAG_OK
) {
598 // Set the address of the register to read.
599 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV4_REG
, reg
) != PIOS_MPU9250_MAG_OK
) {
603 // Trigger the byte transfer.
604 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV4_CTRL
, PIOS_MPU9250_I2C_SLV_ENABLE
) != PIOS_MPU9250_MAG_OK
) {
608 PIOS_DELAY_WaitmS(1);
611 data
= PIOS_MPU9250_GetReg(PIOS_MPU9250_I2C_SLV4_DI
);
612 PIOS_DELAY_WaitmS(1);
617 * @brief Writes one byte to the MPU9250
618 * \param[in] reg Register address
619 * \param[in] data Byte to write
621 static int32_t PIOS_MPU9250_Mag_SetReg(uint8_t reg
, uint8_t data
)
623 // Set the I2C slave address.
624 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV4_ADDR
, PIOS_MPU9250_MAG_I2C_ADDR
) != PIOS_MPU9250_MAG_OK
) {
628 // Set the address of the register to write.
629 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV4_REG
, reg
) != PIOS_MPU9250_MAG_OK
) {
633 // Set the byte to write.
634 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV4_DO
, data
) != PIOS_MPU9250_MAG_OK
) {
638 // Trigger the byte transfer.
639 while (PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV4_CTRL
, PIOS_MPU9250_I2C_SLV_ENABLE
) != PIOS_MPU9250_MAG_OK
) {
642 PIOS_DELAY_WaitmS(1);
643 return PIOS_MPU9250_MAG_OK
;
647 * @rief Get ASAx registers from fuse ROM
648 * Hadj = H*((ASA-128)*0.5/128+1)
649 * \return 0 if test succeeded
650 * \return non-zero value if test failed
652 static int32_t PIOS_MPU9250_Mag_Sensitivity(void)
656 /* Put mag in power down state before changing mode */
657 PIOS_MPU9250_Mag_SetReg(PIOS_MPU9250_CNTL1
, PIOS_MPU9250_MAG_POWER_DOWN_MODE
);
658 PIOS_DELAY_WaitmS(1);
660 /* Enable fuse ROM for access */
661 PIOS_MPU9250_Mag_SetReg(PIOS_MPU9250_CNTL1
, PIOS_MPU9250_MAG_FUSE_ROM_MODE
);
662 PIOS_DELAY_WaitmS(1);
664 if (PIOS_MPU9250_ClaimBus(false) != 0) {
668 /* Set addres and read flag */
669 PIOS_SPI_TransferByte(dev
->spi_id
, PIOS_MPU9250_I2C_SLV0_ADDR
);
670 PIOS_SPI_TransferByte(dev
->spi_id
, PIOS_MPU9250_MAG_I2C_ADDR
| PIOS_MPU9250_MAG_I2C_READ_FLAG
);
672 /* Set the address of the register to read. */
673 PIOS_SPI_TransferByte(dev
->spi_id
, PIOS_MPU9250_I2C_SLV0_REG
);
674 PIOS_SPI_TransferByte(dev
->spi_id
, PIOS_MPU9250_ASAX
);
676 /* Trigger the byte transfer. */
677 PIOS_SPI_TransferByte(dev
->spi_id
, PIOS_MPU9250_I2C_SLV0_CTRL
);
678 PIOS_SPI_TransferByte(dev
->spi_id
, PIOS_MPU9250_I2C_SLV_ENABLE
| 0x3);
680 PIOS_DELAY_WaitmS(1);
682 /* Read the mag data from SPI block */
683 for (i
= 0; i
< 0x3; i
++) {
684 PIOS_SPI_TransferByte(dev
->spi_id
, (PIOS_MPU9250_EXT_SENS_DATA_00
| 0x80) + i
);
685 int32_t ret
= PIOS_SPI_TransferByte(dev
->spi_id
, 0x0);
687 PIOS_MPU9250_ReleaseBus();
690 dev
->mag_sens_adj
[i
] = 1.0f
; // 1.0f + ((float)((uint8_t)ret - 128)) / 256.0f;
693 PIOS_MPU9250_ReleaseBus();
696 /* Put mag in power down state before changing mode */
697 PIOS_MPU9250_Mag_SetReg(PIOS_MPU9250_CNTL1
, PIOS_MPU9250_MAG_POWER_DOWN_MODE
);
699 return PIOS_MPU9250_MAG_OK
;
703 * @brief Read a mag register from MPU9250
704 * @returns The register value or -1 if failure to get bus
705 * @param reg[in] Register address to be read
707 static int32_t PIOS_MPU9250_Mag_Init(void)
709 // I2C multi-master init.
710 PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_MST_CTRL
, PIOS_MPU9250_I2C_MST_P_NSR
| PIOS_MPU9250_I2C_MST_CLOCK_400
);
711 PIOS_DELAY_WaitmS(1);
714 PIOS_MPU9250_Mag_SetReg(PIOS_MPU9250_CNTL2
, PIOS_MPU9250_MAG_RESET
);
715 PIOS_DELAY_WaitmS(1);
718 // read fuse ROM to get the sensitivity adjustment values.
719 if (PIOS_MPU9250_Mag_Sensitivity() != PIOS_MPU9250_MAG_OK
) {
724 while (false && (PIOS_MPU9250_Mag_Test() != PIOS_MPU9250_MAG_OK
)) {
728 // Make sure no other registers will be triggered before entering continuous mode.
729 PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV4_CTRL
, 0x0);
730 PIOS_DELAY_WaitmS(1);
731 PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV0_DO
, 0x0);
732 PIOS_DELAY_WaitmS(1);
734 // Making sure register are accessible.
735 PIOS_MPU9250_Mag_SetReg(PIOS_MPU9250_CNTL1
, PIOS_MPU9250_MAG_OUTPUT_16BITS
| PIOS_MPU9250_MAG_CONTINUOUS_MODE2
);
736 PIOS_DELAY_WaitmS(1);
738 // Get ST1, the 6 mag data and ST2.
739 // This is to save 2 SPI access.
740 // Set the I2C slave address and read command.
741 PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV0_ADDR
, PIOS_MPU9250_MAG_I2C_ADDR
| PIOS_MPU9250_MAG_I2C_READ_FLAG
);
743 // Set the address of the register to read.
744 PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV0_REG
, PIOS_MPU9250_ST1
);
746 // Trigger the byte transfer.
747 PIOS_MPU9250_SetReg(PIOS_MPU9250_I2C_SLV0_CTRL
, PIOS_MPU9250_I2C_SLV_ENABLE
| 0x8);
748 PIOS_DELAY_WaitmS(1);
750 return PIOS_MPU9250_MAG_OK
;
754 * @brief Read the mag identification bytes from the MPU9250 sensor
756 int32_t PIOS_MPU9250_Mag_ReadID()
758 int32_t mpu9250_mag_id
= PIOS_MPU9250_Mag_GetReg(PIOS_MPU9250_WIA
);
760 if (mpu9250_mag_id
< PIOS_MPU9250_MAG_OK
) {
761 return PIOS_MPU9250_ERR_MAG_READ_ID
;
763 return mpu9250_mag_id
;
767 * @brief Run self-test operation.
768 * \return 0 if test succeeded
769 * \return non-zero value if test failed
771 static int32_t PIOS_MPU9250_Mag_Test(void)
773 /* Verify that ID matches */
774 int32_t mpu9250_mag_id
= PIOS_MPU9250_Mag_ReadID();
776 if (mpu9250_mag_id
< PIOS_MPU9250_MAG_OK
) {
777 return PIOS_MPU9250_ERR_MAG_READ_ID
;
780 if (mpu9250_mag_id
!= PIOS_MPU9250_MAG_ID
) {
781 return PIOS_MPU9250_ERR_MAG_BAD_ID
;
784 /* TODO: run self-test */
786 return PIOS_MPU9250_MAG_OK
;
791 * @brief Read the mag data.
792 * \return true if data has been read from mpu
793 * \return false on error
795 static bool PIOS_MPU9250_ReadMag(bool *woken
)
797 if (PIOS_MPU9250_ClaimBusISR(woken
, true) != 0) {
800 // Trigger the byte transfer.
801 PIOS_SPI_TransferByte(dev
->spi_id
, PIOS_MPU9250_I2C_SLV0_CTRL
);
802 PIOS_SPI_TransferByte(dev
->spi_id
, PIOS_MPU9250_I2C_SLV_ENABLE
| 0x8);
804 PIOS_MPU9250_ReleaseBusISR(woken
);
808 #endif /* if defined(PIOS_MPU9250_MAG) */
811 * @brief EXTI IRQ Handler. Read all the data from onboard buffer
812 * @return a boolean to the EXTI IRQ Handler wrapper indicating if a
813 * higher priority task is now eligible to run
815 bool PIOS_MPU9250_IRQHandler(void)
817 uint32_t gyro_read_timestamp
= PIOS_DELAY_GetRaw();
820 if (!mpu9250_configured
) {
824 #if defined(PIOS_MPU9250_MAG)
825 PIOS_MPU9250_ReadMag(&woken
);
828 if (PIOS_MPU9250_ReadSensor(&woken
)) {
829 woken
|= PIOS_MPU9250_HandleData(gyro_read_timestamp
);
835 static bool PIOS_MPU9250_HandleData(uint32_t gyro_read_timestamp
)
837 // Rotate the sensor to OP convention. The datasheet defines X as towards the right
838 // and Y as forward. OP convention transposes this. Also the Z is defined negatively
844 #ifdef PIOS_MPU9250_MAG
845 bool mag_valid
= mpu9250_data
.data
.st1
& PIOS_MPU9250_MAG_DATA_RDY
;
848 // Currently we only support rotations on top so switch X/Y accordingly
849 switch (dev
->cfg
->orientation
) {
850 case PIOS_MPU9250_TOP_0DEG
:
851 #ifdef PIOS_MPU9250_ACCEL
852 queue_data
->sample
[0].y
= GET_SENSOR_DATA(mpu9250_data
, Accel_X
); // chip X
853 queue_data
->sample
[0].x
= GET_SENSOR_DATA(mpu9250_data
, Accel_Y
); // chip Y
855 queue_data
->sample
[1].y
= GET_SENSOR_DATA(mpu9250_data
, Gyro_X
); // chip X
856 queue_data
->sample
[1].x
= GET_SENSOR_DATA(mpu9250_data
, Gyro_Y
); // chip Y
857 #ifdef PIOS_MPU9250_MAG
859 mag_data
->sample
[0].y
= GET_SENSOR_DATA(mpu9250_data
, Mag_Y
) * dev
->mag_sens_adj
[1]; // chip Y
860 mag_data
->sample
[0].x
= GET_SENSOR_DATA(mpu9250_data
, Mag_X
) * dev
->mag_sens_adj
[0]; // chip X
864 case PIOS_MPU9250_TOP_90DEG
:
865 // -1 to bring it back to -32768 +32767 range
866 #ifdef PIOS_MPU9250_ACCEL
867 queue_data
->sample
[0].y
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Accel_Y
)); // chip Y
868 queue_data
->sample
[0].x
= GET_SENSOR_DATA(mpu9250_data
, Accel_X
); // chip X
870 queue_data
->sample
[1].y
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Gyro_Y
)); // chip Y
871 queue_data
->sample
[1].x
= GET_SENSOR_DATA(mpu9250_data
, Gyro_X
); // chip X
872 #ifdef PIOS_MPU9250_MAG
874 mag_data
->sample
[0].y
= GET_SENSOR_DATA(mpu9250_data
, Mag_X
) * dev
->mag_sens_adj
[0]; // chip X
875 mag_data
->sample
[0].x
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Mag_Y
)) * dev
->mag_sens_adj
[1]; // chip Y
880 case PIOS_MPU9250_TOP_180DEG
:
881 #ifdef PIOS_MPU9250_ACCEL
882 queue_data
->sample
[0].y
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Accel_X
)); // chip X
883 queue_data
->sample
[0].x
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Accel_Y
)); // chip Y
885 queue_data
->sample
[1].y
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Gyro_X
)); // chip X
886 queue_data
->sample
[1].x
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Gyro_Y
)); // chip Y
887 #ifdef PIOS_MPU9250_MAG
889 mag_data
->sample
[0].y
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Mag_Y
)) * dev
->mag_sens_adj
[1]; // chip Y
890 mag_data
->sample
[0].x
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Mag_X
)) * dev
->mag_sens_adj
[0]; // chip X
894 case PIOS_MPU9250_TOP_270DEG
:
895 #ifdef PIOS_MPU9250_ACCEL
896 queue_data
->sample
[0].y
= GET_SENSOR_DATA(mpu9250_data
, Accel_Y
); // chip Y
897 queue_data
->sample
[0].x
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Accel_X
)); // chip X
899 queue_data
->sample
[1].y
= GET_SENSOR_DATA(mpu9250_data
, Gyro_Y
); // chip Y
900 queue_data
->sample
[1].x
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Gyro_X
)); // chip X
901 #ifdef PIOS_MPU9250_MAG
903 mag_data
->sample
[0].y
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Mag_X
)) * dev
->mag_sens_adj
[0]; // chip X
904 mag_data
->sample
[0].x
= GET_SENSOR_DATA(mpu9250_data
, Mag_Y
) * dev
->mag_sens_adj
[1]; // chip Y
909 #ifdef PIOS_MPU9250_ACCEL
910 queue_data
->sample
[0].z
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Accel_Z
));
912 queue_data
->sample
[1].z
= -1 - (GET_SENSOR_DATA(mpu9250_data
, Gyro_Z
));
913 const int16_t temp
= GET_SENSOR_DATA(mpu9250_data
, Temperature
);
914 queue_data
->temperature
= 2100 + ((float)(temp
- PIOS_MPU9250_TEMP_OFFSET
)) * (100.0f
/ PIOS_MPU9250_TEMP_SENSITIVITY
);
915 queue_data
->timestamp
= gyro_read_timestamp
;
916 mag_data
->temperature
= queue_data
->temperature
;
917 #ifdef PIOS_MPU9250_MAG
919 mag_data
->sample
[0].z
= GET_SENSOR_DATA(mpu9250_data
, Mag_Z
) * dev
->mag_sens_adj
[2]; // chip Z
924 BaseType_t higherPriorityTaskWoken
;
925 xQueueSendToBackFromISR(dev
->queue
, queue_data
, &higherPriorityTaskWoken
);
926 return higherPriorityTaskWoken
== pdTRUE
;
929 static bool PIOS_MPU9250_ReadSensor(bool *woken
)
931 const uint8_t mpu9250_send_buf
[1 + PIOS_MPU9250_SAMPLES_BYTES
] = { PIOS_MPU9250_SENSOR_FIRST_REG
| 0x80 };
933 if (PIOS_MPU9250_ClaimBusISR(woken
, true) != 0) {
936 if (PIOS_SPI_TransferBlock(dev
->spi_id
, &mpu9250_send_buf
[0], &mpu9250_data
.buffer
[0], sizeof(mpu9250_data_t
), NULL
) < 0) {
937 PIOS_MPU9250_ReleaseBusISR(woken
);
940 PIOS_MPU9250_ReleaseBusISR(woken
);
944 // Sensor driver implementation
945 bool PIOS_MPU9250_Main_driver_Test(__attribute__((unused
)) uintptr_t context
)
947 return !PIOS_MPU9250_Test();
950 void PIOS_MPU9250_Main_driver_Reset(__attribute__((unused
)) uintptr_t context
)
952 PIOS_MPU9250_GetReg(PIOS_MPU9250_INT_STATUS_REG
);
955 void PIOS_MPU9250_Main_driver_get_scale(float *scales
, uint8_t size
, __attribute__((unused
)) uintptr_t contet
)
957 PIOS_Assert(size
>= 2);
958 scales
[0] = PIOS_MPU9250_GetAccelScale();
959 scales
[1] = PIOS_MPU9250_GetScale();
962 QueueHandle_t
PIOS_MPU9250_Main_driver_get_queue(__attribute__((unused
)) uintptr_t context
)
968 /* PIOS sensor driver implementation */
969 bool PIOS_MPU9250_Mag_driver_Test(__attribute__((unused
)) uintptr_t context
)
971 return !PIOS_MPU9250_Test();
974 void PIOS_MPU9250_Mag_driver_Reset(__attribute__((unused
)) uintptr_t context
) {}
976 void PIOS_MPU9250_Mag_driver_get_scale(float *scales
, uint8_t size
, __attribute__((unused
)) uintptr_t context
)
978 PIOS_Assert(size
> 0);
982 void PIOS_MPU9250_Mag_driver_fetch(void *data
, uint8_t size
, __attribute__((unused
)) uintptr_t context
)
985 PIOS_Assert(size
> 0);
986 memcpy(data
, mag_data
, MAG_SENSOR_DATA_SIZE
);
989 bool PIOS_MPU9250_Mag_driver_poll(__attribute__((unused
)) uintptr_t context
)
994 #endif /* PIOS_INCLUDE_MPU9250 */