Solaris Software
Loading...
Searching...
No Matches
icm20948.c
Go to the documentation of this file.
1/**
2 * @file icm20948.c
3 * @brief ICM20948 IMU driver + SPP service implementation.
4 *
5 * Implements SPI register access, DMP firmware loading and the full DMP
6 * initialisation sequence. Exposes a single public accessor
7 * (SPP_SERVICES_ICM20948_getProducerContract) so the device can be registered
8 * with the SPP service registry via SPP_SERVICES_PUBSUB_registerProducer().
9 */
10
12
14#include "spp/hal/spi/spi.h"
15#include "spp/hal/gpio/gpio.h"
16#include "spp/hal/time/time.h"
17#include "spp/core/types.h"
23#ifdef SPP_DEBUG_PRINT
24#include <stdio.h>
25#endif
26
27
28#include <string.h>
29#include <math.h>
30
31/* ----------------------------------------------------------------
32 * CONSTANTS
33 * ---------------------------------------------------------------- */
34
35#define K_READ_OP 0x80U /**< SPI read flag — set MSB to signal a read transaction. */
36#define K_WRITE_OP 0x00U /**< SPI write marker (zero). */
37
38#define K_ICM20948_BASE_SAMPLE_RATE 1125L
39#define K_ICM20948_DMP_RUNNING_RATE 225L
40#define K_ICM20948_DMP_DIVIDER (K_ICM20948_BASE_SAMPLE_RATE / K_ICM20948_DMP_RUNNING_RATE)
41#define K_ICM20948_WHO_AM_I_VALUE 0xEAU
42#define K_ICM20948_DMP_PACKET_SIZE_BYTES 42U
43#define K_ICM20948_FIFO_RESET_THRESHOLD 512U
44#define K_ICM20948_DMP_START_ADDR_MSB 0x10U
45#define K_ICM20948_DMP_START_ADDR_LSB 0x00U
46#define K_ICM20948_LOG_TAG "ICM"
47
48/* ----------------------------------------------------------------
49 * PRIVATE TYPES
50 * ---------------------------------------------------------------- */
51
57
58/* ----------------------------------------------------------------
59 * STATIC FUNCTIONS DECLARATIONS
60 * ---------------------------------------------------------------- */
61
63static SPP_RetVal_t SPP_SERVICES_ICM20948_readReg(void *p_spi, spp_uint8_t reg, spp_uint8_t *p_value);
64static SPP_RetVal_t readFifoBurst(void *p_spi, spp_uint8_t *p_dst, spp_uint8_t count);
67static SPP_RetVal_t SPP_SERVICES_ICM20948_dmpWriteBytes(void *p_data, spp_uint16_t addr, const spp_uint8_t *p_bytes,
68 spp_uint8_t len);
73static SPP_RetVal_t ICM20948_dmpWriteOutputConfig(void *p_data, spp_uint16_t outCtl1, spp_uint16_t motionEvent);
80
81/* ----------------------------------------------------------------
82 * VARIABLES
83 * ---------------------------------------------------------------- */
84
85static const spp_uint8_t s_dmp3Image[] = {
86#include "dmpImage.h"
87};
88
90
92 .p_nameProducer = "icm20948",
93 .tiemoutMs = K_ICM20948_TASK_TIMEOUT_MS,
96};
97
98/* ----------------------------------------------------------------
99 * PUBLIC FUNCTIONS
100 * ---------------------------------------------------------------- */
101
102/**
103 * @brief Returns a pointer to the ICM20948 producer contract.
104 * @return Pointer to the static producer contract.
105 */
110
111/* ----------------------------------------------------------------
112 * STATIC FUNCTIONS
113 * ---------------------------------------------------------------- */
114
115/* ----------------------------------------------------------------
116 * Service — init and acquire
117 * ---------------------------------------------------------------- */
118
119/**
120 * @brief Initialises the ICM20948 interrupt context and registers the GPIO ISR.
121 * @param p_icm Pointer to the ICM20948 interrupt context to initialise.
122 */
124{
125 p_icm->drdyFlag = false;
126 p_icm->isr_ctx.p_flag = &p_icm->drdyFlag;
128 SPP_HAL_GPIO_registerIsr(p_icm->intPin, (void *)&p_icm->isr_ctx);
129}
130
131/**
132 * @brief Service init callback — sets hardware config, registers GPIO ISR, loads DMP firmware.
133 * @return K_SPP_OK on success, K_SPP_ERROR on DMP init failure.
134 */
168
169/**
170 * @brief Service acquire callback — reads FIFO data and publishes a packet.
171 *
172 * Called by the service framework on each cycle. Checks the DRDY flag, reads
173 * the DMP FIFO, packs 9-axis sensor data into an SPP packet and publishes it.
174 *
175 * @return K_SPP_OK on success or no data; K_SPP_ERROR if packet allocation or packing fails.
176 */
178{
179 ICM20948_t *p_ctx = &s_icmData;
180
181 if (!p_ctx->icmData.drdyFlag)
182 {
183 return K_SPP_OK;
184 }
185 p_ctx->icmData.drdyFlag = false;
186 p_ctx->lastData.dataReady = false;
187
189
190 if (!p_ctx->lastData.dataReady)
191 {
192 return K_SPP_OK;
193 }
194
196 if (p_pkt1 == NULL)
197 {
198#ifdef SPP_DEBUG_PRINT
199 SPP_LOGI(K_ICM20948_LOG_TAG, "No free packet");
200#endif
201 return K_SPP_ERROR;
202 }
203
205 if (p_pkt2 == NULL)
206 {
207#ifdef SPP_DEBUG_PRINT
208 SPP_LOGI(K_ICM20948_LOG_TAG, "No free packet");
209#endif
210 return K_SPP_ERROR;
211 }
212
213 float payload1[12] = {p_ctx->lastData.ax, p_ctx->lastData.ay, p_ctx->lastData.az, p_ctx->lastData.gx,
214 p_ctx->lastData.gy, p_ctx->lastData.gz, p_ctx->lastData.mx, p_ctx->lastData.my,
215 p_ctx->lastData.mz, p_ctx->lastData.qw, p_ctx->lastData.qx, p_ctx->lastData.qy};
216
217 float payload2[4U] = {p_ctx->lastData.qz, p_ctx->lastData.accuracy};
218#ifdef SPP_DEBUG_PRINT
220 "[ICM] A:[%.2f %.2f %.2f]g G:[%.1f %.1f %.1f]dps M:[%.1f %.1f "
221 "%.1f]uT"
222 " Q:[w=%.3f x=%.3f y=%.3f z=%.3f] ACC:%f\n",
223 p_ctx->lastData.ax, p_ctx->lastData.ay, p_ctx->lastData.az, p_ctx->lastData.gx, p_ctx->lastData.gy,
224 p_ctx->lastData.gz, p_ctx->lastData.mx, p_ctx->lastData.my, p_ctx->lastData.mz, p_ctx->lastData.qw,
225 p_ctx->lastData.qx, p_ctx->lastData.qy, p_ctx->lastData.qz, p_ctx->lastData.accuracy);
226#endif
227
228 SPP_RetVal_t ret =
229 SPP_SERVICES_DATABANK_packetData(p_pkt1, kpid.value, p_ctx->seq++, payload1, (spp_uint16_t)sizeof(payload1));
230 if (ret != K_SPP_OK)
231 {
232 SPP_LOGE(K_ICM20948_LOG_TAG, "packetData failed ret=%d", (int)ret);
234 return ret;
235 }
236
237 SPP_RetVal_t ret2 =
238 SPP_SERVICES_DATABANK_packetData(p_pkt2, kpid.value, p_ctx->seq++, payload2, (spp_uint16_t)sizeof(payload2));
239 if (ret2 != K_SPP_OK)
240 {
241 SPP_LOGE(K_ICM20948_LOG_TAG, "packetData failed ret=%d", (int)ret);
243 return ret;
244 }
245
246
247 //Publish the packet 1 and packet 2
249 (void)SPP_SERVICES_PUBSUB_publish(p_pkt2);
250
251 return K_SPP_OK;
252}
253
254/* ----------------------------------------------------------------
255 * Driver — private helpers
256 * ---------------------------------------------------------------- */
257
258/**
259 * @brief Writes a single byte to an ICM-20948 register over SPI.
260 * @param p_spi SPI device handle.
261 * @param reg Register address.
262 * @param value Value to write.
263 * @return K_SPP_OK on success, K_SPP_ERROR on SPI failure.
264 */
266{
267 spp_uint8_t txBuffer[2] = {K_WRITE_OP | reg, value};
268 return SPP_HAL_SPI_transmit(p_spi, txBuffer, 2U);
269}
270
271/**
272 * @brief Reads a single byte from an ICM-20948 register over SPI.
273 *
274 * The HAL always issues a 3-byte SPI frame for reads (addr + 2 data bytes);
275 * ICM-20948 has no dummy byte so data lands at buf[1]. buf[2] absorbs the
276 * extra byte clocked out — must exist in the array to avoid a stack write.
277 *
278 * @param p_spi SPI device handle.
279 * @param reg Register address.
280 * @param p_value Output: register value (may be NULL to discard).
281 * @return K_SPP_OK on success, K_SPP_ERROR on SPI failure.
282 */
284{
285 spp_uint8_t txRxBuffer[3] = {K_READ_OP | reg, K_WRITE_OP, K_WRITE_OP};
286 SPP_RetVal_t ret = SPP_HAL_SPI_transmit(p_spi, txRxBuffer, 3U);
287
288 if (p_value != NULL)
289 {
290 *p_value = txRxBuffer[1];
291 }
292
293 return ret;
294}
295
296/**
297 * @brief Reads @p count bytes sequentially from the FIFO_R_W register.
298 *
299 * The HAL issues 3-byte read frames (address + 2 data bytes), yielding 2 FIFO
300 * bytes per frame. @p count must be even; K_ICM20948_DMP_PACKET_SIZE_BYTES
301 * satisfies this requirement.
302 *
303 * @param p_spi SPI device handle.
304 * @param p_dst Destination buffer (must be at least @p count bytes).
305 * @param count Number of bytes to read (must be even).
306 * @return K_SPP_OK on success, K_SPP_ERROR on SPI failure.
307 */
308static SPP_RetVal_t readFifoBurst(void *p_spi, spp_uint8_t *p_dst, spp_uint8_t count)
309{
310 spp_uint8_t frame[3];
311 spp_uint8_t i = 0U;
312 while (i < count)
313 {
315 frame[1] = 0U;
316 frame[2] = 0U;
317 SPP_RetVal_t ret = SPP_HAL_SPI_transmit(p_spi, frame, 3U);
318 if (ret != K_SPP_OK)
319 {
320 return ret;
321 }
322 p_dst[i] = frame[1];
323 i++;
324 if (i < count)
325 {
326 p_dst[i] = frame[2];
327 i++;
328 }
329 }
330 return K_SPP_OK;
331}
332
333/**
334 * @brief Selects the active register bank by writing REG_BANK_SEL.
335 * @param p_spi SPI device handle.
336 * @param regBank Target bank (K_ICM20948_REG_BANK_0 … _3).
337 * @return K_SPP_OK on success, K_SPP_ERROR on invalid bank or SPI failure.
338 */
340{
341 ICM20948_RegBankSel_t regBankSel = {.value = 0U};
342
343 switch (regBank)
344 {
346 regBankSel.bits.bankSel = 0U;
347 break;
349 regBankSel.bits.bankSel = 1U;
350 break;
352 regBankSel.bits.bankSel = 2U;
353 break;
355 regBankSel.bits.bankSel = 3U;
356 break;
357 default:
358 return K_SPP_ERROR;
359 }
360
362}
363
364/**
365 * @brief Resets all five FIFO streams by toggling the FIFO_RST bits.
366 * @param p_spi SPI device handle.
367 * @return K_SPP_OK on success, K_SPP_ERROR on SPI failure.
368 */
370{
371 ICM20948_RegFifoRst_t fifoResetReg = {.value = 0U};
372 SPP_RetVal_t ret;
373
374 fifoResetReg.bits.fifoRst0 = 1U;
375 fifoResetReg.bits.fifoRst1 = 1U;
376 fifoResetReg.bits.fifoRst2 = 1U;
377 fifoResetReg.bits.fifoRst3 = 1U;
378 fifoResetReg.bits.fifoRst4 = 1U;
379
381 if (ret != K_SPP_OK)
382 {
383 return ret;
384 }
385
386 fifoResetReg.bits.fifoRst0 = 0U;
387
389}
390
391/**
392 * @brief Writes @p len bytes to DMP memory starting at address @p addr.
393 * @param p_data SPI device handle.
394 * @param addr DMP memory start address.
395 * @param p_bytes Pointer to byte array to write.
396 * @param len Number of bytes to write.
397 * @return K_SPP_OK on success, K_SPP_ERROR_NULL_POINTER or K_SPP_ERROR on failure.
398 */
400 spp_uint8_t len)
401{
402 void *p_spi = p_data;
403 SPP_RetVal_t ret;
404
405 if ((p_spi == NULL) || (p_bytes == NULL))
406 {
408 }
409
410 for (spp_uint8_t i = 0U; i < len; i++)
411 {
413 if (ret != K_SPP_OK)
414 {
415 return ret;
416 }
417
419 if (ret != K_SPP_OK)
420 {
421 return ret;
422 }
423
425 if (ret != K_SPP_OK)
426 {
427 return ret;
428 }
429 }
430
431 return K_SPP_OK;
432}
433
434/**
435 * @brief Writes a 32-bit big-endian value to DMP memory at @p addr.
436 * @param p_data SPI device handle.
437 * @param addr DMP memory address.
438 * @param value 32-bit value to write.
439 * @return K_SPP_OK on success, K_SPP_ERROR on failure.
440 */
442{
443 spp_uint8_t bytes[4] = {(spp_uint8_t)(value >> 24), (spp_uint8_t)(value >> 16), (spp_uint8_t)(value >> 8),
444 (spp_uint8_t)value};
445
446 return SPP_SERVICES_ICM20948_dmpWriteBytes(p_data, addr, bytes, 4U);
447}
448
449/**
450 * @brief Writes a 16-bit big-endian value to DMP memory at @p addr.
451 * @param p_data SPI device handle.
452 * @param addr DMP memory address.
453 * @param value 16-bit value to write.
454 * @return K_SPP_OK on success, K_SPP_ERROR on failure.
455 */
457{
458 spp_uint8_t bytes[2] = {(spp_uint8_t)(value >> 8), (spp_uint8_t)value};
459
460 return SPP_SERVICES_ICM20948_dmpWriteBytes(p_data, addr, bytes, 2U);
461}
462
463/**
464 * @brief Toggles PWR_MGMT_1 into low-power wake-cycle mode then back to normal.
465 * @param p_data SPI device handle.
466 * @return K_SPP_OK on success, K_SPP_ERROR_NULL_POINTER or K_SPP_ERROR on failure.
467 */
469{
470 void *p_spi = p_data;
471 ICM20948_RegPwrMgmt1_t pwrMgmt1Reg = {.value = 0U};
472 SPP_RetVal_t ret;
473
474 if (p_spi == NULL)
475 {
477 }
478
479 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
480 pwrMgmt1Reg.bits.lpEn = 1U;
481
483 if (ret != K_SPP_OK)
484 {
485 return ret;
486 }
487
488 pwrMgmt1Reg.value = 0U;
489 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
490
492}
493
494/**
495 * @brief Computes the DMP gyroscope scale factor from the PLL trim value.
496 * @param pll PLL timebase correction value read from bank 1.
497 * @return Scaled gyroscope scale factor for the DMP.
498 */
500{
501 spp_int32_t t = 102870L + 81L * (spp_int32_t)pll;
502 spp_int32_t a = (1L << 30) / t;
503 spp_int32_t r = (1L << 30) - a * t;
504 spp_int32_t v = a * 797L * K_ICM20948_DMP_DIVIDER;
505
506 v += (spp_int32_t)(((spp_int64_t)a * 1011387LL * K_ICM20948_DMP_DIVIDER) >> 20);
507 v += r * 797L * K_ICM20948_DMP_DIVIDER / t;
508 v += (spp_int32_t)(((spp_int64_t)r * 1011387LL * K_ICM20948_DMP_DIVIDER) >> 20) / t;
509
510 return v << 1;
511}
512
513/**
514 * @brief Programs the DMP output control and motion event registers.
515 * @param p_data SPI device handle.
516 * @param outCtl1 DATA_OUT_CTL1 bitmask (selects sensor outputs).
517 * @param motionEvent MOTION_EVENT_CTL bitmask.
518 * @return K_SPP_OK on success, K_SPP_ERROR on SPI failure.
519 */
520static SPP_RetVal_t ICM20948_dmpWriteOutputConfig(void *p_data, spp_uint16_t outCtl1, spp_uint16_t motionEvent)
521{
522 SPP_RetVal_t ret;
523
525 if (ret != K_SPP_OK)
526 {
527 return ret;
528 }
529
531 if (ret != K_SPP_OK)
532 {
533 return ret;
534 }
535
537 if (ret != K_SPP_OK)
538 {
539 return ret;
540 }
541
543 if (ret != K_SPP_OK)
544 {
545 return ret;
546 }
547
548 return K_SPP_OK;
549}
550
551/* ----------------------------------------------------------------
552 * Driver — DMP firmware load
553 * ---------------------------------------------------------------- */
554
555/**
556 * @brief Loads the DMP3 firmware image into ICM-20948 SRAM.
557 *
558 * Writes s_dmp3Image byte-by-byte starting at K_ICM20948_DMP_LOAD_START,
559 * then primes the SRAM read path with a dummy read transaction.
560 *
561 * @param p_data SPI device handle.
562 * @return K_SPP_OK on success, K_SPP_ERROR_NULL_POINTER or K_SPP_ERROR on failure.
563 */
565{
566 void *p_spi = p_data;
567 const spp_uint8_t *p_firmware = s_dmp3Image;
568 spp_uint16_t firmwareSize = (spp_uint16_t)sizeof(s_dmp3Image);
569 spp_uint16_t done;
570 spp_uint16_t loadAddr;
571 SPP_RetVal_t ret;
572
573 if (p_spi == NULL)
574 {
576 }
577
579 if (ret != K_SPP_OK)
580 {
581 return ret;
582 }
583
584 /* ---- Write: byte-by-byte, MEM_BANK_SEL only on change ---- */
585 spp_uint8_t lastBank = 0xFFU;
586
587 done = 0U;
588 loadAddr = K_ICM20948_DMP_LOAD_START;
589 while (done < firmwareSize)
590 {
591 spp_uint8_t bank = (spp_uint8_t)(loadAddr >> 8);
592 spp_uint8_t offset = (spp_uint8_t)(loadAddr & 0xFFU);
593
594 if (bank != lastBank)
595 {
597 if (ret != K_SPP_OK)
598 {
599 return ret;
600 }
601 lastBank = bank;
602 }
603
605 if (ret != K_SPP_OK)
606 {
607 return ret;
608 }
609 ret = SPP_SERVICES_ICM20948_writeReg(p_spi, K_ICM20948_REG_MEM_R_W, p_firmware[done]);
610 if (ret != K_SPP_OK)
611 {
612 return ret;
613 }
614
615 done++;
616 loadAddr = (spp_uint16_t)(loadAddr + 1U);
617 }
618
619 /* Prime the SRAM read path — the DMP memory controller needs one read transaction
620 * after the write burst before verify reads return correct values. */
621 {
622 spp_uint8_t primeVal = 0U;
626 }
627
628 return K_SPP_OK;
629}
630
631/* ----------------------------------------------------------------
632 * Driver — DMP initialisation
633 * ---------------------------------------------------------------- */
634
635/**
636 * @brief Executes the full DMP initialisation sequence.
637 *
638 * Resets the device, loads DMP firmware, configures gyroscope/accelerometer
639 * full-scale ranges, compass mount matrix, sample-rate dividers and output
640 * data rates, then starts the magnetometer and enables the DMP FIFO.
641 *
642 * @param p_data SPI device handle.
643 * @return K_SPP_OK on success, K_SPP_ERROR on any step failure.
644 */
646{
647 void *p_spi = p_data;
648 SPP_RetVal_t ret;
649 spp_uint8_t whoAmIValue;
650 spp_uint8_t pllRaw;
651 spp_int8_t pllTrim;
652
653 static const ICM20948_DmpMatrixEntry_t s_cpassMatrix[] = {
654 {K_ICM20948_DMP_CPASS_MTX_00, 0x09999999U}, {K_ICM20948_DMP_CPASS_MTX_01, 0x00000000U},
655 {K_ICM20948_DMP_CPASS_MTX_02, 0x00000000U}, {K_ICM20948_DMP_CPASS_MTX_10, 0x00000000U},
656 {K_ICM20948_DMP_CPASS_MTX_11, 0xF6666667U}, {K_ICM20948_DMP_CPASS_MTX_12, 0x00000000U},
657 {K_ICM20948_DMP_CPASS_MTX_20, 0x00000000U}, {K_ICM20948_DMP_CPASS_MTX_21, 0x00000000U},
658 {K_ICM20948_DMP_CPASS_MTX_22, 0xF6666667U}};
659
660 static const ICM20948_DmpMatrixEntry_t s_b2sMatrix[] = {
661 {K_ICM20948_DMP_B2S_MTX_00, 0x40000000U}, {K_ICM20948_DMP_B2S_MTX_01, 0x00000000U},
662 {K_ICM20948_DMP_B2S_MTX_02, 0x00000000U}, {K_ICM20948_DMP_B2S_MTX_10, 0x00000000U},
663 {K_ICM20948_DMP_B2S_MTX_11, 0x40000000U}, {K_ICM20948_DMP_B2S_MTX_12, 0x00000000U},
664 {K_ICM20948_DMP_B2S_MTX_20, 0x00000000U}, {K_ICM20948_DMP_B2S_MTX_21, 0x00000000U},
665 {K_ICM20948_DMP_B2S_MTX_22, 0x40000000U}};
666
667 if (p_spi == NULL)
668 {
670 }
671
673 if (ret != K_SPP_OK)
674 {
675 return ret;
676 }
677
678 ret = SPP_SERVICES_ICM20948_readReg(p_spi, K_ICM20948_REG_WHO_AM_I, &whoAmIValue);
679 if (ret != K_SPP_OK)
680 {
681 return ret;
682 }
683#ifdef SPP_DEBUG_PRINT
684 SPP_LOGI(K_ICM20948_LOG_TAG, "WHO_AM_I = 0x%02X (expect 0xEA)", whoAmIValue);
685#endif
686 if (whoAmIValue != K_ICM20948_WHO_AM_I_VALUE)
687 {
688 return K_SPP_ERROR;
689 }
690
691 {
692 ICM20948_RegPwrMgmt1_t pwrMgmt1Reg = {.value = 0U};
693 ICM20948_RegUserCtrl_t userCtrlReg = {.value = 0U};
694 ICM20948_RegPwrMgmt2_t pwrMgmt2Reg = {.value = 0U};
695 ICM20948_RegLpConf_t lpConfReg = {.value = 0U};
696
697 /* Software reset — chip returns to POR state. */
698 pwrMgmt1Reg.bits.deviceReset = 1U;
700 if (ret != K_SPP_OK)
701 {
702 return ret;
703 }
705
706 /* Wake up, auto clock, LP_EN=0 — required before DMP SRAM is writable. */
707 pwrMgmt1Reg.value = 0U;
708 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
710 if (ret != K_SPP_OK)
711 {
712 return ret;
713 }
714
715 userCtrlReg.bits.i2cIfDis = 1U;
717 if (ret != K_SPP_OK)
718 {
719 return ret;
720 }
721
722 pwrMgmt2Reg.bits.disableAccelX = 1U;
723 pwrMgmt2Reg.bits.disableAccelY = 1U;
724 pwrMgmt2Reg.bits.disableAccelZ = 1U;
725 pwrMgmt2Reg.bits.disableGyroZ = 1U;
727 if (ret != K_SPP_OK)
728 {
729 return ret;
730 }
731
732 lpConfReg.bits.i2cMstCyc = 1U;
734 if (ret != K_SPP_OK)
735 {
736 return ret;
737 }
738
740 if (ret != K_SPP_OK)
741 {
742 return ret;
743 }
744 }
745
746 SPP_LOGI(K_ICM20948_LOG_TAG, "Loading DMP firmware...");
747 ret = SPP_SERVICES_ICM20948_loadDmp(p_data);
748 if (ret != K_SPP_OK)
749 {
750 SPP_LOGE(K_ICM20948_LOG_TAG, "loadDmp failed ret=%d", (int)ret);
751 return ret;
752 }
753 SPP_LOGI(K_ICM20948_LOG_TAG, "DMP loaded OK");
754
756 if (ret != K_SPP_OK)
757 {
758 return ret;
759 }
760
762 if (ret != K_SPP_OK)
763 {
764 return ret;
765 }
766
768 if (ret != K_SPP_OK)
769 {
770 return ret;
771 }
772
774 if (ret != K_SPP_OK)
775 {
776 return ret;
777 }
778
779 ret = ICM20948_dmpWriteOutputConfig(p_data, 0x0000U, 0x0000U);
780 if (ret != K_SPP_OK)
781 {
782 return ret;
783 }
784
786 if (ret != K_SPP_OK)
787 {
788 return ret;
789 }
790
792 if (ret != K_SPP_OK)
793 {
794 return ret;
795 }
796
797 {
798 ICM20948_RegIntEnable_t intEnableReg = {.value = 0U};
799 ICM20948_RegIntEnable2_t intEnable2Reg = {.value = 0U};
800 ICM20948_RegSingleFifoPrioritySel_t fifoPriorityReg = {.value = 0U};
801 ICM20948_RegHwFixDisable_t hwFixDisableReg = {.value = 0U};
802
803 intEnableReg.bits.rawData0Rdy = 1U;
805 if (ret != K_SPP_OK)
806 {
807 return ret;
808 }
809
810 intEnable2Reg.bits.fifoOverflowEn0 = 1U;
812 if (ret != K_SPP_OK)
813 {
814 return ret;
815 }
816
817 fifoPriorityReg.value = 0xE4U;
819 if (ret != K_SPP_OK)
820 {
821 return ret;
822 }
823
824 hwFixDisableReg.value = 0x48U;
826 if (ret != K_SPP_OK)
827 {
828 return ret;
829 }
830 }
831
833 if (ret != K_SPP_OK)
834 {
835 return ret;
836 }
837
839 if (ret != K_SPP_OK)
840 {
841 return ret;
842 }
843
845 if (ret != K_SPP_OK)
846 {
847 return ret;
848 }
849
851 if (ret != K_SPP_OK)
852 {
853 return ret;
854 }
855
857 if (ret != K_SPP_OK)
858 {
859 return ret;
860 }
861
863 if (ret != K_SPP_OK)
864 {
865 return ret;
866 }
867
869 if (ret != K_SPP_OK)
870 {
871 return ret;
872 }
873
874 {
875 ICM20948_RegFifoCfg_t fifoCfgReg = {.value = 0U};
876 ICM20948_RegFifoEn1_t fifoEn1Reg = {.value = 0U};
877 ICM20948_RegFifoEn2_t fifoEn2Reg = {.value = 0U};
878
880 if (ret != K_SPP_OK)
881 {
882 return ret;
883 }
884
886 if (ret != K_SPP_OK)
887 {
888 return ret;
889 }
890
892 if (ret != K_SPP_OK)
893 {
894 return ret;
895 }
896
898 if (ret != K_SPP_OK)
899 {
900 return ret;
901 }
902 }
903
904 {
905 ICM20948_RegPwrMgmt1_t pwrMgmt1Reg = {.value = 0U};
906 ICM20948_RegPwrMgmt2_t pwrMgmt2Reg = {.value = 0U};
907
908 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
909 pwrMgmt1Reg.bits.lpEn = 1U;
911 if (ret != K_SPP_OK)
912 {
913 return ret;
914 }
915
916 pwrMgmt2Reg.value = 0x7FU;
918 if (ret != K_SPP_OK)
919 {
920 return ret;
921 }
922
923 pwrMgmt1Reg.bits.sleep = 1U;
925 if (ret != K_SPP_OK)
926 {
927 return ret;
928 }
929
931
932 pwrMgmt1Reg.value = 0U;
933 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
934 pwrMgmt1Reg.bits.lpEn = 1U;
936 if (ret != K_SPP_OK)
937 {
938 return ret;
939 }
940
942
943 pwrMgmt1Reg.value = 0U;
944 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
946 if (ret != K_SPP_OK)
947 {
948 return ret;
949 }
950
952 }
953
954 /* AK09916 magnetometer: soft-reset */
956 if (ret != K_SPP_OK)
957 {
958 return ret;
959 }
960
961 SPP_LOGI(K_ICM20948_LOG_TAG, "Phase: mag soft-reset");
963 if (ret != K_SPP_OK)
964 {
965 return ret;
966 }
967
969 if (ret != K_SPP_OK)
970 {
971 return ret;
972 }
973
974 ret = SPP_SERVICES_ICM20948_writeReg(p_spi, 0x0DU, 0x00U);
975 if (ret != K_SPP_OK)
976 {
977 return ret;
978 }
979
980 ret = SPP_SERVICES_ICM20948_writeReg(p_spi, 0x11U, 0x00U);
981 if (ret != K_SPP_OK)
982 {
983 return ret;
984 }
985
987 if (ret != K_SPP_OK)
988 {
989 return ret;
990 }
991
993 if (ret != K_SPP_OK)
994 {
995 return ret;
996 }
997
999 if (ret != K_SPP_OK)
1000 {
1001 return ret;
1002 }
1003
1005 if (ret != K_SPP_OK)
1006 {
1007 return ret;
1008 }
1009
1011 if (ret != K_SPP_OK)
1012 {
1013 return ret;
1014 }
1015
1017 if (ret != K_SPP_OK)
1018 {
1019 return ret;
1020 }
1021
1023 if (ret != K_SPP_OK)
1024 {
1025 return ret;
1026 }
1027
1028 {
1029 ICM20948_RegUserCtrl_t userCtrlReg = {.value = 0U};
1030
1031 userCtrlReg.bits.i2cIfDis = 1U;
1032 userCtrlReg.bits.i2cMstEn = 1U;
1034 if (ret != K_SPP_OK)
1035 {
1036 return ret;
1037 }
1038
1040
1041 userCtrlReg.value = 0U;
1042 userCtrlReg.bits.i2cIfDis = 1U;
1044 if (ret != K_SPP_OK)
1045 {
1046 return ret;
1047 }
1048 }
1049
1051 if (ret != K_SPP_OK)
1052 {
1053 return ret;
1054 }
1055
1057 if (ret != K_SPP_OK)
1058 {
1059 return ret;
1060 }
1061
1063 if (ret != K_SPP_OK)
1064 {
1065 return ret;
1066 }
1067
1069 if (ret != K_SPP_OK)
1070 {
1071 return ret;
1072 }
1073
1074 {
1075 ICM20948_RegUserCtrl_t userCtrlReg = {.value = 0U};
1076
1077 userCtrlReg.bits.i2cIfDis = 1U;
1079 if (ret != K_SPP_OK)
1080 {
1081 return ret;
1082 }
1083 }
1084
1085 SPP_LOGI(K_ICM20948_LOG_TAG, "Phase: cpass+b2s matrix");
1086 for (spp_uint8_t i = 0U; i < (sizeof(s_cpassMatrix) / sizeof(s_cpassMatrix[0])); i++)
1087 {
1088 ret = SPP_SERVICES_ICM20948_dmpWrite32(p_data, s_cpassMatrix[i].addr, s_cpassMatrix[i].val);
1089 if (ret != K_SPP_OK)
1090 {
1091 return ret;
1092 }
1093
1095 if (ret != K_SPP_OK)
1096 {
1097 return ret;
1098 }
1099 }
1100
1102
1103 for (spp_uint8_t i = 0U; i < (sizeof(s_b2sMatrix) / sizeof(s_b2sMatrix[0])); i++)
1104 {
1105 ret = SPP_SERVICES_ICM20948_dmpWrite32(p_data, s_b2sMatrix[i].addr, s_b2sMatrix[i].val);
1106 if (ret != K_SPP_OK)
1107 {
1108 return ret;
1109 }
1110
1112 if (ret != K_SPP_OK)
1113 {
1114 return ret;
1115 }
1116 }
1117
1119
1121 if (ret != K_SPP_OK)
1122 {
1123 return ret;
1124 }
1125
1126 {
1127 ICM20948_RegAccelConfig_t accelConfigReg = {.value = 0U};
1128 ICM20948_RegAccelConfig2_t accelConfig2Reg = {.value = 0U};
1129
1130 accelConfigReg.bits.accelFsSel = K_ICM20948_ACCEL_FS_4G;
1132 if (ret != K_SPP_OK)
1133 {
1134 return ret;
1135 }
1136
1138 if (ret != K_SPP_OK)
1139 {
1140 return ret;
1141 }
1142 }
1143
1145 if (ret != K_SPP_OK)
1146 {
1147 return ret;
1148 }
1149
1151 if (ret != K_SPP_OK)
1152 {
1153 return ret;
1154 }
1155
1157 if (ret != K_SPP_OK)
1158 {
1159 return ret;
1160 }
1161
1163 if (ret != K_SPP_OK)
1164 {
1165 return ret;
1166 }
1167
1169 if (ret != K_SPP_OK)
1170 {
1171 return ret;
1172 }
1173
1175 if (ret != K_SPP_OK)
1176 {
1177 return ret;
1178 }
1179
1180 {
1181 ICM20948_RegGyroConfig_t gyroConfigReg = {.value = 0U};
1182
1183 gyroConfigReg.bits.gyroFchoice = 1U;
1184 gyroConfigReg.bits.gyroFsSel = K_ICM20948_GYRO_FS_2000DPS;
1186 if (ret != K_SPP_OK)
1187 {
1188 return ret;
1189 }
1190
1191 ret = SPP_SERVICES_ICM20948_writeReg(p_spi, 0x02U, 0x00U);
1192 if (ret != K_SPP_OK)
1193 {
1194 return ret;
1195 }
1196 }
1197
1199 if (ret != K_SPP_OK)
1200 {
1201 return ret;
1202 }
1203
1205 if (ret != K_SPP_OK)
1206 {
1207 return ret;
1208 }
1209
1211 if (ret != K_SPP_OK)
1212 {
1213 return ret;
1214 }
1215
1217 if (ret != K_SPP_OK)
1218 {
1219 return ret;
1220 }
1221
1223 if (ret != K_SPP_OK)
1224 {
1225 return ret;
1226 }
1227
1229 if (ret != K_SPP_OK)
1230 {
1231 return ret;
1232 }
1233
1234 pllTrim = (spp_int8_t)pllRaw;
1235
1237 if (ret != K_SPP_OK)
1238 {
1239 return ret;
1240 }
1241
1243 if (ret != K_SPP_OK)
1244 {
1245 return ret;
1246 }
1247
1250 if (ret != K_SPP_OK)
1251 {
1252 return ret;
1253 }
1254
1256 if (ret != K_SPP_OK)
1257 {
1258 return ret;
1259 }
1260
1261 {
1262 ICM20948_RegLpConf_t lpConfReg = {.value = 0U};
1263 ICM20948_RegPwrMgmt1_t pwrMgmt1Reg = {.value = 0U};
1264
1265 lpConfReg.bits.i2cMstCyc = 1U;
1267 if (ret != K_SPP_OK)
1268 {
1269 return ret;
1270 }
1271
1272 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
1274 if (ret != K_SPP_OK)
1275 {
1276 return ret;
1277 }
1278 }
1279
1280 SPP_LOGI(K_ICM20948_LOG_TAG, "Phase: 3-seq DMP enable loop");
1281 for (spp_uint8_t seq = 0U; seq < 3U; seq++)
1282 {
1283 ICM20948_RegUserCtrl_t userCtrlReg = {.value = 0U};
1284 ICM20948_RegPwrMgmt2_t pwrMgmt2Reg = {.value = 0U};
1285 ICM20948_RegPwrMgmt1_t pwrMgmt1Reg = {.value = 0U};
1286
1287 if (seq == 0U)
1288 {
1289 userCtrlReg.bits.i2cIfDis = 1U;
1290 }
1291 else
1292 {
1293 /* 0xD0 = DMP_EN + FIFO_EN + I2C_IF_DIS; I2C master not yet enabled here. */
1294 userCtrlReg.bits.i2cIfDis = 1U;
1295 userCtrlReg.bits.fifoEn = 1U;
1296 userCtrlReg.bits.dmpEn = 1U;
1297 }
1298
1300 if (ret != K_SPP_OK)
1301 {
1302 return ret;
1303 }
1304
1305 pwrMgmt2Reg.value = 0x47U;
1307 if (ret != K_SPP_OK)
1308 {
1309 return ret;
1310 }
1311
1312 /* Second write: same 0xD0 value. */
1313 userCtrlReg.value = 0U;
1314 userCtrlReg.bits.i2cIfDis = 1U;
1315 userCtrlReg.bits.fifoEn = 1U;
1316 userCtrlReg.bits.dmpEn = 1U;
1318 if (ret != K_SPP_OK)
1319 {
1320 return ret;
1321 }
1322
1323 ret = ICM20948_dmpWriteOutputConfig(p_data, 0x0000U, 0x0000U);
1324 if (ret != K_SPP_OK)
1325 {
1326 return ret;
1327 }
1328
1329 if (seq < 2U)
1330 {
1331 pwrMgmt2Reg.value = 0x7FU;
1333 if (ret != K_SPP_OK)
1334 {
1335 return ret;
1336 }
1337
1338 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
1339 pwrMgmt1Reg.bits.sleep = 1U;
1341 if (ret != K_SPP_OK)
1342 {
1343 return ret;
1344 }
1345
1347
1348 pwrMgmt1Reg.value = 0U;
1349 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
1351 if (ret != K_SPP_OK)
1352 {
1353 return ret;
1354 }
1355
1357 if (ret != K_SPP_OK)
1358 {
1359 return ret;
1360 }
1361
1363 if (ret != K_SPP_OK)
1364 {
1365 return ret;
1366 }
1367
1369 if (ret != K_SPP_OK)
1370 {
1371 return ret;
1372 }
1373 }
1374 }
1375
1376 SPP_LOGI(K_ICM20948_LOG_TAG, "Phase: final output config + mag start");
1377 ret = ICM20948_dmpWriteOutputConfig(p_data, 0xE400U, 0x03C0U);
1378 if (ret != K_SPP_OK)
1379 {
1380 return ret;
1381 }
1382
1384 if (ret != K_SPP_OK)
1385 {
1386 return ret;
1387 }
1388
1390 if (ret != K_SPP_OK)
1391 {
1392 return ret;
1393 }
1394
1396 if (ret != K_SPP_OK)
1397 {
1398 return ret;
1399 }
1400
1402 if (ret != K_SPP_OK)
1403 {
1404 return ret;
1405 }
1406
1408 if (ret != K_SPP_OK)
1409 {
1410 return ret;
1411 }
1412
1414 if (ret != K_SPP_OK)
1415 {
1416 return ret;
1417 }
1418
1420 if (ret != K_SPP_OK)
1421 {
1422 return ret;
1423 }
1424
1426 if (ret != K_SPP_OK)
1427 {
1428 return ret;
1429 }
1430
1432 if (ret != K_SPP_OK)
1433 {
1434 return ret;
1435 }
1436
1438 if (ret != K_SPP_OK)
1439 {
1440 return ret;
1441 }
1442
1444 if (ret != K_SPP_OK)
1445 {
1446 return ret;
1447 }
1448
1450 if (ret != K_SPP_OK)
1451 {
1452 return ret;
1453 }
1454
1456 if (ret != K_SPP_OK)
1457 {
1458 return ret;
1459 }
1460
1462 if (ret != K_SPP_OK)
1463 {
1464 return ret;
1465 }
1466
1468 if (ret != K_SPP_OK)
1469 {
1470 return ret;
1471 }
1472
1475 if (ret != K_SPP_OK)
1476 {
1477 return ret;
1478 }
1479
1480 {
1481 ICM20948_RegPwrMgmt2_t pwrMgmt2Reg = {.value = 0U};
1482
1483 pwrMgmt2Reg.value = 0x40U;
1485 if (ret != K_SPP_OK)
1486 {
1487 return ret;
1488 }
1489 }
1490
1492 if (ret != K_SPP_OK)
1493 {
1494 return ret;
1495 }
1496
1498 if (ret != K_SPP_OK)
1499 {
1500 return ret;
1501 }
1502
1504 if (ret != K_SPP_OK)
1505 {
1506 return ret;
1507 }
1508
1510 if (ret != K_SPP_OK)
1511 {
1512 return ret;
1513 }
1514
1516 if (ret != K_SPP_OK)
1517 {
1518 return ret;
1519 }
1520
1522 if (ret != K_SPP_OK)
1523 {
1524 return ret;
1525 }
1526
1528 if (ret != K_SPP_OK)
1529 {
1530 return ret;
1531 }
1532
1534 if (ret != K_SPP_OK)
1535 {
1536 return ret;
1537 }
1538
1540 if (ret != K_SPP_OK)
1541 {
1542 return ret;
1543 }
1544
1546 if (ret != K_SPP_OK)
1547 {
1548 return ret;
1549 }
1550
1552 if (ret != K_SPP_OK)
1553 {
1554 return ret;
1555 }
1556
1557 {
1558 ICM20948_RegUserCtrl_t userCtrlReg = {.value = 0U};
1559
1560 userCtrlReg.bits.i2cIfDis = 1U;
1561 userCtrlReg.bits.i2cMstEn = 1U;
1562 userCtrlReg.bits.fifoEn = 1U;
1563 userCtrlReg.bits.dmpEn = 1U;
1565 if (ret != K_SPP_OK)
1566 {
1567 return ret;
1568 }
1569
1570 userCtrlReg.bits.dmpRst = 1U;
1572 if (ret != K_SPP_OK)
1573 {
1574 return ret;
1575 }
1576 }
1577
1579
1581 if (ret != K_SPP_OK)
1582 {
1583 return ret;
1584 }
1585
1586 {
1587 ICM20948_RegPwrMgmt1_t pwrMgmt1Reg = {.value = 0U};
1588
1589 pwrMgmt1Reg.bits.clkSel = K_ICM20948_CLK_AUTO;
1590 pwrMgmt1Reg.bits.lpEn = 1U;
1592 if (ret != K_SPP_OK)
1593 {
1594 return ret;
1595 }
1596 }
1597
1598 ret = ICM20948_dmpWriteOutputConfig(p_data, 0xE400U, 0x03C0U);
1599 if (ret != K_SPP_OK)
1600 {
1601 return ret;
1602 }
1603
1605 if (ret != K_SPP_OK)
1606 {
1607 return ret;
1608 }
1609
1611 if (ret != K_SPP_OK)
1612 {
1613 return ret;
1614 }
1615
1616 return K_SPP_OK;
1617}
1618
1619/* ----------------------------------------------------------------
1620 * Driver — FIFO and sensor data
1621 * ---------------------------------------------------------------- */
1622
1623/**
1624 * @brief Reads and parses DMP FIFO packets, updating the sensor data fields.
1625 *
1626 * Checks INT_STATUS for a raw-data-ready flag, reads the FIFO count, and
1627 * processes each complete DMP packet. Resets the FIFO if the count exceeds
1628 * K_ICM20948_FIFO_RESET_THRESHOLD.
1629 *
1630 * @param p_ctx Pointer to the ICM20948 driver context.
1631 */
1633{
1634 void *p_spi = p_ctx->p_spi;
1635 spp_uint8_t txRxData[3] = {0U};
1636 SPP_RetVal_t ret;
1637
1638 if (p_spi == NULL)
1639 {
1640 return;
1641 }
1642
1643 txRxData[0] = K_READ_OP | K_ICM20948_REG_INT_STATUS;
1644 txRxData[1] = K_WRITE_OP;
1645 txRxData[2] = K_WRITE_OP;
1646
1647 ret = SPP_HAL_SPI_transmit(p_spi, txRxData, 3U);
1648 if (ret != K_SPP_OK)
1649 {
1650 return;
1651 }
1652
1653 {
1654 spp_uint8_t intStatus = txRxData[1];
1655
1657 txRxData[1] = K_WRITE_OP;
1658 txRxData[2] = K_WRITE_OP;
1659
1660 ret = SPP_HAL_SPI_transmit(p_spi, txRxData, 3U);
1661 if (ret != K_SPP_OK)
1662 {
1663 return;
1664 }
1665
1666 if ((intStatus & 0x02U) != 0U)
1667 {
1668 txRxData[0] = K_READ_OP | K_ICM20948_REG_FIFO_COUNTH;
1669 txRxData[1] = K_WRITE_OP;
1670 txRxData[2] = K_WRITE_OP;
1671
1672 ret = SPP_HAL_SPI_transmit(p_spi, txRxData, 3U);
1673 if (ret != K_SPP_OK)
1674 {
1675 return;
1676 }
1677
1678 {
1679 spp_uint16_t fifoCount = ((spp_uint16_t)txRxData[1] << 8) | txRxData[2];
1680
1681 {
1682 static spp_bool_t s_logged = false;
1683 if (!s_logged)
1684 {
1685 SPP_LOGI(K_ICM20948_LOG_TAG, "FIFO first count=%u pktsz=%u", (unsigned)fifoCount,
1687 s_logged = true;
1688 }
1689 }
1690
1691 if (fifoCount > K_ICM20948_FIFO_RESET_THRESHOLD)
1692 {
1694 return;
1695 }
1696
1697 {
1698 spp_uint16_t numPackets = fifoCount / K_ICM20948_DMP_PACKET_SIZE_BYTES;
1699
1700 for (spp_uint16_t i = 0U; i < numPackets; i++)
1701 {
1702 /* fifoBuffer[0..23]: DMP packet (DATA_OUT_CTL1=0x8400).
1703 * [0-1]=header1, [2-7]=accel, [8-21]=quat9, [22-23]=footer. */
1705
1706 ret = readFifoBurst(p_spi, fifoBuffer, K_ICM20948_DMP_PACKET_SIZE_BYTES);
1707 if (ret != K_SPP_OK)
1708 {
1709 return;
1710 }
1711
1712 if (i == 0U)
1713 {
1714 static spp_bool_t s_hdrLogged = false;
1715 if (!s_hdrLogged)
1716 {
1717 SPP_LOGI(K_ICM20948_LOG_TAG, "DMP hdr=%02X%02X accel=%02X%02X quat=%02X%02X",
1718 fifoBuffer[0], fifoBuffer[1], fifoBuffer[2], fifoBuffer[3], fifoBuffer[8],
1719 fifoBuffer[9]);
1720 s_hdrLogged = true;
1721 }
1722 }
1723
1724 {
1725 /* [0:1]=header1, [2:7]=accel, [8:13]=gyro_raw, [14:19]=gyro_bias(discard),
1726 * [20:25]=compass, [26:37]=quat9(Q1,Q2,Q3), [38:39]=heading_acc, [40:41]=footer */
1727
1728 spp_int16_t accelX = (spp_int16_t)(((spp_uint16_t)fifoBuffer[2] << 8) | fifoBuffer[3]);
1729 spp_int16_t accelY = (spp_int16_t)(((spp_uint16_t)fifoBuffer[4] << 8) | fifoBuffer[5]);
1730 spp_int16_t accelZ = (spp_int16_t)(((spp_uint16_t)fifoBuffer[6] << 8) | fifoBuffer[7]);
1731
1732 spp_int16_t gyroX = (spp_int16_t)(((spp_uint16_t)fifoBuffer[8] << 8) | fifoBuffer[9]);
1733 spp_int16_t gyroY = (spp_int16_t)(((spp_uint16_t)fifoBuffer[10] << 8) | fifoBuffer[11]);
1734 spp_int16_t gyroZ = (spp_int16_t)(((spp_uint16_t)fifoBuffer[12] << 8) | fifoBuffer[13]);
1735 /* [14:19] gyro bias — ignored */
1736
1737 spp_int16_t magX = (spp_int16_t)(((spp_uint16_t)fifoBuffer[20] << 8) | fifoBuffer[21]);
1738 spp_int16_t magY = (spp_int16_t)(((spp_uint16_t)fifoBuffer[22] << 8) | fifoBuffer[23]);
1739 spp_int16_t magZ = (spp_int16_t)(((spp_uint16_t)fifoBuffer[24] << 8) | fifoBuffer[25]);
1740
1741 spp_int32_t q1Raw = ((spp_int32_t)fifoBuffer[26] << 24) |
1742 ((spp_int32_t)fifoBuffer[27] << 16) |
1743 ((spp_int32_t)fifoBuffer[28] << 8) | (spp_int32_t)fifoBuffer[29];
1744 spp_int32_t q2Raw = ((spp_int32_t)fifoBuffer[30] << 24) |
1745 ((spp_int32_t)fifoBuffer[31] << 16) |
1746 ((spp_int32_t)fifoBuffer[32] << 8) | (spp_int32_t)fifoBuffer[33];
1747 spp_int32_t q3Raw = ((spp_int32_t)fifoBuffer[34] << 24) |
1748 ((spp_int32_t)fifoBuffer[35] << 16) |
1749 ((spp_int32_t)fifoBuffer[36] << 8) | (spp_int32_t)fifoBuffer[37];
1750 float accuracy = (spp_int16_t)(((spp_uint16_t)fifoBuffer[38] << 8) | fifoBuffer[39]);
1751
1752 float ax = accelX / 8192.0f;
1753 float ay = accelY / 8192.0f;
1754 float az = accelZ / 8192.0f;
1755 float gx = gyroX / 32.8f;
1756 float gy = gyroY / 32.8f;
1757 float gz = gyroZ / 32.8f;
1758 float mx = magX * 0.15f;
1759 float my = magY * 0.15f;
1760 float mz = magZ * 0.15f;
1761 float qx = q1Raw / 1073741824.0f;
1762 float qy = q2Raw / 1073741824.0f;
1763 float qz = q3Raw / 1073741824.0f;
1764 float qwSq = 1.0f - (qx * qx) - (qy * qy) - (qz * qz);
1765 float qw = (qwSq > 0.0f) ? sqrtf(qwSq) : 0.0f;
1766
1767 p_ctx->lastData.ax = ax;
1768 p_ctx->lastData.ay = ay;
1769 p_ctx->lastData.az = az;
1770 p_ctx->lastData.gx = gx;
1771 p_ctx->lastData.gy = gy;
1772 p_ctx->lastData.gz = gz;
1773 p_ctx->lastData.mx = mx;
1774 p_ctx->lastData.my = my;
1775 p_ctx->lastData.mz = mz;
1776 p_ctx->lastData.qw = qw;
1777 p_ctx->lastData.qx = qx;
1778 p_ctx->lastData.qy = qy;
1779 p_ctx->lastData.qz = qz;
1780 p_ctx->lastData.accuracy = accuracy;
1781 p_ctx->lastData.dataReady = true;
1782 }
1783 }
1784 }
1785 }
1786 }
1787 }
1788}
SPP_Packet_t * SPP_SERVICES_DATABANK_getPacket(void)
Acquire a free packet from the pool.
Definition databank.c:53
SPP_RetVal_t SPP_SERVICES_DATABANK_returnPacket(SPP_Packet_t *p_packet)
Return a packet to the pool after processing.
Definition databank.c:64
SPP_RetVal_t SPP_SERVICES_DATABANK_packetData(SPP_Packet_t *p_packet, spp_uint16_t apid, spp_uint16_t seq, const void *p_data, spp_uint16_t dataLen)
Fill a packet with data and compute its CRC.
Definition databank.c:117
Static packet pool manager.
spp_uint16_t * SPP_CORE_FSM_getErrorsBit(void)
Get the pointer to the FSM errors bit.
Definition fsm.c:33
Finite State Machine (FSM) module for the SPP core.
SPP_RetVal_t SPP_HAL_GPIO_registerIsr(spp_uint32_t pin, void *p_isrCtx)
Register an ISR handler for a GPIO pin.
Definition gpio.c:39
SPP_RetVal_t SPP_HAL_GPIO_configInterrupt(spp_uint32_t pin, spp_uint32_t intrType, spp_uint32_t pull)
Configure a GPIO pin as an interrupt input.
Definition gpio.c:19
SPP GPIO HAL API — dispatches through the registered HAL port.
#define K_ICM20948_FIFO_RESET_THRESHOLD
Definition icm20948.c:43
#define K_ICM20948_DMP_START_ADDR_MSB
Definition icm20948.c:44
static SPP_RetVal_t readFifoBurst(void *p_spi, spp_uint8_t *p_dst, spp_uint8_t count)
Reads count bytes sequentially from the FIFO_R_W register.
Definition icm20948.c:308
#define K_READ_OP
Definition icm20948.c:35
#define K_ICM20948_WHO_AM_I_VALUE
Definition icm20948.c:41
static spp_int32_t SPP_SERVICES_ICM20948_calcGyroSf(spp_int8_t pll)
Computes the DMP gyroscope scale factor from the PLL trim value.
Definition icm20948.c:499
static SPP_RetVal_t SPP_SERVICES_ICM20948_lpWakeCycle(void *p_data)
Toggles PWR_MGMT_1 into low-power wake-cycle mode then back to normal.
Definition icm20948.c:468
static SPP_RetVal_t SPP_SERVICES_ICM20948_readReg(void *p_spi, spp_uint8_t reg, spp_uint8_t *p_value)
Reads a single byte from an ICM-20948 register over SPI.
Definition icm20948.c:283
static SPP_RetVal_t SPP_SERVICES_ICM20948_dmpWrite32(void *p_data, spp_uint16_t addr, spp_uint32_t value)
Writes a 32-bit big-endian value to DMP memory at addr.
Definition icm20948.c:441
#define K_ICM20948_LOG_TAG
Definition icm20948.c:46
static const spp_uint8_t s_dmp3Image[]
Definition icm20948.c:85
static void SPP_SERVICES_ICM20948_initGpio(ICM20948_Data_t *p_icm)
Initialises the ICM20948 interrupt context and registers the GPIO ISR.
Definition icm20948.c:123
static SPP_RetVal_t SPP_SERVICES_ICM20948_configDmpInit(void *p_data)
Executes the full DMP initialisation sequence.
Definition icm20948.c:645
const SPP_SERVICE_ProducerContract_t * SPP_SERVICES_ICM20948_getProducerContract(void)
Returns a pointer to the ICM20948 producer contract.
Definition icm20948.c:106
static SPP_RetVal_t SPP_SERVICES_ICM20948_init(void)
Service init callback — sets hardware config, registers GPIO ISR, loads DMP firmware.
Definition icm20948.c:135
#define K_ICM20948_DMP_PACKET_SIZE_BYTES
Definition icm20948.c:42
static SPP_RetVal_t SPP_SERVICES_ICM20948_writeReg(void *p_spi, spp_uint8_t reg, spp_uint8_t value)
Writes a single byte to an ICM-20948 register over SPI.
Definition icm20948.c:265
#define K_WRITE_OP
Definition icm20948.c:36
static void SPP_SERVICES_ICM20948_checkFifoData(ICM20948_t *p_ctx)
Reads and parses DMP FIFO packets, updating the sensor data fields.
Definition icm20948.c:1632
static SPP_RetVal_t SPP_SERVICES_ICM20948_loadDmp(void *p_data)
Loads the DMP3 firmware image into ICM-20948 SRAM.
Definition icm20948.c:564
static SPP_RetVal_t SPP_SERVICES_ICM20948_dmpWrite16(void *p_data, spp_uint16_t addr, spp_uint16_t value)
Writes a 16-bit big-endian value to DMP memory at addr.
Definition icm20948.c:456
static SPP_RetVal_t SPP_SERVICES_ICM20948_dmpWriteBytes(void *p_data, spp_uint16_t addr, const spp_uint8_t *p_bytes, spp_uint8_t len)
Writes len bytes to DMP memory starting at address addr.
Definition icm20948.c:399
static ICM20948_t s_icmData
Definition icm20948.c:89
static const SPP_SERVICE_ProducerContract_t s_icm20948ProducerContract
Definition icm20948.c:91
#define K_ICM20948_DMP_DIVIDER
Definition icm20948.c:40
static SPP_RetVal_t SPP_SERVICES_ICM20948_resetFifo(void *p_spi)
Resets all five FIFO streams by toggling the FIFO_RST bits.
Definition icm20948.c:369
static SPP_RetVal_t SPP_SERVICES_ICM20948_setBank(void *p_spi, ICM20948_RegBank_t regBank)
Selects the active register bank by writing REG_BANK_SEL.
Definition icm20948.c:339
static SPP_RetVal_t SPP_SERVICES_ICM20948_acquireData(SPP_Kpid_t kpid)
Service acquire callback — reads FIFO data and publishes a packet.
Definition icm20948.c:177
#define K_ICM20948_DMP_START_ADDR_LSB
Definition icm20948.c:45
static SPP_RetVal_t ICM20948_dmpWriteOutputConfig(void *p_data, spp_uint16_t outCtl1, spp_uint16_t motionEvent)
Programs the DMP output control and motion event registers.
Definition icm20948.c:520
ICM20948 IMU driver and SPP service.
#define K_ICM20948_MAG_WR_ADDR
Definition icm20948.h:159
#define K_ICM20948_DMP_DATA_INTR_CTL
Definition icm20948.h:119
#define K_ICM20948_I2C_SLV1_REG
Definition icm20948.h:106
#define K_ICM20948_INT_PIN_NUM
Definition icm20948.h:55
#define K_ICM20948_REG_FIFO_RST
Definition icm20948.h:77
#define K_ICM20948_REG_TIMEBASE_CORRECTION_PLL
Definition icm20948.h:86
ICM20948_RegBank_t
ICM20948 register bank selector.
Definition icm20948.h:190
@ K_ICM20948_REG_BANK_2
Definition icm20948.h:193
@ K_ICM20948_REG_BANK_1
Definition icm20948.h:192
@ K_ICM20948_REG_BANK_0
Definition icm20948.h:191
@ K_ICM20948_REG_BANK_3
Definition icm20948.h:194
#define K_ICM20948_DMP_B2S_MTX_21
Definition icm20948.h:155
#define K_ICM20948_DMP_CPASS_TIME_BUFFER
Definition icm20948.h:127
#define K_ICM20948_REG_INT_ENABLE
Definition icm20948.h:68
#define K_ICM20948_I2C_SLV1_CTRL
Definition icm20948.h:107
#define K_ICM20948_REG_PWR_MGMT_1
Definition icm20948.h:66
#define K_ICM20948_DMP_ODR_QUAT6
Definition icm20948.h:122
#define K_ICM20948_REG_PWR_MGMT_2
Definition icm20948.h:67
#define K_ICM20948_REG_WHO_AM_I
Definition icm20948.h:63
#define K_ICM20948_REG_FIFO_EN_2
Definition icm20948.h:76
#define K_ICM20948_DMP_FIFO_WATERMARK
Definition icm20948.h:130
#define K_ICM20948_DMP_B2S_MTX_01
Definition icm20948.h:149
#define K_ICM20948_REG_ACCEL_SMPLRT_DIV_2
Definition icm20948.h:92
#define K_ICM20948_DMP_GYRO_SF
Definition icm20948.h:128
#define K_ICM20948_DMP_ACC_SCALE2
Definition icm20948.h:134
#define K_ICM20948_TASK_TIMEOUT_MS
Definition icm20948.h:41
#define K_ICM20948_INT_INTR_TYPE
Definition icm20948.h:56
#define K_ICM20948_MAG_CTRL_2
Definition icm20948.h:161
#define K_ICM20948_REG_DMP_ADDR_LSB
Definition icm20948.h:96
#define K_ICM20948_REG_DMP_ADDR_MSB
Definition icm20948.h:95
#define K_ICM20948_I2C_SLV1_DO
Definition icm20948.h:108
#define K_ICM20948_I2C_SLV1_ADDR
Definition icm20948.h:105
#define K_ICM20948_DMP_B2S_MTX_00
Definition icm20948.h:148
#define K_ICM20948_REG_ACCEL_SMPLRT_DIV_1
Definition icm20948.h:91
#define K_ICM20948_DMP_B2S_MTX_11
Definition icm20948.h:152
#define K_ICM20948_INT_PULL
Definition icm20948.h:57
#define K_ICM20948_DMP_ODR_CPASS
Definition icm20948.h:125
#define K_ICM20948_DMP_B2S_MTX_22
Definition icm20948.h:156
#define K_ICM20948_REG_HW_FIX_DISABLE
Definition icm20948.h:82
#define K_ICM20948_REG_SLV0_REG
Definition icm20948.h:102
#define K_ICM20948_DMP_DATA_OUT_CTL1
Definition icm20948.h:117
#define K_ICM20948_REG_LP_CONF
Definition icm20948.h:65
#define K_ICM20948_DMP_CPASS_MTX_00
Definition icm20948.h:135
#define K_ICM20948_DMP_B2S_MTX_02
Definition icm20948.h:150
#define K_ICM20948_DMP_DATA_OUT_CTL2
Definition icm20948.h:118
#define K_ICM20948_DMP_ACCEL_ONLY_GAIN
Definition icm20948.h:133
#define K_ICM20948_REG_BANK_SEL
Definition icm20948.h:60
#define K_ICM20948_DMP_BAC_RATE
Definition icm20948.h:131
@ K_ICM20948_ACCEL_FS_4G
Definition icm20948.h:455
#define K_ICM20948_REG_GYRO_CONFIG
Definition icm20948.h:90
#define K_ICM20948_DMP_ODR_QUAT9
Definition icm20948.h:123
#define K_ICM20948_DMP_ODR_ACCEL
Definition icm20948.h:126
#define K_ICM20948_REG_FIFO_R_W
Definition icm20948.h:81
#define K_ICM20948_DMP_CPASS_MTX_20
Definition icm20948.h:141
#define K_ICM20948_I2C_MST_ODR_CONFIG
Definition icm20948.h:99
#define K_ICM20948_REG_USER_CTRL
Definition icm20948.h:64
@ K_ICM20948_GYRO_FS_2000DPS
Definition icm20948.h:435
#define K_ICM20948_DMP_CPASS_MTX_01
Definition icm20948.h:136
#define K_ICM20948_REG_GYRO_SMPLRT_DIV
Definition icm20948.h:89
#define K_ICM20948_DMP_CPASS_MTX_12
Definition icm20948.h:140
#define K_ICM20948_DMP_MOTION_EVENT_CTL
Definition icm20948.h:120
#define K_ICM20948_DMP_ACCEL_A_VAR
Definition icm20948.h:146
#define K_ICM20948_DMP_ACC_SCALE
Definition icm20948.h:129
#define K_ICM20948_DMP_LOAD_START
Definition icm20948.h:114
#define K_ICM20948_DMP_ACCEL_CAL_INIT
Definition icm20948.h:147
#define K_ICM20948_REG_I2C_CTRL
Definition icm20948.h:100
#define K_ICM20948_DMP_B2S_RATE
Definition icm20948.h:132
#define K_ICM20948_DMP_CPASS_MTX_11
Definition icm20948.h:139
#define K_ICM20948_REG_SLV0_CTRL
Definition icm20948.h:103
#define K_ICM20948_MAG_RD_ADDR
Definition icm20948.h:160
#define K_ICM20948_DMP_B2S_MTX_20
Definition icm20948.h:154
#define K_ICM20948_REG_FIFO_CFG
Definition icm20948.h:83
#define K_ICM20948_REG_MEM_START_ADDR
Definition icm20948.h:111
#define K_ICM20948_REG_SLV0_ADDR
Definition icm20948.h:101
#define K_ICM20948_DMP_CPASS_MTX_10
Definition icm20948.h:138
#define K_ICM20948_DMP_B2S_MTX_10
Definition icm20948.h:151
#define K_ICM20948_DMP_CPASS_MTX_21
Definition icm20948.h:142
#define K_ICM20948_DMP_ODR_GYRO
Definition icm20948.h:124
#define K_ICM20948_REG_ACCEL_CONFIG_2
Definition icm20948.h:94
#define K_ICM20948_REG_INT_ENABLE_2
Definition icm20948.h:70
#define K_ICM20948_SPI_HOST_USED
Definition icm20948.h:45
#define K_ICM20948_DMP_CPASS_MTX_22
Definition icm20948.h:143
#define K_ICM20948_REG_INT_STATUS
Definition icm20948.h:72
@ K_ICM20948_CLK_AUTO
Definition icm20948.h:244
#define K_ICM20948_REG_FIFO_EN_1
Definition icm20948.h:75
#define K_ICM20948_REG_MEM_R_W
Definition icm20948.h:112
#define K_ICM20948_REG_ACCEL_CONFIG
Definition icm20948.h:93
#define K_ICM20948_DMP_ACCEL_ALPHA_VAR
Definition icm20948.h:145
#define K_ICM20948_DMP_B2S_MTX_12
Definition icm20948.h:153
#define K_ICM20948_REG_MEM_BANK_SEL
Definition icm20948.h:113
#define K_ICM20948_DMP_GYRO_FULLSCALE
Definition icm20948.h:144
#define K_ICM20948_DMP_DATA_RDY_STATUS
Definition icm20948.h:121
#define K_ICM20948_REG_DMP_INT_STATUS
Definition icm20948.h:71
#define K_ICM20948_REG_FIFO_COUNTH
Definition icm20948.h:79
#define K_ICM20948_REG_SINGLE_FIFO_PRIORITY_SEL
Definition icm20948.h:73
#define K_ICM20948_DMP_CPASS_MTX_02
Definition icm20948.h:137
SPP logging service.
#define SPP_LOGI(tag, fmt,...)
Definition log.h:69
#define SPP_LOGE(tag, fmt,...)
Definition log.h:67
SPP_Packet_t
Definition packet.h:79
SPP_RetVal_t SPP_SERVICES_PUBSUB_publish(SPP_Packet_t *p_pkt)
Copies a packet into the internal buffer and returns it to the databank.
Definition pubsub.c:128
Publish-subscribe packet router.
Standard return-value type used across all SPP modules.
SPP_RetVal_t
Unified return type for all SPP API functions.
Definition returnTypes.h:24
@ K_SPP_OK
Definition returnTypes.h:25
@ K_SPP_ERROR
Definition returnTypes.h:26
@ K_SPP_ERROR_NULL_POINTER
Definition returnTypes.h:30
SPP module descriptor and registry API.
void * SPP_HAL_SPI_getHandle(spp_uint8_t deviceIdx)
Obtain the SPI device handle for the given device index.
Definition spi.c:39
SPP_RetVal_t SPP_HAL_SPI_deviceInit(void *p_handle)
Initialise a specific SPI device.
Definition spi.c:49
SPP_RetVal_t SPP_HAL_SPI_transmit(void *p_handle, spp_uint8_t *p_data, spp_uint8_t length)
Perform a full-duplex SPI transaction.
Definition spi.c:79
SPP SPI HAL API — dispatches through the registered HAL port.
ICM20948 interrupt and GPIO context.
Definition icm20948.h:558
spp_uint32_t intPin
Definition icm20948.h:561
spp_uint32_t intPull
Definition icm20948.h:563
volatile spp_bool_t drdyFlag
Definition icm20948.h:559
spp_uint32_t intIntrType
Definition icm20948.h:562
SPP_GpioIsrCtx_t isr_ctx
Definition icm20948.h:560
spp_bool_t dataReady
Definition icm20948.h:551
ICM20948 sensor instance.
Definition icm20948.h:573
spp_uint32_t intIntrType
Definition icm20948.h:577
spp_uint32_t intPull
Definition icm20948.h:578
ICM20948_SensorData_t lastData
Definition icm20948.h:583
spp_uint16_t seq
Definition icm20948.h:584
spp_uint8_t spiDevIdx
Definition icm20948.h:575
ICM20948_Data_t icmData
Definition icm20948.h:582
void * p_spi
Definition icm20948.h:581
spp_uint32_t intPin
Definition icm20948.h:576
volatile spp_bool_t * p_flag
Definition gpio.h:28
Describes the contract of a producer module. This module needs to have:
Definition service.h:28
void SPP_HAL_TIME_delayMs(spp_uint32_t ms)
Block for the requested number of milliseconds.
Definition time.c:37
SPP HAL time API — dispatches through the registered HAL port.
Portable integer types and SPI/storage configuration types for SPP.
uint16_t spp_uint16_t
Definition types.h:29
uint32_t spp_uint32_t
Definition types.h:31
int8_t spp_int8_t
Definition types.h:28
uint8_t spp_uint8_t
Definition types.h:27
int32_t spp_int32_t
Definition types.h:32
bool spp_bool_t
Definition types.h:36
int64_t spp_int64_t
Definition types.h:34
int16_t spp_int16_t
Definition types.h:30
ACCEL_CONFIG_2 register bit layout.
Definition icm20948.h:475
ACCEL_CONFIG register bit layout.
Definition icm20948.h:462
struct ICM20948_RegAccelConfig_t::@105015127256256334376214066105107137252170116356 bits
REG_BANK_SEL register bit layout.
Definition icm20948.h:199
spp_uint8_t value
Definition icm20948.h:200
struct ICM20948_RegBankSel_t::@325125135051365156165251362113041170261051301056 bits
FIFO_CFG register bit layout.
Definition icm20948.h:403
spp_uint8_t value
Definition icm20948.h:404
FIFO_EN_1 register bit layout.
Definition icm20948.h:348
spp_uint8_t value
Definition icm20948.h:349
FIFO_EN_2 register bit layout.
Definition icm20948.h:362
spp_uint8_t value
Definition icm20948.h:363
FIFO_RST register bit layout.
Definition icm20948.h:377
struct ICM20948_RegFifoRst_t::@041065277126235241047134372226063255114241367201 bits
spp_uint8_t value
Definition icm20948.h:378
GYRO_CONFIG_1 register bit layout.
Definition icm20948.h:440
struct ICM20948_RegGyroConfig_t::@232176310072375053240213106010173004177117347241 bits
HW_FIX_DISABLE register bit layout.
Definition icm20948.h:414
INT_ENABLE_2 register bit layout.
Definition icm20948.h:293
struct ICM20948_RegIntEnable2_t::@250247060317310121157315035247225131256117306115 bits
INT_ENABLE register bit layout.
Definition icm20948.h:281
struct ICM20948_RegIntEnable_t::@106155203114352110244332375130240203066354261177 bits
LP_CONFIG register bit layout.
Definition icm20948.h:228
spp_uint8_t value
Definition icm20948.h:229
struct ICM20948_RegLpConf_t::@166315220372323112372004253100254373042267240270 bits
PWR_MGMT_1 register bit layout.
Definition icm20948.h:250
struct ICM20948_RegPwrMgmt1_t::@253125264070140253032213157135301362240260244352 bits
PWR_MGMT_2 register bit layout.
Definition icm20948.h:265
struct ICM20948_RegPwrMgmt2_t::@375266177224043361340021226124357137226225313223 bits
SINGLE_FIFO_PRIORITY_SEL register bit layout.
Definition icm20948.h:335
USER_CTRL register bit layout.
Definition icm20948.h:211
struct ICM20948_RegUserCtrl_t::@356065150070305204106352010301107244336331356261 bits
spp_uint16_t value
Definition kpid.h:25