diff --git a/.build-test-rules.yml b/.build-test-rules.yml index 67a1d22a..7ab68d65 100644 --- a/.build-test-rules.yml +++ b/.build-test-rules.yml @@ -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/**" @@ -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/**" diff --git a/components/icm42670/icm42670.c b/components/icm42670/icm42670.c index 1aad8726..ab00dafd 100644 --- a/components/icm42670/icm42670.c +++ b/components/icm42670/icm42670.c @@ -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 #include #include #include #include #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 */ @@ -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; @@ -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); } @@ -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, diff --git a/components/icm42670/idf_component.yml b/components/icm42670/idf_component.yml index 2bf7dcfc..1499f793 100644 --- a/components/icm42670/idf_component.yml +++ b/components/icm42670/idf_component.yml @@ -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" diff --git a/components/icm42670/include/icm42670.h b/components/icm42670/include/icm42670.h index a44b80f9..2d0662e0 100644 --- a/components/icm42670/include/icm42670.h +++ b/components/icm42670/include/icm42670.h @@ -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 */ @@ -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 */ @@ -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 diff --git a/components/icm42670/test_apps/CMakeLists.txt b/components/icm42670/test_apps/CMakeLists.txt new file mode 100644 index 00000000..fa46e274 --- /dev/null +++ b/components/icm42670/test_apps/CMakeLists.txt @@ -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) diff --git a/components/icm42670/test_apps/main/CMakeLists.txt b/components/icm42670/test_apps/main/CMakeLists.txt new file mode 100644 index 00000000..52011288 --- /dev/null +++ b/components/icm42670/test_apps/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register( + SRCS "test_app_icm42670.c" + REQUIRES unity + ) diff --git a/components/icm42670/test_apps/main/idf_component.yml b/components/icm42670/test_apps/main/idf_component.yml new file mode 100644 index 00000000..8fae24de --- /dev/null +++ b/components/icm42670/test_apps/main/idf_component.yml @@ -0,0 +1,6 @@ +## IDF Component Manager Manifest File +dependencies: + idf: ">=5.2" + icm42670: + version: "*" + override_path: "../../" diff --git a/components/icm42670/test_apps/main/test_app_icm42670.c b/components/icm42670/test_apps/main/test_app_icm42670.c new file mode 100644 index 00000000..0333f8a6 --- /dev/null +++ b/components/icm42670/test_apps/main/test_app_icm42670.c @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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, + .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(); +} diff --git a/components/icm42670/test_apps/sdkconfig.defaults b/components/icm42670/test_apps/sdkconfig.defaults new file mode 100644 index 00000000..b5b36e5c --- /dev/null +++ b/components/icm42670/test_apps/sdkconfig.defaults @@ -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 diff --git a/components/qma6100p/test_apps/CMakeLists.txt b/components/qma6100p/test_apps/CMakeLists.txt index 498cfb42..4eecc782 100644 --- a/components/qma6100p/test_apps/CMakeLists.txt +++ b/components/qma6100p/test_apps/CMakeLists.txt @@ -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) \ No newline at end of file +project(test_esp_acc_qma6100p) diff --git a/components/qma6100p/test_apps/main/CMakeLists.txt b/components/qma6100p/test_apps/main/CMakeLists.txt index 3d134a4b..4c535a80 100644 --- a/components/qma6100p/test_apps/main/CMakeLists.txt +++ b/components/qma6100p/test_apps/main/CMakeLists.txt @@ -1 +1,4 @@ -idf_component_register(SRCS "test_esp_acc_qma6100p.c") +idf_component_register( + SRCS "test_esp_acc_qma6100p.c" + REQUIRES unity + ) diff --git a/components/qma6100p/test_apps/main/test_esp_acc_qma6100p.c b/components/qma6100p/test_apps/main/test_esp_acc_qma6100p.c index 47f4f4f8..b6b57d6d 100644 --- a/components/qma6100p/test_apps/main/test_esp_acc_qma6100p.c +++ b/components/qma6100p/test_apps/main/test_esp_acc_qma6100p.c @@ -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); diff --git a/test_apps/components/CMakeLists.txt b/test_apps/components/CMakeLists.txt index df2271a3..f33855ac 100644 --- a/test_apps/components/CMakeLists.txt +++ b/test_apps/components/CMakeLists.txt @@ -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)