Merge pull request #11297 from SteveCEvans/baro_state
[betaflight.git] / src / main / drivers / compass / compass_ak8963.c
blob621d419257b0d8664d29faf2b3ccabf925307e6d
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <stdbool.h>
22 #include <stdint.h>
24 #include <math.h>
26 #include "platform.h"
28 #if defined(USE_MAG_AK8963) || defined(USE_MAG_SPI_AK8963)
30 #include "build/debug.h"
32 #include "common/axis.h"
33 #include "common/maths.h"
34 #include "common/utils.h"
36 #include "drivers/bus.h"
37 #include "drivers/bus_i2c.h"
38 #include "drivers/bus_i2c_busdev.h"
39 #include "drivers/bus_spi.h"
40 #include "drivers/io.h"
41 #include "drivers/sensor.h"
42 #include "drivers/time.h"
44 #include "drivers/compass/compass.h"
46 #include "drivers/accgyro/accgyro.h"
47 #include "drivers/accgyro/accgyro_mpu.h"
48 #include "drivers/accgyro/accgyro_mpu6500.h"
49 #include "drivers/accgyro/accgyro_spi_mpu6500.h"
50 #include "drivers/accgyro/accgyro_spi_mpu9250.h"
51 #include "drivers/compass/compass_ak8963.h"
53 #include "scheduler/scheduler.h"
55 // This sensor is also available also part of the MPU-9250 connected to the secondary I2C bus.
57 // 10 MHz max SPI frequency
58 #define AK8963_MAX_SPI_CLK_HZ 10000000
60 // AK8963, mag sensor address
61 #define AK8963_MAG_I2C_ADDRESS 0x0C
62 #define AK8963_DEVICE_ID 0x48
64 // Registers
65 #define AK8963_MAG_REG_WIA 0x00
66 #define AK8963_MAG_REG_INFO 0x01
67 #define AK8963_MAG_REG_ST1 0x02
68 #define AK8963_MAG_REG_HXL 0x03
69 #define AK8963_MAG_REG_HXH 0x04
70 #define AK8963_MAG_REG_HYL 0x05
71 #define AK8963_MAG_REG_HYH 0x06
72 #define AK8963_MAG_REG_HZL 0x07
73 #define AK8963_MAG_REG_HZH 0x08
74 #define AK8963_MAG_REG_ST2 0x09
75 #define AK8963_MAG_REG_CNTL1 0x0A
76 #define AK8963_MAG_REG_CNTL2 0x0B
77 #define AK8963_MAG_REG_ASCT 0x0C // self test
78 #define AK8963_MAG_REG_I2CDIS 0x0F
79 #define AK8963_MAG_REG_ASAX 0x10 // Fuse ROM x-axis sensitivity adjustment value
80 #define AK8963_MAG_REG_ASAY 0x11 // Fuse ROM y-axis sensitivity adjustment value
81 #define AK8963_MAG_REG_ASAZ 0x12 // Fuse ROM z-axis sensitivity adjustment value
83 #define READ_FLAG 0x80
84 #define I2C_SLV0_EN 0x80
86 #define ST1_DATA_READY 0x01
87 #define ST1_DATA_OVERRUN 0x02
89 #define ST2_MAG_SENSOR_OVERFLOW 0x08
91 #define CNTL1_MODE_POWER_DOWN 0x00
92 #define CNTL1_MODE_ONCE 0x01
93 #define CNTL1_MODE_CONT1 0x02
94 #define CNTL1_MODE_CONT2 0x06
95 #define CNTL1_MODE_SELF_TEST 0x08
96 #define CNTL1_MODE_FUSE_ROM 0x0F
97 #define CNTL1_BIT_14_BIT 0x00
98 #define CNTL1_BIT_16_BIT 0x10
100 #define CNTL2_SOFT_RESET 0x01
102 #define I2CDIS_DISABLE_MASK 0x1D
104 #if defined(USE_MAG_AK8963) && (defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU9250))
106 static bool ak8963SpiWriteRegisterDelay(const extDevice_t *dev, uint8_t reg, uint8_t data)
108 spiWriteReg(dev, reg, data);
109 delayMicroseconds(10);
110 return true;
113 static bool ak8963SlaveReadRegisterBuffer(const extDevice_t *slaveDev, uint8_t reg, uint8_t *buf, uint8_t len)
115 extDevice_t *dev = slaveDev->bus->busType_u.mpuSlave.master;
117 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_ADDR, slaveDev->busType_u.mpuSlave.address | READ_FLAG); // set I2C slave address for read
118 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_REG, reg); // set I2C slave register
119 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_CTRL, (len & 0x0F) | I2C_SLV0_EN); // read number of bytes
120 delay(4);
121 __disable_irq();
122 bool ack = spiReadRegMskBufRB(dev, MPU_RA_EXT_SENS_DATA_00, buf, len); // read I2C
123 __enable_irq();
124 return ack;
127 static bool ak8963SlaveWriteRegister(const extDevice_t *slaveDev, uint8_t reg, uint8_t data)
129 extDevice_t *dev = slaveDev->bus->busType_u.mpuSlave.master;
131 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_ADDR, slaveDev->busType_u.mpuSlave.address); // set I2C slave address for write
132 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_REG, reg); // set I2C slave register
133 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_DO, data); // set I2C sLave value
134 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_CTRL, (1 & 0x0F) | I2C_SLV0_EN); // write 1 byte
135 return true;
138 typedef struct queuedReadState_s {
139 bool waiting;
140 uint8_t len;
141 uint32_t readStartedAt; // time read was queued in micros.
142 } queuedReadState_t;
144 static queuedReadState_t queuedRead = { false, 0, 0};
146 static bool ak8963SlaveStartRead(const extDevice_t *slaveDev, uint8_t reg, uint8_t len)
148 if (queuedRead.waiting) {
149 return false;
152 extDevice_t *dev = slaveDev->bus->busType_u.mpuSlave.master;
154 queuedRead.len = len;
156 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_ADDR, slaveDev->busType_u.mpuSlave.address | READ_FLAG); // set I2C slave address for read
157 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_REG, reg); // set I2C slave register
158 ak8963SpiWriteRegisterDelay(dev, MPU_RA_I2C_SLV0_CTRL, (len & 0x0F) | I2C_SLV0_EN); // read number of bytes
160 queuedRead.readStartedAt = micros();
161 queuedRead.waiting = true;
163 return true;
166 static uint32_t ak8963SlaveQueuedReadTimeRemaining(void)
168 if (!queuedRead.waiting) {
169 return 0;
172 int32_t timeSinceStarted = micros() - queuedRead.readStartedAt;
174 int32_t timeRemaining = 8000 - timeSinceStarted;
176 if (timeRemaining < 0) {
177 return 0;
180 return timeRemaining;
183 static bool ak8963SlaveCompleteRead(const extDevice_t *slaveDev, uint8_t *buf)
185 uint32_t timeRemaining = ak8963SlaveQueuedReadTimeRemaining();
187 extDevice_t *dev = slaveDev->bus->busType_u.mpuSlave.master;
189 if (timeRemaining > 0) {
190 delayMicroseconds(timeRemaining);
193 queuedRead.waiting = false;
195 return spiReadRegMskBufRB(dev, MPU_RA_EXT_SENS_DATA_00, buf, queuedRead.len); // read I2C buffer
198 static bool ak8963SlaveReadData(const extDevice_t *dev, uint8_t *buf)
200 typedef enum {
201 CHECK_STATUS = 0,
202 WAITING_FOR_STATUS,
203 WAITING_FOR_DATA
204 } ak8963ReadState_e;
206 static ak8963ReadState_e state = CHECK_STATUS;
208 bool ack = false;
210 // we currently need a different approach for the MPU9250 connected via SPI.
211 // we cannot use the ak8963SlaveReadRegisterBuffer() method for SPI, it is to slow and blocks for far too long.
213 bool retry = true;
215 restart:
216 switch (state) {
217 case CHECK_STATUS: {
218 ak8963SlaveStartRead(dev, AK8963_MAG_REG_ST1, 1);
219 state = WAITING_FOR_STATUS;
220 return false;
223 case WAITING_FOR_STATUS: {
224 uint32_t timeRemaining = ak8963SlaveQueuedReadTimeRemaining();
225 if (timeRemaining) {
226 return false;
229 ack = ak8963SlaveCompleteRead(dev, &buf[0]);
231 uint8_t status = buf[0];
233 if (!ack || (status & ST1_DATA_READY) == 0) {
234 // too early. queue the status read again
235 state = CHECK_STATUS;
236 if (retry) {
237 retry = false;
238 goto restart;
240 return false;
243 // read the 6 bytes of data and the status2 register
244 ak8963SlaveStartRead(dev, AK8963_MAG_REG_HXL, 7);
246 state = WAITING_FOR_DATA;
247 return false;
250 case WAITING_FOR_DATA: {
251 uint32_t timeRemaining = ak8963SlaveQueuedReadTimeRemaining();
252 if (timeRemaining) {
253 return false;
256 ack = ak8963SlaveCompleteRead(dev, &buf[0]);
257 state = CHECK_STATUS;
261 return ack;
263 #endif
265 static bool ak8963ReadRegisterBuffer(const extDevice_t *dev, uint8_t reg, uint8_t *buf, uint8_t len)
267 #if defined(USE_MAG_AK8963) && (defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU9250))
268 if (dev->bus->busType == BUS_TYPE_MPU_SLAVE) {
269 return ak8963SlaveReadRegisterBuffer(dev, reg, buf, len);
271 #endif
272 return busReadRegisterBuffer(dev, reg, buf, len);
275 static bool ak8963WriteRegister(const extDevice_t *dev, uint8_t reg, uint8_t data)
277 #if defined(USE_MAG_AK8963) && (defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU9250))
278 if (dev->bus->busType == BUS_TYPE_MPU_SLAVE) {
279 return ak8963SlaveWriteRegister(dev, reg, data);
281 #endif
282 return busWriteRegister(dev, reg, data);
285 static bool ak8963DirectReadData(const extDevice_t *dev, uint8_t *buf)
287 uint8_t status;
289 bool ack = ak8963ReadRegisterBuffer(dev, AK8963_MAG_REG_ST1, &status, 1);
291 if (!ack || (status & ST1_DATA_READY) == 0) {
292 return false;
295 return ak8963ReadRegisterBuffer(dev, AK8963_MAG_REG_HXL, buf, 7);
298 static int16_t parseMag(uint8_t *raw, int16_t gain) {
299 int ret = (int16_t)(raw[1] << 8 | raw[0]) * gain / 256;
300 return constrain(ret, INT16_MIN, INT16_MAX);
303 static bool ak8963Read(magDev_t *mag, int16_t *magData)
305 bool ack = false;
306 uint8_t buf[7];
308 extDevice_t *dev = &mag->dev;
310 switch (dev->bus->busType) {
311 #if defined(USE_MAG_SPI_AK8963) || defined(USE_MAG_AK8963)
312 case BUS_TYPE_I2C:
313 case BUS_TYPE_SPI:
314 ack = ak8963DirectReadData(dev, buf);
315 break;
316 #endif
318 #if defined(USE_MAG_AK8963) && (defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU9250))
319 case BUS_TYPE_MPU_SLAVE:
320 ack = ak8963SlaveReadData(dev, buf);
321 break;
322 #endif
323 default:
324 break;
327 uint8_t status2 = buf[6];
328 if (!ack) {
329 return false;
332 ak8963WriteRegister(dev, AK8963_MAG_REG_CNTL1, CNTL1_BIT_16_BIT | CNTL1_MODE_ONCE); // start reading again uint8_t status2 = buf[6];
334 if (status2 & ST2_MAG_SENSOR_OVERFLOW) {
335 return false;
338 magData[X] = parseMag(buf + 0, mag->magGain[X]);
339 magData[Y] = parseMag(buf + 2, mag->magGain[Y]);
340 magData[Z] = parseMag(buf + 4, mag->magGain[Z]);
342 return true;
345 static bool ak8963Init(magDev_t *mag)
347 uint8_t asa[3];
348 uint8_t status;
350 extDevice_t *dev = &mag->dev;
352 busDeviceRegister(dev);
354 ak8963WriteRegister(dev, AK8963_MAG_REG_CNTL1, CNTL1_MODE_POWER_DOWN); // power down before entering fuse mode
355 ak8963WriteRegister(dev, AK8963_MAG_REG_CNTL1, CNTL1_MODE_FUSE_ROM); // Enter Fuse ROM access mode
356 ak8963ReadRegisterBuffer(dev, AK8963_MAG_REG_ASAX, asa, sizeof(asa)); // Read the x-, y-, and z-axis calibration values
358 mag->magGain[X] = asa[X] + 128;
359 mag->magGain[Y] = asa[Y] + 128;
360 mag->magGain[Z] = asa[Z] + 128;
362 ak8963WriteRegister(dev, AK8963_MAG_REG_CNTL1, CNTL1_MODE_POWER_DOWN); // power down after reading.
364 // Clear status registers
365 ak8963ReadRegisterBuffer(dev, AK8963_MAG_REG_ST1, &status, 1);
366 ak8963ReadRegisterBuffer(dev, AK8963_MAG_REG_ST2, &status, 1);
368 // Trigger first measurement
369 ak8963WriteRegister(dev, AK8963_MAG_REG_CNTL1, CNTL1_BIT_16_BIT | CNTL1_MODE_ONCE);
370 return true;
373 void ak8963BusInit(const extDevice_t *dev)
375 switch (dev->bus->busType) {
376 #ifdef USE_MAG_AK8963
377 case BUS_TYPE_I2C:
378 UNUSED(dev);
379 break;
380 #endif
382 #ifdef USE_MAG_SPI_AK8963
383 case BUS_TYPE_SPI:
384 IOHi(dev->busType_u.spi.csnPin); // Disable
385 IOInit(dev->busType_u.spi.csnPin, OWNER_COMPASS_CS, 0);
386 IOConfigGPIO(dev->busType_u.spi.csnPin, IOCFG_OUT_PP);
387 spiSetClkDivisor(dev, spiCalculateDivider(AK8963_MAX_SPI_CLK_HZ));
388 break;
389 #endif
391 #if defined(USE_MAG_AK8963) && (defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU9250))
392 case BUS_TYPE_MPU_SLAVE:
393 rescheduleTask(TASK_COMPASS, TASK_PERIOD_HZ(40));
395 // Disable DMA on gyro as this upsets slave access timing
396 spiDmaEnable(dev->bus->busType_u.mpuSlave.master, false);
398 // initialize I2C master via SPI bus
399 ak8963SpiWriteRegisterDelay(dev->bus->busType_u.mpuSlave.master, MPU_RA_INT_PIN_CFG, MPU6500_BIT_INT_ANYRD_2CLEAR | MPU6500_BIT_BYPASS_EN);
400 ak8963SpiWriteRegisterDelay(dev->bus->busType_u.mpuSlave.master, MPU_RA_I2C_MST_CTRL, 0x0D); // I2C multi-master / 400kHz
401 ak8963SpiWriteRegisterDelay(dev->bus->busType_u.mpuSlave.master, MPU_RA_USER_CTRL, 0x30); // I2C master mode, SPI mode only
402 break;
403 #endif
404 default:
405 break;
409 void ak8963BusDeInit(const extDevice_t *dev)
411 switch (dev->bus->busType) {
412 #ifdef USE_MAG_AK8963
413 case BUS_TYPE_I2C:
414 UNUSED(dev);
415 break;
416 #endif
418 #ifdef USE_MAG_SPI_AK8963
419 case BUS_TYPE_SPI:
420 spiPreinitByIO(dev->busType_u.spi.csnPin);
421 break;
422 #endif
424 #if defined(USE_MAG_AK8963) && (defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU9250))
425 case BUS_TYPE_MPU_SLAVE:
426 ak8963SpiWriteRegisterDelay(dev->bus->busType_u.mpuSlave.master, MPU_RA_INT_PIN_CFG, MPU6500_BIT_INT_ANYRD_2CLEAR);
427 break;
428 #endif
429 default:
430 break;
434 bool ak8963Detect(magDev_t *mag)
436 uint8_t sig = 0;
438 extDevice_t *dev = &mag->dev;
440 if ((dev->bus->busType == BUS_TYPE_I2C || dev->bus->busType == BUS_TYPE_MPU_SLAVE) && dev->busType_u.mpuSlave.address == 0) {
441 dev->busType_u.mpuSlave.address = AK8963_MAG_I2C_ADDRESS;
444 ak8963BusInit(dev);
446 ak8963WriteRegister(dev, AK8963_MAG_REG_CNTL2, CNTL2_SOFT_RESET); // reset MAG
447 delay(4);
449 bool ack = ak8963ReadRegisterBuffer(dev, AK8963_MAG_REG_WIA, &sig, 1); // check for AK8963
451 if (ack && sig == AK8963_DEVICE_ID) // 0x48 / 01001000 / 'H'
453 mag->init = ak8963Init;
454 mag->read = ak8963Read;
456 return true;
459 ak8963BusDeInit(dev);
461 return false;
463 #endif