From c9f85d8d1b64a0d6b9836efa17df59ca6a270219 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Tue, 24 Oct 2023 18:46:27 +0800 Subject: [PATCH] feat(i2c_test): Add multi board test for I2C master and I2C slave --- .../i2c_test_apps/main/CMakeLists.txt | 21 +- .../test_apps/i2c_test_apps/main/test_board.h | 42 ++ .../i2c_test_apps/main/test_i2c_10bit.c | 196 +++++++ .../i2c_test_apps/main/test_i2c_broadcast.c | 121 +++++ .../main/{test_i2c.c => test_i2c_common.c} | 32 +- .../i2c_test_apps/main/test_i2c_iram.c | 141 +++++ .../i2c_test_apps/main/test_i2c_multi.c | 487 ++++++++++++++++++ .../i2c_test_apps/main/test_i2c_ram.c | 215 ++++++++ .../test_apps/i2c_test_apps/pytest_i2c.py | 20 + .../legacy_i2c_driver/main/test_i2c.c | 60 +++ 10 files changed, 1317 insertions(+), 18 deletions(-) create mode 100644 components/driver/test_apps/i2c_test_apps/main/test_board.h create mode 100644 components/driver/test_apps/i2c_test_apps/main/test_i2c_10bit.c create mode 100644 components/driver/test_apps/i2c_test_apps/main/test_i2c_broadcast.c rename components/driver/test_apps/i2c_test_apps/main/{test_i2c.c => test_i2c_common.c} (87%) create mode 100644 components/driver/test_apps/i2c_test_apps/main/test_i2c_iram.c create mode 100644 components/driver/test_apps/i2c_test_apps/main/test_i2c_multi.c create mode 100644 components/driver/test_apps/i2c_test_apps/main/test_i2c_ram.c diff --git a/components/driver/test_apps/i2c_test_apps/main/CMakeLists.txt b/components/driver/test_apps/i2c_test_apps/main/CMakeLists.txt index 61d8e9dae6..b09b511df0 100644 --- a/components/driver/test_apps/i2c_test_apps/main/CMakeLists.txt +++ b/components/driver/test_apps/i2c_test_apps/main/CMakeLists.txt @@ -1,7 +1,26 @@ set(srcs "test_app_main.c" - "test_i2c.c" + "test_i2c_common.c" ) +if(CONFIG_SOC_I2C_SUPPORT_SLAVE) + list(APPEND srcs "test_i2c_multi.c") + if(CONFIG_I2C_ISR_IRAM_SAFE) + list(APPEND srcs "test_i2c_iram.c") + endif() +endif() + +if(CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST) + list(APPEND srcs "test_i2c_broadcast.c") +endif() + +if(CONFIG_SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS) + list(APPEND srcs "test_i2c_ram.c") +endif() + +if(CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR AND CONFIG_SOC_I2C_SUPPORT_SLAVE) + list(APPEND srcs "test_i2c_10bit.c") +endif() + idf_component_register(SRCS ${srcs} PRIV_REQUIRES unity driver test_utils WHOLE_ARCHIVE) diff --git a/components/driver/test_apps/i2c_test_apps/main/test_board.h b/components/driver/test_apps/i2c_test_apps/main/test_board.h new file mode 100644 index 0000000000..e420180d5a --- /dev/null +++ b/components/driver/test_apps/i2c_test_apps/main/test_board.h @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_IDF_TARGET_ESP32 +#define I2C_SLAVE_SCL_IO 18 /*! +#include +#include "sdkconfig.h" +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.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 "driver/i2c_slave.h" +#include "esp_rom_gpio.h" +#include "esp_log.h" +#include "test_utils.h" +#include "test_board.h" + +static QueueHandle_t s_receive_queue; + +static IRAM_ATTR bool example_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data) +{ + BaseType_t high_task_wakeup = pdFALSE; + QueueHandle_t receive_queue = (QueueHandle_t)user_data; + xQueueSendFromISR(receive_queue, edata, &high_task_wakeup); + return high_task_wakeup == pdTRUE; +} + +static void i2c_master_write_test_10bit(void) +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + int i; + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_10, + .device_address = 0x134, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + disp_buf(data_wr, i); + TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void i2c_slave_read_test_10bit(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_10, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x134, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t)); + i2c_slave_event_callbacks_t cbs = { + .on_recv_done = example_i2c_rx_done_callback, + }; + ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue)); + + i2c_slave_rx_done_event_data_t rx_data; + TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(1000)); + + disp_buf(data_rd, DATA_LENGTH); + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i] == i); + } + vQueueDelete(s_receive_queue); + unity_send_signal("ready to delete"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test 10 bit", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_10bit, i2c_slave_read_test_10bit); + + +static void master_read_slave_test_10bit(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_10, + .device_address = 0x134, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + printf("Slave please write data to buffer\n"); + + unity_send_signal("slave write"); + unity_wait_for_signal("master read"); + + TEST_ESP_OK(i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + for (int i = 0; i < DATA_LENGTH; i++) { + printf("%d\n", data_rd[i]); + TEST_ASSERT(data_rd[i]==i); + } + unity_send_signal("ready to delete 10bit"); + + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void slave_write_buffer_test_10bit(void) +{ + uint8_t data_wr[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_10, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x134, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("slave write"); + for (int i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + TEST_ESP_OK(i2c_slave_transmit(slave_handle, data_wr, DATA_LENGTH, -1)); + disp_buf(data_wr, DATA_LENGTH); + unity_send_signal("master read"); + unity_wait_for_signal("ready to delete 10bit"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + + +TEST_CASE_MULTIPLE_DEVICES("I2C master read slave test 10 bit", "[i2c][test_env=generic_multi_device][timeout=150]", master_read_slave_test_10bit, slave_write_buffer_test_10bit); diff --git a/components/driver/test_apps/i2c_test_apps/main/test_i2c_broadcast.c b/components/driver/test_apps/i2c_test_apps/main/test_i2c_broadcast.c new file mode 100644 index 0000000000..e6cf562289 --- /dev/null +++ b/components/driver/test_apps/i2c_test_apps/main/test_i2c_broadcast.c @@ -0,0 +1,121 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + + +#include +#include +#include "sdkconfig.h" +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.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 "driver/i2c_slave.h" +#include "esp_rom_gpio.h" +#include "esp_log.h" +#include "test_utils.h" +#include "test_board.h" + +static QueueHandle_t s_receive_queue; + +static IRAM_ATTR bool example_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data) +{ + BaseType_t high_task_wakeup = pdFALSE; + QueueHandle_t receive_queue = (QueueHandle_t)user_data; + xQueueSendFromISR(receive_queue, edata, &high_task_wakeup); + return high_task_wakeup == pdTRUE; +} + +static void i2c_master_write_test_broadcast(void) +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + int i; + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x00, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + disp_buf(data_wr, i); + TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void i2c_slave_read_test_broadcast(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x53, + .flags.broadcast_en = true, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t)); + i2c_slave_event_callbacks_t cbs = { + .on_recv_done = example_i2c_rx_done_callback, + }; + ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue)); + + i2c_slave_rx_done_event_data_t rx_data; + TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + + xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(1000)); + disp_buf(data_rd, DATA_LENGTH); + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i] == i); + } + vQueueDelete(s_receive_queue); + unity_send_signal("ready to delete"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test broadcast", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_broadcast, i2c_slave_read_test_broadcast); diff --git a/components/driver/test_apps/i2c_test_apps/main/test_i2c.c b/components/driver/test_apps/i2c_test_apps/main/test_i2c_common.c similarity index 87% rename from components/driver/test_apps/i2c_test_apps/main/test_i2c.c rename to components/driver/test_apps/i2c_test_apps/main/test_i2c_common.c index 17152f67c5..ee307c32a3 100644 --- a/components/driver/test_apps/i2c_test_apps/main/test_i2c.c +++ b/components/driver/test_apps/i2c_test_apps/main/test_i2c_common.c @@ -22,23 +22,18 @@ #include "esp_rom_gpio.h" #include "esp_log.h" #include "test_utils.h" +#include "test_board.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, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, }; i2c_master_bus_handle_t i2c_mst_handle1; @@ -46,8 +41,9 @@ TEST_CASE("I2C bus install-uninstall test", "[i2c]") 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, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, }; i2c_master_bus_handle_t i2c_mst_handle2; #endif @@ -75,8 +71,9 @@ 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, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, }; i2c_master_bus_handle_t bus_handle; @@ -95,8 +92,9 @@ 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, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, }; i2c_master_bus_handle_t bus_handle; @@ -137,8 +135,8 @@ TEST_CASE("I2C master probe device 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, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, .flags.enable_internal_pullup = true, }; i2c_master_bus_handle_t bus_handle; diff --git a/components/driver/test_apps/i2c_test_apps/main/test_i2c_iram.c b/components/driver/test_apps/i2c_test_apps/main/test_i2c_iram.c new file mode 100644 index 0000000000..d59967fb0e --- /dev/null +++ b/components/driver/test_apps/i2c_test_apps/main/test_i2c_iram.c @@ -0,0 +1,141 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.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 "driver/i2c_slave.h" +#include "esp_rom_gpio.h" +#include "esp_log.h" +#include "test_utils.h" +#include "test_board.h" +#include "unity_test_utils_cache.h" + +static QueueHandle_t s_send_queue; +static QueueHandle_t s_receive_queue; + +static IRAM_ATTR bool test_master_tx_done_callback(i2c_master_dev_handle_t i2c_dev, const i2c_master_event_data_t *evt_data, void *arg) +{ + BaseType_t high_task_wakeup = pdFALSE; + QueueHandle_t s_send_queue = (QueueHandle_t)arg; + xQueueSendFromISR(s_send_queue, evt_data, &high_task_wakeup); + return high_task_wakeup == pdTRUE; +} + +static IRAM_ATTR bool test_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data) +{ + BaseType_t high_task_wakeup = pdFALSE; + QueueHandle_t receive_queue = (QueueHandle_t)user_data; + xQueueSendFromISR(receive_queue, edata, &high_task_wakeup); + return high_task_wakeup == pdTRUE; +} + +static void IRAM_ATTR test_delay_post_cache_disable(void *args) +{ + esp_rom_delay_us(10000); +} + +static void i2c_master_write_test_iram_safe(void) +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + int i; + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + .trans_queue_depth = 200, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + s_send_queue = xQueueCreate(1, sizeof(i2c_master_event_data_t)); + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + i2c_master_event_callbacks_t cbs = { + .on_trans_done = test_master_tx_done_callback, + }; + i2c_master_event_data_t evt_data; + i2c_master_register_event_callbacks(dev_handle, &cbs, s_send_queue); + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + disp_buf(data_wr, i); + TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + unity_utils_run_cache_disable_stub(test_delay_post_cache_disable, NULL); + xQueueReceive(s_send_queue, &evt_data, pdMS_TO_TICKS(10000)); + unity_wait_for_signal("ready to delete"); + vQueueDelete(s_send_queue); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void i2c_slave_read_test_iram_safe(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t)); + i2c_slave_event_callbacks_t cbs = { + .on_recv_done = test_i2c_rx_done_callback, + }; + ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue)); + + i2c_slave_rx_done_event_data_t rx_data; + TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH)); + unity_utils_run_cache_disable_stub(test_delay_post_cache_disable, NULL); + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000)); + disp_buf(data_rd, DATA_LENGTH); + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i] == i); + } + vQueueDelete(s_receive_queue); + unity_send_signal("ready to delete"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test iram safe", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_iram_safe, i2c_slave_read_test_iram_safe); diff --git a/components/driver/test_apps/i2c_test_apps/main/test_i2c_multi.c b/components/driver/test_apps/i2c_test_apps/main/test_i2c_multi.c new file mode 100644 index 0000000000..eaf026f0c8 --- /dev/null +++ b/components/driver/test_apps/i2c_test_apps/main/test_i2c_multi.c @@ -0,0 +1,487 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + + +#include +#include +#include "sdkconfig.h" +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.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 "driver/i2c_slave.h" +#include "esp_rom_gpio.h" +#include "esp_log.h" +#include "test_utils.h" +#include "test_board.h" + +void disp_buf(uint8_t *buf, int len) +{ + int i; + for (i = 0; i < len; i++) { + printf("%02x ", buf[i]); + if (( i + 1 ) % 16 == 0) { + printf("\n"); + } + } + printf("\n"); +} + +#define DATA_LENGTH 100 + +static QueueHandle_t s_receive_queue; + +static IRAM_ATTR bool test_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data) +{ + BaseType_t high_task_wakeup = pdFALSE; + QueueHandle_t receive_queue = (QueueHandle_t)user_data; + xQueueSendFromISR(receive_queue, edata, &high_task_wakeup); + return high_task_wakeup == pdTRUE; +} + +static void i2c_master_write_test(void) +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + int i; + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + disp_buf(data_wr, i); + TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void i2c_slave_read_test(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t)); + i2c_slave_event_callbacks_t cbs = { + .on_recv_done = test_i2c_rx_done_callback, + }; + ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue)); + + i2c_slave_rx_done_event_data_t rx_data; + TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000)); + disp_buf(data_rd, DATA_LENGTH); + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i] == i); + } + vQueueDelete(s_receive_queue); + unity_send_signal("ready to delete"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test, i2c_slave_read_test); + + +static void master_read_slave_test(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + printf("Slave please write data to buffer\n"); + + unity_send_signal("slave write"); + unity_wait_for_signal("master read"); + + TEST_ESP_OK(i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + for (int i = 0; i < DATA_LENGTH; i++) { + printf("%d\n", data_rd[i]); + TEST_ASSERT(data_rd[i]==i); + } + unity_send_signal("ready to delete master read test"); + + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void slave_write_buffer_test(void) +{ + uint8_t data_wr[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("slave write"); + for (int i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + TEST_ESP_OK(i2c_slave_transmit(slave_handle, data_wr, DATA_LENGTH, -1)); + disp_buf(data_wr, DATA_LENGTH); + unity_send_signal("master read"); + unity_wait_for_signal("ready to delete master read test"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + + +TEST_CASE_MULTIPLE_DEVICES("I2C master read slave test", "[i2c][test_env=generic_multi_device][timeout=150]", master_read_slave_test, slave_write_buffer_test); + +static void i2c_master_write_read_test(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + uint8_t data_wr[DATA_LENGTH] = {0}; + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + printf("master read buffer\n"); + + unity_send_signal("slave write"); + unity_wait_for_signal("master read and write"); + + TEST_ESP_OK(i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + disp_buf(data_rd, DATA_LENGTH); + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i] == i); + } + + for (int i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + vTaskDelay(100 / portTICK_PERIOD_MS); + unity_send_signal("slave read"); + unity_wait_for_signal("ready to read"); + TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + unity_send_signal("sent done"); + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void i2c_slave_read_write_test(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + uint8_t data_wr[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t)); + i2c_slave_event_callbacks_t cbs = { + .on_recv_done = test_i2c_rx_done_callback, + }; + ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue)); + + unity_send_signal("i2c slave init finish"); + unity_wait_for_signal("slave write"); + + for (int i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + TEST_ESP_OK(i2c_slave_transmit(slave_handle, data_wr, DATA_LENGTH, -1)); + disp_buf(data_wr, DATA_LENGTH); + unity_send_signal("master read and write"); + unity_wait_for_signal("slave read"); + TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH)); + unity_send_signal("ready to read"); + unity_wait_for_signal("sent done"); + i2c_slave_rx_done_event_data_t rx_data; + xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(1000)); + + printf("slave read data is:\n"); + disp_buf(data_rd, DATA_LENGTH); + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i] == i); + } + unity_send_signal("ready to delete"); + vQueueDelete(s_receive_queue); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C read and write test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_read_test, i2c_slave_read_write_test); + + +static void i2c_master_repeat_write(void) +{ + uint8_t data_wr[DATA_LENGTH] = {0}; + int times = 3; + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + + i2c_master_bus_handle_t bus_handle; + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + for (int j = 0; j < times; j++) { + for (int i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = j + i; + } + TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + disp_buf(data_wr, DATA_LENGTH); + } + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void i2c_slave_repeat_read(void) +{ + uint32_t size = 0; + int times = 3; + uint8_t data_rd[DATA_LENGTH * 3] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t)); + i2c_slave_event_callbacks_t cbs = { + .on_recv_done = test_i2c_rx_done_callback, + }; + TEST_ESP_OK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue)); + + unity_send_signal("i2c slave init finish"); + + while (times > 0) { + i2c_slave_rx_done_event_data_t rx_data; + TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd + size, DATA_LENGTH)); + xQueueReceive(s_receive_queue, &rx_data, (TickType_t)portMAX_DELAY); + + size += DATA_LENGTH; + times--; + } + + disp_buf(data_rd, size); + for (int j = 0; j < times; j++) { + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i + DATA_LENGTH * j] == (i + j)); + } + } + unity_send_signal("ready to delete"); + vQueueDelete(s_receive_queue); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C repeat write test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_repeat_write, i2c_slave_repeat_read); + +#if SOC_I2C_NUM > 1 +// Now chips with mutiple I2C controllers are up to 2, can change this to interation when we have more I2C controllers. +static void i2c_master_write_test_more_port(void) +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + int i; + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = 1, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + disp_buf(data_wr, i); + TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void i2c_slave_read_test_more_port(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = 1, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t)); + i2c_slave_event_callbacks_t cbs = { + .on_recv_done = test_i2c_rx_done_callback, + }; + ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue)); + + i2c_slave_rx_done_event_data_t rx_data; + TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000)); + disp_buf(data_rd, DATA_LENGTH); + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i] == i); + } + vQueueDelete(s_receive_queue); + unity_send_signal("ready to delete"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test, more ports", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_more_port, i2c_slave_read_test_more_port); +#endif diff --git a/components/driver/test_apps/i2c_test_apps/main/test_i2c_ram.c b/components/driver/test_apps/i2c_test_apps/main/test_i2c_ram.c new file mode 100644 index 0000000000..165d3afb3b --- /dev/null +++ b/components/driver/test_apps/i2c_test_apps/main/test_i2c_ram.c @@ -0,0 +1,215 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + + +#include +#include +#include "sdkconfig.h" +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.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 "driver/i2c_slave.h" +#include "esp_rom_gpio.h" +#include "esp_log.h" +#include "test_utils.h" +#include "test_board.h" + +static esp_err_t i2c_master_write_to_addr(i2c_master_dev_handle_t device_handle, uint8_t address, const uint8_t *data, uint32_t size, int xfer_timeout_ms) +{ + esp_err_t ret = ESP_OK; + uint8_t *buffer = (uint8_t*)calloc(1, size + 1); + buffer[0] = address; + memcpy(buffer + 1, data, size); + ret = i2c_master_transmit(device_handle, buffer, 1 + size, xfer_timeout_ms); + return ret; +} + +#define DATA_LENGTH_RAM 6 + +static void i2c_master_write_to_ram_test(void) +{ + uint8_t data_wr[DATA_LENGTH_RAM] = { 0 }; + int i; + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH_RAM; i++) { + data_wr[i] = i + 1; + } + disp_buf(data_wr, i); + // Write slave ram address is 0x5. + i2c_master_write_to_addr(dev_handle, 0x5, data_wr, DATA_LENGTH_RAM, -1); + + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void i2c_slave_read_from_ram_test(void) +{ + uint8_t data_rd[DATA_LENGTH_RAM] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + .flags.access_ram_en = true, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + + TEST_ESP_OK(i2c_slave_read_ram(slave_handle, 0x5, data_rd, DATA_LENGTH_RAM)); + + disp_buf(data_rd, DATA_LENGTH_RAM); + for (int i = 0; i < DATA_LENGTH_RAM; i++) { + TEST_ASSERT(data_rd[i] == (i + 1)); + } + unity_send_signal("ready to delete"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test - slave directly read from ram", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_to_ram_test, i2c_slave_read_from_ram_test); + + +static void master_read_slave_from_ram_test(void) +{ + uint8_t data_rd[DATA_LENGTH_RAM] = {0}; + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + printf("Slave please write data to buffer\n"); + + unity_send_signal("slave write"); + unity_wait_for_signal("master read"); + + uint8_t *buffer = (uint8_t*)malloc(sizeof(uint8_t)); + buffer[0] = 0x2; // Means write offset 2 in I2C ram. + TEST_ESP_OK(i2c_master_transmit_receive(dev_handle, buffer, 1, data_rd, DATA_LENGTH_RAM, -1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + for (int i = 0; i < DATA_LENGTH_RAM; i++) { + printf("%d\n", data_rd[i]); + TEST_ASSERT(data_rd[i]==i); + } + unity_send_signal("ready to delete ram test"); + + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void slave_write_buffer_to_ram_test(void) +{ + uint8_t data_wr[DATA_LENGTH_RAM] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + .flags.access_ram_en = true, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("slave write"); + for (int i = 0; i < DATA_LENGTH_RAM; i++) { + data_wr[i] = i; + } + + TEST_ESP_OK(i2c_slave_write_ram(slave_handle, 0x2, data_wr, DATA_LENGTH_RAM)); + disp_buf(data_wr, DATA_LENGTH_RAM); + unity_send_signal("master read"); + unity_wait_for_signal("ready to delete ram test"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + + +TEST_CASE_MULTIPLE_DEVICES("I2C master read slave ram test", "[i2c][test_env=generic_multi_device][timeout=150]", master_read_slave_from_ram_test, slave_write_buffer_to_ram_test); + +TEST_CASE("I2C slave init as ram but read by fifo", "[i2c]") +{ + uint8_t data_rd[10] = {0}; + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + .flags.access_ram_en = true, + }; + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, i2c_slave_receive(slave_handle, data_rd, 10)); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} diff --git a/components/driver/test_apps/i2c_test_apps/pytest_i2c.py b/components/driver/test_apps/i2c_test_apps/pytest_i2c.py index 21bd8b4348..afcf27563f 100644 --- a/components/driver/test_apps/i2c_test_apps/pytest_i2c.py +++ b/components/driver/test_apps/i2c_test_apps/pytest_i2c.py @@ -17,3 +17,23 @@ from pytest_embedded import Dut ) def test_i2c(dut: Dut) -> None: dut.run_all_single_board_cases() + + +@pytest.mark.esp32 +@pytest.mark.esp32c3 +@pytest.mark.esp32c6 +@pytest.mark.esp32h2 +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.generic_multi_device +@pytest.mark.parametrize( + 'count, config', + [ + (2, 'defaults',), + ], + indirect=True +) +def test_i2c_multi_device(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) diff --git a/components/driver/test_apps/legacy_i2c_driver/main/test_i2c.c b/components/driver/test_apps/legacy_i2c_driver/main/test_i2c.c index b8f4257a31..ea4b03da85 100644 --- a/components/driver/test_apps/legacy_i2c_driver/main/test_i2c.c +++ b/components/driver/test_apps/legacy_i2c_driver/main/test_i2c.c @@ -508,6 +508,66 @@ static void i2c_slave_repeat_read(void) TEST_CASE_MULTIPLE_DEVICES("I2C repeat write test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_repeat_write, i2c_slave_repeat_read); +#if SOC_I2C_NUM > 1 + +static void i2c_master_write_test_more_ports(void) +{ + uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH); + int i; + + i2c_config_t conf_master = i2c_master_init(); + TEST_ESP_OK(i2c_param_config(I2C_NUM_1, &conf_master)); + + TEST_ESP_OK(i2c_driver_install(I2C_NUM_1, I2C_MODE_MASTER, + I2C_MASTER_RX_BUF_DISABLE, + I2C_MASTER_TX_BUF_DISABLE, 0)); + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH / 2; i++) { + data_wr[i] = i; + } + i2c_master_write_slave(I2C_NUM_1, data_wr, DATA_LENGTH / 2); + disp_buf(data_wr, i); + free(data_wr); + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_driver_delete(I2C_NUM_1)); +} + +static void i2c_slave_read_test_more_ports(void) +{ + uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH); + int size_rd = 0; + int len = 0; + + i2c_config_t conf_slave = i2c_slave_init(); + TEST_ESP_OK(i2c_param_config( I2C_NUM_1, &conf_slave)); + TEST_ESP_OK(i2c_driver_install(I2C_NUM_1, I2C_MODE_SLAVE, + I2C_SLAVE_RX_BUF_LEN, + I2C_SLAVE_TX_BUF_LEN, 0)); + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + while (1) { + len = i2c_slave_read_buffer( I2C_NUM_1, data_rd + size_rd, DATA_LENGTH, 10000 / portTICK_PERIOD_MS); + if (len == 0) { + break; + } + size_rd += len; + } + disp_buf(data_rd, size_rd); + for (int i = 0; i < size_rd; i++) { + TEST_ASSERT(data_rd[i] == i); + } + free(data_rd); + unity_send_signal("ready to delete"); + TEST_ESP_OK(i2c_driver_delete(I2C_NUM_1)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test, more ports", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_more_ports, i2c_slave_read_test_more_ports); + +#endif + static volatile bool exit_flag; static bool test_read_func;