Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/sensors/icm42670/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.3")
set(REQ esp_driver_i2c)
set(REQ esp_driver_i2c esp_driver_spi)
else()
set(REQ driver)
endif()
Expand Down
6 changes: 1 addition & 5 deletions components/sensors/icm42670/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Component Registry](https://components.espressif.com/components/espressif/icm42670/badge.svg)](https://components.espressif.com/components/espressif/icm42670)
![maintenance-status](https://img.shields.io/badge/maintenance-passively--maintained-yellowgreen.svg)

C driver for Invensense ICM42607/ICM42670 6-axis gyroscope and accelerometer based on I2C communication.
C driver for Invensense ICM42607/ICM42670 6-axis gyroscope and accelerometer based on I2C/SPI communication.

## Features

Expand All @@ -12,10 +12,6 @@ C driver for Invensense ICM42607/ICM42670 6-axis gyroscope and accelerometer bas
- Configure gyroscope and accelerometer sensitivity.
- ICM42607/ICM42670 power down mode.

## Limitations

- Only I2C communication is supported.

## Get Started

This driver, along with many other components from this repository, can be used as a package from [Espressif's IDF Component Registry](https://components.espressif.com). To include this driver in your project, run the following idf.py from the project's root directory:
Expand Down
173 changes: 119 additions & 54 deletions components/sensors/icm42670/icm42670.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,103 +16,128 @@
#include "iot_sensor_hub.h"
#include "icm42670.h"

#define I2C_CLK_SPEED 400000
#define ICM42670_I2C_CLK_SPEED 400000
#define ICM42670_SPI_CLK_SPEED 1000000

#define ALPHA 0.97f /*!< Weight of gyroscope */
#define RAD_TO_DEG 57.27272727f /*!< Radians to degrees */
#define ALPHA 0.97f /*!< Weight of gyroscope */
#define RAD_TO_DEG 57.27272727f /*!< Radians to degrees */

#define ICM42607_ID 0x60
#define ICM42670_ID 0x67

/* ICM42670 register */
#define ICM42670_WHOAMI 0x75
#define ICM42670_GYRO_CONFIG0 0x20
#define ICM42670_ACCEL_CONFIG0 0x21
#define ICM42670_TEMP_CONFIG 0x22
#define ICM42670_PWR_MGMT0 0x1F
#define ICM42670_TEMP_DATA 0x09
#define ICM42670_ACCEL_DATA 0x0B
#define ICM42670_GYRO_DATA 0x11
#define ICM42670_WHOAMI 0x75
#define ICM42670_GYRO_CONFIG0 0x20
#define ICM42670_ACCEL_CONFIG0 0x21
#define ICM42670_TEMP_CONFIG 0x22
#define ICM42670_PWR_MGMT0 0x1F
#define ICM42670_TEMP_DATA 0x09
#define ICM42670_ACCEL_DATA 0x0B
#define ICM42670_GYRO_DATA 0x11

/* Sensitivity of the gyroscope */
#define GYRO_FS_2000_SENSITIVITY (16.4)
#define GYRO_FS_1000_SENSITIVITY (32.8)
#define GYRO_FS_500_SENSITIVITY (65.5)
#define GYRO_FS_250_SENSITIVITY (131.0)
#define GYRO_FS_500_SENSITIVITY (65.5)
#define GYRO_FS_250_SENSITIVITY (131.0)

/* Sensitivity of the accelerometer */
#define ACCE_FS_16G_SENSITIVITY (2048)
#define ACCE_FS_8G_SENSITIVITY (4096)
#define ACCE_FS_4G_SENSITIVITY (8192)
#define ACCE_FS_2G_SENSITIVITY (16384)
#define ACCE_FS_8G_SENSITIVITY (4096)
#define ACCE_FS_4G_SENSITIVITY (8192)
#define ACCE_FS_2G_SENSITIVITY (16384)

/*******************************************************************************
* Types definitions
*******************************************************************************/
* Types definitions
*******************************************************************************/

typedef struct {
bool using_spi;
spi_device_handle_t spi_handle;
i2c_master_dev_handle_t i2c_handle;
bool initialized_filter;
uint64_t previous_measurement_us;
complimentary_angle_t previous_measurement;
} icm42670_dev_t;

/*******************************************************************************
* Function definitions
*******************************************************************************/
* Function definitions
*******************************************************************************/
static esp_err_t icm42670_write(icm42670_handle_t sensor, const uint8_t reg_start_addr, const uint8_t *data_buf,
const uint8_t data_len);
static esp_err_t icm42670_read(icm42670_handle_t sensor, const uint8_t reg_start_addr, uint8_t *data_buf,
const uint8_t data_len);

static esp_err_t icm42670_get_raw_value(icm42670_handle_t sensor, uint8_t reg, icm42670_raw_value_t *value);

static esp_err_t check_device_present(icm42670_handle_t sensor);
/*******************************************************************************
* Local variables
*******************************************************************************/
* Local variables
*******************************************************************************/
static const char *TAG = "ICM42670";

/*******************************************************************************
* Public API functions
*******************************************************************************/
* Public API functions
*******************************************************************************/

esp_err_t icm42670_create(i2c_master_bus_handle_t i2c_bus, const uint8_t dev_addr, icm42670_handle_t *handle_ret)
{
esp_err_t ret = ESP_OK;

// Allocate memory and init the driver object
icm42670_dev_t *sensor = (icm42670_dev_t *) calloc(1, sizeof(icm42670_dev_t));
ESP_RETURN_ON_FALSE(sensor != NULL, ESP_ERR_NO_MEM, TAG, "Not enough memory");
icm42670_dev_t *sensor = (icm42670_dev_t *)calloc(1, sizeof(icm42670_dev_t));
ESP_RETURN_ON_FALSE(sensor, ESP_ERR_NO_MEM, TAG, "Not enough memory");

// Add new I2C device
const i2c_device_config_t i2c_dev_cfg = {
.device_address = dev_addr,
.scl_speed_hz = I2C_CLK_SPEED,
.scl_speed_hz = ICM42670_I2C_CLK_SPEED,
};
ESP_GOTO_ON_ERROR(i2c_master_bus_add_device(i2c_bus, &i2c_dev_cfg, &sensor->i2c_handle), err, TAG,
"Failed to add new I2C device");
assert(sensor->i2c_handle);

// Check device presence
uint8_t dev_id = 0;
icm42670_get_deviceid(sensor, &dev_id);
ESP_GOTO_ON_FALSE(dev_id == ICM42607_ID
|| dev_id == ICM42670_ID, ESP_ERR_NOT_FOUND, err, TAG, "Incorrect Device ID (0x%02x).", dev_id);
ESP_GOTO_ON_ERROR(check_device_present(sensor), err, TAG, "Incorrect device ID received");

ESP_LOGD(TAG, "Found device %s, ID: 0x%02x", (dev_id == ICM42607_ID ? "ICM42607" : "ICM42670"), dev_id);
*handle_ret = sensor;
return ESP_OK;

err:
icm42670_delete(sensor);
return ret;
}

esp_err_t icm42670_create_spi(spi_host_device_t spi_bus, gpio_num_t cs_pin, icm42670_handle_t *handle_ret)
{
esp_err_t ret = ESP_OK;
icm42670_dev_t *sensor = (icm42670_dev_t *)calloc(1, sizeof(icm42670_dev_t));
ESP_RETURN_ON_FALSE(sensor, ESP_ERR_NO_MEM, TAG, "Not enough memory");
sensor->using_spi = true;

spi_device_interface_config_t dev_cfg = {
.clock_speed_hz = ICM42670_SPI_CLK_SPEED,
.spics_io_num = cs_pin,
.mode = 3,
.queue_size = 1,
};
ESP_GOTO_ON_ERROR(spi_bus_add_device(spi_bus, &dev_cfg, &sensor->spi_handle), err, TAG, "Failed to add new SPI device");
assert(sensor->spi_handle);

ESP_GOTO_ON_ERROR(check_device_present(sensor), err, TAG, "Incorrect device ID received");

*handle_ret = sensor;
return ESP_OK;
err:
icm42670_delete(sensor);
return ret;
}

void icm42670_delete(icm42670_handle_t sensor)
{
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;

if (sens->i2c_handle) {
icm42670_dev_t *sens = (icm42670_dev_t *)sensor;
if (sens->using_spi && sens->spi_handle) {
spi_bus_remove_device(sens->spi_handle);
} else if (sens->i2c_handle) {
i2c_master_bus_rm_device(sens->i2c_handle);
}

Expand Down Expand Up @@ -333,9 +358,23 @@ esp_err_t icm42670_get_temp_value(icm42670_handle_t sensor, float *value)
}

/*******************************************************************************
* Private functions
*******************************************************************************/
* Private functions
*******************************************************************************/

static esp_err_t check_device_present(icm42670_handle_t sensor)
{
uint8_t dev_id = 0;
esp_err_t ret = icm42670_get_deviceid(sensor, &dev_id);
if (ret != ESP_OK) {
return ret;
}
if (dev_id != ICM42607_ID && dev_id != ICM42670_ID) {
ESP_LOGD(TAG, "Incorrect Device ID (0x%02x).", dev_id);
return ESP_ERR_NOT_FOUND;
}
ESP_LOGD(TAG, "Found device %s, ID: 0x%02x", (dev_id == ICM42607_ID ? "ICM42607" : "ICM42670"), dev_id);
return ESP_OK;
}
static esp_err_t icm42670_get_raw_value(icm42670_handle_t sensor, uint8_t reg, icm42670_raw_value_t *value)
{
esp_err_t ret = ESP_FAIL;
Expand All @@ -360,30 +399,52 @@ static esp_err_t icm42670_get_raw_value(icm42670_handle_t sensor, uint8_t reg, i
static esp_err_t icm42670_write(icm42670_handle_t sensor, const uint8_t reg_start_addr, const uint8_t *data_buf,
const uint8_t data_len)
{
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;
icm42670_dev_t *sens = (icm42670_dev_t *)sensor;
assert(sens);

assert(data_len < 5);
uint8_t write_buff[5] = {reg_start_addr};
memcpy(&write_buff[1], data_buf, data_len);
return i2c_master_transmit(sens->i2c_handle, write_buff, data_len + 1, -1);
if (sens->using_spi) {
spi_transaction_t trans = {
.length = (data_len + 1) * 8, // Total length in bits
.tx_buffer = write_buff,
};
return spi_device_transmit(sens->spi_handle, &trans);
} else {
return i2c_master_transmit(sens->i2c_handle, write_buff, data_len + 1, -1);
}
}

static esp_err_t icm42670_read(icm42670_handle_t sensor, const uint8_t reg_start_addr, uint8_t *data_buf,
const uint8_t data_len)
{
uint8_t reg_buff[] = {reg_start_addr};
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;
assert(sens);

/* Write register number and read data */
return i2c_master_transmit_receive(sens->i2c_handle, reg_buff, sizeof(reg_buff), data_buf, data_len, -1);
icm42670_dev_t *sens = (icm42670_dev_t *)sensor;
assert(sens && data_buf && data_len <= 6);
esp_err_t ret;
if (sens->using_spi) {
uint8_t tx_buf[7] = {reg_start_addr | 0x80}; // Set MSB for read operation
uint8_t rx_buf[7] = {0}; // Buffer to receive data (including the register address)
spi_transaction_t trans = {
.length = (data_len + 1) * 8, // Total length in bits
.tx_buffer = tx_buf,
.rx_buffer = rx_buf,
};
ret = spi_device_transmit(sens->spi_handle, &trans);
if (ret == ESP_OK) {
memcpy(data_buf, &rx_buf[1], data_len); // Skip the first byte (register address)
}
} else {
uint8_t reg_buff[] = {reg_start_addr};
/* Write register number and read data */
ret = i2c_master_transmit_receive(sens->i2c_handle, reg_buff, sizeof(reg_buff), data_buf, data_len, -1);
}
return ret;
}

esp_err_t icm42670_complimentory_filter(icm42670_handle_t sensor, const icm42670_value_t *const acce_value,
const icm42670_value_t *const gyro_value, complimentary_angle_t *const complimentary_angle)
{
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;
icm42670_dev_t *sens = (icm42670_dev_t *)sensor;
float measurement_delta;
uint64_t current_time_us;
float acc_roll_angle;
Expand All @@ -392,9 +453,11 @@ esp_err_t icm42670_complimentory_filter(icm42670_handle_t sensor, const icm42670
float gyro_pitch_angle;

acc_roll_angle = (atan2(acce_value->y,
sqrt(acce_value->x * acce_value->x + acce_value->z * acce_value->z)) * RAD_TO_DEG);
sqrt(acce_value->x * acce_value->x + acce_value->z * acce_value->z)) *
RAD_TO_DEG);
acc_pitch_angle = (atan2(-acce_value->x,
sqrt(acce_value->y * acce_value->y + acce_value->z * acce_value->z)) * RAD_TO_DEG);
sqrt(acce_value->y * acce_value->y + acce_value->z * acce_value->z)) *
RAD_TO_DEG);

if (!sens->initialized_filter) {
sens->initialized_filter = true;
Expand All @@ -411,9 +474,11 @@ esp_err_t icm42670_complimentory_filter(icm42670_handle_t sensor, const icm42670
gyro_pitch_angle = gyro_value->y * measurement_delta;

complimentary_angle->roll = (ALPHA * (sens->previous_measurement.roll + gyro_roll_angle)) + ((
1 - ALPHA) * acc_roll_angle);
1 - ALPHA) *
acc_roll_angle);
complimentary_angle->pitch = (ALPHA * (sens->previous_measurement.pitch + gyro_pitch_angle)) + ((
1 - ALPHA) * acc_pitch_angle);
1 - ALPHA) *
acc_pitch_angle);

sens->previous_measurement.roll = complimentary_angle->roll;
sens->previous_measurement.pitch = complimentary_angle->pitch;
Expand Down Expand Up @@ -519,13 +584,13 @@ esp_err_t icm42670_impl_deinit(void)
return ESP_OK;
}

esp_err_t icm42670_impl_test (void)
esp_err_t icm42670_impl_test(void)
{
uint8_t device_id;
return icm42670_get_deviceid(sensor_hub_icm42670_handle, &device_id);
}

esp_err_t icm42670_impl_acquire_acce (float *acce_x, float *acce_y, float *acce_z)
esp_err_t icm42670_impl_acquire_acce(float *acce_x, float *acce_y, float *acce_z)
{
icm42670_value_t value;
ESP_RETURN_ON_ERROR(icm42670_get_acce_value(sensor_hub_icm42670_handle, &value), TAG,
Expand Down
2 changes: 1 addition & 1 deletion components/sensors/icm42670/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
version: 2.1.0
description: I2C driver for ICM 42670 6-Axis MotionTracking
description: I2C/SPI driver for ICM 42670 6-Axis MotionTracking
url: https://github.com/espressif/esp-bsp/tree/master/components/sensors/icm42670
dependencies:
idf: ">=5.2"
Expand Down
Loading
Loading