espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.45k stars 7.25k forks source link

ESP32-S2:TWAI RX does not work (IDFGH-3670) #5604

Closed atanisoft closed 2 years ago

atanisoft commented 4 years ago

Environment

Problem Description

The TWAI driver does not trigger RX events when running at 125kbps (pins rx: 36, tx: 37) with accept all filter.

Expected Behavior

Actual Behavior

Steps to reproduce

After fixing https://github.com/espressif/esp-idf/issues/5603 mappings (minimum needed for my old code):

-#include "hal/can_types.h"
+#include "hal/twai_types.h"
...
+#define CAN_TIMING_CONFIG_125KBITS      TWAI_TIMING_CONFIG_125KBITS
+#define CAN_FILTER_CONFIG_ACCEPT_ALL    TWAI_FILTER_CONFIG_ACCEPT_ALL
+
+#define CAN_MODE_NORMAL                 TWAI_MODE_NORMAL
+#define CAN_MSG_FLAG_NONE               TWAI_MSG_FLAG_NONE
+#define CAN_MSG_FLAG_EXTD               TWAI_MSG_FLAG_EXTD
+#define CAN_MSG_FLAG_RTR                TWAI_MSG_FLAG_RTR
+#define CAN_MSG_FLAG_DLC_NON_COMP       TWAI_MSG_FLAG_DLC_NON_COMP
+
+typedef twai_timing_config_t            can_timing_config_t;
+typedef twai_filter_config_t            can_filter_config_t;
+typedef twai_message_t can_message_t;

I was able to compile my old code (https://github.com/openmrn/OpenMRNLite/tree/master/examples/ESP32IOBoard). I can see the frames being transmitted by the S2 to the other devices on the network but the S2 never raises an RX event.

I added

#include "soc_log.h"
SOC_LOGE("TWAI-HAL", "%04x, %04x, %d:%d\n", interrupts, status, tec, rec);

to https://github.com/espressif/esp-idf/blob/master/components/soc/src/hal/twai_hal.c#L91 in order to confirm the RX event was never raised:

[ESP-TWAI] sending frame
E (2070) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
E (2076) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
[ESP-TWAI] sending frame
E (2085) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
Allocating new alias 849 for node 050201030000
[ESP-TWAI] sending frame
E (2287) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
[ESP-TWAI] sending frame
E (2290) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
[ESP-TWAI] sending frame
E (2299) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
[ESP-TWAI] sending frame
E (2308) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
[ESP-TWAI] sending frame
E (2317) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
E (2323) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
[ESP-TWAI] sending frame
E (2332) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
[ESP-TWAI] sending frame
E (2533) TWAI-HAL: 0002, 002c, 0:0

ESP-TWAI: 0400
ESP-TWAI: TX SUCCESS
atanisoft commented 4 years ago

@Dazza0 I've rewritten my code to directly leverage the new TWAI APIs. Unfortunately, I still see the same problem with RX not firing. I added an LM358 to the TX and RX pins to visually indicate activity and I can see there is activity on both TX and RX now but the RX event doesn't appear to be firing. Any updates or things I can try to help resolve this?

atanisoft commented 4 years ago

@Dazza0 I've tested the TWAI code I linked to above on the ESP32 on latest IDF master with no issues. I'm at a loss as to what is missing on the ESP32-S2 side.

For both the ESP32 and ESP32-S2 I've used SN65HVD230 with this circuit to visualize the TX/RX activity:alt text

It appears that even though the frames are visually confirmed as being sent by the SN65HVD230 to the ESP32-S2 it would appear the ESP32-S2 is not processing them.

Dazza0 commented 4 years ago

@atanisoft I've just tested the ESP32-S2 by porting over the can.h and can_types.h and haven't been able to recreate this issue. Could you share a snippet of your mapping header file and also you application code?

atanisoft commented 4 years ago

@Dazza0 let me share a private repo with you that contains a version of it and instructions on how to test it with that code. I haven't been able to receive with the code using only the new TWAI API on the S2 but it works on the esp32.

atanisoft commented 4 years ago

@Dazza0 you should have received an invite to the repo and I've added some notes in the readme which explain how to connect the ESP32-S2 and what sort of data to send to it (very basic frames really)

Dazza0 commented 4 years ago

@atanisoft The invite I received doesn't seem to work.

atanisoft commented 4 years ago

@Dazza0 if you can send me an email I'll send you a zip file if the project.

Is it possibly an issue with using pins 41 (rx), 42 (tx)? I have no issues with tx but rx doesn't seem to be firing even though the transceiver shows activity on rx.

atanisoft commented 4 years ago

@Dazza0 I tested using the arduino-esp32 esp32s2 branch (uses v4.3-dev-907-g6c17e3a64-dirty) and it somewhat works. I'll be digging through the diffs further.

atanisoft commented 3 years ago

latest code seems to work correctly...

atanisoft commented 3 years ago

@Dazza0 I'm circling back to this with the latest IDF v4.4 (master cf457d412) and I'm seeing consistent failure with my S2 Saola WROVER:

09:12:34.212 -> ESP-ROM:esp32s2-rc4-20191025
09:12:34.212 -> Build:Oct 25 2019
09:12:34.212 -> rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
09:12:34.212 -> SPIWP:0xee
09:12:34.212 -> mode:DIO, clock div:1
09:12:34.245 -> load:0x3ffe6100,len:0x4b0
09:12:34.245 -> load:0x4004c000,len:0xa6c
09:12:34.245 -> load:0x40050000,len:0x25c0
09:12:34.245 -> entry 0x4004c198
09:12:34.576 -> [SoC] reset reason:1 - power on reset
09:12:34.576 -> [SoC] model:ESP32-S2,rev:0,cores:1,flash:No,WiFi:Yes,BLE:No,BT:No
09:12:34.576 -> [SoC] Heap: 207.92kB / 281.12Kb
09:12:34.576 -> [SoC] PSRAM: 2045.63kB / 2048.00Kb
09:12:34.576 -> [SoC] App running from: app0

As you can see it is an early rev0 board, I'm wondering if possibly this specific board has a broken TWAI peripheral? It works fine for TX but never for RX.

brice-fr commented 3 years ago

I have apparently the same issue here. My (simple example) Rx /Tx code is working well on a ESP32, but when compiled for ESP32-s2 (in arduino-esp32-2.0.2rc1, based on esp-idf4..4) , only TX is working and no RX event is firing... The acceptance filter is supposed to be configured for letting all frames in. On the same board a circuitpython script is able to both receive and transmit so I am pretty sure it is not the HW (furthermore, frames from the other node are acknowledged and no error is raised on transmission, which means the twai controller is properly seeing what happens on the bus)
@atanisoft have you solved your issue ?

atanisoft commented 3 years ago

@brice-fr I have not found a workable solution as of now, I'm using IDF v4.3 release branch for esp32, esp32-c3 and esp32-s2. The code works on all three for TX but RX doesn't seem to ever trigger on the esp32-s2.

Since you have seen circuit python working for this, it would be good to see the diff of what is being used there compared to IDF. It could be a bug in the HAL-LL code for the esp32-s2.

brice-fr commented 3 years ago

@atanisoft there is indeed some hint in the adafruit canio/twai driver https://github.com/adafruit/circuitpython/blob/main/ports/esp32s2/common-hal/canio/Listener.c#L47

It is pointing to this issue : https://github.com/espressif/esp-idf/issues/6020 (thanks to @jepler for pointing this in the first time)

I can not recompile easily the esp-idf library that is used in esp32-arduino but I have somehow duplicated the twai driver in my project and just adding "attribute((optimize("O0")))" in the prototype of the filter setting function in twai_ll.h actually allows to solve this issue:

static inline void __attribute__((optimize("O0"))) twaie_ll_set_acc_filter(twaie_dev_t* hw, uint32_t code, uint32_t mask, bool single_filter)
{
    uint32_t code_swapped = HAL_SWAP32(code);
    uint32_t mask_swapped = HAL_SWAP32(mask);
    for (int i = 0; i < 4; i++) {
        hw->acceptance_filter.acr[i].byte = ((code_swapped >> (i * 8)) & 0xFF);
        hw->acceptance_filter.amr[i].byte = ((mask_swapped >> (i * 8)) & 0xFF);
    }
    hw->mode_reg.afm = single_filter;
}

Reworking the struct as @Dazza0 planned might also do the trick but meanwhile this solution seems the most easy and effective

atanisoft commented 3 years ago

@brice-fr wow, such a simple fix possibly. I'll give it a test with my hardware setup and if it works can submit a PR for @Dazza0 to review.

brice-fr commented 3 years ago

Most probably replacing the ".byte" (x2) by ".val“ would have also worked as this is what is done with the TX buffers. Gone to work right now but I can try that this evening...

[edit] ... and I can confirm this version also works:

`static inline void twaie_ll_set_acc_filter(twaie_dev_t* hw, uint32_t code, uint32_t mask, bool single_filter)
{
    uint32_t code_swapped = HAL_SWAP32(code);
    uint32_t mask_swapped = HAL_SWAP32(mask);
    for (int i = 0; i < 4; i++) {
        hw->acceptance_filter.acr[i].val = ((code_swapped >> (i * 8)) & 0xFF);
        hw->acceptance_filter.amr[i].val = ((mask_swapped >> (i * 8)) & 0xFF);
    }
    hw->mode_reg.afm = single_filter;
}`
atanisoft commented 3 years ago

@brice-fr I'm seeing some other issues with the patched method. But I do see the RX ISR event firing so that is some progress. I suspect it may be a few other 8-bit accesses causing the issues.

EmilyNerdGirl commented 3 years ago

Just ran into this myself and was stumped why the identical code on an ESP32 failed on an ESP32-S2 for receive. Googling online there were others with the same problem that eventually led me here. I haven't been able to get my own twai driver working for some reason as brice-fr was. Hopefully this is figured out soon as in the Espressif Arduino forum, they were asking for feedback on bugs as looking to release 2.0.0

Dazza0 commented 3 years ago

PTAL at commit 2e0ffbd543abc0226f0dbd2f725eb891235abe02. The commit should prevent s8 access on all peripherals.

jepler commented 3 years ago

Thank you!

atanisoft commented 3 years ago

@Dazza0 Seeing some issues with the updates when used in C++ code:

esp-idf-master/components/hal/platform_port/include/hal/misc.h:35:18: error: ambiguous overload for 'operator=' (operand types are 'volatile twai_dev_s::<unnamed union>' and 'volatile twai_dev_s::<unnamed union>')
     (base_reg) = temp_reg;                                  \
                  ^~~~~~~~
esp-idf-master/components/hal/esp32s2/include/hal/twai_ll.h:663:9: note: in expansion of macro 'HAL_FORCE_MODIFY_U32_REG_FIELD'
         HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider_reg, cd, 0);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from esp-idf-master/components/soc/include/soc/twai_periph.h:24,
                 from esp-idf-master/components/hal/esp32s2/include/hal/twai_ll.h:33,
                 from esp-idf-master/components/hal/include/hal/twai_hal.h:31,
                 from ../components/OpenMRNIDF/src/freertos_drivers/esp32/Esp32HardwareTwai.cpp:64:
esp-idf-master/components/soc/esp32s2/include/soc/twai_struct.h:198:11: note: candidate: 'constexpr twai_dev_s::<unnamed union>& twai_dev_s::<unnamed union>::operator=(const twai_dev_s::<unnamed union>&)' <near match>
     union {
           ^
esp-idf-master/components/soc/esp32s2/include/soc/twai_struct.h:198:11: note:   conversion of argument 1 would be ill-formed:
In file included from esp-idf-master/components/hal/esp32s2/include/hal/twai_ll.h:31,
                 from esp-idf-master/components/hal/include/hal/twai_hal.h:31,
                 from ../components/OpenMRNIDF/src/freertos_drivers/esp32/Esp32HardwareTwai.cpp:64:
esp-idf-master/components/hal/platform_port/include/hal/misc.h:35:18: error: binding reference of type 'const twai_dev_s::<unnamed union>&' to 'volatile twai_dev_s::<unnamed union>' discards qualifiers
     (base_reg) = temp_reg;                                  \
                  ^~~~~~~~
esp-idf-master/components/hal/esp32s2/include/hal/twai_ll.h:663:9: note: in expansion of macro 'HAL_FORCE_MODIFY_U32_REG_FIELD'
         HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider_reg, cd, 0);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Any ideas? Esp32HardwareTwai.cpp can be found here. I'm not using driver/twai.c due to overriding the ISR and exposing as a VFS.

EDIT: This is seen for ESP32-C3 and ESP32 as well.

atanisoft commented 3 years ago

@Dazza0 A simpler example of the failure is likely as simple as:

main.cpp

#include <hal/twai_hal.h>

extern "C" void app_main() {}

Likely other HAL header files would reproduce this as well since the new macros are used quite extensively.

This seems to be a behavior difference of C vs C++ related to the typeof operator.

Dazza0 commented 3 years ago

@atanisoft Seems like there are two separate issues when C++ tries to use the macros provided in hal/misc.h

  1. Using typeof() on a union{} register somehow discards its volatile qualifier. Not sure why.
  2. Attempting to assign one register to another val typeof(base_reg) temp_reg = (base_reg); will invoke a non-existent copy constructor.

Try replacing the macros in hal/misc.h with the following and see if the issues is resolved

#define HAL_FORCE_MODIFY_U32_REG_FIELD(base_reg, reg_field, field_val)    \
{                                                           \
    uint32_t temp_val = base_reg.val;                       \
    typeof(base_reg) temp_reg;                              \
    temp_reg.val = temp_val;                                \
    temp_reg.reg_field = (field_val);                       \
    (base_reg).val = temp_reg.val;                          \
}

#define HAL_FORCE_READ_U32_REG_FIELD(base_reg, reg_field) ({    \
    uint32_t temp_val = base_reg.val;                       \
    typeof(base_reg) temp_reg;                              \
    temp_reg.val = temp_val;                                \
    temp_reg.reg_field;                                     \
})
atanisoft commented 3 years ago

@Dazza0 Compilation seems to be successful with the updated macros, will test with this on: ESP32, ESP32-S2, ESP32-C3 and report back.

atanisoft commented 3 years ago

@Dazza0 I've confirmed that using the above macros the linked Esp32HardwareTwai.cpp code works for the ESP32-S2. I'll continue testing over the weekend but so far it looks good.

atanisoft commented 3 years ago

@Dazza0 Can this HAL fix be backported to IDF v4.3?

Dazza0 commented 3 years ago

@atanisoft Technically this will need to be back-ported all the way back to v4.2 since this was the first version where ESP32-S2 was supported, so v4.3 should also have this backport. But I want to double check if this bug is present in all of our compiler versions (given that the source of this bug is due to the -fstrict-volatile-bitfields not working).

atanisoft commented 3 years ago

I can confirm it is broken in v4.3 at least, which also uses the same gcc as master is today.

atanisoft commented 3 years ago

@Dazza0 Any timeline for the fix being backported to IDF v4.3?

Dazza0 commented 3 years ago

@atanisoft MR for v4.3 backport is current review

Dazza0 commented 2 years ago
atanisoft commented 2 years ago

Thanks @Dazza0 I'll run it through validations in a bit

Kunaalkk1 commented 1 year ago

@Dazza0, I am also facing the Rx issue with ESP32 (ESP-WROOM-32) while Tx is working perfectly. I am using the MCP2515 module as my CAN transceiver.

I tried ESP-IDF v5 as well as v4.4.4, neither of which seem to work.

I saw a YouTube video with someone who used a similar code, and it was working perfectly for him (YouTube Video: link: https://youtu.be/bxzWuIqfn9Y).

This is my code:

#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "stdio.h"
#include "stdlib.h"
#include "driver/twai.h"

void twai_setup_and_install(){
    //Initialize configuration structures using macro initializers
    twai_general_config_t g_config = {
        .mode = TWAI_MODE_NORMAL,
        .tx_io = GPIO_NUM_5,
        .rx_io = GPIO_NUM_4,
        .clkout_io = TWAI_IO_UNUSED,
        .bus_off_io = TWAI_IO_UNUSED,
        .tx_queue_len = 5,
        .rx_queue_len = 5,
        .alerts_enabled = TWAI_ALERT_NONE,
        .clkout_divider = 0
    };

    twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
    twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

    // Install TWAI driver
    if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
        printf("Driver installed\n");
    } else {
        printf("Failed to install driver\n");
        return;
    }

    // Start TWAI driver
    if (twai_start() == ESP_OK) {
        printf("Driver started\n");
    } else {
        printf("Failed to start driver\n");
        return;
    }
}

void new_message(twai_message_t *message, uint32_t id, uint8_t dlc, uint8_t *data)
{

    message->flags = TWAI_MSG_FLAG_NONE;
    message->identifier = id;
    message->data_length_code = dlc;
    for (int i = 0; i < dlc; i++) {
        message->data[i] = data[i];
    }
    printf("Message created\nID: %ld DLC: %d Data:\t", message->identifier, message->data_length_code);
    for (int i = 0; i < message->data_length_code; i++) {
        printf("%d\t", message->data[i]);
    }
    printf("\n");
}

void transmit_message(twai_message_t *message)
{
    if (twai_transmit(message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        printf("Message queued for transmission\n");
    } else {
        printf("Failed to send message\n");
    }
}

void receive_message(twai_message_t *message)
{
    if (twai_receive(message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        printf("Message received:\n");
        printf("ID: %ld DLC: %d Data:\t", message->identifier, message->data_length_code);
        for (int i = 0; i < message->data_length_code; i++) {
            (message->extd)?printf("Extended ID"):printf("Standard ID");
            printf("%d\t", message->data[i]);
        }
    } else {
        printf("Failed to receive message\n");
    }
}

void app_main()
{

    twai_setup_and_install();
    twai_message_t message;
    twai_message_t message1;
    // Set the data to send
    uint8_t data[8] = {rand() % 255, rand() % 255, rand() % 255, 
    rand() % 255, rand() % 255, rand() % 255, rand() % 255, rand() % 255};

    while(true){ 
    // Create a new message
    new_message(&message, 0x123, 8, data);

    // Transmit the message to a queue
    transmit_message(&message);

    // Receive the message from the queue
    receive_message(&message1);

    // Wait for 1 second
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    }

}

@brice-fr @eloebl @atanisoft @jepler

If anyone can help me, it would be really appreciated!

Regards,

Awaiting reply ASAP

MrLeafster commented 1 year ago

@Dazza0, I am also facing the Rx issue with ESP32 (ESP-WROOM-32) while Tx is working perfectly. I am using the MCP2515 module as my CAN transceiver.

I tried ESP-IDF v5 as well as v4.4.4, neither of which seem to work.

I saw a YouTube video with someone who used a similar code, and it was working perfectly for him (YouTube Video: link: https://youtu.be/bxzWuIqfn9Y).

This is my code:

#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "stdio.h"
#include "stdlib.h"
#include "driver/twai.h"

void twai_setup_and_install(){
    //Initialize configuration structures using macro initializers
    twai_general_config_t g_config = {
        .mode = TWAI_MODE_NORMAL,
        .tx_io = GPIO_NUM_5,
        .rx_io = GPIO_NUM_4,
        .clkout_io = TWAI_IO_UNUSED,
        .bus_off_io = TWAI_IO_UNUSED,
        .tx_queue_len = 5,
        .rx_queue_len = 5,
        .alerts_enabled = TWAI_ALERT_NONE,
        .clkout_divider = 0
    };

    twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
    twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

    // Install TWAI driver
    if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
        printf("Driver installed\n");
    } else {
        printf("Failed to install driver\n");
        return;
    }

    // Start TWAI driver
    if (twai_start() == ESP_OK) {
        printf("Driver started\n");
    } else {
        printf("Failed to start driver\n");
        return;
    }
}

void new_message(twai_message_t *message, uint32_t id, uint8_t dlc, uint8_t *data)
{

    message->flags = TWAI_MSG_FLAG_NONE;
    message->identifier = id;
    message->data_length_code = dlc;
    for (int i = 0; i < dlc; i++) {
        message->data[i] = data[i];
    }
    printf("Message created\nID: %ld DLC: %d Data:\t", message->identifier, message->data_length_code);
    for (int i = 0; i < message->data_length_code; i++) {
        printf("%d\t", message->data[i]);
    }
    printf("\n");
}

void transmit_message(twai_message_t *message)
{
    if (twai_transmit(message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        printf("Message queued for transmission\n");
    } else {
        printf("Failed to send message\n");
    }
}

void receive_message(twai_message_t *message)
{
    if (twai_receive(message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        printf("Message received:\n");
        printf("ID: %ld DLC: %d Data:\t", message->identifier, message->data_length_code);
        for (int i = 0; i < message->data_length_code; i++) {
            (message->extd)?printf("Extended ID"):printf("Standard ID");
            printf("%d\t", message->data[i]);
        }
    } else {
        printf("Failed to receive message\n");
    }
}

void app_main()
{

    twai_setup_and_install();
    twai_message_t message;
    twai_message_t message1;
    // Set the data to send
    uint8_t data[8] = {rand() % 255, rand() % 255, rand() % 255, 
    rand() % 255, rand() % 255, rand() % 255, rand() % 255, rand() % 255};

    while(true){ 
    // Create a new message
    new_message(&message, 0x123, 8, data);

    // Transmit the message to a queue
    transmit_message(&message);

    // Receive the message from the queue
    receive_message(&message1);

    // Wait for 1 second
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    }

}

@brice-fr @eloebl @atanisoft @jepler

If anyone can help me, it would be really appreciated!

Regards,

Awaiting reply ASAP

@Kunaalkk1 Hi, I'm currently working with the same board and the same code, but it also doesn't work... have you figured it out in the meantime?

devilreraser commented 10 months ago

Just Recover from BUS OFF state - here is example

void drv_can_check_bus_off_and_recover(void) { twai_status_info_t status_info; esp_err_t twai_err = twai_get_status_info(&status_info);

if(twai_err == ESP_OK)
{
    ESP_LOGI(TAG, "twai_status : %s", 
        (status_info.state == TWAI_STATE_STOPPED)? "TWAI_STATE_STOPPED" :
        (status_info.state == TWAI_STATE_RUNNING)? "TWAI_STATE_RUNNING" :
        (status_info.state == TWAI_STATE_BUS_OFF)? "TWAI_STATE_BUS_OFF" :
        (status_info.state == TWAI_STATE_RECOVERING)? "TWAI_STATE_RECOVERING" : "TWAI_STATE_UNKNOWN"

    );
    if (status_info.state == TWAI_STATE_BUS_OFF)
    {
        if(twai_initiate_recovery() == ESP_OK)  
        {
            ESP_LOGW(TAG, "twai_initiate_recovery"); 
        } 
        else
        {
            ESP_LOGE(TAG, "twai_initiate_recovery failure"); 
        }
    } 
    else
    if (status_info.state == TWAI_STATE_STOPPED)
    {
        if(twai_start() == ESP_OK)  
        {
            ESP_LOGW(TAG, "twai_start"); 
        } 
        else
        {
            ESP_LOGE(TAG, "twai_start failure"); 
        }
    } 
}

}