Skip to content

Commit 2f78152

Browse files
Merge pull request #10994 from BortEngineerDude/master
Add QMC5883P driver
2 parents ba252e2 + a8b0554 commit 2f78152

File tree

9 files changed

+257
-1
lines changed

9 files changed

+257
-1
lines changed

src/main/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ main_sources(COMMON_SRC
152152
drivers/compass/compass_mpu9250.h
153153
drivers/compass/compass_qmc5883l.c
154154
drivers/compass/compass_qmc5883l.h
155+
drivers/compass/compass_qmc5883p.c
156+
drivers/compass/compass_qmc5883p.h
155157
drivers/compass/compass_rm3100.c
156158
drivers/compass/compass_rm3100.h
157159
drivers/compass/compass_vcm5883.c

src/main/drivers/bus.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ typedef enum {
107107
DEVHW_IST8310_1,
108108
DEVHW_IST8308,
109109
DEVHW_QMC5883,
110+
DEVHW_QMC5883P,
110111
DEVHW_MAG3110,
111112
DEVHW_LIS3MDL,
112113
DEVHW_RM3100,
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* This file is part of INAV Project.
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
6+
* You can obtain one at http://mozilla.org/MPL/2.0/.
7+
*
8+
* Alternatively, the contents of this file may be used under the terms
9+
* of the GNU General Public License Version 3, as described below:
10+
*
11+
* This file is free software: you may copy, redistribute and/or modify
12+
* it under the terms of the GNU General Public License as published by the
13+
* Free Software Foundation, either version 3 of the License, or (at your
14+
* option) any later version.
15+
*
16+
* This file is distributed in the hope that it will be useful, but
17+
* WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19+
* Public License for more details.
20+
*
21+
* You should have received a copy of the GNU General Public License
22+
* along with this program. If not, see http://www.gnu.org/licenses/.
23+
*/
24+
25+
#include <stdbool.h>
26+
#include <stdint.h>
27+
28+
#include <math.h>
29+
30+
#include "platform.h"
31+
32+
#ifdef USE_MAG_QMC5883P
33+
34+
#include "build/build_config.h"
35+
36+
#include "common/axis.h"
37+
#include "common/maths.h"
38+
#include "common/utils.h"
39+
40+
#include "drivers/time.h"
41+
#include "drivers/bus_i2c.h"
42+
43+
#include "sensors/boardalignment.h"
44+
#include "sensors/sensors.h"
45+
46+
#include "drivers/sensor.h"
47+
#include "drivers/compass/compass.h"
48+
49+
#include "drivers/compass/compass_qmc5883p.h"
50+
51+
#define QMC5883P_MAG_I2C_ADDRESS 0x2C
52+
53+
#define QMC5883P_REG_ID 0x00
54+
#define QMC5883P_ID_VAL 0x80
55+
56+
#define QMC5883P_REG_DATA_OUTPUT_X 0x01
57+
#define QMC5883P_DATA_BYTES 6
58+
59+
#define QMC5883P_REG_CONF1 0x0A
60+
61+
#define QMC5883P_CONF1_MODE_SUSPEND 0x00
62+
#define QMC5883P_CONF1_MODE_NORMAL 0x01
63+
#define QMC5883P_CONF1_MODE_SINGLE 0x02
64+
#define QMC5883P_CONF1_MODE_CONTINUOUS 0x03
65+
66+
#define QMC5883P_CONF1_ODR_10HZ (0x00 << 2)
67+
#define QMC5883P_CONF1_ODR_50HZ (0x01 << 2)
68+
#define QMC5883P_CONF1_ODR_100HZ (0x02 << 2)
69+
#define QMC5883P_CONF1_ODR_200HZ (0x03 << 2)
70+
71+
#define QMC5883P_CONF1_OSR1_8 (0x00 << 4)
72+
#define QMC5883P_CONF1_OSR1_4 (0x01 << 4)
73+
#define QMC5883P_CONF1_OSR1_2 (0x02 << 4)
74+
#define QMC5883P_CONF1_OSR1_1 (0x03 << 4)
75+
76+
#define QMC5883P_CONF1_OSR2_1 (0x00 << 6)
77+
#define QMC5883P_CONF1_OSR2_2 (0x01 << 6)
78+
#define QMC5883P_CONF1_OSR2_4 (0x02 << 6)
79+
#define QMC5883P_CONF1_OSR2_8 (0x03 << 6)
80+
81+
82+
#define QMC5883P_REG_CONF2 0x0B
83+
84+
#define QMC5883P_CONF2_SET_RESET_ON 0x00
85+
#define QMC5883P_CONF2_SET_ON_RESET_OFF 0x01
86+
#define QMC5883P_CONF2_SET_RESET_OFF 0x02
87+
88+
#define QMC5883P_CONF2_RNG_30G (0x00 << 2)
89+
#define QMC5883P_CONF2_RNG_12G (0x01 << 2)
90+
#define QMC5883P_CONF2_RNG_8G (0x02 << 2)
91+
#define QMC5883P_CONF2_RNG_2G (0x03 << 2)
92+
93+
#define QMC5883P_CONF2_SELF_TEST 0x40
94+
95+
#define QMC5883P_CONF2_RESET 0x80
96+
97+
98+
#define QMC5883P_REG_STATUS 0x09
99+
#define QMC5883P_STATUS_DRDY_MASK 0x01
100+
#define QMC5883P_STATUS_OVFL_MASK 0x02
101+
102+
// This register has no definition in the datasheet and only mentioned in an example
103+
#define QMC5883P_REG_DATA_SIGN 0x29
104+
#define QMC5883P_DATA_SIGN_MAGIC_VALUE 0x06
105+
106+
static bool qmc5883pInit(magDev_t * mag)
107+
{
108+
bool ack = true;
109+
110+
ack = ack && busWrite(mag->busDev, QMC5883P_REG_CONF2, QMC5883P_CONF2_RESET);
111+
112+
delay(30);
113+
114+
ack = ack && busWrite(mag->busDev, QMC5883P_REG_DATA_SIGN, QMC5883P_DATA_SIGN_MAGIC_VALUE);
115+
ack = ack && busWrite(mag->busDev, QMC5883P_REG_CONF2, QMC5883P_CONF2_RNG_8G);
116+
ack = ack && busWrite(mag->busDev,
117+
QMC5883P_REG_CONF1,
118+
QMC5883P_CONF1_MODE_CONTINUOUS |
119+
QMC5883P_CONF1_ODR_200HZ |
120+
QMC5883P_CONF1_OSR1_8 |
121+
QMC5883P_CONF1_OSR2_8);
122+
123+
return ack;
124+
}
125+
126+
static bool qmc5883pRead(magDev_t * mag)
127+
{
128+
uint8_t status;
129+
uint8_t buf[QMC5883P_DATA_BYTES];
130+
131+
// set magData to zero for case of failed read
132+
mag->magADCRaw[X] = 0;
133+
mag->magADCRaw[Y] = 0;
134+
mag->magADCRaw[Z] = 0;
135+
136+
bool ack = busRead(mag->busDev, QMC5883P_REG_STATUS, &status);
137+
if (!ack || (status & QMC5883P_STATUS_DRDY_MASK) == 0) {
138+
return false;
139+
}
140+
141+
ack = busReadBuf(mag->busDev, QMC5883P_REG_DATA_OUTPUT_X, buf, QMC5883P_DATA_BYTES);
142+
if (!ack) {
143+
return false;
144+
}
145+
146+
/*
147+
Initially, this sensor provided the data like this:
148+
mag->magADCRaw[X] = (int16_t)(buf[1] << 8 | buf[0]);
149+
mag->magADCRaw[Y] = (int16_t)(buf[3] << 8 | buf[2]);
150+
mag->magADCRaw[Z] = (int16_t)(buf[5] << 8 | buf[4]);
151+
152+
But QMC5883P has a different reference point and axis directions, compared to QMC5883L.
153+
As QMC5883P is designed to be a drop-in replacement for QMC5883L, apply alignment at
154+
readout to obtain the same readings in the same position. In particular, it does
155+
the same transformation to the data, as the CW270_DEG_FLIP option:
156+
dest[X] = -y;
157+
dest[Y] = -x;
158+
dest[Z] = -z;
159+
*/
160+
mag->magADCRaw[X] = -(int16_t)(buf[3] << 8 | buf[2]);
161+
mag->magADCRaw[Y] = -(int16_t)(buf[1] << 8 | buf[0]);
162+
mag->magADCRaw[Z] = -(int16_t)(buf[5] << 8 | buf[4]);
163+
164+
return true;
165+
}
166+
167+
#define DETECTION_MAX_RETRY_COUNT 5
168+
static bool deviceDetect(magDev_t * mag)
169+
{
170+
for (int retryCount = 0; retryCount < DETECTION_MAX_RETRY_COUNT; retryCount++) {
171+
// Must write reset first - don't care about the result
172+
busWrite(mag->busDev, QMC5883P_REG_CONF2, QMC5883P_CONF2_RESET);
173+
delay(30);
174+
175+
uint8_t sig = 0;
176+
bool ack = busRead(mag->busDev, QMC5883P_REG_ID, &sig);
177+
178+
if (ack && sig == QMC5883P_ID_VAL) {
179+
return true;
180+
}
181+
}
182+
183+
return false;
184+
}
185+
186+
bool qmc5883pDetect(magDev_t * mag)
187+
{
188+
mag->busDev = busDeviceInit(BUSTYPE_ANY, DEVHW_QMC5883P, mag->magSensorToUse, OWNER_COMPASS);
189+
if (mag->busDev == NULL) {
190+
return false;
191+
}
192+
193+
if (!deviceDetect(mag)) {
194+
busDeviceDeInit(mag->busDev);
195+
return false;
196+
}
197+
198+
mag->init = qmc5883pInit;
199+
mag->read = qmc5883pRead;
200+
201+
return true;
202+
}
203+
#endif
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* This file is part of INAV Project.
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
6+
* You can obtain one at http://mozilla.org/MPL/2.0/.
7+
*
8+
* Alternatively, the contents of this file may be used under the terms
9+
* of the GNU General Public License Version 3, as described below:
10+
*
11+
* This file is free software: you may copy, redistribute and/or modify
12+
* it under the terms of the GNU General Public License as published by the
13+
* Free Software Foundation, either version 3 of the License, or (at your
14+
* option) any later version.
15+
*
16+
* This file is distributed in the hope that it will be useful, but
17+
* WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19+
* Public License for more details.
20+
*
21+
* You should have received a copy of the GNU General Public License
22+
* along with this program. If not, see http://www.gnu.org/licenses/.
23+
*/
24+
25+
#pragma once
26+
27+
bool qmc5883pDetect(magDev_t *mag);

src/main/fc/settings.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ tables:
88
values: ["NONE", "SRF10", "VL53L0X", "MSP", "BENEWAKE", "VL53L1X", "US42", "TOF10120_I2C", "FAKE", "TERARANGER_EVO", "USD1_V0", "NRA"]
99
enum: rangefinderType_e
1010
- name: mag_hardware
11-
values: ["NONE", "AUTO", "HMC5883", "AK8975", "MAG3110", "AK8963", "IST8310", "QMC5883", "MPU9250", "IST8308", "LIS3MDL", "MSP", "RM3100", "VCM5883", "MLX90393", "FAKE"]
11+
values: ["NONE", "AUTO", "HMC5883", "AK8975", "MAG3110", "AK8963", "IST8310", "QMC5883", "QMC5883P", "MPU9250", "IST8308", "LIS3MDL", "MSP", "RM3100", "VCM5883", "MLX90393", "FAKE"]
1212
enum: magSensor_e
1313
- name: opflow_hardware
1414
values: ["NONE", "CXOF", "MSP", "FAKE"]

src/main/sensors/compass.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "drivers/compass/compass_ist8310.h"
3939
#include "drivers/compass/compass_ist8308.h"
4040
#include "drivers/compass/compass_qmc5883l.h"
41+
#include "drivers/compass/compass_qmc5883p.h"
4142
#include "drivers/compass/compass_mpu9250.h"
4243
#include "drivers/compass/compass_lis3mdl.h"
4344
#include "drivers/compass/compass_rm3100.h"
@@ -107,6 +108,19 @@ bool compassDetect(magDev_t *dev, magSensor_e magHardwareToUse)
107108
}
108109
FALLTHROUGH;
109110

111+
case MAG_QMC5883P:
112+
#ifdef USE_MAG_QMC5883P
113+
if (qmc5883pDetect(dev)) {
114+
magHardware = MAG_QMC5883P;
115+
break;
116+
}
117+
#endif
118+
/* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
119+
if (magHardwareToUse != MAG_AUTODETECT) {
120+
break;
121+
}
122+
FALLTHROUGH;
123+
110124
case MAG_HMC5883:
111125
#ifdef USE_MAG_HMC5883
112126
if (hmc5883lDetect(dev)) {

src/main/sensors/compass.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ typedef enum {
3636
MAG_AK8963,
3737
MAG_IST8310,
3838
MAG_QMC5883,
39+
MAG_QMC5883P,
3940
MAG_MPU9250,
4041
MAG_IST8308,
4142
MAG_LIS3MDL,

src/main/target/common_hardware.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,13 @@
213213
BUSDEV_REGISTER_I2C(busdev_qmc5883, DEVHW_QMC5883, QMC5883_I2C_BUS, 0x0D, NONE, DEVFLAGS_NONE, 0);
214214
#endif
215215

216+
#if defined(USE_MAG_QMC5883P)
217+
#if !defined(QMC5883P_I2C_BUS)
218+
#define QMC5883P_I2C_BUS MAG_I2C_BUS
219+
#endif
220+
BUSDEV_REGISTER_I2C(busdev_qmc5883p, DEVHW_QMC5883P, QMC5883P_I2C_BUS, 0x2C, NONE, DEVFLAGS_NONE, 0);
221+
#endif
222+
216223
#if defined(USE_MAG_AK8963)
217224
#if defined(AK8963_SPI_BUS)
218225
BUSDEV_REGISTER_SPI(busdev_ak8963, DEVHW_AK8963, AK8963_SPI_BUS, AK8963_CS_PIN, NONE, DEVFLAGS_NONE, 0);

src/main/target/common_post.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ extern uint8_t __config_end;
8585
#define USE_MAG_LIS3MDL
8686
#define USE_MAG_MAG3110
8787
#define USE_MAG_QMC5883
88+
#define USE_MAG_QMC5883P
8889

8990
//#if (MCU_FLASH_SIZE > 512)
9091
#define USE_MAG_AK8963

0 commit comments

Comments
 (0)