@@ -27,36 +27,163 @@ SOFTWARE.
2727#include " mag.h"
2828#include " ../hal/MF_I2C.h"
2929
30+ // #include "../cli/stat.h" //for debugging
31+
32+
33+ // https://www.lcsc.com/datasheet/lcsc_datasheet_2410121623_QST-QMC6309_C5439871.pdf
34+
35+ // Who Am I register
36+ #define QMC6309_WAI_REG 0x00
37+
38+ #define QMC6309_WAI_VALUE 0x90
39+
40+ // Data register
41+ #define QMC6309_OUTX_REG 0x01
42+
43+ // Status register {DRDY:1;OVFL:1;...}
44+ #define QMC6309_STAT_REG 0x09
45+
46+ #define QMC6309_STAT_DRDY 0x01 // 1=data ready
47+ #define QMC6309_STAT_OVFL 0x02 // 1=overflow
48+ #define QMC6309_STAT_ST_RDY 0x04 // 1=self test ready
49+ #define QMC6309_STAT_NVM_RDY 0x08 // 1=nvm ready for access
50+ #define QMC6309_STAT_NVM_LOAD_DONE 0x10 // 1=nvm loading done
51+
52+ // Control register 1 {MD:2;:1;OSR:2;LPF:3;}
53+ #define QMC6309_CTRL1_REG 0x0A
54+
55+ #define QMC6309_CTRL1_MD_SUSPEND 0b00
56+ #define QMC6309_CTRL1_MD_NORMAL 0b01
57+ #define QMC6309_CTRL1_MD_SINGLE 0b10
58+ #define QMC6309_CTRL1_MD_CONTINUOUS 0b11
59+
60+ #define QMC6309_CTRL1_OSR_1 (0b11 <<3 )
61+ #define QMC6309_CTRL1_OSR_2 (0b10 <<3 )
62+ #define QMC6309_CTRL1_OSR_4 (0b01 <<3 )
63+ #define QMC6309_CTRL1_OSR_8 (0b00 <<3 )
64+
65+ #define QMC6309_CTRL1_LPF_1 (0b000 <<5 )
66+ #define QMC6309_CTRL1_LPF_2 (0b001 <<5 )
67+ #define QMC6309_CTRL1_LPF_4 (0b010 <<5 )
68+ #define QMC6309_CTRL1_LPF_8 (0b011 <<5 )
69+ #define QMC6309_CTRL1_LPF_16 (0b100 <<5 )
70+
71+ // Control register 2 {SET:2;RGN:2;ODR:3;SRT:1;}
72+ #define QMC6309_CTRL2_REG 0x0B
73+
74+ #define QMC6309_CTRL2_SET_RESET_ON 0b00
75+ #define QMC6309_CTRL2_SET_ONLY 0b01
76+ #define QMC6309_CTRL2_SET_RESET_OFF 0b11
77+
78+ #define QMC6309_CTRL2_RNG_32G (0b00 <<2 )
79+ #define QMC6309_CTRL2_RNG_16G (0b01 <<2 )
80+ #define QMC6309_CTRL2_RNG_8G (0b10 <<2 )
81+
82+ // output data rate for normal mode
83+ #define QMC6309_CTRL2_ODR_1Hz (0b000 <<4 )
84+ #define QMC6309_CTRL2_ODR_10Hz (0b001 <<4 )
85+ #define QMC6309_CTRL2_ODR_50Hz (0b010 <<4 )
86+ #define QMC6309_CTRL2_ODR_100Hz (0b011 <<4 )
87+ #define QMC6309_CTRL2_ODR_200Hz (0b100 <<4 )
88+
89+ #define QMC6309_CTRL2_SOFT_RESET_START 0x80
90+ #define QMC6309_CTRL2_SOFT_RESET_STOP 0x00
91+
92+
3093class MagGizmoQMC6309 : public MagGizmo {
3194private:
3295 MF_I2CDevice *dev = nullptr ;
3396
97+
3498public:
35- MagGizmoQMC6309 (MF_I2C *i2c, int8_t i2c_adr) {
36- i2c_adr = 0x7C ; // fixed: 0x7C
37- this ->dev = new MF_I2CDevice (i2c, i2c_adr);
99+ const float scale_uT = 0.025 ; // scale factor to uT (at +/-800uT (+/-8G) RNG)
100+ int16_t mx; // raw adc values
101+ int16_t my;
102+ int16_t mz;
38103
39- // setup for 16 sample moving average (my interpretation of data sheet OSR2 setting), sample rate = 1500Hz (continous mode)
40- dev->writeReg (0x0B , 0x04 ); // ODR=1Hz, Scale=8G, Reset
41- dev->writeReg (0x0A , 0xFD ); // OSR2(filter)=16, OSR=1, Continuous Mode
104+ ~MagGizmoQMC6309 () {
105+ delete dev;
42106 }
43107
108+ MagGizmoQMC6309 (MF_I2C *i2c) {
109+ i2c->setClock (400000 );
44110
45- ~MagGizmoQMC6309 () {
46- delete dev;
111+ this ->dev = new MF_I2CDevice (i2c, 0x7C ); // i2c address is always 0x7C
112+
113+ // soft reset
114+ // dev->writeReg(QMC6309_CTRL2_REG, QMC6309_CTRL2_SOFT_RESET_START);
115+ // dev->writeReg(QMC6309_CTRL2_REG, QMC6309_CTRL2_SOFT_RESET_STOP);
116+
117+ // configure 220Hz update rate with LPF_16
118+ uint8_t ctrl2_val = QMC6309_CTRL2_SET_RESET_ON | QMC6309_CTRL2_RNG_8G | QMC6309_CTRL2_ODR_100Hz;
119+ uint8_t ctrl1_val = QMC6309_CTRL1_MD_CONTINUOUS | QMC6309_CTRL1_OSR_8 | QMC6309_CTRL1_LPF_16; // mx mean:-10.982379 stdev:1.401531 min:-14.000000 max:-8.000000 n:227
120+ // uint8_t ctrl1_val = QMC6309_CTRL1_MD_CONTINUOUS | QMC6309_CTRL1_OSR_8 | QMC6309_CTRL1_LPF_1; //mx mean:-10.060345 stdev:6.673316 min:-33.000000 max:+4.000000 n:232
121+ // uint8_t ctrl1_val = QMC6309_CTRL1_MD_CONTINUOUS | QMC6309_CTRL1_OSR_1 | QMC6309_CTRL1_LPF_1; //mx mean:-11.925335 stdev:38.645042 min:-119.000000 max:+106.000000 n:1125
122+
123+ int tries = 20 ;
124+ uint8_t wai = 0 ;
125+ while (tries) {
126+ uint8_t ctrl1 = dev->readReg (QMC6309_CTRL1_REG);
127+ uint8_t ctrl2 = dev->readReg (QMC6309_CTRL2_REG);
128+ wai = dev->readReg (QMC6309_WAI_REG);
129+
130+ // setup
131+ if (ctrl2 != ctrl2_val) dev->writeReg (QMC6309_CTRL2_REG, ctrl2_val);
132+ if (ctrl1 != ctrl1_val) dev->writeReg (QMC6309_CTRL1_REG, ctrl1_val);
133+ delay (1 );
134+
135+ uint8_t stat = dev->readReg (QMC6309_STAT_REG);
136+ if (stat & QMC6309_STAT_DRDY) {
137+ break ;
138+ }
139+
140+ tries--;
141+
142+ // Serial.printf("try wai=%02X stat=%02X ctrl2=%02X(%02X) ctrl1=%02X(%02X)\n", wai, stat, ctrl2, ctrl2_val, ctrl1, ctrl1_val);
143+ }
144+ if (!tries) Serial.printf (" MAG: ERROR could not configure QMC6309. wai:0x%02X, expected 0x%02X\n " , wai, QMC6309_WAI_VALUE);
145+
146+ /* //DEBUG
147+ while(1) {
148+ Stat mx,my,mz;
149+ uint32_t start_ts = micros();
150+ while(micros() - start_ts < 1000000) {
151+ float x,y,z;
152+ if(update(&x,&y,&z)) {
153+ mx.append(x);
154+ my.append(y);
155+ mz.append(z);
156+ }
157+ }
158+
159+ Serial.println("=== Magnetometer (external) ===");
160+ mx.print("mx");
161+ my.print("my");
162+ mz.print("mz");
163+ }
164+ */
47165 }
48166
167+ bool update_raw () {
168+ uint8_t stat = dev->readReg (QMC6309_STAT_REG);
169+ if ((stat & QMC6309_STAT_DRDY) == 0 || (stat & QMC6309_STAT_OVFL) != 0 ) return false ;
49170
50- bool update (float *x, float *y, float *z) override {
51171 uint8_t d[6 ];
52- dev->readReg (0x01 , d, 6 );
53- int16_t mx = d[0 ] | (d[1 ] << 8 ); // 16 bit litte-endian signed
54- int16_t my = d[2 ] | (d[3 ] << 8 );
55- int16_t mz = d[4 ] | (d[5 ] << 8 );
56-
57- *x = 200e-9 * mx; // in [T]
58- *y = 200e-9 * my;
59- *z = 200e-9 * mz;
172+ dev->readReg (QMC6309_OUTX_REG, d, 6 );
173+
174+ mx = d[0 ] | (d[1 ] << 8 ); // 16 bit litte-endian signed - 40LSB/uT at +/-800uT scale
175+ my = d[2 ] | (d[3 ] << 8 );
176+ mz = d[4 ] | (d[5 ] << 8 );
177+
178+ return true ;
179+ }
180+
181+ bool update (float *x, float *y, float *z) override {
182+ if (!update_raw ()) return false ;
183+
184+ *x = scale_uT * mx;
185+ *y = scale_uT * my;
186+ *z = scale_uT * mz;
60187 return true ;
61188 }
62189};
0 commit comments