-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathao_BNO055.cpp
328 lines (296 loc) · 10.6 KB
/
ao_BNO055.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#include "Arduino.h"
#include "ao_JetiExBusSensor.h"
#include "ao_BNO055.h"
#include "ao_WireLight.h"
#include "ao_JetiExBus.h"
#include "ao_Eeprom.h"
#include "ao_SystemConf.h"
uint16_t bnoerrorcnt=0;
extern WireLight wireLight;
extern SystemConf sysConf;
extern volatile uint8_t bnoTimerCnt;
//data
#define BNO_CLK_SEL 0x80
#define BNO_RST_SYS 0x20
#define POWER_MODE_NORMAL 0X00
// status
#define BNO_CALIB_STAT_ADR 0X35
#define BNO_SELFTEST_RESULT_ADR 0X36
#define BNO_INTR_STAT_ADR 0X37
#define BNO_SYS_CLK_STAT_ADR 0X38
#define BNO_SYS_STAT_ADR 0X39
#define BNO_SYS_ERR_ADR 0X3A
// config
#define BNO_UNIT_SEL_ADR 0X3B
#define BNO_DATA_SELECT_ADR 0X3C
#define BNO_OPR_MODE_ADR 0X3D
#define BNO_PWR_MODE_ADR 0X3E
#define BNO_SYS_TRIGGER_ADR 0X3F
#define BNO_TEMP_SOURCE_ADR 0X40
#define BNO_AXIS_MAP_ASSIGN_ADR 0X41
#define BNO_AXIS_MAP_SIGN_ADR 0X42
// control register
#define BNO_CHIP_ID_ADR 0x00
#define BNO_ACCEL_REV_ID_ADR 0x01
#define BNO_MAG_REV_ID_ADR 0x02
#define BNO_GYRO_REV_ID_ADR 0x03
#define BNO_SW_REV_ID_LSB_ADR 0x04
#define BNO_SW_REV_ID_MSB_ADR 0x05
#define BNO_BL_REV_ID_ADR 0X06
#define BNO_PAGE_ID_ADR 0X07
// calibration
#define BNO_CALIBDATA_REG 0x55
//
uint8_t const AO_BNO::axisMap[];
volatile uint16_t AO_BNO::waitToAction;
void AO_BNO::doMain(void){
if ((waitToAction==0)&&((stateMachine&BNO_STATE_CNT)==0)){ // wait for BNO chip or stateMachine
if (sysConf.getHardwareActive(SYS_CONF_HW_ORIENTATION)){
if (sysConf.getHardwareChanged(SYS_CONF_HW_ORIENTATION)){
start(); // enabled while running
} else {
if (bnoTimerCnt>24){ // 100ms passed?
bnoTimerCnt=0;
if ((stateMachine&(BNO_ERROR|BNO_PRESENT|BNO_READY))==(BNO_PRESENT|BNO_READY)){ // chip present, no error
/* uint8_t stat; // reinit bno if not running
getSensorRegister(&stat, nullptr, nullptr);
if (stat!=5){ // is BNO still running?
start(); // restart BNO
return;
}
*/
// Headding, roll, nick
DataVector dv;
getSensor(dv, BNO_REG_EULER);
exBus.setSensorValue(SEM_ORI_HEAD,dv.x);
exBus.setSensorValue(SEM_ORI_NICK,dv.y);
exBus.setSensorValue(SEM_ORI_ROLL,dv.z);
// Acceleration
getSensor(dv, BNO_REG_ACCELEROMETER);
exBus.setSensorValue(SEM_ORI_AC_X,dv.x);
exBus.setSensorValue(SEM_ORI_AC_Y,dv.y);
exBus.setSensorValue(SEM_ORI_AC_Z,dv.z);
// total acceleration
uint32_t totalG=sqrt((uint32_t)(dv.x*dv.x)+(uint32_t)(dv.y*dv.y)+(uint32_t)(dv.z*dv.z));
exBus.setSensorValue(SEM_ORI_AC_T,totalG);
}
if (axesMap&0x80){ // new axes data from menue?
startAxes();
} else if (sysConf.getHardwareActive(SYS_CONF_HW_ORIENT_CALI)&&!eepromJobBNO){ // request and previous job done?
if (getCalibSatus()==0xFF){
startCalib2EE();
}
}
}
}
} else {
if (!eepromJobBNO){
stateMachine=0; // all done then turn off
}
}
}
doStateMachine();
// write calibration data to eeprom
if (eepromJobBNO){
if (safeCalibData()){
sysConf.setHardwareActive(SYS_CONF_HW_ORIENT_CALI,false); // reset JB requestflag for calibration
}
}
}
//----------------------------------------------------------------------
bool AO_BNO::safeCalibData(void){
bool calib=false;
if (eepromJobBNO==BNO_CALIBDATA_LENGTH+3) {
eepromJobBNO--;
calData = new uint8_t[BNO_CALIBDATA_LENGTH+1]; // get memory
calData[BNO_CALIBDATA_LENGTH]=57; // simple checksum
} else if (eepromJobBNO==BNO_CALIBDATA_LENGTH+2) {
if (stateMachine==(BNO_PRESENT|BNO_READY)){ // data from BNO ready
for (uint8_t i=0; i<BNO_CALIBDATA_LENGTH; i++)
calData[BNO_CALIBDATA_LENGTH]+=calData[i];
eepromJobBNO--;
}
} else if (eepromJobBNO){ // write data to eeprom
eepromJobBNO--;
if (!AEEPROM.update(BNO_CALIB_EEPROM+eepromJobBNO, calData[eepromJobBNO])){
eepromJobBNO++;
} else if (!eepromJobBNO){
delete [] calData; // done, return memory
calib=true;
}
}
return calib;
}
void AO_BNO::start(void){
stateMachine=BNO_START|BNO_CNT0;
axesMap&=0x7F;
waitToAction=1000; // delay for next action >650ms
}
void AO_BNO::startAxes(void){
stateMachine=BNO_PRESENT|BNO_AXES|BNO_CNT1;
axesMap&=0x7F;
setModeConfig();
}
void AO_BNO::startCalib2EE(void){
stateMachine=BNO_PRESENT|BNO_CALIB2EE|BNO_CNT1;
setModeConfig();
eepromJobBNO=BNO_CALIBDATA_LENGTH+3; // start Calibration to EEprom
}
void AO_BNO::startOff(void){ // no further action on BNO
stateMachine=0;
}
void AO_BNO::doStateMachine(void){
if (waitToAction) return; // wait for BNO chip
//
switch (stateMachine&0x1F){
case (BNO_START|BNO_CNT0) :{ // start 0
if (isPresent()){
stateMachine=BNO_PRESENT|BNO_START|BNO_CNT1; // start reset
setReset();
} else {
stateMachine=BNO_ERROR; // if not present then error
}
stateMachine=BNO_PRESENT|BNO_START|BNO_CNT1;// start => 1
break;}
case (BNO_START|BNO_CNT1) :{ // start 1
setPowerMode();
writeAxes();
writeCalibData();
setModeOperation();
stateMachine=BNO_PRESENT|BNO_START|BNO_CNT2;// start => 2
break;}
case (BNO_START|BNO_CNT2) :{ // start 2
uint8_t stat;
getSensorRegister(&stat, nullptr, nullptr);
if (stat==5){
stateMachine=BNO_PRESENT|BNO_READY; // mode is running
} else {
waitToAction=10000; // error, try again in 10s
stateMachine=BNO_PRESENT|BNO_START|BNO_CNT3;// start => 3
}
break;}
case (BNO_START|BNO_CNT3) :{ // restart 3
start();
break;}
case (BNO_AXES|BNO_CNT1) :{ // set axes
writeAxes();
setModeOperation();
stateMachine=BNO_PRESENT|BNO_READY;
break;}
case (BNO_CALIB2EE|BNO_CNT1) :{ // read calib data from BNO
readCalibData(calData);
setModeOperation();
stateMachine=BNO_PRESENT|BNO_READY;
break;}
}
}
// --- funtion blocks -------------------
// check chip ID
inline bool AO_BNO::isPresent(void) {
uint8_t value;
wireLight.requestFrom(BNO_CHIP_ADRESS, BNO_CHIP_ID_ADR, &value);
return (value == BNO_ID ? true:false);
}
// do chip reset
inline void AO_BNO::setReset(void){
uint8_t value=0;
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_PAGE_ID_ADR, &value); // Page 0
value=BNO_RST_SYS;
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_SYS_TRIGGER_ADR, &value); // reset BNO
waitToAction=1000; // delay for next action >650ms
}
// cconfig: set power mode
inline void AO_BNO::setPowerMode(void) {
uint8_t value= BNO_CLK_SEL; // external crystal
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_SYS_TRIGGER_ADR, &value);
value=POWER_MODE_NORMAL; // NORMAL Power mode
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_PWR_MODE_ADR, &value);
}
// set config mode
void AO_BNO::setModeConfig(void) {
uint8_t mode= BNO_OPMODE_CONFIG;
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_OPR_MODE_ADR, &mode);
waitToAction=15; // >8 delay for mode change
}
// set measure mode
void AO_BNO::setModeOperation(void) {
uint8_t mode= BNO_OPMODE_NDOF;
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_OPR_MODE_ADR, &mode);
waitToAction=1500; // NDOF needs about 400ms (simple> 19ms) delay for mode change
}
// config: upper nibble: axis signs xyz 0-7, lower nibble: axis remapping 0-5
void AO_BNO::writeAxes(void) {
uint8_t am=(axesMap>>4)&0x07;
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_AXIS_MAP_SIGN_ADR, &am);
am=axisMap[axesMap&0x07];
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_AXIS_MAP_ASSIGN_ADR, &am);
}
// config:
void AO_BNO::readCalibData(uint8_t *calibData) {
wireLight.requestFrom(BNO_CHIP_ADRESS, BNO_CALIBDATA_REG, calibData, BNO_CALIBDATA_LENGTH);
}
// config:
void AO_BNO::writeCalibData(void){
uint8_t calData[BNO_CALIBDATA_LENGTH+1];
uint8_t checkSum=57;
for(uint8_t i=0; i<BNO_CALIBDATA_LENGTH; i++){
calData[i]=AEEPROM.read(BNO_CALIB_EEPROM+i);
checkSum+=calData[i];
}
uint8_t checkSumEE=AEEPROM.read(BNO_CALIB_EEPROM+BNO_CALIBDATA_LENGTH);
if (checkSumEE==checkSum){ // write only calibration data to chip with valid checksum
setCalibOffsets(calData);
}
}
// config:
void AO_BNO::setCalibOffsets(uint8_t *calibData) {
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_CALIBDATA_REG, calibData, BNO_CALIBDATA_LENGTH);
}
// config:
void AO_BNO::clearCalibration(void){
uint8_t calibData[BNO_CALIBDATA_LENGTH];
memset(calibData,0,BNO_CALIBDATA_LENGTH);
wireLight.sendTo(BNO_CHIP_ADRESS, BNO_CALIBDATA_REG, calibData, BNO_CALIBDATA_LENGTH);
}
// --- interfaces -------------------
void AO_BNO::setAxes(uint8_t axesMapping){
axesMap=axesMapping|0x80; // mark as new
}
void AO_BNO::getSensorRegister(uint8_t *status, uint8_t *selftest, uint8_t *error) {
if (status)
wireLight.requestFrom(BNO_CHIP_ADRESS, BNO_SYS_STAT_ADR, status);
if (selftest)
wireLight.requestFrom(BNO_CHIP_ADRESS, BNO_SELFTEST_RESULT_ADR, selftest);
if (error)
wireLight.requestFrom(BNO_CHIP_ADRESS, BNO_SYS_ERR_ADR, error);
}
// reads measured data from register
void AO_BNO::getSensor(DataVector &dv, uint8_t regAdr) {
uint8_t rxBuffer[6];
wireLight.requestFrom(BNO_CHIP_ADRESS, regAdr, rxBuffer, 6);
int16_t x = ((int16_t)rxBuffer[0]) | (((int16_t)rxBuffer[1]) << 8);
int16_t y = ((int16_t)rxBuffer[2]) | (((int16_t)rxBuffer[3]) << 8);
int16_t z = ((int16_t)rxBuffer[4]) | (((int16_t)rxBuffer[5]) << 8);
int16_t divisor;
switch (regAdr) {
// case BNO_REG_MAGNETOMETER:
// case BNO_REG_GYROSCOPE:
case BNO_REG_EULER:
divisor=16;
break;
default:
divisor=10;
}
dv.x = x/ divisor;
dv.y = y/ divisor;
dv.z = z/ divisor;
}
//
uint8_t AO_BNO::getCalibSatus(void) {
uint8_t clibStatus = 0;
wireLight.requestFrom(BNO_CHIP_ADRESS, BNO_CALIB_STAT_ADR, &clibStatus);
return clibStatus;
}
uint8_t AO_BNO::getStatus(void){
return stateMachine&0xE0;
}