@@ -319,6 +319,28 @@ static uint32_t gyro_period_ns[] = {
319319 [ICM42688_DT_GYRO_ODR_32000 ] = UINT32_C (1000000 ) / 32 ,
320320};
321321
322+ static int icm42688_calc_timestamp_delta (int rtc_freq , int chan_type , int dt_odr , int frame_count ,
323+ uint64_t * out_delta )
324+ {
325+ uint32_t period ;
326+
327+ if (IS_ACCEL (chan_type )) {
328+ period = accel_period_ns [dt_odr ];
329+ } else if (IS_GYRO (chan_type )) {
330+ period = gyro_period_ns [dt_odr ];
331+ } else {
332+ return - EINVAL ;
333+ }
334+
335+ /*
336+ * When ODR is set to r and an external clock with frequency f is used,
337+ * the actual ODR = f * r / 32000.
338+ */
339+ * out_delta = (uint64_t )period * frame_count * 32000 / rtc_freq ;
340+
341+ return 0 ;
342+ }
343+
322344static int icm42688_fifo_decode (const uint8_t * buffer , struct sensor_chan_spec chan_spec ,
323345 uint32_t * fit , uint16_t max_count , void * data_out )
324346{
@@ -363,27 +385,66 @@ static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec c
363385 }
364386 if (chan_spec .chan_type == SENSOR_CHAN_DIE_TEMP ) {
365387 struct sensor_q31_data * data = (struct sensor_q31_data * )data_out ;
388+ uint64_t ts_delta ;
366389
367- data -> shift = 9 ;
368390 if (has_accel ) {
369- data -> readings [count ].timestamp_delta =
370- accel_period_ns [edata -> accel_odr ] * (accel_frame_count - 1 );
391+ rc = icm42688_calc_timestamp_delta (
392+ edata -> rtc_freq , SENSOR_CHAN_ACCEL_XYZ , edata -> accel_odr ,
393+ accel_frame_count - 1 , & ts_delta );
371394 } else {
372- data -> readings [count ].timestamp_delta =
373- gyro_period_ns [edata -> gyro_odr ] * (gyro_frame_count - 1 );
395+ rc = icm42688_calc_timestamp_delta (
396+ edata -> rtc_freq , SENSOR_CHAN_GYRO_XYZ , edata -> gyro_odr ,
397+ gyro_frame_count - 1 , & ts_delta );
398+ }
399+ if (rc < 0 ) {
400+ buffer = frame_end ;
401+ continue ;
402+ }
403+
404+ /*
405+ * TODO: For some extreme combination of ODR and FIFO count, using uint32_t
406+ * to store timestamp delta will overflow. Better error reporting?
407+ */
408+ if (ts_delta > UINT32_MAX ) {
409+ LOG_ERR ("Timestamp delta overflow" );
410+ buffer = frame_end ;
411+ continue ;
374412 }
413+
414+ data -> readings [count ].timestamp_delta = ts_delta ;
415+
416+ data -> shift = 9 ;
375417 data -> readings [count ].temperature =
376418 icm42688_read_temperature_from_packet (buffer );
377419 } else if (IS_ACCEL (chan_spec .chan_type ) && has_accel ) {
378420 /* Decode accel */
379421 struct sensor_three_axis_data * data =
380422 (struct sensor_three_axis_data * )data_out ;
381- uint64_t period_ns = accel_period_ns [ edata -> accel_odr ] ;
423+ uint64_t ts_delta ;
382424
383425 icm42688_get_shift (SENSOR_CHAN_ACCEL_XYZ , edata -> header .accel_fs ,
384426 edata -> header .gyro_fs , & data -> shift );
385427
386- data -> readings [count ].timestamp_delta = (accel_frame_count - 1 ) * period_ns ;
428+ rc = icm42688_calc_timestamp_delta (edata -> rtc_freq , SENSOR_CHAN_ACCEL_XYZ ,
429+ edata -> accel_odr , accel_frame_count - 1 ,
430+ & ts_delta );
431+ if (rc < 0 ) {
432+ buffer = frame_end ;
433+ continue ;
434+ }
435+
436+ /*
437+ * TODO: For some extreme combination of ODR and FIFO count, using uint32_t
438+ * to store timestamp delta will overflow. Better error reporting?
439+ */
440+ if (ts_delta > UINT32_MAX ) {
441+ LOG_ERR ("Timestamp delta overflow" );
442+ buffer = frame_end ;
443+ continue ;
444+ }
445+
446+ data -> readings [count ].timestamp_delta = ts_delta ;
447+
387448 rc = icm42688_read_imu_from_packet (buffer , true, edata -> header .accel_fs , 0 ,
388449 & data -> readings [count ].x );
389450 rc |= icm42688_read_imu_from_packet (buffer , true, edata -> header .accel_fs , 1 ,
@@ -399,12 +460,31 @@ static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec c
399460 /* Decode gyro */
400461 struct sensor_three_axis_data * data =
401462 (struct sensor_three_axis_data * )data_out ;
402- uint64_t period_ns = gyro_period_ns [ edata -> gyro_odr ] ;
463+ uint64_t ts_delta ;
403464
404465 icm42688_get_shift (SENSOR_CHAN_GYRO_XYZ , edata -> header .accel_fs ,
405466 edata -> header .gyro_fs , & data -> shift );
406467
407- data -> readings [count ].timestamp_delta = (gyro_frame_count - 1 ) * period_ns ;
468+ rc = icm42688_calc_timestamp_delta (edata -> rtc_freq , SENSOR_CHAN_GYRO_XYZ ,
469+ edata -> gyro_odr , gyro_frame_count - 1 ,
470+ & ts_delta );
471+ if (rc < 0 ) {
472+ buffer = frame_end ;
473+ continue ;
474+ }
475+
476+ /*
477+ * TODO: For some extreme combination of ODR and FIFO count, using uint32_t
478+ * to store timestamp delta will overflow. Better error reporting?
479+ */
480+ if (ts_delta > UINT32_MAX ) {
481+ LOG_ERR ("Timestamp delta overflow" );
482+ buffer = frame_end ;
483+ continue ;
484+ }
485+
486+ data -> readings [count ].timestamp_delta = ts_delta ;
487+
408488 rc = icm42688_read_imu_from_packet (buffer , false, edata -> header .gyro_fs , 0 ,
409489 & data -> readings [count ].x );
410490 rc |= icm42688_read_imu_from_packet (buffer , false, edata -> header .gyro_fs , 1 ,
0 commit comments