Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICM42670: I2C Driver-NG #404

Merged
merged 2 commits into from
Oct 16, 2024
Merged
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
15 changes: 13 additions & 2 deletions .build-test-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ test_apps/noglib:
test_apps/components:
depends_filepatterns:
- "components/bh1750/**"
- "components/ds18b20/**"
- "components/fbm320/**"
- "components/hts221/**"
- "components/icm42670/**"
- "components/io_expander/**"
- "components/lcd/ra8875/**"
- "components/lcd/sh1107/**"
Expand Down Expand Up @@ -68,6 +66,19 @@ components/lcd/esp_lcd_st7796:
- "components/lcd/esp_lcd_st7796/**"

components/ds18b20:
depends_filepatterns:
- "components/ds18b20/**"
disable:
- if: SOC_RMT_SUPPORTED != 1
reason: Onewire component depends on RMT peripheral

components/icm42670:
depends_filepatterns:
- "components/icm42670/**"
disable:
- if: (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR < 2) or IDF_VERSION_MAJOR < 5
reason: Requires I2C Driver-NG which was introduced in v5.2

components/qma6100p:
depends_filepatterns:
- "components/qma6100p/**"
78 changes: 40 additions & 38 deletions components/icm42670/icm42670.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <string.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include "esp_system.h"
#include "esp_check.h"
#include "driver/i2c.h"
#include "icm42670.h"

#define I2C_CLK_SPEED 400000

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

Expand Down Expand Up @@ -46,8 +48,7 @@
*******************************************************************************/

typedef struct {
i2c_port_t bus;
uint8_t dev_addr;
i2c_master_dev_handle_t i2c_handle;
uint32_t counter;
float dt; /*!< delay time between two measurements, dt should be small (ms level) */
struct timeval *timer;
Expand All @@ -70,31 +71,46 @@ static const char *TAG = "ICM42670";
* Public API functions
*******************************************************************************/

icm42670_handle_t icm42670_create(i2c_port_t port, const uint8_t dev_addr)
esp_err_t icm42670_create(i2c_master_bus_handle_t i2c_bus, const uint8_t dev_addr, icm42670_handle_t *handle_ret)
{
icm42670_dev_t *sensor = (icm42670_dev_t *) heap_caps_calloc(1, sizeof(icm42670_dev_t), MALLOC_CAP_DEFAULT);
sensor->bus = port;
sensor->dev_addr = dev_addr;
sensor->counter = 0;
sensor->dt = 0;
sensor->timer = (struct timeval *) calloc(1, sizeof(struct timeval));

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));
struct timeval *timer = (struct timeval *) calloc(1, sizeof(struct timeval));
ESP_RETURN_ON_FALSE(sensor != NULL && timer != NULL, ESP_ERR_NO_MEM, TAG, "Not enough memory");
sensor->timer = timer;

// Add new I2C device
const i2c_device_config_t i2c_dev_cfg = {
.device_address = dev_addr,
.scl_speed_hz = 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);
if (dev_id != ICM42607_ID && dev_id != ICM42670_ID) {
ESP_LOGE(TAG, "Incorrect Device ID (0x%02x).", dev_id);
return NULL;
}
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_LOGI(TAG, "Found device %s, ID: 0x%02x", (dev_id == ICM42607_ID ? "ICM42607" : "ICM42670"), dev_id);
ESP_LOGD(TAG, "Found device %s, ID: 0x%02x", (dev_id == ICM42607_ID ? "ICM42607" : "ICM42670"), dev_id);
*handle_ret = sensor;
return ret;

return (icm42670_handle_t) sensor;
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) {
i2c_master_bus_rm_device(sens->i2c_handle);
}

if (sens->timer) {
free(sens->timer);
}
Expand Down Expand Up @@ -343,36 +359,22 @@ 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;
esp_err_t ret;

assert(sens);

i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ret = i2c_master_start(cmd);
assert(ESP_OK == ret);
ret = i2c_master_write_byte(cmd, (sens->dev_addr << 1) | I2C_MASTER_WRITE, true);
assert(ESP_OK == ret);
ret = i2c_master_write_byte(cmd, reg_start_addr, true);
assert(ESP_OK == ret);
ret = i2c_master_write(cmd, data_buf, data_len, true);
assert(ESP_OK == ret);
ret = i2c_master_stop(cmd);
assert(ESP_OK == ret);
ret = i2c_master_cmd_begin(sens->bus, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

return ret;
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);
}

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)
{
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;
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_write_read_device(sens->bus, sens->dev_addr, reg_buff, sizeof(reg_buff), data_buf, data_len, 1000 / portTICK_PERIOD_MS);
return i2c_master_transmit_receive(sens->i2c_handle, reg_buff, sizeof(reg_buff), data_buf, data_len, -1);
}

esp_err_t icm42670_complimentory_filter(icm42670_handle_t sensor, const icm42670_value_t *const acce_value,
Expand Down
4 changes: 2 additions & 2 deletions components/icm42670/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
version: "1.0.0"
version: "2.0.0"
description: I2C driver for ICM 42670 6-Axis MotionTracking
url: https://github.com/espressif/esp-bsp/tree/master/components/icm42670
dependencies:
idf: ">=4.4"
idf: ">=5.2"
19 changes: 11 additions & 8 deletions components/icm42670/include/icm42670.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -10,7 +10,7 @@
extern "C" {
#endif

#include "driver/i2c.h"
#include "driver/i2c_master.h"

#define ICM42670_I2C_ADDRESS 0x68 /*!< I2C address with AD0 pin low */
#define ICM42670_I2C_ADDRESS_1 0x69 /*!< I2C address with AD0 pin high */
Expand Down Expand Up @@ -94,16 +94,19 @@ typedef struct {
typedef void *icm42670_handle_t;

/**
* @brief Create and init sensor object and return a sensor handle
* @brief Create and init sensor object
*
* @param port I2C port number
* @param dev_addr I2C device address of sensor
* @param[in] i2c_bus I2C bus handle. Obtained from i2c_new_master_bus()
* @param[in] dev_addr I2C device address of sensor. Can be ICM42670_I2C_ADDRESS or ICM42670_I2C_ADDRESS_1
* @param[out] handle_ret Handle to created ICM42670 driver object
*
* @return
* - NULL Fail
* - Others Success
* - ESP_OK Success
* - ESP_ERR_NO_MEM Not enough memory for the driver
* - ESP_ERR_NOT_FOUND Sensor not found on the I2C bus
* - Others Error from underlying I2C driver
*/
icm42670_handle_t icm42670_create(i2c_port_t port, const uint8_t dev_addr);
esp_err_t icm42670_create(i2c_master_bus_handle_t i2c_bus, const uint8_t dev_addr, icm42670_handle_t *handle_ret);

/**
* @brief Delete and release a sensor object
Expand Down
7 changes: 7 additions & 0 deletions components/icm42670/test_apps/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_app_icm42670)
4 changes: 4 additions & 0 deletions components/icm42670/test_apps/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
idf_component_register(
SRCS "test_app_icm42670.c"
REQUIRES unity
)
6 changes: 6 additions & 0 deletions components/icm42670/test_apps/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
idf: ">=5.2"
icm42670:
version: "*"
override_path: "../../"
110 changes: 110 additions & 0 deletions components/icm42670/test_apps/main/test_app_icm42670.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdio.h>
#include "unity.h"
#include "driver/i2c_master.h"
#include "icm42670.h"
#include "esp_system.h"
#include "esp_log.h"
#include "unity.h"
#include "unity_test_runner.h"
#include "unity_test_utils_memory.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

// Pinout for ESP32-S3-BOX
#define I2C_MASTER_SCL_IO 18 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO 8 /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */

static const char *TAG = "icm42670 test";
static icm42670_handle_t icm42670 = NULL;
static i2c_master_bus_handle_t i2c_handle = NULL;

static void i2c_bus_init(void)
{
const i2c_master_bus_config_t bus_config = {
.i2c_port = I2C_MASTER_NUM,
tore-espressif marked this conversation as resolved.
Show resolved Hide resolved
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.clk_source = I2C_CLK_SRC_DEFAULT,
};

esp_err_t ret = i2c_new_master_bus(&bus_config, &i2c_handle);
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, ret, "I2C install returned error");
}

static void i2c_sensor_icm42670_init(void)
{
esp_err_t ret;

i2c_bus_init();
ret = icm42670_create(i2c_handle, ICM42670_I2C_ADDRESS, &icm42670);
TEST_ASSERT_EQUAL(ESP_OK, ret);
TEST_ASSERT_NOT_NULL_MESSAGE(icm42670, "icm42670 create returned NULL");

/* Configuration of the accelerometer and gyroscope */
const icm42670_cfg_t imu_cfg = {
.acce_fs = ACCE_FS_2G,
.acce_odr = ACCE_ODR_400HZ,
.gyro_fs = GYRO_FS_2000DPS,
.gyro_odr = GYRO_ODR_400HZ,
};
ret = icm42670_config(icm42670, &imu_cfg);
TEST_ASSERT_EQUAL(ESP_OK, ret);
}

TEST_CASE("Sensor icm42670 test", "[icm42670]")
{
esp_err_t ret;
icm42670_value_t acc, gyro;
float temperature;

i2c_sensor_icm42670_init();

/* Set accelerometer and gyroscope to ON */
ret = icm42670_acce_set_pwr(icm42670, ACCE_PWR_LOWNOISE);
TEST_ASSERT_EQUAL(ESP_OK, ret);
ret = icm42670_gyro_set_pwr(icm42670, GYRO_PWR_LOWNOISE);
TEST_ASSERT_EQUAL(ESP_OK, ret);

for (int i = 0; i < 100; i++) {
vTaskDelay(pdMS_TO_TICKS(50));
ret = icm42670_get_acce_value(icm42670, &acc);
TEST_ASSERT_EQUAL(ESP_OK, ret);
ret = icm42670_get_gyro_value(icm42670, &gyro);
TEST_ASSERT_EQUAL(ESP_OK, ret);
ret = icm42670_get_temp_value(icm42670, &temperature);
TEST_ASSERT_EQUAL(ESP_OK, ret);
ESP_LOGI(TAG, "acc_x:%.2f, acc_y:%.2f, acc_z:%.2f, gyro_x:%.2f, gyro_y:%.2f, gyro_z:%.2f temp: %.1f",
acc.x, acc.y, acc.z, gyro.x, gyro.y, gyro.z, temperature);
}

icm42670_delete(icm42670);
ret = i2c_del_master_bus(i2c_handle);
TEST_ASSERT_EQUAL(ESP_OK, ret);
vTaskDelay(10); // Give FreeRTOS some time to free its resources
}

#define TEST_MEMORY_LEAK_THRESHOLD (400)

void setUp(void)
{
unity_utils_set_leak_level(TEST_MEMORY_LEAK_THRESHOLD);
unity_utils_record_free_mem();
}

void tearDown(void)
{
unity_utils_evaluate_leaks();
}

void app_main(void)
{
unity_run_menu();
}
12 changes: 12 additions & 0 deletions components/icm42670/test_apps/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_COMPILER_OPTIMIZATION_PERF=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
CONFIG_SPIRAM_RODATA=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096
3 changes: 2 additions & 1 deletion components/qma6100p/test_apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_esp_acc_qma6100p)
project(test_esp_acc_qma6100p)
5 changes: 4 additions & 1 deletion components/qma6100p/test_apps/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
idf_component_register(SRCS "test_esp_acc_qma6100p.c")
idf_component_register(
SRCS "test_esp_acc_qma6100p.c"
REQUIRES unity
)
3 changes: 0 additions & 3 deletions components/qma6100p/test_apps/main/test_esp_acc_qma6100p.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,6 @@ TEST_CASE("Sensor qma6100p test", "[qma6100p][iot][sensor]")

#define TEST_MEMORY_LEAK_THRESHOLD (300)

static size_t before_free_8bit;
static size_t before_free_32bit;

void setUp(void)
{
unity_utils_set_leak_level(TEST_MEMORY_LEAK_THRESHOLD);
Expand Down
2 changes: 1 addition & 1 deletion test_apps/components/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ if(NOT "${IDF_TARGET}" STREQUAL "esp32s2" AND NOT "${IDF_TARGET}" STREQUAL "esp3
endif()

# Set the components to include the tests for.
set(TEST_COMPONENTS bh1750 mpu6050 mag3110 hts221 fbm320 icm42670 qma6100p CACHE STRING "List of components to test")
set(TEST_COMPONENTS bh1750 mpu6050 mag3110 hts221 fbm320 CACHE STRING "List of components to test")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_bsp_test_app)
Loading