-
Notifications
You must be signed in to change notification settings - Fork 36
/
BMI160.cpp
2385 lines (2213 loc) · 80.8 KB
/
BMI160.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
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
===============================================
BMI160 accelerometer/gyroscope library for Intel(R) Curie(TM) devices.
Copyright (c) 2015 Intel Corporation. All rights reserved.
Based on MPU6050 Arduino library provided by Jeff Rowberg as part of his
excellent I2Cdev device library: https://github.com/jrowberg/i2cdevlib
===============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/
#include "BMI160.h"
#define BMI160_CHIP_ID 0xD1
#define BMI160_ACCEL_POWERUP_DELAY_MS 10
#define BMI160_GYRO_POWERUP_DELAY_MS 100
/* Test the sign bit and set remaining MSBs if sign bit is set */
#define BMI160_SIGN_EXTEND(val, from) \
(((val) & (1 << ((from) - 1))) ? (val | (((1 << (1 + (sizeof(val) << 3) - (from))) - 1) << (from))) : val)
/******************************************************************************/
uint8_t BMI160Class::reg_read (uint8_t reg)
{
uint8_t buffer[1];
buffer[0] = reg;
serial_buffer_transfer(buffer, 1, 1);
return buffer[0];
}
void BMI160Class::reg_write(uint8_t reg, uint8_t data)
{
uint8_t buffer[2];
buffer[0] = reg;
buffer[1] = data;
serial_buffer_transfer(buffer, 2, 0);
}
void BMI160Class::reg_write_bits(uint8_t reg, uint8_t data, unsigned pos, unsigned len)
{
uint8_t b = reg_read(reg);
uint8_t mask = ((1 << len) - 1) << pos;
data <<= pos; // shift data into correct position
data &= mask; // zero all non-important bits in data
b &= ~(mask); // zero all important bits in existing byte
b |= data; // combine data with existing byte
reg_write(reg, b);
}
uint8_t BMI160Class::reg_read_bits(uint8_t reg, unsigned pos, unsigned len)
{
uint8_t b = reg_read(reg);
uint8_t mask = (1 << len) - 1;
b >>= pos;
b &= mask;
return b;
}
/******************************************************************************/
/** Power on and prepare for general usage.
* This will activate the device and take it out of sleep mode (which must be done
* after start-up). This function also sets both the accelerometer and the gyroscope
* to default range settings, namely +/- 2g and +/- 250 degrees/sec.
*/
void BMI160Class::initialize()
{
/* Issue a soft-reset to bring the device into a clean state */
reg_write(BMI160_RA_CMD, BMI160_CMD_SOFT_RESET);
delay(1);
/* Issue a dummy-read to force the device into SPI comms mode */
reg_read(0x7F);
delay(1);
/* Power up the accelerometer */
reg_write(BMI160_RA_CMD, BMI160_CMD_ACC_MODE_NORMAL);
delay(1);
/* Wait for power-up to complete */
while (0x1 != reg_read_bits(BMI160_RA_PMU_STATUS,
BMI160_ACC_PMU_STATUS_BIT,
BMI160_ACC_PMU_STATUS_LEN))
delay(1);
/* Power up the gyroscope */
reg_write(BMI160_RA_CMD, BMI160_CMD_GYR_MODE_NORMAL);
delay(1);
/* Wait for power-up to complete */
while (0x1 != reg_read_bits(BMI160_RA_PMU_STATUS,
BMI160_GYR_PMU_STATUS_BIT,
BMI160_GYR_PMU_STATUS_LEN))
delay(1);
setFullScaleGyroRange(BMI160_GYRO_RANGE_250);
setFullScaleAccelRange(BMI160_ACCEL_RANGE_2G);
/* Only PIN1 interrupts currently supported - map all interrupts to PIN1 */
reg_write(BMI160_RA_INT_MAP_0, 0xFF);
reg_write(BMI160_RA_INT_MAP_1, 0xF0);
reg_write(BMI160_RA_INT_MAP_2, 0x00);
}
/** Get Device ID.
* This register is used to verify the identity of the device (0b11010001, 0xD1).
* @return Device ID (should be 0xD1)
* @see BMI160_RA_CHIP_ID
*/
uint8_t BMI160Class::getDeviceID() {
return reg_read(BMI160_RA_CHIP_ID);
}
/** Verify the SPI connection.
* Make sure the device is connected and responds as expected.
* @return True if connection is valid, false otherwise
*/
bool BMI160Class::testConnection()
{
return (BMI160_CHIP_ID == getDeviceID());
}
/** Get gyroscope output data rate.
* The gyr_odr parameter allows setting the output data rate of the gyroscope
* as described in the table below.
*
* <pre>
* 6 = 25Hz
* 7 = 50Hz
* 8 = 100Hz
* 9 = 200Hz
* 10 = 400Hz
* 11 = 800Hz
* 12 = 1600Hz
* 13 = 3200Hz
* </pre>
*
* @return Current sample rate
* @see BMI160_RA_GYRO_CONF
* @see BMI160GyroRate
*/
uint8_t BMI160Class::getGyroRate() {
return reg_read_bits(BMI160_RA_GYRO_CONF,
BMI160_GYRO_RATE_SEL_BIT,
BMI160_GYRO_RATE_SEL_LEN);
}
/** Set gyroscope output data rate.
* @param rate New output data rate
* @see getGyroRate()
* @see BMI160_GYRO_RATE_25HZ
* @see BMI160_RA_GYRO_CONF
*/
void BMI160Class::setGyroRate(uint8_t rate) {
reg_write_bits(BMI160_RA_GYRO_CONF, rate,
BMI160_GYRO_RATE_SEL_BIT,
BMI160_GYRO_RATE_SEL_LEN);
}
/** Get accelerometer output data rate.
* The acc_odr parameter allows setting the output data rate of the accelerometer
* as described in the table below.
*
* <pre>
* 5 = 25/2Hz
* 6 = 25Hz
* 7 = 50Hz
* 8 = 100Hz
* 9 = 200Hz
* 10 = 400Hz
* 11 = 800Hz
* 12 = 1600Hz
* 13 = 3200Hz
* </pre>
*
* @return Current sample rate
* @see BMI160_RA_ACCEL_CONF
* @see BMI160AccelRate
*/
uint8_t BMI160Class::getAccelRate() {
return reg_read_bits(BMI160_RA_ACCEL_CONF,
BMI160_ACCEL_RATE_SEL_BIT,
BMI160_ACCEL_RATE_SEL_LEN);
}
/** Set accelerometer output data rate.
* @param rate New output data rate
* @see getAccelRate()
* @see BMI160_RA_ACCEL_CONF
*/
void BMI160Class::setAccelRate(uint8_t rate) {
reg_write_bits(BMI160_RA_ACCEL_CONF, rate,
BMI160_ACCEL_RATE_SEL_BIT,
BMI160_ACCEL_RATE_SEL_LEN);
}
/** Get gyroscope digital low-pass filter mode.
* The gyro_bwp parameter sets the gyroscope digital low pass filter configuration.
*
* When the filter mode is set to Normal (@see BMI160_DLPF_MODE_NORM), the filter
* bandwidth for each respective gyroscope output data rates is shown in the table below:
*
* <pre>
* ODR | 3dB cut-off
* --------+------------
* 25Hz | 10.7Hz
* 50Hz | 20.8Hz
* 100Hz | 39.9Hz
* 200Hz | 74.6Hz
* 400Hz | 136.6Hz
* 800Hz | 254.6Hz
* 1600Hz | 523.9Hz
* 3200Hz | 890Hz
* </pre>
*
* When the filter mode is set to OSR2 (@see BMI160_DLPF_MODE_OSR2), the filter
* bandwidths above are approximately halved.
*
* When the filter mode is set to OSR4 (@see BMI160_DLPF_MODE_OSR4), the filter
* bandwidths above are approximately 4 times smaller.
*
* @return DLFP configuration
* @see BMI160_RA_GYRO_CONF
* @see BMI160DLPFMode
*/
uint8_t BMI160Class::getGyroDLPFMode() {
return reg_read_bits(BMI160_RA_GYRO_CONF,
BMI160_GYRO_DLPF_SEL_BIT,
BMI160_GYRO_DLPF_SEL_LEN);
}
/** Set gyroscope digital low-pass filter configuration.
* @param mode New DLFP configuration setting
* @see getGyroDLPFMode()
*/
void BMI160Class::setGyroDLPFMode(uint8_t mode) {
return reg_write_bits(BMI160_RA_GYRO_CONF, mode,
BMI160_GYRO_DLPF_SEL_BIT,
BMI160_GYRO_DLPF_SEL_LEN);
}
/** Get accelerometer digital low-pass filter mode.
* The acc_bwp parameter sets the accelerometer digital low pass filter configuration.
*
* When the filter mode is set to Normal (@see BMI160_DLPF_MODE_NORM), the filter
* bandwidth for each respective accelerometer output data rates is shown in the table below:
*
* <pre>
* ODR | 3dB cut-off
* --------+--------------
* 12.5Hz | 5.06Hz
* 25Hz | 10.12Hz
* 50Hz | 20.25Hz
* 100Hz | 40.5Hz
* 200Hz | 80Hz
* 400Hz | 162Hz (155Hz for Z axis)
* 800Hz | 324Hz (262Hz for Z axis)
* 1600Hz | 684Hz (353Hz for Z axis)
* </pre>
*
* When the filter mode is set to OSR2 (@see BMI160_DLPF_MODE_OSR2), the filter
* bandwidths above are approximately halved.
*
* When the filter mode is set to OSR4 (@see BMI160_DLPF_MODE_OSR4), the filter
* bandwidths above are approximately 4 times smaller.
*
* @return DLFP configuration
* @see BMI160_RA_GYRO_CONF
* @see BMI160DLPFMode
*/
uint8_t BMI160Class::getAccelDLPFMode() {
return reg_read_bits(BMI160_RA_ACCEL_CONF,
BMI160_ACCEL_DLPF_SEL_BIT,
BMI160_ACCEL_DLPF_SEL_LEN);
}
/** Set accelerometer digital low-pass filter configuration.
* @param mode New DLFP configuration setting
* @see getAccelDLPFMode()
*/
void BMI160Class::setAccelDLPFMode(uint8_t mode) {
return reg_write_bits(BMI160_RA_ACCEL_CONF, mode,
BMI160_ACCEL_DLPF_SEL_BIT,
BMI160_ACCEL_DLPF_SEL_LEN);
}
/** Get full-scale gyroscope range.
* The gyr_range parameter allows setting the full-scale range of the gyro sensors,
* as described in the table below.
*
* <pre>
* 4 = +/- 125 degrees/sec
* 3 = +/- 250 degrees/sec
* 2 = +/- 500 degrees/sec
* 1 = +/- 1000 degrees/sec
* 0 = +/- 2000 degrees/sec
* </pre>
*
* @return Current full-scale gyroscope range setting
* @see BMI160_RA_GYRO_RANGE
* @see BMI160GyroRange
*/
uint8_t BMI160Class::getFullScaleGyroRange() {
return reg_read_bits(BMI160_RA_GYRO_RANGE,
BMI160_GYRO_RANGE_SEL_BIT,
BMI160_GYRO_RANGE_SEL_LEN);
}
/** Set full-scale gyroscope range.
* @param range New full-scale gyroscope range value
* @see getFullScaleGyroRange()
*/
void BMI160Class::setFullScaleGyroRange(uint8_t range) {
reg_write_bits(BMI160_RA_GYRO_RANGE, range,
BMI160_GYRO_RANGE_SEL_BIT,
BMI160_GYRO_RANGE_SEL_LEN);
}
/** Get full-scale accelerometer range.
* The FS_SEL parameter allows setting the full-scale range of the accelerometer
* sensors, as described in the table below.
*
* <pre>
* 3 = +/- 2g
* 5 = +/- 4g
* 8 = +/- 8g
* 12 = +/- 16g
* </pre>
*
* @return Current full-scale accelerometer range setting
* @see BMI160_RA_ACCEL_RANGE
* @see BMI160AccelRange
*/
uint8_t BMI160Class::getFullScaleAccelRange() {
return reg_read_bits(BMI160_RA_ACCEL_RANGE,
BMI160_ACCEL_RANGE_SEL_BIT,
BMI160_ACCEL_RANGE_SEL_LEN);
}
/** Set full-scale accelerometer range.
* @param range New full-scale accelerometer range setting
* @see getFullScaleAccelRange()
* @see BMI160AccelRange
*/
void BMI160Class::setFullScaleAccelRange(uint8_t range) {
reg_write_bits(BMI160_RA_ACCEL_RANGE, range,
BMI160_ACCEL_RANGE_SEL_BIT,
BMI160_ACCEL_RANGE_SEL_LEN);
}
/** Get accelerometer offset compensation enabled value.
* @see getXAccelOffset()
* @see BMI160_RA_OFFSET_6
*/
bool BMI160Class::getAccelOffsetEnabled() {
return !!(reg_read_bits(BMI160_RA_OFFSET_6,
BMI160_ACC_OFFSET_EN,
1));
}
/** Set accelerometer offset compensation enabled value.
* @see getXAccelOffset()
* @see BMI160_RA_OFFSET_6
*/
void BMI160Class::setAccelOffsetEnabled(bool enabled) {
reg_write_bits(BMI160_RA_OFFSET_6, enabled ? 0x1 : 0,
BMI160_ACC_OFFSET_EN,
1);
}
/** Execute internal calibration to generate Accelerometer X-Axis offset value.
* This populates the Accelerometer offset compensation value for the X-Axis only.
* These can be retrieved using the getXAccelOffset() methods.
* Note that this procedure may take up to 250ms to complete.
*
* IMPORTANT: The user MUST ensure NO movement and correct orientation of the
* BMI160 device occurs while this auto-calibration process is active.
* For example, to calibrate to a target of 0g on the X-axis, the BMI160 device
* must be resting horizontally as shown in Section 5.2 of the BMI160 Data Sheet.
*
* To enable offset compensation, @see setAccelOffsetEnabled()
*
* @param target X-axis target value (0 = 0g, 1 = +1g, -1 = -1g)
* @see setAccelOffsetEnabled()
* @see getXAccelOffset()
* @see BMI160_RA_FOC_CONF
* @see BMI160_RA_CMD
*/
void BMI160Class::autoCalibrateXAccelOffset(int target) {
uint8_t foc_conf;
if (target == 1)
foc_conf = (0x1 << BMI160_FOC_ACC_X_BIT);
else if (target == -1)
foc_conf = (0x2 << BMI160_FOC_ACC_X_BIT);
else if (target == 0)
foc_conf = (0x3 << BMI160_FOC_ACC_X_BIT);
else
return; /* Invalid target value */
reg_write(BMI160_RA_FOC_CONF, foc_conf);
reg_write(BMI160_RA_CMD, BMI160_CMD_START_FOC);
while (!(reg_read_bits(BMI160_RA_STATUS,
BMI160_STATUS_FOC_RDY,
1)))
delay(1);
}
/** Execute internal calibration to generate Accelerometer Y-Axis offset value.
* This populates the Accelerometer offset compensation value for the Y-Axis only.
* These can be retrieved using the getYAccelOffset() methods.
* Note that this procedure may take up to 250ms to complete.
*
* IMPORTANT: The user MUST ensure NO movement and correct orientation of the
* BMI160 device occurs while this auto-calibration process is active.
* For example, to calibrate to a target of 0g on the Y-axis, the BMI160 device
* must be resting horizontally as shown in Section 5.2 of the BMI160 Data Sheet.
*
* To enable offset compensation, @see setAccelOffsetEnabled()
*
* @param target Y-axis target value (0 = 0g, 1 = +1g, -1 = -1g)
* @see setAccelOffsetEnabled()
* @see getYAccelOffset()
* @see BMI160_RA_FOC_CONF
* @see BMI160_RA_CMD
*/
void BMI160Class::autoCalibrateYAccelOffset(int target) {
uint8_t foc_conf;
if (target == 1)
foc_conf = (0x1 << BMI160_FOC_ACC_Y_BIT);
else if (target == -1)
foc_conf = (0x2 << BMI160_FOC_ACC_Y_BIT);
else if (target == 0)
foc_conf = (0x3 << BMI160_FOC_ACC_Y_BIT);
else
return; /* Invalid target value */
reg_write(BMI160_RA_FOC_CONF, foc_conf);
reg_write(BMI160_RA_CMD, BMI160_CMD_START_FOC);
while (!(reg_read_bits(BMI160_RA_STATUS,
BMI160_STATUS_FOC_RDY,
1)))
delay(1);
}
/** Execute internal calibration to generate Accelerometer Z-Axis offset value.
* This populates the Accelerometer offset compensation value for the Z-Axis only.
* These can be retrieved using the getZAccelOffset() methods.
* Note that this procedure may take up to 250ms to complete.
*
* IMPORTANT: The user MUST ensure NO movement and correct orientation of the
* BMI160 device occurs while this auto-calibration process is active.
* For example, to calibrate to a target of +1g on the Z-axis, the BMI160 device
* must be resting horizontally as shown in Section 5.2 of the BMI160 Data Sheet.
*
* To enable offset compensation, @see setAccelOffsetEnabled()
*
* @param target Z-axis target value (0 = 0g, 1 = +1g, -1 = -1g)
* @see setAccelOffsetEnabled()
* @see getZAccelOffset()
* @see BMI160_RA_FOC_CONF
* @see BMI160_RA_CMD
*/
void BMI160Class::autoCalibrateZAccelOffset(int target) {
uint8_t foc_conf;
if (target == 1)
foc_conf = (0x1 << BMI160_FOC_ACC_Z_BIT);
else if (target == -1)
foc_conf = (0x2 << BMI160_FOC_ACC_Z_BIT);
else if (target == 0)
foc_conf = (0x3 << BMI160_FOC_ACC_Z_BIT);
else
return; /* Invalid target value */
reg_write(BMI160_RA_FOC_CONF, foc_conf);
reg_write(BMI160_RA_CMD, BMI160_CMD_START_FOC);
while (!(reg_read_bits(BMI160_RA_STATUS,
BMI160_STATUS_FOC_RDY,
1)))
delay(1);
}
/** Get offset compensation value for accelerometer X-axis data.
* The value is represented as an 8-bit two-complement number in
* units of 3.9mg per LSB.
* @see BMI160_RA_OFFSET_0
*/
int8_t BMI160Class::getXAccelOffset() {
return reg_read(BMI160_RA_OFFSET_0);
}
/** Set offset compensation value for accelerometer X-axis data.
* This is used for applying manual calibration constants if required.
* For auto-calibration, @see autoCalibrateXAccelOffset().
* @see getXAccelOffset()
* @see BMI160_RA_OFFSET_0
*/
void BMI160Class::setXAccelOffset(int8_t offset) {
reg_write(BMI160_RA_OFFSET_0, offset);
getAccelerationX(); /* Read and discard the next data value */
}
/** Get offset compensation value for accelerometer Y-axis data.
* The value is represented as an 8-bit two-complement number in
* units of 3.9mg per LSB.
* @see BMI160_RA_OFFSET_1
*/
int8_t BMI160Class::getYAccelOffset() {
return reg_read(BMI160_RA_OFFSET_1);
}
/** Set offset compensation value for accelerometer Y-axis data.
* This is used for applying manual calibration constants if required.
* For auto-calibration, @see autoCalibrateYAccelOffset().
* @see getYAccelOffset()
* @see BMI160_RA_OFFSET_1
*/
void BMI160Class::setYAccelOffset(int8_t offset) {
reg_write(BMI160_RA_OFFSET_1, offset);
getAccelerationY(); /* Read and discard the next data value */
}
/** Get offset compensation value for accelerometer Z-axis data.
* The value is represented as an 8-bit two-complement number in
* units of 3.9mg per LSB.
* @see BMI160_RA_OFFSET_2
*/
int8_t BMI160Class::getZAccelOffset() {
return reg_read(BMI160_RA_OFFSET_2);
}
/** Set offset compensation value for accelerometer Z-axis data.
* This is used for applying manual calibration constants if required.
* For auto-calibration, @see autoCalibrateZAccelOffset().
* @see getZAccelOffset()
* @see BMI160_RA_OFFSET_2
*/
void BMI160Class::setZAccelOffset(int8_t offset) {
reg_write(BMI160_RA_OFFSET_2, offset);
getAccelerationZ(); /* Read and discard the next data value */
}
/** Get gyroscope offset compensation enabled value.
* @see getXGyroOffset()
* @see BMI160_RA_OFFSET_6
*/
bool BMI160Class::getGyroOffsetEnabled() {
return !!(reg_read_bits(BMI160_RA_OFFSET_6,
BMI160_GYR_OFFSET_EN,
1));
}
/** Set gyroscope offset compensation enabled value.
* @see getXGyroOffset()
* @see BMI160_RA_OFFSET_6
*/
void BMI160Class::setGyroOffsetEnabled(bool enabled) {
reg_write_bits(BMI160_RA_OFFSET_6, enabled ? 0x1 : 0,
BMI160_GYR_OFFSET_EN,
1) ;
}
/** Execute internal calibration to generate Gyro offset values.
* This populates the Gyro offset compensation values for all 3 axes.
* These can be retrieved using the get[X/Y/Z]GyroOffset() methods.
* Note that this procedure may take up to 250ms to complete.
*
* IMPORTANT: The user MUST ensure that NO rotation of the BMI160 device
* occurs while this auto-calibration process is active.
*
* To enable offset compensation, @see setGyroOffsetEnabled()
* @see setGyroOffsetEnabled()
* @see getXGyroOffset()
* @see getYGyroOffset()
* @see getZGyroOffset()
* @see BMI160_RA_FOC_CONF
* @see BMI160_RA_CMD
*/
void BMI160Class::autoCalibrateGyroOffset() {
uint8_t foc_conf = (1 << BMI160_FOC_GYR_EN);
reg_write(BMI160_RA_FOC_CONF, foc_conf);
reg_write(BMI160_RA_CMD, BMI160_CMD_START_FOC);
while (!(reg_read_bits(BMI160_RA_STATUS,
BMI160_STATUS_FOC_RDY,
1)))
delay(1);
}
/** Get offset compensation value for gyroscope X-axis data.
* The value is represented as an 10-bit two-complement number in
* units of 0.061 degrees/s per LSB (sign-extended for int16_t type).
* @see BMI160_RA_OFFSET_3
* @see BMI160_RA_OFFSET_6
*/
int16_t BMI160Class::getXGyroOffset() {
int16_t offset = reg_read(BMI160_RA_OFFSET_3);
offset |= (int16_t)(reg_read_bits(BMI160_RA_OFFSET_6,
BMI160_GYR_OFFSET_X_MSB_BIT,
BMI160_GYR_OFFSET_X_MSB_LEN)) << 8;
return BMI160_SIGN_EXTEND(offset, 10);
}
/** Set offset compensation value for gyroscope X-axis data.
* This is used for applying manual calibration constants if required.
* For auto-calibration, @see autoCalibrateGyroOffset().
* @see getXGyroOffset()
* @see BMI160_RA_OFFSET_3
* @see BMI160_RA_OFFSET_6
*/
void BMI160Class::setXGyroOffset(int16_t offset) {
reg_write(BMI160_RA_OFFSET_3, offset);
reg_write_bits(BMI160_RA_OFFSET_6, offset >> 8,
BMI160_GYR_OFFSET_X_MSB_BIT,
BMI160_GYR_OFFSET_X_MSB_LEN);
getRotationX(); /* Read and discard the next data value */
}
/** Get offset compensation value for gyroscope Y-axis data.
* The value is represented as an 10-bit two-complement number in
* units of 0.061 degrees/s per LSB (sign-extended for int16_t type).
* @see BMI160_RA_OFFSET_4
* @see BMI160_RA_OFFSET_6
*/
int16_t BMI160Class::getYGyroOffset() {
int16_t offset = reg_read(BMI160_RA_OFFSET_4);
offset |= (int16_t)(reg_read_bits(BMI160_RA_OFFSET_6,
BMI160_GYR_OFFSET_Y_MSB_BIT,
BMI160_GYR_OFFSET_Y_MSB_LEN)) << 8;
return BMI160_SIGN_EXTEND(offset, 10);
}
/** Set offset compensation value for gyroscope Y-axis data.
* This is used for applying manual calibration constants if required.
* For auto-calibration, @see autoCalibrateGyroOffset().
* @see getYGyroOffset()
* @see BMI160_RA_OFFSET_4
* @see BMI160_RA_OFFSET_6
*/
void BMI160Class::setYGyroOffset(int16_t offset) {
reg_write(BMI160_RA_OFFSET_4, offset);
reg_write_bits(BMI160_RA_OFFSET_6, offset >> 8,
BMI160_GYR_OFFSET_Y_MSB_BIT,
BMI160_GYR_OFFSET_Y_MSB_LEN);
getRotationY(); /* Read and discard the next data value */
}
/** Get offset compensation value for gyroscope Z-axis data.
* The value is represented as an 10-bit two-complement number in
* units of 0.061 degrees/s per LSB (sign-extended for int16_t type).
* @see BMI160_RA_OFFSET_5
* @see BMI160_RA_OFFSET_6
*/
int16_t BMI160Class::getZGyroOffset() {
int16_t offset = reg_read(BMI160_RA_OFFSET_5);
offset |= (int16_t)(reg_read_bits(BMI160_RA_OFFSET_6,
BMI160_GYR_OFFSET_Z_MSB_BIT,
BMI160_GYR_OFFSET_Z_MSB_LEN)) << 8;
return BMI160_SIGN_EXTEND(offset, 10);
}
/** Set offset compensation value for gyroscope Z-axis data.
* This is used for applying manual calibration constants if required.
* For auto-calibration, @see autoCalibrateGyroOffset().
* @see getZGyroOffset()
* @see BMI160_RA_OFFSET_5
* @see BMI160_RA_OFFSET_6
*/
void BMI160Class::setZGyroOffset(int16_t offset) {
reg_write(BMI160_RA_OFFSET_5, offset);
reg_write_bits(BMI160_RA_OFFSET_6, offset >> 8,
BMI160_GYR_OFFSET_Z_MSB_BIT,
BMI160_GYR_OFFSET_Z_MSB_LEN);
getRotationZ(); /* Read and discard the next data value */
}
/** Get free-fall event acceleration threshold.
* This register configures the detection threshold for Free Fall event
* detection. The unit of int_low_th is 1LSB = 7.81mg (min: 3.91mg). Free Fall
* is detected when the absolute value of the accelerometer measurements for the
* three axes are each less than the detection threshold. This condition
* triggers the Free-Fall (low-g) interrupt if the condition is maintained for
* the duration specified in the int_low_dur field of the INT_LOWHIGH[0]
* register (@see BMI160_RA_INT_LOWHIGH_0)
*
* For more details on the Free Fall detection interrupt, see Section 2.6.7 of the
* BMI160 Data Sheet.
*
* @return Current free-fall acceleration threshold value (LSB = 7.81mg, 0 = 3.91mg)
* @see BMI160_RA_INT_LOWHIGH_1
*/
uint8_t BMI160Class::getFreefallDetectionThreshold() {
return reg_read(BMI160_RA_INT_LOWHIGH_1);
}
/** Set free-fall event acceleration threshold.
* @param threshold New free-fall acceleration threshold value (LSB = 7.81mg, 0 = 3.91mg)
* @see getFreefallDetectionThreshold()
* @see BMI160_RA_INT_LOWHIGH_1
*/
void BMI160Class::setFreefallDetectionThreshold(uint8_t threshold) {
reg_write(BMI160_RA_INT_LOWHIGH_1, threshold);
}
/** Get free-fall event duration threshold.
* This register configures the duration threshold for Free Fall event
* detection. The int_low_dur field of the INT_LOWHIGH[0] register has a unit
* of 1 LSB = 2.5 ms (minimum 2.5ms).
*
* For more details on the Free Fall detection interrupt, see Section 2.6.7 of
* the BMI160 Data Sheet.
*
* @return Current free-fall duration threshold value (LSB = 2.5ms, 0 = 2.5ms)
* @see BMI160_RA_INT_LOWHIGH_0
*/
uint8_t BMI160Class::getFreefallDetectionDuration() {
return reg_read(BMI160_RA_INT_LOWHIGH_0);
}
/** Set free-fall event duration threshold.
* @param duration New free-fall duration threshold value (LSB = 2.5ms, 0 = 2.5ms)
* @see getFreefallDetectionDuration()
* @see BMI160_RA_INT_LOWHIGH_0
*/
void BMI160Class::setFreefallDetectionDuration(uint8_t duration) {
reg_write(BMI160_RA_INT_LOWHIGH_0, duration);
}
/** Get shock event acceleration threshold.
* This register configures the detection threshold for Shock event
* detection. The unit of threshold is dependent on the accelerometer
* sensitivity range (@see getFullScaleAccelRange()):
*
* <pre>
* Full Scale Range | LSB Resolution
* -----------------+----------------
* +/- 2g | 7.81 mg/LSB (0 = 3.91mg)
* +/- 4g | 15.63 mg/LSB (0 = 7.81mg)
* +/- 8g | 31.25 mg/LSB (0 = 15.63mg)
* +/- 16g | 62.50 mg/LSB (0 = 31.25mg)
* </pre>
*
* Shock is detected when the absolute value of the accelerometer measurements
* for any of the three axes exceeds the detection threshold. This condition
* triggers the Shock (high-g) interrupt if the condition is maintained without
* a sign-change for the duration specified in the int_high_dur field of the
* INT_LOWHIGH[3] register (@see BMI160_RA_INT_LOWHIGH_3).
*
* For more details on the Shock (high-g) detection interrupt, see Section 2.6.8 of the
* BMI160 Data Sheet.
*
* @return Current shock acceleration threshold value
* @see BMI160_RA_INT_LOWHIGH_4
*/
uint8_t BMI160Class::getShockDetectionThreshold() {
return reg_read(BMI160_RA_INT_LOWHIGH_4);
}
/** Set shock event acceleration threshold.
* @param threshold New shock acceleration threshold value
* @see getShockDetectionThreshold()
* @see BMI160_RA_INT_LOWHIGH_4
*/
void BMI160Class::setShockDetectionThreshold(uint8_t threshold) {
reg_write(BMI160_RA_INT_LOWHIGH_4, threshold);
}
/** Get shock event duration threshold.
* This register configures the duration threshold for Shock event
* detection. The int_high_dur field of the INT_LOWHIGH[3] register has a unit
* of 1 LSB = 2.5 ms (minimum 2.5ms).
*
* For more details on the Shock detection interrupt, see Section 2.6.8 of
* the BMI160 Data Sheet.
*
* @return Current shock duration threshold value (LSB = 2.5ms, 0 = 2.5ms)
* @see BMI160_RA_INT_LOWHIGH_3
*/
uint8_t BMI160Class::getShockDetectionDuration() {
return reg_read(BMI160_RA_INT_LOWHIGH_3);
}
/** Set free-fall event duration threshold.
* @param duration New free-fall duration threshold value (LSB = 2.5ms, 0 = 2.5ms)
* @see getFreefallDetectionDuration()
* @see BMI160_RA_INT_LOWHIGH_3
*/
void BMI160Class::setShockDetectionDuration(uint8_t duration) {
reg_write(BMI160_RA_INT_LOWHIGH_3, duration);
}
/** Get Step Detection mode.
* Returns an enum value which corresponds to current mode
* 0 = Normal Mode
* 1 = Sensitive Mode
* 2 = Robust Mode
* 3 = Unkown Mode
* For more details on the Step Detection, see Section
* 2.11.37 of the BMI160 Data Sheet.
*
* @return Current configuration of the step detector
* @see BMI160_RA_STEP_CONF_0
* @see BMI160_RA_STEP_CONF_1
*/
uint8_t BMI160Class::getStepDetectionMode() {
uint8_t ret_step_conf0, ret_min_step_buf;
ret_step_conf0 = reg_read(BMI160_RA_STEP_CONF_0);
ret_min_step_buf = reg_read(BMI160_RA_STEP_CONF_1);
if ((ret_step_conf0 == BMI160_RA_STEP_CONF_0_NOR) && (ret_min_step_buf == BMI160_RA_STEP_CONF_1_NOR))
return BMI160_STEP_MODE_NORMAL;
else if ((ret_step_conf0 == BMI160_RA_STEP_CONF_0_SEN) && (ret_min_step_buf == BMI160_RA_STEP_CONF_1_SEN))
return BMI160_STEP_MODE_SENSITIVE;
else if ((ret_step_conf0 == BMI160_RA_STEP_CONF_0_ROB) && (ret_min_step_buf == BMI160_RA_STEP_CONF_1_ROB))
return BMI160_STEP_MODE_ROBUST;
else
return BMI160_STEP_MODE_UNKNOWN;
}
/** Set Step Detection mode.
* Sets the step detection mode to one of 3 predefined sensitivity settings:
*
* @see BMI160_STEP_MODE_NORMAL (Recommended for most applications)
* @see BMI160_STEP_MODE_SENSITIVE
* @see BMI160_STEP_MODE_ROBUST
*
* Please refer to Section 2.11.37 of the BMI160 Data Sheet for more information
* on Step Detection configuration.
*
* @return Set Step Detection mode
* @see BMI160_RA_STEP_CONF_0
* @see BMI160_RA_STEP_CONF_1
* @see BMI160StepMode
*/
void BMI160Class::setStepDetectionMode(BMI160StepMode mode) {
uint8_t step_conf0, min_step_buf;
/* Applying pre-defined values suggested in data-sheet Section 2.11.37 */
switch (mode) {
case BMI160_STEP_MODE_NORMAL:
step_conf0 = 0x15;
min_step_buf = 0x3;
break;
case BMI160_STEP_MODE_SENSITIVE:
step_conf0 = 0x2D;
min_step_buf = 0x0;
break;
case BMI160_STEP_MODE_ROBUST:
step_conf0 = 0x1D;
min_step_buf = 0x7;
break;
default:
/* Unrecognised mode option */
return;
};
reg_write(BMI160_RA_STEP_CONF_0, step_conf0);
reg_write_bits(BMI160_RA_STEP_CONF_1, min_step_buf,
BMI160_STEP_BUF_MIN_BIT,
BMI160_STEP_BUF_MIN_LEN);
}
/** Get Step Counter enabled status.
* Once enabled and configured correctly (@see setStepDetectionMode()), the
* BMI160 will increment a counter for every step detected by the accelerometer.
* To retrieve the current step count, @see getStepCount().
*
* For more details on the Step Counting feature, see Section
* 2.7 of the BMI160 Data Sheet.
*
* @return Current Step Counter enabled status
* @see BMI160_RA_STEP_CONF_1
* @see BMI160_STEP_CNT_EN_BIT
*/
bool BMI160Class::getStepCountEnabled() {
return !!(reg_read_bits(BMI160_RA_STEP_CONF_1,
BMI160_STEP_CNT_EN_BIT,
1));
}
/** Set Step Counter enabled status.
*
* @return Set Step Counter enabled
* @see getStepCountEnabled()
* @see BMI160_RA_STEP_CONF_1
* @see BMI160_STEP_CNT_EN_BIT
*/
void BMI160Class::setStepCountEnabled(bool enabled) {
return reg_write_bits(BMI160_RA_STEP_CONF_1, enabled ? 0x1 : 0,
BMI160_STEP_CNT_EN_BIT,
1);
}
/** Get current number of detected step movements (Step Count).
* Returns a step counter which is incremented when step movements are detected
* (assuming Step Detection mode and Step Counter are configured/enabled).
*
* @return Number of steps as an unsigned 16-bit integer
* @see setStepCountEnabled()
* @see setStepDetectionMode()
* @see BMI160_RA_STEP_CNT_L
*/
uint16_t BMI160Class::getStepCount() {
uint8_t buffer[2];
buffer[0] = BMI160_RA_STEP_CNT_L;
serial_buffer_transfer(buffer, 1, 2);
return (((uint16_t)buffer[1]) << 8) | buffer[0];
}
/** Resets the current number of detected step movements (Step Count) to 0.
*
* @see getStepCount()
* @see BMI160_RA_CMD
*/
void BMI160Class::resetStepCount() {
reg_write(BMI160_RA_CMD, BMI160_CMD_STEP_CNT_CLR);
}
/** Get motion detection event acceleration threshold.
* This register configures the detection threshold for Motion interrupt
* generation in the INT_MOTION[1] register. The unit of threshold is
* dependent on the accelerometer sensitivity range (@see
* getFullScaleAccelRange()):
*
* <pre>
* Full Scale Range | LSB Resolution
* -----------------+----------------
* +/- 2g | 3.91 mg/LSB
* +/- 4g | 7.81 mg/LSB
* +/- 8g | 15.63 mg/LSB
* +/- 16g | 31.25 mg/LSB
* </pre>
*
* Motion is detected when the difference between the absolute value of
* consecutive accelerometer measurements for the 3 axes exceeds this Motion
* detection threshold. This condition triggers the Motion interrupt if the
* condition is maintained for the sample count interval specified in the
* int_anym_dur field of the INT_MOTION[0] register (@see BMI160_RA_INT_MOTION_0)
*
* The Motion interrupt will indicate the axis and polarity of detected motion
* in INT_STATUS[2] (@see BMI160_RA_INT_STATUS_2).
*
* For more details on the Motion detection interrupt, see Section 2.6.1 of the
* BMI160 Data Sheet.
*
* @return Current motion detection acceleration threshold value
* @see getMotionDetectionDuration()
* @see BMI160_RA_INT_MOTION_1
*/
uint8_t BMI160Class::getMotionDetectionThreshold() {
return reg_read(BMI160_RA_INT_MOTION_1);
}
/** Set motion detection event acceleration threshold.
* @param threshold New motion detection acceleration threshold value
* @see getMotionDetectionThreshold()
* @see BMI160_RA_INT_MOTION_1
*/
void BMI160Class::setMotionDetectionThreshold(uint8_t threshold) {
return reg_write(BMI160_RA_INT_MOTION_1, threshold);
}
/** Get motion detection event duration threshold.
* This register configures the duration counter threshold for Motion interrupt
* generation, as a number of consecutive samples (from 1-4). The time
* between samples depends on the accelerometer Output Data Rate
* (@see getAccelRate()).
*
* The Motion detection interrupt is triggered when the difference between
* samples exceeds the Any-Motion interrupt threshold for the number of
* consecutive samples specified here.
*
* For more details on the Motion detection interrupt, see Section 2.6.1 of the
* BMI160 Data Sheet.
*
* @return Current motion detection duration threshold value (#samples [1-4])
* @see getMotionDetectionThreshold()
* @see BMI160_RA_INT_MOTION_0
*/