forked from espressif/esp-idf
test(driver_twai): test app rename and add cache safe test
This commit is contained in:
@@ -72,15 +72,7 @@ components/driver/test_apps/legacy_timer_driver:
|
||||
depends_filepatterns:
|
||||
- components/driver/deprecated/**/*timer*
|
||||
|
||||
components/driver/test_apps/touch_sensor_v1:
|
||||
disable:
|
||||
- if: SOC_TOUCH_SENSOR_VERSION != 1
|
||||
|
||||
components/driver/test_apps/touch_sensor_v2:
|
||||
disable:
|
||||
- if: SOC_TOUCH_SENSOR_VERSION != 2
|
||||
|
||||
components/driver/test_apps/twai:
|
||||
components/driver/test_apps/legacy_twai:
|
||||
disable:
|
||||
- if: SOC_TWAI_SUPPORTED != 1 or SOC_TWAI_SUPPORT_FD == 1
|
||||
reason: legacy driver doesn't support FD
|
||||
@@ -88,3 +80,11 @@ components/driver/test_apps/twai:
|
||||
- components/driver/twai/**/*
|
||||
depends_components:
|
||||
- esp_driver_gpio
|
||||
|
||||
components/driver/test_apps/touch_sensor_v1:
|
||||
disable:
|
||||
- if: SOC_TOUCH_SENSOR_VERSION != 1
|
||||
|
||||
components/driver/test_apps/touch_sensor_v2:
|
||||
disable:
|
||||
- if: SOC_TOUCH_SENSOR_VERSION != 2
|
||||
|
@@ -1,4 +1,4 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
# primitives for checking sleep internal state
|
||||
CONFIG_ESP_SLEEP_DEBUG=y
|
@@ -1,6 +1,5 @@
|
||||
components/esp_driver_twai/test_apps/twaifd_test:
|
||||
components/esp_driver_twai/test_apps/test_twai:
|
||||
disable:
|
||||
- if: SOC_TWAI_SUPPORTED != 1 or SOC_TWAI_SUPPORT_FD != 1
|
||||
reason: Only support FD targets now
|
||||
- if: SOC_TWAI_SUPPORTED != 1
|
||||
depends_components:
|
||||
- esp_driver_twai
|
||||
|
@@ -5,9 +5,23 @@ cmake_minimum_required(VERSION 3.16)
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(twaifd_test)
|
||||
project(test_twai)
|
||||
|
||||
message(STATUS "Checking TWAI registers are not read-write by half-word")
|
||||
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
|
||||
check_register_rw_half_word(SOC_MODULES "twai*" "pcr" "hp_sys_clkrst"
|
||||
HAL_MODULES "twai*")
|
||||
|
||||
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/esp_driver_twai/,${CMAKE_BINARY_DIR}/esp-idf/hal/
|
||||
--elf-file ${CMAKE_BINARY_DIR}/test_twai.elf
|
||||
find-refs
|
||||
--from-sections=.iram0.text
|
||||
--to-sections=.flash.text,.flash.rodata
|
||||
--exit-code
|
||||
DEPENDS ${elf}
|
||||
)
|
||||
endif()
|
2
components/esp_driver_twai/test_apps/test_twai/README.md
Normal file
2
components/esp_driver_twai/test_apps/test_twai/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
@@ -0,0 +1,15 @@
|
||||
set(srcs "test_app_main.c")
|
||||
|
||||
if(CONFIG_SOC_TWAI_SUPPORTED)
|
||||
list(APPEND srcs "test_twai_common.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_TWAI_SUPPORT_FD)
|
||||
list(APPEND srcs "test_twai_fd.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${srcs}
|
||||
PRIV_REQUIRES esp_driver_twai esp_timer
|
||||
WHOLE_ARCHIVE
|
||||
)
|
@@ -19,6 +19,7 @@ void setUp(void)
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
esp_reent_cleanup();
|
||||
unity_utils_evaluate_leaks_direct(LEAKS);
|
||||
}
|
||||
|
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils_cache.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_twai.h"
|
||||
#include "esp_twai_onchip.h"
|
||||
|
||||
#define TEST_TX_GPIO 4
|
||||
#define TEST_RX_GPIO 5
|
||||
#define TEST_TWAI_QUEUE_DEPTH 5
|
||||
#define TEST_TRANS_LEN 100
|
||||
#define TEST_FRAME_LEN 7
|
||||
#define TEST_FRAME_NUM howmany(TEST_TRANS_LEN, TEST_FRAME_LEN)
|
||||
|
||||
static IRAM_ATTR bool test_driver_install_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
twai_frame_t rx_frame;
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) {
|
||||
ESP_EARLY_LOGI("Recv ", "id 0x%lx rtr %d", rx_frame.header.id, rx_frame.header.rtr);
|
||||
}
|
||||
if (rx_frame.header.id != 0x100) {
|
||||
TEST_FAIL(); //callback is unregistered, should not run here
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai install uninstall (loopback)", "[TWAI]")
|
||||
{
|
||||
esp_err_t ret;
|
||||
twai_node_handle_t node_hdl[SOC_TWAI_CONTROLLER_NUM + 1];
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 1000000,
|
||||
.data_timing.bitrate = 1000000,
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
|
||||
// loop 10 times to check memory leak
|
||||
for (uint8_t loop = 0; loop < 10; loop ++) {
|
||||
for (uint8_t i = 0; i < SOC_TWAI_CONTROLLER_NUM + 1; i++) {
|
||||
ret = twai_new_node_onchip(&node_config, &node_hdl[i]);
|
||||
printf("Install TWAI%d return %s\n", i, esp_err_to_name(ret));
|
||||
TEST_ASSERT(ret == ((i < SOC_TWAI_CONTROLLER_NUM) ? ESP_OK : ESP_ERR_NOT_FOUND));
|
||||
}
|
||||
// can't disable before enable
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_disable(node_hdl[0]));
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_driver_install_rx_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL));
|
||||
|
||||
printf("Test unregister callback\n");
|
||||
user_cbs.on_rx_done = NULL;
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL));
|
||||
|
||||
twai_frame_t tx_frame = {
|
||||
.header.id = 0x82,
|
||||
.header.rtr = true,
|
||||
};
|
||||
printf("Test transmit before enable\n");
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_transmit(node_hdl[0], &tx_frame, 0));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl[0]));
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl[0]));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl[0]));
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl[0], &tx_frame, 0));
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl[0]));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl[0]));
|
||||
|
||||
printf("Test install after delete\n");
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl[SOC_TWAI_CONTROLLER_NUM]));
|
||||
user_cbs.on_rx_done = test_driver_install_rx_cb,
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[SOC_TWAI_CONTROLLER_NUM], &user_cbs, NULL));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl[SOC_TWAI_CONTROLLER_NUM]));
|
||||
tx_frame.header.id = 0x100;
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl[SOC_TWAI_CONTROLLER_NUM], &tx_frame, 0));
|
||||
twai_frame_t rx_frame;
|
||||
printf("Test receive from task\n");
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_receive_from_isr(node_hdl[SOC_TWAI_CONTROLLER_NUM], &rx_frame));
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl[SOC_TWAI_CONTROLLER_NUM]));
|
||||
for (uint8_t i = 1; i <= SOC_TWAI_CONTROLLER_NUM; i++) {
|
||||
printf("Uninstall TWAI%d\n", i - 1);
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR bool test_enable_disable_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
twai_frame_t *rx_frame = user_ctx;
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, rx_frame)) {
|
||||
ESP_EARLY_LOGI("Recv", "RX id 0x%x len %d ext %d brs %d esi %d", rx_frame->header.id, twaifd_dlc2len(rx_frame->header.dlc), rx_frame->header.ide, rx_frame->header.brs, rx_frame->header.esi);
|
||||
rx_frame->buffer += rx_frame->buffer_len;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai transmit stop resume (loopback)", "[TWAI]")
|
||||
{
|
||||
// prepare test memory
|
||||
uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
|
||||
uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr);
|
||||
printf("Transmit %d bytes package in %d frames\n", TEST_TRANS_LEN, TEST_FRAME_NUM);
|
||||
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 200000,
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
twai_frame_t rx_frame = {
|
||||
.buffer = recv_pkg_ptr,
|
||||
.buffer_len = TEST_FRAME_LEN,
|
||||
};
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_enable_disable_rx_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
|
||||
//create and enqueue all transfers
|
||||
twai_frame_t *tx_msgs = heap_caps_calloc(TEST_FRAME_NUM, sizeof(twai_frame_t), MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT(tx_msgs);
|
||||
for (uint32_t tx_cnt = 0; tx_cnt < TEST_FRAME_NUM; tx_cnt++) {
|
||||
tx_msgs[tx_cnt].header.id = tx_cnt | 0x400;
|
||||
tx_msgs[tx_cnt].header.ide = !!(tx_cnt % 3);
|
||||
tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * TEST_FRAME_LEN;
|
||||
tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == TEST_FRAME_NUM) ? (TEST_TRANS_LEN - tx_cnt * TEST_FRAME_LEN) : TEST_FRAME_LEN;
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 500));
|
||||
}
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
for (uint8_t i = 3; i > 0; i--) {
|
||||
printf("interrupted, %d sec\n", i);
|
||||
vTaskDelay(1000);
|
||||
}
|
||||
printf("continuing ...\n");
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
|
||||
//waiting pkg receive finish
|
||||
while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_LEN) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
free(tx_msgs);
|
||||
|
||||
// check if pkg receive correct
|
||||
printf("pkg check %s!!\n", memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_LEN) ? "failed" : "ok");
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_LEN);
|
||||
|
||||
free(send_pkg_ptr);
|
||||
free(recv_pkg_ptr);
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
||||
|
||||
static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t trans_num)
|
||||
{
|
||||
uint8_t send_pkg_ptr[TWAI_FRAME_MAX_LEN];
|
||||
twai_frame_t tx_msg = {
|
||||
.buffer = send_pkg_ptr,
|
||||
};
|
||||
printf("Sending %ld random trans ...\n", trans_num);
|
||||
for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) {
|
||||
tx_msg.header.id = tx_cnt | 0xf000;
|
||||
tx_msg.header.ide = !!(tx_cnt % 2);
|
||||
tx_msg.header.rtr = !!(tx_cnt % 3);
|
||||
tx_msg.buffer_len = tx_cnt % TWAI_FRAME_MAX_LEN;
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msg, 0));
|
||||
vTaskDelay(8); //as async transaction, waiting trans done
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR bool test_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
uint8_t *test_ctrl = user_ctx;
|
||||
uint8_t recv_pkg_ptr[TWAI_FRAME_MAX_LEN];
|
||||
twai_frame_t rx_frame = {
|
||||
.buffer = recv_pkg_ptr,
|
||||
.buffer_len = TWAI_FRAME_MAX_LEN,
|
||||
};
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) {
|
||||
ESP_EARLY_LOGI("Recv", "RX id 0x%4x len %2d ext %d rmt %d", rx_frame.header.id, twaifd_dlc2len(rx_frame.header.dlc), rx_frame.header.ide, rx_frame.header.rtr);
|
||||
switch (test_ctrl[0]) {
|
||||
case 0: // receive something
|
||||
TEST_ASSERT(rx_frame.header.id >= 0x10);
|
||||
TEST_ASSERT(!rx_frame.header.ide);
|
||||
break;
|
||||
case 1: // receive all
|
||||
case 2: break; // receive none
|
||||
default: TEST_ASSERT(false);
|
||||
}
|
||||
test_ctrl[1] ++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai mask filter (loopback)", "[TWAI]")
|
||||
{
|
||||
uint8_t test_ctrl[2];
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 1000000,
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_filter_rx_done_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl));
|
||||
|
||||
twai_mask_filter_config_t mfilter_cfg = {0};
|
||||
for (uint8_t i = 0; i < SOC_TWAI_MASK_FILTER_NUM; i++) {
|
||||
printf("\n--------------------------------------\n");
|
||||
test_ctrl[0] = 0;
|
||||
test_ctrl[1] = 0;
|
||||
mfilter_cfg.id = 0x10,
|
||||
mfilter_cfg.mask = 0xf0,
|
||||
mfilter_cfg.is_ext = false,
|
||||
printf("Testing mask filter %d: id 0x%lx mask 0x%lx is_ext %d\n", i, mfilter_cfg.id, mfilter_cfg.mask, mfilter_cfg.is_ext);
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, i, &mfilter_cfg));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 30);
|
||||
TEST_ASSERT_EQUAL(7, test_ctrl[1]); // must receive 7 of 30 frames under filter config
|
||||
|
||||
test_ctrl[0] = 1;
|
||||
test_ctrl[1] = 0;
|
||||
mfilter_cfg.id = 0;
|
||||
mfilter_cfg.mask = 0;
|
||||
printf("Change filter %d to receive ALL: id 0x%lx mask 0x%lx\n", i, mfilter_cfg.id, mfilter_cfg.mask);
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, i, &mfilter_cfg));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 20);
|
||||
TEST_ASSERT_EQUAL(20, test_ctrl[1]);
|
||||
|
||||
test_ctrl[0] = 2;
|
||||
test_ctrl[1] = 0;
|
||||
mfilter_cfg.id = 0xFFFFFFFF;
|
||||
mfilter_cfg.mask = 0xFFFFFFFF;
|
||||
printf("Disable filter %d: id 0x%lx mask 0x%lx\n", i, mfilter_cfg.id, mfilter_cfg.mask);
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, i, &mfilter_cfg));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 40);
|
||||
TEST_ASSERT_EQUAL(0, test_ctrl[1]);
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
}
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
||||
|
||||
//------------------ Dual Filter Test -------------------//
|
||||
#if !SOC_TWAI_SUPPORT_FD
|
||||
static IRAM_ATTR bool test_dual_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
uint8_t *test_ctrl = user_ctx;
|
||||
uint8_t recv_pkg_ptr[TWAI_FRAME_MAX_LEN];
|
||||
twai_frame_t rx_frame = {
|
||||
.buffer = recv_pkg_ptr,
|
||||
.buffer_len = TWAI_FRAME_MAX_LEN,
|
||||
};
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) {
|
||||
ESP_EARLY_LOGI("Recv", "RX id 0x%4x len %2d ext %d rmt %d", rx_frame.header.id, twaifd_dlc2len(rx_frame.header.dlc), rx_frame.header.ide, rx_frame.header.rtr);
|
||||
switch (test_ctrl[0]) {
|
||||
case 0: // receive something
|
||||
TEST_ASSERT(!rx_frame.header.ide);
|
||||
TEST_ASSERT((rx_frame.header.id >= 0x10) && (rx_frame.header.id <= 0x2f));
|
||||
break;
|
||||
case 1: break; // receive none
|
||||
default: TEST_ASSERT(false);
|
||||
}
|
||||
test_ctrl[1] ++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai dual 16bit mask filter (loopback)", "[TWAI]")
|
||||
{
|
||||
uint8_t test_ctrl[2];
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 1000000,
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_dual_filter_rx_done_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl));
|
||||
|
||||
printf("Testing dual filter: id1 0x%x mask1 0x%x, id2 0x%x mask2 0x%x\n", 0x020, 0x7f0, 0x013, 0x7f8);
|
||||
test_ctrl[0] = 0;
|
||||
test_ctrl[1] = 0;
|
||||
// filter 1 receive only std id 0x02x
|
||||
// filter 2 receive only std id 0x010~0x017
|
||||
twai_mask_filter_config_t dual_config = twai_make_dual_filter(0x020, 0x7f0, 0x013, 0x7f8, false);
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &dual_config));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 50);
|
||||
TEST_ASSERT_EQUAL(12, test_ctrl[1]); // must receive 12 of 50 frames under filter config
|
||||
|
||||
printf("Disable filter\n");
|
||||
test_ctrl[0] = 1;
|
||||
test_ctrl[1] = 0;
|
||||
dual_config.id = 0xFFFFFFFF;
|
||||
dual_config.mask = 0xFFFFFFFF;
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &dual_config));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 40);
|
||||
TEST_ASSERT_EQUAL(0, test_ctrl[1]);
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_TWAI_ISR_CACHE_SAFE
|
||||
static IRAM_ATTR bool test_iram_safe_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
twai_frame_t *rx_frame = user_ctx;
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, rx_frame)) {
|
||||
esp_rom_printf(DRAM_STR("RX id 0x%x len %d ext %d brs %d esi %d\n"), rx_frame->header.id, twaifd_dlc2len(rx_frame->header.dlc), rx_frame->header.ide, rx_frame->header.brs, rx_frame->header.esi);
|
||||
rx_frame->buffer += rx_frame->buffer_len;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR test_wait_trans_done_cache_disable(void *args)
|
||||
{
|
||||
twai_frame_t *rx_frame = ((twai_frame_t **)args)[0];
|
||||
uint8_t *orig_buff = ((uint8_t **)args)[1];
|
||||
|
||||
esp_rom_printf(DRAM_STR("Cache disabled now !!!\n"));
|
||||
//waiting pkg receive finish
|
||||
while (rx_frame->buffer < orig_buff + TEST_TRANS_LEN) {
|
||||
esp_rom_delay_us(1000);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("twai driver cache safe (loopback)", "[TWAI]")
|
||||
{
|
||||
// prepare test memory
|
||||
uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
|
||||
uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr);
|
||||
printf("Transmit %d bytes package in %d frames\n", TEST_TRANS_LEN, TEST_FRAME_NUM);
|
||||
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 50000, //slow bitrate to ensure cache disabled before tx_queue finish
|
||||
.tx_queue_depth = TEST_FRAME_NUM,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
twai_frame_t rx_frame = {
|
||||
.buffer = recv_pkg_ptr,
|
||||
.buffer_len = TEST_FRAME_LEN,
|
||||
};
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_iram_safe_rx_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
|
||||
//create and enqueue all transfers
|
||||
twai_frame_t *tx_msgs = heap_caps_calloc(TEST_FRAME_NUM, sizeof(twai_frame_t), MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT(tx_msgs);
|
||||
for (uint32_t tx_cnt = 0; tx_cnt < TEST_FRAME_NUM; tx_cnt++) {
|
||||
tx_msgs[tx_cnt].header.id = tx_cnt | 0x400;
|
||||
tx_msgs[tx_cnt].header.ide = !!(tx_cnt % 3);
|
||||
tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * TEST_FRAME_LEN;
|
||||
tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == TEST_FRAME_NUM) ? (TEST_TRANS_LEN - tx_cnt * TEST_FRAME_LEN) : TEST_FRAME_LEN;
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 0));
|
||||
}
|
||||
|
||||
//disable cache immediately before tx_queue finish
|
||||
void *user_data[2] = {&rx_frame, recv_pkg_ptr};
|
||||
unity_utils_run_cache_disable_stub(test_wait_trans_done_cache_disable, user_data);
|
||||
|
||||
//if it is able to waiting finish, means pass the test
|
||||
free(tx_msgs);
|
||||
|
||||
// check if pkg receive correct
|
||||
printf("Transaction finish, pkg check %s!!\n", memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_LEN) ? "failed" : "ok");
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_LEN);
|
||||
|
||||
free(send_pkg_ptr);
|
||||
free(recv_pkg_ptr);
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
||||
#endif //CONFIG_TWAI_ISR_CACHE_SAFE
|
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_twai.h"
|
||||
#include "esp_twai_onchip.h"
|
||||
|
||||
#define TEST_TX_GPIO 4
|
||||
#define TEST_RX_GPIO 5
|
||||
#define TEST_TWAI_QUEUE_DEPTH 5
|
||||
|
||||
static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t trans_num)
|
||||
{
|
||||
uint8_t send_pkg_ptr[TWAIFD_FRAME_MAX_LEN];
|
||||
twai_frame_t tx_msg = {
|
||||
.buffer = send_pkg_ptr,
|
||||
};
|
||||
printf("Sending %ld random trans ...\n", trans_num);
|
||||
for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) {
|
||||
tx_msg.header.id = tx_cnt | 0xf000;
|
||||
tx_msg.header.ide = !!(tx_cnt % 2);
|
||||
tx_msg.header.rtr = !!(tx_cnt % 3);
|
||||
tx_msg.header.fdf = !!(tx_cnt % 5);
|
||||
tx_msg.buffer_len = tx_msg.header.fdf ? (tx_cnt % TWAIFD_FRAME_MAX_LEN) : (tx_cnt % TWAI_FRAME_MAX_LEN);
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msg, 0));
|
||||
vTaskDelay(8); //as async transaction, waiting trans done
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR bool test_range_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
uint8_t *test_ctrl = user_ctx;
|
||||
uint8_t recv_pkg_ptr[TWAIFD_FRAME_MAX_LEN];
|
||||
twai_frame_t rx_frame = {
|
||||
.buffer = recv_pkg_ptr,
|
||||
.buffer_len = TWAIFD_FRAME_MAX_LEN,
|
||||
};
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) {
|
||||
ESP_EARLY_LOGI("Recv", "RX id 0x%4x len %2d ext %d rmt %d fd %d", rx_frame.header.id, twaifd_dlc2len(rx_frame.header.dlc), rx_frame.header.ide, rx_frame.header.rtr, rx_frame.header.fdf);
|
||||
switch (test_ctrl[0]) {
|
||||
case 0: // enable range filter
|
||||
TEST_ASSERT(!rx_frame.header.ide);
|
||||
TEST_ASSERT((rx_frame.header.id >= 0x0a) && (rx_frame.header.id <= 0x15));
|
||||
break;
|
||||
case 1: break; // disable range filter
|
||||
default: TEST_ASSERT(false);
|
||||
}
|
||||
test_ctrl[1] ++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai range filter (loopback)", "[TWAI]")
|
||||
{
|
||||
uint8_t test_ctrl[2];
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 1000000,
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_range_filter_rx_done_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl));
|
||||
|
||||
// disable mask filter 0 which enabled by default
|
||||
twai_mask_filter_config_t mfilter_cfg = {
|
||||
.id = 0xFFFFFFFF,
|
||||
.mask = 0xFFFFFFFF,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg));
|
||||
|
||||
test_ctrl[0] = 0;
|
||||
test_ctrl[1] = 0;
|
||||
twai_range_filter_config_t rfilter_cfg = {
|
||||
.range_low = 0x0a,
|
||||
.range_high = 0x15,
|
||||
.is_ext = false,
|
||||
};
|
||||
printf("Config range filter 0: 0x%lx - 0x%lx\n", rfilter_cfg.range_low, rfilter_cfg.range_high);
|
||||
TEST_ESP_OK(twai_node_config_range_filter(node_hdl, 0, &rfilter_cfg));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 30);
|
||||
TEST_ASSERT_EQUAL(6, test_ctrl[1]); // must receive 6 of 30 frames under filter config
|
||||
|
||||
test_ctrl[0] = 1;
|
||||
test_ctrl[1] = 0;
|
||||
rfilter_cfg.range_low = 1;
|
||||
rfilter_cfg.range_high = 0; // config invalid range to disable range filter
|
||||
printf("Disable range filter 0: 0x%lx - 0x%lx\n", rfilter_cfg.range_low, rfilter_cfg.range_high);
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_config_range_filter(node_hdl, 0, &rfilter_cfg));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 30);
|
||||
TEST_ASSERT_EQUAL(0, test_ctrl[1]);
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
||||
|
||||
#define TEST_TRANS_TIME_BUF_LEN 20000
|
||||
static IRAM_ATTR bool test_fd_trans_time_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
twai_frame_t *rx_frame = user_ctx;
|
||||
uint32_t data_len;
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, rx_frame)) {
|
||||
data_len = MIN(twaifd_dlc2len(rx_frame->header.dlc), rx_frame->buffer_len);
|
||||
ESP_EARLY_LOGD("Recv", "RX id 0x%x len %d brs %d", rx_frame->header.id, data_len, rx_frame->header.brs);
|
||||
rx_frame->buffer += data_len;
|
||||
// calc the `rx_frame->buffer_len` for last frame receive
|
||||
if ((rx_frame->header.id - 0x400 + 1) * rx_frame->buffer_len > (TEST_TRANS_TIME_BUF_LEN - rx_frame->buffer_len)) {
|
||||
rx_frame->buffer_len = TEST_TRANS_TIME_BUF_LEN % rx_frame->buffer_len;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai fd transmit time (loopback)", "[TWAI]")
|
||||
{
|
||||
// prepare test memory
|
||||
uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_TIME_BUF_LEN, MALLOC_CAP_8BIT);
|
||||
uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_TIME_BUF_LEN, MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr);
|
||||
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 1000000,
|
||||
.data_timing.bitrate = 4000000,
|
||||
.data_timing.ssp_permill = 700, // ssp 70.0%
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
twai_frame_t rx_frame = {.buffer_len = 64};
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_fd_trans_time_rx_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
printf("%-12s %-14s %-14s %-7s %-15s %s\n", "pkg_len", "frame_len", "frame_num", "brs", "trans_time/ms", "result");
|
||||
printf("-------------------------------------------------------------------------\n");
|
||||
|
||||
uint64_t time1, time2;
|
||||
for (uint8_t test_mode = 0; test_mode < 3; test_mode ++) {
|
||||
//create and enqueue all transfers
|
||||
uint8_t frame_len = test_mode >= 1 ? 64 : 8;
|
||||
uint16_t trans_num = howmany(TEST_TRANS_TIME_BUF_LEN, frame_len);
|
||||
rx_frame.buffer = recv_pkg_ptr;
|
||||
rx_frame.buffer_len = frame_len;
|
||||
memset(recv_pkg_ptr, 0xff, TEST_TRANS_TIME_BUF_LEN);
|
||||
twai_frame_t *tx_msgs = heap_caps_calloc(trans_num, sizeof(twai_frame_t), MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT(tx_msgs);
|
||||
time1 = esp_timer_get_time();
|
||||
for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) {
|
||||
tx_msgs[tx_cnt].header.id = tx_cnt | 0x400;
|
||||
tx_msgs[tx_cnt].header.fdf = frame_len == 64;
|
||||
tx_msgs[tx_cnt].header.brs = test_mode == 2;
|
||||
tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * frame_len;
|
||||
tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == trans_num) ? (TEST_TRANS_TIME_BUF_LEN - tx_cnt * frame_len) : frame_len;
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 1000));
|
||||
}
|
||||
|
||||
//waiting pkg receive finish
|
||||
while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_TIME_BUF_LEN) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
time2 = esp_timer_get_time();
|
||||
free(tx_msgs);
|
||||
|
||||
// check if pkg receive correct
|
||||
printf("%-12d %-14d %-14d %-7d %-15.2f %-s\n",
|
||||
TEST_TRANS_TIME_BUF_LEN,
|
||||
frame_len,
|
||||
trans_num,
|
||||
(test_mode == 2),
|
||||
(time2 - time1) / 1000.f,
|
||||
memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_TIME_BUF_LEN) ? "failed" : "ok");
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_TIME_BUF_LEN);
|
||||
}
|
||||
printf("-------------------------------------------------------------------------\n");
|
||||
|
||||
free(send_pkg_ptr);
|
||||
free(recv_pkg_ptr);
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
@@ -8,7 +8,7 @@ from pytest_embedded_idf.utils import soc_filtered_targets
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize('config', ['release'], indirect=True)
|
||||
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORT_FD == 1'), indirect=['target'])
|
||||
@pytest.mark.parametrize('config', ['release', 'cache_safe'], indirect=True)
|
||||
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
||||
def test_driver_twai_loopbk(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases(reset=True)
|
@@ -0,0 +1,6 @@
|
||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||
CONFIG_TWAI_ISR_CACHE_SAFE=y
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
|
@@ -1,2 +0,0 @@
|
||||
| Supported Targets | ESP32-C5 |
|
||||
| ----------------- | -------- |
|
@@ -1,11 +0,0 @@
|
||||
set(srcs "test_app_main.c")
|
||||
|
||||
if(CONFIG_SOC_TWAI_SUPPORT_FD)
|
||||
list(APPEND srcs "test_twaifd.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${srcs}
|
||||
PRIV_REQUIRES esp_driver_twai
|
||||
WHOLE_ARCHIVE
|
||||
)
|
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_twai.h"
|
||||
#include "esp_twai_onchip.h"
|
||||
|
||||
#define TEST_TX_GPIO 4
|
||||
#define TEST_RX_GPIO 5
|
||||
#define TEST_TWAI_QUEUE_DEPTH 5
|
||||
#define TEST_TRANS_LEN 100
|
||||
#define TEST_FRAME_LEN 7
|
||||
#define TEST_FRAME_NUM howmany(TEST_TRANS_LEN, TEST_FRAME_LEN)
|
||||
|
||||
static bool test_driver_install_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
twai_frame_header_t rx_header;
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_header, NULL, 0, NULL)) {
|
||||
ESP_EARLY_LOGI("Recv ", "id 0x%lx rtr %d", rx_header.id, rx_header.rtr);
|
||||
}
|
||||
if (rx_header.id != 0x100) {
|
||||
TEST_FAIL(); //callback is unregistered, should not run here
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai install uninstall (loopback)", "[TWAI]")
|
||||
{
|
||||
esp_err_t ret;
|
||||
twai_node_handle_t node_hdl[SOC_TWAI_CONTROLLER_NUM + 1];
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 1000000,
|
||||
.data_timing.bitrate = 1000000,
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
|
||||
// loop 10 times to check memory leak
|
||||
for (uint8_t loop = 0; loop < 10; loop ++) {
|
||||
for (uint8_t i = 0; i < SOC_TWAI_CONTROLLER_NUM + 1; i++) {
|
||||
ret = twai_new_node_onchip(&node_config, &node_hdl[i]);
|
||||
printf("Install TWAI%d return %s\n", i, esp_err_to_name(ret));
|
||||
TEST_ASSERT(ret == ((i < SOC_TWAI_CONTROLLER_NUM) ? ESP_OK : ESP_ERR_NOT_FOUND));
|
||||
}
|
||||
// can't disable before enable
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_disable(node_hdl[0]));
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_driver_install_rx_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL));
|
||||
|
||||
printf("Test unregister callback\n");
|
||||
user_cbs.on_rx_done = NULL;
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL));
|
||||
|
||||
twai_frame_t tx_frame = {
|
||||
.header.id = 0x82,
|
||||
.header.rtr = true,
|
||||
};
|
||||
printf("Test transmit before enable\n");
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_transmit(node_hdl[0], &tx_frame, 0));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl[0]));
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl[0]));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl[0]));
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl[0], &tx_frame, 0));
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl[0]));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl[0]));
|
||||
|
||||
printf("Test install after delete\n");
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl[SOC_TWAI_CONTROLLER_NUM]));
|
||||
user_cbs.on_rx_done = test_driver_install_rx_cb,
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[SOC_TWAI_CONTROLLER_NUM], &user_cbs, NULL));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl[SOC_TWAI_CONTROLLER_NUM]));
|
||||
tx_frame.header.id = 0x100;
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl[SOC_TWAI_CONTROLLER_NUM], &tx_frame, 0));
|
||||
twai_frame_t rx_frame;
|
||||
printf("Test receive from task\n");
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_receive_from_isr(node_hdl[SOC_TWAI_CONTROLLER_NUM], &rx_frame.header, rx_frame.buffer, rx_frame.buffer_len, NULL));
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl[SOC_TWAI_CONTROLLER_NUM]));
|
||||
for (uint8_t i = 1; i <= SOC_TWAI_CONTROLLER_NUM; i++) {
|
||||
printf("Uninstall TWAI%d\n", i - 1);
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool test_enable_disable_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
twai_frame_t *rx_frame = user_ctx;
|
||||
size_t ret_len;
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame->header, rx_frame->buffer, rx_frame->buffer_len, &ret_len)) {
|
||||
ESP_EARLY_LOGI("twai", "RX id 0x%x len %d ext %d fd %d brs %d esi %d", rx_frame->header.id, ret_len, rx_frame->header.ide, rx_frame->header.fdf, rx_frame->header.brs, rx_frame->header.esi);
|
||||
rx_frame->buffer += rx_frame->buffer_len;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai transmit stop resume (loopback)", "[TWAI]")
|
||||
{
|
||||
// prepare test memory
|
||||
uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
|
||||
uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr);
|
||||
printf("Transmit %d bytes package in %d frames\n", TEST_TRANS_LEN, TEST_FRAME_NUM);
|
||||
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 20000,
|
||||
.data_timing.bitrate = 4000000,
|
||||
.data_timing.ssp_permill = 700, // ssp 70.0%
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
// reconfig fd timing to 80M/(4+3+2+1)=8MHz, ssp=8/(4+3+2+1)=80%
|
||||
twai_timing_advanced_config_t timing_fd = {
|
||||
.brp = 1,
|
||||
.prop_seg = 4,
|
||||
.tseg_1 = 3,
|
||||
.tseg_2 = 2,
|
||||
.sjw = 2,
|
||||
.ssp_offset = 8,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_reconfig_timing(node_hdl, NULL, &timing_fd));
|
||||
|
||||
twai_frame_t rx_frame = {
|
||||
.buffer = recv_pkg_ptr,
|
||||
.buffer_len = TEST_FRAME_LEN,
|
||||
};
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_enable_disable_rx_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
|
||||
//create and enqueue all transfers
|
||||
twai_frame_t *tx_msgs = heap_caps_calloc(TEST_FRAME_NUM, sizeof(twai_frame_t), MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT(tx_msgs);
|
||||
for (uint32_t tx_cnt = 0; tx_cnt < TEST_FRAME_NUM; tx_cnt++) {
|
||||
tx_msgs[tx_cnt].header.id = tx_cnt | 0x400;
|
||||
tx_msgs[tx_cnt].header.ide = !!(tx_cnt % 3);
|
||||
tx_msgs[tx_cnt].header.fdf = !!(tx_cnt % 4);
|
||||
tx_msgs[tx_cnt].header.brs = !!(tx_cnt % 2);
|
||||
tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * TEST_FRAME_LEN;
|
||||
tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == TEST_FRAME_NUM) ? (TEST_TRANS_LEN - tx_cnt * TEST_FRAME_LEN) : TEST_FRAME_LEN;
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 500));
|
||||
}
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
for (uint8_t i = 3; i > 0; i--) {
|
||||
printf("interrupted, %d sec\n", i);
|
||||
vTaskDelay(1000);
|
||||
}
|
||||
printf("continuing ...\n");
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
|
||||
//waiting pkg receive finish
|
||||
while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_LEN) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
free(tx_msgs);
|
||||
|
||||
// check if pkg receive correct
|
||||
printf("pkg check %s!!\n", memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_LEN) ? "failed" : "ok");
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_LEN);
|
||||
|
||||
free(send_pkg_ptr);
|
||||
free(recv_pkg_ptr);
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
||||
|
||||
static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t trans_num)
|
||||
{
|
||||
uint8_t send_pkg_ptr[TWAIFD_FRAME_MAX_LEN];
|
||||
twai_frame_t tx_msg = {
|
||||
.buffer = send_pkg_ptr,
|
||||
};
|
||||
printf("Sending %ld random trans ...\n", trans_num);
|
||||
for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) {
|
||||
tx_msg.header.id = tx_cnt | 0xf000;
|
||||
tx_msg.header.ide = !!(tx_cnt % 2);
|
||||
tx_msg.header.rtr = !!(tx_cnt % 3);
|
||||
tx_msg.header.fdf = !!(tx_cnt % 5);
|
||||
tx_msg.buffer_len = tx_msg.header.fdf ? (tx_cnt % TWAIFD_FRAME_MAX_LEN) : (tx_cnt % TWAI_FRAME_MAX_LEN);
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msg, 0));
|
||||
vTaskDelay(8); //as async transaction, waiting trans done
|
||||
}
|
||||
}
|
||||
|
||||
static bool test_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
uint8_t *test_ctrl = user_ctx;
|
||||
size_t ret_len;
|
||||
uint8_t recv_pkg_ptr[TWAIFD_FRAME_MAX_LEN];
|
||||
twai_frame_t rx_frame = {
|
||||
.buffer = recv_pkg_ptr,
|
||||
.buffer_len = TWAIFD_FRAME_MAX_LEN,
|
||||
};
|
||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame.header, rx_frame.buffer, rx_frame.buffer_len, &ret_len)) {
|
||||
ESP_EARLY_LOGI("twai", "RX id 0x%4x len %2d ext %d rmt %d fd %d", rx_frame.header.id, ret_len, rx_frame.header.ide, rx_frame.header.rtr, rx_frame.header.fdf);
|
||||
switch (test_ctrl[0]) {
|
||||
case 0: //filter 0
|
||||
TEST_ASSERT(rx_frame.header.id >= 0x10);
|
||||
TEST_ASSERT(!rx_frame.header.ide);
|
||||
break;
|
||||
case 1:
|
||||
case 2: break;
|
||||
case 3: //filter 1
|
||||
TEST_ASSERT((rx_frame.header.id & 0xfff0) == 0xf000);
|
||||
TEST_ASSERT(rx_frame.header.ide && !rx_frame.header.fdf);
|
||||
break;
|
||||
case 4: //range filter 0
|
||||
TEST_ASSERT(!rx_frame.header.ide && rx_frame.header.fdf);
|
||||
break;
|
||||
default: TEST_ASSERT(false);
|
||||
}
|
||||
test_ctrl[1] ++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("twai filter (loopback)", "[TWAI]")
|
||||
{
|
||||
uint8_t test_ctrl[2];
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {
|
||||
.io_cfg.tx = TEST_TX_GPIO,
|
||||
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
|
||||
.bit_timing.bitrate = 1000000,
|
||||
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
|
||||
.flags.enable_loopback = true,
|
||||
.flags.enable_self_test = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
twai_event_callbacks_t user_cbs = {
|
||||
.on_rx_done = test_filter_rx_done_cb,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl));
|
||||
|
||||
//------------------ Filter 0 -------------------//
|
||||
test_ctrl[0] = 0;
|
||||
test_ctrl[1] = 0;
|
||||
printf("Testing mask filter 0\n");
|
||||
twai_mask_filter_config_t mfilter_cfg0 = {
|
||||
.id = 0x10,
|
||||
.mask = 0xf0,
|
||||
.is_ext = false,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 30);
|
||||
TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]); //after filter, rx frame should less than tx num
|
||||
|
||||
printf("Change to receive ALL\n");
|
||||
test_ctrl[0] = 1;
|
||||
test_ctrl[1] = 0;
|
||||
// set to receive ALL
|
||||
mfilter_cfg0.id = 0;
|
||||
mfilter_cfg0.mask = 0;
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 30);
|
||||
TEST_ASSERT_EQUAL(30, test_ctrl[1]);
|
||||
|
||||
printf("Change to receive NONE\n");
|
||||
test_ctrl[0] = 2;
|
||||
test_ctrl[1] = 0;
|
||||
// set to receive NONE
|
||||
mfilter_cfg0.id = 0xFFFFFFFF;
|
||||
mfilter_cfg0.mask = 0xFFFFFFFF;
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 30);
|
||||
TEST_ASSERT_EQUAL(0, test_ctrl[1]);
|
||||
|
||||
//------------------ Filter 1 -------------------//
|
||||
test_ctrl[0] = 3;
|
||||
test_ctrl[1] = 0;
|
||||
printf("Testing mask filter 1\n");
|
||||
twai_mask_filter_config_t mfilter_cfg1 = {
|
||||
.id = 0xf000,
|
||||
.mask = 0xfff0,
|
||||
.is_ext = true,
|
||||
.no_fd = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 1, &mfilter_cfg1));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 30);
|
||||
TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]);
|
||||
// set to receive NONE
|
||||
mfilter_cfg1.id = 0xFFFFFFFF;
|
||||
mfilter_cfg1.mask = 0xFFFFFFFF;
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 1, &mfilter_cfg1));
|
||||
|
||||
//------------------ Range Filter 0 -------------------//
|
||||
test_ctrl[0] = 4;
|
||||
test_ctrl[1] = 0;
|
||||
printf("Testing range filter 0\n");
|
||||
twai_range_filter_config_t rfilter_cfg0 = {
|
||||
.range_low = 0,
|
||||
.range_high = 0xFFFFFFFF,
|
||||
.is_ext = false,
|
||||
.no_classic = true,
|
||||
};
|
||||
TEST_ESP_OK(twai_node_config_range_filter(node_hdl, 0, &rfilter_cfg0));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
test_random_trans_generator(node_hdl, 30);
|
||||
TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]);
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
Reference in New Issue
Block a user