DevLab_ICM20948 1.0.0
ICM-20948 9-Axis Motion Sensor Driver
Loading...
Searching...
No Matches
DevLab_ICM20948.h
Go to the documentation of this file.
1#ifndef ICM20948_DEVLAB_H
2#define ICM20948_DEVLAB_H
3
4#include <Arduino.h>
5#include <Wire.h>
6#include <SPI.h>
7#include "ICM20948_regs.h"
8
9#include "7Semi_Interface.h"
10#include "7Semi_I2C_Interface.h"
11#include "7Semi_SPI_Interface.h"
12#include "BusIO_7Semi.h"
13
14enum class ICM20948_Op_Mode : uint8_t
15{
16 MODE_POWER_DOWN = 0x00,
18 MODE_CONTINUOUS_1 = 0x02,
19 MODE_CONTINUOUS_2 = 0x04,
20 MODE_CONTINUOUS_3 = 0x06,
21 MODE_CONTINUOUS_4 = 0x08,
22 MODE_SELF_TEST = 0x10
23};
24
25enum class ICM20948_Clock_Source : uint8_t
26{
27 INTERNAL_20MHZ_0 = 0x00, // Internal oscillator
28 AUTO_PLL_1 = 0x01, // Auto select (PLL if ready)
29 AUTO_PLL_2 = 0x02,
30 AUTO_PLL_3 = 0x03,
31 AUTO_PLL_4 = 0x04,
32 AUTO_PLL_5 = 0x05,
33 INTERNAL_20MHZ_6 = 0x06, // Internal oscillator
34 STOP_CLOCK = 0x07 // Stops clock, timing generator reset
35};
36
37enum class ICM20948_Gyro_DLPF : uint8_t
38{
39 DLPF_196HZ = 0x00, // BW ≈ 196.6 Hz, NBW ≈ 229.8 Hz
40 DLPF_151HZ = 0x01, // BW ≈ 151.8 Hz, NBW ≈ 187.6 Hz
41 DLPF_119HZ = 0x02, // BW ≈ 119.5 Hz, NBW ≈ 154.3 Hz
42 DLPF_51HZ = 0x03, // BW ≈ 51.2 Hz, NBW ≈ 73.3 Hz
43 DLPF_23HZ = 0x04, // BW ≈ 23.9 Hz, NBW ≈ 35.9 Hz
44 DLPF_11HZ = 0x05, // BW ≈ 11.6 Hz, NBW ≈ 17.8 Hz
45 DLPF_5HZ = 0x06, // BW ≈ 5.7 Hz, NBW ≈ 8.9 Hz
46 DLPF_361HZ = 0x07 // BW ≈ 361.4 Hz, NBW ≈ 376.5 Hz
47};
48
49enum class ICM20948_Gyro_Average : uint8_t
50{
51 AVG_1 = 0x00, // 1x Average (no averaging)
52 AVG_2 = 0x01, // 2x Average
53 AVG_4 = 0x02, // 4x Average
54 AVG_8 = 0x03, // 8x Average
55 AVG_16 = 0x04, // Average 16 samples
56 AVG_32 = 0x05, // Average 32 samples
57 AVG_64 = 0x06, // Average 64 samples
58 AVG_128 = 0x07 // Average 128 samples
59};
60enum class ICM20948_Gyro_FullScale : uint8_t
61{
62 DPS_250 = 0x00, // ±250 dps
63 DPS_500 = 0x01, // ±500 dps
64 DPS_1000 = 0x02, // ±1000 dps
65 DPS_2000 = 0x03 // ±2000 dps
66};
67
68enum class ICM20948_Accel_FullScale : uint8_t
69{
70 G_2 = 0x00, // ±2g
71 G_4 = 0x01, // ±4g
72 G_8 = 0x02, // ±8g
73 G_16 = 0x03 // ±16g
74};
75
76enum class ICM20948_Accel_Average : uint8_t
77{
78 AVG_1_OR_4 = 0x00, // Depends on ACCEL_FCHOICE
79 AVG_8 = 0x01, // Average 8 samples
80 AVG_16 = 0x02, // Average 16 samples
81 AVG_32 = 0x03 // Average 32 samples
82};
83
84enum class ICM20948_Accel_DLPFCFG : uint8_t
85{
86 DLPF0_246HZ = 0x00, // BW ≈ 246 Hz, NBW ≈ 265 Hz
87 DLPF_246HZ = 0x01, // BW ≈ 246 Hz, NBW ≈ 265 Hz
88 DLPF_111HZ = 0x02, // BW ≈ 111 Hz, NBW ≈ 136 Hz
89 DLPF_50HZ = 0x03, // BW ≈ 50 Hz, NBW ≈ 68.8 Hz
90 DLPF_24HZ = 0x04, // BW ≈ 24 Hz, NBW ≈ 34.4 Hz
91 DLPF_12HZ = 0x05, // BW ≈ 12 Hz, NBW ≈ 17 Hz
92 DLPF_6HZ = 0x06, // BW ≈ 6 Hz, NBW ≈ 8.3 Hz
93 DLPF_473HZ = 0x07, // BW ≈ 473 Hz, NBW ≈ 499 Hz
94};
95
96/**
97 * ICM20948_IntPinConfig
98 *
99 * - Physical configuration of the INT pin (INT_PIN_CFG register, BANK 0)
100 * - Controls electrical behavior and clear condition of the interrupt line
101 * - Pass to intInit() to apply settings
102 */
104{
105 uint8_t activeLevel : 1; // bit 7 | 0 = active high, 1 = active low
106 uint8_t driveMode : 1; // bit 6 | 0 = push-pull, 1 = open-drain
107 uint8_t latchMode : 1; // bit 5 | 0 = pulse 50µs, 1 = latch held
108 uint8_t clearMode : 1; // bit 4 | 0 = read INT_STATUS, 1 = any read
109 uint8_t fsyncActLevel : 1; // bit 3 | 0 = FSYNC active high, 1 = FSYNC active low
110 uint8_t fsyncIntEn : 1; // bit 2 | 0 = FSYNC disabled, 1 = FSYNC as interrupt
111 uint8_t bypassEn : 1; // bit 1 | 0 = normal, 1 = I2C bypass mode
112};
113
114/**
115 * ICM20948_IntEnableConfig
116 *
117 * - Selects which interrupt sources are routed to the INT pin
118 * - Covers INT_ENABLE (0x10), INT_ENABLE_1 (0x11), INT_ENABLE_2 (0x12), INT_ENABLE_3 (0x13)
119 * - FIFO overflow and watermark fields are per-channel arrays [0]–[4]
120 * - Pass to intEnableConfig() to write all four registers in one call
121 */
123{
124 // --- INT_ENABLE (0x10) ---
125 uint8_t wofEn : 1; // Wake on FSYNC
126 uint8_t womIntEn : 1; // Wake on motion
127 uint8_t pllRdyEn : 1; // PLL ready
128 uint8_t dmpInt1En : 1; // DMP interrupt
129 uint8_t i2cMstIntEn : 1; // I2C master interrupt
130
131 // --- INT_ENABLE_1 (0x11) ---
132 uint8_t rawDataRdyEn : 1; // Raw data ready
133
134 // --- INT_ENABLE_2 (0x12) --- canal por canal
135 uint8_t fifoOvfEn[5]; // [0]–[4]: 1 = overflow interrupt ON para ese canal
136
137 // --- INT_ENABLE_3 (0x13) --- canal por canal
138 uint8_t fifoWmEn[5]; // [0]–[4]: 1 = watermark interrupt ON para ese canal
139};
140
141/**
142 * ICM20948_IntStatus
143 *
144 * - Holds the parsed state of the four interrupt status registers
145 * - Covers INT_STATUS (0x19), INT_STATUS_1 (0x1A), INT_STATUS_2 (0x1B), INT_STATUS_3 (0x1C)
146 * - Populated by checkIntStatus() via a single 4-byte burst read
147 * - Reading these registers clears the interrupt flags (when clearMode = 0 in IntPinConfig)
148 */
150{
151 // --- INT_STATUS (0x19) ---
152 uint8_t womInt : 1; // Wake on motion ocurrió
153 uint8_t pllRdyInt : 1; // PLL listo
154 uint8_t dmpInt1 : 1; // DMP generó interrupción
155 uint8_t i2cMstInt : 1; // I2C master generó interrupción
156
157 // --- INT_STATUS_1 (0x1A) ---
158 uint8_t rawDataRdy : 1; // Datos de sensores listos para leer
159
160 // --- INT_STATUS_2 (0x1B) ---
161 uint8_t fifoOvf[5]; // [0]–[4]: FIFO overflow por canal
162
163 // --- INT_STATUS_3 (0x1C) ---
164 uint8_t fifoWm[5]; // [0]–[4]: FIFO watermark por canal
165};
166
167/**
168 * Class
169 * - Manages ICM-20948 over I2C (SPI path disabled in this cut)
170 * - Caches scale factors for LSB->physical conversions
171 */
173{
174public:
175
177
178 /**
179 * beginI2C
180 *
181 * - Initialize ICM20948 using I2C interface
182 * - Sets up communication layer (Interface + BusIO)
183 * - Verifies device identity (WHO_AM_I)
184 * - Configures basic power and clock settings
185 *
186 * Returns:
187 * - true → Device initialized successfully
188 * - false → Communication or configuration failed
189 */
190 bool beginI2C(uint8_t address = 0x69, TwoWire &i2cPort = Wire, uint32_t i2cSpeed = 400000);
191
192 bool beginSPI(uint8_t csPin, SPIClass &spiPort = SPI, uint32_t spiSpeed = 1000000);
193
194 /**
195 * readWhoAmI
196 *
197 * - Read WHO_AM_I register (device ID)
198 * - Used during initialization to verify ICM20948
199 * - Expected value: 0xEA
200 *
201 * Returns:
202 * - true → Read successful
203 * - false → Operation failed
204 */
205 bool readWhoAmI(uint8_t &whoAmI);
206
207 /**
208 * selectBank
209 *
210 * - Select USER BANK (0–3)
211 * - Used to access different register groups inside ICM20948
212 *
213 * Returns:
214 * - true → Bank switch successful
215 * - false → Write failed
216 */
217 bool selectBank(uint8_t bank);
218
219 /**
220 * softReset
221 *
222 * - Perform software reset of ICM20948
223 * - Resets all internal registers to default state
224 *
225 * Flow:
226 * - Select USER BANK 0
227 * - Set DEVICE_RESET bit
228 * - Wait for device to restart
229 *
230 * Returns:
231 * - true → Reset successful
232 * - false → Operation failed
233 */
234 bool softReset();
235
236 /**
237 * sleep
238 *
239 * - Enable or disable sleep mode
240 * - Maintains clock source (CLKSEL = 1)
241 *
242 * Flow:
243 * - Select USER BANK 0
244 * - Set or clear SLEEP bit
245 *
246 * Returns:
247 * - true → Operation successful
248 * - false → Operation failed
249 */
250 bool sleep(bool en);
251
252 /**
253 * applyBasicDefaults
254 *
255 * - Apply basic sensor configuration
256 * - Configure power, filters, ranges, and sampling rates
257 *
258 * Returns:
259 * - true → Configuration successful
260 * - false → Any register write failed
261 */
262 bool applyBasicDefaults();
263
264 /**
265 * readAccel
266 *
267 * - Read accelerometer data (X, Y, Z)
268 * - Convert raw values to g using LSB scale
269 *
270 * Returns:
271 * - true → Read successful
272 * - false → Read failed
273 */
274 bool readAccel(float &x, float &y, float &z);
275
276 /**
277 * readGyro
278 *
279 * - Read gyroscope data (X, Y, Z)
280 * - Convert raw values to dps using LSB scale
281 *
282 * Returns:
283 * - true → Read successful
284 * - false → Read failed
285 */
286 bool readGyro(float &x, float &y, float &z);
287
288 /**
289 * readTemperature
290 *
291 * - Read temperature sensor
292 * - Convert raw values to °C
293 *
294 * Returns:
295 * - true → Read successful
296 * - false → Read failed
297 */
298 bool readTemperature(float &temperature);
299
300 /**
301 * readMag
302 *
303 * - Read magnetometer data via internal I2C master
304 * - Data comes from EXT_SLV_SENS_DATA registers
305 * - Convert raw values to µT
306 *
307 * Returns:
308 * - true → Read successful
309 * - false → Read failed
310 */
311 bool readMag(float &x, float &y, float &z);
312
313 /**
314 * initMag
315 *
316 * - Initialize AK09916 magnetometer using internal I2C master
317 * - Verifies WHO_AM_I and enables continuous mode
318 * - Configures SLV0 for automatic data read
319 *
320 * Returns:
321 * - true → Initialization successful
322 * - false → Operation failed
323 */
324 bool initMag();
325
326 /**
327 * setMagOpMode
328 *
329 * - Set magnetometer operation mode
330 *
331 * Returns:
332 * - true → Mode set successfully
333 * - false → Write failed
334 */
335 bool setMagOpMode(ICM20948_Op_Mode opMode);
336
337 /**
338 * setLowPower
339 *
340 * - Enable or disable low power mode
341 * - Controls LP_EN bit in PWR_MGMT_1
342 *
343 * Returns:
344 * - true → Operation successful
345 * - false → Operation failed
346 */
347 bool setLowPower(bool enable);
348
349 /**
350 * getLowPower
351 *
352 * - Read low power mode status
353 * - Returns state of LP_EN bit
354 *
355 * Returns:
356 * - true → Read successful
357 * - false → Operation failed
358 */
359 bool getLowPower(bool &enable);
360
361 /**
362 * setClock
363 *
364 * - Set clock source (CLKSEL [2:0])
365 * - Selects internal clock for sensor operation
366 *
367 * Returns:
368 * - true → Operation successful
369 * - false → Operation failed
370 */
372
373 /**
374 * getClock
375 *
376 * - Read current clock source (CLKSEL [2:0])
377 *
378 * Returns:
379 * - true → Read successful
380 * - false → Operation failed
381 */
382 bool getClock(uint8_t &clock);
383
384 /**
385 * setGyroSampleRate
386 *
387 * - Set gyroscope sample rate
388 * - Uses internal divider (SRD) based on 1100 Hz base rate
389 *
390 * Returns:
391 * - true → Operation successful
392 * - false → Invalid input or write failed
393 */
394 bool setGyroSampleRate(float sampleRate);
395
396 /**
397 * getGyroSampleRate
398 *
399 * - Get current gyroscope sample rate
400 * - Computes value from divider register
401 *
402 * Returns:
403 * - true → Read successful
404 * - false → Operation failed
405 */
406 bool getGyroSampleRate(float &sampleRate);
407 bool setGyroDivRate(uint8_t divisor);
408 /**
409 * setDLPF
410 *
411 * - Configure gyroscope digital low-pass filter (DLPF)
412 * - Option to bypass filter (full bandwidth)
413 *
414 * Returns:
415 * - true → Operation successful
416 * - false → Operation failed
417 */
418 bool setDLPF(ICM20948_Gyro_DLPF dlpf, bool bypass);
419
420 /**
421 * getDLPF
422 *
423 * - Read gyroscope DLPF configuration
424 * - Returns filter setting and bypass state
425 *
426 * Returns:
427 * - true → Read successful
428 * - false → Operation failed
429 */
430 bool getDLPF(uint8_t &dlpf, bool &bypass);
431
432 /**
433 * setGyroScale
434 *
435 * - Set gyroscope full-scale range (FS_SEL)
436 * - Controls sensitivity (dps range)
437 *
438 * Flow:
439 * - Validate bus pointer
440 * - Select USER BANK 2
441 * - Write FS_SEL bits [2:1]
442 *
443 * Returns:
444 * - true → Operation successful
445 * - false → Operation failed
446 */
449 /**
450 * getGyroScale
451 *
452 * - Get current gyroscope full-scale range (FS_SEL
453 *
454 * Returns:
455 * - true → Read successful
456 * - false → Operation failed
457 */
458 bool getGyroScale(uint8_t &fullScale);
459
460 /**
461 * selfTestGyro
462 *
463 * - Enable or disable gyroscope self-test per axis
464 *
465 * Returns:
466 * - true → Operation successful
467 * - false → Operation failed
468 */
469 bool selfTestGyro(bool x, bool y, bool z);
470
471 bool setAccelDivRate(uint16_t divisor);
472 /**
473 * setAccelSampleRate
474 *
475 * - Set accelerometer output data rate (ODR)
476 * - Uses 1125 Hz base rate with 12-bit divider
477 *
478 * Returns:
479 * - true → Operation successful
480 * - false → Operation failed
481 */
482 bool setAccelSampleRate(uint16_t sampleRate);
483
484 /**
485 * getAccelSampleRate
486 *
487 * - Get accelerometer output data rate (ODR)
488 * - Computes value from divider registers
489 *
490 * Returns:
491 * - true → Read successful
492 * - false → Operation failed
493 */
494 bool getAccelSampleRate(float &sampleRate);
495
496 /**
497 * selfTestAccel
498 *
499 * - Enable or disable accelerometer self-test per axis
500 *
501 * Returns:
502 * - true → Operation successful
503 * - false → Operation failed
504 */
505 bool selfTestAccel(bool x, bool y, bool z);
506
507 /**
508 * setAccelScale
509 *
510 * - Set accelerometer full-scale range (FS_SEL)
511 * - Controls measurement range (±2g, ±4g, ±8g, ±16g)
512 *
513 * Returns:
514 * - true → Operation successful
515 * - false → Operation failed
516 */
518
519 /**
520 * getAccelScale
521 *
522 * - Get current accelerometer full-scale range (FS_SEL)
523 *
524 * Returns:
525 * - true → Read successful
526 * - false → Operation failed
527 */
528 bool getAccelScale(uint8_t &fullScale);
529
530 /**
531 * setAccelDLPF
532 *
533 * - Configure accelerometer digital low-pass filter (DLPF)
534 * - Option to bypass filter (full bandwidth)
535 *
536 * Flow:
537 * - Validate bus pointer
538 * - Select USER BANK 2
539 * - Set or clear bypass bit
540 * - Configure DLPF bits if not bypassed
541 *
542 * Returns:
543 * - true → Operation successful
544 * - false → Operation failed
545 */
546 bool setAccelDLPF(uint8_t dlpf, bool bypass);
547
548 /**
549 * getAccelDLPF
550 *
551 * - Read accelerometer DLPF configuration
552 * - Returns filter setting and bypass state
553 *
554 * Flow:
555 * - Validate bus pointer
556 * - Select USER BANK 2
557 * - Read ACCEL_CONFIG register
558 * - Extract bypass and DLPF bits
559 *
560 * Returns:
561 * - true → Read successful
562 * - false → Operation failed
563 */
564 bool getAccelDLPF(uint8_t &dlpf, bool &bypass);
565
566 /**
567 * setAccelAveraging
568 *
569 * - Configure accelerometer averaging / decimation (DEC3)
570 * - Controls internal averaging of accel samples
571 *
572 * Flow:
573 * - Validate bus pointer
574 * - Select USER BANK 2
575 * - Write DEC3 bits [1:0]
576 *
577 * Returns:
578 * - true → Operation successful
579 * - false → Operation failed
580 */
582
583 /**
584 * getAccelAveraging
585 *
586 * - Read accelerometer averaging / decimation setting (DEC3)
587 *
588 * Flow:
589 * - Validate bus pointer
590 * - Select USER BANK 2
591 * - Read DEC3 bits [1:0]
592 *
593 * Returns:
594 * - true → Read successful
595 * - false → Operation failed
596 */
597 bool getAccelAveraging(uint8_t &avg);
598
599 /**
600 * setSensors
601 *
602 * - Enable or disable accel, gyro, and temperature sensor
603 * - Controls power gating via PWR_MGMT_2 and TEMP_DIS
604 *
605 * Flow:
606 * - Validate bus pointer
607 * - Select USER BANK 0
608 * - Build PWR_MGMT_2 mask
609 * - Configure temperature enable/disable
610 *
611 * Returns:
612 * - true → Operation successful
613 * - false → Operation failed
614 */
615 bool setSensors(bool accel_on, bool gyro_on, bool temp_on);
616
617 /**
618 * getSensors
619 *
620 * - Read accel, gyro, and temperature enable state
621 *
622 * Flow:
623 * - Validate bus pointer
624 * - Select USER BANK 0
625 * - Read PWR_MGMT_2 register
626 * - Read TEMP_DIS bit
627 * - Decode enable states
628 *
629 * Returns:
630 * - true → Read successful
631 * - false → Operation failed
632 */
633 bool getSensors(bool &accel_on, bool &gyro_on, bool &temp_on);
634
635 /**
636 * setGyroOffset
637 *
638 * - Set gyroscope offset values for X, Y, Z axes
639 * - Writes offset registers in USER BANK 2
640 *
641 * Flow:
642 * - Validate bus pointer
643 * - Select USER BANK 2
644 * - Pack offsets into byte array
645 * - Write to offset registers
646 *
647 * Returns:
648 * - true → Operation successful
649 * - false → Operation failed
650 */
651 bool setGyroOffset(uint16_t offsetX, uint16_t offsetY, uint16_t offsetZ);
652
653 /**
654 * getGyroOffset
655 *
656 * - Read gyroscope offset values for X, Y, Z axes
657 * - Reads offset registers from USER BANK 2
658 *
659 * Flow:
660 * - Validate bus pointer
661 * - Select USER BANK 2
662 * - Read offset registers
663 * - Convert to signed values
664 *
665 * Returns:
666 * - true → Read successful
667 * - false → Operation failed
668 */
669 bool getGyroOffset(int16_t &offsetX, int16_t &offsetY, int16_t &offsetZ);
670
671 /**
672 * setAccelOffset
673 *
674 * - Set accelerometer offset values for X, Y, Z axes
675 * - Writes offset registers in USER BANK 1
676 *
677 * Flow:
678 * - Validate bus pointer
679 * - Select USER BANK 1
680 * - Pack offsets into byte array
681 * - Write to offset registers
682 *
683 * Returns:
684 * - true → Operation successful
685 * - false → Operation failed
686 */
687 bool setAccelOffset(int16_t offsetX, int16_t offsetY, int16_t offsetZ);
688
689 /**
690 * getAccelOffset
691 *
692 * - Read accelerometer offset values for X, Y, Z axes
693 * - Reads offset registers from USER BANK 1
694 *
695 * Flow:
696 * - Validate bus pointer
697 * - Select USER BANK 1
698 * - Read offset registers
699 * - Convert to signed values
700 *
701 * Returns:
702 * - true → Read successful
703 * - false → Operation failed
704 */
705 bool getAccelOffset(int16_t &offsetX, int16_t &offsetY, int16_t &offsetZ);
706
707 /**
708 * intInit
709 *
710 * - Configure the physical behavior of the INT pin (INT_PIN_CFG register, BANK 0)
711 * - Sets active level, drive mode (push-pull / open-drain), latch vs pulse mode,
712 * clear condition, FSYNC level, FSYNC interrupt enable, and I2C bypass
713 *
714 * Parameters:
715 * - cfg: ICM20948_IntPinConfig struct with the desired pin settings
716 *
717 * Returns:
718 * - true → Configuration written successfully
719 * - false → Operation failed
720 */
721 bool intInit(const ICM20948_IntPinConfig &cfg);
722
723 /**
724 * intEnableConfig
725 *
726 * - Enable or disable individual interrupt sources routed to the INT pin
727 * - Writes INT_ENABLE (0x10), INT_ENABLE_1 (0x11), INT_ENABLE_2 (0x12),
728 * and INT_ENABLE_3 (0x13) in BANK 0
729 * - Must call intInit() first to configure the pin electrical behavior
730 *
731 * Parameters:
732 * - cfg: ICM20948_IntEnableConfig struct with the desired interrupt sources enabled
733 *
734 * Returns:
735 * - true → All four registers written successfully
736 * - false → Operation failed
737 */
739
740 /**
741 * checkIntStatus
742 *
743 * - Read and parse all four interrupt status registers in a single burst read
744 * - Covers INT_STATUS (0x19), INT_STATUS_1 (0x1A), INT_STATUS_2 (0x1B),
745 * INT_STATUS_3 (0x1C) from BANK 0
746 * - Reading clears the interrupt flags when clearMode = 0 in ICM20948_IntPinConfig
747 * - Typically called inside the INT pin ISR or polled in the main loop
748 *
749 * Parameters:
750 * - status: ICM20948_IntStatus struct populated with the current interrupt flags
751 *
752 * Returns:
753 * - true → Status read successfully
754 * - false → Operation failed
755 */
757
758 /**
759 * auxMasterEnable
760 *
761 * - Enable the ICM20948 internal I2C master for auxiliary bus
762 * - Clears BYPASS_EN so the aux bus is controlled by the ICM
763 * - Sets I2C_MST_EN in USER_CTRL
764 * - Configures auxiliary master clock frequency
765 *
766 * Parameters:
767 * - clkFreq: clock divider value (e.g. 0x07 ≈ 345.6 kHz, 0x0D ≈ 400 kHz)
768 *
769 * Returns:
770 * - true → Master enabled successfully
771 * - false → Operation failed
772 */
773 bool auxMasterEnable(uint8_t clkFreq);
774
775 /**
776 * auxWriteByte
777 *
778 * - Write a single byte to a register of an auxiliary I2C slave via SLV4
779 * - Uses one-shot SLV4 transaction: polls SLV4_DONE, checks for NACK
780 * - Suitable for configuration writes (not continuous streaming)
781 *
782 * Parameters:
783 * - slaveAddr: 7-bit I2C address of the auxiliary slave
784 * - reg: target register address on the slave
785 * - data: byte to write
786 *
787 * Returns:
788 * - true → Write acknowledged by slave
789 * - false → Timeout or NACK
790 */
791 bool auxWriteByte(uint8_t slaveAddr, uint8_t reg, uint8_t data);
792
793 /**
794 * auxReadByte
795 *
796 * - Read a single byte from a register of an auxiliary I2C slave via SLV4
797 * - Generates a combined write-then-read transaction (reg byte + repeated START)
798 * - Suitable for slaves that follow standard I2C register-read protocol
799 *
800 * Note: slaves that need separate write/read transactions (e.g. command-response
801 * firmware) should use auxWriteCommand + auxReadResponse instead.
802 *
803 * Parameters:
804 * - slaveAddr: 7-bit I2C address of the auxiliary slave
805 * - reg: register address to read from
806 * - data: output byte received from slave
807 *
808 * Returns:
809 * - true → Read successful
810 * - false → Timeout or NACK
811 */
812 bool auxReadByte(uint8_t slaveAddr, uint8_t reg, uint8_t &data);
813
814 /**
815 * auxWriteCommand
816 *
817 * - Send a single command byte to an auxiliary I2C slave via SLV4
818 * - Uses REG_DIS: generates [START, addr+W, cmd_byte, STOP] with no register prefix
819 * - Designed for slaves that use a command-response protocol (no register addressing)
820 *
821 * Parameters:
822 * - slaveAddr: 7-bit I2C address of the auxiliary slave
823 * - cmd: command byte to send
824 *
825 * Returns:
826 * - true → Command acknowledged by slave
827 * - false → Timeout or NACK
828 */
829 bool auxWriteCommand(uint8_t slaveAddr, uint8_t cmd);
830
831 /**
832 * auxConfigSlave
833 *
834 * - Configure SLV0 for automatic periodic reads from an auxiliary I2C slave
835 * - The ICM20948 master will read numBytes starting at reg on every ODR cycle
836 * - Data is deposited into EXT_SLV_SENS_DATA_00 and subsequent registers
837 * - Call once during initialization; read results with auxReadSensorData
838 *
839 * Parameters:
840 * - slaveAddr: 7-bit I2C address of the auxiliary slave
841 * - reg: starting register address to read from on the slave
842 * - numBytes: number of bytes to read per cycle (1–15)
843 *
844 * Returns:
845 * - true → SLV0 configured successfully
846 * - false → Operation failed
847 */
848 bool auxConfigSlave(uint8_t slaveAddr, uint8_t reg, uint8_t numBytes);
849
850 /**
851 * auxReadSensorData
852 *
853 * - Read bytes from EXT_SLV_SENS_DATA registers (BANK 0)
854 * - Returns data collected by the ICM20948 master from SLV0–SLV3 on the last cycle
855 * - Must call auxConfigSlave first to set up the automatic read
856 *
857 * Parameters:
858 * - buf: output buffer to store the received bytes
859 * - len: number of bytes to read (must match numBytes configured in auxConfigSlave)
860 *
861 * Returns:
862 * - true → Read successful
863 * - false → Bus error
864 */
865 bool auxReadSensorData(uint8_t *buf, uint8_t len);
866
867 /**
868 * auxReadResponse
869 *
870 * - Read a single response byte from an auxiliary I2C slave via SLV4
871 * - Generates a pure read transaction: [START, addr+R, 1 byte, STOP]
872 * - No register byte is sent (REG_DIS); slave must already be ready to transmit
873 * - Use after auxWriteCommand to complete a command-response exchange with slaves
874 * that require separate write and read transactions (e.g. PY32F0 firmware slaves)
875 *
876 * Parameters:
877 * - slaveAddr: 7-bit I2C address of the auxiliary slave
878 * - data: output byte received from slave
879 *
880 * Returns:
881 * - true → Response received successfully
882 * - false → Timeout or NACK
883 */
884 bool auxReadResponse(uint8_t slaveAddr, uint8_t &data);
885
886 /**
887 * auxRead12bit
888 *
889 * - Read a 12-bit value previously configured via auxConfigSlave (SLV0, numBytes = 2)
890 * - Assumes little-endian packing: first byte = LSB, second byte = MSB
891 * - Result is masked to 12 bits (0-4095)
892 *
893 * Returns:
894 * - true → Read successful
895 * - false → Read failed
896 */
897 bool auxRead12bit(uint16_t &raw);
898private:
899 I2C_Interface i2c;
900 SPI_Interface spi;
901
902 Interface_7Semi *iface = nullptr;
903
904 BusIO_7Semi<Interface_7Semi> *bus = nullptr;
905
906 float mg_per_lsb = 16384.0f; // LSB/g at ±16g
907 float degree_per_second = 131.072f; // LSB/dps at ±2000 dps
908
909 bool writeSlave4(uint8_t reg, uint8_t value);
910 bool readSlave4(uint8_t reg, uint8_t &value);
911};
912
913
914#endif /* ICM20948_DEVLAB_H */
ICM20948_Gyro_FullScale
ICM20948_Clock_Source
ICM20948_Accel_DLPFCFG
ICM20948_Gyro_Average
ICM20948_Accel_Average
ICM20948_Accel_FullScale
ICM20948_Gyro_DLPF
ICM20948_Op_Mode
bool readGyro(float &x, float &y, float &z)
bool setMagOpMode(ICM20948_Op_Mode opMode)
bool setDLPF(ICM20948_Gyro_DLPF dlpf, bool bypass)
bool auxWriteByte(uint8_t slaveAddr, uint8_t reg, uint8_t data)
bool setGyroDivRate(uint8_t divisor)
bool setClock(ICM20948_Clock_Source clock)
bool setAccelScale(ICM20948_Accel_FullScale fullScale)
bool auxReadByte(uint8_t slaveAddr, uint8_t reg, uint8_t &data)
bool auxRead12bit(uint16_t &raw)
bool readAccel(float &x, float &y, float &z)
bool intEnableConfig(const ICM20948_IntEnableConfig &cfg)
bool getGyroOffset(int16_t &offsetX, int16_t &offsetY, int16_t &offsetZ)
bool sleep(bool en)
bool beginSPI(uint8_t csPin, SPIClass &spiPort=SPI, uint32_t spiSpeed=1000000)
bool auxReadResponse(uint8_t slaveAddr, uint8_t &data)
bool getGyroScale(uint8_t &fullScale)
bool setAccelAveraging(ICM20948_Accel_Average avg)
bool checkIntStatus(ICM20948_IntStatus &status)
bool setGyroOffset(uint16_t offsetX, uint16_t offsetY, uint16_t offsetZ)
bool setGyroScale(ICM20948_Gyro_FullScale fullScale)
bool setLowPower(bool enable)
bool setGyroSampleRate(float sampleRate)
bool getGyroSampleRate(float &sampleRate)
bool setGyroAveraging(ICM20948_Gyro_Average avg)
bool setAccelOffset(int16_t offsetX, int16_t offsetY, int16_t offsetZ)
bool getSensors(bool &accel_on, bool &gyro_on, bool &temp_on)
bool readWhoAmI(uint8_t &whoAmI)
bool auxReadSensorData(uint8_t *buf, uint8_t len)
bool beginI2C(uint8_t address=0x69, TwoWire &i2cPort=Wire, uint32_t i2cSpeed=400000)
bool getAccelDLPF(uint8_t &dlpf, bool &bypass)
bool getLowPower(bool &enable)
bool selfTestGyro(bool x, bool y, bool z)
bool getAccelSampleRate(float &sampleRate)
bool readMag(float &x, float &y, float &z)
bool readTemperature(float &temperature)
bool selectBank(uint8_t bank)
bool auxMasterEnable(uint8_t clkFreq)
bool intInit(const ICM20948_IntPinConfig &cfg)
bool getDLPF(uint8_t &dlpf, bool &bypass)
bool auxConfigSlave(uint8_t slaveAddr, uint8_t reg, uint8_t numBytes)
bool auxWriteCommand(uint8_t slaveAddr, uint8_t cmd)
bool getClock(uint8_t &clock)
bool setAccelDLPF(uint8_t dlpf, bool bypass)
bool setAccelDivRate(uint16_t divisor)
bool getAccelScale(uint8_t &fullScale)
bool selfTestAccel(bool x, bool y, bool z)
bool getAccelAveraging(uint8_t &avg)
bool getAccelOffset(int16_t &offsetX, int16_t &offsetY, int16_t &offsetZ)
bool setSensors(bool accel_on, bool gyro_on, bool temp_on)
bool setAccelSampleRate(uint16_t sampleRate)