diff --git a/components/driver/twai/twai.c b/components/driver/twai/twai.c index 4243f0a23f7..05002726ed4 100644 --- a/components/driver/twai/twai.c +++ b/components/driver/twai/twai.c @@ -243,8 +243,8 @@ static void twai_intr_handler_main(void *arg) //Note: This event will never occur if there is a periph reset event twai_handle_rx_buffer_frames(p_twai_obj, &task_woken, &alert_req); } - if (events & TWAI_HAL_EVENT_TX_BUFF_FREE) { - twai_handle_tx_buffer_frame(p_twai_obj, (events & TWAI_HAL_EVENT_TX_SUCCESS), &task_woken, &alert_req); + if (events & TWAI_HAL_EVENT_TX0_DONE) { + twai_handle_tx_buffer_frame(p_twai_obj, (events & TWAI_HAL_EVENT_TX0_SUCCESS), &task_woken, &alert_req); } //Handle events that only require alerting (i.e. no handler) diff --git a/components/esp_driver_twai/esp_twai_onchip.c b/components/esp_driver_twai/esp_twai_onchip.c index e6092e00dae..869a284eea6 100644 --- a/components/esp_driver_twai/esp_twai_onchip.c +++ b/components/esp_driver_twai/esp_twai_onchip.c @@ -68,10 +68,11 @@ typedef struct { _Atomic twai_error_state_t state; twai_node_record_t history; + uint8_t tx_slot_num; atomic_bool hw_busy; atomic_bool rx_isr; - const twai_frame_t *p_curr_tx; + const twai_frame_t *p_curr_tx[TWAI_HAL_TX_BUFFER_SLOT_NUM]; twai_hal_frame_t rcv_buff; } twai_onchip_ctx_t; @@ -162,9 +163,9 @@ static void _node_release_io(twai_onchip_ctx_t *node) } } -static void _node_start_trans(twai_onchip_ctx_t *node) +static void _node_start_trans(twai_onchip_ctx_t *node, uint8_t buffer_idx) { - const twai_frame_t *frame = node->p_curr_tx; + const twai_frame_t *frame = node->p_curr_tx[buffer_idx]; twai_hal_context_t *hal = node->hal; twai_hal_frame_t hal_buf = {}; @@ -180,8 +181,40 @@ static void _node_start_trans(twai_onchip_ctx_t *node) }, }; twai_hal_format_frame(&hal_trans, &hal_buf); - //TODO: utilize all txt buffers - twai_hal_set_tx_buffer_and_transmit(hal, &hal_buf, 0); + twai_hal_set_tx_buffer_and_transmit(hal, &hal_buf, buffer_idx); +} + +static uint8_t _node_start_tx_batch_from_isr(twai_onchip_ctx_t *node, BaseType_t *yield_required) +{ + uint8_t tx_idx = 0; + // Note: hardware slot has default priority (like 0>1>2...), + // we should fill slot with same order to avoid data inverse + while (tx_idx < node->tx_slot_num) { // try best to fill all tx slots + const twai_frame_t *frame = NULL; + if (xQueueReceiveFromISR(node->tx_mount_queue, &frame, yield_required) != pdTRUE) { + break; + } + node->p_curr_tx[tx_idx] = frame; + _node_start_trans(node, tx_idx); + tx_idx++; + } + return tx_idx; +} + +static void _node_mark_tx_idle(twai_onchip_ctx_t *node) +{ + memset(node->p_curr_tx, 0, sizeof(node->p_curr_tx)); + atomic_store(&node->hw_busy, false); +} + +static inline bool _node_is_tx_all_done(twai_onchip_ctx_t *node) +{ + for (uint8_t tx_idx = 0; tx_idx < node->tx_slot_num; tx_idx++) { + if (node->p_curr_tx[tx_idx]) { + return false; + } + } + return true; } static void _node_isr_main(void *arg) @@ -229,11 +262,10 @@ static void _node_isr_main(void *arg) } // node recover from busoff, restart remain tx transaction if ((e_data.old_sta == TWAI_ERROR_BUS_OFF) && (e_data.new_sta == TWAI_ERROR_ACTIVE)) { - if (xQueueReceiveFromISR(twai_ctx->tx_mount_queue, &twai_ctx->p_curr_tx, &do_yield)) { + if (_node_start_tx_batch_from_isr(twai_ctx, &do_yield)) { atomic_store(&twai_ctx->hw_busy, true); - _node_start_trans(twai_ctx); } else { - atomic_store(&twai_ctx->hw_busy, false); + _node_mark_tx_idle(twai_ctx); xEventGroupSetBitsFromISR(twai_ctx->event_group, TWAI_IDLE_EVENT_BIT, &do_yield); } } @@ -265,21 +297,27 @@ static void _node_isr_main(void *arg) } // deal TX event - if (events & TWAI_HAL_EVENT_TX_BUFF_FREE) { - if (twai_ctx->cbs.on_tx_done) { - twai_tx_done_event_data_t tx_ev = { - .is_tx_success = (events & TWAI_HAL_EVENT_TX_SUCCESS), // find 'on_error_cb' if not success - .done_tx_frame = twai_ctx->p_curr_tx, - }; - do_yield |= twai_ctx->cbs.on_tx_done(&twai_ctx->api_base, &tx_ev, twai_ctx->user_data); + if (events & TWAI_HAL_EVENT_TX_DONE_MASK) { + uint32_t tx_done_events = (events & TWAI_HAL_EVENT_TX_DONE_MASK) >> __builtin_ctz(TWAI_HAL_EVENT_TX0_DONE); + while (tx_done_events) { + uint32_t slot_event = tx_done_events & -tx_done_events; // get the lowest event bit + uint8_t tx_idx = __builtin_ctz(slot_event) / 2; + assert((tx_idx < twai_ctx->tx_slot_num) && twai_ctx->p_curr_tx[tx_idx]); + if (twai_ctx->cbs.on_tx_done) { + twai_tx_done_event_data_t tx_ev = { + .is_tx_success = (events & TWAI_HAL_EVENT_TX_SUCC_SLOT(tx_idx)), // find 'on_error_cb' if not success + .done_tx_frame = twai_ctx->p_curr_tx[tx_idx], + }; + do_yield |= twai_ctx->cbs.on_tx_done(&twai_ctx->api_base, &tx_ev, twai_ctx->user_data); + } + twai_ctx->p_curr_tx[tx_idx] = NULL; + tx_done_events &= ~slot_event; } - // start a new TX - if ((atomic_load(&twai_ctx->state) != TWAI_ERROR_BUS_OFF) && xQueueReceiveFromISR(twai_ctx->tx_mount_queue, &twai_ctx->p_curr_tx, &do_yield)) { - _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 + + // start a new TX batch only when all hardware TX buffers from this batch are done + if (_node_is_tx_all_done(twai_ctx) && (atomic_load(&twai_ctx->state) != TWAI_ERROR_BUS_OFF)) { + if (!_node_start_tx_batch_from_isr(twai_ctx, &do_yield)) { + _node_mark_tx_idle(twai_ctx); xEventGroupSetBitsFromISR(twai_ctx->event_group, TWAI_IDLE_EVENT_BIT, &do_yield); } } @@ -456,7 +494,11 @@ static esp_err_t _node_enable(twai_node_handle_t node) atomic_store(&twai_ctx->state, hw_state); // continuing the transaction if there be if (atomic_load(&twai_ctx->hw_busy) && hw_state != TWAI_ERROR_BUS_OFF) { - _node_start_trans(twai_ctx); + for (uint8_t tx_idx = 0; tx_idx < twai_ctx->tx_slot_num; tx_idx++) { + if (twai_ctx->p_curr_tx[tx_idx]) { + _node_start_trans(twai_ctx, tx_idx); + } + } } ESP_RETURN_ON_ERROR(esp_intr_enable(twai_ctx->intr_hdl), TAG, "enable interrupt failed"); return ESP_OK; @@ -576,8 +618,8 @@ static esp_err_t _node_queue_tx(twai_node_handle_t node, const twai_frame_t *fra 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; - _node_start_trans(twai_ctx); + twai_ctx->p_curr_tx[0] = frame; // here only has one frame, using slot 0 + _node_start_trans(twai_ctx, 0); } else { // Hardware busy, need to queue the frame BaseType_t is_isr_context = xPortInIsrContext(); @@ -596,13 +638,12 @@ static esp_err_t _node_queue_tx(twai_node_handle_t node, const twai_frame_t *fra if (atomic_compare_exchange_strong(&twai_ctx->hw_busy, &false_var, true)) { BaseType_t dequeue_result; if (is_isr_context) { - dequeue_result = xQueueReceiveFromISR(twai_ctx->tx_mount_queue, &twai_ctx->p_curr_tx, &yield_required); + dequeue_result = xQueueReceiveFromISR(twai_ctx->tx_mount_queue, &twai_ctx->p_curr_tx[0], &yield_required); } else { - dequeue_result = xQueueReceive(twai_ctx->tx_mount_queue, &twai_ctx->p_curr_tx, 0); + dequeue_result = xQueueReceive(twai_ctx->tx_mount_queue, &twai_ctx->p_curr_tx[0], 0); } - if (dequeue_result == pdTRUE) { - _node_start_trans(twai_ctx); + _node_start_trans(twai_ctx, 0); } else { // any reason here means frame already taken and maybe finished by fast hardware, so back `hw_busy` to false atomic_store(&twai_ctx->hw_busy, false); @@ -757,6 +798,11 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa .enable_loopback = node_config->flags.enable_loopback, }; ESP_GOTO_ON_FALSE(twai_hal_init(node->hal, &hal_config), ESP_ERR_INVALID_STATE, err, TAG, "hardware not in reset state"); + node->tx_slot_num = twai_hal_get_tx_slot_num(node->hal); + if (node->tx_slot_num > TWAI_HAL_TX_BUFFER_SLOT_NUM) { + ESP_LOGW(TAG, "HW TX slot num (%d) is greater than supported, only using %d slots", node->tx_slot_num, TWAI_HAL_TX_BUFFER_SLOT_NUM); + node->tx_slot_num = TWAI_HAL_TX_BUFFER_SLOT_NUM; + } // Configure bus timing ESP_GOTO_ON_ERROR(_node_calc_set_bit_timing(&node->api_base, &node_config->bit_timing, &node_config->data_timing), err, TAG, "bitrate error"); // Configure GPIO diff --git a/components/esp_driver_twai/linker.lf b/components/esp_driver_twai/linker.lf index 2fcbcef5929..50fea46cbf3 100644 --- a/components/esp_driver_twai/linker.lf +++ b/components/esp_driver_twai/linker.lf @@ -6,6 +6,9 @@ entries: esp_twai_onchip: _node_isr_main (noflash) esp_twai_onchip: _node_start_trans (noflash) esp_twai_onchip: _node_parse_rx (noflash) + esp_twai_onchip: _node_start_tx_batch_from_isr (noflash) + esp_twai_onchip: _node_mark_tx_idle (noflash) + esp_twai_onchip: _node_is_tx_all_done (noflash) if TWAI_IO_FUNC_IN_IRAM = y: esp_twai_onchip: _node_queue_tx (noflash) 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 fa10bc71536..05d76c77bec 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 @@ -194,12 +194,12 @@ TEST_CASE("twai fd transmit time (loopback)", "[twai]") } uint64_t predict_time_ms = (uint64_t)trans_num * arb_bits * 1000 / node_config.bit_timing.bitrate; predict_time_ms += (uint64_t)trans_num * data_bits * 1000 / node_config.data_timing.bitrate; - predict_time_ms += (trans_num * 20) / 1000; // add about 20 us interrupt overhead per frame + predict_time_ms += (trans_num * 10) / 1000; // add about 10 us interrupt overhead per frame #if CONFIG_COMPILER_OPTIMIZATION_NONE - predict_time_ms += (trans_num * 10) / 1000; // non optimized slow code + predict_time_ms += (trans_num * 5) / 1000; // non optimized slow code #endif #if CONFIG_PM_DFS_INIT_AUTO - predict_time_ms += (trans_num * 35) / 1000; // slow cpu + predict_time_ms += (trans_num * 10) / 1000; // slow cpu #endif //waiting pkg receive finish diff --git a/components/esp_hal_twai/esp32/include/hal/twai_ll.h b/components/esp_hal_twai/esp32/include/hal/twai_ll.h index 02bb17750db..b83d4cf8003 100644 --- a/components/esp_hal_twai/esp32/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32/include/hal/twai_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -701,6 +701,17 @@ static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_ /* ------------------------- TX/RX Buffer Registers ------------------------- */ +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twai_ll_get_tx_buffer_total(twai_dev_t *hw) +{ + return 1; // only one TX buffer +} + /** * @brief Copy a formatted TWAI frame into TX buffer for transmission * diff --git a/components/esp_hal_twai/esp32c3/include/hal/twai_ll.h b/components/esp_hal_twai/esp32c3/include/hal/twai_ll.h index 5f52f7c9b9c..ba61a769617 100644 --- a/components/esp_hal_twai/esp32c3/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32c3/include/hal/twai_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -627,6 +627,17 @@ static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_ /* ------------------------- TX/RX Buffer Registers ------------------------- */ +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twai_ll_get_tx_buffer_total(twai_dev_t *hw) +{ + return 1; // only one TX buffer +} + /** * @brief Copy a formatted TWAI frame into TX buffer for transmission * diff --git a/components/esp_hal_twai/esp32c5/include/hal/twaifd_ll.h b/components/esp_hal_twai/esp32c5/include/hal/twaifd_ll.h index 3baad4e6f7e..62fcf6061d1 100644 --- a/components/esp_hal_twai/esp32c5/include/hal/twaifd_ll.h +++ b/components/esp_hal_twai/esp32c5/include/hal/twaifd_ll.h @@ -48,6 +48,10 @@ #define TWAIFD_LL_TX_CMD_READY TWAIFD_TXCR // Set tx buffer to "Ready" state #define TWAIFD_LL_TX_CMD_ABORT TWAIFD_TXCA // Set tx buffer to "Aborted" state +#define TWAIFD_LL_TX_STATUS_SUCCESS 0x4 // TX buffer transmitted successfully +#define TWAIFD_LL_TX_STATUS_FAILED 0x6 // TX buffer transmission failed +#define TWAIFD_LL_TX_STATUS_ABORTED 0x7 // TX buffer transmission aborted + #define TWAIFD_LL_HW_CMD_RST_ERR_CNT TWAIFD_ERCRST // Error Counters Reset #define TWAIFD_LL_HW_CMD_RST_RX_CNT TWAIFD_RXFCRST // Clear RX bus traffic counter #define TWAIFD_LL_HW_CMD_RST_TX_CNT TWAIFD_TXFCRST // Clear TX bus traffic counter @@ -665,11 +669,10 @@ static inline uint32_t twaifd_ll_get_tx_buffer_total(twaifd_dev_t *hw) * @param buffer_idx Index of the TX buffer (0-7). * @return The status of the selected TX buffer. */ +__attribute__((always_inline)) static inline uint32_t twaifd_ll_get_tx_buffer_status(twaifd_dev_t *hw, uint8_t buffer_idx) { - HAL_ASSERT(buffer_idx < twaifd_ll_get_tx_buffer_total(hw)); // Ensure buffer index is valid - uint32_t reg_val = hw->tx_status.val; - return reg_val & (TWAIFD_TX2S_V << (TWAIFD_TX2S_S * buffer_idx)); // Get status for buffer + return (hw->tx_status.val >> (TWAIFD_TX2S_S * buffer_idx)) & TWAIFD_TX2S_V; } /** @@ -700,7 +703,6 @@ static inline void twaifd_ll_set_tx_buffer_cmd(twaifd_dev_t *hw, uint8_t buffer_ */ static inline void twaifd_ll_set_tx_buffer_priority(twaifd_dev_t *hw, uint8_t buffer_idx, uint32_t priority) { - HAL_ASSERT(buffer_idx < twaifd_ll_get_tx_buffer_total(hw)); // Ensure buffer index is valid uint32_t reg_val = hw->tx_priority.val; reg_val &= ~(TWAIFD_TXT1P_V << (TWAIFD_TXT2P_S * buffer_idx)); // Clear old priority reg_val |= priority << (TWAIFD_TXT2P_S * buffer_idx); // Set new priority diff --git a/components/esp_hal_twai/esp32c6/include/hal/twai_ll.h b/components/esp_hal_twai/esp32c6/include/hal/twai_ll.h index bf5f7b71455..adc318e5261 100644 --- a/components/esp_hal_twai/esp32c6/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32c6/include/hal/twai_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -637,6 +637,17 @@ static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_ /* ------------------------- TX/RX Buffer Registers ------------------------- */ +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twai_ll_get_tx_buffer_total(twai_dev_t *hw) +{ + return 1; // only one TX buffer +} + /** * @brief Copy a formatted TWAI frame into TX buffer for transmission * diff --git a/components/esp_hal_twai/esp32h2/include/hal/twai_ll.h b/components/esp_hal_twai/esp32h2/include/hal/twai_ll.h index 701b5e7f913..4b868b55503 100644 --- a/components/esp_hal_twai/esp32h2/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32h2/include/hal/twai_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -615,6 +615,17 @@ static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_ /* ------------------------- TX/RX Buffer Registers ------------------------- */ +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twai_ll_get_tx_buffer_total(twai_dev_t *hw) +{ + return 1; // only one TX buffer +} + /** * @brief Copy a formatted TWAI frame into TX buffer for transmission * diff --git a/components/esp_hal_twai/esp32h21/include/hal/twai_ll.h b/components/esp_hal_twai/esp32h21/include/hal/twai_ll.h index 2e9001fd585..3d3ded42300 100644 --- a/components/esp_hal_twai/esp32h21/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32h21/include/hal/twai_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -615,6 +615,17 @@ static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_ /* ------------------------- TX/RX Buffer Registers ------------------------- */ +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twai_ll_get_tx_buffer_total(twai_dev_t *hw) +{ + return 1; // only one TX buffer +} + /** * @brief Copy a formatted TWAI frame into TX buffer for transmission * diff --git a/components/esp_hal_twai/esp32h4/include/hal/twaifd_ll.h b/components/esp_hal_twai/esp32h4/include/hal/twaifd_ll.h index 1874ae9fc6d..a3b3f757c7e 100644 --- a/components/esp_hal_twai/esp32h4/include/hal/twaifd_ll.h +++ b/components/esp_hal_twai/esp32h4/include/hal/twaifd_ll.h @@ -48,6 +48,10 @@ #define TWAIFD_LL_TX_CMD_READY TWAIFD_TXCR // Set tx buffer to "Ready" state #define TWAIFD_LL_TX_CMD_ABORT TWAIFD_TXCA // Set tx buffer to "Aborted" state +#define TWAIFD_LL_TX_STATUS_SUCCESS 0x4 // TX buffer transmitted successfully +#define TWAIFD_LL_TX_STATUS_FAILED 0x6 // TX buffer transmission failed +#define TWAIFD_LL_TX_STATUS_ABORTED 0x7 // TX buffer transmission aborted + #define TWAIFD_LL_HW_CMD_RST_ERR_CNT TWAIFD_ERCRST // Error Counters Reset #define TWAIFD_LL_HW_CMD_RST_RX_CNT TWAIFD_RXFCRST // Clear RX bus traffic counter #define TWAIFD_LL_HW_CMD_RST_TX_CNT TWAIFD_TXFCRST // Clear TX bus traffic counter @@ -664,11 +668,10 @@ static inline uint32_t twaifd_ll_get_tx_buffer_total(twaifd_dev_t *hw) * @param buffer_idx Index of the TX buffer (0-7). * @return The status of the selected TX buffer. */ +__attribute__((always_inline)) static inline uint32_t twaifd_ll_get_tx_buffer_status(twaifd_dev_t *hw, uint8_t buffer_idx) { - HAL_ASSERT(buffer_idx < twaifd_ll_get_tx_buffer_total(hw)); // Ensure buffer index is valid - uint32_t reg_val = hw->tx_status.val; - return reg_val & (TWAIFD_TX2S_V << (TWAIFD_TX2S_S * buffer_idx)); // Get status for buffer + return (hw->tx_status.val >> (TWAIFD_TX2S_S * buffer_idx)) & TWAIFD_TX2S_V; } /** @@ -699,7 +702,6 @@ static inline void twaifd_ll_set_tx_buffer_cmd(twaifd_dev_t *hw, uint8_t buffer_ */ static inline void twaifd_ll_set_tx_buffer_priority(twaifd_dev_t *hw, uint8_t buffer_idx, uint32_t priority) { - HAL_ASSERT(buffer_idx < twaifd_ll_get_tx_buffer_total(hw)); // Ensure buffer index is valid uint32_t reg_val = hw->tx_priority.val; reg_val &= ~(TWAIFD_TXT1P_V << (TWAIFD_TXT2P_S * buffer_idx)); // Clear old priority reg_val |= priority << (TWAIFD_TXT2P_S * buffer_idx); // Set new priority diff --git a/components/esp_hal_twai/esp32p4/include/hal/twai_ll.h b/components/esp_hal_twai/esp32p4/include/hal/twai_ll.h index 762cb9e4ac4..1a2ebb7e3f0 100644 --- a/components/esp_hal_twai/esp32p4/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32p4/include/hal/twai_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -680,6 +680,17 @@ static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_ /* ------------------------- TX/RX Buffer Registers ------------------------- */ +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twai_ll_get_tx_buffer_total(twai_dev_t *hw) +{ + return 1; // only one TX buffer +} + /** * @brief Copy a formatted TWAI frame into TX buffer for transmission * diff --git a/components/esp_hal_twai/esp32s2/include/hal/twai_ll.h b/components/esp_hal_twai/esp32s2/include/hal/twai_ll.h index abd1ffba065..d2f9d7f9ae1 100644 --- a/components/esp_hal_twai/esp32s2/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32s2/include/hal/twai_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -630,6 +630,17 @@ static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_ /* ------------------------- TX/RX Buffer Registers ------------------------- */ +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twai_ll_get_tx_buffer_total(twai_dev_t *hw) +{ + return 1; // only one TX buffer +} + /** * @brief Copy a formatted TWAI frame into TX buffer for transmission * diff --git a/components/esp_hal_twai/esp32s3/include/hal/twai_ll.h b/components/esp_hal_twai/esp32s3/include/hal/twai_ll.h index aad2bc7819a..5906369caba 100644 --- a/components/esp_hal_twai/esp32s3/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32s3/include/hal/twai_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -627,6 +627,17 @@ static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_ /* ------------------------- TX/RX Buffer Registers ------------------------- */ +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twai_ll_get_tx_buffer_total(twai_dev_t *hw) +{ + return 1; // only one TX buffer +} + /** * @brief Copy a formatted TWAI frame into TX buffer for transmission * diff --git a/components/esp_hal_twai/include/hal/twai_hal.h b/components/esp_hal_twai/include/hal/twai_hal.h index 23bf080ab5a..5fc80557f1e 100644 --- a/components/esp_hal_twai/include/hal/twai_hal.h +++ b/components/esp_hal_twai/include/hal/twai_hal.h @@ -50,9 +50,29 @@ typedef union twai_ll_frame_buffer_t twai_hal_frame_t; #define TWAI_HAL_EVENT_BUS_ERR (1 << 7) #define TWAI_HAL_EVENT_ARB_LOST (1 << 8) #define TWAI_HAL_EVENT_RX_BUFF_FRAME (1 << 9) -#define TWAI_HAL_EVENT_TX_BUFF_FREE (1 << 10) -#define TWAI_HAL_EVENT_NEED_PERIPH_RESET (1 << 11) -#define TWAI_HAL_EVENT_TX_SUCCESS (1 << 12) +#define TWAI_HAL_EVENT_NEED_PERIPH_RESET (1 << 10) +#define TWAI_HAL_EVENT_TX0_DONE (1 << 11) +#define TWAI_HAL_EVENT_TX0_SUCCESS (1 << 12) +#define TWAI_HAL_EVENT_TX1_DONE (1 << 13) +#define TWAI_HAL_EVENT_TX1_SUCCESS (1 << 14) +#define TWAI_HAL_EVENT_TX2_DONE (1 << 15) +#define TWAI_HAL_EVENT_TX2_SUCCESS (1 << 16) +#define TWAI_HAL_EVENT_TX3_DONE (1 << 17) +#define TWAI_HAL_EVENT_TX3_SUCCESS (1 << 18) +#define TWAI_HAL_EVENT_TX4_DONE (1 << 19) +#define TWAI_HAL_EVENT_TX4_SUCCESS (1 << 20) +#define TWAI_HAL_EVENT_TX5_DONE (1 << 21) +#define TWAI_HAL_EVENT_TX5_SUCCESS (1 << 22) +#define TWAI_HAL_EVENT_TX6_DONE (1 << 23) +#define TWAI_HAL_EVENT_TX6_SUCCESS (1 << 24) +#define TWAI_HAL_EVENT_TX7_DONE (1 << 25) +#define TWAI_HAL_EVENT_TX7_SUCCESS (1 << 26) +#define TWAI_HAL_TX_BUFFER_SLOT_NUM 8 // support up to 8 TX slots in hal layer + +#define TWAI_HAL_EVENT_TX_DONE_MASK (TWAI_HAL_EVENT_TX0_DONE | TWAI_HAL_EVENT_TX1_DONE | TWAI_HAL_EVENT_TX2_DONE | TWAI_HAL_EVENT_TX3_DONE | \ + TWAI_HAL_EVENT_TX4_DONE | TWAI_HAL_EVENT_TX5_DONE | TWAI_HAL_EVENT_TX6_DONE | TWAI_HAL_EVENT_TX7_DONE) +#define TWAI_HAL_EVENT_TX_DONE_SLOT(buffer_idx) (TWAI_HAL_EVENT_TX0_DONE << ((buffer_idx) * 2)) +#define TWAI_HAL_EVENT_TX_SUCC_SLOT(buffer_idx) (TWAI_HAL_EVENT_TX0_SUCCESS << ((buffer_idx) * 2)) typedef struct { twai_soc_handle_t dev; // TWAI SOC layer handle (i.e. register base address) @@ -61,6 +81,7 @@ typedef struct { uint32_t timer_overflow_cnt; twai_error_flags_t errors; uint8_t sja1000_filter_id_type; // hardware don't check id type, check in software, 0:no_filter, 1: std_id_only, 2: ext_id_only + uint8_t tx_buffer_num; int8_t retry_cnt; bool enable_self_test; bool enable_loopback; @@ -296,6 +317,14 @@ static inline twai_error_flags_t twai_hal_get_err_flags(twai_hal_context_t *hal_ */ uint32_t twai_hal_get_rx_msg_count(twai_hal_context_t *hal_ctx); +/** + * @brief Get the number of TX buffers supported by the hardware + * + * @param hal_ctx Context of the HAL layer + * @return TX buffer count + */ +#define twai_hal_get_tx_slot_num(hal_ctx) (hal_ctx->tx_buffer_num) + /** * @brief TWAI hal transaction description type */ diff --git a/components/esp_hal_twai/twai_hal_v1.c b/components/esp_hal_twai/twai_hal_v1.c index 518f5a61c4c..8db40957686 100644 --- a/components/esp_hal_twai/twai_hal_v1.c +++ b/components/esp_hal_twai/twai_hal_v1.c @@ -50,6 +50,7 @@ bool twai_hal_init(twai_hal_context_t *hal_ctx, const twai_hal_config_t *config) if (!twai_ll_is_in_reset_mode(hal_ctx->dev)) { //Must enter reset mode to write to config registers return false; } + hal_ctx->tx_buffer_num = twai_ll_get_tx_buffer_total(hal_ctx->dev); #if TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE hal_ctx->errata_ctx = (twai_hal_errata_ctx_t *)(hal_ctx + 1); //errata context is place at end of hal_ctx #endif @@ -238,10 +239,10 @@ static inline uint32_t twai_hal_decode_interrupt(twai_hal_context_t *hal_ctx) #else if (interrupts & TWAI_LL_INTR_TI) { #endif - TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_TX_BUFF_FREE); + TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_TX0_DONE); TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED); if (status & TWAI_LL_STATUS_TCS) { - TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_TX_SUCCESS); + TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_TX0_SUCCESS); } } //Error Passive Interrupt on transition from error active to passive or vice versa diff --git a/components/esp_hal_twai/twai_hal_v2.c b/components/esp_hal_twai/twai_hal_v2.c index cba5b646577..05e54ee5f7a 100644 --- a/components/esp_hal_twai/twai_hal_v2.c +++ b/components/esp_hal_twai/twai_hal_v2.c @@ -22,6 +22,7 @@ bool twai_hal_init(twai_hal_context_t *hal_ctx, const twai_hal_config_t *config) hal_ctx->enable_listen_only = config->enable_listen_only; twaifd_ll_reset(hal_ctx->dev); + hal_ctx->tx_buffer_num = twaifd_ll_get_tx_buffer_total(hal_ctx->dev); twaifd_ll_enable_hw(hal_ctx->dev, false); //mode should be changed under disabled twaifd_ll_set_mode(hal_ctx->dev, config->enable_listen_only, config->enable_self_test, config->enable_loopback); twaifd_ll_set_tx_retrans_limit(hal_ctx->dev, config->retry_cnt); @@ -222,9 +223,20 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx) hal_ctx->timer_overflow_cnt ++; } if (int_stat & (TWAIFD_LL_INTR_TX_DONE)) { - hal_events |= TWAI_HAL_EVENT_TX_BUFF_FREE; - if (int_stat & TWAIFD_LL_INTR_TX_FRAME) { - hal_events |= TWAI_HAL_EVENT_TX_SUCCESS; + for (uint32_t i = 0; i < MIN(hal_ctx->tx_buffer_num, TWAI_HAL_TX_BUFFER_SLOT_NUM); i++) { + uint32_t tx_status = twaifd_ll_get_tx_buffer_status(hal_ctx->dev, i); + switch (tx_status) { + case TWAIFD_LL_TX_STATUS_SUCCESS: + hal_events |= TWAI_HAL_EVENT_TX_SUCC_SLOT(i); + __attribute__((fallthrough)); // success event must be a done event, just fallthrough + case TWAIFD_LL_TX_STATUS_FAILED: + case TWAIFD_LL_TX_STATUS_ABORTED: + hal_events |= TWAI_HAL_EVENT_TX_DONE_SLOT(i); + twaifd_ll_set_tx_buffer_cmd(hal_ctx->dev, i, TWAIFD_LL_TX_CMD_EMPTY); // clear buffer to empty state + break; + default: + break; + } } } if (int_stat & TWAIFD_LL_INTR_RX_NOT_EMPTY) {