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 <aurelie.fontaine@tdk.com>
This commit is contained in:
parent
98dc480603
commit
8a0469dc4f
11 changed files with 1230 additions and 998 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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 <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#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_ */
|
||||
|
|
|
|||
177
drivers/sensor/tdk/icm42670/icm42670_apex.c
Normal file
177
drivers/sensor/tdk/icm42670/icm42670_apex.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
return i2c_burst_read_dt(&bus->i2c, reg, buf, size);
|
||||
}
|
||||
|
||||
static int icm42670_reg_read_i2c(const union icm42670_bus *bus, uint16_t reg, uint8_t *data,
|
||||
size_t len)
|
||||
static int icm42670_reg_write_i2c(const union icm42670_bus *bus, uint8_t reg, uint8_t *buf,
|
||||
uint32_t size)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static int icm42670_reg_update_i2c(const union icm42670_bus *bus, uint16_t reg, uint8_t mask,
|
||||
uint8_t val)
|
||||
{
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -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 <zephyr/sys/util.h>
|
||||
|
||||
/* 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_ */
|
||||
|
|
@ -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 <zephyr/kernel.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
/*
|
||||
* Bus-specific functionality for ICM42670 accessed via SPI.
|
||||
*/
|
||||
|
||||
#include "icm42670.h"
|
||||
#include "icm42670_reg.h"
|
||||
|
||||
#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,
|
||||
}
|
||||
};
|
||||
#if CONFIG_SPI
|
||||
|
||||
const struct spi_buf_set tx = {
|
||||
.buffers = buf,
|
||||
.count = 2,
|
||||
};
|
||||
|
||||
return spi_write_dt(&bus->spi, &tx);
|
||||
}
|
||||
|
||||
static inline int spi_read_register(const union icm42670_bus *bus, uint8_t reg, uint8_t *data,
|
||||
size_t len)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uint8_t temp = 0;
|
||||
int res = icm42670_spi_read(bus, reg, &temp, 1);
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
temp &= ~mask;
|
||||
temp |= FIELD_PREP(mask, data);
|
||||
|
||||
return icm42670_spi_single_write(bus, reg, temp);
|
||||
}
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_DECLARE(ICM42670, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static int icm42670_bus_check_spi(const union icm42670_bus *bus)
|
||||
{
|
||||
return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static int icm42670_reg_read_spi(const union icm42670_bus *bus, uint8_t start, uint8_t *buf,
|
||||
uint32_t size)
|
||||
|
||||
{
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icm42670_reg_write_spi(const union icm42670_bus *bus, uint8_t reg, uint8_t *buf,
|
||||
uint32_t size)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -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 <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include "icm42670.h"
|
||||
#include "icm42670_reg.h"
|
||||
#include "icm42670_trigger.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
50
include/zephyr/drivers/sensor/icm42670.h
Normal file
50
include/zephyr/drivers/sensor/icm42670.h
Normal file
|
|
@ -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 <zephyr/drivers/sensor.h>
|
||||
|
||||
/**
|
||||
* @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_ */
|
||||
47
include/zephyr/drivers/sensor/tdk_apex.h
Normal file
47
include/zephyr/drivers/sensor/tdk_apex.h
Normal file
|
|
@ -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 <zephyr/drivers/sensor.h>
|
||||
|
||||
/**
|
||||
* @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_ */
|
||||
Loading…
Reference in a new issue