mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-03 10:30:58 +02:00
Merge branch 'test/add_i3c_multi_test' into 'master'
test(i3c_master): Add multi test for i3c master, adding i3c slave ll support. Closes IDFCI-3058 See merge request espressif/esp-idf!41049
This commit is contained in:
@@ -332,14 +332,14 @@ static esp_err_t i3c_pins_config(const i3c_master_bus_config_t *bus_config)
|
|||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
// SDA pin configurations
|
// SDA pin configurations
|
||||||
ESP_RETURN_ON_ERROR(gpio_set_level(bus_config->sda_io_num, 1), TAG, "i2c sda pin set level failed");
|
ESP_RETURN_ON_ERROR(gpio_set_level(bus_config->sda_io_num, 1), TAG, "i3c sda pin set level failed");
|
||||||
gpio_input_enable(bus_config->sda_io_num);
|
gpio_input_enable(bus_config->sda_io_num);
|
||||||
gpio_func_sel(bus_config->sda_io_num, PIN_FUNC_GPIO);
|
gpio_func_sel(bus_config->sda_io_num, PIN_FUNC_GPIO);
|
||||||
gpio_matrix_output(bus_config->sda_io_num, i3c_master_periph_signal->sda_out_sig, 0, 0);
|
gpio_matrix_output(bus_config->sda_io_num, i3c_master_periph_signal->sda_out_sig, 0, 0);
|
||||||
gpio_matrix_input(bus_config->sda_io_num, i3c_master_periph_signal->sda_in_sig, 0);
|
gpio_matrix_input(bus_config->sda_io_num, i3c_master_periph_signal->sda_in_sig, 0);
|
||||||
|
|
||||||
// SCL pin configurations
|
// SCL pin configurations
|
||||||
ESP_RETURN_ON_ERROR(gpio_set_level(bus_config->scl_io_num, 1), TAG, "i2c scl pin set level failed");
|
ESP_RETURN_ON_ERROR(gpio_set_level(bus_config->scl_io_num, 1), TAG, "i3c scl pin set level failed");
|
||||||
gpio_input_enable(bus_config->scl_io_num);
|
gpio_input_enable(bus_config->scl_io_num);
|
||||||
gpio_func_sel(bus_config->scl_io_num, PIN_FUNC_GPIO);
|
gpio_func_sel(bus_config->scl_io_num, PIN_FUNC_GPIO);
|
||||||
gpio_matrix_output(bus_config->scl_io_num, i3c_master_periph_signal->scl_out_sig, 0, 0);
|
gpio_matrix_output(bus_config->scl_io_num, i3c_master_periph_signal->scl_out_sig, 0, 0);
|
||||||
@@ -445,7 +445,6 @@ static esp_err_t do_dma_transaction_handler(i3c_master_bus_handle_t bus_handle,
|
|||||||
{
|
{
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
bus_handle->cur_trans = trans;
|
bus_handle->cur_trans = trans;
|
||||||
printf("here, do dma\n");
|
|
||||||
|
|
||||||
portENTER_CRITICAL_SAFE(&bus_handle->spinlock);
|
portENTER_CRITICAL_SAFE(&bus_handle->spinlock);
|
||||||
if (trans->scl_freq_hz > 400 * 1000) {
|
if (trans->scl_freq_hz > 400 * 1000) {
|
||||||
@@ -509,7 +508,6 @@ static esp_err_t do_dma_transaction_handler(i3c_master_bus_handle_t bus_handle,
|
|||||||
portENTER_CRITICAL_SAFE(&bus_handle->spinlock);
|
portENTER_CRITICAL_SAFE(&bus_handle->spinlock);
|
||||||
i3c_master_ll_start_transaction(bus_handle->hal.dev);
|
i3c_master_ll_start_transaction(bus_handle->hal.dev);
|
||||||
portEXIT_CRITICAL_SAFE(&bus_handle->spinlock);
|
portEXIT_CRITICAL_SAFE(&bus_handle->spinlock);
|
||||||
printf("here, start transaction\n");
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,5 +27,5 @@ endif()
|
|||||||
|
|
||||||
message(STATUS "Checking i3c registers are not read-write by half-word")
|
message(STATUS "Checking i3c registers are not read-write by half-word")
|
||||||
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
|
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
|
||||||
check_register_rw_half_word(SOC_MODULES "i3c_mst" "i3c_mst_mem" "hp_sys_clkrst" "lpperi" "lp_clkrst"
|
check_register_rw_half_word(SOC_MODULES "i3c_mst" "i3c_mst_mem" "hp_sys_clkrst" "i3c_slv"
|
||||||
HAL_MODULES "i3c_master")
|
HAL_MODULES "i3c_master" "i3c_slave")
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
set(srcs "test_app_main.c"
|
set(srcs "test_app_main.c"
|
||||||
"test_i3c_master_common.c"
|
"test_i3c_master_common.cpp"
|
||||||
|
"test_i3c_multi.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
PRIV_REQUIRES unity test_utils esp_driver_i3c
|
PRIV_REQUIRES unity test_utils esp_driver_i3c esp_driver_uart esp_driver_gpio
|
||||||
WHOLE_ARCHIVE)
|
WHOLE_ARCHIVE)
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#define LEAKS (100)
|
#define LEAKS (150)
|
||||||
|
|
||||||
void setUp(void)
|
void setUp(void)
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "soc/gpio_num.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define I3C_SLAVE_SCL_IO GPIO_NUM_32 /*!<gpio number for I3C slave clock */
|
||||||
|
#define I3C_SLAVE_SDA_IO GPIO_NUM_33 /*!<gpio number for I3C slave data */
|
||||||
|
#define I3C_MASTER_SCL_IO GPIO_NUM_32 /*!< gpio number for I3C master clock */
|
||||||
|
#define I3C_MASTER_SDA_IO GPIO_NUM_33 /*!< gpio number for I3C master data */
|
||||||
|
|
||||||
|
#define TEST_STATIC_ADDRESS 0x6a
|
||||||
|
#define TEST_DYNAMIC_ADDRESS 0x06
|
||||||
|
|
||||||
|
#define DATA_LENGTH 16
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@@ -14,16 +14,21 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "test_utils.h"
|
#include "test_utils.h"
|
||||||
|
#include "test_i3c_board.h"
|
||||||
|
#include "driver/uart.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
static const char TAG[] = "test-i3c";
|
static const char TAG[] = "test-i3c";
|
||||||
|
|
||||||
TEST_CASE("I3C bus install-uninstall test", "[i3c]")
|
TEST_CASE("I3C bus install-uninstall test", "[i3c]")
|
||||||
{
|
{
|
||||||
i3c_master_bus_config_t i3c_bus_config = {
|
i3c_master_bus_config_t i3c_bus_config = {
|
||||||
|
.sda_io_num = I3C_MASTER_SDA_IO,
|
||||||
|
.scl_io_num = I3C_MASTER_SCL_IO,
|
||||||
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
||||||
.scl_io_num = 5,
|
|
||||||
.sda_io_num = 6,
|
|
||||||
.trans_queue_depth = 30,
|
.trans_queue_depth = 30,
|
||||||
|
.intr_priority = 0,
|
||||||
|
.flags = {0}
|
||||||
};
|
};
|
||||||
i3c_master_bus_handle_t bus_handle;
|
i3c_master_bus_handle_t bus_handle;
|
||||||
|
|
||||||
@@ -42,10 +47,12 @@ TEST_CASE("I3C bus install-uninstall test", "[i3c]")
|
|||||||
TEST_CASE("I3C driver memory leaking check", "[i3c]")
|
TEST_CASE("I3C driver memory leaking check", "[i3c]")
|
||||||
{
|
{
|
||||||
i3c_master_bus_config_t i3c_bus_config = {
|
i3c_master_bus_config_t i3c_bus_config = {
|
||||||
|
.sda_io_num = I3C_MASTER_SDA_IO,
|
||||||
|
.scl_io_num = I3C_MASTER_SCL_IO,
|
||||||
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
||||||
.scl_io_num = 5,
|
|
||||||
.sda_io_num = 6,
|
|
||||||
.trans_queue_depth = 30,
|
.trans_queue_depth = 30,
|
||||||
|
.intr_priority = 0,
|
||||||
|
.flags = {0}
|
||||||
};
|
};
|
||||||
i3c_master_bus_handle_t bus_handle;
|
i3c_master_bus_handle_t bus_handle;
|
||||||
|
|
||||||
@@ -62,33 +69,34 @@ TEST_CASE("I3C driver memory leaking check", "[i3c]")
|
|||||||
TEST_CASE("I3C device add & remove check", "[i3c]")
|
TEST_CASE("I3C device add & remove check", "[i3c]")
|
||||||
{
|
{
|
||||||
i3c_master_bus_config_t i2c_mst_config_1 = {
|
i3c_master_bus_config_t i2c_mst_config_1 = {
|
||||||
|
.sda_io_num = I3C_MASTER_SDA_IO,
|
||||||
|
.scl_io_num = I3C_MASTER_SCL_IO,
|
||||||
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
||||||
.scl_io_num = 5,
|
|
||||||
.sda_io_num = 6,
|
|
||||||
.flags.enable_async_trans = true,
|
|
||||||
.trans_queue_depth = 30,
|
.trans_queue_depth = 30,
|
||||||
|
.intr_priority = 0,
|
||||||
|
.flags = {.enable_async_trans = 1}
|
||||||
};
|
};
|
||||||
i3c_master_bus_handle_t bus_handle;
|
i3c_master_bus_handle_t bus_handle;
|
||||||
|
|
||||||
TEST_ESP_OK(i3c_new_master_bus(&i2c_mst_config_1, &bus_handle));
|
TEST_ESP_OK(i3c_new_master_bus(&i2c_mst_config_1, &bus_handle));
|
||||||
|
|
||||||
i3c_device_i2c_config_t dev_cfg_1 = {
|
i3c_device_i2c_config_t dev_cfg_1 = {
|
||||||
.scl_freq_hz = 100 * 1000,
|
|
||||||
.device_address = 0x10,
|
.device_address = 0x10,
|
||||||
|
.scl_freq_hz = 100 * 1000
|
||||||
};
|
};
|
||||||
i3c_master_i2c_device_handle_t dev_1;
|
i3c_master_i2c_device_handle_t dev_1;
|
||||||
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg_1, &dev_1));
|
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg_1, &dev_1));
|
||||||
|
|
||||||
i3c_device_i2c_config_t dev_cfg_2 = {
|
i3c_device_i2c_config_t dev_cfg_2 = {
|
||||||
.scl_freq_hz = 100 * 1000,
|
|
||||||
.device_address = 0x20,
|
.device_address = 0x20,
|
||||||
|
.scl_freq_hz = 100 * 1000
|
||||||
};
|
};
|
||||||
i3c_master_i2c_device_handle_t dev_2;
|
i3c_master_i2c_device_handle_t dev_2;
|
||||||
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg_2, &dev_2));
|
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg_2, &dev_2));
|
||||||
|
|
||||||
i3c_device_i2c_config_t dev_cfg_3 = {
|
i3c_device_i2c_config_t dev_cfg_3 = {
|
||||||
.scl_freq_hz = 100 * 1000,
|
|
||||||
.device_address = 0x30,
|
.device_address = 0x30,
|
||||||
|
.scl_freq_hz = 100 * 1000
|
||||||
};
|
};
|
||||||
i3c_master_i2c_device_handle_t dev_3;
|
i3c_master_i2c_device_handle_t dev_3;
|
||||||
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg_3, &dev_3));
|
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg_3, &dev_3));
|
||||||
@@ -100,3 +108,49 @@ TEST_CASE("I3C device add & remove check", "[i3c]")
|
|||||||
TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev_3));
|
TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev_3));
|
||||||
TEST_ESP_OK(i3c_del_master_bus(bus_handle));
|
TEST_ESP_OK(i3c_del_master_bus(bus_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("I3C master clock frequency test", "[i3c]")
|
||||||
|
{
|
||||||
|
uint8_t data_wr[500] = { 0 };
|
||||||
|
|
||||||
|
i3c_master_bus_config_t i3c_mst_config = {
|
||||||
|
.sda_io_num = I3C_MASTER_SDA_IO,
|
||||||
|
.scl_io_num = I3C_MASTER_SCL_IO,
|
||||||
|
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
||||||
|
.trans_queue_depth = 1,
|
||||||
|
.intr_priority = 0,
|
||||||
|
.flags = {0}
|
||||||
|
};
|
||||||
|
i3c_master_bus_handle_t bus_handle;
|
||||||
|
gpio_pullup_en(I3C_MASTER_SCL_IO);
|
||||||
|
gpio_pullup_en(I3C_MASTER_SDA_IO);
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_new_master_bus(&i3c_mst_config, &bus_handle));
|
||||||
|
|
||||||
|
i3c_device_i2c_config_t dev_cfg_1 = {
|
||||||
|
.device_address = TEST_STATIC_ADDRESS,
|
||||||
|
.scl_freq_hz = 400 * 1000
|
||||||
|
};
|
||||||
|
i3c_master_i2c_device_handle_t dev_1;
|
||||||
|
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg_1, &dev_1));
|
||||||
|
|
||||||
|
uart_bitrate_detect_config_t conf = {
|
||||||
|
.rx_io_num = I3C_MASTER_SCL_IO,
|
||||||
|
.source_clk = UART_SCLK_DEFAULT,
|
||||||
|
};
|
||||||
|
uart_bitrate_res_t res = {};
|
||||||
|
uart_detect_bitrate_start(UART_NUM_1, &conf);
|
||||||
|
|
||||||
|
i3c_master_i2c_device_transmit(dev_1, data_wr, 50, -1);
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(50));
|
||||||
|
uart_detect_bitrate_stop(UART_NUM_1, true, &res);
|
||||||
|
|
||||||
|
int freq_hz = res.clk_freq_hz / res.pos_period;
|
||||||
|
printf("The tested I3C SCL frequency(fm) is %d\n", freq_hz);
|
||||||
|
TEST_ASSERT_INT_WITHIN(500, 400000, freq_hz);
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev_1));
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_del_master_bus(bus_handle));
|
||||||
|
}
|
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 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 "esp_err.h"
|
||||||
|
#include "soc/clk_tree_defs.h"
|
||||||
|
#include "esp_private/periph_ctrl.h"
|
||||||
|
#include "driver/i3c_master.h"
|
||||||
|
#include "driver/i3c_master_i2c.h"
|
||||||
|
#include "hal/i3c_slave_ll.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "test_utils.h"
|
||||||
|
#include "test_i3c_board.h"
|
||||||
|
#include "esp_private/gpio.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "soc/gpio_sig_map.h"
|
||||||
|
#include "soc/io_mux_reg.h"
|
||||||
|
#include "soc/i3c_slv_struct.h"
|
||||||
|
#include "soc/i3c_slv_reg.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
static const char TAG[] = "test-i3c";
|
||||||
|
|
||||||
|
static esp_err_t i3c_slave_pins_config(void)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
// SDA pin configurations
|
||||||
|
gpio_input_enable(I3C_SLAVE_SDA_IO);
|
||||||
|
gpio_func_sel(I3C_SLAVE_SDA_IO, PIN_FUNC_GPIO);
|
||||||
|
gpio_matrix_output(I3C_SLAVE_SDA_IO, I3C_SLV_SDA_PAD_OUT_IDX, 0, 0);
|
||||||
|
gpio_matrix_input(I3C_SLAVE_SDA_IO, I3C_SLV_SDA_PAD_IN_IDX, 0);
|
||||||
|
|
||||||
|
// SCL pin configurations
|
||||||
|
gpio_input_enable(I3C_SLAVE_SCL_IO);
|
||||||
|
gpio_func_sel(I3C_SLAVE_SCL_IO, PIN_FUNC_GPIO);
|
||||||
|
gpio_matrix_output(I3C_SLAVE_SCL_IO, I3C_SLV_SCL_PAD_OUT_IDX, 0, 0);
|
||||||
|
gpio_matrix_input(I3C_SLAVE_SCL_IO, I3C_SLV_SCL_PAD_IN_IDX, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i3c_slave_init(void)
|
||||||
|
{
|
||||||
|
PERIPH_RCC_ATOMIC() {
|
||||||
|
i3c_slave_ll_enable_bus_clock(&I3C_SLV, true);
|
||||||
|
i3c_slave_ll_reset_register(&I3C_SLV);
|
||||||
|
}
|
||||||
|
|
||||||
|
i3c_slave_pins_config();
|
||||||
|
i3c_slave_ll_config_static_address(&I3C_SLV, TEST_STATIC_ADDRESS);
|
||||||
|
i3c_slave_ll_enable_intr_mask(&I3C_SLV, I3C_SLAVE_LL_EVENT_INTR);
|
||||||
|
|
||||||
|
i3c_slave_ll_unlock_register(&I3C_SLV, true);
|
||||||
|
i3c_slave_ll_set_transmit_fifo_threshold(&I3C_SLV, 1);
|
||||||
|
i3c_slave_ll_set_receive_fifo_threshold(&I3C_SLV, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i3c_i2c_slave_read_test(void)
|
||||||
|
{
|
||||||
|
unity_wait_for_signal("i2c master init first");
|
||||||
|
|
||||||
|
uint8_t *temp_data = (uint8_t*)heap_caps_malloc(DATA_LENGTH, MALLOC_CAP_DEFAULT);
|
||||||
|
assert(temp_data);
|
||||||
|
|
||||||
|
i3c_slave_init();
|
||||||
|
|
||||||
|
unity_send_signal("i2c slave init finish");
|
||||||
|
|
||||||
|
unity_wait_for_signal("master write");
|
||||||
|
|
||||||
|
i3c_slave_ll_read_data(&I3C_SLV, temp_data, DATA_LENGTH);
|
||||||
|
|
||||||
|
ESP_LOG_BUFFER_HEX(TAG, temp_data, DATA_LENGTH);
|
||||||
|
|
||||||
|
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||||
|
TEST_ASSERT(temp_data[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
unity_send_signal("ready to delete");
|
||||||
|
free(temp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i3c_i2c_master_write_test(void)
|
||||||
|
{
|
||||||
|
uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i3c_master_bus_config_t i3c_mst_config = {
|
||||||
|
.sda_io_num = I3C_MASTER_SDA_IO,
|
||||||
|
.scl_io_num = I3C_MASTER_SCL_IO,
|
||||||
|
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
||||||
|
.trans_queue_depth = 1,
|
||||||
|
.intr_priority = 0,
|
||||||
|
.flags = {0}
|
||||||
|
};
|
||||||
|
i3c_master_bus_handle_t bus_handle;
|
||||||
|
gpio_pullup_en(I3C_MASTER_SCL_IO);
|
||||||
|
gpio_pullup_en(I3C_MASTER_SDA_IO);
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_new_master_bus(&i3c_mst_config, &bus_handle));
|
||||||
|
|
||||||
|
i3c_device_i2c_config_t dev_cfg = {
|
||||||
|
.device_address = TEST_STATIC_ADDRESS,
|
||||||
|
.scl_freq_hz = 100 * 1000
|
||||||
|
};
|
||||||
|
i3c_master_i2c_device_handle_t dev;
|
||||||
|
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg, &dev));
|
||||||
|
|
||||||
|
unity_send_signal("i2c master init first");
|
||||||
|
|
||||||
|
unity_wait_for_signal("i2c slave init finish");
|
||||||
|
|
||||||
|
unity_send_signal("master write");
|
||||||
|
for (i = 0; i < DATA_LENGTH; i++) {
|
||||||
|
data_wr[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOG_BUFFER_HEX(TAG, data_wr, i);
|
||||||
|
|
||||||
|
i3c_master_i2c_device_transmit(dev, data_wr, DATA_LENGTH, -1);
|
||||||
|
|
||||||
|
unity_wait_for_signal("ready to delete");
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev));
|
||||||
|
TEST_ESP_OK(i3c_del_master_bus(bus_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_MULTIPLE_DEVICES("I3C-I2C master write slave test in fifo mode", "[i3c][test_env=generic_multi_device][timeout=150]", i3c_i2c_master_write_test, i3c_i2c_slave_read_test);
|
||||||
|
|
||||||
|
static void i3c_i2c_master_read_slave_test(void)
|
||||||
|
{
|
||||||
|
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||||
|
i3c_master_bus_config_t i3c_mst_config = {
|
||||||
|
.sda_io_num = I3C_MASTER_SDA_IO,
|
||||||
|
.scl_io_num = I3C_MASTER_SCL_IO,
|
||||||
|
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
||||||
|
.trans_queue_depth = 1,
|
||||||
|
.intr_priority = 0,
|
||||||
|
.flags = {0}
|
||||||
|
};
|
||||||
|
i3c_master_bus_handle_t bus_handle;
|
||||||
|
gpio_pullup_en(I3C_MASTER_SCL_IO);
|
||||||
|
gpio_pullup_en(I3C_MASTER_SDA_IO);
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_new_master_bus(&i3c_mst_config, &bus_handle));
|
||||||
|
|
||||||
|
i3c_device_i2c_config_t dev_cfg = {
|
||||||
|
.device_address = TEST_STATIC_ADDRESS,
|
||||||
|
.scl_freq_hz = 100 * 1000
|
||||||
|
};
|
||||||
|
i3c_master_i2c_device_handle_t dev;
|
||||||
|
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg, &dev));
|
||||||
|
|
||||||
|
unity_wait_for_signal("i2c slave init finish");
|
||||||
|
|
||||||
|
i3c_master_i2c_device_receive(dev, data_rd, DATA_LENGTH, -1);
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
|
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||||
|
printf("%x\n", data_rd[i]);
|
||||||
|
TEST_ASSERT(data_rd[i] == i);
|
||||||
|
}
|
||||||
|
unity_send_signal("ready to delete master read test");
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev));
|
||||||
|
TEST_ESP_OK(i3c_del_master_bus(bus_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i3c_i2c_slave_write_buffer_test(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t data_wr[DATA_LENGTH];
|
||||||
|
|
||||||
|
i3c_slave_init();
|
||||||
|
|
||||||
|
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||||
|
data_wr[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
i3c_slave_ll_write_data(&I3C_SLV, data_wr, DATA_LENGTH);
|
||||||
|
|
||||||
|
unity_send_signal("i2c slave init finish");
|
||||||
|
|
||||||
|
unity_wait_for_signal("ready to delete master read test");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_MULTIPLE_DEVICES("I3C-I2C master read slave test in fifo mode", "[i3c][test_env=generic_multi_device][timeout=150]", i3c_i2c_master_read_slave_test, i3c_i2c_slave_write_buffer_test);
|
||||||
|
|
||||||
|
static void i3c_i2c_master_write_via_dma_test(void)
|
||||||
|
{
|
||||||
|
__attribute__((aligned(4))) uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i3c_master_bus_config_t i3c_mst_config = {
|
||||||
|
.sda_io_num = I3C_MASTER_SDA_IO,
|
||||||
|
.scl_io_num = I3C_MASTER_SCL_IO,
|
||||||
|
.clock_source = I3C_MASTER_CLK_SRC_DEFAULT,
|
||||||
|
.trans_queue_depth = 1,
|
||||||
|
.intr_priority = 0,
|
||||||
|
.flags = {0}
|
||||||
|
};
|
||||||
|
i3c_master_bus_handle_t bus_handle;
|
||||||
|
gpio_pullup_en(I3C_MASTER_SCL_IO);
|
||||||
|
gpio_pullup_en(I3C_MASTER_SDA_IO);
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_new_master_bus(&i3c_mst_config, &bus_handle));
|
||||||
|
|
||||||
|
i3c_device_i2c_config_t dev_cfg = {
|
||||||
|
.device_address = TEST_STATIC_ADDRESS,
|
||||||
|
.scl_freq_hz = 100 * 1000
|
||||||
|
};
|
||||||
|
i3c_master_i2c_device_handle_t dev;
|
||||||
|
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg, &dev));
|
||||||
|
|
||||||
|
i3c_master_dma_config_t dma_config = {
|
||||||
|
.max_transfer_size = 50,
|
||||||
|
.dma_burst_size = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
i3c_master_bus_decorate_dma(bus_handle, &dma_config);
|
||||||
|
|
||||||
|
unity_send_signal("i2c master init first");
|
||||||
|
|
||||||
|
unity_wait_for_signal("i2c slave init finish");
|
||||||
|
|
||||||
|
unity_send_signal("master write");
|
||||||
|
for (i = 0; i < DATA_LENGTH; i++) {
|
||||||
|
data_wr[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOG_BUFFER_HEX(TAG, data_wr, i);
|
||||||
|
i3c_master_i2c_device_transmit(dev, data_wr, DATA_LENGTH, -1);
|
||||||
|
|
||||||
|
unity_wait_for_signal("ready to delete");
|
||||||
|
|
||||||
|
TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev));
|
||||||
|
TEST_ESP_OK(i3c_master_bus_decorate_dma(bus_handle, NULL));
|
||||||
|
TEST_ESP_OK(i3c_del_master_bus(bus_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_MULTIPLE_DEVICES("I3C-I2C master write slave test in dma mode", "[i3c][test_env=generic_multi_device][timeout=150]", i3c_i2c_master_write_via_dma_test, i3c_i2c_slave_read_test);
|
@@ -18,3 +18,17 @@ from pytest_embedded_idf.utils import soc_filtered_targets
|
|||||||
@idf_parametrize('target', soc_filtered_targets('SOC_I3C_MASTER_SUPPORTED == 1'), indirect=['target'])
|
@idf_parametrize('target', soc_filtered_targets('SOC_I3C_MASTER_SUPPORTED == 1'), indirect=['target'])
|
||||||
def test_i3c(dut: Dut) -> None:
|
def test_i3c(dut: Dut) -> None:
|
||||||
dut.run_all_single_board_cases()
|
dut.run_all_single_board_cases()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.generic_multi_device
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'count, config',
|
||||||
|
[
|
||||||
|
(2, 'release'),
|
||||||
|
(2, 'cache_safe'),
|
||||||
|
],
|
||||||
|
indirect=True,
|
||||||
|
)
|
||||||
|
@idf_parametrize('target', soc_filtered_targets('SOC_I3C_MASTER_SUPPORTED == 1'), indirect=['target'])
|
||||||
|
def test_i3c_multi_device(case_tester) -> None: # type: ignore
|
||||||
|
case_tester.run_all_multi_dev_cases(reset=True)
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "soc/clk_tree_defs.h"
|
#include "soc/clk_tree_defs.h"
|
||||||
#include "soc/hp_sys_clkrst_struct.h"
|
#include "soc/hp_sys_clkrst_struct.h"
|
||||||
#include "soc/lpperi_struct.h"
|
|
||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "soc/i3c_mst_mem_struct.h"
|
#include "soc/i3c_mst_mem_struct.h"
|
||||||
#include "soc/i3c_mst_struct.h"
|
#include "soc/i3c_mst_struct.h"
|
||||||
|
211
components/hal/esp32p4/include/hal/i3c_slave_ll.h
Normal file
211
components/hal/esp32p4/include/hal/i3c_slave_ll.h
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The LL layer for I3C slave register operations
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "hal/misc.h"
|
||||||
|
#include "hal/assert.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
#include "soc/clk_tree_defs.h"
|
||||||
|
#include "soc/hp_sys_clkrst_struct.h"
|
||||||
|
#include "hal/misc.h"
|
||||||
|
#include "soc/i3c_slv_struct.h"
|
||||||
|
#include "soc/i3c_slv_reg.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define I3C_SLAVE_LL_EVENT_INTR (I3C_SLV_RXPEND_ENA_M | I3C_SLV_TXSEND_ENA_M)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable or disable I3C slave bus clock
|
||||||
|
*
|
||||||
|
* @param hw I3C slave hardware pointer (currently unused)
|
||||||
|
* @param enable true: enable clock, false: disable clock
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_enable_bus_clock(i3c_slv_dev_t *hw, bool enable)
|
||||||
|
{
|
||||||
|
(void)hw; // Suppress unused parameter warning
|
||||||
|
HP_SYS_CLKRST.soc_clk_ctrl2.reg_i3c_slv_apb_clk_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||||
|
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||||
|
#define i3c_slave_ll_enable_bus_clock(...) do {(void)__DECLARE_RCC_ATOMIC_ENV; i3c_slave_ll_enable_bus_clock(__VA_ARGS__);} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset I3C slave registers
|
||||||
|
*
|
||||||
|
* Perform register reset by setting reset signal to 1 then 0
|
||||||
|
*
|
||||||
|
* @param hw I3C slave hardware pointer (currently unused)
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_reset_register(i3c_slv_dev_t *hw)
|
||||||
|
{
|
||||||
|
(void)hw; // Suppress unused parameter warning
|
||||||
|
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_i3cslv = 1;
|
||||||
|
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_i3cslv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||||
|
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||||
|
#define i3c_slave_ll_reset_register(...) do {(void)__DECLARE_RCC_ATOMIC_ENV; i3c_slave_ll_reset_register(__VA_ARGS__);} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure I3C slave static address
|
||||||
|
*
|
||||||
|
* @param hw I3C slave hardware pointer
|
||||||
|
* @param address 7-bit static address to set
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_config_static_address(i3c_slv_dev_t *hw, uint8_t address)
|
||||||
|
{
|
||||||
|
hw->config.saddr = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get pointer to I3C slave interrupt status register
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @return volatile void* Pointer to interrupt masked status register
|
||||||
|
*/
|
||||||
|
static inline volatile void *i3c_slave_ll_get_interrupt_status_reg(i3c_slv_dev_t *dev)
|
||||||
|
{
|
||||||
|
return &dev->intmasked;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear I3C slave interrupt flags
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param mask Interrupt bit mask to clear
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_clear_intr_mask(i3c_slv_dev_t *dev, uint32_t mask)
|
||||||
|
{
|
||||||
|
dev->intclr.val = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable I3C slave interrupt mask
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param mask Interrupt bit mask to enable
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_enable_intr_mask(i3c_slv_dev_t *dev, uint32_t mask)
|
||||||
|
{
|
||||||
|
dev->intset.val |= mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable I3C slave interrupt mask
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param mask Interrupt bit mask to disable
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_disable_intr_mask(i3c_slv_dev_t *dev, uint32_t mask)
|
||||||
|
{
|
||||||
|
dev->intset.val &= (~mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get current I3C slave interrupt mask status
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param intr_status Pointer to store interrupt status
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_get_intr_mask(i3c_slv_dev_t *dev, uint32_t *intr_status)
|
||||||
|
{
|
||||||
|
*intr_status = dev->intmasked.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write data to I3C slave device
|
||||||
|
*
|
||||||
|
* Write data to transmit FIFO byte by byte
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param data Pointer to data to write
|
||||||
|
* @param length Length of data to write (bytes)
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_write_data(i3c_slv_dev_t *dev, const uint8_t *data, size_t length)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
dev->wdatab.val = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get data length in I3C slave receive FIFO
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @return size_t Number of bytes available to read in receive FIFO
|
||||||
|
*/
|
||||||
|
static inline size_t i3c_slave_ll_get_read_data_length(i3c_slv_dev_t *dev)
|
||||||
|
{
|
||||||
|
return dev->datactrl.rxcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from I3C slave device
|
||||||
|
*
|
||||||
|
* Read data from receive FIFO byte by byte
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param data Buffer to store read data
|
||||||
|
* @param length Length of data to read (bytes)
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_read_data(i3c_slv_dev_t *dev, uint8_t *data, size_t length)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
data[i] = dev->rdarab.data0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlock or lock I3C slave registers
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param unlock true: unlock registers to allow modification, false: lock registers to prevent modification
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_unlock_register(i3c_slv_dev_t *dev, bool unlock)
|
||||||
|
{
|
||||||
|
dev->datactrl.unlock = unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set I3C slave transmit FIFO trigger level
|
||||||
|
*
|
||||||
|
* When transmit FIFO contains fewer bytes than this level, interrupt or DMA request will be triggered
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param threshold Transmit FIFO trigger level (0-3)
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_set_transmit_fifo_threshold(i3c_slv_dev_t *dev, uint8_t threshold)
|
||||||
|
{
|
||||||
|
dev->datactrl.txtrig = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set I3C slave receive FIFO trigger level
|
||||||
|
*
|
||||||
|
* When receive FIFO reaches this level, interrupt or DMA request will be triggered
|
||||||
|
*
|
||||||
|
* @param dev I3C slave hardware pointer
|
||||||
|
* @param threshold Receive FIFO trigger level (0-3)
|
||||||
|
*/
|
||||||
|
static inline void i3c_slave_ll_set_receive_fifo_threshold(i3c_slv_dev_t *dev, uint8_t threshold)
|
||||||
|
{
|
||||||
|
dev->datactrl.rxtrig = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
Reference in New Issue
Block a user