blob: 6caff216ae4da0f6fcf3cc22ab45a9ab0ec27a97 [file] [log] [blame]
/*
* Copyright (c) 2022 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_H_
#define ZEPHYR_DRIVERS_SENSOR_ICM42688_H_
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
#include <stdlib.h>
/**
* @brief Accelerometer power modes
*/
enum icm42688_accel_mode {
ICM42688_ACCEL_OFF,
ICM42688_ACCEL_LP = 2,
ICM42688_ACCEL_LN = 3,
};
/**
* @brief Gyroscope power modes
*/
enum icm42688_gyro_mode {
ICM42688_GYRO_OFF,
ICM42688_GYRO_STANDBY,
ICM42688_GYRO_LN = 3,
};
/**
* @brief Accelerometer scale options
*/
enum icm42688_accel_fs {
ICM42688_ACCEL_FS_16G,
ICM42688_ACCEL_FS_8G,
ICM42688_ACCEL_FS_4G,
ICM42688_ACCEL_FS_2G,
};
/**
* @brief Gyroscope scale options
*/
enum icm42688_gyro_fs {
ICM42688_GYRO_FS_2000,
ICM42688_GYRO_FS_1000,
ICM42688_GYRO_FS_500,
ICM42688_GYRO_FS_250,
ICM42688_GYRO_FS_125,
ICM42688_GYRO_FS_62_5,
ICM42688_GYRO_FS_31_25,
ICM42688_GYRO_FS_15_625,
};
/**
* @brief Accelerometer data rate options
*/
enum icm42688_accel_odr {
ICM42688_ACCEL_ODR_32000 = 1,
ICM42688_ACCEL_ODR_16000,
ICM42688_ACCEL_ODR_8000,
ICM42688_ACCEL_ODR_4000,
ICM42688_ACCEL_ODR_2000,
ICM42688_ACCEL_ODR_1000,
ICM42688_ACCEL_ODR_200,
ICM42688_ACCEL_ODR_100,
ICM42688_ACCEL_ODR_50,
ICM42688_ACCEL_ODR_25,
ICM42688_ACCEL_ODR_12_5,
ICM42688_ACCEL_ODR_6_25,
ICM42688_ACCEL_ODR_3_125,
ICM42688_ACCEL_ODR_1_5625,
ICM42688_ACCEL_ODR_500,
};
/**
* @brief Gyroscope data rate options
*/
enum icm42688_gyro_odr {
ICM42688_GYRO_ODR_32000 = 1,
ICM42688_GYRO_ODR_16000,
ICM42688_GYRO_ODR_8000,
ICM42688_GYRO_ODR_4000,
ICM42688_GYRO_ODR_2000,
ICM42688_GYRO_ODR_1000,
ICM42688_GYRO_ODR_200,
ICM42688_GYRO_ODR_100,
ICM42688_GYRO_ODR_50,
ICM42688_GYRO_ODR_25,
ICM42688_GYRO_ODR_12_5,
ICM42688_GYRO_ODR_500 = 0xF
};
/**
* @brief All sensor configuration options
*/
struct icm42688_cfg {
enum icm42688_accel_mode accel_mode;
enum icm42688_accel_fs accel_fs;
enum icm42688_accel_odr accel_odr;
/* TODO accel signal processing options */
enum icm42688_gyro_mode gyro_mode;
enum icm42688_gyro_fs gyro_fs;
enum icm42688_gyro_odr gyro_odr;
/* TODO gyro signal processing options */
bool temp_dis;
/* TODO temp signal processing options */
/* TODO timestamp options */
bool fifo_en;
uint16_t fifo_wm;
bool fifo_hires;
/* TODO additional FIFO options */
/* TODO interrupt options */
};
/**
* @brief Device data (struct device)
*/
struct icm42688_dev_data {
struct icm42688_cfg cfg;
};
/**
* @brief Device config (struct device)
*/
struct icm42688_dev_cfg {
struct spi_dt_spec spi;
struct gpio_dt_spec gpio_int1;
struct gpio_dt_spec gpio_int2;
};
/**
* @brief Reset the sensor
*
* @param dev icm42688 device pointer
*
* @retval 0 success
* @retval -EINVAL Reset status or whoami register returned unexpected value.
*/
int icm42688_reset(const struct device *dev);
/**
* @brief (Re)Configure the sensor with the given configuration
*
* @param dev icm42688 device pointer
* @param cfg icm42688_cfg pointer
*
* @retval 0 success
* @retval -errno Error
*/
int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg);
/**
* @brief Reads all channels
*
* Regardless of what is enabled/disabled this reads all data registers
* as the time to read the 14 bytes at 1MHz is going to be 112 us which
* is less time than a SPI transaction takes to setup typically.
*
* @param dev icm42688 device pointer
* @param buf 14 byte buffer to store data values (7 channels, 2 bytes each)
*
* @retval 0 success
* @retval -errno Error
*/
int icm42688_read_all(const struct device *dev, uint8_t data[14]);
/**
* @brief Convert icm42688 accelerometer value to useful g values
*
* @param cfg icm42688_cfg current device configuration
* @param in raw data value in int32_t format
* @param out_g whole G's output in int32_t
* @param out_ug micro (1/1000000) of a G output as uint32_t
*/
static inline void icm42688_accel_g(struct icm42688_cfg *cfg, int32_t in, int32_t *out_g,
uint32_t *out_ug)
{
int32_t sensitivity = 0; /* value equivalent for 1g */
switch (cfg->accel_fs) {
case ICM42688_ACCEL_FS_2G:
sensitivity = 16384;
break;
case ICM42688_ACCEL_FS_4G:
sensitivity = 8192;
break;
case ICM42688_ACCEL_FS_8G:
sensitivity = 4096;
break;
case ICM42688_ACCEL_FS_16G:
sensitivity = 2048;
break;
}
/* Whole g's */
*out_g = in / sensitivity;
/* Micro g's */
*out_ug = ((abs(in) - (abs((*out_g)) * sensitivity)) * 1000000) / sensitivity;
}
/**
* @brief Convert icm42688 gyroscope value to useful deg/s values
*
* @param cfg icm42688_cfg current device configuration
* @param in raw data value in int32_t format
* @param out_dps whole deg/s output in int32_t
* @param out_udps micro (1/1000000) deg/s as uint32_t
*/
static inline void icm42688_gyro_dps(struct icm42688_cfg *cfg, int32_t in, int32_t *out_dps,
uint32_t *out_udps)
{
int64_t sensitivity = 0; /* value equivalent for 10x gyro reading deg/s */
switch (cfg->gyro_fs) {
case ICM42688_GYRO_FS_2000:
sensitivity = 164;
break;
case ICM42688_GYRO_FS_1000:
sensitivity = 328;
break;
case ICM42688_GYRO_FS_500:
sensitivity = 655;
break;
case ICM42688_GYRO_FS_250:
sensitivity = 1310;
break;
case ICM42688_GYRO_FS_125:
sensitivity = 2620;
break;
case ICM42688_GYRO_FS_62_5:
sensitivity = 5243;
break;
case ICM42688_GYRO_FS_31_25:
sensitivity = 10486;
break;
case ICM42688_GYRO_FS_15_625:
sensitivity = 20972;
break;
}
int32_t in10 = in * 10;
/* Whole deg/s */
*out_dps = in10 / sensitivity;
/* Micro deg/s */
*out_udps = ((int64_t)(llabs(in10) - (llabs((*out_dps)) * sensitivity)) * 1000000LL) /
sensitivity;
}
/**
* @brief Convert icm42688 accelerometer value to useful m/s^2 values
*
* @param cfg icm42688_cfg current device configuration
* @param in raw data value in int32_t format
* @param out_ms meters/s^2 (whole) output in int32_t
* @param out_ums micrometers/s^2 output as uint32_t
*/
static inline void icm42688_accel_ms(struct icm42688_cfg *cfg, int32_t in, int32_t *out_ms,
uint32_t *out_ums)
{
int64_t sensitivity = 0; /* value equivalent for 1g */
switch (cfg->accel_fs) {
case ICM42688_ACCEL_FS_2G:
sensitivity = 16384;
break;
case ICM42688_ACCEL_FS_4G:
sensitivity = 8192;
break;
case ICM42688_ACCEL_FS_8G:
sensitivity = 4096;
break;
case ICM42688_ACCEL_FS_16G:
sensitivity = 2048;
break;
}
/* Convert to micrometers/s^2 */
int64_t in_ms = in * SENSOR_G;
/* meters/s^2 whole values */
*out_ms = in_ms / (sensitivity * 1000000LL);
/* micrometers/s^2 */
*out_ums = ((llabs(in_ms) - (llabs(*out_ms) * sensitivity * 1000000LL)) / sensitivity);
}
/**
* @brief Convert icm42688 gyroscope value to useful rad/s values
*
* @param cfg icm42688_cfg current device configuration
* @param in raw data value in int32_t format
* @param out_rads whole rad/s output in int32_t
* @param out_urads microrad/s as uint32_t
*/
static inline void icm42688_gyro_rads(struct icm42688_cfg *cfg, int32_t in, int32_t *out_rads,
uint32_t *out_urads)
{
int64_t sensitivity = 0; /* value equivalent for 10x gyro reading deg/s */
switch (cfg->gyro_fs) {
case ICM42688_GYRO_FS_2000:
sensitivity = 164;
break;
case ICM42688_GYRO_FS_1000:
sensitivity = 328;
break;
case ICM42688_GYRO_FS_500:
sensitivity = 655;
break;
case ICM42688_GYRO_FS_250:
sensitivity = 1310;
break;
case ICM42688_GYRO_FS_125:
sensitivity = 2620;
break;
case ICM42688_GYRO_FS_62_5:
sensitivity = 5243;
break;
case ICM42688_GYRO_FS_31_25:
sensitivity = 10486;
break;
case ICM42688_GYRO_FS_15_625:
sensitivity = 20972;
break;
}
int64_t in10_rads = (int64_t)in * SENSOR_PI * 10LL;
/* Whole rad/s */
*out_rads = in10_rads / (sensitivity * 180LL * 1000000LL);
/* microrad/s */
*out_urads = ((llabs(in10_rads) - (llabs((*out_rads)) * sensitivity * 180LL * 1000000LL))) /
(sensitivity * 180LL);
}
/**
* @brief Convert icm42688 temp value to useful celsius values
*
* @param cfg icm42688_cfg current device configuration
* @param in raw data value in int32_t format
* @param out_c whole celsius output in int32_t
* @param out_uc micro (1/1000000) celsius as uint32_t
*/
static inline void icm42688_temp_c(int32_t in, int32_t *out_c, uint32_t *out_uc)
{
int64_t sensitivity = 13248; /* value equivalent for x100 1c */
int64_t in100 = in * 100;
/* Whole celsius */
*out_c = in100 / sensitivity;
/* Micro celsius */
*out_uc = ((llabs(in100) - (llabs(*out_c)) * sensitivity) * 1000000LL) / sensitivity;
/* Shift whole celsius 25 degress */
*out_c = *out_c + 25;
}
#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_H_ */