2022-10-02 20:41:51 +01:00
|
|
|
|
/*
|
|
|
|
|
xsns_99_qmc5883l.ino - QMC5883L 3-Axis Digital Compass sensor support for Tasmota
|
|
|
|
|
|
|
|
|
|
Copyright (C) 2022 Helge Scheunemann
|
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
DATASHEET
|
|
|
|
|
|
|
|
|
|
The QMC5883L is a multi-chip three-axis magnetic sensor. This
|
|
|
|
|
surface -mount, small sized chip has integrated magnetic sensors with
|
|
|
|
|
signal condition ASIC, targeted for high precision applications such as
|
|
|
|
|
compassing, navigation and gaming in drone, robot, mobile and
|
|
|
|
|
personal hand-held devices.
|
|
|
|
|
The QMC5883L is based on our state-of-the-art, high resolution,
|
|
|
|
|
magneto-resistive technology licensed from Honeywell AMR technology.
|
|
|
|
|
Along with custom-designed 16-bit ADC ASIC, it offers the advantages of
|
|
|
|
|
low noise, high accuracy, low power consumption, offset cancellation and
|
|
|
|
|
temperature compensation. QMC5883L enables 1° to 2° compass
|
|
|
|
|
heading accuracy. The I²C serial bus allows for easy interface
|
|
|
|
|
|
|
|
|
|
9.1 Register Map
|
|
|
|
|
The table below provides a list of the 8-bit registers embedded in the device and their respective function and
|
|
|
|
|
addresses
|
|
|
|
|
|
|
|
|
|
Table 13. Register Map
|
|
|
|
|
Addr. 7 6 5 4 3 2 1 0 Access
|
|
|
|
|
00H Data Output X LSB Register XOUT[7:0] Read only
|
|
|
|
|
01H Data Output X MSB Register XOUT[15:8] Read only
|
|
|
|
|
02H Data Output Y LSB Register YOUT[7:0] Read only
|
|
|
|
|
03H Data Output Y MSB Register YOUT[15:8] Read only
|
|
|
|
|
04H Data Output Z LSB Register ZOUT[7:0] Read only
|
|
|
|
|
05H Data Output Z MSB Register ZOUT[15:8] Read only
|
|
|
|
|
06H DOR OVL DRDY Read only
|
|
|
|
|
07H TOUT[7:0] Read only
|
|
|
|
|
08H TOUT[15:8] Read only
|
|
|
|
|
09H OSR[1:0] RNG[1:0] ODR[1:0] MODE[1:0] Read/Write
|
|
|
|
|
0AH SOFT_RST ROL_P NT INT_E NB R/W, Read only on blanks
|
|
|
|
|
0BH SET/RESET Period FBR [7:0] Read/Write
|
|
|
|
|
0CH Reserved Read only
|
|
|
|
|
0DH Reserved Read only
|
|
|
|
|
|
|
|
|
|
9.2 Register Definition
|
|
|
|
|
9.2.1 Output Data Register
|
|
|
|
|
Registers 00H ~ 05H store the measurement data from each axis magnetic sensor in continuous-measurement.
|
|
|
|
|
In the continuous measurement mode, the output data is refreshed periodically based on the data update rate
|
|
|
|
|
ODR setup in control registers 1. The data stays the same, regardless of reading status through I2C, until new
|
|
|
|
|
data replaces them. Each axis has 16 bit data width in 2’s complement, i.e., MSB of 01H/03H/05H indicates the
|
|
|
|
|
sign of each axis. The output data of each channel saturates at -32768 and 32767.
|
|
|
|
|
|
|
|
|
|
Table 14. Output Data Register
|
|
|
|
|
Addr. 7 6 5 4 3 2 1 0
|
|
|
|
|
00H Data Output X LSB Register XOUT[7:0]
|
|
|
|
|
01H Data Output X MSB Register XOUT[15:8]
|
|
|
|
|
02H Data Output Y LSB Register YOUT[7:0]
|
|
|
|
|
03H Data Output Y MSB Register YOUT[15:8]
|
|
|
|
|
04H Data Output Z LSB Register ZOUT[7:0]
|
|
|
|
|
05H Data Output Z MSB Register ZOUT[15:8]
|
|
|
|
|
|
|
|
|
|
9.2.2 Status Register
|
|
|
|
|
There are two status registers located in address 06H and 0CH.
|
|
|
|
|
Register 06H has three bits indicating for status flags, the rest are reserved for factory use. The status registers
|
|
|
|
|
are read only bits.
|
|
|
|
|
|
|
|
|
|
Table 15. Status Register 1
|
|
|
|
|
Addr. 7 6 5 4 3 2 1 0
|
|
|
|
|
06H DOR OVL DRDY
|
|
|
|
|
|
|
|
|
|
Data Ready Register (DRDY), it is set when all three axis data is ready, and loaded to the output data registers in
|
|
|
|
|
the continuous measurement mode. It is reset to “0” by reading any data register (00H~05H) through I2C
|
|
|
|
|
commends
|
|
|
|
|
DRDY: “0”: no new data, “1”: new data is ready
|
|
|
|
|
Overflow flag (OVL) is set to “1” if any data of three axis magnetic sensor channels is out of range. The output
|
|
|
|
|
data of each axis saturates at -32768 and 32767, if any of the axis exceeds this range, OVL flag is set to “1”. This
|
|
|
|
|
flag is reset to “0” if next measurement goes back to the range of (-32768, 32767), otherwise, it keeps as “1”.
|
|
|
|
|
OVL: “0”: normal, “1”: data overflow
|
|
|
|
|
Data Skip (DOR) bit is set to “1” if all the channels of output data registers are skipped in reading in the
|
|
|
|
|
continuous-measurement mode. It is reset to “0” by reading any data register (00H~05H) through I2C
|
|
|
|
|
DOR: “0”: normal, “1”: data skipped for reading
|
|
|
|
|
|
|
|
|
|
9.2.3 Temperature Data Registers
|
|
|
|
|
Registers 07H-08H store temperature sensor output data. 16 bits temperature sensor output is in 2’s complement.
|
|
|
|
|
Temperature sensor gain is factory-calibrated, but its offset has not been compensated, only relative temperature
|
|
|
|
|
value is accurate. The temperature coefficient is about 100 LSB/℃
|
|
|
|
|
|
|
|
|
|
Table 17. Temperature Sensor Output
|
|
|
|
|
Addr. 7 6 5 4 3 2 1 0
|
|
|
|
|
07H TOUT[7:0]
|
|
|
|
|
08H TOUT[15:8]
|
|
|
|
|
|
|
|
|
|
9.2.4 Control Registers
|
|
|
|
|
Two 8-bits registers are used to control the device configurations.
|
|
|
|
|
Control register 1 is located in address 09H, it sets the operational modes (MODE). output data update rate
|
|
|
|
|
(ODR), magnetic field measurement range or sensitivity of the sensors (RNG) and over sampling rate (OSR).
|
|
|
|
|
Control register 2 is located in address 0AH. It controls Interrupt Pin enabling (INT_ENB), Point roll over function
|
|
|
|
|
enabling(POL_PNT) and soft reset (SOFT_RST).
|
|
|
|
|
Two bits of MODE registers can transfer mode of operations in the device, the two modes are Standby, and
|
|
|
|
|
Continuous measurements. The default mode after Power-on-Reset (POR) is standby. There is no any restriction
|
|
|
|
|
in the transferring between the modes.
|
|
|
|
|
Output data rate is controlled by ODR registers. Four data update frequencies can be selected: 10Hz, 50Hz,
|
|
|
|
|
100Hz and 200Hz. For most of compassing applications, we recommend 10 Hz for low power consumption. For
|
|
|
|
|
gaming, the high update rate such as 100Hz or 200Hz can be used.
|
|
|
|
|
Field ranges of the magnetic sensor can be selected through the register RNG. The full scale field range is
|
|
|
|
|
determined by the application environments. For magnetic clear environment, low field range such as +/- 2gauss
|
|
|
|
|
can be used. The field range goes hand in hand with the sensitivity of the magnetic sensor. The lowest field range
|
|
|
|
|
has the highest sensitivity, therefore, higher resolution.
|
|
|
|
|
Over sample Rate (OSR) registers are used to control bandwidth of an internal digital filter. Larger OSR value
|
|
|
|
|
leads to smaller filter bandwidth, less in-band noise and higher power consumption. It could be used to reach a
|
|
|
|
|
good balance between noise and power. Four over sample ratio can be selected, 64, 128, 256 or 512.
|
|
|
|
|
|
|
|
|
|
Table 18. Control Register 1
|
|
|
|
|
Addr 7 6 5 4 3 2 1 0
|
|
|
|
|
09H OSR[1:0] RNG[1:0] ODR[1:0] MODE[1:0]
|
|
|
|
|
|
|
|
|
|
Reg. Definition 00 01 10 11
|
|
|
|
|
Mode Mode Control Standby Continuous Reserve Reserve
|
|
|
|
|
ODR Output Data Rate 10Hz 50Hz 100Hz 200Hz
|
|
|
|
|
RNG Full Scale 2G 8G Reserve Reserve
|
|
|
|
|
OSR Over Sample Ratio 512 256 128 64
|
|
|
|
|
|
|
|
|
|
Interrupt enabling is controlled by register INT_ENB in control register 2. Once the interrupt is enabled, it will flag
|
|
|
|
|
when new data is in Data Output Registers.
|
|
|
|
|
INT_ENB: “0”: enable interrupt PIN, “1”: disable interrupt PIN
|
|
|
|
|
Pointer roll-over function is controlled by ROL_PNT register. When the point roll-over function is enabled, the I2C
|
|
|
|
|
data pointer automatically rolls between 00H ~ 06H, if I2C read begins at any address among 00H~06H.
|
|
|
|
|
ROL_PNT: “0”: Normal, “1”: Enable pointer roll-over function
|
|
|
|
|
Soft Reset can be done by changing the register SOFT_RST to set. Soft reset can be invoked at any time of any
|
|
|
|
|
mode. For example, if soft reset occurs at the middle of continuous mode reading, QMC5883L immediately
|
|
|
|
|
switches to standby mode due to mode register is reset to “00” in default.
|
|
|
|
|
SOFT_RST: “0”: Normal“1”: Soft reset, restore default value of all registers.
|
|
|
|
|
Table 19. Control Register 2
|
|
|
|
|
Addr. 7 6 5 4 3 2 1 0
|
|
|
|
|
0AH SOFT_RST ROL_PNT INT_ENB
|
|
|
|
|
|
|
|
|
|
9.2.5 SET/RESET Period Register
|
|
|
|
|
SET/RESET Period is controlled by FBR [7:0], it is recommended that the register 0BH is written by 0x01.
|
|
|
|
|
|
|
|
|
|
Table 20. SET/RESET Period Register
|
|
|
|
|
Addr. 7 6 5 4 3 2 1 0
|
|
|
|
|
0BH SET/RESET Perio [7:0]
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef USE_I2C
|
|
|
|
|
#ifdef USE_QMC5883L
|
|
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
|
* QMC5883L is 3-Axis Digital Compass sensor
|
|
|
|
|
*
|
|
|
|
|
* Source: Helge Scheunemann
|
|
|
|
|
*
|
|
|
|
|
* I2C Address: 0x0D
|
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
|
|
// Define driver ID
|
|
|
|
|
#define XSNS_33 33
|
|
|
|
|
#define XI2C_71 71 // See I2CDEVICES.md
|
|
|
|
|
|
|
|
|
|
/* The default I2C address of this chip */
|
|
|
|
|
#define QMC5883L_ADDR 0x0D
|
|
|
|
|
|
|
|
|
|
/* Register numbers */
|
|
|
|
|
#define QMC5883L_X_LSB 0x00
|
|
|
|
|
#define QMC5883L_X_MSB 0x01
|
|
|
|
|
#define QMC5883L_Y_LSB 0x02
|
|
|
|
|
#define QMC5883L_Y_MSB 0x03
|
|
|
|
|
#define QMC5883L_Z_LSB 0x04
|
|
|
|
|
#define QMC5883L_Z_MSB 0x05
|
|
|
|
|
#define QMC5883L_STATUS 0x06
|
|
|
|
|
#define QMC5883L_TEMP_LSB 0x07
|
|
|
|
|
#define QMC5883L_TEMP_MSB 0x08
|
|
|
|
|
#define QMC5883L_CONFIG 0x09
|
|
|
|
|
#define QMC5883L_CONFIG2 0x0a
|
|
|
|
|
#define QMC5883L_RESET 0x0b
|
|
|
|
|
#define QMC5883L_RESERVED 0x0c
|
|
|
|
|
#define QMC5883L_CHIP_ID 0x0d
|
|
|
|
|
|
|
|
|
|
/* Bit values for the STATUS register */
|
|
|
|
|
#define QMC5883L_STATUS_DRDY 1
|
|
|
|
|
#define QMC5883L_STATUS_OVL 2
|
|
|
|
|
#define QMC5883L_STATUS_DOR 4
|
|
|
|
|
|
|
|
|
|
/* Oversampling values for the CONFIG register */
|
|
|
|
|
#define QMC5883L_CONFIG_OS512 0b00000000
|
|
|
|
|
#define QMC5883L_CONFIG_OS256 0b01000000
|
|
|
|
|
#define QMC5883L_CONFIG_OS128 0b10000000
|
|
|
|
|
#define QMC5883L_CONFIG_OS64 0b11000000
|
|
|
|
|
|
|
|
|
|
/* Range values for the CONFIG register */
|
|
|
|
|
#define QMC5883L_CONFIG_2GAUSS 0b00000000
|
|
|
|
|
#define QMC5883L_CONFIG_8GAUSS 0b00010000
|
|
|
|
|
|
|
|
|
|
/* Rate values for the CONFIG register */
|
|
|
|
|
#define QMC5883L_CONFIG_10HZ 0b00000000
|
|
|
|
|
#define QMC5883L_CONFIG_50HZ 0b00000100
|
|
|
|
|
#define QMC5883L_CONFIG_100HZ 0b00001000
|
|
|
|
|
#define QMC5883L_CONFIG_200HZ 0b00001100
|
|
|
|
|
|
|
|
|
|
/* Mode values for the CONFIG register */
|
|
|
|
|
#define QMC5883L_CONFIG_STANDBY 0b00000000
|
|
|
|
|
#define QMC5883L_CONFIG_CONT 0b00000001
|
|
|
|
|
|
|
|
|
|
/* Mode values for the CONFIG2 register */
|
|
|
|
|
#define QMC5883L_CONFIG2_RESET 0b10000000
|
|
|
|
|
|
2022-10-04 14:48:27 +01:00
|
|
|
|
// data field
|
|
|
|
|
struct QMC5883L_s
|
|
|
|
|
{
|
|
|
|
|
int16_t MX, MY, MZ;
|
|
|
|
|
int16_t temp;
|
|
|
|
|
uint16_t scalar;
|
2022-10-04 17:16:49 +01:00
|
|
|
|
bool ready;
|
2022-10-04 14:48:27 +01:00
|
|
|
|
} *QMC5883L = nullptr;
|
2022-10-02 20:41:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initialise the device
|
|
|
|
|
void QMC5883L_Init()
|
|
|
|
|
{
|
2022-10-04 17:16:49 +01:00
|
|
|
|
QMC5883L = (QMC5883L_s *)calloc(1, sizeof(struct QMC5883L_s));
|
|
|
|
|
QMC5883L->ready = false;
|
2022-10-04 14:48:27 +01:00
|
|
|
|
if (!I2cSetDevice(QMC5883L_ADDR))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
I2cSetActiveFound(QMC5883L_ADDR, "QMC5883L");
|
2022-10-02 20:41:51 +01:00
|
|
|
|
// reset QMC5883L
|
2022-10-04 14:48:27 +01:00
|
|
|
|
if (I2cWrite8(QMC5883L_ADDR, QMC5883L_CONFIG2, QMC5883L_CONFIG2_RESET) == false)
|
|
|
|
|
return; // Software Reset
|
|
|
|
|
if (I2cWrite8(QMC5883L_ADDR, QMC5883L_RESET, 0x01) == false)
|
|
|
|
|
return;
|
2022-10-02 20:41:51 +01:00
|
|
|
|
// write config
|
2022-10-04 14:48:27 +01:00
|
|
|
|
if (I2cWrite8(QMC5883L_ADDR, QMC5883L_CONFIG, QMC5883L_CONFIG_OS256 | QMC5883L_CONFIG_8GAUSS | QMC5883L_CONFIG_100HZ | QMC5883L_CONFIG_CONT) == false)
|
|
|
|
|
return;
|
2022-10-04 17:16:49 +01:00
|
|
|
|
QMC5883L->ready = true;
|
2022-10-02 20:41:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Read the magnetic data
|
|
|
|
|
void QMC5883L_read_data(void)
|
|
|
|
|
{
|
|
|
|
|
// check if chip is ready to provice data
|
2022-10-04 14:48:27 +01:00
|
|
|
|
if (!(I2cRead8(QMC5883L_ADDR, QMC5883L_STATUS) & QMC5883L_STATUS_DRDY))
|
|
|
|
|
return; // chip not yet ready, next round try again
|
|
|
|
|
|
|
|
|
|
QMC5883L->MX = I2cReadS16_LE(QMC5883L_ADDR, QMC5883L_X_LSB); // select LSB register
|
|
|
|
|
QMC5883L->MY = I2cReadS16_LE(QMC5883L_ADDR, QMC5883L_Y_LSB);
|
|
|
|
|
QMC5883L->MZ = I2cReadS16_LE(QMC5883L_ADDR, QMC5883L_Z_LSB);
|
2022-10-02 20:41:51 +01:00
|
|
|
|
|
|
|
|
|
// calculate scalar magnetic induction
|
2022-10-04 14:48:27 +01:00
|
|
|
|
QMC5883L->scalar = sqrt((QMC5883L->MX * QMC5883L->MX) + (QMC5883L->MY * QMC5883L->MY) + (QMC5883L->MZ * QMC5883L->MZ));
|
|
|
|
|
|
|
|
|
|
// get temperature
|
|
|
|
|
QMC5883L->temp = (I2cReadS16_LE(QMC5883L_ADDR, QMC5883L_TEMP_LSB) / 100) + QMC5883L_TEMP_SHIFT;
|
2022-10-02 20:41:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
|
* Presentation
|
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
|
|
#ifdef USE_WEBSERVER
|
|
|
|
|
const char HTTP_SNS_QMC5883L[] PROGMEM =
|
|
|
|
|
"{s}QMC5883L " D_MX "{m}%d " D_UNIT_MICROTESLA "{e}" // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
|
|
|
|
"{s}QMC5883L " D_MY "{m}%d " D_UNIT_MICROTESLA "{e}" // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
|
|
|
|
"{s}QMC5883L " D_MZ "{m}%d " D_UNIT_MICROTESLA "{e}" // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
|
|
|
|
"{s}QMC5883L " D_MAGNETICFLD "{m}%d " D_UNIT_MICROTESLA "{e}" // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
|
|
|
|
"{s}QMC5883L " D_TEMPERATURE "{m}%d " D_UNIT_DEGREE D_UNIT_CELSIUS "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
|
|
|
|
|
|
|
|
|
const char HTTP_SNS_QMC5883L_ERROR[] PROGMEM =
|
2022-10-03 19:42:28 +01:00
|
|
|
|
"{s}QMC5883L {m} %s {e}";
|
2022-10-02 20:41:51 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void QMC5883L_Show(uint8_t json)
|
|
|
|
|
{
|
|
|
|
|
if (json)
|
|
|
|
|
{
|
2022-10-04 14:48:27 +01:00
|
|
|
|
ResponseAppend_P(PSTR(",\"QMC5883L\":{\"" D_JSON_MX "\":%d,\"" D_JSON_MY "\":%d,\"" D_JSON_MZ "\":%d,\"" D_JSON_MAGNETICFLD "\":%u,\"" D_JSON_TEMPERATURE "\":%d}"), QMC5883L->MX, QMC5883L->MY, QMC5883L->MZ, QMC5883L->scalar, QMC5883L->temp);
|
2022-10-02 20:41:51 +01:00
|
|
|
|
}
|
|
|
|
|
#ifdef USE_WEBSERVER
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-10-04 14:48:27 +01:00
|
|
|
|
WSContentSend_PD(HTTP_SNS_QMC5883L, QMC5883L->MX, QMC5883L->MY, QMC5883L->MZ, QMC5883L->scalar, QMC5883L->temp);
|
2022-10-02 20:41:51 +01:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
|
* Interface
|
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
2022-10-02 21:21:18 +01:00
|
|
|
|
bool Xsns33(byte function)
|
2022-10-02 20:41:51 +01:00
|
|
|
|
{
|
2022-10-02 21:21:18 +01:00
|
|
|
|
if (!I2cEnabled(XI2C_71))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-10-04 17:16:49 +01:00
|
|
|
|
if (FUNC_INIT == function)
|
2022-10-03 19:42:28 +01:00
|
|
|
|
{
|
2022-10-04 17:16:49 +01:00
|
|
|
|
QMC5883L_Init();
|
|
|
|
|
}
|
|
|
|
|
else if (QMC5883L->ready == true)
|
|
|
|
|
{
|
|
|
|
|
switch (function)
|
|
|
|
|
{
|
2022-10-04 14:48:27 +01:00
|
|
|
|
case FUNC_JSON_APPEND:
|
|
|
|
|
QMC5883L_Show(1);
|
|
|
|
|
break;
|
|
|
|
|
case FUNC_EVERY_SECOND:
|
|
|
|
|
QMC5883L_read_data();
|
|
|
|
|
break;
|
2022-10-02 20:41:51 +01:00
|
|
|
|
#ifdef USE_WEBSERVER
|
2022-10-04 14:48:27 +01:00
|
|
|
|
case FUNC_WEB_SENSOR:
|
|
|
|
|
QMC5883L_Show(0);
|
|
|
|
|
break;
|
2022-10-02 20:41:51 +01:00
|
|
|
|
#endif // USE_WEBSERVER
|
2022-10-04 17:16:49 +01:00
|
|
|
|
}
|
2022-10-02 20:41:51 +01:00
|
|
|
|
}
|
2022-10-03 19:42:28 +01:00
|
|
|
|
return true;
|
2022-10-02 20:41:51 +01:00
|
|
|
|
}
|
|
|
|
|
#endif // USE_QMC5883L
|
|
|
|
|
#endif // USE_I2C
|