fix(driver_twai): fixed TWAI arbitration lost event handling

Merges https://github.com/espressif/esp-idf/pull/18100
This commit is contained in:
Franz Höpfinger
2026-01-08 11:19:02 +01:00
committed by wanckl
parent 97d9585357
commit 448b300a14
4 changed files with 59 additions and 8 deletions
@@ -20,6 +20,7 @@
#include "esp_twai_onchip.h"
#include "hal/twai_periph.h"
#include "esp_private/gpio.h"
#include "soc/gpio_sig_map.h"
#include "driver/uart.h" // for baudrate detection
#define TEST_TX_GPIO GPIO_NUM_4
@@ -575,6 +576,55 @@ TEST_CASE("twai bus off recovery (loopback)", "[twai]")
TEST_ESP_OK(twai_node_delete(node_hdl));
}
static IRAM_ATTR bool test_arb_error_cb(twai_node_handle_t handle, const twai_error_event_data_t *edata, void *user_ctx)
{
esp_rom_printf("bus error: 0x%lx\n", edata->err_flags.val);
// only arb lost or stuff err is expected, stuff_err comes from RX section after arb lost
// test using loopback mode, arb_lost -> switch to RX -> no one is sending -> can't receive new waves -> stuff err
TEST_ASSERT(edata->err_flags.arb_lost || edata->err_flags.stuff_err);
return true;
}
TEST_CASE("test arb lost and stuff err", "[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.io_cfg.quanta_clk_out = GPIO_NUM_NC;
node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC;
node_config.bit_timing.bitrate = 50000; //slow bitrate to ensure soft error trigger
node_config.tx_queue_depth = 1;
node_config.flags.enable_self_test = true;
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
twai_event_callbacks_t user_cbs = {};
user_cbs.on_error = test_arb_error_cb;
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, NULL));
TEST_ESP_OK(twai_node_enable(node_hdl));
twai_node_status_t node_status = {};
twai_frame_t tx_frame = {};
tx_frame.header.id = 0x7F0; // send high id range to easier trigger arb lost
gpio_set_level(TEST_TX_GPIO, 0);
while (node_status.state != TWAI_ERROR_BUS_OFF && (tx_frame.header.id > 0x7F0 - 10)) {
printf("sending frame %lx last tec %d rec %d\n", tx_frame.header.id --, node_status.tx_error_count, node_status.rx_error_count);
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame, 500));
if (tx_frame.header.id < 0x7F0 - 2) { // trigger error after 2 frames
printf("trigger arb lost now!\n");
esp_rom_delay_us(5 * (1000000 / node_config.bit_timing.bitrate)); // trigger error at 30 bits after frame start
gpio_matrix_output(TEST_TX_GPIO, SIG_GPIO_OUT_IDX, false, false);
esp_rom_delay_us(2 * (1000000 / node_config.bit_timing.bitrate)); // trigger error for 2 bits
gpio_matrix_output(TEST_TX_GPIO, twai_periph_signals[0].tx_sig, false, false);
}
vTaskDelay(pdMS_TO_TICKS(1000)); // some time for hardware report errors
twai_node_get_info(node_hdl, &node_status, NULL);
}
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);
@@ -280,7 +280,9 @@ twai_error_state_t twai_hal_get_err_state(twai_hal_context_t *hal_ctx);
__attribute__((always_inline))
static inline twai_error_flags_t twai_hal_get_err_flags(twai_hal_context_t *hal_ctx)
{
return hal_ctx->errors;
twai_error_flags_t error_flags = hal_ctx->errors;
hal_ctx->errors.val = 0; // clear ctx for next errors
return error_flags;
}
/* ------------------------------- TX and RX -------------------------------- */
+5 -7
View File
@@ -276,13 +276,10 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx)
twai_ll_err_dir_t dir;
twai_ll_err_seg_t seg;
twai_ll_parse_err_code_cap(hal_ctx->dev, &type, &dir, &seg); //Decode error interrupt
twai_error_flags_t errors = {
.bit_err = (type == TWAI_LL_ERR_BIT),
.form_err = (type == TWAI_LL_ERR_FORM),
.stuff_err = (type == TWAI_LL_ERR_STUFF),
.ack_err = (type == TWAI_LL_ERR_OTHER) && (seg == TWAI_LL_ERR_SEG_ACK_SLOT),
};
hal_ctx->errors = errors;
hal_ctx->errors.bit_err = (type == TWAI_LL_ERR_BIT);
hal_ctx->errors.form_err = (type == TWAI_LL_ERR_FORM);
hal_ctx->errors.stuff_err = (type == TWAI_LL_ERR_STUFF);
hal_ctx->errors.ack_err = (type == TWAI_LL_ERR_OTHER) && (seg == TWAI_LL_ERR_SEG_ACK_SLOT);
#if TWAI_LL_HAS_RX_FRAME_ISSUE
//Check for errata condition (RX message has bus error at particular segments)
if (dir == TWAI_LL_ERR_DIR_RX &&
@@ -293,6 +290,7 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx)
}
#endif
}
hal_ctx->errors.arb_lost = !!(events & TWAI_HAL_EVENT_ARB_LOST);
if (events & TWAI_HAL_EVENT_ARB_LOST) {
twai_ll_clear_arb_lost_cap(hal_ctx->dev);
}
+1
View File
@@ -218,6 +218,7 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx)
hal_ctx->errors = twaifd_ll_get_err_reason(hal_ctx->dev);
hal_events |= TWAI_HAL_EVENT_BUS_ERR;
}
hal_ctx->errors.arb_lost = !!(int_stat & TWAIFD_LL_INTR_ARBIT_LOST);
if (int_stat & TWAIFD_LL_INTR_ARBIT_LOST) {
hal_events |= TWAI_HAL_EVENT_ARB_LOST;
}