2 * This file is part of Betaflight.
4 * Betaflight is free software. You can redistribute this software
5 * and/or modify this software under the terms of the GNU General
6 * Public License as published by the Free Software Foundation,
7 * either version 3 of the License, or (at your option) any later
10 * Betaflight is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this software.
19 * If not, see <http://www.gnu.org/licenses/>.
29 #ifdef USE_MAG_IST8310
31 #include "build/debug.h"
33 #include "common/axis.h"
34 #include "common/maths.h"
36 #include "drivers/bus.h"
37 #include "drivers/bus_i2c.h"
38 #include "drivers/bus_i2c_busdev.h"
39 #include "drivers/sensor.h"
40 #include "drivers/time.h"
43 #include "compass_ist8310.h"
45 //#define DEBUG_MAG_DATA_READY_INTERRUPT
47 #define IST8310_MAG_I2C_ADDRESS 0x0E
49 /* ist8310 Slave Address Select : default address 0x0C
50 * CAD1 | CAD0 | Address
51 * ------------------------------
56 * if CAD1 and CAD0 are floating, I2C address will be 0EH
59 * CTRL_REGA: Control Register 1
63 * 3:0 DO2-DO0: Operating mode setting
64 * DO3 | DO2 | DO1 | DO0 | mode
65 * ------------------------------------------------------
66 * 0 | 0 | 0 | 0 | Stand-By mode
67 * 0 | 0 | 0 | 1 | Single measurement mode
70 * CTRL_REGB: Control Register 2
74 * 3 DREN : Data ready enable control:
77 * 2 DRP: DRDY pin polarity control
81 * 0 SRST: Soft reset, perform Power On Reset (POR) routine
83 * 1: start immediately POR routine
84 * This bit will be set to zero after POR routine
87 #define IST8310_REG_DATA 0x03
88 #define IST8310_REG_WAI 0x00
89 #define IST8310_REG_WAI_VALID 0x10
91 #define IST8310_REG_STAT1 0x02
92 #define IST8310_REG_STAT2 0x09
94 #define IST8310_DRDY_MASK 0x01
96 // I2C Control Register
97 #define IST8310_REG_CNTRL1 0x0A
98 #define IST8310_REG_CNTRL2 0x0B
99 #define IST8310_REG_AVERAGE 0x41
100 #define IST8310_REG_PDCNTL 0x42
103 // ODR = Output Data Rate, we use single measure mode for getting more data.
104 #define IST8310_ODR_SINGLE 0x01
105 #define IST8310_ODR_10_HZ 0x03
106 #define IST8310_ODR_20_HZ 0x05
107 #define IST8310_ODR_50_HZ 0x07
108 #define IST8310_ODR_100_HZ 0x06
110 #define IST8310_AVG_16 0x24
111 #define IST8310_PULSE_DURATION_NORMAL 0xC0
113 #define IST8310_CNTRL2_RESET 0x01
114 #define IST8310_CNTRL2_DRPOL 0x04
115 #define IST8310_CNTRL2_DRENA 0x08
117 static bool ist8310Init(magDev_t
*magDev
)
119 extDevice_t
*dev
= &magDev
->dev
;
121 busDeviceRegister(dev
);
124 bool ack
= busWriteRegister(dev
, IST8310_REG_AVERAGE
, IST8310_AVG_16
);
126 ack
= ack
&& busWriteRegister(dev
, IST8310_REG_PDCNTL
, IST8310_PULSE_DURATION_NORMAL
);
128 ack
= ack
&& busWriteRegister(dev
, IST8310_REG_CNTRL1
, IST8310_ODR_SINGLE
);
130 magDev
->magOdrHz
= 100;
131 // need to check what ODR is actually returned, may be a bit faster than 100Hz
135 static bool ist8310Read(magDev_t
* magDev
, int16_t *magData
)
137 extDevice_t
*dev
= &magDev
->dev
;
139 static uint8_t buf
[6];
140 const int LSB2FSV
= 3; // 3mG - 14 bit
145 } state
= STATE_REQUEST_DATA
;
149 case STATE_REQUEST_DATA
:
150 if (busReadRegisterBufferStart(dev
, IST8310_REG_DATA
, buf
, sizeof(buf
))) {
151 state
= STATE_FETCH_DATA
;
155 case STATE_FETCH_DATA
:
156 // Looks like datasheet is incorrect and we need to invert Y axis to conform to right hand rule
157 magData
[X
] = (int16_t)(buf
[1] << 8 | buf
[0]) * LSB2FSV
;
158 magData
[Y
] = -(int16_t)(buf
[3] << 8 | buf
[2]) * LSB2FSV
;
159 magData
[Z
] = (int16_t)(buf
[5] << 8 | buf
[4]) * LSB2FSV
;
161 // Force single measurement mode for next read
162 if (busWriteRegisterStart(dev
, IST8310_REG_CNTRL1
, IST8310_ODR_SINGLE
)) {
163 state
= STATE_REQUEST_DATA
;
171 // TODO: do cross axis compensation
176 static bool deviceDetect(magDev_t
* magDev
)
179 bool ack
= busReadRegisterBuffer(&magDev
->dev
, IST8310_REG_WAI
, &result
, 1);
181 return ack
&& result
== IST8310_REG_WAI_VALID
;
184 bool ist8310Detect(magDev_t
* magDev
)
186 extDevice_t
*dev
= &magDev
->dev
;
188 if (dev
->bus
->busType
== BUS_TYPE_I2C
&& dev
->busType_u
.i2c
.address
== 0) {
189 dev
->busType_u
.i2c
.address
= IST8310_MAG_I2C_ADDRESS
;
192 if (deviceDetect(magDev
)) {
193 magDev
->init
= ist8310Init
;
194 magDev
->read
= ist8310Read
;