From 6288067296a50130a96bf2497ab2276044c78f61 Mon Sep 17 00:00:00 2001 From: wanckl Date: Wed, 16 Jul 2025 16:34:12 +0800 Subject: [PATCH] feat(driver_twai): add tx wait all done api --- components/esp_driver_twai/esp_twai.c | 30 ++++++---- components/esp_driver_twai/esp_twai_onchip.c | 34 +++++++++++- .../include/esp_private/twai_interface.h | 12 ++++ components/esp_driver_twai/include/esp_twai.h | 9 +++ .../test_twai/main/test_twai_common.cpp | 55 +++++++++++++++++-- .../test_apps/test_twai/main/test_twai_fd.cpp | 6 +- .../test_twai/main/test_twai_network.cpp | 1 + .../test_twai/sdkconfig.ci.cache_safe | 1 + docs/en/api-reference/peripherals/twai.rst | 1 + docs/zh_CN/api-reference/peripherals/twai.rst | 1 + 10 files changed, 130 insertions(+), 20 deletions(-) diff --git a/components/esp_driver_twai/esp_twai.c b/components/esp_driver_twai/esp_twai.c index 0cbc86e7ad..732e3e5b4b 100644 --- a/components/esp_driver_twai/esp_twai.c +++ b/components/esp_driver_twai/esp_twai.c @@ -65,7 +65,7 @@ uint32_t twai_node_timing_calc_param(const uint32_t source_freq, const twai_timi esp_err_t twai_node_enable(twai_node_handle_t node) { ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle"); - ESP_RETURN_ON_FALSE(node->enable, ESP_ERR_NOT_SUPPORTED, TAG, "enable func null"); + ESP_RETURN_ON_FALSE(node->enable, ESP_ERR_NOT_SUPPORTED, TAG, "enable is not supported"); return node->enable(node); } @@ -73,7 +73,7 @@ esp_err_t twai_node_enable(twai_node_handle_t node) esp_err_t twai_node_disable(twai_node_handle_t node) { ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle"); - ESP_RETURN_ON_FALSE(node->disable, ESP_ERR_NOT_SUPPORTED, TAG, "disable func null"); + ESP_RETURN_ON_FALSE(node->disable, ESP_ERR_NOT_SUPPORTED, TAG, "disable is not supported"); return node->disable(node); } @@ -81,7 +81,7 @@ esp_err_t twai_node_disable(twai_node_handle_t node) esp_err_t twai_node_delete(twai_node_handle_t node) { ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle"); - ESP_RETURN_ON_FALSE(node->del, ESP_ERR_NOT_SUPPORTED, TAG, "delete func null"); + ESP_RETURN_ON_FALSE(node->del, ESP_ERR_NOT_SUPPORTED, TAG, "delete is not supported"); return node->del(node); } @@ -89,7 +89,7 @@ esp_err_t twai_node_delete(twai_node_handle_t node) esp_err_t twai_node_config_mask_filter(twai_node_handle_t node, uint8_t filter_id, const twai_mask_filter_config_t *mask_cfg) { ESP_RETURN_ON_FALSE(node && mask_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null"); - ESP_RETURN_ON_FALSE(node->config_mask_filter, ESP_ERR_NOT_SUPPORTED, TAG, "config_mask_filter func null"); + ESP_RETURN_ON_FALSE(node->config_mask_filter, ESP_ERR_NOT_SUPPORTED, TAG, "config_mask_filter is not supported"); return node->config_mask_filter(node, filter_id, mask_cfg); } @@ -97,7 +97,7 @@ esp_err_t twai_node_config_mask_filter(twai_node_handle_t node, uint8_t filter_i esp_err_t twai_node_config_range_filter(twai_node_handle_t node, uint8_t filter_id, const twai_range_filter_config_t *range_cfg) { ESP_RETURN_ON_FALSE(node && range_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null"); - ESP_RETURN_ON_FALSE(node->config_range_filter, ESP_ERR_NOT_SUPPORTED, TAG, "config_range_filter func null"); + ESP_RETURN_ON_FALSE(node->config_range_filter, ESP_ERR_NOT_SUPPORTED, TAG, "config_range_filter is not supported"); return node->config_range_filter(node, filter_id, range_cfg); } @@ -105,7 +105,7 @@ esp_err_t twai_node_config_range_filter(twai_node_handle_t node, uint8_t filter_ esp_err_t twai_node_reconfig_timing(twai_node_handle_t node, const twai_timing_advanced_config_t *bit_timing, const twai_timing_advanced_config_t *data_timing) { ESP_RETURN_ON_FALSE(node && (bit_timing || data_timing), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null"); - ESP_RETURN_ON_FALSE(node->reconfig_timing, ESP_ERR_NOT_SUPPORTED, TAG, "reconfig_timing func null"); + ESP_RETURN_ON_FALSE(node->reconfig_timing, ESP_ERR_NOT_SUPPORTED, TAG, "reconfig_timing is not supported"); return node->reconfig_timing(node, bit_timing, data_timing); } @@ -113,7 +113,7 @@ esp_err_t twai_node_reconfig_timing(twai_node_handle_t node, const twai_timing_a esp_err_t twai_node_register_event_callbacks(twai_node_handle_t node, const twai_event_callbacks_t *cbs, void *user_data) { ESP_RETURN_ON_FALSE(node && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null"); - ESP_RETURN_ON_FALSE(node->register_cbs, ESP_ERR_NOT_SUPPORTED, TAG, "register_cbs func null"); + ESP_RETURN_ON_FALSE(node->register_cbs, ESP_ERR_NOT_SUPPORTED, TAG, "register_cbs is not supported"); return node->register_cbs(node, cbs, user_data); } @@ -121,7 +121,7 @@ esp_err_t twai_node_register_event_callbacks(twai_node_handle_t node, const twai esp_err_t twai_node_recover(twai_node_handle_t node) { ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle"); - ESP_RETURN_ON_FALSE(node->recover, ESP_ERR_NOT_SUPPORTED, TAG, "recover func null"); + ESP_RETURN_ON_FALSE(node->recover, ESP_ERR_NOT_SUPPORTED, TAG, "recover is not supported"); return node->recover(node); } @@ -129,7 +129,7 @@ esp_err_t twai_node_recover(twai_node_handle_t node) esp_err_t twai_node_get_info(twai_node_handle_t node, twai_node_status_t *status_ret, twai_node_record_t *statistics_ret) { ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle"); - ESP_RETURN_ON_FALSE(node->get_info, ESP_ERR_NOT_SUPPORTED, TAG, "get_info func null"); + ESP_RETURN_ON_FALSE(node->get_info, ESP_ERR_NOT_SUPPORTED, TAG, "get_info is not supported"); return node->get_info(node, status_ret, statistics_ret); } @@ -137,16 +137,24 @@ esp_err_t twai_node_get_info(twai_node_handle_t node, twai_node_status_t *status esp_err_t twai_node_transmit(twai_node_handle_t node, const twai_frame_t *frame, int timeout_ms) { ESP_RETURN_ON_FALSE(node && frame, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null"); - ESP_RETURN_ON_FALSE(node->transmit, ESP_ERR_NOT_SUPPORTED, TAG, "transmit func null"); + ESP_RETURN_ON_FALSE(node->transmit, ESP_ERR_NOT_SUPPORTED, TAG, "transmit is not supported"); return node->transmit(node, frame, timeout_ms); } +esp_err_t twai_node_transmit_wait_all_done(twai_node_handle_t node, int timeout_ms) +{ + ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle"); + ESP_RETURN_ON_FALSE(node->transmit_wait_done, ESP_ERR_NOT_SUPPORTED, TAG, "transmit_wait_done is not supported"); + + return node->transmit_wait_done(node, timeout_ms); +} + esp_err_t twai_node_receive_from_isr(twai_node_handle_t node, twai_frame_t *rx_frame) { ESP_RETURN_ON_FALSE_ISR(node && rx_frame, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null"); ESP_RETURN_ON_FALSE_ISR((rx_frame->buffer_len == 0) || esp_ptr_in_dram(rx_frame->buffer) || esp_ptr_external_ram(rx_frame->buffer), ESP_ERR_INVALID_ARG, TAG, "invalid 'rx_frame->buffer' pointer or buffer_len"); - ESP_RETURN_ON_FALSE_ISR(node->receive_isr, ESP_ERR_NOT_SUPPORTED, TAG, "receive func null"); + ESP_RETURN_ON_FALSE_ISR(node->receive_isr, ESP_ERR_NOT_SUPPORTED, TAG, "receive is not supported"); return node->receive_isr(node, rx_frame); } diff --git a/components/esp_driver_twai/esp_twai_onchip.c b/components/esp_driver_twai/esp_twai_onchip.c index 383bd8f1c3..2046d2b3c5 100644 --- a/components/esp_driver_twai/esp_twai_onchip.c +++ b/components/esp_driver_twai/esp_twai_onchip.c @@ -60,6 +60,8 @@ static void _twai_rcc_clock_sel(uint8_t ctrlr_id, twai_clock_source_t clock) } #endif //SOC_TWAI_SUPPORT_FD +#define TWAI_IDLE_EVENT_BIT BIT0 //event used for tx_wait_all_done + typedef struct { struct twai_node_base api_base; int ctrlr_id; @@ -67,6 +69,7 @@ typedef struct { twai_hal_context_t *hal; intr_handle_t intr_hdl; QueueHandle_t tx_mount_queue; + EventGroupHandle_t event_group; twai_clock_source_t curr_clk_src; uint32_t valid_fd_timing; twai_event_callbacks_t cbs; @@ -239,6 +242,7 @@ static void _node_isr_main(void *arg) _node_start_trans(twai_ctx); } else { atomic_store(&twai_ctx->hw_busy, false); + xEventGroupSetBitsFromISR(twai_ctx->event_group, TWAI_IDLE_EVENT_BIT, &do_yield); } } } @@ -284,6 +288,10 @@ static void _node_isr_main(void *arg) _node_start_trans(twai_ctx); } else { atomic_store(&twai_ctx->hw_busy, false); + if (atomic_load(&twai_ctx->state) != TWAI_ERROR_BUS_OFF) { + // only when node is not in busoff here, means tx is finished + xEventGroupSetBitsFromISR(twai_ctx->event_group, TWAI_IDLE_EVENT_BIT, &do_yield); + } } } @@ -305,6 +313,9 @@ static void _node_destroy(twai_onchip_ctx_t *twai_ctx) if (twai_ctx->tx_mount_queue) { vQueueDeleteWithCaps(twai_ctx->tx_mount_queue); } + if (twai_ctx->event_group) { + vEventGroupDeleteWithCaps(twai_ctx->event_group); + } if (twai_ctx->ctrlr_id != -1) { _ctrlr_release(twai_ctx->ctrlr_id); } @@ -582,6 +593,7 @@ static esp_err_t _node_queue_tx(twai_node_handle_t node, const twai_frame_t *fra ESP_RETURN_ON_FALSE(atomic_load(&twai_ctx->state) != TWAI_ERROR_BUS_OFF, ESP_ERR_INVALID_STATE, TAG, "node is bus off"); TickType_t ticks_to_wait = (timeout == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout); + xEventGroupClearBits(twai_ctx->event_group, TWAI_IDLE_EVENT_BIT); //going to send, clear the idle event bool false_var = false; if (atomic_compare_exchange_strong(&twai_ctx->hw_busy, &false_var, true)) { twai_ctx->p_curr_tx = frame; @@ -601,10 +613,28 @@ static esp_err_t _node_queue_tx(twai_node_handle_t node, const twai_frame_t *fra return ESP_OK; } +static esp_err_t _node_wait_tx_all_done(twai_node_handle_t node, int timeout) +{ + twai_onchip_ctx_t *twai_ctx = __containerof(node, twai_onchip_ctx_t, api_base); + TickType_t ticks_to_wait = (timeout == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout); + ESP_RETURN_ON_FALSE(atomic_load(&twai_ctx->state) != TWAI_ERROR_BUS_OFF, ESP_ERR_INVALID_STATE, TAG, "node is bus off"); + + // either hw_busy or tx_mount_queue is not empty, means tx is not finished + // otherwise, hardware is idle, return immediately + if (atomic_load(&twai_ctx->hw_busy) || uxQueueMessagesWaiting(twai_ctx->tx_mount_queue)) { + //wait for idle event bit but without clear it, every tasks block here can be waked up + if (TWAI_IDLE_EVENT_BIT != xEventGroupWaitBits(twai_ctx->event_group, TWAI_IDLE_EVENT_BIT, pdFALSE, pdFALSE, ticks_to_wait)) { + return ESP_ERR_TIMEOUT; + } + } + return ESP_OK; +} + static esp_err_t _node_parse_rx(twai_node_handle_t node, twai_frame_t *rx_frame) { twai_onchip_ctx_t *twai_ctx = __containerof(node, twai_onchip_ctx_t, api_base); ESP_RETURN_ON_FALSE_ISR(atomic_load(&twai_ctx->rx_isr), ESP_ERR_INVALID_STATE, TAG, "rx can only called in `rx_done` callback"); + assert(xPortInIsrContext() && "should always in rx_done callback"); twai_hal_parse_frame(&twai_ctx->rcv_buff, &rx_frame->header, rx_frame->buffer, rx_frame->buffer_len); return ESP_OK; @@ -630,7 +660,8 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa // state is in bus_off before enabled atomic_store(&node->state, TWAI_ERROR_BUS_OFF); node->tx_mount_queue = xQueueCreateWithCaps(node_config->tx_queue_depth, sizeof(twai_frame_t *), TWAI_MALLOC_CAPS); - ESP_GOTO_ON_FALSE(node->tx_mount_queue || node_config->flags.enable_listen_only, ESP_ERR_NO_MEM, err, TAG, "no_mem"); + node->event_group = xEventGroupCreateWithCaps(TWAI_MALLOC_CAPS); + ESP_GOTO_ON_FALSE((node->tx_mount_queue && node->event_group) || node_config->flags.enable_listen_only, ESP_ERR_NO_MEM, err, TAG, "no_mem"); uint32_t intr_flags = TWAI_INTR_ALLOC_FLAGS; intr_flags |= (node_config->intr_priority > 0) ? BIT(node_config->intr_priority) : ESP_INTR_FLAG_LOWMED; ESP_GOTO_ON_ERROR(esp_intr_alloc(twai_periph_signals[ctrlr_id].irq_id, intr_flags, _node_isr_main, (void *)node, &node->intr_hdl), @@ -683,6 +714,7 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa node->api_base.reconfig_timing = _node_set_bit_timing; node->api_base.register_cbs = _node_register_callbacks; node->api_base.transmit = _node_queue_tx; + node->api_base.transmit_wait_done = _node_wait_tx_all_done; node->api_base.receive_isr = _node_parse_rx; node->api_base.get_info = _node_get_status; diff --git a/components/esp_driver_twai/include/esp_private/twai_interface.h b/components/esp_driver_twai/include/esp_private/twai_interface.h index dddf00c7b1..83c7c84496 100644 --- a/components/esp_driver_twai/include/esp_private/twai_interface.h +++ b/components/esp_driver_twai/include/esp_private/twai_interface.h @@ -91,6 +91,18 @@ struct twai_node_base { */ esp_err_t (*transmit)(struct twai_node_base *node, const twai_frame_t *frame, int timeout); + /** + * @brief Wait for the TWAI node to finish transmitting + * + * @param[in] node Pointer to the TWAI node base + * @param[in] timeout Timeout in milliseconds + * @return esp_err_t + * - ESP_OK: Success + * - ESP_ERR_TIMEOUT: Waiting timeout + * - ESP_ERR_INVALID_STATE: Node is not enabled or already in bus-off state + */ + esp_err_t (*transmit_wait_done)(struct twai_node_base *node, int timeout); + /** * @brief Receive a TWAI frame through the ISR callback * diff --git a/components/esp_driver_twai/include/esp_twai.h b/components/esp_driver_twai/include/esp_twai.h index 448bb05c80..73cba1a636 100644 --- a/components/esp_driver_twai/include/esp_twai.h +++ b/components/esp_driver_twai/include/esp_twai.h @@ -111,6 +111,15 @@ esp_err_t twai_node_get_info(twai_node_handle_t node, twai_node_status_t *status */ esp_err_t twai_node_transmit(twai_node_handle_t node, const twai_frame_t *frame, int timeout_ms); +/** + * @brief Wait for all pending transfers to finish, if bus-off happens during waiting, wait until node recovered and tx is finished, or timeout + * + * @param[in] node Handle to the TWAI node + * @param[in] timeout_ms Maximum wait time for all pending transfers to finish (milliseconds), -1 to wait forever + * @return ESP_OK on success, error code otherwise + */ +esp_err_t twai_node_transmit_wait_all_done(twai_node_handle_t node, int timeout_ms); + /** * @brief Receive a TWAI frame from 'rx_done_cb' * diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp index 0da10f6f4c..d13b287ad5 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include "unity.h" #include "unity_test_utils_cache.h" @@ -89,7 +90,9 @@ TEST_CASE("twai install uninstall (loopback)", "[twai]") 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_wait_all_done(node_hdl[SOC_TWAI_CONTROLLER_NUM], 0)); // test wait before transmit TEST_ESP_OK(twai_node_transmit(node_hdl[SOC_TWAI_CONTROLLER_NUM], &tx_frame, 0)); + TEST_ESP_ERR(ESP_ERR_TIMEOUT, twai_node_transmit_wait_all_done(node_hdl[SOC_TWAI_CONTROLLER_NUM], 0)); // test return before finish 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)); @@ -216,9 +219,7 @@ TEST_CASE("twai transmit stop resume (loopback)", "[twai]") TEST_ESP_OK(twai_node_enable(node_hdl)); //waiting pkg receive finish - while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_LEN) { - vTaskDelay(1); - } + TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, -1)); free(tx_msgs); // check if pkg receive correct @@ -244,7 +245,7 @@ static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t tr 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 + TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, 8)); } } @@ -530,3 +531,49 @@ TEST_CASE("twai bus off recovery (loopback)", "[twai]") TEST_ESP_OK(twai_node_disable(node_hdl)); TEST_ESP_OK(twai_node_delete(node_hdl)); } + +static void test_send_wait_task(void *args) +{ + const char *task_name = pcTaskGetName(NULL); + twai_node_handle_t node_hdl = ((twai_node_handle_t *)args)[0]; + atomic_int *tasks_finished = ((atomic_int **)args)[1]; + twai_frame_t tx_frame = {}; + tx_frame.header.rtr = true; + + for (uint8_t i = 0; i < 10; i++) { + tx_frame.header.id = 0x100 + i; + printf("%s send %d\n", task_name, i); + TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame, -1)); + printf("%s wait %d\n", task_name, i); + TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, -1)); + } + printf("%s finished\n", task_name); + atomic_fetch_add(tasks_finished, 1); + vTaskDelete(NULL); +} + +TEST_CASE("twai tx_wait_all_done thread safe", "[twai]") +{ + twai_node_handle_t node_hdl; + twai_onchip_node_config_t node_config = {}; + node_config.io_cfg.tx = TEST_TX_GPIO; + node_config.io_cfg.rx = TEST_TX_GPIO; //Using same pin for test without transceiver + node_config.bit_timing.bitrate = 100000; //slow bitrate to ensure transmite finish during wait_all_done + node_config.tx_queue_depth = TEST_FRAME_NUM; + node_config.flags.enable_self_test = true; + + TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + + atomic_int tasks_finished = 0; + void *args[2] = {node_hdl, &tasks_finished}; + xTaskCreate(test_send_wait_task, "task_high", 4096, args, 1, NULL); + xTaskCreate(test_send_wait_task, "task_low ", 4096, args, 0, NULL); + + vTaskDelay(500); //wait for tasks finished + printf("tasks_finished: %d\n", atomic_load(&tasks_finished)); + TEST_ASSERT_EQUAL(2, atomic_load(&tasks_finished)); + + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_delete(node_hdl)); +} diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp index 2994873634..59e3861e1e 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp @@ -32,7 +32,7 @@ static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t tr 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 + TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, -1)); } } @@ -179,9 +179,7 @@ TEST_CASE("twai fd transmit time (loopback)", "[twai]") } //waiting pkg receive finish - while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_TIME_BUF_LEN) { - vTaskDelay(1); - } + TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, -1)); time2 = esp_timer_get_time(); free(tx_msgs); diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_network.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_network.cpp index 609c792436..043154ddb7 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_network.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_network.cpp @@ -54,6 +54,7 @@ TEST_CASE("twai_listen_only", "[twai_net]") while (!rx_msg_cnt) { vTaskDelay(1); } + TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, 0)); // test wait after only receive ESP_LOGI("Test", "receive with id 0x%lx", rx_frame.header.id); ESP_LOG_BUFFER_HEX("Data", rx_frame.buffer, twaifd_dlc2len(rx_frame.header.dlc)); TEST_ASSERT_EQUAL_HEX(0x6688, rx_frame.header.id); diff --git a/components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.cache_safe b/components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.cache_safe index a46e7e0fa4..3591ebd430 100644 --- a/components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.cache_safe +++ b/components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.cache_safe @@ -1,5 +1,6 @@ CONFIG_COMPILER_DUMP_RTL_FILES=y CONFIG_TWAI_ISR_CACHE_SAFE=y +CONFIG_FREERTOS_IN_IRAM=y CONFIG_COMPILER_OPTIMIZATION_NONE=y CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y diff --git a/docs/en/api-reference/peripherals/twai.rst b/docs/en/api-reference/peripherals/twai.rst index 396683acb1..28d94a1d47 100644 --- a/docs/en/api-reference/peripherals/twai.rst +++ b/docs/en/api-reference/peripherals/twai.rst @@ -120,6 +120,7 @@ To reduce performance overhead caused by memory copying, the TWAI driver uses po .buffer_len = sizeof(send_buff), // Length of data to transmit }; ESP_ERROR_CHECK(twai_node_transmit(node_hdl, &tx_msg, 0)); // Timeout = 0: returns immediately if queue is full + ESP_ERROR_CHECK(twai_node_transmit_wait_all_done(node_hdl, -1)); // Wait for transmission to finish In this example, :cpp:member:`twai_frame_t::header::id` specifies the ID of the message as 0x01. Message IDs are typically used to indicate the type of message in an application and also play a role in bus arbitration during transmission—lower values indicate higher priority on the bus. :cpp:member:`twai_frame_t::buffer` points to the memory address where the data to be transmitted is stored, and :cpp:member:`twai_frame_t::buffer_len` specifies the length of that data. diff --git a/docs/zh_CN/api-reference/peripherals/twai.rst b/docs/zh_CN/api-reference/peripherals/twai.rst index 2c4a5ed622..2342b27dba 100644 --- a/docs/zh_CN/api-reference/peripherals/twai.rst +++ b/docs/zh_CN/api-reference/peripherals/twai.rst @@ -120,6 +120,7 @@ TWAI 报文有多种类型,由报头指定。一个典型的数据帧报文主 .buffer_len = sizeof(send_buff), // 发送数据的长度 }; ESP_ERROR_CHECK(twai_node_transmit(node_hdl, &tx_msg, 0)); // 超时为0,队列满则直接返回超时 + ESP_ERROR_CHECK(twai_node_transmit_wait_all_done(node_hdl, -1)); // 等待发送完成 其中 :cpp:member:`twai_frame_t::header::id` 指示了该文的 ID 为 0x01。报文的 ID 通常用于表示报文在应用中的类型,并在发送过程中起到总线竞争仲裁的作用,其数值越小,在总线上的优先级越高。:cpp:member:`twai_frame_t::buffer` 则指向要发送数据所在的内存地址,并由 :cpp:member:`twai_frame_t::buffer_len` 给出数据长度。