Skip to content

Commit 39923e3

Browse files
ymleung314kartben
authored andcommitted
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 <ymleung314@gmail.com>
1 parent b7f046d commit 39923e3

File tree

8 files changed

+200
-14
lines changed

8 files changed

+200
-14
lines changed

drivers/sensor/tdk/icm42688/icm42688.c

Lines changed: 32 additions & 2 deletions
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;
@@ -305,15 +333,17 @@ void icm42688_unlock(const struct device *dev)
305333
.accel_fs = DT_INST_PROP(inst, accel_fs), \
306334
.accel_odr = DT_INST_PROP(inst, accel_odr), \
307335
.gyro_pwr_mode = DT_INST_PROP(inst, gyro_pwr_mode), \
308-
.gyro_fs = DT_INST_PROP(inst, gyro_fs), \
336+
.gyro_fs = DT_INST_PROP(inst, gyro_fs), \
309337
.gyro_odr = DT_INST_PROP(inst, gyro_odr), \
310338
.temp_dis = false, \
311339
.fifo_en = IS_ENABLED(CONFIG_ICM42688_STREAM), \
312340
.batch_ticks = 0, \
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 = 32000 \
317347
}
318348

319349
#define ICM42688_DEFINE_DATA(inst) \

drivers/sensor/tdk/icm42688/icm42688.h

Lines changed: 3 additions & 0 deletions
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

Lines changed: 36 additions & 0 deletions
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,41 @@ 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+
/* Set pin 9 function */
160+
uint8_t intf_config5 = FIELD_PREP(MASK_PIN9_FUNCTION, cfg->pin9_function);
161+
162+
LOG_DBG("INTF_CONFIG5 (0x%lx) 0x%x", FIELD_GET(REG_ADDRESS_MASK, REG_INTF_CONFIG5),
163+
intf_config5);
164+
res = icm42688_spi_single_write(&dev_cfg->spi, REG_INTF_CONFIG5, intf_config5);
165+
if (res != 0) {
166+
LOG_ERR("Error writing INTF_CONFIG5");
167+
return -EINVAL;
168+
}
169+
170+
/* Select register bank 0 */
171+
res = icm42688_spi_single_write(&dev_cfg->spi, REG_BANK_SEL, BIT_BANK0);
172+
if (res != 0) {
173+
LOG_ERR("Error selecting register bank 0");
174+
return -EINVAL;
175+
}
176+
177+
bool is_pin9_clkin = cfg->pin9_function == ICM42688_PIN9_FUNCTION_CLKIN;
178+
uint8_t intf_config1 = 0x91 | FIELD_PREP(BIT_RTC_MODE, is_pin9_clkin);
179+
180+
LOG_DBG("INTF_CONFIG1 (0x%x) 0x%x", REG_INTF_CONFIG1, intf_config1);
181+
res = icm42688_spi_single_write(&dev_cfg->spi, REG_INTF_CONFIG1, intf_config1);
182+
if (res != 0) {
183+
LOG_ERR("Error writing INTF_CONFIG1");
184+
return -EINVAL;
185+
}
186+
151187
/* Power management to set gyro/accel modes */
152188
uint8_t pwr_mgmt0 = FIELD_PREP(MASK_GYRO_MODE, cfg->gyro_pwr_mode) |
153189
FIELD_PREP(MASK_ACCEL_MODE, cfg->accel_pwr_mode) |

drivers/sensor/tdk/icm42688/icm42688_decoder.c

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
322344
static 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,

drivers/sensor/tdk/icm42688/icm42688_decoder.h

Lines changed: 4 additions & 3 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 32 additions & 0 deletions
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)