From 7fa65f4cff4c5b9a317cefaa11b8006a8cf05dad Mon Sep 17 00:00:00 2001 From: wanckl Date: Wed, 22 Oct 2025 17:25:25 +0800 Subject: [PATCH 1/6] refactor(driver_twai): remove errata config selection 1 --- components/driver/twai/Kconfig.twai | 12 ------------ components/hal/esp32/include/hal/twai_ll.h | 9 ++++++++- components/hal/twai_hal_v1.c | 2 +- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/components/driver/twai/Kconfig.twai b/components/driver/twai/Kconfig.twai index 11ff4187296..64e60d7c61e 100644 --- a/components/driver/twai/Kconfig.twai +++ b/components/driver/twai/Kconfig.twai @@ -21,18 +21,6 @@ menu "Legacy TWAI Driver Configurations" (driver/twai.h). If you want to continue using the legacy driver, and don't want to see related deprecation warnings, you can enable this option. - config TWAI_ERRATA_FIX_BUS_OFF_REC - bool "Add SW workaround for REC change during bus-off" - depends on IDF_TARGET_ESP32 - default y - help - When the bus-off condition is reached, the REC should be reset to 0 and frozen (via LOM) by the - driver's ISR. However on the ESP32, there is an edge case where the REC will increase before the - driver's ISR can respond in time (e.g., due to the rapid occurrence of bus errors), thus causing the - REC to be non-zero after bus-off. A non-zero REC can prevent bus-off recovery as the bus-off recovery - condition is that both TEC and REC become 0. Enabling this option will add a workaround in the driver - to forcibly reset REC to zero on reaching bus-off. - config TWAI_ERRATA_FIX_TX_INTR_LOST bool "Add SW workaround for TX interrupt lost errata" depends on IDF_TARGET_ESP32 diff --git a/components/hal/esp32/include/hal/twai_ll.h b/components/hal/esp32/include/hal/twai_ll.h index 59a0513d7e9..d38a5049ecf 100644 --- a/components/hal/esp32/include/hal/twai_ll.h +++ b/components/hal/esp32/include/hal/twai_ll.h @@ -28,7 +28,13 @@ #include "soc/dport_reg.h" #define TWAI_LL_GET_HW(controller_id) ((controller_id == 0) ? (&TWAI) : NULL) -#define TWAI_LL_BRP_DIV_THRESH 128 + +// When the bus-off condition is reached, the REC should be reset to 0 and frozen (via LOM) by the +// driver's ISR. However on the ESP32, there is an edge case where the REC will increase before the +// driver's ISR can respond in time (e.g., due to the rapid occurrence of bus errors), thus causing the +// REC to be non-zero after bus-off. A non-zero REC can prevent bus-off recovery as the bus-off recovery +// condition is that both TEC and REC become 0. +#define TWAI_LL_HAS_BUSOFF_REC_ISSUE 1 #ifdef __cplusplus extern "C" { @@ -38,6 +44,7 @@ static uint32_t twai_ll_get_brp_max(void); /* ------------------------- Defines and Typedefs --------------------------- */ #define TWAI_LL_BRP_MIN 2 #define TWAI_LL_BRP_MAX twai_ll_get_brp_max() // max brp of esp32 is depends on chip version +#define TWAI_LL_BRP_DIV_THRESH 128 #define TWAI_LL_TSEG1_MIN 1 #define TWAI_LL_TSEG2_MIN 1 #define TWAI_LL_TSEG1_MAX 16 //the max register value diff --git a/components/hal/twai_hal_v1.c b/components/hal/twai_hal_v1.c index e063bdffa93..c8f8a731636 100644 --- a/components/hal/twai_hal_v1.c +++ b/components/hal/twai_hal_v1.c @@ -270,7 +270,7 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx) //Handle low latency events if (events & TWAI_HAL_EVENT_BUS_OFF) { -#ifdef CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC +#if TWAI_LL_HAS_BUSOFF_REC_ISSUE //Errata workaround: Force REC to 0 by re-triggering bus-off (by setting TEC to 0 then 255) twai_ll_set_tec(hal_ctx->dev, 0); twai_ll_set_tec(hal_ctx->dev, 255); From 08de38ae62aee8814e7a5b4746bfe5fc856ef98a Mon Sep 17 00:00:00 2001 From: wanckl Date: Wed, 22 Oct 2025 17:36:59 +0800 Subject: [PATCH 2/6] refactor(driver_twai): remove errata config selection 2 --- components/driver/twai/Kconfig.twai | 17 ++++------------- components/hal/esp32/include/hal/twai_ll.h | 4 ++++ components/hal/twai_hal_v1.c | 3 ++- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/components/driver/twai/Kconfig.twai b/components/driver/twai/Kconfig.twai index 64e60d7c61e..b6de8caa443 100644 --- a/components/driver/twai/Kconfig.twai +++ b/components/driver/twai/Kconfig.twai @@ -7,12 +7,6 @@ menu "Legacy TWAI Driver Configurations" help Place the TWAI ISR in to IRAM to reduce latency and increase performance - config TWAI_SKIP_LEGACY_CONFLICT_CHECK - bool "Skip legacy driver conflict check" - default n - help - This configuration option used to bypass the conflict check mechanism with legacy code. - config TWAI_SUPPRESS_DEPRECATE_WARN bool "Suppress legacy driver deprecated warning" default n @@ -21,14 +15,11 @@ menu "Legacy TWAI Driver Configurations" (driver/twai.h). If you want to continue using the legacy driver, and don't want to see related deprecation warnings, you can enable this option. - config TWAI_ERRATA_FIX_TX_INTR_LOST - bool "Add SW workaround for TX interrupt lost errata" - depends on IDF_TARGET_ESP32 - default y + config TWAI_SKIP_LEGACY_CONFLICT_CHECK + bool "Skip legacy driver conflict check" + default n help - On the ESP32, when a transmit interrupt occurs, and interrupt register is read on the same APB clock - cycle, the transmit interrupt could be lost. Enabling this option will add a workaround that checks the - transmit buffer status bit to recover any lost transmit interrupt. + This configuration option used to bypass the conflict check mechanism with legacy code. config TWAI_ERRATA_FIX_RX_FRAME_INVALID bool "Add SW workaround for invalid RX frame errata" diff --git a/components/hal/esp32/include/hal/twai_ll.h b/components/hal/esp32/include/hal/twai_ll.h index d38a5049ecf..ba5e6556d1c 100644 --- a/components/hal/esp32/include/hal/twai_ll.h +++ b/components/hal/esp32/include/hal/twai_ll.h @@ -36,6 +36,10 @@ // condition is that both TEC and REC become 0. #define TWAI_LL_HAS_BUSOFF_REC_ISSUE 1 +// On the ESP32, when a transmit interrupt occurs, and interrupt register is read on the same APB clock +// cycle, the transmit interrupt could be lost. +#define TWAI_LL_HAS_INTR_LOST_ISSUE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/hal/twai_hal_v1.c b/components/hal/twai_hal_v1.c index c8f8a731636..8f677fb99a0 100644 --- a/components/hal/twai_hal_v1.c +++ b/components/hal/twai_hal_v1.c @@ -231,7 +231,8 @@ static inline uint32_t twai_hal_decode_interrupt(twai_hal_context_t *hal_ctx) TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_RX_BUFF_FRAME); } //Transmit interrupt set whenever TX buffer becomes free -#ifdef CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST +#if TWAI_LL_HAS_INTR_LOST_ISSUE + // Errata workaround: Check the transmit buffer status bit to recover any lost transmit interrupt. if ((interrupts & TWAI_LL_INTR_TI || hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED) && status & TWAI_LL_STATUS_TBS) { #else if (interrupts & TWAI_LL_INTR_TI) { From 425f7f8053b01f6cd0199a24c2341c1dccf1fc24 Mon Sep 17 00:00:00 2001 From: wanckl Date: Wed, 22 Oct 2025 17:51:02 +0800 Subject: [PATCH 3/6] refactor(driver_twai): remove errata config selection 3 --- components/driver/twai/Kconfig.twai | 11 ----------- components/hal/esp32/include/hal/twai_ll.h | 5 +++++ components/hal/esp32c3/include/hal/twai_ll.h | 5 +++++ components/hal/esp32s2/include/hal/twai_ll.h | 5 +++++ components/hal/esp32s3/include/hal/twai_ll.h | 5 +++++ components/hal/twai_hal_v1.c | 10 ++++------ 6 files changed, 24 insertions(+), 17 deletions(-) diff --git a/components/driver/twai/Kconfig.twai b/components/driver/twai/Kconfig.twai index b6de8caa443..6e98a87ef4b 100644 --- a/components/driver/twai/Kconfig.twai +++ b/components/driver/twai/Kconfig.twai @@ -42,15 +42,4 @@ menu "Legacy TWAI Driver Configurations" on detection of this errata condition. Note that if a frame is being sent on the bus during the reset bus during the reset, the message will be lost. - config TWAI_ERRATA_FIX_LISTEN_ONLY_DOM - bool "Add SW workaround for listen only transmits dominant bit errata" - depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3 - default y - help - When in the listen only mode, the TWAI controller must not influence the TWAI bus (i.e., must not send - any dominant bits). However, while in listen only mode on the ESP32/ESP32-S2/ESP32-S3/ESP32-C3, the - TWAI controller will still transmit dominant bits when it detects an error (i.e., as part of an active - error frame). Enabling this option will add a workaround that forces the TWAI controller into an error - passive state on initialization, thus preventing any dominant bits from being sent. - endmenu # TWAI Configuration diff --git a/components/hal/esp32/include/hal/twai_ll.h b/components/hal/esp32/include/hal/twai_ll.h index ba5e6556d1c..2f8d0a75cb3 100644 --- a/components/hal/esp32/include/hal/twai_ll.h +++ b/components/hal/esp32/include/hal/twai_ll.h @@ -40,6 +40,11 @@ // cycle, the transmit interrupt could be lost. #define TWAI_LL_HAS_INTR_LOST_ISSUE 1 +// When in the listen only mode, the TWAI controller must not influence the TWAI bus (i.e., must not send +// any dominant bits). However, while in listen only mode, the TWAI controller will still transmit dominant +// bits when it detects an error (i.e., as part of an active error frame). +#define TWAI_LL_HAS_LOM_DOM_ISSUE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/hal/esp32c3/include/hal/twai_ll.h b/components/hal/esp32c3/include/hal/twai_ll.h index a1a7c3d0596..c1a19c68c2d 100644 --- a/components/hal/esp32c3/include/hal/twai_ll.h +++ b/components/hal/esp32c3/include/hal/twai_ll.h @@ -27,6 +27,11 @@ #define TWAI_LL_GET_HW(controller_id) ((controller_id == 0) ? (&TWAI) : NULL) +// When in the listen only mode, the TWAI controller must not influence the TWAI bus (i.e., must not send +// any dominant bits). However, while in listen only mode, the TWAI controller will still transmit dominant +// bits when it detects an error (i.e., as part of an active error frame). +#define TWAI_LL_HAS_LOM_DOM_ISSUE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/hal/esp32s2/include/hal/twai_ll.h b/components/hal/esp32s2/include/hal/twai_ll.h index a46717c2c52..a224b9523f9 100644 --- a/components/hal/esp32s2/include/hal/twai_ll.h +++ b/components/hal/esp32s2/include/hal/twai_ll.h @@ -27,6 +27,11 @@ #define TWAI_LL_GET_HW(controller_id) ((controller_id == 0) ? (&TWAI) : NULL) +// When in the listen only mode, the TWAI controller must not influence the TWAI bus (i.e., must not send +// any dominant bits). However, while in listen only mode, the TWAI controller will still transmit dominant +// bits when it detects an error (i.e., as part of an active error frame). +#define TWAI_LL_HAS_LOM_DOM_ISSUE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/hal/esp32s3/include/hal/twai_ll.h b/components/hal/esp32s3/include/hal/twai_ll.h index 965f162859e..538a40e1292 100644 --- a/components/hal/esp32s3/include/hal/twai_ll.h +++ b/components/hal/esp32s3/include/hal/twai_ll.h @@ -27,6 +27,11 @@ #define TWAI_LL_GET_HW(controller_id) ((controller_id == 0) ? (&TWAI) : NULL) +// When in the listen only mode, the TWAI controller must not influence the TWAI bus (i.e., must not send +// any dominant bits). However, while in listen only mode, the TWAI controller will still transmit dominant +// bits when it detects an error (i.e., as part of an active error frame). +#define TWAI_LL_HAS_LOM_DOM_ISSUE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/hal/twai_hal_v1.c b/components/hal/twai_hal_v1.c index 8f677fb99a0..3224c2d1bf8 100644 --- a/components/hal/twai_hal_v1.c +++ b/components/hal/twai_hal_v1.c @@ -143,12 +143,10 @@ void twai_hal_start(twai_hal_context_t *hal_ctx) twai_ll_set_mode(hal_ctx->dev, hal_ctx->enable_listen_only, hal_ctx->enable_self_test, hal_ctx->enable_loopback); //Clear the TEC and REC twai_ll_set_tec(hal_ctx->dev, 0); -#ifdef CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM - /* - Errata workaround: Prevent transmission of dominant error frame while in listen only mode by setting REC to 128 - before exiting reset mode. This forces the controller to be error passive (thus only transmits recessive bits). - The TEC/REC remain frozen in listen only mode thus ensuring we remain error passive. - */ +#if TWAI_LL_HAS_LOM_DOM_ISSUE + // Errata workaround: Prevent transmission of dominant error frame while in listen only mode by setting REC to 128 + // before exiting reset mode. This forces the controller to be error passive (thus only transmits recessive bits). + // The TEC/REC remain frozen in listen only mode thus ensuring we remain error passive. if (hal_ctx->enable_listen_only) { twai_ll_set_rec(hal_ctx->dev, 128); } else From 334a0d2747b92e71477dd01e3eab9a47cea39018 Mon Sep 17 00:00:00 2001 From: wanckl Date: Thu, 23 Oct 2025 15:58:26 +0800 Subject: [PATCH 4/6] refactor(driver_twai): remove errata config selection 4 --- components/driver/twai/Kconfig.twai | 10 ---------- components/driver/twai/linker.lf | 2 +- components/driver/twai/twai.c | 5 ++++- components/esp_driver_twai/Kconfig | 2 +- components/hal/esp32/include/hal/twai_ll.h | 4 ++++ components/hal/twai_hal_v1.c | 12 +++++++----- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/components/driver/twai/Kconfig.twai b/components/driver/twai/Kconfig.twai index 6e98a87ef4b..35a535771d4 100644 --- a/components/driver/twai/Kconfig.twai +++ b/components/driver/twai/Kconfig.twai @@ -32,14 +32,4 @@ menu "Legacy TWAI Driver Configurations" the bus whilst the reset is ongoing, the message will not be receive by the peripheral sent on the bus during the reset, the message will be lost. - config TWAI_ERRATA_FIX_RX_FIFO_CORRUPT - bool "Add SW workaround for RX FIFO corruption errata" - depends on IDF_TARGET_ESP32 - default y - help - On the ESP32, when the RX FIFO overruns and the RX message counter maxes out at 64 messages, the entire - RX FIFO is no longer recoverable. Enabling this option will add a workaround that resets the peripheral - on detection of this errata condition. Note that if a frame is being sent on the bus during the reset - bus during the reset, the message will be lost. - endmenu # TWAI Configuration diff --git a/components/driver/twai/linker.lf b/components/driver/twai/linker.lf index 2d0c47b0b95..67b93ecd9c2 100644 --- a/components/driver/twai/linker.lf +++ b/components/driver/twai/linker.lf @@ -23,7 +23,7 @@ entries: twai_hal_v1: twai_hal_check_state_flags (noflash) twai_hal_v1: twai_hal_clear_rx_fifo_overrun (noflash) - if TWAI_ERRATA_FIX_RX_FRAME_INVALID = y || TWAI_ERRATA_FIX_RX_FIFO_CORRUPT = y: + if TWAI_ERRATA_FIX_RX_FRAME_INVALID = y || IDF_TARGET_ESP32 = y: twai_hal_v1: twai_hal_prepare_for_reset (noflash) twai_hal_v1: twai_hal_recover_from_reset (noflash) twai_hal_v1: twai_hal_backup_config (noflash) diff --git a/components/driver/twai/twai.c b/components/driver/twai/twai.c index 5a42e178171..bb47982bb91 100644 --- a/components/driver/twai/twai.c +++ b/components/driver/twai/twai.c @@ -226,8 +226,11 @@ static void twai_intr_handler_main(void *arg) portENTER_CRITICAL_ISR(&p_twai_obj->spinlock); events = twai_hal_get_events(p_twai_obj->hal); //Get the events that triggered the interrupt -#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT) +#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || TWAI_LL_HAS_RX_FIFO_ISSUE + // Errata workaround: Reset the peripheral on detection of this errata condition. + // Note that if a frame is being sent on the bus during the reset, the message will be lost. if (events & TWAI_HAL_EVENT_NEED_PERIPH_RESET) { + ESP_EARLY_LOGD(TWAI_TAG, "Triggered peripheral reset"); twai_hal_prepare_for_reset(p_twai_obj->hal); TWAI_RCC_ATOMIC() { twai_ll_reset_register(p_twai_obj->controller_id); diff --git a/components/esp_driver_twai/Kconfig b/components/esp_driver_twai/Kconfig index e9ace179f15..6b657a8521a 100644 --- a/components/esp_driver_twai/Kconfig +++ b/components/esp_driver_twai/Kconfig @@ -18,7 +18,7 @@ menu "ESP-Driver:TWAI Configurations" config TWAI_ISR_CACHE_SAFE bool "Allow TWAI ISR execute when cache disabled" if !SPI_FLASH_AUTO_SUSPEND select TWAI_ISR_IN_IRAM - select ESP_PERIPH_CTRL_FUNC_IN_IRAM if TWAI_ERRATA_FIX_RX_FRAME_INVALID || TWAI_ERRATA_FIX_RX_FIFO_CORRUPT + select ESP_PERIPH_CTRL_FUNC_IN_IRAM if TWAI_ERRATA_FIX_RX_FRAME_INVALID || IDF_TARGET_ESP32 default n help Allow TWAI works under Cache disabled (such as when writing to SPI Flash), diff --git a/components/hal/esp32/include/hal/twai_ll.h b/components/hal/esp32/include/hal/twai_ll.h index 2f8d0a75cb3..4a3654446b5 100644 --- a/components/hal/esp32/include/hal/twai_ll.h +++ b/components/hal/esp32/include/hal/twai_ll.h @@ -45,6 +45,10 @@ // bits when it detects an error (i.e., as part of an active error frame). #define TWAI_LL_HAS_LOM_DOM_ISSUE 1 +// On the ESP32, when the RX FIFO overruns and the RX message counter maxes out at 64 messages, the entire +// RX FIFO is no longer recoverable. +#define TWAI_LL_HAS_RX_FIFO_ISSUE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/hal/twai_hal_v1.c b/components/hal/twai_hal_v1.c index 3224c2d1bf8..f03016d325e 100644 --- a/components/hal/twai_hal_v1.c +++ b/components/hal/twai_hal_v1.c @@ -7,6 +7,7 @@ #include #include "sdkconfig.h" #include "esp_compiler.h" +#include "hal/log.h" #include "hal/twai_hal.h" #include "hal/twai_ll.h" #include "soc/soc_caps.h" @@ -177,7 +178,7 @@ void twai_hal_start_bus_recovery(twai_hal_context_t *hal_ctx) /* ------------------------------------ IRAM Content ------------------------------------ */ -#ifdef CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT +#if TWAI_LL_HAS_RX_FIFO_ISSUE //Errata condition occurs at 64 messages. Threshold set to 62 to prevent the chance of failing to detect errata condition. #define TWAI_RX_FIFO_CORRUPT_THRESH 62 #endif @@ -300,13 +301,14 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx) if (events & TWAI_HAL_EVENT_ARB_LOST) { twai_ll_clear_arb_lost_cap(hal_ctx->dev); } -#ifdef CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT +#if TWAI_LL_HAS_RX_FIFO_ISSUE //Check for errata condition (rx_msg_count >= corruption_threshold) if (events & TWAI_HAL_EVENT_RX_BUFF_FRAME && twai_ll_get_rx_msg_count(hal_ctx->dev) >= TWAI_RX_FIFO_CORRUPT_THRESH) { TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_NEED_PERIPH_RESET); + HAL_LOGD("TWAI_HAL", "RX FIFO corruption detected"); } #endif -#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT) +#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || TWAI_LL_HAS_RX_FIFO_ISSUE if (events & TWAI_HAL_EVENT_NEED_PERIPH_RESET) { //A peripheral reset will invalidate an RX event; TWAI_HAL_CLEAR_BITS(events, (TWAI_HAL_EVENT_RX_BUFF_FRAME)); @@ -404,7 +406,7 @@ void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_f twai_ll_set_cmd_tx(hal_ctx->dev); } TWAI_HAL_SET_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED); -#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT) +#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || TWAI_LL_HAS_RX_FIFO_ISSUE if (&hal_ctx->errata_ctx->tx_frame_save == tx_frame) { return; } @@ -412,7 +414,7 @@ void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_f ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-overlapping-buffers") // TODO IDF-11085 memcpy(&hal_ctx->errata_ctx->tx_frame_save, tx_frame, sizeof(twai_hal_frame_t)); ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-overlapping-buffers") -#endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT) +#endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || TWAI_LL_HAS_RX_FIFO_ISSUE } uint32_t twai_hal_get_rx_msg_count(twai_hal_context_t *hal_ctx) From 3e361a559f8fc2291f5d62a446f538b44bcdaaf9 Mon Sep 17 00:00:00 2001 From: wanckl Date: Thu, 23 Oct 2025 16:36:58 +0800 Subject: [PATCH 5/6] refactor(driver_twai): remove errata config selection 5 --- components/driver/twai/Kconfig.twai | 11 ----------- components/driver/twai/linker.lf | 2 +- components/driver/twai/twai.c | 2 +- components/esp_driver_twai/Kconfig | 2 +- components/esp_driver_twai/esp_twai_onchip.c | 7 +++++-- components/hal/esp32/include/hal/twai_ll.h | 4 ++++ components/hal/twai_hal_v1.c | 20 +++++++++++--------- 7 files changed, 23 insertions(+), 25 deletions(-) diff --git a/components/driver/twai/Kconfig.twai b/components/driver/twai/Kconfig.twai index 35a535771d4..7ed12e03f17 100644 --- a/components/driver/twai/Kconfig.twai +++ b/components/driver/twai/Kconfig.twai @@ -21,15 +21,4 @@ menu "Legacy TWAI Driver Configurations" help This configuration option used to bypass the conflict check mechanism with legacy code. - config TWAI_ERRATA_FIX_RX_FRAME_INVALID - bool "Add SW workaround for invalid RX frame errata" - depends on IDF_TARGET_ESP32 - default y - help - On the ESP32, when receiving a data or remote frame, if a bus error occurs in the data or CRC field, - the data of the next received frame could be invalid. Enabling this option will add a workaround that - will reset the peripheral on detection of this errata condition. Note that if a frame is transmitted on - the bus whilst the reset is ongoing, the message will not be receive by the peripheral sent on the bus - during the reset, the message will be lost. - endmenu # TWAI Configuration diff --git a/components/driver/twai/linker.lf b/components/driver/twai/linker.lf index 67b93ecd9c2..968506ed339 100644 --- a/components/driver/twai/linker.lf +++ b/components/driver/twai/linker.lf @@ -23,7 +23,7 @@ entries: twai_hal_v1: twai_hal_check_state_flags (noflash) twai_hal_v1: twai_hal_clear_rx_fifo_overrun (noflash) - if TWAI_ERRATA_FIX_RX_FRAME_INVALID = y || IDF_TARGET_ESP32 = y: + if IDF_TARGET_ESP32 = y: #For errata workarounds twai_hal_v1: twai_hal_prepare_for_reset (noflash) twai_hal_v1: twai_hal_recover_from_reset (noflash) twai_hal_v1: twai_hal_backup_config (noflash) diff --git a/components/driver/twai/twai.c b/components/driver/twai/twai.c index bb47982bb91..3b107c7b718 100644 --- a/components/driver/twai/twai.c +++ b/components/driver/twai/twai.c @@ -226,7 +226,7 @@ static void twai_intr_handler_main(void *arg) portENTER_CRITICAL_ISR(&p_twai_obj->spinlock); events = twai_hal_get_events(p_twai_obj->hal); //Get the events that triggered the interrupt -#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || TWAI_LL_HAS_RX_FIFO_ISSUE +#if TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE // Errata workaround: Reset the peripheral on detection of this errata condition. // Note that if a frame is being sent on the bus during the reset, the message will be lost. if (events & TWAI_HAL_EVENT_NEED_PERIPH_RESET) { diff --git a/components/esp_driver_twai/Kconfig b/components/esp_driver_twai/Kconfig index 6b657a8521a..1b979310563 100644 --- a/components/esp_driver_twai/Kconfig +++ b/components/esp_driver_twai/Kconfig @@ -18,7 +18,7 @@ menu "ESP-Driver:TWAI Configurations" config TWAI_ISR_CACHE_SAFE bool "Allow TWAI ISR execute when cache disabled" if !SPI_FLASH_AUTO_SUSPEND select TWAI_ISR_IN_IRAM - select ESP_PERIPH_CTRL_FUNC_IN_IRAM if TWAI_ERRATA_FIX_RX_FRAME_INVALID || IDF_TARGET_ESP32 + select ESP_PERIPH_CTRL_FUNC_IN_IRAM if IDF_TARGET_ESP32 #For errata workarounds default n help Allow TWAI works under Cache disabled (such as when writing to SPI Flash), diff --git a/components/esp_driver_twai/esp_twai_onchip.c b/components/esp_driver_twai/esp_twai_onchip.c index f83b76dc31f..7a8440842ed 100644 --- a/components/esp_driver_twai/esp_twai_onchip.c +++ b/components/esp_driver_twai/esp_twai_onchip.c @@ -201,8 +201,11 @@ static void _node_isr_main(void *arg) twai_onchip_ctx_t *twai_ctx = arg; uint32_t events = twai_hal_get_events(twai_ctx->hal); //Get the events that triggered the interrupt -#if CONFIG_IDF_TARGET_ESP32 // only esp32 have this errata, TODO: IDF-13002 check errata runtime +#if TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE + // Errata workaround: Reset the peripheral on detection of this errata condition. + // Note that if a frame is being sent on the bus during the reset, the message will be lost. if (events & TWAI_HAL_EVENT_NEED_PERIPH_RESET) { + ESP_EARLY_LOGD(TAG, "Triggered peripheral reset"); twai_hal_prepare_for_reset(twai_ctx->hal); TWAI_RCC_ATOMIC() { twai_ll_reset_register(twai_ctx->ctrlr_id); @@ -498,7 +501,7 @@ static esp_err_t _node_disable(twai_node_handle_t node) ESP_RETURN_ON_ERROR(esp_intr_disable(twai_ctx->intr_hdl), TAG, "disable interrupt failed"); atomic_store(&twai_ctx->state, TWAI_ERROR_BUS_OFF); twai_hal_stop(twai_ctx->hal); -#if CONFIG_IDF_TARGET_ESP32 // only esp32 have this errata, TODO: IDF-13002 check errata runtime +#if TWAI_LL_HAS_RX_FRAME_ISSUE // when `disable` happens during hardware busy, the next RX frame is corrupted, a HW reset can fix it if (twai_hal_is_hw_busy(twai_ctx->hal)) { twai_hal_backup_config(twai_ctx->hal); diff --git a/components/hal/esp32/include/hal/twai_ll.h b/components/hal/esp32/include/hal/twai_ll.h index 4a3654446b5..036a8e6c610 100644 --- a/components/hal/esp32/include/hal/twai_ll.h +++ b/components/hal/esp32/include/hal/twai_ll.h @@ -49,6 +49,10 @@ // RX FIFO is no longer recoverable. #define TWAI_LL_HAS_RX_FIFO_ISSUE 1 +// On the ESP32, when receiving a data or remote frame, if a bus error occurs in the data or CRC field, +// the data field of the NEXT received frame could be invalid. +#define TWAI_LL_HAS_RX_FRAME_ISSUE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/hal/twai_hal_v1.c b/components/hal/twai_hal_v1.c index f03016d325e..570db8be366 100644 --- a/components/hal/twai_hal_v1.c +++ b/components/hal/twai_hal_v1.c @@ -17,7 +17,8 @@ #define TWAI_HAL_INIT_REC 0 #define TWAI_HAL_INIT_EWL 96 -#if CONFIG_IDF_TARGET_ESP32 // only esp32 have this errata, TODO: IDF-13002 check errata runtime +#if TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE +// context for errata workarounds typedef struct twai_hal_errata_ctx_t { twai_hal_frame_t tx_frame_save; twai_ll_reg_save_t reg_save; @@ -26,7 +27,7 @@ typedef struct twai_hal_errata_ctx_t { #endif size_t twai_hal_get_mem_requirment(void) { -#if CONFIG_IDF_TARGET_ESP32 // only esp32 have this errata, TODO: IDF-13002 check errata runtime +#if TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE return sizeof(twai_hal_context_t) + sizeof(twai_hal_errata_ctx_t); #else return sizeof(twai_hal_context_t); @@ -49,7 +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; } -#if CONFIG_IDF_TARGET_ESP32 // only esp32 have this errata, TODO: IDF-13002 check errata runtime +#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 #if SOC_TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT @@ -289,12 +290,13 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx) .ack_err = (type == TWAI_LL_ERR_OTHER) && (seg == TWAI_LL_ERR_SEG_ACK_SLOT), }; hal_ctx->errors = errors; -#ifdef CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID +#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 && ((seg == TWAI_LL_ERR_SEG_DATA || seg == TWAI_LL_ERR_SEG_CRC_SEQ) || (seg == TWAI_LL_ERR_SEG_ACK_DELIM && type == TWAI_LL_ERR_OTHER))) { TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_NEED_PERIPH_RESET); + HAL_LOGD("TWAI_HAL", "RX frame invalid detected"); } #endif } @@ -308,7 +310,7 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx) HAL_LOGD("TWAI_HAL", "RX FIFO corruption detected"); } #endif -#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || TWAI_LL_HAS_RX_FIFO_ISSUE +#if TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE if (events & TWAI_HAL_EVENT_NEED_PERIPH_RESET) { //A peripheral reset will invalidate an RX event; TWAI_HAL_CLEAR_BITS(events, (TWAI_HAL_EVENT_RX_BUFF_FRAME)); @@ -317,7 +319,7 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx) return events; } -#if CONFIG_IDF_TARGET_ESP32 // only esp32 have this errata, TODO: IDF-13002 check errata runtime +#if TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE bool twai_hal_is_hw_busy(twai_hal_context_t *hal_ctx) { return (TWAI_LL_STATUS_TS | TWAI_LL_STATUS_RS) & twai_ll_get_status(hal_ctx->dev); @@ -366,7 +368,7 @@ void twai_hal_recover_from_reset(twai_hal_context_t *hal_ctx) TWAI_HAL_CLEAR_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_NEED_RETRY); } } -#endif // CONFIG_IDF_TARGET_ESP32 +#endif // TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE void twai_hal_format_frame(const twai_hal_trans_desc_t *trans_desc, twai_hal_frame_t *frame) { @@ -406,7 +408,7 @@ void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_f twai_ll_set_cmd_tx(hal_ctx->dev); } TWAI_HAL_SET_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED); -#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || TWAI_LL_HAS_RX_FIFO_ISSUE +#if TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE if (&hal_ctx->errata_ctx->tx_frame_save == tx_frame) { return; } @@ -414,7 +416,7 @@ void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_f ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-overlapping-buffers") // TODO IDF-11085 memcpy(&hal_ctx->errata_ctx->tx_frame_save, tx_frame, sizeof(twai_hal_frame_t)); ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-overlapping-buffers") -#endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || TWAI_LL_HAS_RX_FIFO_ISSUE +#endif //TWAI_LL_HAS_RX_FRAME_ISSUE || TWAI_LL_HAS_RX_FIFO_ISSUE } uint32_t twai_hal_get_rx_msg_count(twai_hal_context_t *hal_ctx) From 9176ef32a40bbe83d24a9492190e2cc51316a3ff Mon Sep 17 00:00:00 2001 From: wanckl Date: Thu, 23 Oct 2025 19:21:49 +0800 Subject: [PATCH 6/6] refactor(driver_twai): using hal/config in hal layer --- components/hal/include/hal/twai_types_deprecated.h | 8 ++++---- components/hal/twai_hal_v1.c | 1 - tools/ci/sg_rules/no_kconfig_in_hal_component.yml | 7 ------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/components/hal/include/hal/twai_types_deprecated.h b/components/hal/include/hal/twai_types_deprecated.h index 3dfe57d5225..1752c786665 100644 --- a/components/hal/include/hal/twai_types_deprecated.h +++ b/components/hal/include/hal/twai_types_deprecated.h @@ -8,9 +8,9 @@ #include #include -#include "sdkconfig.h" #include "soc/soc_caps.h" #include "soc/clk_tree_defs.h" +#include "hal/config.h" #ifdef __cplusplus extern "C" { @@ -56,11 +56,11 @@ extern "C" { #define TWAI_TIMING_CONFIG_10KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 200000, .brp = 0, .prop_seg = 0, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} #endif // SOC_TWAI_BRP_MAX > 256 -#if (SOC_TWAI_BRP_MAX > 128) || (CONFIG_ESP32_REV_MIN_FULL >= 200) +#if (SOC_TWAI_BRP_MAX > 128) || (SOC_IS(ESP32) && (HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 200)) #define TWAI_TIMING_CONFIG_12_5KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 312500, .brp = 0, .prop_seg = 0, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} #define TWAI_TIMING_CONFIG_16KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 400000, .brp = 0, .prop_seg = 0, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} #define TWAI_TIMING_CONFIG_20KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 400000, .brp = 0, .prop_seg = 0, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} -#endif // (SOC_TWAI_BRP_MAX > 128) || (CONFIG_ESP32_REV_MIN_FULL >= 200) +#endif #if SOC_TWAI_CLK_SUPPORT_XTAL #define TWAI_TIMING_CONFIG_25KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 500000, .brp = 0, .prop_seg = 0, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} @@ -71,7 +71,7 @@ extern "C" { #define TWAI_TIMING_CONFIG_100KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 2000000, .brp = 0, .prop_seg = 0, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} #define TWAI_TIMING_CONFIG_125KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 2000000, .brp = 0, .prop_seg = 0, .tseg_1 = 11, .tseg_2 = 4, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} #define TWAI_TIMING_CONFIG_250KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 4000000, .brp = 0, .prop_seg = 0, .tseg_1 = 11, .tseg_2 = 4, .sjw = 2, .ssp_offset = 0, .triple_sampling = false} -#if SOC_TWAI_CLK_SUPPORT_XTAL && CONFIG_XTAL_FREQ == 40 // TWAI_CLK_SRC_XTAL = 40M +#if SOC_TWAI_CLK_SUPPORT_XTAL && HAL_CONFIG(XTAL_HINT_FREQ_MHZ) == 40 // TWAI_CLK_SRC_XTAL = 40M #define TWAI_TIMING_CONFIG_500KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 10000000, .brp = 0, .prop_seg = 0, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} #define TWAI_TIMING_CONFIG_800KBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 20000000, .brp = 0, .prop_seg = 0, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} #define TWAI_TIMING_CONFIG_1MBITS() {.clk_src = TWAI_CLK_SRC_DEFAULT, .quanta_resolution_hz = 20000000, .brp = 0, .prop_seg = 0, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .ssp_offset = 0, .triple_sampling = false} diff --git a/components/hal/twai_hal_v1.c b/components/hal/twai_hal_v1.c index 570db8be366..a3590816eb9 100644 --- a/components/hal/twai_hal_v1.c +++ b/components/hal/twai_hal_v1.c @@ -5,7 +5,6 @@ */ #include -#include "sdkconfig.h" #include "esp_compiler.h" #include "hal/log.h" #include "hal/twai_hal.h" diff --git a/tools/ci/sg_rules/no_kconfig_in_hal_component.yml b/tools/ci/sg_rules/no_kconfig_in_hal_component.yml index b505efbf435..87ed8167825 100644 --- a/tools/ci/sg_rules/no_kconfig_in_hal_component.yml +++ b/tools/ci/sg_rules/no_kconfig_in_hal_component.yml @@ -12,10 +12,6 @@ ignores: - "components/hal/platform_port/**/*" - "components/hal/test_apps/**/*" - "components/esp_hal*/test_apps/**/*" - # the following files should be refactored to remove Kconfig macros - - "components/hal/twai_hal_v1.c" - - "components/hal/esp32/include/hal/twai_ll.h" - - "components/hal/include/hal/twai_types_deprecated.h" rule: any: - kind: argument_list @@ -47,9 +43,6 @@ ignores: - "components/hal/platform_port/**/*" - "components/hal/test_apps/**/*" - "components/esp_hal*/test_apps/**/*" - # the following files should be refactored to remove sdkconfig.h - - "components/hal/twai_hal_v1.c" - - "components/hal/include/hal/twai_types_deprecated.h" rule: kind: preproc_include has: