Skip to content

Commit cbad13b

Browse files
committed
drivers: icm42688: pin9 function
PIN9 of an ICM42688 can be configured as an interrupt output, external clock input or frame sync output. Pin function can now be set via a sensor attribute. Signed-off-by: Yau-ming Leung <[email protected]>
1 parent 379eb7a commit cbad13b

File tree

8 files changed

+207
-15
lines changed

8 files changed

+207
-15
lines changed

drivers/sensor/tdk/icm42688/icm42688.c

+31-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define DT_DRV_COMPAT invensense_icm42688
1010

1111
#include <zephyr/drivers/sensor.h>
12+
#include <zephyr/drivers/sensor/icm42688.h>
1213
#include <zephyr/drivers/spi.h>
1314
#include <zephyr/sys/byteorder.h>
1415

@@ -162,6 +163,29 @@ static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan,
162163
return -EINVAL;
163164
}
164165
new_config.batch_ticks = val->val1;
166+
} else if ((enum sensor_attribute_icm42688)attr ==
167+
SENSOR_ATTR_ICM42688_PIN9_FUNCTION) {
168+
if (val->val1 != ICM42688_PIN9_FUNCTION_INT2 &&
169+
val->val1 != ICM42688_PIN9_FUNCTION_FSYNC &&
170+
val->val1 != ICM42688_PIN9_FUNCTION_CLKIN) {
171+
LOG_ERR("Unknown pin function");
172+
return -EINVAL;
173+
}
174+
175+
if (val->val2 < 31000 || val->val2 > 50000) {
176+
LOG_ERR("RTC frequency must be between 31kHz and 50kHz");
177+
return -EINVAL;
178+
}
179+
180+
/* TODO: Allow this if FSYNC is configurable later. */
181+
if (val->val1 == ICM42688_PIN9_FUNCTION_FSYNC) {
182+
LOG_ERR("FSYNC is disabled, PIN9_FUNCTION should not be set to "
183+
"FSYNC");
184+
return -ENOTSUP;
185+
}
186+
187+
new_config.pin9_function = val->val1;
188+
new_config.rtc_freq = val->val2;
165189
} else {
166190
LOG_ERR("Unsupported attribute");
167191
res = -EINVAL;
@@ -219,6 +243,10 @@ static int icm42688_attr_get(const struct device *dev, enum sensor_channel chan,
219243
if (attr == SENSOR_ATTR_BATCH_DURATION) {
220244
val->val1 = cfg->batch_ticks;
221245
val->val2 = 0;
246+
} else if ((enum sensor_attribute_icm42688)attr ==
247+
SENSOR_ATTR_ICM42688_PIN9_FUNCTION) {
248+
val->val1 = cfg->pin9_function;
249+
val->val2 = cfg->rtc_freq;
222250
} else {
223251
LOG_ERR("Unsupported attribute");
224252
res = -EINVAL;
@@ -313,7 +341,9 @@ void icm42688_unlock(const struct device *dev)
313341
.fifo_hires = false, \
314342
.interrupt1_drdy = false, \
315343
.interrupt1_fifo_ths = false, \
316-
.interrupt1_fifo_full = false \
344+
.interrupt1_fifo_full = false, \
345+
.pin9_function = ICM42688_PIN9_FUNCTION_INT2, \
346+
.rtc_freq = 0 \
317347
}
318348

319349
#define ICM42688_DEFINE_DATA(inst) \

drivers/sensor/tdk/icm42688/icm42688.h

+3
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ struct icm42688_cfg {
308308
bool interrupt1_drdy;
309309
bool interrupt1_fifo_ths;
310310
bool interrupt1_fifo_full;
311+
312+
uint8_t pin9_function;
313+
uint16_t rtc_freq;
311314
};
312315

313316
struct icm42688_trigger_entry {

drivers/sensor/tdk/icm42688/icm42688_common.c

+42
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <zephyr/drivers/sensor.h>
10+
#include <zephyr/drivers/sensor/icm42688.h>
1011
#include <zephyr/drivers/spi.h>
1112
#include <zephyr/sys/byteorder.h>
1213
#include "icm42688.h"
@@ -148,6 +149,47 @@ int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg)
148149

149150
/* TODO maybe do the next few steps intelligently by checking current config */
150151

152+
/* Select register bank 1 */
153+
res = icm42688_spi_single_write(&dev_cfg->spi, REG_BANK_SEL, BIT_BANK1);
154+
if (res != 0) {
155+
LOG_ERR("Error selecting register bank 1");
156+
return -EINVAL;
157+
}
158+
159+
k_busy_wait(50);
160+
161+
/* Set pin 9 function */
162+
uint8_t intf_config5 = FIELD_PREP(MASK_PIN9_FUNCTION, cfg->pin9_function);
163+
164+
LOG_DBG("INTF_CONFIG5 (0x%lx) 0x%x", FIELD_GET(REG_ADDRESS_MASK, REG_INTF_CONFIG5),
165+
intf_config5);
166+
res = icm42688_spi_single_write(&dev_cfg->spi, REG_INTF_CONFIG5, intf_config5);
167+
if (res != 0) {
168+
LOG_ERR("Error writing INTF_CONFIG5");
169+
return -EINVAL;
170+
}
171+
172+
/* Select register bank 0 */
173+
res = icm42688_spi_single_write(&dev_cfg->spi, REG_BANK_SEL, BIT_BANK0);
174+
if (res != 0) {
175+
LOG_ERR("Error selecting register bank 0");
176+
return -EINVAL;
177+
}
178+
179+
k_busy_wait(50);
180+
181+
bool is_pin9_clkin = cfg->pin9_function == ICM42688_PIN9_FUNCTION_CLKIN;
182+
uint8_t intf_config1 = 0x91 | FIELD_PREP(BIT_RTC_MODE, is_pin9_clkin);
183+
184+
LOG_DBG("INTF_CONFIG1 (0x%x) 0x%x", REG_INTF_CONFIG1, intf_config1);
185+
res = icm42688_spi_single_write(&dev_cfg->spi, REG_INTF_CONFIG1, intf_config1);
186+
if (res != 0) {
187+
LOG_ERR("Error writing INTF_CONFIG1");
188+
return -EINVAL;
189+
}
190+
191+
k_busy_wait(250);
192+
151193
/* Power management to set gyro/accel modes */
152194
uint8_t pwr_mgmt0 = FIELD_PREP(MASK_GYRO_MODE, cfg->gyro_pwr_mode) |
153195
FIELD_PREP(MASK_ACCEL_MODE, cfg->accel_pwr_mode) |

drivers/sensor/tdk/icm42688/icm42688_decoder.c

+91-11
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ static uint32_t accel_period_ns[] = {
277277
[ICM42688_DT_ACCEL_ODR_1_5625] = UINT32_C(10000000000000) / 15625,
278278
[ICM42688_DT_ACCEL_ODR_3_125] = UINT32_C(10000000000000) / 31250,
279279
[ICM42688_DT_ACCEL_ODR_6_25] = UINT32_C(10000000000000) / 62500,
280-
[ICM42688_DT_ACCEL_ODR_12_5] = UINT32_C(10000000000000) / 12500,
280+
[ICM42688_DT_ACCEL_ODR_12_5] = UINT32_C(10000000000000) / 125000,
281281
[ICM42688_DT_ACCEL_ODR_25] = UINT32_C(1000000000) / 25,
282282
[ICM42688_DT_ACCEL_ODR_50] = UINT32_C(1000000000) / 50,
283283
[ICM42688_DT_ACCEL_ODR_100] = UINT32_C(1000000000) / 100,
@@ -292,7 +292,7 @@ static uint32_t accel_period_ns[] = {
292292
};
293293

294294
static uint32_t gyro_period_ns[] = {
295-
[ICM42688_DT_GYRO_ODR_12_5] = UINT32_C(10000000000000) / 12500,
295+
[ICM42688_DT_GYRO_ODR_12_5] = UINT32_C(10000000000000) / 125000,
296296
[ICM42688_DT_GYRO_ODR_25] = UINT32_C(1000000000) / 25,
297297
[ICM42688_DT_GYRO_ODR_50] = UINT32_C(1000000000) / 50,
298298
[ICM42688_DT_GYRO_ODR_100] = UINT32_C(1000000000) / 100,
@@ -306,6 +306,28 @@ static uint32_t gyro_period_ns[] = {
306306
[ICM42688_DT_GYRO_ODR_32000] = UINT32_C(1000000) / 32,
307307
};
308308

309+
static int icm42688_calc_timestamp_delta(int rtc_freq, int chan_type, int dt_odr, int frame_count,
310+
uint64_t *out_delta)
311+
{
312+
uint32_t period;
313+
314+
if (IS_ACCEL(chan_type)) {
315+
period = accel_period_ns[dt_odr];
316+
} else if (IS_GYRO(chan_type)) {
317+
period = gyro_period_ns[dt_odr];
318+
} else {
319+
return -EINVAL;
320+
}
321+
322+
/*
323+
* When ODR is set to r and an external clock with frequency f is used,
324+
* the actual ODR = f * r / 32000.
325+
*/
326+
*out_delta = (uint64_t)period * frame_count * 32000 / rtc_freq;
327+
328+
return 0;
329+
}
330+
309331
static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
310332
uint32_t *fit, uint16_t max_count, void *data_out)
311333
{
@@ -350,27 +372,66 @@ static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec c
350372
}
351373
if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) {
352374
struct sensor_q31_data *data = (struct sensor_q31_data *)data_out;
375+
uint64_t ts_delta;
353376

354-
data->shift = 9;
355377
if (has_accel) {
356-
data->readings[count].timestamp_delta =
357-
accel_period_ns[edata->accel_odr] * (accel_frame_count - 1);
378+
rc = icm42688_calc_timestamp_delta(
379+
edata->rtc_freq, SENSOR_CHAN_ACCEL_XYZ, edata->accel_odr,
380+
accel_frame_count - 1, &ts_delta);
358381
} else {
359-
data->readings[count].timestamp_delta =
360-
gyro_period_ns[edata->gyro_odr] * (gyro_frame_count - 1);
382+
rc = icm42688_calc_timestamp_delta(
383+
edata->rtc_freq, SENSOR_CHAN_GYRO_XYZ, edata->gyro_odr,
384+
gyro_frame_count - 1, &ts_delta);
385+
}
386+
if (rc < 0) {
387+
buffer = frame_end;
388+
continue;
389+
}
390+
391+
/*
392+
* TODO: For some extreme combination of ODR and FIFO count, using uint32_t
393+
* to store timestamp delta will overflow. Better error reporting?
394+
*/
395+
if (ts_delta > UINT32_MAX) {
396+
LOG_ERR("Timestamp delta overflow");
397+
buffer = frame_end;
398+
continue;
361399
}
400+
401+
data->readings[count].timestamp_delta = ts_delta;
402+
403+
data->shift = 9;
362404
data->readings[count].temperature =
363405
icm42688_read_temperature_from_packet(buffer);
364406
} else if (IS_ACCEL(chan_spec.chan_type) && has_accel) {
365407
/* Decode accel */
366408
struct sensor_three_axis_data *data =
367409
(struct sensor_three_axis_data *)data_out;
368-
uint64_t period_ns = accel_period_ns[edata->accel_odr];
410+
uint64_t ts_delta;
369411

370412
icm42688_get_shift(SENSOR_CHAN_ACCEL_XYZ, edata->header.accel_fs,
371413
edata->header.gyro_fs, &data->shift);
372414

373-
data->readings[count].timestamp_delta = (accel_frame_count - 1) * period_ns;
415+
rc = icm42688_calc_timestamp_delta(edata->rtc_freq, SENSOR_CHAN_ACCEL_XYZ,
416+
edata->accel_odr, accel_frame_count - 1,
417+
&ts_delta);
418+
if (rc < 0) {
419+
buffer = frame_end;
420+
continue;
421+
}
422+
423+
/*
424+
* TODO: For some extreme combination of ODR and FIFO count, using uint32_t
425+
* to store timestamp delta will overflow. Better error reporting?
426+
*/
427+
if (ts_delta > UINT32_MAX) {
428+
LOG_ERR("Timestamp delta overflow");
429+
buffer = frame_end;
430+
continue;
431+
}
432+
433+
data->readings[count].timestamp_delta = ts_delta;
434+
374435
rc = icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 0,
375436
&data->readings[count].x);
376437
rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 1,
@@ -386,12 +447,31 @@ static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec c
386447
/* Decode gyro */
387448
struct sensor_three_axis_data *data =
388449
(struct sensor_three_axis_data *)data_out;
389-
uint64_t period_ns = gyro_period_ns[edata->gyro_odr];
450+
uint64_t ts_delta;
390451

391452
icm42688_get_shift(SENSOR_CHAN_GYRO_XYZ, edata->header.accel_fs,
392453
edata->header.gyro_fs, &data->shift);
393454

394-
data->readings[count].timestamp_delta = (gyro_frame_count - 1) * period_ns;
455+
rc = icm42688_calc_timestamp_delta(edata->rtc_freq, SENSOR_CHAN_GYRO_XYZ,
456+
edata->gyro_odr, gyro_frame_count - 1,
457+
&ts_delta);
458+
if (rc < 0) {
459+
buffer = frame_end;
460+
continue;
461+
}
462+
463+
/*
464+
* TODO: For some extreme combination of ODR and FIFO count, using uint32_t
465+
* to store timestamp delta will overflow. Better error reporting?
466+
*/
467+
if (ts_delta > UINT32_MAX) {
468+
LOG_ERR("Timestamp delta overflow");
469+
buffer = frame_end;
470+
continue;
471+
}
472+
473+
data->readings[count].timestamp_delta = ts_delta;
474+
395475
rc = icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 0,
396476
&data->readings[count].x);
397477
rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 1,

drivers/sensor/tdk/icm42688/icm42688_decoder.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ struct icm42688_decoder_header {
2121
struct icm42688_fifo_data {
2222
struct icm42688_decoder_header header;
2323
uint8_t int_status;
24-
uint16_t gyro_odr: 4;
25-
uint16_t accel_odr: 4;
24+
uint8_t gyro_odr: 4;
25+
uint8_t accel_odr: 4;
2626
uint16_t fifo_count: 11;
27-
uint16_t reserved: 5;
27+
uint16_t padding1: 5;
28+
uint16_t rtc_freq;
2829
} __attribute__((__packed__));
2930

3031
struct icm42688_encoded_data {

drivers/sensor/tdk/icm42688/icm42688_reg.h

+3
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@
276276
#define BIT_INT_TDEASSERT_DISABLE BIT(5)
277277
#define BIT_INT_ASYNC_RESET BIT(4)
278278

279+
/* Bank1 REG_INTF_CONFIG5 */
280+
#define MASK_PIN9_FUNCTION GENMASK(2, 1)
281+
279282
/* misc. defines */
280283
#define WHO_AM_I_ICM42688 0x47
281284
#define MIN_ACCEL_SENS_SHIFT 11

drivers/sensor/tdk/icm42688/icm42688_rtio_stream.c

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, v
118118
.int_status = drv_data->int_status,
119119
.gyro_odr = drv_data->cfg.gyro_odr,
120120
.accel_odr = drv_data->cfg.accel_odr,
121+
.rtc_freq = drv_data->cfg.rtc_freq,
121122
};
122123
uint32_t buf_avail = buf_len;
123124

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright The Zephyr Project Contributors
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_ICM42688_H_
8+
#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_ICM42688_H_
9+
10+
#include <zephyr/drivers/sensor.h>
11+
12+
/**
13+
* @file
14+
* @brief Extended public API for ICM42688
15+
*
16+
* Pin function configuration via attributes under the current sensor driver abstraction.
17+
*/
18+
19+
#define ICM42688_PIN9_FUNCTION_INT2 0
20+
#define ICM42688_PIN9_FUNCTION_FSYNC 1
21+
#define ICM42688_PIN9_FUNCTION_CLKIN 2
22+
23+
/**
24+
* @brief Extended sensor attributes for ICM42688
25+
*
26+
* Attributes for setting pin function.
27+
*/
28+
enum sensor_attribute_icm42688 {
29+
SENSOR_ATTR_ICM42688_PIN9_FUNCTION = SENSOR_ATTR_PRIV_START
30+
};
31+
32+
#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_ICM42688_H_ */

0 commit comments

Comments
 (0)