Probleme TWAI-Treiber ArduinoNanoESP32

Environment

  • Development Kit: Arduino Nano ESP32
  • Kit version (for WiKi): Not applicable
  • Module or chip used: ESP32-S3-MINI-1-N8
  • IDF version (run git describe --tags to find it):
    • Arduino-ESP32 Core: v2.0.18-arduino.5
    • ESP-IDF: v4.4.7-dirty
  • Build System: Arduino IDE 2.x
  • Compiler version (run xtensa-esp32-elf-gcc --version to find it): xtensa-esp32s3-elf-gcc 2021r2-p5
  • Operating System: Windows
  • Using an IDE: Arduino IDE / PlatformIO
  • Power Supply: USB

Problem Description

The TWAI (CAN) driver on ESP32-S3 reports successful message transmission (ESP_OK) but messages are not physically transmitted on the CAN bus. The twai_transmit() function completes in 0 milliseconds, which is physically impossible for actual CAN transmission at 500 kbit/s (should take 5-50ms).

This issue has been tested extensively with:

  • Two different Arduino Nano ESP32 boards (both ESP32-S3)
  • Multiple SN65HVD230D CAN transceivers
  • Different GPIO pin combinations
  • Various baudrates (500k, 125k, 25k)
  • Both NORMAL and NO_ACK modes
  • Multiple TWAI libraries (native API, ESP32-TWAI-CAN, arduino-CAN)

The result is always the same: 0ms transmission time = no physical output.


Expected Behavior

When calling twai_transmit() with a valid CAN message:

  1. Function should take 5-50ms to complete (depending on baudrate and bus arbitration)
  2. CAN message should be physically transmitted on CAN_H/CAN_L differential lines
  3. A second ESP32 board (receiver) should receive the message
  4. Multiple consecutive transmissions should work reliably

Actual Behavior

Observed with NORMAL Mode (2 boards connected):

[0] TX... OK (1ms)     ← First message appears to work
[1] TX... OK (0ms)     ← 0ms = NOT physically sent!
[2] TX... OK (0ms)
[3] TX... OK (0ms)
[4] TX... OK (0ms)
[5] TX... OK (0ms)
[6] TX... ERROR 263 (2000ms)  ← ESP_ERR_TIMEOUT
[7] TX... ERROR 263 (2000ms)

Receiver board: No messages received (0 messages)

Observed with NO_ACK Mode (single board loopback):

[0] OK (32 µs)
[1] OK (7 µs)
[2-15] OK (7-11 µs)    ← Works for ~15 messages
[16] ERROR 259 (3 µs)  ← ESP_ERR_INVALID_STATE
[17+] ERROR 259        ← Continues failing

After error 259:

twai_status_info_t status:
  state = TWAI_STATE_RECOVERING (2)
  tx_error_counter = 128+
  bus_error_count = increasing

Steps to Reproduce

Hardware Setup:

Board 1 (Sender):

Arduino Nano ESP32
├── GPIO 3 → SN65HVD230 TX (Pin 1)
├── GPIO 2 → SN65HVD230 RX (Pin 4)
├── GPIO 13 → SN65HVD230 Rs (Pin 8) [set to LOW for high-speed]
├── 3.3V → SN65HVD230 VCC
└── GND → SN65HVD230 GND

Board 2 (Receiver):

Same configuration as Board 1

CAN Bus Connection:

Board 1 CAN_H (Pin 7) ──┬── 120Ω ──┬── Board 2 CAN_H
Board 1 CAN_L (Pin 6) ──┤          ├── Board 2 CAN_L
Board 1 GND ────────────┴──────────┴── Board 2 GND

Cable: 30cm twisted-pair, 4-wire
Termination: 120Ω on both ends (measured ~60Ω total)

Software - Sender Code:

#include "driver/twai.h"

#define CAN_TX 3
#define CAN_RX 2

void setup() {
  Serial.begin(115200);
  delay(2000);
  
  Serial.println("TWAI Sender Test");
  
  // Configure TWAI
  twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(
    (gpio_num_t)CAN_TX, 
    (gpio_num_t)CAN_RX, 
    TWAI_MODE_NORMAL
  );
  
  twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
  twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
  
  // Install and start
  if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
    Serial.println("Driver installed");
  } else {
    Serial.println("Driver install FAILED");
    while(1);
  }
  
  if (twai_start() == ESP_OK) {
    Serial.println("Driver started\n");
  } else {
    Serial.println("Driver start FAILED");
    while(1);
  }
}

void loop() {
  static uint32_t counter = 0;
  
  // Prepare message
  twai_message_t msg;
  msg.identifier = 0x101;
  msg.data_length_code = 5;
  msg.data[0] = 'H';
  msg.data[1] = 'E';
  msg.data[2] = 'L';
  msg.data[3] = 'L';
  msg.data[4] = 'O';
  msg.extd = 0;
  msg.rtr = 0;
  
  // Measure transmission time
  unsigned long start = millis();
  esp_err_t err = twai_transmit(&msg, pdMS_TO_TICKS(2000));
  unsigned long duration = millis() - start;
  
  // Report
  Serial.printf("[%lu] TX... ", counter);
  if (err == ESP_OK) {
    Serial.printf("OK (%lums)\n", duration);  // Shows 0ms after first message!
  } else {
    Serial.printf("ERROR %d (%lums)\n", err, duration);
  }
  
  counter++;
  delay(2000);
}

Software - Receiver Code:

#include "driver/twai.h"

#define CAN_TX 3
#define CAN_RX 2

void setup() {
  Serial.begin(115200);
  delay(2000);
  
  Serial.println("TWAI Receiver Test");
  
  twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(
    (gpio_num_t)CAN_TX, 
    (gpio_num_t)CAN_RX, 
    TWAI_MODE_NORMAL
  );
  
  twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
  twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
  
  twai_driver_install(&g_config, &t_config, &f_config);
  twai_start();
  
  Serial.println("Waiting for messages...\n");
}

void loop() {
  twai_message_t msg;
  
  if (twai_receive(&msg, pdMS_TO_TICKS(100)) == ESP_OK) {
    Serial.println("=== MESSAGE RECEIVED ===");
    Serial.printf("ID: 0x%03X\n", msg.identifier);
    Serial.printf("DLC: %d\n", msg.data_length_code);
    Serial.print("Data: ");
    for (int i = 0; i < msg.data_length_code; i++) {
      Serial.printf("%02X ", msg.data[i]);
    }
    Serial.println("\n========================\n");
  }
}

Debug Information

Test 1: Different GPIO Pins Tested

TX Pin RX Pin Result
GPIO 3 GPIO 2 0ms (no transmission)
GPIO 0 GPIO 1 0ms (no transmission)
GPIO 5 GPIO 6 0ms (no transmission)

All combinations show the same behavior.

Test 2: Different Baudrates Tested

Baudrate Result
500 kbit/s 0ms transmission
125 kbit/s 0ms transmission
25 kbit/s 0ms transmission

Baudrate makes no difference.

Test 3: Board Swap Test

Swapped sender and receiver code between boards → Same issue on both boards.

Conclusion: Not a hardware defect of individual board.

Test 4: SN65HVD230 Rs-Pin Configuration

Rs-Pin explicitly set to LOW (high-speed mode):

pinMode(13, OUTPUT);
digitalWrite(13, LOW);  // Rs = LOW = High-Speed

Result: No change, still 0ms transmission.

Test 5: Different Libraries Tested

  1. Native TWAI API (driver/twai.h): :cross_mark: 0ms issue
  2. ESP32-TWAI-CAN library (handmade0octopus): :cross_mark: Same 0ms issue
  3. arduino-CAN library (sandeepmistry): :cross_mark: Doesn't compile for ESP32-S3

All libraries use the same underlying TWAI driver → same bug.


Additional Context

Community Reports

Multiple forum posts confirm TWAI issues on ESP32-S3:

Comparison with ESP32 Classic

The same code and hardware setup works reliably on ESP32 Classic (non-S3) boards.

This appears to be specific to ESP32-S3 TWAI implementation.


Suspected Root Cause

Based on behavior analysis:

  1. twai_transmit() returns immediately (0ms) without waiting for physical transmission
  2. TX error counter increases after ~15 messages in NO_ACK mode
  3. Bus enters RECOVERING state prematurely

Hypothesis: The ESP32-S3 TWAI peripheral may have:

  • A bug in the transmission state machine
  • Incorrect error handling causing premature bus-off
  • GPIO matrix routing issues specific to S3

Workaround

Currently using Modbus TCP over WiFi as alternative communication method between devices.


Request

  1. Can you confirm this is a known issue with ESP32-S3 TWAI?
  2. Is there a planned fix in upcoming ESP-IDF or Arduino-ESP32 releases?
  3. Are there specific ESP32-S3 hardware revisions where TWAI works correctly?
  4. Should users avoid TWAI on ESP32-S3 and use alternatives (SPI CAN controllers, WiFi)?

System Logs

Full Serial Output (Sender) ``` TWAI Sender Test Driver installed Driver started

[0] TX... OK (1ms)
[1] TX... OK (0ms)
[2] TX... OK (0ms)
[3] TX... OK (0ms)
[4] TX... OK (0ms)
[5] TX... OK (0ms)
[6] TX... ERROR 263 (2000ms)
[7] TX... ERROR 263 (2000ms)
[8] TX... ERROR 263 (2000ms)

</details>

<details>
<summary>Full Serial Output (Receiver)</summary>

TWAI Receiver Test
Waiting for messages...

(no output - no messages received)

</details>

---

## Thank You

Thank you for maintaining this excellent framework. We appreciate any guidance or fixes you can provide for this issue.

Your two topics on the same subject have been merged. Please do not cross-post, it wastes peoples time.

If you think the the "Networking" category is the better place for your topic you can move your topic or flag it and request the move.

Not true. It returns in less than a millisecond because it only moves the data from your code into the transmit buffer provided by FreeRTOS.

Your test shows the Tx buffer overflowing because no messages are being put on the bus.

First test is to use an oscilloscope to check for data on the TX and RX pins.

Nothing helps, it just doesn't work. As long as there's no update for the Arduino ESP from version 2.0.18 to a newer version that fixes the CAN mapping/matrix problem, like in version 3.3.4 of the Espressif ESP32, nothing works. I don't have the time or the inclination to test all the pin assignments to see which ones might work. And with this Arduino NanoESP32, it's simply not possible to update to ESP32 version 3.3.4. Arduino.cc is responsible for fixing this, not the user. Therefore, CAN is dead. This thread can be closed.

Hi @luzie.

I'm not sure I understand what you mean by that.

Although it is true that the Arduino company only officially supports the use of the Nano ESP32 board with the official "Arduino ESP32 Boards" platform, the maintainers of the 3rd party "esp32" boards platform do provide support for the Nano ESP32 board in their platform.

So advanced users do indeed have the option of using the Nano ESP32 with version 3.3.4 of the "esp32" platform.

Thanks for your reply, but then explain to a non-expert how this works. I tried following the instructions. I was able to flash the Arduino with ESP32 version 3.3.4, but during boot, I got an error message regarding memory allocation, and unfortunately, I had to flash the original version. I always get the same message when I try to switch to version 3.3.4:

esptool.py v4.5.1
Serial port COM3
Connecting...
Chip is ESP32-S3 (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
MAC: dc:da:0c:21:65:04
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 2.4s
Hard resetting via RTS pin...

I connected the B1 pin to GND so it changed its status. Then I selected the ESPTool programmer and rewritten the bootloader. Then I uploaded SCTECH with the programmer. But nothing changes. It remains at version 2.0.18. If I remove this version from the IDE, the board is no longer detected.

\Arduino15\packages\arduino\hardware\esp32\2.0.18-arduino.5
Verwendung des Kerns 'esp32' von Platform im Ordner: \Arduino15\packages\arduino\hardware\esp32\2.0.18-arduino.5

In order to make relevant information available to any who are interested in this subject, I'll share a link to the issue @luzie submitted to the "esp32" platform developers:

Note this update comment from @luzie:

https://github.com/espressif/arduino-esp32/issues/12074#issuecomment-3611904444

we discovered that not all pins of the Arduino Nano are compatible, as described in the documentation for this component. For our purposes, we used pin 2 (GPIO5) and pin 3 (GPIO6). Pin 2 as RX and pin 3 as TX. We found that pin 2 was constantly pulled high, even though it should be pulled low. This is unfortunately due to the internal pull-up and pull-down resistors. Therefore, the driver couldn't function properly and went into error mode. However, after using pins 4 and 5, our test code worked: Written 1, Read 1, Written 0, Read 0. Okay, now we've used the TWAIN driver, first the one from the example included with the ESP32 in the library. However, this code had errors, so there was no communication. Therefore, with the help of AI, we used a slightly different code, and lo and behold, the bus is finally working.