feat(i2c): Add new API and implementation for I2C driver

This commit is contained in:
Cao Sen Miao
2023-08-03 12:29:44 +08:00
parent db4308888d
commit 4ef94fc0dc
52 changed files with 3351 additions and 605 deletions
@@ -0,0 +1,131 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "unity.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "soc/gpio_periph.h"
#include "soc/clk_tree_defs.h"
#include "soc/soc_caps.h"
#include "hal/gpio_hal.h"
#include "hal/uart_ll.h"
#include "esp_private/periph_ctrl.h"
#include "driver/gpio.h"
#include "driver/i2c_master.h"
#include "esp_rom_gpio.h"
#include "esp_log.h"
#include "test_utils.h"
static const char TAG[] = "test-i2c";
#define TEST_I2C_SCL_PIN 2
#define TEST_I2C_SDA_PIN 4
#define TEST_I2C_SCL_FREQ (100 * 1000)
#define TEST_I2C_PORT 0
#define SLAVE_ADDR 0x58
TEST_CASE("I2C bus install-uninstall test", "[i2c]")
{
i2c_master_bus_config_t i2c_mst_config_1 = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = TEST_I2C_PORT,
.scl_io_num = TEST_I2C_SCL_PIN,
.sda_io_num = TEST_I2C_SDA_PIN,
};
i2c_master_bus_handle_t i2c_mst_handle1;
#if SOC_I2C_NUM > 1
i2c_master_bus_config_t i2c_mst_config_2 = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = 1,
.scl_io_num = TEST_I2C_SCL_PIN,
.sda_io_num = TEST_I2C_SDA_PIN,
};
i2c_master_bus_handle_t i2c_mst_handle2;
#endif
// Install master bus 0
ESP_LOGI(TAG, "Initialize bus0");
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_1, &i2c_mst_handle1));
#if SOC_I2C_NUM > 1
// Install master bus 1
ESP_LOGI(TAG, "Initialize bus1");
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_2, &i2c_mst_handle2));
#endif
// Install master bus 0 again
ESP_LOGI(TAG, "Initialize bus0 again");
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, i2c_new_master_bus(&i2c_mst_config_1, &i2c_mst_handle1));
ESP_LOGI(TAG, "Delete bus0");
TEST_ESP_OK(i2c_del_master_bus(i2c_mst_handle1));
#if SOC_I2C_NUM > 1
ESP_LOGI(TAG, "Delete bus1");
TEST_ESP_OK(i2c_del_master_bus(i2c_mst_handle2));
#endif
}
TEST_CASE("I2C driver memory leaking check", "[i2c]")
{
i2c_master_bus_config_t i2c_mst_config_1 = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = TEST_I2C_PORT,
.scl_io_num = TEST_I2C_SCL_PIN,
.sda_io_num = TEST_I2C_SDA_PIN,
};
i2c_master_bus_handle_t bus_handle;
int size = esp_get_free_heap_size();
for (uint32_t i = 0; i <= 5; i++) {
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_1, &bus_handle));
vTaskDelay(10 / portTICK_PERIOD_MS);
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
}
TEST_ASSERT_INT_WITHIN(300, size, esp_get_free_heap_size());
}
TEST_CASE("I2C device add & remove check", "[i2c]")
{
i2c_master_bus_config_t i2c_mst_config_1 = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = TEST_I2C_PORT,
.scl_io_num = TEST_I2C_SCL_PIN,
.sda_io_num = TEST_I2C_SDA_PIN,
};
i2c_master_bus_handle_t bus_handle;
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_1, &bus_handle));
i2c_device_config_t dev_cfg_1 = {
.scl_speed_hz = 100*1000,
.device_address = 0x10,
};
i2c_master_dev_handle_t dev_1;
i2c_master_bus_add_device(bus_handle, &dev_cfg_1, &dev_1);
i2c_device_config_t dev_cfg_2 = {
.scl_speed_hz = 100*1000,
.device_address = 0x20,
};
i2c_master_dev_handle_t dev_2;
i2c_master_bus_add_device(bus_handle, &dev_cfg_2, &dev_2);
i2c_device_config_t dev_cfg_3 = {
.scl_speed_hz = 100*1000,
.device_address = 0x30,
};
i2c_master_dev_handle_t dev_3;
i2c_master_bus_add_device(bus_handle, &dev_cfg_3, &dev_3);
i2c_master_bus_rm_device(dev_1);
i2c_master_bus_rm_device(dev_2);
i2c_master_bus_rm_device(dev_3);
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
}
@@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.supported_targets
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'release',
'iram_safe',
],
indirect=True,
)
def test_i2c(dut: Dut) -> None:
dut.run_all_single_board_cases()
@@ -0,0 +1,6 @@
CONFIG_PM_ENABLE=y
CONFIG_COMPILER_DUMP_RTL_FILES=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_NONE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_I2C_ISR_IRAM_SAFE=y
@@ -0,0 +1,22 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS
"$ENV{IDF_PATH}/tools/unit-test-app/components"
)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(legacy_i2c_test)
if(CONFIG_COMPILER_DUMP_RTL_FILES)
add_custom_target(check_test_app_sections ALL
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
--rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/driver/,${CMAKE_BINARY_DIR}/esp-idf/hal/
--elf-file ${CMAKE_BINARY_DIR}/legacy_i2c_test.elf
find-refs
--from-sections=.iram0.text
--to-sections=.flash.text,.flash.rodata
--exit-code
DEPENDS ${elf}
)
endif()
@@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
@@ -0,0 +1,6 @@
set(srcs "test_app_main.c"
"test_i2c.c"
)
idf_component_register(SRCS ${srcs}
WHOLE_ARCHIVE)
@@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "unity_test_utils_memory.h"
#include "esp_heap_caps.h"
// Some resources are lazy allocated in I2C driver, so we reserved this threshold when checking memory leak
// A better way to check a potential memory leak is running a same case by twice, for the second time, the memory usage delta should be zero
#define LEAKS (400)
void setUp(void)
{
unity_utils_record_free_mem();
}
void tearDown(void)
{
unity_utils_evaluate_leaks_direct(LEAKS);
}
void app_main(void)
{
// ___ ____ ____ _____ _
// |_ _|___ \ / ___| |_ _|__ ___| |_
// | | __) | | | |/ _ \/ __| __|
// | | / __/| |___ | | __/\__ \ |_
// |___|_____|\____| |_|\___||___/\__|
printf(" ___ ____ ____ _____ _ \n");
printf("|_ _|___ \\ / ___| |_ _|__ ___| |_ \n");
printf(" | | __) | | | |/ _ \\/ __| __|\n");
printf(" | | / __/| |___ | | __/\\__ \\ |_ \n");
printf("|___|_____|\\____| |_|\\___||___/\\__|\n");
unity_run_menu();
}
@@ -15,7 +15,7 @@ from pytest_embedded import Dut
],
indirect=True,
)
def test_i2c(dut: Dut) -> None:
def test_i2c_legacy(dut: Dut) -> None:
dut.run_all_single_board_cases()
@@ -33,7 +33,7 @@ def test_i2c(dut: Dut) -> None:
],
indirect=True
)
def test_i2c_multi_dev(case_tester) -> None: # type: ignore
def test_i2c_multi_dev_legacy(case_tester) -> None: # type: ignore
for case in case_tester.test_menu:
if case.attributes.get('test_env', 'generic_multi_device') == 'generic_multi_device':
case_tester.run_multi_dev_case(case=case, reset=True)
@@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n
@@ -0,0 +1,5 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
@@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n