Skip to content

Commit f580175

Browse files
Merge pull request #404 from espressif/refactor/icm4267_i2c_ng
ICM42670: I2C Driver-NG
2 parents 61ab9cb + 8c75afa commit f580175

File tree

13 files changed

+212
-56
lines changed

13 files changed

+212
-56
lines changed

.build-test-rules.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ test_apps/noglib:
1515
test_apps/components:
1616
depends_filepatterns:
1717
- "components/bh1750/**"
18-
- "components/ds18b20/**"
1918
- "components/fbm320/**"
2019
- "components/hts221/**"
21-
- "components/icm42670/**"
2220
- "components/io_expander/**"
2321
- "components/lcd/ra8875/**"
2422
- "components/lcd/sh1107/**"
@@ -68,6 +66,19 @@ components/lcd/esp_lcd_st7796:
6866
- "components/lcd/esp_lcd_st7796/**"
6967

7068
components/ds18b20:
69+
depends_filepatterns:
70+
- "components/ds18b20/**"
7171
disable:
7272
- if: SOC_RMT_SUPPORTED != 1
7373
reason: Onewire component depends on RMT peripheral
74+
75+
components/icm42670:
76+
depends_filepatterns:
77+
- "components/icm42670/**"
78+
disable:
79+
- if: (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR < 2) or IDF_VERSION_MAJOR < 5
80+
reason: Requires I2C Driver-NG which was introduced in v5.2
81+
82+
components/qma6100p:
83+
depends_filepatterns:
84+
- "components/qma6100p/**"

components/icm42670/icm42670.c

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include <string.h>
78
#include <stdio.h>
89
#include <math.h>
910
#include <time.h>
1011
#include <sys/time.h>
1112
#include "esp_system.h"
1213
#include "esp_check.h"
13-
#include "driver/i2c.h"
1414
#include "icm42670.h"
1515

16+
#define I2C_CLK_SPEED 400000
17+
1618
#define ALPHA 0.99f /*!< Weight of gyroscope */
1719
#define RAD_TO_DEG 57.27272727f /*!< Radians to degrees */
1820

@@ -46,8 +48,7 @@
4648
*******************************************************************************/
4749

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

73-
icm42670_handle_t icm42670_create(i2c_port_t port, const uint8_t dev_addr)
74+
esp_err_t icm42670_create(i2c_master_bus_handle_t i2c_bus, const uint8_t dev_addr, icm42670_handle_t *handle_ret)
7475
{
75-
icm42670_dev_t *sensor = (icm42670_dev_t *) heap_caps_calloc(1, sizeof(icm42670_dev_t), MALLOC_CAP_DEFAULT);
76-
sensor->bus = port;
77-
sensor->dev_addr = dev_addr;
78-
sensor->counter = 0;
79-
sensor->dt = 0;
80-
sensor->timer = (struct timeval *) calloc(1, sizeof(struct timeval));
81-
76+
esp_err_t ret = ESP_OK;
77+
78+
// Allocate memory and init the driver object
79+
icm42670_dev_t *sensor = (icm42670_dev_t *) calloc(1, sizeof(icm42670_dev_t));
80+
struct timeval *timer = (struct timeval *) calloc(1, sizeof(struct timeval));
81+
ESP_RETURN_ON_FALSE(sensor != NULL && timer != NULL, ESP_ERR_NO_MEM, TAG, "Not enough memory");
82+
sensor->timer = timer;
83+
84+
// Add new I2C device
85+
const i2c_device_config_t i2c_dev_cfg = {
86+
.device_address = dev_addr,
87+
.scl_speed_hz = I2C_CLK_SPEED,
88+
};
89+
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");
90+
assert(sensor->i2c_handle);
91+
92+
// Check device presence
8293
uint8_t dev_id = 0;
8394
icm42670_get_deviceid(sensor, &dev_id);
84-
if (dev_id != ICM42607_ID && dev_id != ICM42670_ID) {
85-
ESP_LOGE(TAG, "Incorrect Device ID (0x%02x).", dev_id);
86-
return NULL;
87-
}
95+
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);
8896

89-
ESP_LOGI(TAG, "Found device %s, ID: 0x%02x", (dev_id == ICM42607_ID ? "ICM42607" : "ICM42670"), dev_id);
97+
ESP_LOGD(TAG, "Found device %s, ID: 0x%02x", (dev_id == ICM42607_ID ? "ICM42607" : "ICM42670"), dev_id);
98+
*handle_ret = sensor;
99+
return ret;
90100

91-
return (icm42670_handle_t) sensor;
101+
err:
102+
icm42670_delete(sensor);
103+
return ret;
92104
}
93105

94106
void icm42670_delete(icm42670_handle_t sensor)
95107
{
96108
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;
97109

110+
if (sens->i2c_handle) {
111+
i2c_master_bus_rm_device(sens->i2c_handle);
112+
}
113+
98114
if (sens->timer) {
99115
free(sens->timer);
100116
}
@@ -343,36 +359,22 @@ static esp_err_t icm42670_get_raw_value(icm42670_handle_t sensor, uint8_t reg, i
343359
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)
344360
{
345361
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;
346-
esp_err_t ret;
347-
348362
assert(sens);
349363

350-
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
351-
ret = i2c_master_start(cmd);
352-
assert(ESP_OK == ret);
353-
ret = i2c_master_write_byte(cmd, (sens->dev_addr << 1) | I2C_MASTER_WRITE, true);
354-
assert(ESP_OK == ret);
355-
ret = i2c_master_write_byte(cmd, reg_start_addr, true);
356-
assert(ESP_OK == ret);
357-
ret = i2c_master_write(cmd, data_buf, data_len, true);
358-
assert(ESP_OK == ret);
359-
ret = i2c_master_stop(cmd);
360-
assert(ESP_OK == ret);
361-
ret = i2c_master_cmd_begin(sens->bus, cmd, 1000 / portTICK_PERIOD_MS);
362-
i2c_cmd_link_delete(cmd);
363-
364-
return ret;
364+
assert(data_len < 5);
365+
uint8_t write_buff[5] = {reg_start_addr};
366+
memcpy(&write_buff[1], data_buf, data_len);
367+
return i2c_master_transmit(sens->i2c_handle, write_buff, data_len + 1, -1);
365368
}
366369

367370
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)
368371
{
369-
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;
370372
uint8_t reg_buff[] = {reg_start_addr};
371-
373+
icm42670_dev_t *sens = (icm42670_dev_t *) sensor;
372374
assert(sens);
373375

374376
/* Write register number and read data */
375-
return i2c_master_write_read_device(sens->bus, sens->dev_addr, reg_buff, sizeof(reg_buff), data_buf, data_len, 1000 / portTICK_PERIOD_MS);
377+
return i2c_master_transmit_receive(sens->i2c_handle, reg_buff, sizeof(reg_buff), data_buf, data_len, -1);
376378
}
377379

378380
esp_err_t icm42670_complimentory_filter(icm42670_handle_t sensor, const icm42670_value_t *const acce_value,
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
version: "1.0.0"
1+
version: "2.0.0"
22
description: I2C driver for ICM 42670 6-Axis MotionTracking
33
url: https://github.com/espressif/esp-bsp/tree/master/components/icm42670
44
dependencies:
5-
idf: ">=4.4"
5+
idf: ">=5.2"

components/icm42670/include/icm42670.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -10,7 +10,7 @@
1010
extern "C" {
1111
#endif
1212

13-
#include "driver/i2c.h"
13+
#include "driver/i2c_master.h"
1414

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

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

108111
/**
109112
* @brief Delete and release a sensor object
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
5+
set(COMPONENTS main)
6+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
7+
project(test_app_icm42670)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
idf_component_register(
2+
SRCS "test_app_icm42670.c"
3+
REQUIRES unity
4+
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## IDF Component Manager Manifest File
2+
dependencies:
3+
idf: ">=5.2"
4+
icm42670:
5+
version: "*"
6+
override_path: "../../"
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdio.h>
8+
#include "unity.h"
9+
#include "driver/i2c_master.h"
10+
#include "icm42670.h"
11+
#include "esp_system.h"
12+
#include "esp_log.h"
13+
#include "unity.h"
14+
#include "unity_test_runner.h"
15+
#include "unity_test_utils_memory.h"
16+
17+
#include "freertos/FreeRTOS.h"
18+
#include "freertos/task.h"
19+
20+
// Pinout for ESP32-S3-BOX
21+
#define I2C_MASTER_SCL_IO 18 /*!< gpio number for I2C master clock */
22+
#define I2C_MASTER_SDA_IO 8 /*!< gpio number for I2C master data */
23+
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
24+
25+
static const char *TAG = "icm42670 test";
26+
static icm42670_handle_t icm42670 = NULL;
27+
static i2c_master_bus_handle_t i2c_handle = NULL;
28+
29+
static void i2c_bus_init(void)
30+
{
31+
const i2c_master_bus_config_t bus_config = {
32+
.i2c_port = I2C_MASTER_NUM,
33+
.sda_io_num = I2C_MASTER_SDA_IO,
34+
.scl_io_num = I2C_MASTER_SCL_IO,
35+
.clk_source = I2C_CLK_SRC_DEFAULT,
36+
};
37+
38+
esp_err_t ret = i2c_new_master_bus(&bus_config, &i2c_handle);
39+
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, ret, "I2C install returned error");
40+
}
41+
42+
static void i2c_sensor_icm42670_init(void)
43+
{
44+
esp_err_t ret;
45+
46+
i2c_bus_init();
47+
ret = icm42670_create(i2c_handle, ICM42670_I2C_ADDRESS, &icm42670);
48+
TEST_ASSERT_EQUAL(ESP_OK, ret);
49+
TEST_ASSERT_NOT_NULL_MESSAGE(icm42670, "icm42670 create returned NULL");
50+
51+
/* Configuration of the accelerometer and gyroscope */
52+
const icm42670_cfg_t imu_cfg = {
53+
.acce_fs = ACCE_FS_2G,
54+
.acce_odr = ACCE_ODR_400HZ,
55+
.gyro_fs = GYRO_FS_2000DPS,
56+
.gyro_odr = GYRO_ODR_400HZ,
57+
};
58+
ret = icm42670_config(icm42670, &imu_cfg);
59+
TEST_ASSERT_EQUAL(ESP_OK, ret);
60+
}
61+
62+
TEST_CASE("Sensor icm42670 test", "[icm42670]")
63+
{
64+
esp_err_t ret;
65+
icm42670_value_t acc, gyro;
66+
float temperature;
67+
68+
i2c_sensor_icm42670_init();
69+
70+
/* Set accelerometer and gyroscope to ON */
71+
ret = icm42670_acce_set_pwr(icm42670, ACCE_PWR_LOWNOISE);
72+
TEST_ASSERT_EQUAL(ESP_OK, ret);
73+
ret = icm42670_gyro_set_pwr(icm42670, GYRO_PWR_LOWNOISE);
74+
TEST_ASSERT_EQUAL(ESP_OK, ret);
75+
76+
for (int i = 0; i < 100; i++) {
77+
vTaskDelay(pdMS_TO_TICKS(50));
78+
ret = icm42670_get_acce_value(icm42670, &acc);
79+
TEST_ASSERT_EQUAL(ESP_OK, ret);
80+
ret = icm42670_get_gyro_value(icm42670, &gyro);
81+
TEST_ASSERT_EQUAL(ESP_OK, ret);
82+
ret = icm42670_get_temp_value(icm42670, &temperature);
83+
TEST_ASSERT_EQUAL(ESP_OK, ret);
84+
ESP_LOGI(TAG, "acc_x:%.2f, acc_y:%.2f, acc_z:%.2f, gyro_x:%.2f, gyro_y:%.2f, gyro_z:%.2f temp: %.1f",
85+
acc.x, acc.y, acc.z, gyro.x, gyro.y, gyro.z, temperature);
86+
}
87+
88+
icm42670_delete(icm42670);
89+
ret = i2c_del_master_bus(i2c_handle);
90+
TEST_ASSERT_EQUAL(ESP_OK, ret);
91+
vTaskDelay(10); // Give FreeRTOS some time to free its resources
92+
}
93+
94+
#define TEST_MEMORY_LEAK_THRESHOLD (400)
95+
96+
void setUp(void)
97+
{
98+
unity_utils_set_leak_level(TEST_MEMORY_LEAK_THRESHOLD);
99+
unity_utils_record_free_mem();
100+
}
101+
102+
void tearDown(void)
103+
{
104+
unity_utils_evaluate_leaks();
105+
}
106+
107+
void app_main(void)
108+
{
109+
unity_run_menu();
110+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CONFIG_IDF_TARGET="esp32s3"
2+
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
3+
CONFIG_COMPILER_OPTIMIZATION_PERF=y
4+
CONFIG_SPIRAM=y
5+
CONFIG_SPIRAM_MODE_OCT=y
6+
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
7+
CONFIG_SPIRAM_RODATA=y
8+
CONFIG_SPIRAM_SPEED_80M=y
9+
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
10+
CONFIG_ESP_TASK_WDT_EN=n
11+
CONFIG_FREERTOS_HZ=1000
12+
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096

components/qma6100p/test_apps/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
# in this exact order for cmake to work correctly
33
cmake_minimum_required(VERSION 3.5)
44
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
5+
set(COMPONENTS main)
56
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6-
project(test_esp_acc_qma6100p)
7+
project(test_esp_acc_qma6100p)

0 commit comments

Comments
 (0)