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 2db5a9bc3e..6b8f9c498e 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 @@ -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); diff --git a/components/esp_hal_twai/include/hal/twai_hal.h b/components/esp_hal_twai/include/hal/twai_hal.h index 8216731fd0..82798d5bbc 100644 --- a/components/esp_hal_twai/include/hal/twai_hal.h +++ b/components/esp_hal_twai/include/hal/twai_hal.h @@ -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 -------------------------------- */ diff --git a/components/esp_hal_twai/twai_hal_v1.c b/components/esp_hal_twai/twai_hal_v1.c index dc69a8ac8f..cf01ef1a6b 100644 --- a/components/esp_hal_twai/twai_hal_v1.c +++ b/components/esp_hal_twai/twai_hal_v1.c @@ -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); } diff --git a/components/esp_hal_twai/twai_hal_v2.c b/components/esp_hal_twai/twai_hal_v2.c index 62ff17e6f6..acad4dc5df 100644 --- a/components/esp_hal_twai/twai_hal_v2.c +++ b/components/esp_hal_twai/twai_hal_v2.c @@ -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; }