esp-idf: ESP32-S2:TWAI RX does not work (IDFGH-3670)

Environment

  • Development Kit: ESP32-S2
  • Kit version (for WroverKit/PicoKit/DevKitC): [v1|v2|v3|v4]
  • Module or chip used: WROVER
  • IDF version (run git describe --tags to find it): master (latest)
  • Build System: CMake
  • Compiler version (run xtensa-esp32-elf-gcc --version to find it): 8.2.0r2
  • Operating System: Linux
  • Using an IDE?: No
  • Power Supply: USB (or external 5v or 3v3)

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

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 34 (1 by maintainers)

Most upvoted comments

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;
}`

@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

  • Closed on master by commits 874a720286b78e866684129ce18a6c948c8fa7fe, C++ fix 14fe6dcaaf6d1bb9a1d1bb1d0e51a8fd184101e7
  • Closed on v4.3 by commit 29accf2533fa7f1c0ed8d3d60d93e80bbbb04202

@atanisoft MR for v4.3 backport is current review

@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;                                     \
})

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

@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.