From dbcc7dc2bd1c1d18f11707ef8d1e0b40769d752a Mon Sep 17 00:00:00 2001 From: Aurelie Fontaine Date: Tue, 3 Dec 2024 15:08:11 +0100 Subject: [PATCH 1/6] module: hal_tdk module https://github.com/tdk-invn-oss/zephyr.hal_tdk Signed-off-by: Aurelie Fontaine --- MAINTAINERS.yml | 11 +++++++++++ modules/hal_tdk/Kconfig | 14 ++++++++++++++ west.yml | 5 +++++ 3 files changed, 30 insertions(+) create mode 100644 modules/hal_tdk/Kconfig diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 22b80979c8aed..68a5f64571aff 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4861,6 +4861,17 @@ West: labels: - "platform: STM32" +"West project: hal_tdk": + status: maintained + maintainers: + - afontaine-invn + collaborators: + - rbuisson-invn + - gjabouley-invn + - sriccardi-invn + files: + - modules/hal_tdk/Kconfig + "West project: hal_telink": status: maintained maintainers: diff --git a/modules/hal_tdk/Kconfig b/modules/hal_tdk/Kconfig new file mode 100644 index 0000000000000..7ea0caec70f7b --- /dev/null +++ b/modules/hal_tdk/Kconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 TDK Invensense +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_HAL_TDK_MODULE + bool "TDK HAL sensor drivers" + help + Use the TDK HAL + +config USE_EMD_ICM42670 + bool "ICM42x7x High Performance 6-Axis MotionTracking IMU" + default y + depends on ZEPHYR_HAL_TDK_MODULE + depends on DT_HAS_INVENSENSE_ICM42670P_ENABLED \ + || DT_HAS_INVENSENSE_ICM42670S_ENABLED diff --git a/west.yml b/west.yml index deecf69acfe98..ea4bb4e5fcdfd 100644 --- a/west.yml +++ b/west.yml @@ -238,6 +238,11 @@ manifest: path: modules/hal/stm32 groups: - hal + - name: hal_tdk + revision: 16eaeeb54138348fb3227323d7d7c4b94e96ac3d + path: modules/hal/tdk + groups: + - hal - name: hal_telink revision: 4226c7fc17d5a34e557d026d428fc766191a0800 path: modules/hal/telink From 9bf51c0b55eb5e7bf516d1d864ebb1187352b84f Mon Sep 17 00:00:00 2001 From: Aurelie Fontaine Date: Thu, 5 Dec 2024 10:55:18 +0100 Subject: [PATCH 2/6] drivers: sensor: icm42670: supports icm42670-P/-S Prepare to use official TDK Invensense Inc. driver for icm42670-P/-S sensor in tdk_hal module. Simplify I2C and SPI transport files. Driver code moves in hal_tdk module. Adds APEX features, such as Pedometer, Tilt detection, Wake on Motion and Significant Motion Detector. Signed-off-by: Aurelie Fontaine --- drivers/sensor/tdk/icm42670/CMakeLists.txt | 10 +- drivers/sensor/tdk/icm42670/Kconfig | 33 +- drivers/sensor/tdk/icm42670/icm42670.c | 1145 +++++++++++------ drivers/sensor/tdk/icm42670/icm42670.h | 86 +- drivers/sensor/tdk/icm42670/icm42670_apex.c | 177 +++ drivers/sensor/tdk/icm42670/icm42670_i2c.c | 105 +- drivers/sensor/tdk/icm42670/icm42670_reg.h | 268 ---- drivers/sensor/tdk/icm42670/icm42670_spi.c | 201 +-- .../sensor/tdk/icm42670/icm42670_trigger.c | 44 +- include/zephyr/drivers/sensor/icm42670.h | 50 + include/zephyr/drivers/sensor/tdk_apex.h | 47 + 11 files changed, 1199 insertions(+), 967 deletions(-) create mode 100644 drivers/sensor/tdk/icm42670/icm42670_apex.c delete mode 100644 drivers/sensor/tdk/icm42670/icm42670_reg.h create mode 100644 include/zephyr/drivers/sensor/icm42670.h create mode 100644 include/zephyr/drivers/sensor/tdk_apex.h diff --git a/drivers/sensor/tdk/icm42670/CMakeLists.txt b/drivers/sensor/tdk/icm42670/CMakeLists.txt index e2257782e6990..f15f333989761 100644 --- a/drivers/sensor/tdk/icm42670/CMakeLists.txt +++ b/drivers/sensor/tdk/icm42670/CMakeLists.txt @@ -2,10 +2,10 @@ zephyr_library() -zephyr_library_sources( - icm42670.c - icm42670_spi.c - icm42670_i2c.c -) +zephyr_library_sources(icm42670.c) + +zephyr_library_sources_ifdef(CONFIG_SPI icm42670_spi.c) +zephyr_library_sources_ifdef(CONFIG_I2C icm42670_i2c.c) zephyr_library_sources_ifdef(CONFIG_ICM42670_TRIGGER icm42670_trigger.c) +zephyr_library_sources_ifdef(CONFIG_TDK_APEX icm42670_apex.c) diff --git a/drivers/sensor/tdk/icm42670/Kconfig b/drivers/sensor/tdk/icm42670/Kconfig index bd16320c472da..a5b06e7af108f 100644 --- a/drivers/sensor/tdk/icm42670/Kconfig +++ b/drivers/sensor/tdk/icm42670/Kconfig @@ -1,18 +1,33 @@ -# ICM42670 Six-Axis Motion Tracking device configuration options +# ICM42670-P ICM42670-S Six-Axis Motion Tracking device configuration options # +# Copyright (c) 2024 TDK Invensense # Copyright (c) 2022 Esco Medical ApS # Copyright (c) 2020 TDK Invensense # # SPDX-License-Identifier: Apache-2.0 +config TDK_APEX + bool "TDK APEX features" menuconfig ICM42670 - bool "ICM42670 Six-Axis Motion Tracking Device" + bool "ICM42670-P/-S Six-Axis Motion Tracking Device" default y - depends on DT_HAS_INVENSENSE_ICM42670_ENABLED - select SPI if $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM42670),spi) - select I2C if $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM42670),i2c) + depends on DT_HAS_INVENSENSE_ICM42670P_ENABLED \ + || DT_HAS_INVENSENSE_ICM42670S_ENABLED + depends on ZEPHYR_HAL_TDK_MODULE + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM42670P),spi) \ + || $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM42670S),spi) + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM42670P),i2c) \ + || $(dt_compat_on_bus,$(DT_COMPAT_INVENSENSE_ICM42670S),i2c) + select TDK_APEX if $(dt_node_str_prop_equals,$(dt_nodelabel_path,icm42670p),apex,pedometer) \ + || $(dt_node_str_prop_equals,$(dt_nodelabel_path,icm42670p),apex,tilt) \ + || $(dt_node_str_prop_equals,$(dt_nodelabel_path,icm42670p),apex,smd) \ + || $(dt_node_str_prop_equals,$(dt_nodelabel_path,icm42670p),apex,wom) \ + || $(dt_node_str_prop_equals,$(dt_nodelabel_path,icm42670s),apex,pedometer) \ + || $(dt_node_str_prop_equals,$(dt_nodelabel_path,icm42670s),apex,tilt) \ + || $(dt_node_str_prop_equals,$(dt_nodelabel_path,icm42670s),apex,smd) \ + || $(dt_node_str_prop_equals,$(dt_nodelabel_path,icm42670s),apex,wom) help - Enable driver for ICM42670 SPI-based six-axis motion tracking device. + Enable driver for ICM42670 SPI-based or I2C-based Six-Axis Motion Tracking device. if ICM42670 @@ -28,13 +43,15 @@ config ICM42670_TRIGGER_NONE config ICM42670_TRIGGER_GLOBAL_THREAD bool "Use global thread" depends on GPIO - depends on $(dt_compat_any_has_prop,$(DT_COMPAT_INVENSENSE_ICM42670),int-gpios) + depends on $(dt_compat_any_has_prop,$(DT_COMPAT_INVENSENSE_ICM42670P),int-gpios) \ + || $(dt_compat_any_has_prop,$(DT_COMPAT_INVENSENSE_ICM42670S),int-gpios) select ICM42670_TRIGGER config ICM42670_TRIGGER_OWN_THREAD bool "Use own thread" depends on GPIO - depends on $(dt_compat_any_has_prop,$(DT_COMPAT_INVENSENSE_ICM42670),int-gpios) + depends on $(dt_compat_any_has_prop,$(DT_COMPAT_INVENSENSE_ICM42670P),int-gpios) \ + || $(dt_compat_any_has_prop,$(DT_COMPAT_INVENSENSE_ICM42670S),int-gpios) select ICM42670_TRIGGER endchoice diff --git a/drivers/sensor/tdk/icm42670/icm42670.c b/drivers/sensor/tdk/icm42670/icm42670.c index e16b9b20e71cf..a2fe604c75dee 100644 --- a/drivers/sensor/tdk/icm42670/icm42670.c +++ b/drivers/sensor/tdk/icm42670/icm42670.c @@ -1,254 +1,476 @@ /* + * Copyright (c) 2024 TDK Invensense * Copyright (c) 2022 Esco Medical ApS * Copyright (c) 2020 TDK Invensense * * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT invensense_icm42670 - +#include #include -#include +#include +#include +#include #include +#include +#include +#include + #include "icm42670.h" -#include "icm42670_reg.h" #include "icm42670_trigger.h" #include LOG_MODULE_REGISTER(ICM42670, CONFIG_SENSOR_LOG_LEVEL); -/* - * Gyro FS to scaling factor mapping. - * See datasheet section 3.1 for details - */ -static const uint16_t icm42670_gyro_sensitivity_x10[] = { - 164, /* BIT_GYRO_UI_FS_2000 */ - 328, /* BIT_GYRO_UI_FS_1000 */ - 655, /* BIT_GYRO_UI_FS_500 */ - 1310, /* BIT_GYRO_UI_FS_250 */ -}; +/* Convert DT enum to sensor ODR selection */ +#define ICM42670_CONVERT_ENUM_TO_ODR_POS (4) + +/* Maximum bytes to read/write on ICM42670 serial interface */ +#define ICM42670_SERIAL_INTERFACE_MAX_READ (1024 * 32) +#define ICM42670_SERIAL_INTERFACE_MAX_WRITE (1024 * 32) -static int icm42670_set_accel_fs(const struct device *dev, uint16_t fs) +static inline int icm42670_reg_read(const struct device *dev, uint8_t reg, uint8_t *buf, + uint32_t size) { const struct icm42670_config *cfg = dev->config; - struct icm42670_data *data = dev->data; - uint8_t temp; - if ((fs > 16) || (fs < 2)) { - LOG_ERR("Unsupported range"); - return -ENOTSUP; - } - - if (fs > 8) { - temp = BIT_ACCEL_UI_FS_16; - } else if (fs > 4) { - temp = BIT_ACCEL_UI_FS_8; - } else if (fs > 2) { - temp = BIT_ACCEL_UI_FS_4; - } else { - temp = BIT_ACCEL_UI_FS_2; - } - - data->accel_sensitivity_shift = MIN_ACCEL_SENS_SHIFT + temp; + return cfg->bus_io->read(&cfg->bus, reg, buf, size); +} - return cfg->bus_io->update(&cfg->bus, REG_ACCEL_CONFIG0, - (uint8_t)MASK_ACCEL_UI_FS_SEL, temp); +static inline int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t *rbuffer, + uint32_t rlen) +{ + return icm42670_reg_read(serif->context, reg, rbuffer, rlen); } -static int icm42670_set_gyro_fs(const struct device *dev, uint16_t fs) +static inline int icm42670_reg_write(const struct device *dev, uint8_t reg, const uint8_t *buf, + uint32_t size) { const struct icm42670_config *cfg = dev->config; - struct icm42670_data *data = dev->data; - uint8_t temp; - if ((fs > 2000) || (fs < 250)) { - LOG_ERR("Unsupported range"); - return -ENOTSUP; - } + return cfg->bus_io->write(&cfg->bus, reg, (uint8_t *)buf, size); +} - if (fs > 1000) { - temp = BIT_GYRO_UI_FS_2000; - } else if (fs > 500) { - temp = BIT_GYRO_UI_FS_1000; - } else if (fs > 250) { - temp = BIT_GYRO_UI_FS_500; - } else { - temp = BIT_GYRO_UI_FS_250; - } +static inline int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg, + const uint8_t *wbuffer, uint32_t wlen) +{ + return icm42670_reg_write(serif->context, reg, wbuffer, wlen); +} - data->gyro_sensitivity_x10 = icm42670_gyro_sensitivity_x10[temp]; +void inv_imu_sleep_us(uint32_t us) +{ + k_sleep(K_USEC(us)); +} - return cfg->bus_io->update(&cfg->bus, REG_GYRO_CONFIG0, - (uint8_t)MASK_GYRO_UI_FS_SEL, temp); +uint64_t inv_imu_get_time_us(void) +{ + /* returns the elapsed time since the system booted, in milliseconds */ + return k_uptime_get() * 1000; } -static int icm42670_set_accel_odr(const struct device *dev, uint16_t rate) +static uint16_t convert_dt_enum_to_freq(uint8_t val) { - const struct icm42670_config *cfg = dev->config; - uint8_t temp; + uint16_t freq; - if ((rate > 1600) || (rate < 1)) { - LOG_ERR("Unsupported frequency"); - return -ENOTSUP; + switch (val) { + case 0: + freq = 0; + break; + case 1: + freq = 1600; + break; + case 2: + freq = 800; + break; + case 3: + freq = 400; + break; + case 4: + freq = 200; + break; + case 5: + freq = 100; + break; + case 6: + freq = 50; + break; + case 7: + freq = 25; + break; + case 8: + freq = 12; + break; + case 9: + freq = 6; + break; + case 10: + freq = 3; + break; + case 11: + freq = 1; + break; + default: + freq = 0; + break; } + return freq; +} - if (rate > 800) { - temp = BIT_ACCEL_ODR_1600; - } else if (rate > 400) { - temp = BIT_ACCEL_ODR_800; - } else if (rate > 200) { - temp = BIT_ACCEL_ODR_400; - } else if (rate > 100) { - temp = BIT_ACCEL_ODR_200; - } else if (rate > 50) { - temp = BIT_ACCEL_ODR_100; - } else if (rate > 25) { - temp = BIT_ACCEL_ODR_50; - } else if (rate > 12) { - temp = BIT_ACCEL_ODR_25; - } else if (rate > 6) { - temp = BIT_ACCEL_ODR_12; - } else if (rate > 3) { - temp = BIT_ACCEL_ODR_6; - } else if (rate > 1) { - temp = BIT_ACCEL_ODR_3; - } else { - temp = BIT_ACCEL_ODR_1; +static uint32_t convert_freq_to_bitfield(uint32_t val, uint16_t *freq) +{ + uint32_t odr_bitfield = 0; + + if (val < 3 && val >= 1) { + odr_bitfield = ACCEL_CONFIG0_ODR_1_5625_HZ; /*(= GYRO_CONFIG0_ODR_1_5625_HZ )*/ + *freq = 1; + } else if (val < 6 && val >= 3) { + odr_bitfield = ACCEL_CONFIG0_ODR_3_125_HZ; /*(= GYRO_CONFIG0_ODR_3_125_HZ )*/ + *freq = 3; + } else if (val < 12 && val >= 6) { + odr_bitfield = ACCEL_CONFIG0_ODR_6_25_HZ; /*(= GYRO_CONFIG0_ODR_6_25_HZ )*/ + *freq = 6; + } else if (val < 25 && val >= 12) { + odr_bitfield = ACCEL_CONFIG0_ODR_12_5_HZ; /*(= GYRO_CONFIG0_ODR_12_5_HZ )*/ + *freq = 12; + } else if (val < 50 && val >= 25) { + odr_bitfield = ACCEL_CONFIG0_ODR_25_HZ; /*(= GYRO_CONFIG0_ODR_25_HZ )*/ + *freq = 25; + } else if (val < 100 && val >= 50) { + odr_bitfield = ACCEL_CONFIG0_ODR_50_HZ; /*(GYRO_CONFIG0_ODR_50_HZ)*/ + *freq = 50; + } else if (val < 200 && val >= 100) { + odr_bitfield = ACCEL_CONFIG0_ODR_100_HZ; /*(= GYRO_CONFIG0_ODR_100_HZ )*/ + *freq = 100; + } else if (val < 400 && val >= 200) { + odr_bitfield = ACCEL_CONFIG0_ODR_200_HZ; /*(= GYRO_CONFIG0_ODR_200_HZ )*/ + *freq = 200; + } else if (val < 800 && val >= 400) { + odr_bitfield = ACCEL_CONFIG0_ODR_400_HZ; /*(= GYRO_CONFIG0_ODR_400_HZ )*/ + *freq = 400; + } else if (val < 1600 && val >= 800) { + odr_bitfield = ACCEL_CONFIG0_ODR_800_HZ; /*(= GYRO_CONFIG0_ODR_800_HZ )*/ + *freq = 800; + } else if (val == 1600) { + odr_bitfield = ACCEL_CONFIG0_ODR_1600_HZ; /*(= GYRO_CONFIG0_ODR_1600_HZ )*/ + *freq = 1600; } - - return cfg->bus_io->update(&cfg->bus, REG_ACCEL_CONFIG0, (uint8_t)MASK_ACCEL_ODR, - temp); + return odr_bitfield; } -static int icm42670_set_gyro_odr(const struct device *dev, uint16_t rate) +static uint32_t convert_acc_fs_to_bitfield(uint32_t val, uint8_t *fs) { - const struct icm42670_config *cfg = dev->config; - uint8_t temp; - - if ((rate > 1600) || (rate < 12)) { - LOG_ERR("Unsupported frequency"); - return -ENOTSUP; + uint32_t bitfield = 0; + + if (val < 4 && val >= 2) { + bitfield = ACCEL_CONFIG0_FS_SEL_2g; + *fs = 2; + } else if (val < 8 && val >= 4) { + bitfield = ACCEL_CONFIG0_FS_SEL_4g; + *fs = 4; + } else if (val < 16 && val >= 8) { + bitfield = ACCEL_CONFIG0_FS_SEL_8g; + *fs = 8; + } else if (val == 16) { + bitfield = ACCEL_CONFIG0_FS_SEL_16g; + *fs = 16; } + return bitfield; +} - if (rate > 800) { - temp = BIT_GYRO_ODR_1600; - } else if (rate > 400) { - temp = BIT_GYRO_ODR_800; - } else if (rate > 200) { - temp = BIT_GYRO_ODR_400; - } else if (rate > 100) { - temp = BIT_GYRO_ODR_200; - } else if (rate > 50) { - temp = BIT_GYRO_ODR_100; - } else if (rate > 25) { - temp = BIT_GYRO_ODR_50; - } else if (rate > 12) { - temp = BIT_GYRO_ODR_25; - } else { - temp = BIT_GYRO_ODR_12; +static uint32_t convert_gyr_fs_to_bitfield(uint32_t val, uint16_t *fs) +{ + uint32_t bitfield = 0; + + if (val < 500 && val >= 250) { + bitfield = GYRO_CONFIG0_FS_SEL_250dps; + *fs = 250; + } else if (val < 1000 && val >= 500) { + bitfield = GYRO_CONFIG0_FS_SEL_500dps; + *fs = 500; + } else if (val < 2000 && val >= 1000) { + bitfield = GYRO_CONFIG0_FS_SEL_1000dps; + *fs = 1000; + } else if (val == 2000) { + bitfield = GYRO_CONFIG0_FS_SEL_2000dps; + *fs = 2000; } - - return cfg->bus_io->update(&cfg->bus, REG_GYRO_CONFIG0, (uint8_t)MASK_GYRO_ODR, - temp); + return bitfield; } -static int icm42670_enable_mclk(const struct device *dev) +static uint32_t convert_ln_bw_to_bitfield(uint32_t val) { - const struct icm42670_config *cfg = dev->config; - - /* switch on MCLK by setting the IDLE bit */ - int res = cfg->bus_io->write(&cfg->bus, REG_PWR_MGMT0, BIT_IDLE); + uint32_t bitfield = 0xFF; + + if (val < 25 && val >= 16) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_16; /* (= GYRO_CONFIG1_GYRO_FILT_BW_16) */ + } else if (val < 34 && val >= 25) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_25; /* (= GYRO_CONFIG1_GYRO_FILT_BW_25) */ + } else if (val < 53 && val >= 34) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_34; /* (= GYRO_CONFIG1_GYRO_FILT_BW_34) */ + } else if (val < 73 && val >= 53) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_53; /* (= GYRO_CONFIG1_GYRO_FILT_BW_53) */ + } else if (val < 121 && val >= 73) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_73; /* (= GYRO_CONFIG1_GYRO_FILT_BW_73) */ + } else if (val < 180 && val >= 121) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_121; /* (= GYRO_CONFIG1_GYRO_FILT_BW_121) */ + } else if (val == 180) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_180; /* (= GYRO_CONFIG1_GYRO_FILT_BW_180) */ + } else if (val == 0) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_BW_NO_FILTER; + /*(= GYRO_CONFIG1_GYRO_FILT_BW_NO_FILTER)*/ + } + return bitfield; +} - if (res) { - return res; +static uint32_t convert_lp_avg_to_bitfield(uint32_t val) +{ + uint32_t bitfield = 0xFF; + + if (val < 4 && val >= 2) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_2; + } else if (val < 8 && val >= 4) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_4; + } else if (val < 16 && val >= 8) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_8; + } else if (val < 32 && val >= 16) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_16; + } else if (val < 64 && val >= 32) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_32; + } else if (val == 64) { + bitfield = ACCEL_CONFIG1_ACCEL_FILT_AVG_64; } + return bitfield; +} - /* wait for the MCLK to stabilize by polling MCLK_RDY register */ - for (int i = 0; i < MCLK_POLL_ATTEMPTS; i++) { - uint8_t value = 0; +static uint8_t convert_bitfield_to_acc_fs(uint8_t bitfield) +{ + uint8_t acc_fs = 0; + + if (bitfield == ACCEL_CONFIG0_FS_SEL_2g) { + acc_fs = 2; + } else if (bitfield == ACCEL_CONFIG0_FS_SEL_4g) { + acc_fs = 4; + } else if (bitfield == ACCEL_CONFIG0_FS_SEL_8g) { + acc_fs = 8; + } else if (bitfield == ACCEL_CONFIG0_FS_SEL_16g) { + acc_fs = 16; + } + return acc_fs; +} - k_usleep(MCLK_POLL_INTERVAL_US); - res = cfg->bus_io->read(&cfg->bus, REG_MCLK_RDY, &value, 1); +static uint16_t convert_bitfield_to_gyr_fs(uint8_t bitfield) +{ + uint16_t gyr_fs = 0; + + if (bitfield == GYRO_CONFIG0_FS_SEL_250dps) { + gyr_fs = 250; + } else if (bitfield == GYRO_CONFIG0_FS_SEL_500dps) { + gyr_fs = 500; + } else if (bitfield == GYRO_CONFIG0_FS_SEL_1000dps) { + gyr_fs = 1000; + } else if (bitfield == GYRO_CONFIG0_FS_SEL_2000dps) { + gyr_fs = 2000; + } + return gyr_fs; +} - if (res) { - return res; +static int icm42670_set_accel_power_mode(struct icm42670_data *drv_data, + const struct sensor_value *val) +{ + if ((val->val1 == ICM42670_LOW_POWER_MODE) && + (drv_data->accel_pwr_mode != ICM42670_LOW_POWER_MODE)) { + if (drv_data->accel_hz != 0) { + if (drv_data->accel_hz <= 400) { + inv_imu_enable_accel_low_power_mode(&drv_data->driver); + } else { + LOG_ERR("Not supported ATTR value"); + return -EINVAL; + } } - - if (FIELD_GET(BIT_MCLK_RDY, value)) { - return 0; + drv_data->accel_pwr_mode = val->val1; + } else if ((val->val1 == ICM42670_LOW_NOISE_MODE) && + (drv_data->accel_pwr_mode != ICM42670_LOW_NOISE_MODE)) { + if (drv_data->accel_hz != 0) { + if (drv_data->accel_hz >= 12) { + inv_imu_enable_accel_low_noise_mode(&drv_data->driver); + } else { + LOG_ERR("Not supported ATTR value"); + return -EINVAL; + } } + drv_data->accel_pwr_mode = val->val1; + } else { + LOG_ERR("Not supported ATTR value"); + return -EINVAL; } - - return -EIO; + return 0; } -static int icm42670_sensor_init(const struct device *dev) +static int icm42670_set_accel_odr(struct icm42670_data *drv_data, const struct sensor_value *val) { - int res; - uint8_t value; - const struct icm42670_config *cfg = dev->config; - - /* start up time for register read/write after POR is 1ms and supply ramp time is 3ms */ - k_msleep(3); - - /* perform a soft reset to ensure a clean slate, reset bit will auto-clear */ - res = cfg->bus_io->write(&cfg->bus, REG_SIGNAL_PATH_RESET, BIT_SOFT_RESET); + if (val->val1 <= 1600 && val->val1 >= 1) { + if (drv_data->accel_hz == 0) { + inv_imu_set_accel_frequency( + &drv_data->driver, + convert_freq_to_bitfield(val->val1, &drv_data->accel_hz)); + if (drv_data->accel_pwr_mode == ICM42670_LOW_POWER_MODE) { + inv_imu_enable_accel_low_power_mode(&drv_data->driver); + } else if (drv_data->accel_pwr_mode == ICM42670_LOW_NOISE_MODE) { + inv_imu_enable_accel_low_noise_mode(&drv_data->driver); + } + } else { + inv_imu_set_accel_frequency( + &drv_data->driver, + convert_freq_to_bitfield(val->val1, &drv_data->accel_hz)); + } + } else if (val->val1 == 0) { + inv_imu_disable_accel(&drv_data->driver); + drv_data->accel_hz = val->val1; + } else { + LOG_ERR("Incorrect sampling value"); + return -EINVAL; + } + return 0; +} - if (res) { - LOG_ERR("write REG_SIGNAL_PATH_RESET failed"); - return res; +static int icm42670_set_accel_fs(struct icm42670_data *drv_data, const struct sensor_value *val) +{ + if (val->val1 > 16 || val->val1 < 2) { + LOG_ERR("Incorrect fullscale value"); + return -EINVAL; } + inv_imu_set_accel_fsr(&drv_data->driver, + convert_acc_fs_to_bitfield(val->val1, &drv_data->accel_fs)); + LOG_DBG("Set accel full scale to: %d G", drv_data->accel_fs); + return 0; +} - /* wait for soft reset to take effect */ - k_msleep(SOFT_RESET_TIME_MS); +static int icm42670_accel_config(struct icm42670_data *drv_data, enum sensor_attribute attr, + const struct sensor_value *val) +{ + if (attr == SENSOR_ATTR_CONFIGURATION) { + icm42670_set_accel_power_mode(drv_data, val); - /* force SPI-4w hardware configuration (so that next read is correct) */ - res = cfg->bus_io->write(&cfg->bus, REG_DEVICE_CONFIG, BIT_SPI_AP_4WIRE); + } else if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + icm42670_set_accel_odr(drv_data, val); - if (res) { - return res; - } + } else if (attr == SENSOR_ATTR_FULL_SCALE) { + icm42670_set_accel_fs(drv_data, val); - /* always use internal RC oscillator */ - res = cfg->bus_io->write(&cfg->bus, REG_INTF_CONFIG1, - (uint8_t)FIELD_PREP(MASK_CLKSEL, BIT_CLKSEL_INT_RC)); + } else if ((enum sensor_attribute_icm42670)attr == SENSOR_ATTR_BW_FILTER_LPF) { + if (val->val1 > 180) { + LOG_ERR("Incorrect low pass filter bandwidth value"); + return -EINVAL; + } + inv_imu_set_accel_ln_bw(&drv_data->driver, convert_ln_bw_to_bitfield(val->val1)); - if (res) { - return res; + } else if ((enum sensor_attribute_icm42670)attr == SENSOR_ATTR_AVERAGING) { + if (val->val1 > 64 || val->val1 < 2) { + LOG_ERR("Incorrect averaging filter value"); + return -EINVAL; + } + inv_imu_set_accel_lp_avg(&drv_data->driver, convert_lp_avg_to_bitfield(val->val1)); + } else { + LOG_ERR("Unsupported attribute"); + return -EINVAL; } + return 0; +} - /* clear reset done int flag */ - res = cfg->bus_io->read(&cfg->bus, REG_INT_STATUS, &value, 1); - - if (res) { - return res; +static int icm42670_set_gyro_odr(struct icm42670_data *drv_data, const struct sensor_value *val) +{ + if (val->val1 <= 1600 && val->val1 > 12) { + if (drv_data->gyro_hz == 0) { + inv_imu_set_gyro_frequency( + &drv_data->driver, + convert_freq_to_bitfield(val->val1, &drv_data->gyro_hz)); + inv_imu_enable_gyro_low_noise_mode(&drv_data->driver); + } else { + inv_imu_set_gyro_frequency( + &drv_data->driver, + convert_freq_to_bitfield(val->val1, &drv_data->gyro_hz)); + } + } else if (val->val1 == 0) { + inv_imu_disable_gyro(&drv_data->driver); + drv_data->gyro_hz = val->val1; + } else { + LOG_ERR("Incorrect sampling value"); + return -EINVAL; } + return 0; +} - if (FIELD_GET(BIT_STATUS_RESET_DONE_INT, value) != 1) { - LOG_ERR("unexpected RESET_DONE_INT value, %i", value); +static int icm42670_set_gyro_fs(struct icm42670_data *drv_data, const struct sensor_value *val) +{ + if (val->val1 > 2000 || val->val1 < 250) { + LOG_ERR("Incorrect fullscale value"); return -EINVAL; } + inv_imu_set_gyro_fsr(&drv_data->driver, + convert_gyr_fs_to_bitfield(val->val1, &drv_data->gyro_fs)); + LOG_DBG("Set gyro fullscale to: %d dps", drv_data->gyro_fs); + return 0; +} - /* enable the master clock to ensure proper operation */ - res = icm42670_enable_mclk(dev); +static int icm42670_gyro_config(struct icm42670_data *drv_data, enum sensor_attribute attr, + const struct sensor_value *val) +{ + if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + icm42670_set_gyro_odr(drv_data, val); - if (res) { - return res; - } + } else if (attr == SENSOR_ATTR_FULL_SCALE) { + icm42670_set_gyro_fs(drv_data, val); - res = cfg->bus_io->read(&cfg->bus, REG_WHO_AM_I, &value, 1); + } else if ((enum sensor_attribute_icm42670)attr == SENSOR_ATTR_BW_FILTER_LPF) { + if (val->val1 > 180) { + LOG_ERR("Incorrect low pass filter bandwidth value"); + return -EINVAL; + } + inv_imu_set_gyro_ln_bw(&drv_data->driver, convert_ln_bw_to_bitfield(val->val1)); - if (res) { - return res; + } else { + LOG_ERR("Unsupported attribute"); + return -EINVAL; } + return 0; +} - if (value != WHO_AM_I_ICM42670) { - LOG_ERR("invalid WHO_AM_I value, was %i but expected %i", value, WHO_AM_I_ICM42670); - return -EINVAL; +static int icm42670_sensor_init(const struct device *dev) +{ + struct icm42670_data *data = dev->data; + int err = 0; + + /* Initialize serial interface and device */ + data->serif.context = (struct device *)dev; + data->serif.read_reg = inv_io_hal_read_reg; + data->serif.write_reg = inv_io_hal_write_reg; + data->serif.max_read = ICM42670_SERIAL_INTERFACE_MAX_READ; + data->serif.max_write = ICM42670_SERIAL_INTERFACE_MAX_WRITE; +#if CONFIG_SPI + data->serif.serif_type = UI_SPI4; +#endif +#if CONFIG_I2C + data->serif.serif_type = UI_I2C; +#endif + err = inv_imu_init(&data->driver, &data->serif, NULL); + if (err < 0) { + LOG_ERR("Init failed: %d", err); + return err; } - LOG_DBG("device id: 0x%02X", value); + err = inv_imu_get_who_am_i(&data->driver, &data->chip_id); + if (err < 0) { + LOG_ERR("ID read failed: %d", err); + return err; + } + + if (data->chip_id != data->imu_whoami) { + LOG_ERR("invalid WHO_AM_I value, was 0x%x but expected 0x%x for %s", data->chip_id, + data->imu_whoami, data->imu_name); + return -ENOTSUP; + } + LOG_DBG("\"%s\" %s OK", dev->name, data->imu_name); return 0; } @@ -256,43 +478,67 @@ static int icm42670_turn_on_sensor(const struct device *dev) { struct icm42670_data *data = dev->data; const struct icm42670_config *cfg = dev->config; - uint8_t value; - int res; - - value = FIELD_PREP(MASK_ACCEL_MODE, BIT_ACCEL_MODE_LNM) | - FIELD_PREP(MASK_GYRO_MODE, BIT_GYRO_MODE_LNM); - - res = cfg->bus_io->update(&cfg->bus, REG_PWR_MGMT0, - (uint8_t)(MASK_ACCEL_MODE | MASK_GYRO_MODE), value); - - if (res) { - return res; + int err = 0; + + err = inv_imu_set_accel_fsr(&data->driver, + (cfg->accel_fs << ACCEL_CONFIG0_ACCEL_UI_FS_SEL_POS)); + data->accel_fs = + convert_bitfield_to_acc_fs((cfg->accel_fs << ACCEL_CONFIG0_ACCEL_UI_FS_SEL_POS)); + if ((err < 0) || (data->accel_fs == 0)) { + LOG_ERR("Failed to configure accel FSR"); + return -EIO; } - - res = icm42670_set_accel_fs(dev, data->accel_fs); - - if (res) { - return res; + LOG_DBG("Set accel full scale to: %d G", data->accel_fs); + + err = inv_imu_set_gyro_fsr(&data->driver, + (cfg->gyro_fs << GYRO_CONFIG0_GYRO_UI_FS_SEL_POS)); + data->gyro_fs = + convert_bitfield_to_gyr_fs((cfg->gyro_fs << GYRO_CONFIG0_GYRO_UI_FS_SEL_POS)); + if ((err < 0) || (data->gyro_fs == 0)) { + LOG_ERR("Failed to configure gyro FSR"); + return -EIO; } - - res = icm42670_set_accel_odr(dev, data->accel_hz); - - if (res) { - return res; + LOG_DBG("Set gyro full scale to: %d dps", data->gyro_fs); + + err = inv_imu_set_accel_lp_avg(&data->driver, + (cfg->accel_avg << ACCEL_CONFIG1_ACCEL_UI_AVG_POS)); + err |= inv_imu_set_accel_ln_bw(&data->driver, + (cfg->accel_filt_bw << ACCEL_CONFIG1_ACCEL_UI_FILT_BW_POS)); + err |= inv_imu_set_gyro_ln_bw(&data->driver, + (cfg->gyro_filt_bw << GYRO_CONFIG1_GYRO_UI_FILT_BW_POS)); + if (err < 0) { + LOG_ERR("Failed to configure filtering."); + return -EIO; } - res = icm42670_set_gyro_fs(dev, data->gyro_fs); - - if (res) { - return res; + if (cfg->accel_hz != 0) { + err |= inv_imu_set_accel_frequency( + &data->driver, cfg->accel_hz + ICM42670_CONVERT_ENUM_TO_ODR_POS); + if ((cfg->accel_pwr_mode == ICM42670_LOW_NOISE_MODE) && + (convert_dt_enum_to_freq(cfg->accel_hz) >= 12)) { + err |= inv_imu_enable_accel_low_noise_mode(&data->driver); + } else if ((cfg->accel_pwr_mode == ICM42670_LOW_POWER_MODE) && + (convert_dt_enum_to_freq(cfg->accel_hz) <= 400)) { + err |= inv_imu_enable_accel_low_power_mode(&data->driver); + } else { + LOG_ERR("Not supported power mode value"); + } + } + if (cfg->gyro_hz != 0) { + err |= inv_imu_set_gyro_frequency(&data->driver, + cfg->gyro_hz + ICM42670_CONVERT_ENUM_TO_ODR_POS); + err |= inv_imu_enable_gyro_low_noise_mode(&data->driver); } - res = icm42670_set_gyro_odr(dev, data->gyro_hz); - - if (res) { - return res; + if (err < 0) { + LOG_ERR("Failed to configure ODR."); + return -EIO; } + data->accel_pwr_mode = cfg->accel_pwr_mode; + data->accel_hz = convert_dt_enum_to_freq(cfg->accel_hz); + data->gyro_hz = convert_dt_enum_to_freq(cfg->gyro_hz); + /* * Accelerometer sensor need at least 10ms startup time * Gyroscope sensor need at least 30ms startup time @@ -302,84 +548,90 @@ static int icm42670_turn_on_sensor(const struct device *dev) return 0; } -static void icm42670_convert_accel(struct sensor_value *val, int16_t raw_val, - uint16_t sensitivity_shift) +static void icm42670_convert_accel(struct sensor_value *val, int16_t raw_val, uint16_t fs) { + int64_t conv_val; + + /* 16 bit accelerometer. 2^15 bits represent the range in G */ /* see datasheet section 3.2 for details */ - int64_t conv_val = ((int64_t)raw_val * SENSOR_G) >> sensitivity_shift; + conv_val = (int64_t)raw_val * SENSOR_G * fs / INT16_MAX; - val->val1 = conv_val / 1000000LL; - val->val2 = conv_val % 1000000LL; + val->val1 = conv_val / 1000000; + val->val2 = conv_val % 1000000; } -static void icm42670_convert_gyro(struct sensor_value *val, int16_t raw_val, - uint16_t sensitivity_x10) +static void icm42670_convert_gyro(struct sensor_value *val, int16_t raw_val, uint16_t fs) { + int64_t conv_val; + + /* 16 bit gyroscope. 2^15 bits represent the range in degrees/s */ /* see datasheet section 3.1 for details */ - int64_t conv_val = ((int64_t)raw_val * SENSOR_PI * 10) / (sensitivity_x10 * 180LL); + conv_val = ((int64_t)raw_val * fs * SENSOR_PI) / (INT16_MAX * 180U); - val->val1 = conv_val / 1000000LL; - val->val2 = conv_val % 1000000LL; + val->val1 = conv_val / 1000000; + val->val2 = conv_val % 1000000; } -static inline void icm42670_convert_temp(struct sensor_value *val, int16_t raw_val) +static void icm42670_convert_temp(struct sensor_value *val, int16_t raw_val) { - /* see datasheet section 15.9 for details */ - val->val1 = (((int64_t)raw_val * 100) / 12800) + 25; - val->val2 = ((((int64_t)raw_val * 100) % 12800) * 1000000) / 12800; + int64_t conv_val; - if (val->val2 < 0) { - val->val1--; - val->val2 += 1000000; - } else if (val->val2 >= 1000000) { - val->val1++; - val->val2 -= 1000000; - } + /* see datasheet section 15.9 for details */ + conv_val = 25 * 1000000 + ((int64_t)raw_val * 1000000 / 2); + val->val1 = conv_val / 1000000; + val->val2 = conv_val % 1000000; } static int icm42670_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { int res = 0; - const struct icm42670_data *data = dev->data; + struct icm42670_data *data = dev->data; +#ifdef CONFIG_TDK_APEX + const struct icm42670_config *cfg = dev->config; +#endif icm42670_lock(dev); - switch (chan) { - case SENSOR_CHAN_ACCEL_XYZ: - icm42670_convert_accel(&val[0], data->accel_x, data->accel_sensitivity_shift); - icm42670_convert_accel(&val[1], data->accel_y, data->accel_sensitivity_shift); - icm42670_convert_accel(&val[2], data->accel_z, data->accel_sensitivity_shift); - break; - case SENSOR_CHAN_ACCEL_X: - icm42670_convert_accel(val, data->accel_x, data->accel_sensitivity_shift); - break; - case SENSOR_CHAN_ACCEL_Y: - icm42670_convert_accel(val, data->accel_y, data->accel_sensitivity_shift); - break; - case SENSOR_CHAN_ACCEL_Z: - icm42670_convert_accel(val, data->accel_z, data->accel_sensitivity_shift); - break; - case SENSOR_CHAN_GYRO_XYZ: - icm42670_convert_gyro(&val[0], data->gyro_x, data->gyro_sensitivity_x10); - icm42670_convert_gyro(&val[1], data->gyro_y, data->gyro_sensitivity_x10); - icm42670_convert_gyro(&val[2], data->gyro_z, data->gyro_sensitivity_x10); - break; - case SENSOR_CHAN_GYRO_X: - icm42670_convert_gyro(val, data->gyro_x, data->gyro_sensitivity_x10); - break; - case SENSOR_CHAN_GYRO_Y: - icm42670_convert_gyro(val, data->gyro_y, data->gyro_sensitivity_x10); - break; - case SENSOR_CHAN_GYRO_Z: - icm42670_convert_gyro(val, data->gyro_z, data->gyro_sensitivity_x10); - break; - case SENSOR_CHAN_DIE_TEMP: + if (chan == SENSOR_CHAN_ACCEL_XYZ) { + icm42670_convert_accel(&val[0], data->accel_x, data->accel_fs); + icm42670_convert_accel(&val[1], data->accel_y, data->accel_fs); + icm42670_convert_accel(&val[2], data->accel_z, data->accel_fs); + } else if (chan == SENSOR_CHAN_ACCEL_X) { + icm42670_convert_accel(val, data->accel_x, data->accel_fs); + } else if (chan == SENSOR_CHAN_ACCEL_Y) { + icm42670_convert_accel(val, data->accel_y, data->accel_fs); + } else if (chan == SENSOR_CHAN_ACCEL_Z) { + icm42670_convert_accel(val, data->accel_z, data->accel_fs); + } else if (chan == SENSOR_CHAN_GYRO_XYZ) { + icm42670_convert_gyro(&val[0], data->gyro_x, data->gyro_fs); + icm42670_convert_gyro(&val[1], data->gyro_y, data->gyro_fs); + icm42670_convert_gyro(&val[2], data->gyro_z, data->gyro_fs); + } else if (chan == SENSOR_CHAN_GYRO_X) { + icm42670_convert_gyro(val, data->gyro_x, data->gyro_fs); + } else if (chan == SENSOR_CHAN_GYRO_Y) { + icm42670_convert_gyro(val, data->gyro_y, data->gyro_fs); + } else if (chan == SENSOR_CHAN_GYRO_Z) { + icm42670_convert_gyro(val, data->gyro_z, data->gyro_fs); + } else if (chan == SENSOR_CHAN_DIE_TEMP) { icm42670_convert_temp(val, data->temp); - break; - default: +#ifdef CONFIG_TDK_APEX + } else if ((enum sensor_channel_tdk_apex)chan == SENSOR_CHAN_APEX_MOTION) { + if (cfg->apex == TDK_APEX_PEDOMETER) { + val[0].val1 = data->pedometer_cnt; + val[1].val1 = data->pedometer_activity; + icm42670_apex_pedometer_cadence_convert(&val[2], data->pedometer_cadence, + data->dmp_odr_hz); + } else if (cfg->apex == TDK_APEX_WOM) { + val[0].val1 = (data->apex_status & ICM42670_APEX_STATUS_MASK_WOM_X) ? 1 : 0; + val[1].val1 = (data->apex_status & ICM42670_APEX_STATUS_MASK_WOM_Y) ? 1 : 0; + val[2].val1 = (data->apex_status & ICM42670_APEX_STATUS_MASK_WOM_Z) ? 1 : 0; + } else if ((cfg->apex == TDK_APEX_TILT) || (cfg->apex == TDK_APEX_SMD)) { + val[0].val1 = data->apex_status; + } +#endif + } else { res = -ENOTSUP; - break; } icm42670_unlock(dev); @@ -387,13 +639,100 @@ static int icm42670_channel_get(const struct device *dev, enum sensor_channel ch return res; } +#ifdef CONFIG_ICM42670_TRIGGER +static int icm42670_fetch_from_fifo(const struct device *dev) +{ + struct icm42670_data *data = dev->data; + int status = 0; + uint8_t int_status; + uint16_t packet_size = FIFO_HEADER_SIZE + FIFO_ACCEL_DATA_SIZE + FIFO_GYRO_DATA_SIZE + + FIFO_TEMP_DATA_SIZE + FIFO_TS_FSYNC_SIZE; + uint16_t fifo_idx = 0; + + /* Ensure data ready status bit is set */ + status |= inv_imu_read_reg(&data->driver, INT_STATUS, 1, &int_status); + if (status != 0) { + return status; + } + + if ((int_status & INT_STATUS_FIFO_THS_INT_MASK) || + (int_status & INT_STATUS_FIFO_FULL_INT_MASK)) { + uint16_t packet_count; + + /* Make sure RCOSC is enabled to guarrantee FIFO read */ + status |= inv_imu_switch_on_mclk(&data->driver); + + /* Read FIFO frame count */ + status |= inv_imu_get_frame_count(&data->driver, &packet_count); + + /* Check for error */ + if (status != 0) { + status |= inv_imu_switch_off_mclk(&data->driver); + return status; + } + + /* Read FIFO data */ + status |= inv_imu_read_reg(&data->driver, FIFO_DATA, packet_size * packet_count, + (uint8_t *)&data->driver.fifo_data); + + /* Check for error */ + if (status != 0) { + status |= inv_imu_reset_fifo(&data->driver); + status |= inv_imu_switch_off_mclk(&data->driver); + return status; + } + + for (uint16_t i = 0; i < packet_count; i++) { + inv_imu_sensor_event_t event; + + status |= inv_imu_decode_fifo_frame( + &data->driver, &data->driver.fifo_data[fifo_idx], &event); + fifo_idx += packet_size; + + /* Check for error */ + if (status != 0) { + status |= inv_imu_reset_fifo(&data->driver); + status |= inv_imu_switch_off_mclk(&data->driver); + return status; + } + + if (event.sensor_mask & (1 << INV_SENSOR_ACCEL)) { + data->accel_x = event.accel[0]; + data->accel_y = event.accel[1]; + data->accel_z = event.accel[2]; + } + if (event.sensor_mask & (1 << INV_SENSOR_GYRO)) { + data->gyro_x = event.gyro[0]; + data->gyro_y = event.gyro[1]; + data->gyro_z = event.gyro[2]; + } + if (event.sensor_mask & (1 << INV_SENSOR_TEMPERATURE)) { + data->temp = event.temperature; + } + /* + * TODO use the sensor streaming interface with RTIO to handle multiple + * samples in FIFO + */ + + } /* end of FIFO read for loop */ + + status |= inv_imu_switch_off_mclk(&data->driver); + if (status < 0) { + return status; + } + } /*else: FIFO threshold was not reached and FIFO was not full */ + + return 0; +} +#endif + +#ifndef CONFIG_ICM42670_TRIGGER static int icm42670_sample_fetch_accel(const struct device *dev) { - const struct icm42670_config *cfg = dev->config; struct icm42670_data *data = dev->data; uint8_t buffer[ACCEL_DATA_SIZE]; - int res = cfg->bus_io->read(&cfg->bus, REG_ACCEL_DATA_X1, buffer, ACCEL_DATA_SIZE); + int res = inv_imu_read_reg(&data->driver, ACCEL_DATA_X1, ACCEL_DATA_SIZE, buffer); if (res) { return res; @@ -408,11 +747,10 @@ static int icm42670_sample_fetch_accel(const struct device *dev) static int icm42670_sample_fetch_gyro(const struct device *dev) { - const struct icm42670_config *cfg = dev->config; struct icm42670_data *data = dev->data; uint8_t buffer[GYRO_DATA_SIZE]; - int res = cfg->bus_io->read(&cfg->bus, REG_GYRO_DATA_X1, buffer, GYRO_DATA_SIZE); + int res = inv_imu_read_reg(&data->driver, GYRO_DATA_X1, GYRO_DATA_SIZE, buffer); if (res) { return res; @@ -427,11 +765,10 @@ static int icm42670_sample_fetch_gyro(const struct device *dev) static int icm42670_sample_fetch_temp(const struct device *dev) { - const struct icm42670_config *cfg = dev->config; struct icm42670_data *data = dev->data; uint8_t buffer[TEMP_DATA_SIZE]; - int res = cfg->bus_io->read(&cfg->bus, REG_TEMP_DATA1, buffer, TEMP_DATA_SIZE); + int res = inv_imu_read_reg(&data->driver, TEMP_DATA1, TEMP_DATA_SIZE, buffer); if (res) { return res; @@ -442,133 +779,139 @@ static int icm42670_sample_fetch_temp(const struct device *dev) return 0; } -static int icm42670_sample_fetch(const struct device *dev, enum sensor_channel chan) +static int icm42670_fetch_from_registers(const struct device *dev, enum sensor_channel chan) { - uint8_t status; - const struct icm42670_config *cfg = dev->config; + struct icm42670_data *data = dev->data; + int res = 0; + uint8_t int_status; + + LOG_ERR("Fetch from reg"); icm42670_lock(dev); - int res = cfg->bus_io->read(&cfg->bus, REG_INT_STATUS_DRDY, &status, 1); + /* Ensure data ready status bit is set */ + int err = inv_imu_read_reg(&data->driver, INT_STATUS_DRDY, 1, &int_status); + + if (int_status & INT_STATUS_DRDY_DATA_RDY_INT_MASK) { + switch (chan) { + case SENSOR_CHAN_ALL: + err |= icm42670_sample_fetch_accel(dev); + err |= icm42670_sample_fetch_gyro(dev); + err |= icm42670_sample_fetch_temp(dev); + break; + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + err |= icm42670_sample_fetch_accel(dev); + break; + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + err |= icm42670_sample_fetch_gyro(dev); + break; + case SENSOR_CHAN_DIE_TEMP: + err |= icm42670_sample_fetch_temp(dev); + break; + default: + res = -ENOTSUP; + break; + } + } + + icm42670_unlock(dev); - if (res) { - goto cleanup; + if (err < 0) { + res = -EIO; } + return res; +} +#endif - if (!FIELD_GET(BIT_INT_STATUS_DATA_DRDY, status)) { - res = -EBUSY; - goto cleanup; +static int icm42670_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + int status = -ENOTSUP; + + icm42670_lock(dev); + +#ifdef CONFIG_TDK_APEX + if ((enum sensor_channel_tdk_apex)chan == SENSOR_CHAN_APEX_MOTION) { + status = icm42670_apex_fetch_from_dmp(dev); } +#endif - switch (chan) { - case SENSOR_CHAN_ALL: - res |= icm42670_sample_fetch_accel(dev); - res |= icm42670_sample_fetch_gyro(dev); - res |= icm42670_sample_fetch_temp(dev); - break; - case SENSOR_CHAN_ACCEL_XYZ: - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - res = icm42670_sample_fetch_accel(dev); - break; - case SENSOR_CHAN_GYRO_XYZ: - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - res = icm42670_sample_fetch_gyro(dev); - break; - case SENSOR_CHAN_DIE_TEMP: - res = icm42670_sample_fetch_temp(dev); - break; - default: - res = -ENOTSUP; - break; + if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_ACCEL_XYZ) || + (chan == SENSOR_CHAN_ACCEL_X) || (chan == SENSOR_CHAN_ACCEL_Y) || + (chan == SENSOR_CHAN_ACCEL_Z) || (chan == SENSOR_CHAN_GYRO_XYZ) || + (chan == SENSOR_CHAN_GYRO_X) || (chan == SENSOR_CHAN_GYRO_Y) || + (chan == SENSOR_CHAN_GYRO_Z) || (chan == SENSOR_CHAN_DIE_TEMP)) { +#ifdef CONFIG_ICM42670_TRIGGER + status = icm42670_fetch_from_fifo(dev); +#else + status = icm42670_fetch_from_registers(dev, chan); +#endif } -cleanup: icm42670_unlock(dev); - return res; + return status; } static int icm42670_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { - int res = 0; - struct icm42670_data *data = dev->data; + struct icm42670_data *drv_data = dev->data; __ASSERT_NO_MSG(val != NULL); icm42670_lock(dev); - switch (chan) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: - if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { - res = icm42670_set_accel_odr(dev, data->accel_hz); - - if (res) { - LOG_ERR("Incorrect sampling value"); - } else { - data->accel_hz = val->val1; - } - } else if (attr == SENSOR_ATTR_FULL_SCALE) { - res = icm42670_set_accel_fs(dev, data->accel_fs); - - if (res) { - LOG_ERR("Incorrect fullscale value"); + if ((enum sensor_channel_tdk_apex)chan == SENSOR_CHAN_APEX_MOTION) { + if (attr == SENSOR_ATTR_CONFIGURATION) { +#ifdef CONFIG_TDK_APEX + if (val->val1 == TDK_APEX_PEDOMETER) { + icm42670_apex_enable(&drv_data->driver); + icm42670_apex_enable_pedometer(dev, &drv_data->driver); + } else if (val->val1 == TDK_APEX_TILT) { + icm42670_apex_enable(&drv_data->driver); + icm42670_apex_enable_tilt(&drv_data->driver); + } else if (val->val1 == TDK_APEX_SMD) { + icm42670_apex_enable(&drv_data->driver); + icm42670_apex_enable_smd(&drv_data->driver); + } else if (val->val1 == TDK_APEX_WOM) { + icm42670_apex_enable_wom(&drv_data->driver); } else { - data->accel_fs = val->val1; + LOG_ERR("Not supported ATTR value"); } +#endif } else { - LOG_ERR("Unsupported attribute"); - res = -ENOTSUP; + LOG_ERR("Not supported ATTR"); + return -EINVAL; } - break; - - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - case SENSOR_CHAN_GYRO_XYZ: - if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { - res = icm42670_set_gyro_odr(dev, data->gyro_hz); + } else if ((chan == SENSOR_CHAN_ACCEL_XYZ) || (chan == SENSOR_CHAN_ACCEL_X) || + (chan == SENSOR_CHAN_ACCEL_Y) || (chan == SENSOR_CHAN_ACCEL_Z)) { + icm42670_accel_config(drv_data, attr, val); - if (res) { - LOG_ERR("Incorrect sampling value"); - } else { - data->gyro_hz = val->val1; - } - } else if (attr == SENSOR_ATTR_FULL_SCALE) { - res = icm42670_set_gyro_fs(dev, data->gyro_fs); + } else if ((chan == SENSOR_CHAN_GYRO_XYZ) || (chan == SENSOR_CHAN_GYRO_X) || + (chan == SENSOR_CHAN_GYRO_Y) || (chan == SENSOR_CHAN_GYRO_Z)) { + icm42670_gyro_config(drv_data, attr, val); - if (res) { - LOG_ERR("Incorrect fullscale value"); - } else { - data->gyro_fs = val->val1; - } - } else { - LOG_ERR("Unsupported attribute"); - res = -EINVAL; - } - break; - - default: + } else { LOG_ERR("Unsupported channel"); - res = -EINVAL; - break; + (void)drv_data; + return -EINVAL; } icm42670_unlock(dev); - return res; + return 0; } static int icm42670_attr_get(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, struct sensor_value *val) { const struct icm42670_data *data = dev->data; + const struct icm42670_config *cfg = dev->config; int res = 0; __ASSERT_NO_MSG(val != NULL); @@ -604,6 +947,12 @@ static int icm42670_attr_get(const struct device *dev, enum sensor_channel chan, } break; + case SENSOR_CHAN_APEX_MOTION: + if (attr == SENSOR_ATTR_CONFIGURATION) { + val->val1 = cfg->apex; + } + break; + default: LOG_ERR("Unsupported channel"); res = -EINVAL; @@ -625,9 +974,10 @@ static inline int icm42670_bus_check(const struct device *dev) static int icm42670_init(const struct device *dev) { struct icm42670_data *data = dev->data; + int res = 0; if (icm42670_bus_check(dev) < 0) { - LOG_ERR("SPI bus is not ready"); + LOG_ERR("bus check failed"); return -ENODEV; } @@ -645,20 +995,15 @@ static int icm42670_init(const struct device *dev) } #ifdef CONFIG_ICM42670_TRIGGER - if (icm42670_trigger_init(dev)) { - LOG_ERR("Failed to initialize interrupts."); - return -EIO; + res |= icm42670_trigger_enable_interrupt(dev); + res |= icm42670_trigger_init(dev); + if (res < 0) { + LOG_ERR("Failed to initialize interrupt."); + return res; } #endif - int res = icm42670_turn_on_sensor(dev); - -#ifdef CONFIG_ICM42670_TRIGGER - if (icm42670_trigger_enable_interrupt(dev)) { - LOG_ERR("Failed to enable interrupts"); - return -EIO; - } -#endif + res |= icm42670_turn_on_sensor(dev); return res; } @@ -688,36 +1033,58 @@ static DEVICE_API(sensor, icm42670_driver_api) = { }; /* device defaults to spi mode 0/3 support */ -#define ICM42670_SPI_CFG \ - SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_TRANSFER_MSB +#define ICM42670_SPI_CFG (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA) + +/* Initializes a common struct icm42670_config */ +#define ICM42670_CONFIG_COMMON(inst) \ + IF_ENABLED(CONFIG_ICM42670_TRIGGER, \ + (.gpio_int = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}),)) \ + .accel_fs = DT_INST_ENUM_IDX(inst, accel_fs), \ + .accel_hz = DT_INST_ENUM_IDX(inst, accel_hz), \ + .accel_avg = DT_INST_ENUM_IDX(inst, accel_avg), \ + .accel_filt_bw = DT_INST_ENUM_IDX(inst, accel_filt_bw_hz), \ + .gyro_fs = DT_INST_ENUM_IDX(inst, gyro_fs), \ + .gyro_hz = DT_INST_ENUM_IDX(inst, gyro_hz), \ + .gyro_filt_bw = DT_INST_ENUM_IDX(inst, gyro_filt_bw_hz), \ + .accel_pwr_mode = DT_INST_ENUM_IDX(inst, power_mode), \ + .apex = DT_INST_ENUM_IDX(inst, apex), /* Initializes the bus members for an instance on a SPI bus. */ #define ICM42670_CONFIG_SPI(inst) \ - .bus.spi = SPI_DT_SPEC_INST_GET(inst, ICM42670_SPI_CFG, 0), \ - .bus_io = &icm42670_bus_io_spi, + {.bus.spi = SPI_DT_SPEC_INST_GET(inst, ICM42670_SPI_CFG, 0), \ + .bus_io = &icm42670_bus_io_spi, \ + ICM42670_CONFIG_COMMON(inst)} /* Initializes the bus members for an instance on an I2C bus. */ #define ICM42670_CONFIG_I2C(inst) \ - .bus.i2c = I2C_DT_SPEC_INST_GET(inst), \ - .bus_io = &icm42670_bus_io_i2c, - -#define ICM42670_INIT(inst) \ - static struct icm42670_data icm42670_driver_##inst = { \ - .accel_hz = DT_INST_PROP(inst, accel_hz), \ - .accel_fs = DT_INST_PROP(inst, accel_fs), \ - .gyro_hz = DT_INST_PROP(inst, gyro_hz), \ - .gyro_fs = DT_INST_PROP(inst, gyro_fs), \ - }; \ - \ - static const struct icm42670_config icm42670_cfg_##inst = { \ - COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ - (ICM42670_CONFIG_SPI(inst)), \ - (ICM42670_CONFIG_I2C(inst))) \ - .gpio_int = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \ + {.bus.i2c = I2C_DT_SPEC_INST_GET(inst), \ + .bus_io = &icm42670_bus_io_i2c, \ + ICM42670_CONFIG_COMMON(inst)} + +/* + * Main instantiation macro, which selects the correct bus-specific + * instantiation macros for the instance. + */ +#define ICM42670_DEFINE(inst, name, whoami) \ + static struct icm42670_data icm42670_data_##inst = { \ + .imu_name = name, \ + .imu_whoami = whoami, \ }; \ - \ - SENSOR_DEVICE_DT_INST_DEFINE(inst, icm42670_init, NULL, &icm42670_driver_##inst, \ - &icm42670_cfg_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ - &icm42670_driver_api); + static const struct icm42670_config icm42670_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (ICM42670_CONFIG_SPI(inst)), \ + (ICM42670_CONFIG_I2C(inst))); \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, icm42670_init, NULL, &icm42670_data_##inst, \ + &icm42670_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &icm42670_driver_api); + +#define DT_DRV_COMPAT invensense_icm42670p +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +DT_INST_FOREACH_STATUS_OKAY_VARGS(ICM42670_DEFINE, INV_ICM42670P_STRING_ID, INV_ICM42670P_WHOAMI); +#endif +#undef DT_DRV_COMPAT -DT_INST_FOREACH_STATUS_OKAY(ICM42670_INIT) +#define DT_DRV_COMPAT invensense_icm42670s +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +DT_INST_FOREACH_STATUS_OKAY_VARGS(ICM42670_DEFINE, INV_ICM42670S_STRING_ID, INV_ICM42670S_WHOAMI); +#endif diff --git a/drivers/sensor/tdk/icm42670/icm42670.h b/drivers/sensor/tdk/icm42670/icm42670.h index 43adc3efb7196..c029d7c6f9112 100644 --- a/drivers/sensor/tdk/icm42670/icm42670.h +++ b/drivers/sensor/tdk/icm42670/icm42670.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024 TDK Invensense * Copyright (c) 2022 Esco Medical ApS * Copyright (c) 2020 TDK Invensense * @@ -14,56 +15,66 @@ #include #include -#define ICM42670_BUS_SPI DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(invensense_icm42670, spi) -#define ICM42670_BUS_I2C DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(invensense_icm42670, i2c) +#include "imu/inv_imu_driver.h" +#ifdef CONFIG_TDK_APEX +#include "imu/inv_imu_apex.h" +#endif union icm42670_bus { -#if ICM42670_BUS_SPI +#if CONFIG_SPI struct spi_dt_spec spi; #endif -#if ICM42670_BUS_I2C +#if CONFIG_I2C struct i2c_dt_spec i2c; #endif }; typedef int (*icm42670_bus_check_fn)(const union icm42670_bus *bus); -typedef int (*icm42670_reg_read_fn)(const union icm42670_bus *bus, - uint16_t reg, uint8_t *data, size_t size); -typedef int (*icm42670_reg_write_fn)(const union icm42670_bus *bus, - uint16_t reg, uint8_t data); - -typedef int (*icm42670_reg_update_fn)(const union icm42670_bus *bus, - uint16_t reg, uint8_t mask, uint8_t data); +typedef int (*icm42670_reg_read_fn)(const union icm42670_bus *bus, uint8_t reg, uint8_t *buf, + uint32_t size); +typedef int (*icm42670_reg_write_fn)(const union icm42670_bus *bus, uint8_t reg, uint8_t *buf, + uint32_t size); struct icm42670_bus_io { icm42670_bus_check_fn check; icm42670_reg_read_fn read; icm42670_reg_write_fn write; - icm42670_reg_update_fn update; }; -#if ICM42670_BUS_SPI +#if CONFIG_SPI extern const struct icm42670_bus_io icm42670_bus_io_spi; #endif -#if ICM42670_BUS_I2C +#if CONFIG_I2C extern const struct icm42670_bus_io icm42670_bus_io_i2c; #endif struct icm42670_data { - int16_t accel_x; - int16_t accel_y; - int16_t accel_z; - uint16_t accel_sensitivity_shift; + struct inv_imu_serif serif; + struct inv_imu_device driver; + uint8_t imu_whoami; + char *imu_name; + uint8_t chip_id; + int32_t accel_x; + int32_t accel_y; + int32_t accel_z; uint16_t accel_hz; - uint16_t accel_fs; - int16_t gyro_x; - int16_t gyro_y; - int16_t gyro_z; - uint16_t gyro_sensitivity_x10; + uint8_t accel_fs; + uint8_t accel_pwr_mode; + int32_t gyro_x; + int32_t gyro_y; + int32_t gyro_z; uint16_t gyro_hz; uint16_t gyro_fs; - int16_t temp; + int32_t temp; +#ifdef CONFIG_TDK_APEX + uint8_t dmp_odr_hz; + uint64_t pedometer_cnt; + uint8_t pedometer_activity; + uint8_t pedometer_cadence; + uint8_t apex_status; +#endif + #ifdef CONFIG_ICM42670_TRIGGER const struct device *dev; struct gpio_callback gpio_cb; @@ -85,6 +96,33 @@ struct icm42670_config { union icm42670_bus bus; const struct icm42670_bus_io *bus_io; struct gpio_dt_spec gpio_int; + uint8_t accel_fs; + uint16_t accel_hz; + uint16_t accel_avg; + uint16_t accel_filt_bw; + uint16_t gyro_fs; + uint16_t gyro_hz; + uint16_t gyro_filt_bw; + uint8_t accel_pwr_mode; + uint8_t apex; }; +#ifdef CONFIG_TDK_APEX + +#define ICM42670_APEX_STATUS_MASK_TILT BIT(0) +#define ICM42670_APEX_STATUS_MASK_SMD BIT(1) +#define ICM42670_APEX_STATUS_MASK_WOM_X BIT(2) +#define ICM42670_APEX_STATUS_MASK_WOM_Y BIT(3) +#define ICM42670_APEX_STATUS_MASK_WOM_Z BIT(4) + +int icm42670_apex_enable(inv_imu_device_t *s); +int icm42670_apex_fetch_from_dmp(const struct device *dev); +void icm42670_apex_pedometer_cadence_convert(struct sensor_value *val, uint8_t raw_val, + uint8_t dmp_odr_hz); +int icm42670_apex_enable_pedometer(const struct device *dev, inv_imu_device_t *s); +int icm42670_apex_enable_tilt(inv_imu_device_t *s); +int icm42670_apex_enable_smd(inv_imu_device_t *s); +int icm42670_apex_enable_wom(inv_imu_device_t *s); +#endif + #endif /* ZEPHYR_DRIVERS_SENSOR_ICM42670_H_ */ diff --git a/drivers/sensor/tdk/icm42670/icm42670_apex.c b/drivers/sensor/tdk/icm42670/icm42670_apex.c new file mode 100644 index 0000000000000..bdd128b6238e0 --- /dev/null +++ b/drivers/sensor/tdk/icm42670/icm42670_apex.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2024 TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "icm42670.h" +#include "imu/inv_imu_apex.h" + +int icm42670_apex_enable(inv_imu_device_t *s) +{ + int err = 0; + inv_imu_apex_parameters_t apex_inputs; + inv_imu_interrupt_parameter_t config_int = {(inv_imu_interrupt_value)0}; + + /* Disabling FIFO to avoid extra power consumption due to ALP config */ + err |= inv_imu_configure_fifo(s, INV_IMU_FIFO_DISABLED); + + /* Enable Pedometer, Tilt and SMD interrupts */ + config_int.INV_STEP_DET = INV_IMU_ENABLE; + config_int.INV_STEP_CNT_OVFL = INV_IMU_ENABLE; + config_int.INV_TILT_DET = INV_IMU_ENABLE; + config_int.INV_SMD = INV_IMU_ENABLE; + err |= inv_imu_set_config_int1(s, &config_int); + + /* Enable accelerometer to feed the APEX Pedometer algorithm */ + err |= inv_imu_set_accel_frequency(s, ACCEL_CONFIG0_ODR_50_HZ); + + /* Set 2x averaging, in order to minimize power consumption (16x by default) */ + err |= inv_imu_set_accel_lp_avg(s, ACCEL_CONFIG1_ACCEL_FILT_AVG_2); + err |= inv_imu_enable_accel_low_power_mode(s); + + /* Get the default parameters for the APEX features */ + err |= inv_imu_apex_init_parameters_struct(s, &apex_inputs); + + /* + * Configure the power mode Normal mode. + * Avalaible mode : Low Power mode (WoM+Pedometer), + * configure the WoM to wake-up the DMP once it goes in power save mode + */ + apex_inputs.power_save = APEX_CONFIG0_DMP_POWER_SAVE_DIS; + err |= inv_imu_apex_configure_parameters(s, &apex_inputs); + + /* Configure sampling frequency to 50Hz */ + err |= inv_imu_apex_set_frequency(s, APEX_CONFIG1_DMP_ODR_50Hz); + + return err; +} + +int icm42670_apex_fetch_from_dmp(const struct device *dev) +{ + struct icm42670_data *data = dev->data; + int rc = 0; + uint8_t int_status2, int_status3; + + /* Read APEX interrupt status */ + rc |= inv_imu_read_reg(&data->driver, INT_STATUS2, 1, &int_status2); + rc |= inv_imu_read_reg(&data->driver, INT_STATUS3, 1, &int_status3); + + /* Test Pedometer interrupt */ + if (int_status3 & (INT_STATUS3_STEP_DET_INT_MASK)) { + inv_imu_apex_step_activity_t apex_pedometer; + uint8_t step_cnt_ovflw = 0; + + if (int_status3 & INT_STATUS3_STEP_CNT_OVF_INT_MASK) { + step_cnt_ovflw = 1; + } + + rc |= inv_imu_apex_get_data_activity(&data->driver, &apex_pedometer); + + if (data->pedometer_cnt != + apex_pedometer.step_cnt + step_cnt_ovflw * (uint64_t)UINT16_MAX) { + data->pedometer_cnt = + apex_pedometer.step_cnt + step_cnt_ovflw * (uint64_t)UINT16_MAX; + data->pedometer_activity = apex_pedometer.activity_class; + data->pedometer_cadence = apex_pedometer.step_cadence; + } else { + /* Pedometer data processing */ + rc = 1; + } + } + /* Test Tilt interrupt */ + if (int_status3 & (INT_STATUS3_TILT_DET_INT_MASK)) { + data->apex_status = ICM42670_APEX_STATUS_MASK_TILT; + } + /* Test SMD interrupt */ + if ((int_status2 & (INT_STATUS2_SMD_INT_MASK)) || (rc != 0)) { + data->apex_status = ICM42670_APEX_STATUS_MASK_SMD; + } + /* Test WOM interrupts */ + if (int_status2 & (INT_STATUS2_WOM_X_INT_MASK | INT_STATUS2_WOM_Y_INT_MASK | + INT_STATUS2_WOM_Z_INT_MASK)) { + data->apex_status = 0; + if (int_status2 & INT_STATUS2_WOM_X_INT_MASK) { + data->apex_status |= ICM42670_APEX_STATUS_MASK_WOM_X; + } + if (int_status2 & INT_STATUS2_WOM_Y_INT_MASK) { + data->apex_status |= ICM42670_APEX_STATUS_MASK_WOM_Y; + } + if (int_status2 & INT_STATUS2_WOM_Z_INT_MASK) { + data->apex_status |= ICM42670_APEX_STATUS_MASK_WOM_Z; + } + } + return rc; +} + +void icm42670_apex_pedometer_cadence_convert(struct sensor_value *val, uint8_t raw_val, + uint8_t dmp_odr_hz) +{ + int64_t conv_val; + + /* Converting u6.2 */ + conv_val = (int64_t)(dmp_odr_hz << 2) * 1000000 / (raw_val + (raw_val & 0x03)); + val->val1 = conv_val / 1000000; + val->val2 = conv_val % 1000000; +} + +int icm42670_apex_enable_pedometer(const struct device *dev, inv_imu_device_t *s) +{ + struct icm42670_data *data = dev->data; + + data->dmp_odr_hz = 50; + /* Enable the pedometer */ + return inv_imu_apex_enable_pedometer(s); +} + +int icm42670_apex_enable_tilt(inv_imu_device_t *s) +{ + /* Enable Tilt */ + return inv_imu_apex_enable_tilt(s); +} + +int icm42670_apex_enable_smd(inv_imu_device_t *s) +{ + int rc = 0; + + /* Enable SMD (and Pedometer as SMD uses it) */ + rc |= inv_imu_apex_enable_pedometer(s); + rc |= inv_imu_apex_enable_smd(s); + + return rc; +} + +int icm42670_apex_enable_wom(inv_imu_device_t *s) +{ + int rc = 0; + inv_imu_interrupt_parameter_t config_int = {(inv_imu_interrupt_value)0}; + + /* + * Optimize power consumption: + * - Disable FIFO usage. + * - Disable data ready interrupt and enable WOM interrupts. + * - Set 2X averaging. + * - Use Low-Power mode at low frequency. + */ + rc |= inv_imu_configure_fifo(s, INV_IMU_FIFO_DISABLED); + + config_int.INV_WOM_X = INV_IMU_ENABLE; + config_int.INV_WOM_Y = INV_IMU_ENABLE; + config_int.INV_WOM_Z = INV_IMU_ENABLE; + rc |= inv_imu_set_config_int1(s, &config_int); + + rc |= inv_imu_set_accel_lp_avg(s, ACCEL_CONFIG1_ACCEL_FILT_AVG_2); + rc |= inv_imu_set_accel_frequency(s, ACCEL_CONFIG0_ODR_12_5_HZ); + rc |= inv_imu_enable_accel_low_power_mode(s); + + /* + * Configure WOM thresholds for each axis to 195 mg (Resolution 1g/256) + * WOM threshold = 50 * 1000 / 256 = 195 mg + * and enable WOM + */ + rc |= inv_imu_configure_wom(s, 50, 50, 50, WOM_CONFIG_WOM_INT_MODE_ORED, + WOM_CONFIG_WOM_INT_DUR_1_SMPL); + rc |= inv_imu_enable_wom(s); + + return rc; +} diff --git a/drivers/sensor/tdk/icm42670/icm42670_i2c.c b/drivers/sensor/tdk/icm42670/icm42670_i2c.c index 3ee3dfef24e4b..a3871ec25d5c9 100644 --- a/drivers/sensor/tdk/icm42670/icm42670_i2c.c +++ b/drivers/sensor/tdk/icm42670/icm42670_i2c.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024 TDK Invensense * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 @@ -9,114 +10,28 @@ */ #include "icm42670.h" -#include "icm42670_reg.h" -#if ICM42670_BUS_I2C +#if CONFIG_I2C static int icm42670_bus_check_i2c(const union icm42670_bus *bus) { - return i2c_is_ready_dt(&bus->i2c) ? 0 : -ENODEV; + return device_is_ready(bus->i2c.bus) ? 0 : -ENODEV; } -static int i2c_read_mreg(const union icm42670_bus *bus, uint8_t reg, uint8_t bank, - uint8_t *buf, size_t len) +static int icm42670_reg_read_i2c(const union icm42670_bus *bus, uint8_t reg, uint8_t *buf, + uint32_t size) { - int res = i2c_reg_write_byte_dt(&bus->i2c, REG_BLK_SEL_R, bank); - - if (res) { - return res; - } - - /* reads from MREG registers must be done byte-by-byte */ - for (size_t i = 0; i < len; i++) { - uint8_t addr = reg + i; - - res = i2c_reg_write_byte_dt(&bus->i2c, REG_MADDR_R, addr); - - if (res) { - return res; - } - - k_usleep(MREG_R_W_WAIT_US); - res = i2c_reg_read_byte_dt(&bus->i2c, REG_M_R, &buf[i]); - - if (res) { - return res; - } - - k_usleep(MREG_R_W_WAIT_US); - } - - return 0; -} - -static int icm42670_reg_read_i2c(const union icm42670_bus *bus, uint16_t reg, uint8_t *data, - size_t len) -{ - int res = 0; - uint8_t bank = FIELD_GET(REG_BANK_MASK, reg); - uint8_t address = FIELD_GET(REG_ADDRESS_MASK, reg); - - if (bank) { - res = i2c_read_mreg(bus, address, bank, data, len); - } else { - res = i2c_burst_read_dt(&bus->i2c, address, data, len); - } - - return res; -} - -static int i2c_write_mreg(const union icm42670_bus *bus, uint16_t reg, uint8_t bank, - uint8_t buf) -{ - int res = i2c_reg_write_byte_dt(&bus->i2c, REG_BLK_SEL_W, bank); - - if (res) { - return res; - } - - res = i2c_reg_write_byte_dt(&bus->i2c, REG_MADDR_W, reg); - - if (res) { - return res; - } - - res = i2c_reg_write_byte_dt(&bus->i2c, REG_M_W, buf); - - if (res) { - return res; - } - - k_usleep(MREG_R_W_WAIT_US); - - return 0; -} - -static int icm42670_reg_write_i2c(const union icm42670_bus *bus, - uint16_t reg, uint8_t data) -{ - int res = 0; - uint8_t bank = FIELD_GET(REG_BANK_MASK, reg); - uint8_t address = FIELD_GET(REG_ADDRESS_MASK, reg); - - if (bank) { - res = i2c_write_mreg(bus, address, bank, data); - } else { - res = i2c_reg_write_byte_dt(&bus->i2c, address, data); - } - - return res; + return i2c_burst_read_dt(&bus->i2c, reg, buf, size); } -static int icm42670_reg_update_i2c(const union icm42670_bus *bus, uint16_t reg, uint8_t mask, - uint8_t val) +static int icm42670_reg_write_i2c(const union icm42670_bus *bus, uint8_t reg, uint8_t *buf, + uint32_t size) { - return i2c_reg_update_byte_dt(&bus->i2c, reg, mask, val); + return i2c_burst_write_dt(&bus->i2c, reg, buf, size); } const struct icm42670_bus_io icm42670_bus_io_i2c = { .check = icm42670_bus_check_i2c, .read = icm42670_reg_read_i2c, .write = icm42670_reg_write_i2c, - .update = icm42670_reg_update_i2c, }; -#endif /* ICM42670_BUS_I2C */ +#endif /* CONFIG_I2C */ diff --git a/drivers/sensor/tdk/icm42670/icm42670_reg.h b/drivers/sensor/tdk/icm42670/icm42670_reg.h deleted file mode 100644 index 6a26f859a515b..0000000000000 --- a/drivers/sensor/tdk/icm42670/icm42670_reg.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2022 Esco Medical ApS - * Copyright (c) 2020 TDK Invensense - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42670_REG_H_ -#define ZEPHYR_DRIVERS_SENSOR_ICM42670_REG_H_ - -#include - -/* Helper macros for addressing registers in MREG1-3, see datasheet section 13 */ -#define REG_MADDR_BASE 0x0028 -#define REG_MREG1_SHIFT 8 -#define REG_MREG2_SHIFT 9 -#define REG_MREG3_SHIFT 10 -#define REG_BANK0_OFFSET 0x0000 -#define REG_MREG1_OFFSET (REG_MADDR_BASE << REG_MREG1_SHIFT) -#define REG_MREG2_OFFSET (REG_MADDR_BASE << REG_MREG2_SHIFT) -#define REG_MREG3_OFFSET (REG_MADDR_BASE << REG_MREG3_SHIFT) -#define REG_ADDRESS_MASK GENMASK(7, 0) -#define REG_BANK_MASK GENMASK(15, 8) -#define REG_SPI_READ_BIT BIT(7) -#define MREG_R_W_WAIT_US 20 /* 10us, but use 20us to be on the safe side */ - -/* BANK 0 */ -#define REG_MCLK_RDY (REG_BANK0_OFFSET | 0x00) -#define REG_DEVICE_CONFIG (REG_BANK0_OFFSET | 0x01) -#define REG_SIGNAL_PATH_RESET (REG_BANK0_OFFSET | 0x02) -#define REG_DRIVE_CONFIG1 (REG_BANK0_OFFSET | 0x03) -#define REG_DRIVE_CONFIG2 (REG_BANK0_OFFSET | 0x04) -#define REG_DRIVE_CONFIG3 (REG_BANK0_OFFSET | 0x05) -#define REG_INT_CONFIG (REG_BANK0_OFFSET | 0x06) -#define REG_TEMP_DATA1 (REG_BANK0_OFFSET | 0x09) -#define REG_TEMP_DATA0 (REG_BANK0_OFFSET | 0x0a) -#define REG_ACCEL_DATA_X1 (REG_BANK0_OFFSET | 0x0b) -#define REG_ACCEL_DATA_X0 (REG_BANK0_OFFSET | 0x0c) -#define REG_ACCEL_DATA_Y1 (REG_BANK0_OFFSET | 0x0d) -#define REG_ACCEL_DATA_Y0 (REG_BANK0_OFFSET | 0x0e) -#define REG_ACCEL_DATA_Z1 (REG_BANK0_OFFSET | 0x0f) -#define REG_ACCEL_DATA_Z0 (REG_BANK0_OFFSET | 0x10) -#define REG_GYRO_DATA_X1 (REG_BANK0_OFFSET | 0x11) -#define REG_GYRO_DATA_X0 (REG_BANK0_OFFSET | 0x12) -#define REG_GYRO_DATA_Y1 (REG_BANK0_OFFSET | 0x13) -#define REG_GYRO_DATA_Y0 (REG_BANK0_OFFSET | 0x14) -#define REG_GYRO_DATA_Z1 (REG_BANK0_OFFSET | 0x15) -#define REG_GYRO_DATA_Z0 (REG_BANK0_OFFSET | 0x16) -#define REG_TMST_FSYNCH (REG_BANK0_OFFSET | 0x17) -#define REG_TMST_FSYNCL (REG_BANK0_OFFSET | 0x18) -#define REG_APEX_DATA4 (REG_BANK0_OFFSET | 0x1d) -#define REG_APEX_DATA5 (REG_BANK0_OFFSET | 0x1e) -#define REG_PWR_MGMT0 (REG_BANK0_OFFSET | 0x1f) -#define REG_GYRO_CONFIG0 (REG_BANK0_OFFSET | 0x20) -#define REG_ACCEL_CONFIG0 (REG_BANK0_OFFSET | 0x21) -#define REG_TEMP_CONFIG0 (REG_BANK0_OFFSET | 0x22) -#define REG_GYRO_CONFIG1 (REG_BANK0_OFFSET | 0x23) -#define REG_ACCEL_CONFIG1 (REG_BANK0_OFFSET | 0x24) -#define REG_APEX_CONFIG0 (REG_BANK0_OFFSET | 0x25) -#define REG_APEX_CONFIG1 (REG_BANK0_OFFSET | 0x26) -#define REG_WOM_CONFIG (REG_BANK0_OFFSET | 0x27) -#define REG_FIFO_CONFIG1 (REG_BANK0_OFFSET | 0x28) -#define REG_FIFO_CONFIG2 (REG_BANK0_OFFSET | 0x29) -#define REG_FIFO_CONFIG3 (REG_BANK0_OFFSET | 0x2a) -#define REG_INT_SOURCE0 (REG_BANK0_OFFSET | 0x2b) -#define REG_INT_SOURCE1 (REG_BANK0_OFFSET | 0x2c) -#define REG_INT_SOURCE3 (REG_BANK0_OFFSET | 0x2d) -#define REG_INT_SOURCE4 (REG_BANK0_OFFSET | 0x2e) -#define REG_FIFO_LOST_PKT0 (REG_BANK0_OFFSET | 0x2f) -#define REG_FIFO_LOST_PKT1 (REG_BANK0_OFFSET | 0x30) -#define REG_APEX_DATA0 (REG_BANK0_OFFSET | 0x31) -#define REG_APEX_DATA1 (REG_BANK0_OFFSET | 0x32) -#define REG_APEX_DATA2 (REG_BANK0_OFFSET | 0x33) -#define REG_APEX_DATA3 (REG_BANK0_OFFSET | 0x34) -#define REG_INTF_CONFIG0 (REG_BANK0_OFFSET | 0x35) -#define REG_INTF_CONFIG1 (REG_BANK0_OFFSET | 0x36) -#define REG_INT_STATUS_DRDY (REG_BANK0_OFFSET | 0x39) -#define REG_INT_STATUS (REG_BANK0_OFFSET | 0x3a) -#define REG_INT_STATUS2 (REG_BANK0_OFFSET | 0x3b) -#define REG_INT_STATUS3 (REG_BANK0_OFFSET | 0x3c) -#define REG_FIFO_COUNTH (REG_BANK0_OFFSET | 0x3d) -#define REG_FIFO_COUNTL (REG_BANK0_OFFSET | 0x3e) -#define REG_FIFO_DATA (REG_BANK0_OFFSET | 0x3f) -#define REG_WHO_AM_I (REG_BANK0_OFFSET | 0x75) -#define REG_BLK_SEL_W (REG_BANK0_OFFSET | 0x79) -#define REG_MADDR_W (REG_BANK0_OFFSET | 0x7a) -#define REG_M_W (REG_BANK0_OFFSET | 0x7b) -#define REG_BLK_SEL_R (REG_BANK0_OFFSET | 0x7c) -#define REG_MADDR_R (REG_BANK0_OFFSET | 0x7d) -#define REG_M_R (REG_BANK0_OFFSET | 0x7e) - -/* MREG1 */ -#define REG_TMST_CONFIG1 (REG_MREG1_OFFSET | 0x00) -#define REG_FIFO_CONFIG5 (REG_MREG1_OFFSET | 0x01) -#define REG_FIFO_CONFIG6 (REG_MREG1_OFFSET | 0x02) -#define REG_FSYNC_CONFIG (REG_MREG1_OFFSET | 0x03) -#define REG_INT_CONFIG0 (REG_MREG1_OFFSET | 0x04) -#define REG_INT_CONFIG1 (REG_MREG1_OFFSET | 0x05) -#define REG_SENSOR_CONFIG3 (REG_MREG1_OFFSET | 0x06) -#define REG_ST_CONFIG (REG_MREG1_OFFSET | 0x13) -#define REG_SELFTEST (REG_MREG1_OFFSET | 0x14) -#define REG_INTF_CONFIG6 (REG_MREG1_OFFSET | 0x23) -#define REG_INTF_CONFIG10 (REG_MREG1_OFFSET | 0x25) -#define REG_INTF_CONFIG7 (REG_MREG1_OFFSET | 0x28) -#define REG_OTP_CONFIG (REG_MREG1_OFFSET | 0x2b) -#define REG_INT_SOURCE6 (REG_MREG1_OFFSET | 0x2f) -#define REG_INT_SOURCE7 (REG_MREG1_OFFSET | 0x30) -#define REG_INT_SOURCE8 (REG_MREG1_OFFSET | 0x31) -#define REG_INT_SOURCE9 (REG_MREG1_OFFSET | 0x32) -#define REG_INT_SOURCE10 (REG_MREG1_OFFSET | 0x33) -#define REG_APEX_CONFIG2 (REG_MREG1_OFFSET | 0x44) -#define REG_APEX_CONFIG3 (REG_MREG1_OFFSET | 0x45) -#define REG_APEX_CONFIG4 (REG_MREG1_OFFSET | 0x46) -#define REG_APEX_CONFIG5 (REG_MREG1_OFFSET | 0x47) -#define REG_APEX_CONFIG9 (REG_MREG1_OFFSET | 0x48) -#define REG_APEX_CONFIG10 (REG_MREG1_OFFSET | 0x49) -#define REG_APEX_CONFIG11 (REG_MREG1_OFFSET | 0x4a) -#define REG_ACCEL_WOM_X_THR (REG_MREG1_OFFSET | 0x4b) -#define REG_ACCEL_WOM_Y_THR (REG_MREG1_OFFSET | 0x4c) -#define REG_ACCEL_WOM_Z_THR (REG_MREG1_OFFSET | 0x4d) -#define REG_OFFSET_USER0 (REG_MREG1_OFFSET | 0x4e) -#define REG_OFFSET_USER1 (REG_MREG1_OFFSET | 0x4f) -#define REG_OFFSET_USER2 (REG_MREG1_OFFSET | 0x50) -#define REG_OFFSET_USER3 (REG_MREG1_OFFSET | 0x51) -#define REG_OFFSET_USER4 (REG_MREG1_OFFSET | 0x52) -#define REG_OFFSET_USER5 (REG_MREG1_OFFSET | 0x53) -#define REG_OFFSET_USER6 (REG_MREG1_OFFSET | 0x54) -#define REG_OFFSET_USER7 (REG_MREG1_OFFSET | 0x55) -#define REG_OFFSET_USER8 (REG_MREG1_OFFSET | 0x56) -#define REG_ST_STATUS1 (REG_MREG1_OFFSET | 0x63) -#define REG_ST_STATUS2 (REG_MREG1_OFFSET | 0x64) -#define REG_FDR_CONFIG (REG_MREG1_OFFSET | 0x66) -#define REG_APEX_CONFIG12 (REG_MREG1_OFFSET | 0x67) - -/* MREG2 */ -#define REG_OTP_CTRL7 (REG_MREG2_OFFSET | 0x06) - -/* MREG3 */ -#define REG_XA_ST_DATA3 (REG_MREG3_OFFSET | 0x00) -#define REG_YA_ST_DATA3 (REG_MREG3_OFFSET | 0x01) -#define REG_ZA_ST_DATA3 (REG_MREG3_OFFSET | 0x02) -#define REG_XG_ST_DATA3 (REG_MREG3_OFFSET | 0x03) -#define REG_YG_ST_DATA3 (REG_MREG3_OFFSET | 0x04) -#define REG_ZG_ST_DATA3 (REG_MREG3_OFFSET | 0x05) - -/* Bank0 REG_MCLK_RDY */ -#define BIT_MCLK_RDY BIT(3) - -/* Bank0 REG_DEVICE_CONFIG */ -#define BIT_SPI_AP_4WIRE BIT(2) -#define BIT_SPI_MODE BIT(0) - -/* Bank0 REG_SIGNAL_PATH_RESET */ -#define BIT_FIFO_FLUSH BIT(2) -#define BIT_SOFT_RESET BIT(4) - -/* Bank0 REG_INST_STATUS */ -#define BIT_STATUS_RESET_DONE_INT BIT(4) - -/* Bank0 REG_INT_CONFIG */ -#define BIT_INT1_POLARITY BIT(0) -#define BIT_INT1_DRIVE_CIRCUIT BIT(1) -#define BIT_INT1_MODE BIT(2) -#define BIT_INT2_POLARITY BIT(3) -#define BIT_INT2_DRIVE_CIRCUIT BIT(4) -#define BIT_INT2_MODE BIT(5) - -/* Bank0 REG_PWR_MGMT_0 */ -#define MASK_ACCEL_MODE GENMASK(1, 0) -#define BIT_ACCEL_MODE_OFF 0x00 -#define BIT_ACCEL_MODE_LPM 0x02 -#define BIT_ACCEL_MODE_LNM 0x03 -#define MASK_GYRO_MODE GENMASK(3, 2) -#define BIT_GYRO_MODE_OFF 0x00 -#define BIT_GYRO_MODE_STBY 0x01 -#define BIT_GYRO_MODE_LNM 0x03 -#define BIT_IDLE BIT(4) -#define BIT_ACCEL_LP_CLK_SEL BIT(7) - -/* Bank0 REG_INT_SOURCE0 */ -#define BIT_INT_AGC_RDY_INT1_EN BIT(0) -#define BIT_INT_FIFO_FULL_INT1_EN BIT(1) -#define BIT_INT_FIFO_THS_INT1_EN BIT(2) -#define BIT_INT_DRDY_INT1_EN BIT(3) -#define BIT_INT_RESET_DONE_INT1_EN BIT(4) -#define BIT_INT_PLL_RDY_INT1_EN BIT(5) -#define BIT_INT_FSYNC_INT1_EN BIT(6) -#define BIT_INT_ST_INT1_EN BIT(7) - -/* Bank0 REG_INT_STATUS_DRDY */ -#define BIT_INT_STATUS_DATA_DRDY BIT(0) - -/* Bank9 REG_INTF_CONFIG1 */ -#define BIT_I3C_SDR_EN BIT(3) -#define BIT_I3C_DDR_EN BIT(2) -#define MASK_CLKSEL GENMASK(1, 0) -#define BIT_CLKSEL_INT_RC 0x00 -#define BIT_CLKSEL_PLL_OR_RC 0x01 -#define BIT_CLKSEL_DISABLE 0x11 - -/* Bank0 REG_INT_STATUS */ -#define BIT_INT_STATUS_AGC_RDY BIT(0) -#define BIT_INT_STATUS_FIFO_FULL BIT(1) -#define BIT_INT_STATUS_FIFO_THS BIT(2) -#define BIT_INT_STATUS_RESET_DONE BIT(4) -#define BIT_INT_STATUS_PLL_RDY BIT(5) -#define BIT_INT_STATUS_FSYNC BIT(6) -#define BIT_INT_STATUS_ST BIT(7) - -/* Bank0 REG_INT_STATUS2 */ -#define BIT_INT_STATUS_WOM_Z BIT(0) -#define BIT_INT_STATUS_WOM_Y BIT(1) -#define BIT_INT_STATUS_WOM_X BIT(2) -#define BIT_INT_STATUS_SMD BIT(3) - -/* Bank0 REG_INT_STATUS3 */ -#define BIT_INT_STATUS_LOWG_DET BIT(1) -#define BIT_INT_STATUS_FF_DET BIT(2) -#define BIT_INT_STATUS_TILT_DET BIT(3) -#define BIT_INT_STATUS_STEP_CNT_OVFL BIT(4) -#define BIT_INT_STATUS_STEP_DET BIT(5) - -/* Bank0 REG_ACCEL_CONFIG0 */ -#define MASK_ACCEL_UI_FS_SEL GENMASK(6, 5) -#define BIT_ACCEL_UI_FS_16 0x00 -#define BIT_ACCEL_UI_FS_8 0x01 -#define BIT_ACCEL_UI_FS_4 0x02 -#define BIT_ACCEL_UI_FS_2 0x03 -#define MASK_ACCEL_ODR GENMASK(3, 0) -#define BIT_ACCEL_ODR_1600 0x05 -#define BIT_ACCEL_ODR_800 0x06 -#define BIT_ACCEL_ODR_400 0x07 -#define BIT_ACCEL_ODR_200 0x08 -#define BIT_ACCEL_ODR_100 0x09 -#define BIT_ACCEL_ODR_50 0x0A -#define BIT_ACCEL_ODR_25 0x0B -#define BIT_ACCEL_ODR_12 0x0C -#define BIT_ACCEL_ODR_6 0x0D -#define BIT_ACCEL_ODR_3 0x0E -#define BIT_ACCEL_ODR_1 0x0F - -/* Bank0 REG_GYRO_CONFIG0 */ -#define MASK_GYRO_UI_FS_SEL GENMASK(6, 5) -#define BIT_GYRO_UI_FS_2000 0x00 -#define BIT_GYRO_UI_FS_1000 0x01 -#define BIT_GYRO_UI_FS_500 0x02 -#define BIT_GYRO_UI_FS_250 0x03 -#define MASK_GYRO_ODR GENMASK(3, 0) -#define BIT_GYRO_ODR_1600 0x05 -#define BIT_GYRO_ODR_800 0x06 -#define BIT_GYRO_ODR_400 0x07 -#define BIT_GYRO_ODR_200 0x08 -#define BIT_GYRO_ODR_100 0x09 -#define BIT_GYRO_ODR_50 0x0A -#define BIT_GYRO_ODR_25 0x0B -#define BIT_GYRO_ODR_12 0x0C - -/* misc. defines */ -#define WHO_AM_I_ICM42670 0x67 -#define MIN_ACCEL_SENS_SHIFT 11 -#define ACCEL_DATA_SIZE 6 -#define GYRO_DATA_SIZE 6 -#define TEMP_DATA_SIZE 2 -#define MCLK_POLL_INTERVAL_US 250 -#define MCLK_POLL_ATTEMPTS 100 -#define SOFT_RESET_TIME_MS 2 /* 1ms + elbow room */ - -#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42670_REG_H_ */ diff --git a/drivers/sensor/tdk/icm42670/icm42670_spi.c b/drivers/sensor/tdk/icm42670/icm42670_spi.c index ce1b7b1148499..22c778c5ee99e 100644 --- a/drivers/sensor/tdk/icm42670/icm42670_spi.c +++ b/drivers/sensor/tdk/icm42670/icm42670_spi.c @@ -1,185 +1,72 @@ /* + * Copyright (c) 2024 TDK Invensense * Copyright (c) 2022 Esco Medical ApS * Copyright (c) 2020 TDK Invensense * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include "icm42670.h" -#include "icm42670_reg.h" +/* + * Bus-specific functionality for ICM42670 accessed via SPI. + */ -#if ICM42670_BUS_SPI -static inline int spi_write_register(const union icm42670_bus *bus, uint8_t reg, uint8_t data) -{ - const struct spi_buf buf[2] = { - { - .buf = ®, - .len = 1, - }, - { - .buf = &data, - .len = 1, - } - }; +#include "icm42670.h" - const struct spi_buf_set tx = { - .buffers = buf, - .count = 2, - }; +#if CONFIG_SPI - return spi_write_dt(&bus->spi, &tx); -} +#include +LOG_MODULE_DECLARE(ICM42670, CONFIG_SENSOR_LOG_LEVEL); -static inline int spi_read_register(const union icm42670_bus *bus, uint8_t reg, uint8_t *data, - size_t len) +static int icm42670_bus_check_spi(const union icm42670_bus *bus) { - uint8_t tx_buffer = REG_SPI_READ_BIT | reg; - - const struct spi_buf tx_buf = { - .buf = &tx_buffer, - .len = 1, - }; - - const struct spi_buf_set tx = { - .buffers = &tx_buf, - .count = 1, - }; - - struct spi_buf rx_buf[2] = { - { - .buf = NULL, - .len = 1, - }, - { - .buf = data, - .len = len, - } - }; - - const struct spi_buf_set rx = { - .buffers = rx_buf, - .count = 2, - }; - - return spi_transceive_dt(&bus->spi, &tx, &rx); + return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV; } -static inline int spi_read_mreg(const union icm42670_bus *bus, uint8_t reg, uint8_t bank, - uint8_t *buf, size_t len) -{ - int res = spi_write_register(bus, REG_BLK_SEL_R, bank); - - if (res) { - return res; - } - - /* reads from MREG registers must be done byte-by-byte */ - for (size_t i = 0; i < len; i++) { - uint8_t addr = reg + i; - - res = spi_write_register(bus, REG_MADDR_R, addr); - - if (res) { - return res; - } - - k_usleep(MREG_R_W_WAIT_US); - res = spi_read_register(bus, REG_M_R, &buf[i], 1); - - if (res) { - return res; - } +static int icm42670_reg_read_spi(const union icm42670_bus *bus, uint8_t start, uint8_t *buf, + uint32_t size) - k_usleep(MREG_R_W_WAIT_US); - } - - return 0; -} - -static inline int spi_write_mreg(const union icm42670_bus *bus, uint8_t reg, uint8_t bank, - uint8_t buf) { - int res = spi_write_register(bus, REG_BLK_SEL_W, bank); - - if (res) { - return res; - } - - res = spi_write_register(bus, REG_MADDR_W, reg); - - if (res) { - return res; + uint8_t cmd[] = {(start | 0x80)}; + const struct spi_buf tx_buf = {.buf = cmd, .len = sizeof(cmd)}; + const struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1}; + struct spi_buf rx_buf[2]; + const struct spi_buf_set rx = {.buffers = rx_buf, .count = ARRAY_SIZE(rx_buf)}; + int ret; + + rx_buf[0].buf = NULL; + rx_buf[0].len = 1; + + rx_buf[1].len = size; + rx_buf[1].buf = buf; + + ret = spi_transceive_dt(&bus->spi, &tx, &rx); + if (ret) { + LOG_ERR("spi_transceive FAIL %d\n", ret); + return ret; } - - res = spi_write_register(bus, REG_M_W, buf); - - if (res) { - return res; - } - - k_usleep(MREG_R_W_WAIT_US); - return 0; } -int icm42670_spi_read(const union icm42670_bus *bus, uint16_t reg, uint8_t *data, size_t len) -{ - int res = 0; - uint8_t bank = FIELD_GET(REG_BANK_MASK, reg); - uint8_t address = FIELD_GET(REG_ADDRESS_MASK, reg); - - if (bank) { - res = spi_read_mreg(bus, address, bank, data, len); - } else { - res = spi_read_register(bus, address, data, len); - } - - return res; -} - -int icm42670_spi_single_write(const union icm42670_bus *bus, uint16_t reg, uint8_t data) -{ - int res = 0; - uint8_t bank = FIELD_GET(REG_BANK_MASK, reg); - uint8_t address = FIELD_GET(REG_ADDRESS_MASK, reg); - - if (bank) { - res = spi_write_mreg(bus, address, bank, data); - } else { - res = spi_write_register(bus, address, data); - } - - return res; -} - -int icm42670_spi_update_register(const union icm42670_bus *bus, uint16_t reg, uint8_t mask, - uint8_t data) +static int icm42670_reg_write_spi(const union icm42670_bus *bus, uint8_t reg, uint8_t *buf, + uint32_t size) { - uint8_t temp = 0; - int res = icm42670_spi_read(bus, reg, &temp, 1); - - if (res) { - return res; + uint8_t cmd[] = {reg & 0x7F}; + const struct spi_buf tx_buf[2] = {{.buf = cmd, .len = sizeof(cmd)}, + {.buf = buf, .len = size}}; + const struct spi_buf_set tx = {.buffers = tx_buf, .count = 2}; + int ret = spi_write_dt(&bus->spi, &tx); + + if (ret) { + LOG_ERR("spi_write FAIL %d\n", ret); + return ret; } - - temp &= ~mask; - temp |= FIELD_PREP(mask, data); - - return icm42670_spi_single_write(bus, reg, temp); -} - -static int icm42670_bus_check_spi(const union icm42670_bus *bus) -{ - return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV; + return 0; } const struct icm42670_bus_io icm42670_bus_io_spi = { .check = icm42670_bus_check_spi, - .read = icm42670_spi_read, - .write = icm42670_spi_single_write, - .update = icm42670_spi_update_register, + .read = icm42670_reg_read_spi, + .write = icm42670_reg_write_spi, }; -#endif /* ICM42670_BUS_SPI */ +#endif /* CONFIG_SPI */ diff --git a/drivers/sensor/tdk/icm42670/icm42670_trigger.c b/drivers/sensor/tdk/icm42670/icm42670_trigger.c index 3d84d884e8049..cfe0f0723ff54 100644 --- a/drivers/sensor/tdk/icm42670/icm42670_trigger.c +++ b/drivers/sensor/tdk/icm42670/icm42670_trigger.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024 TDK Invensense * Copyright (c) 2022 Esco Medical ApS * Copyright (c) 2016 TDK Invensense * @@ -9,7 +10,6 @@ #include #include #include "icm42670.h" -#include "icm42670_reg.h" #include "icm42670_trigger.h" #include @@ -60,7 +60,6 @@ static void icm42670_thread(void *p1, void *p2, void *p3) icm42670_thread_cb(data->dev); } } - #elif defined(CONFIG_ICM42670_TRIGGER_GLOBAL_THREAD) static void icm42670_work_handler(struct k_work *work) @@ -75,7 +74,6 @@ static void icm42670_work_handler(struct k_work *work) int icm42670_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler) { - int res = 0; struct icm42670_data *data = dev->data; const struct icm42670_config *cfg = dev->config; @@ -86,20 +84,22 @@ int icm42670_trigger_set(const struct device *dev, const struct sensor_trigger * icm42670_lock(dev); gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE); - switch (trig->type) { - case SENSOR_TRIG_DATA_READY: + if (trig->type == SENSOR_TRIG_DATA_READY) { data->data_ready_handler = handler; data->data_ready_trigger = trig; - break; - default: - res = -ENOTSUP; - break; +#ifdef CONFIG_TDK_APEX + } else if (trig->type == SENSOR_TRIG_MOTION) { + data->data_ready_handler = handler; + data->data_ready_trigger = trig; +#endif + } else { + return -ENOTSUP; } icm42670_unlock(dev); gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE); - return res; + return 0; } int icm42670_trigger_init(const struct device *dev) @@ -139,24 +139,26 @@ int icm42670_trigger_init(const struct device *dev) data->work.handler = icm42670_work_handler; #endif - return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE); + return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_INACTIVE); } int icm42670_trigger_enable_interrupt(const struct device *dev) { - int res; - const struct icm42670_config *cfg = dev->config; + struct icm42670_data *data = dev->data; + int err = 0; + inv_imu_int1_pin_config_t int1_pin_config; + inv_imu_interrupt_parameter_t config_int = {(inv_imu_interrupt_value)0}; - /* pulse-mode (auto clearing), push-pull and active-high */ - res = cfg->bus_io->write(&cfg->bus, REG_INT_CONFIG, - BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); + /* Set interrupt config */ + int1_pin_config.int_polarity = INT_CONFIG_INT1_POLARITY_HIGH; + int1_pin_config.int_mode = INT_CONFIG_INT1_MODE_PULSED; + int1_pin_config.int_drive = INT_CONFIG_INT1_DRIVE_CIRCUIT_PP; + err |= inv_imu_set_pin_config_int1(&data->driver, &int1_pin_config); - if (res) { - return res; - } + config_int.INV_FIFO_THS = INV_IMU_ENABLE; + err |= inv_imu_set_config_int1(&data->driver, &config_int); - /* enable data ready interrupt on INT1 pin */ - return cfg->bus_io->write(&cfg->bus, REG_INT_SOURCE0, BIT_INT_DRDY_INT1_EN); + return err; } void icm42670_lock(const struct device *dev) diff --git a/include/zephyr/drivers/sensor/icm42670.h b/include/zephyr/drivers/sensor/icm42670.h new file mode 100644 index 0000000000000..9894109fd75d6 --- /dev/null +++ b/include/zephyr/drivers/sensor/icm42670.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_ICM42670_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_ICM42670_H_ + +#include + +/** + * @file + * @brief Extended public API for ICM42670 6-axis MEMS sensor + * + * Some capabilities and operational requirements for this sensor + * cannot be expressed within the sensor driver abstraction. + */ + +/** ICM42670 power mode */ +#define ICM42670_LOW_NOISE_MODE (0) +#define ICM42670_LOW_POWER_MODE (1) + +/** + * @brief Extended sensor attributes for ICM42670 6-axis MEMS sensor + * + * This exposes attributes for the ICM42670 which can be used for + * setting the signal path filtering parameters. + * + * The signal path starts with ADCs for the gyroscope and accelerometer. + * Low-Noise Mode and Low-Power Mode options are available for the + * accelerometer. Only Low-Noise Mode is available for gyroscope. + * In Low-Noise Mode, the ADC output is sent through an Anti-Alias Filter + * (AAF). The AAF is a filter with fixed coefficients (not user configurable), + * also the AAF cannot be bypassed. The AAF is followed by a 1st Order Low Pass + * Filter (LPF) with user selectable filter bandwidth options. + * In Low-Power Mode, the accelerometer ADC output is sent through an Average + * filter, with user configurable average filter setting. + * The output of 1st Order LPF in Low-Noise Mode, or Average filter in Low-Power + * Mode is subject to ODR selection, with user selectable ODR. + */ +enum sensor_attribute_icm42670 { + /** BW filtering */ + + /** Low-pass filter configuration */ + SENSOR_ATTR_BW_FILTER_LPF = SENSOR_ATTR_PRIV_START, + /** Averaging configuration */ + SENSOR_ATTR_AVERAGING, +}; +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_ICM42670_H_ */ diff --git a/include/zephyr/drivers/sensor/tdk_apex.h b/include/zephyr/drivers/sensor/tdk_apex.h new file mode 100644 index 0000000000000..eaa1300a5bbbe --- /dev/null +++ b/include/zephyr/drivers/sensor/tdk_apex.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_TDK_APEX_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_TDK_APEX_H_ + +#include + +/** + * @file + * @brief Extended public API for TDK MEMS sensor + * + * Some capabilities and operational requirements for this sensor + * cannot be expressed within the sensor driver abstraction. + */ + +/** TDK APEX features */ +#define TDK_APEX_PEDOMETER (1) +#define TDK_APEX_TILT (2) +#define TDK_APEX_SMD (3) +#define TDK_APEX_WOM (4) + +/** + * @brief Extended sensor channel for TDK MEMS supportintg APEX features + * + * This exposes sensor channel for the TDK MEMS which can be used for + * getting the APEX features data. + * + * The APEX (Advanced Pedometer and Event Detection – neXt gen) features of + * TDK MEMS consist of: + * ** Pedometer: Tracks step count. + * ** Tilt Detection: Detect the Tilt angle exceeds 35 degrees. + * ** Wake on Motion (WoM): Detects motion when accelerometer samples exceed + * a programmable threshold. This motion event can be used to enable device + * operation from sleep mode. + * ** Significant Motion Detector (SMD): Detects significant motion based on + * accelerometer data. + */ +enum sensor_channel_tdk_apex { + + /** APEX features */ + SENSOR_CHAN_APEX_MOTION = SENSOR_CHAN_PRIV_START, +}; +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_TDK_APEX_H_ */ From 412f8c3aa66cdd186fba347bfd9c757bb36fe562 Mon Sep 17 00:00:00 2001 From: Aurelie Fontaine Date: Thu, 5 Dec 2024 10:55:43 +0100 Subject: [PATCH 3/6] dts: bindings: sensor: Add invensense icm42670 properties Add the power mode, accel and gyro filtering options, and apex features. Add -p and -s compatible. Signed-off-by: Aurelie Fontaine --- dts/bindings/sensor/invensense,icm42670.yaml | 120 +++++++++++++++--- ...i2c.yaml => invensense,icm42670p-i2c.yaml} | 4 +- ...spi.yaml => invensense,icm42670p-spi.yaml} | 4 +- .../sensor/invensense,icm42670s-i2c.yaml | 8 ++ .../sensor/invensense,icm42670s-spi.yaml | 9 ++ 5 files changed, 124 insertions(+), 21 deletions(-) rename dts/bindings/sensor/{invensense,icm42670-i2c.yaml => invensense,icm42670p-i2c.yaml} (65%) rename dts/bindings/sensor/{invensense,icm42670-spi.yaml => invensense,icm42670p-spi.yaml} (67%) create mode 100644 dts/bindings/sensor/invensense,icm42670s-i2c.yaml create mode 100644 dts/bindings/sensor/invensense,icm42670s-spi.yaml diff --git a/dts/bindings/sensor/invensense,icm42670.yaml b/dts/bindings/sensor/invensense,icm42670.yaml index 39fb582e708ed..6b79dcb3034fc 100644 --- a/dts/bindings/sensor/invensense,icm42670.yaml +++ b/dts/bindings/sensor/invensense,icm42670.yaml @@ -1,3 +1,4 @@ +# Copyright (c) 2024 TDK Invensense # Copyright (c) 2022 Esco Medical ApS # Copyright (c) 2020 TDK Invensense # SPDX-License-Identifier: Apache-2.0 @@ -22,17 +23,18 @@ properties: Maps to ACCEL_ODR field in ACCEL_CONFIG0 setting Power-on reset value is 800. enum: - - 1 - - 3 - - 6 - - 12 - - 25 - - 50 - - 100 - - 200 - - 400 - - 800 + - 0 - 1600 + - 800 + - 400 + - 200 + - 100 + - 50 + - 25 + - 12 + - 6 + - 3 + - 1 gyro-hz: type: int @@ -42,14 +44,29 @@ properties: Maps to GYRO_ODR field in GYRO_CONFIG0 setting Power-on reset value is 800. enum: - - 12 - - 25 - - 50 - - 100 - - 200 - - 400 - - 800 + - 0 - 1600 + - 800 + - 400 + - 200 + - 100 + - 50 + - 25 + - 12 + + power-mode: + type: string + default: "low-noise" + description: | + Power mode. + Low power mode is allowed for accelerometer sensor only from + 1.5625Hz to 400Hz. + The default is chosen to support both accelerometer and + gyroscope sensors. + enum: + - "low-noise" + - "low-power" + accel-fs: type: int @@ -64,6 +81,40 @@ properties: - 4 - 2 + accel-avg: + type: int + default: 32 + description: | + Averaging filter setting to create accelerometer output + in accelerometer low power mode. + Maps to ACCEL_UI_AVG field in ACCEL_CONFIG1 setting. + The default corresponds to the reset value of the register field. + enum: + - 2 + - 4 + - 8 + - 16 + - 32 + - 64 + + accel-filt-bw-hz: + type: int + default: 180 + description: | + Accelerometer low pass filter bandwidth frequency (Unit - Hz). + Maps to ACCEL_UI_FILT_BW field in ACCEL_CONFIG1 setting. + The default corresponds to the reset value of the register field. + enum: + - 0 + - 180 + - 121 + - 73 + - 53 + - 34 + - 25 + - 16 + + gyro-fs: type: int required: true @@ -76,3 +127,38 @@ properties: - 1000 - 500 - 250 + + gyro-filt-bw-hz: + type: int + default: 180 + description: | + Gyroscope low pass filter bandwidth frequency (Unit - Hz). + Maps to GYRO_UI_FILT_BW field in GYRO_CONFIG1 setting. + The default corresponds to the reset value of the register field. + enum: + - 0 + - 180 + - 121 + - 73 + - 53 + - 34 + - 25 + - 16 + + apex: + type: string + default: "none" + description: | + APEX (Advanced Pedometer and Event Detection) features. It consists of: + * Pedometer: Tracks step count, and provide details such as the cadence and + the estimated activity type (Walk, Run, Unknown). + * Tilt Detection: Detects the Tilt when tilting the board with an angle of + 30 degrees or more held for 4 seconds. + * Wake on Motion (WoM): Detects motion per axis exceeding 195 mg threshold. + * Significant Motion Detector (SMD): Detects when the user has moved significantly. + enum: + - "none" + - "pedometer" + - "tilt" + - "smd" + - "wom" diff --git a/dts/bindings/sensor/invensense,icm42670-i2c.yaml b/dts/bindings/sensor/invensense,icm42670p-i2c.yaml similarity index 65% rename from dts/bindings/sensor/invensense,icm42670-i2c.yaml rename to dts/bindings/sensor/invensense,icm42670p-i2c.yaml index 37311b44db43a..8a0f2e86b50cf 100644 --- a/dts/bindings/sensor/invensense,icm42670-i2c.yaml +++ b/dts/bindings/sensor/invensense,icm42670p-i2c.yaml @@ -1,8 +1,8 @@ # Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -description: ICM-42670 motion tracking device +description: ICM-42670-P motion tracking device -compatible: "invensense,icm42670" +compatible: "invensense,icm42670p" include: [i2c-device.yaml, "invensense,icm42670.yaml"] diff --git a/dts/bindings/sensor/invensense,icm42670-spi.yaml b/dts/bindings/sensor/invensense,icm42670p-spi.yaml similarity index 67% rename from dts/bindings/sensor/invensense,icm42670-spi.yaml rename to dts/bindings/sensor/invensense,icm42670p-spi.yaml index 069a78eae1f8b..69ea42822f899 100644 --- a/dts/bindings/sensor/invensense,icm42670-spi.yaml +++ b/dts/bindings/sensor/invensense,icm42670p-spi.yaml @@ -2,8 +2,8 @@ # Copyright (c) 2020 TDK Invensense # SPDX-License-Identifier: Apache-2.0 -description: ICM-42670 motion tracking device +description: ICM-42670-P motion tracking device -compatible: "invensense,icm42670" +compatible: "invensense,icm42670p" include: [spi-device.yaml, "invensense,icm42670.yaml"] diff --git a/dts/bindings/sensor/invensense,icm42670s-i2c.yaml b/dts/bindings/sensor/invensense,icm42670s-i2c.yaml new file mode 100644 index 0000000000000..e2ff832d68e7e --- /dev/null +++ b/dts/bindings/sensor/invensense,icm42670s-i2c.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: ICM-42670-S motion tracking device + +compatible: "invensense,icm42670s" + +include: [i2c-device.yaml, "invensense,icm42670.yaml"] diff --git a/dts/bindings/sensor/invensense,icm42670s-spi.yaml b/dts/bindings/sensor/invensense,icm42670s-spi.yaml new file mode 100644 index 0000000000000..5df9d9157e25b --- /dev/null +++ b/dts/bindings/sensor/invensense,icm42670s-spi.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2022 Esco Medical ApS +# Copyright (c) 2020 TDK Invensense +# SPDX-License-Identifier: Apache-2.0 + +description: ICM-42670-S motion tracking device + +compatible: "invensense,icm42670s" + +include: [spi-device.yaml, "invensense,icm42670.yaml"] From a42f4d4909fdfc5b5cc09d4d11d18de0b191afa9 Mon Sep 17 00:00:00 2001 From: Aurelie Fontaine Date: Thu, 5 Dec 2024 18:06:06 +0100 Subject: [PATCH 4/6] samples: sensor: 6DOF motion DRDY generic sample It reports IMU 6-axis accelerometer and gyroscope data using DRDY interrupt. Signed-off-by: Aurelie Fontaine --- .../sensor/6dof_motion_drdy/CMakeLists.txt | 12 ++ samples/sensor/6dof_motion_drdy/README.rst | 56 +++++++++ .../boards/nrf52dk_nrf52832_i2c.overlay | 43 +++++++ .../boards/nrf52dk_nrf52832_spi.overlay | 41 +++++++ samples/sensor/6dof_motion_drdy/prj.conf | 19 +++ samples/sensor/6dof_motion_drdy/sample.yaml | 9 ++ samples/sensor/6dof_motion_drdy/src/main.c | 113 ++++++++++++++++++ 7 files changed, 293 insertions(+) create mode 100644 samples/sensor/6dof_motion_drdy/CMakeLists.txt create mode 100644 samples/sensor/6dof_motion_drdy/README.rst create mode 100644 samples/sensor/6dof_motion_drdy/boards/nrf52dk_nrf52832_i2c.overlay create mode 100644 samples/sensor/6dof_motion_drdy/boards/nrf52dk_nrf52832_spi.overlay create mode 100644 samples/sensor/6dof_motion_drdy/prj.conf create mode 100644 samples/sensor/6dof_motion_drdy/sample.yaml create mode 100644 samples/sensor/6dof_motion_drdy/src/main.c diff --git a/samples/sensor/6dof_motion_drdy/CMakeLists.txt b/samples/sensor/6dof_motion_drdy/CMakeLists.txt new file mode 100644 index 0000000000000..892aaf5ed8add --- /dev/null +++ b/samples/sensor/6dof_motion_drdy/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2024 TDK Invensense +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(6dof_motion_drdy) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/6dof_motion_drdy/README.rst b/samples/sensor/6dof_motion_drdy/README.rst new file mode 100644 index 0000000000000..811259b795d5b --- /dev/null +++ b/samples/sensor/6dof_motion_drdy/README.rst @@ -0,0 +1,56 @@ +.. zephyr:code-sample:: 6dof_motion_drdy + :name: Generic 6DOF Motion Dataready + :relevant-api: sensor_interface + + Get 6-Axis accelerometer and gyroscope data from a sensor (data ready interrupt mode). + +Overview +******** + +This sample application periodically (100 Hz) measures the 6-axis IMU sensor with +temperature, acceleration, and angular velocity, displaying the +values on the console along with a timestamp since startup. +Trigger options could be configured through KConfig. + +Wiring +****** + +This sample uses an external breakout for the sensor. A devicetree +overlay must be provided to identify the 6-axis motion sensor, the SPI or I2C bus interface and the interrupt +sensor GPIO. + +Building and Running +******************** + +This sample supports up to 6-Axis IMU devices. Each device needs +to be aliased as ``6dof-motion-drdyN`` where ``N`` goes from ``0`` to ``9``. For example: + +.. code-block:: devicetree + + / { + aliases { + 6dof-motion-drdy0 = &icm42670p; + }; + }; + +Make sure the aliases are in devicetree, then build and run with: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/6dof_motion_drdy + :board: nrf52dk/nrf52832 + :goals: build flash + +Sample Output +============= + +.. code-block:: console + +Found device "icm42670p@68", getting sensor data +[0:00:01.716]: temp 23.00 Cel accel 0.150839 -0.140065 9.994899 m/s/s gyro -0.001597 0.005859 0.001597 rad/s +[0:00:01.726]: temp 23.00 Cel accel 0.140065 -0.146050 9.988914 m/s/s gyro -0.002663 0.005859 0.003195 rad/s +[0:00:01.736]: temp 23.50 Cel accel 0.146050 -0.130487 9.988914 m/s/s gyro -0.001597 0.006391 0.003195 rad/s +[0:00:01.746]: temp 23.00 Cel accel 0.149642 -0.136473 9.990111 m/s/s gyro -0.002663 0.004261 0.002663 rad/s +[0:00:01.756]: temp 23.00 Cel accel 0.146050 -0.136473 9.979337 m/s/s gyro -0.002130 0.005326 0.001597 rad/s +[0:00:01.766]: temp 23.00 Cel accel 0.136473 -0.147247 9.986519 m/s/s gyro -0.001065 0.005859 0.002663 rad/s + + diff --git a/samples/sensor/6dof_motion_drdy/boards/nrf52dk_nrf52832_i2c.overlay b/samples/sensor/6dof_motion_drdy/boards/nrf52dk_nrf52832_i2c.overlay new file mode 100644 index 0000000000000..24a82484942f8 --- /dev/null +++ b/samples/sensor/6dof_motion_drdy/boards/nrf52dk_nrf52832_i2c.overlay @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Get a node identifier for 6-axis IMU sensor. + */ +/ { + aliases { + 6dof-motion-drdy0 = &icm42670p; + }; +}; + +/* + * Example configuration of a ICM42670-P device on i2c0 compatible with an Arduino I2C bus. + * + * Device address 0x68 is assumed. Your device may have a different + * address; check your device documentation if unsure. + * + * Configure 100Hz IMU data reporting + */ +&arduino_i2c { + status = "okay"; + icm42670p: icm42670p@68 { + compatible = "invensense,icm42670p"; + reg = <0x68>; + int-gpios = <&arduino_header 8 GPIO_ACTIVE_HIGH>; /* D2 */ + accel-hz = <100>; + gyro-hz = <100>; + accel-fs = <16>; + gyro-fs = <2000>; + }; +}; + +/* + * Increase native UART speed to report all IMU data at 100Hz. + */ +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <1000000>; +}; diff --git a/samples/sensor/6dof_motion_drdy/boards/nrf52dk_nrf52832_spi.overlay b/samples/sensor/6dof_motion_drdy/boards/nrf52dk_nrf52832_spi.overlay new file mode 100644 index 0000000000000..d74e8bd092f40 --- /dev/null +++ b/samples/sensor/6dof_motion_drdy/boards/nrf52dk_nrf52832_spi.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024, TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Get a node identifier for 6-axis IMU sensor. + */ +/ { + aliases { + 6dof-motion-drdy0 = &icm42670p; + }; +}; + +/* Example configuration of a ICM42670-P device on spi2 compatible with an Arduino SPI bus. + * + * Configure 100Hz IMU data reporting + */ +&arduino_spi { + status = "okay"; + cs-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */ + icm42670p: icm42670p@0 { + compatible = "invensense,icm42670p"; + reg = <0>; + spi-max-frequency = <1000000>; /* conservatively set to 1MHz */ + int-gpios = <&arduino_header 8 GPIO_ACTIVE_HIGH>; /* D2 */ + accel-hz = <100>; + gyro-hz = <100>; + accel-fs = <16>; + gyro-fs = <2000>; + }; +}; + +/* + * Increase native UART speed to report all IMU data at 100Hz. + */ +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <1000000>; +}; diff --git a/samples/sensor/6dof_motion_drdy/prj.conf b/samples/sensor/6dof_motion_drdy/prj.conf new file mode 100644 index 0000000000000..30d939774836a --- /dev/null +++ b/samples/sensor/6dof_motion_drdy/prj.conf @@ -0,0 +1,19 @@ +# +# Copyright (c) 2024 TDK Invensense +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SENSOR=y +CONFIG_LOG=y +CONFIG_SENSOR_LOG_LEVEL_DBG=n + +# Floating point format support +# Selecting this increases stack size requirements slightly, but increases code size significantly. +CONFIG_CBPRINTF_FP_SUPPORT=y + +# nrf52dk/nrf52832 specific +CONFIG_USE_SEGGER_RTT=n + +# Trigger mode: sample is using interrupt triggering +CONFIG_ICM42670_TRIGGER_OWN_THREAD=y diff --git a/samples/sensor/6dof_motion_drdy/sample.yaml b/samples/sensor/6dof_motion_drdy/sample.yaml new file mode 100644 index 0000000000000..02932da4ebd56 --- /dev/null +++ b/samples/sensor/6dof_motion_drdy/sample.yaml @@ -0,0 +1,9 @@ +sample: + name: 6DOF Motion dataready sample +tests: + sample.sensor.6dof_motion_drdy: + build_only: true + tags: sensors + filter: dt_alias_exists("6dof_motion_drdy0") + integration_platforms: + - nrf52dk/nrf52832 diff --git a/samples/sensor/6dof_motion_drdy/src/main.c b/samples/sensor/6dof_motion_drdy/src/main.c new file mode 100644 index 0000000000000..547c86b51da83 --- /dev/null +++ b/samples/sensor/6dof_motion_drdy/src/main.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024 TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static struct sensor_trigger data_trigger; + +/* Flag set from IMU device irq handler */ +static volatile int irq_from_device; + +/* + * Get a device structure from a devicetree node from alias + * "6dof_motion_drdy0". + */ +static const struct device *get_6dof_motion_device(void) +{ + const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(6dof_motion_drdy0)); + + if (!device_is_ready(dev)) { + printk("\nError: Device \"%s\" is not ready; " + "check the driver initialization logs for errors.\n", + dev->name); + return NULL; + } + + printk("Found device \"%s\", getting sensor data\n", dev->name); + return dev; +} + +static const char *now_str(void) +{ + static char buf[16]; /* ...HH:MM:SS.MMM */ + uint32_t now = k_uptime_get_32(); + unsigned int ms = now % MSEC_PER_SEC; + unsigned int s; + unsigned int min; + unsigned int h; + + now /= MSEC_PER_SEC; + s = now % 60U; + now /= 60U; + min = now % 60U; + now /= 60U; + h = now; + + snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u", h, min, s, ms); + return buf; +} + +static void handle_6dof_motion_drdy(const struct device *dev, const struct sensor_trigger *trig) +{ + if (trig->type == SENSOR_TRIG_DATA_READY) { + int rc = sensor_sample_fetch_chan(dev, trig->chan); + + if (rc < 0) { + printf("sample fetch failed: %d\n", rc); + printf("cancelling trigger due to failure: %d\n", rc); + (void)sensor_trigger_set(dev, trig, NULL); + return; + } else if (rc == 0) { + irq_from_device = 1; + } + } +} + +int main(void) +{ + const struct device *dev = get_6dof_motion_device(); + struct sensor_value accel[3]; + struct sensor_value gyro[3]; + struct sensor_value temperature; + + if (dev == NULL) { + return 0; + } + + data_trigger = (struct sensor_trigger){ + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + if (sensor_trigger_set(dev, &data_trigger, handle_6dof_motion_drdy) < 0) { + printf("Cannot configure data trigger!!!\n"); + return 0; + } + + k_sleep(K_MSEC(1000)); + + while (1) { + + if (irq_from_device) { + sensor_channel_get(dev, SENSOR_CHAN_ACCEL_XYZ, accel); + sensor_channel_get(dev, SENSOR_CHAN_GYRO_XYZ, gyro); + sensor_channel_get(dev, SENSOR_CHAN_DIE_TEMP, &temperature); + + printf("[%s]: temp %.2f Cel " + " accel %f %f %f m/s/s " + " gyro %f %f %f rad/s\n", + now_str(), sensor_value_to_double(&temperature), + sensor_value_to_double(&accel[0]), sensor_value_to_double(&accel[1]), + sensor_value_to_double(&accel[2]), sensor_value_to_double(&gyro[0]), + sensor_value_to_double(&gyro[1]), sensor_value_to_double(&gyro[2])); + irq_from_device = 0; + } + } + return 0; +} From 38c4fbc01f199b248246206c92d48f811a038ff1 Mon Sep 17 00:00:00 2001 From: Aurelie Fontaine Date: Thu, 5 Dec 2024 18:06:28 +0100 Subject: [PATCH 5/6] samples: sensor: TDK APEX generic sample It reports Advanced Pedometer and Event Detection features, such as Pedometer, Tilt detection, Wake on Motion and Significant Motion Detector. Device tree options. Signed-off-by: Aurelie Fontaine --- samples/sensor/tdk_apex/CMakeLists.txt | 12 ++ samples/sensor/tdk_apex/README.rst | 134 ++++++++++++++++ .../boards/nrf52dk_nrf52832_i2c.overlay | 34 ++++ .../boards/nrf52dk_nrf52832_spi.overlay | 33 ++++ samples/sensor/tdk_apex/prj.conf | 19 +++ samples/sensor/tdk_apex/sample.yaml | 9 ++ samples/sensor/tdk_apex/src/main.c | 150 ++++++++++++++++++ 7 files changed, 391 insertions(+) create mode 100644 samples/sensor/tdk_apex/CMakeLists.txt create mode 100644 samples/sensor/tdk_apex/README.rst create mode 100644 samples/sensor/tdk_apex/boards/nrf52dk_nrf52832_i2c.overlay create mode 100644 samples/sensor/tdk_apex/boards/nrf52dk_nrf52832_spi.overlay create mode 100644 samples/sensor/tdk_apex/prj.conf create mode 100644 samples/sensor/tdk_apex/sample.yaml create mode 100644 samples/sensor/tdk_apex/src/main.c diff --git a/samples/sensor/tdk_apex/CMakeLists.txt b/samples/sensor/tdk_apex/CMakeLists.txt new file mode 100644 index 0000000000000..16fbf44e810ff --- /dev/null +++ b/samples/sensor/tdk_apex/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2024 TDK Invensense +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(tdk_apex) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/tdk_apex/README.rst b/samples/sensor/tdk_apex/README.rst new file mode 100644 index 0000000000000..9d6f9c20d13dc --- /dev/null +++ b/samples/sensor/tdk_apex/README.rst @@ -0,0 +1,134 @@ +.. zephyr:code-sample:: tdk_apex + :name: TDK Advanced Pedometer and Event Detection (APEX) + :relevant-api: sensor_interface + + Get TDK APEX event detection (trigger mode). + +Overview +******** + +This sample application shows how to use the APEX (Advanced Pedometer +and Event Detection) features of TDK Invensense sensors. It consists of: +** Pedometer: Tracks step count, and provide details such as the cadence +and the estimated activity type (Walk, Run, Unknown). +** Tilt Detection: Detects the Tilt when tilting the board with an angle +of 30 degrees or more. The tilt event is generated when the +position is held for 4 seconds. +** Wake on Motion (WoM): Detects motion per axis exceeding 195 mg threshold. +** Significant Motion Detector (SMD): Detects when the user has moved +significantly. +APEX features support are configured through devicetree. + +References +********** + + - https://invensense.tdk.com/download-pdf/an-000271-icm-42607x-and-icm-42670x-apex-motion-functions-description-and-usage/ + +Driver configuration +******************** + +The APEX is based on accelerometer data only. The TDK Sensor driver configures +accelerometer low power mode and the APEX operating frequency (25Hz or 50Hz). + +Wiring +******* + +This sample uses an external breakout for the sensor. A devicetree +overlay must be provided to identify the TDK sensor, the SPI or I2C bus interface and the interrupt +sensor GPIO. + +Building and Running +******************** + +This sample supports TDK IMU devices. Each device needs +to be aliased as ``tdk-apex-sensorN`` where ``N`` goes from ``0`` to ``9``. For example: + +.. code-block:: devicetree + + / { + aliases { + tdk-apex-sensor0 = &icm42670p; + }; + }; + +This sample supports APEX feature of TDK device. It needs to be specified as bellow: + +.. code-block:: devicetree + + icm42670p: icm42670p@0 { + apex = "pedometer"; + } + +Make sure the apex feature used is in devicetree, then build and run with: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/tdk_apex + :board: nrf52dk/nrf52832 + :goals: build flash + +Sample Output +============= + +.. code-block:: devicetree + + icm42670p: icm42670p@0 { + apex = "pedometer"; + } + +.. code-block:: console + + Found device "icm42670p@68", getting sensor data + [0:00:09.287]: STEP_DET count: 6 steps cadence: 2.0 steps/s activity: Unknown + [0:00:09.689]: STEP_DET count: 7 steps cadence: 2.1 steps/s activity: Walk + [0:00:10.051]: STEP_DET count: 8 steps cadence: 2.2 steps/s activity: Walk + [0:00:10.433]: STEP_DET count: 9 steps cadence: 2.2 steps/s activity: Walk + [0:00:10.835]: STEP_DET count: 10 steps cadence: 2.3 steps/s activity: Walk + + + +.. code-block:: devicetree + + icm42670p: icm42670p@0 { + apex = "tilt"; + } + +.. code-block:: console + + Found device "icm42670p@68", getting sensor data + [0:00:15.249]: TILT + [0:00:21.479]: TILT + [0:00:26.765]: TILT + + + +.. code-block:: devicetree + + icm42670p: icm42670p@0 { + apex = "wom"; + } + +.. code-block:: console + + Found device "icm42670p@68", getting sensor data + [0:00:02.555]: WOM x=1 y=0 z=1 + [0:00:02.636]: WOM x=0 y=0 z=1 + [0:00:02.797]: WOM x=0 y=1 z=0 + [0:00:02.877]: WOM x=0 y=0 z=1 + [0:00:02.957]: WOM x=1 y=1 z=1 + + + +.. code-block:: devicetree + + icm42670p: icm42670p@0 { + apex = "smd"; + } + +.. code-block:: console + + Found device "icm42670@68", getting sensor data + [0:00:04.622]: SMD + [0:00:05.084]: SMD + [0:00:05.566]: SMD + + diff --git a/samples/sensor/tdk_apex/boards/nrf52dk_nrf52832_i2c.overlay b/samples/sensor/tdk_apex/boards/nrf52dk_nrf52832_i2c.overlay new file mode 100644 index 0000000000000..8c9056772605e --- /dev/null +++ b/samples/sensor/tdk_apex/boards/nrf52dk_nrf52832_i2c.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Get a node identifier for TDK IMU sensor supporting APEX feature. + */ +/ { + aliases { + tdk-apex-sensor0 = &icm42670p; + }; +}; + +/* + * Example configuration of a ICM42670-P device on i2c0 compatible with an Arduino I2C bus. + * + * Device address 0x68 is assumed. Your device may have a different + * address; check your device documentation if unsure. + */ +&arduino_i2c { + status = "okay"; + icm42670p: icm42670p@68 { + compatible = "invensense,icm42670p"; + reg = <0x68>; + int-gpios = <&arduino_header 8 GPIO_ACTIVE_HIGH>; /* D2 */ + accel-hz = <50>; + gyro-hz = <50>; + accel-fs = <16>; + gyro-fs = <2000>; + apex = "pedometer"; + }; +}; diff --git a/samples/sensor/tdk_apex/boards/nrf52dk_nrf52832_spi.overlay b/samples/sensor/tdk_apex/boards/nrf52dk_nrf52832_spi.overlay new file mode 100644 index 0000000000000..a7976d29ed2ac --- /dev/null +++ b/samples/sensor/tdk_apex/boards/nrf52dk_nrf52832_spi.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Get a node identifier for TDK IMU sensor supporting APEX feature. + */ +/ { + aliases { + tdk-apex-sensor0 = &icm42670p; + }; +}; + +/* + * Example configuration of a ICM42670-P device on spi2 compatible with an Arduino SPI bus. + */ +&arduino_spi { + status = "okay"; + cs-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */ + icm42670p: icm42670p@0 { + compatible = "invensense,icm42670p"; + reg = <0>; + spi-max-frequency = <1000000>; /* conservatively set to 1MHz */ + int-gpios = <&arduino_header 8 GPIO_ACTIVE_HIGH>; /* D2 */ + accel-hz = <50>; + gyro-hz = <50>; + accel-fs = <16>; + gyro-fs = <2000>; + apex = "pedometer"; + }; +}; diff --git a/samples/sensor/tdk_apex/prj.conf b/samples/sensor/tdk_apex/prj.conf new file mode 100644 index 0000000000000..30d939774836a --- /dev/null +++ b/samples/sensor/tdk_apex/prj.conf @@ -0,0 +1,19 @@ +# +# Copyright (c) 2024 TDK Invensense +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SENSOR=y +CONFIG_LOG=y +CONFIG_SENSOR_LOG_LEVEL_DBG=n + +# Floating point format support +# Selecting this increases stack size requirements slightly, but increases code size significantly. +CONFIG_CBPRINTF_FP_SUPPORT=y + +# nrf52dk/nrf52832 specific +CONFIG_USE_SEGGER_RTT=n + +# Trigger mode: sample is using interrupt triggering +CONFIG_ICM42670_TRIGGER_OWN_THREAD=y diff --git a/samples/sensor/tdk_apex/sample.yaml b/samples/sensor/tdk_apex/sample.yaml new file mode 100644 index 0000000000000..5b266cc8104de --- /dev/null +++ b/samples/sensor/tdk_apex/sample.yaml @@ -0,0 +1,9 @@ +sample: + name: TDK Sensor APEX sample +tests: + sample.sensor.icm42670.apex: + build_only: true + tags: sensors + filter: dt_alias_exists("tdk_apex_sensor0") + integration_platforms: + - nrf52dk/nrf52832 diff --git a/samples/sensor/tdk_apex/src/main.c b/samples/sensor/tdk_apex/src/main.c new file mode 100644 index 0000000000000..09e1cc7a0455c --- /dev/null +++ b/samples/sensor/tdk_apex/src/main.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2024 TDK Invensense + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +static struct sensor_trigger data_trigger; + +/* Flag set from IMU device irq handler */ +static volatile int irq_from_device; + +/* + * Get a device structure from a devicetree node from alias + * "tdk_apex_sensor0". + */ +static const struct device *get_tdk_apex_device(void) +{ + const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(tdk_apex_sensor0)); + + if (!device_is_ready(dev)) { + printk("\nError: Device \"%s\" is not ready; " + "check the driver initialization logs for errors.\n", + dev->name); + return NULL; + } + + printk("Found device \"%s\", getting sensor data\n", dev->name); + return dev; +} + +static const char *now_str(void) +{ + static char buf[16]; /* ...HH:MM:SS.MMM */ + uint32_t now = k_uptime_get_32(); + unsigned int ms = now % MSEC_PER_SEC; + unsigned int s; + unsigned int min; + unsigned int h; + + now /= MSEC_PER_SEC; + s = now % 60U; + now /= 60U; + min = now % 60U; + now /= 60U; + h = now; + + snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u", h, min, s, ms); + return buf; +} + +static void handle_tdk_apex_drdy(const struct device *dev, const struct sensor_trigger *trig) +{ + if (trig->type == SENSOR_TRIG_MOTION) { + int rc = sensor_sample_fetch_chan(dev, trig->chan); + + if (rc < 0) { + printf("sample fetch failed: %d\n", rc); + printf("cancelling trigger due to failure: %d\n", rc); + (void)sensor_trigger_set(dev, trig, NULL); + return; + } else if (rc == 0) { + irq_from_device = 1; + } + } +} + +int main(void) +{ + const struct device *dev = get_tdk_apex_device(); + struct sensor_value apex_mode; + + if (dev == NULL) { + return 0; + } + + sensor_attr_get(dev, SENSOR_CHAN_APEX_MOTION, SENSOR_ATTR_CONFIGURATION, &apex_mode); + if (apex_mode.val1 == TDK_APEX_PEDOMETER) { + printf("Pedometer data sample.\n"); + } else if (apex_mode.val1 == TDK_APEX_TILT) { + printf("Tilt data sample.\n"); + } else if (apex_mode.val1 == TDK_APEX_WOM) { + printf("WOM data sample.\n"); + } else if (apex_mode.val1 == TDK_APEX_SMD) { + printf("SMD data sample.\n"); + } + apex_mode.val2 = 0; + sensor_attr_set(dev, SENSOR_CHAN_APEX_MOTION, SENSOR_ATTR_CONFIGURATION, &apex_mode); + + data_trigger = (struct sensor_trigger){ + .type = SENSOR_TRIG_MOTION, + .chan = SENSOR_CHAN_APEX_MOTION, + }; + if (sensor_trigger_set(dev, &data_trigger, handle_tdk_apex_drdy) < 0) { + printf("Cannot configure data trigger!!!\n"); + return 0; + } + + printf("Configured for APEX data collecting.\n"); + + k_sleep(K_MSEC(1000)); + + while (1) { + + if (irq_from_device) { + if (apex_mode.val1 == TDK_APEX_PEDOMETER) { + struct sensor_value apex_pedometer[3]; + + sensor_channel_get(dev, SENSOR_CHAN_APEX_MOTION, apex_pedometer); + + printf("[%s]: STEP_DET count: %d steps cadence: %.1f steps/s " + "activity: %s\n", + now_str(), apex_pedometer[0].val1, + sensor_value_to_double(&apex_pedometer[2]), + apex_pedometer[1].val1 == 1 ? "Walk" + : apex_pedometer[1].val1 == 2 ? "Run" + : "Unknown"); + } else if (apex_mode.val1 == TDK_APEX_TILT) { + struct sensor_value apex_tilt; + + sensor_channel_get(dev, SENSOR_CHAN_APEX_MOTION, &apex_tilt); + + printf("[%s]: %s\n", now_str(), + apex_tilt.val1 ? "TILT" : "Unknown trig"); + } else if (apex_mode.val1 == TDK_APEX_WOM) { + struct sensor_value apex_wom[3]; + + sensor_channel_get(dev, SENSOR_CHAN_APEX_MOTION, apex_wom); + + printf("[%s]: WOM x=%d y=%d z=%d\n", now_str(), apex_wom[0].val1, + apex_wom[1].val1, apex_wom[2].val1); + } else if (apex_mode.val1 == TDK_APEX_SMD) { + struct sensor_value apex_smd; + + sensor_channel_get(dev, SENSOR_CHAN_APEX_MOTION, &apex_smd); + + printf("[%s]: %s\n", now_str(), + apex_smd.val1 ? "SMD" : "Unknown trig"); + } + irq_from_device = 0; + } + } + return 0; +} From 5a1c84607865fcb8328f2354487e1e38ae71b128 Mon Sep 17 00:00:00 2001 From: Aurelie Fontaine Date: Thu, 5 Dec 2024 18:06:42 +0100 Subject: [PATCH 6/6] tests: sensor: update sensor compatible icm42670p Update i2c and spi dtsi test to comply with new compatible icm42670p. Signed-off-by: Aurelie Fontaine --- tests/drivers/build_all/sensor/i2c.dtsi | 4 ++-- tests/drivers/build_all/sensor/spi.dtsi | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 7b5ef3e9294bf..9b7ad2149dcd0 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -1039,8 +1039,8 @@ test_i2c_lsm9ds1: lsm9ds1@92 { reg = <0x92>; }; -test_i2c_icm42670: icm42670@93 { - compatible = "invensense,icm42670"; +test_i2c_icm42670p: icm42670p@93 { + compatible = "invensense,icm42670p"; reg = <0x93>; int-gpios = <&test_gpio 0 0>; accel-hz = <800>; diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index b03e5c028dbda..6f48188a2411c 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -178,8 +178,8 @@ test_spi_i3g4250d: i3g4250d@17 { spi-max-frequency = <0>; }; -test_spi_icm42670: icm42670@18 { - compatible = "invensense,icm42670"; +test_spi_icm42670p: icm42670p@18 { + compatible = "invensense,icm42670p"; reg = <0x18>; spi-max-frequency = <0>; int-gpios = <&test_gpio 0 0>;