examples/peripherals/twai/twai_utils/README.md
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|---|
This example demonstrates using the TWAI (Two-Wire Automotive Interface) driver through an interactive console interface. It provides comprehensive TWAI functionality including frame transmission/reception, message filtering, and bus monitoring. The example can be used for both standalone testing via loopback mode and real TWAI network communication.
Supported Commands:
| Command | Description | Linux can-utils Equivalent |
|---|---|---|
twai_init <controller> -t <tx> -r <rx> [opts] | Initialize TWAI controller with GPIO and mode options | ip link set can0 up type can bitrate 500000 |
twai_deinit <controller> | Deinitialize TWAI controller | ip link set can0 down |
twai_send <controller> <frame> | Send TWAI frame (standard/extended/RTR/FD) | cansend can0 123#DEADBEEF |
twai_dump <controller>[,filter] [-t mode] / twai_dump <controller> --stop | Monitor TWAI traffic with hardware filtering and timestamps | candump can0 |
twai_info <controller> | Display controller configuration, status | ip -details link show can0 |
twai_recover <controller> [-t <ms>] | Recover controller from Bus-Off state | N/A |
twai_dump runs continuously in the background. Use twai_dump <controller> --stop to stop monitoring.Connect the ESP board to a transceiver:
ESP32 Pin Transceiver TWAI Bus
--------- ----------- --------
GPIO4 (TX) --> CTX
GPIO5 (RX) <-- CRX
3.3V --> VCC
GND --> GND
TWAI_H <--> TWAI_H
TWAI_L <--> TWAI_L
Note: The specific GPIO pins for TX and RX must be provided in the twai_init command.
For immediate testing without any external hardware, you can use the No Transceiver Mode by connecting a single GPIO pin to itself.
# Connect GPIO4 to itself (or leave it unconnected for self-test)
# Initialize with the same TX/RX GPIO, and enable loopback and self-test modes.
twai> twai_init twai0 -t 4 -r 4 --loopback --self-test
# Send a test frame
twai> twai_send twai0 123#DEADBEEF
# Check controller status
twai> twai_info twai0
This mode is ideal for learning the commands, testing application logic, and debugging frame formats without a physical bus.
idf.py menuconfig
Navigate to Example Configuration -> TWAI Configuration and configure:
Note: For every controller, you must specify the TX and RX pins explicitly with the -t and -r options when issuing twai_init. Failing to do so will make initialization return an error.
idf.py -p PORT flash monitor
(To exit the serial monitor, type Ctrl-].)
twai_initInitializes and starts the TWAI driver. TX and RX pins are required.
Usage:
twai_init <controller> -t <tx_gpio> -r <rx_gpio> [options]
Arguments:
<controller>: Controller ID (twai0, twai1).-t, --tx: TX GPIO pin number (required).-r, --rx: RX GPIO pin number (required).-b, --bitrate: Arbitration bitrate in bps (default: CONFIG_EXAMPLE_DEFAULT_BITRATE).-B, --fd-bitrate: Data bitrate for TWAI-FD (FD-capable chips only, default: CONFIG_EXAMPLE_DEFAULT_FD_BITRATE).--loopback: Enable loopback mode.--self-test: Enable self-test mode (internal loopback).--listen: Enable listen-only mode.-c, --clk-out: Clock output GPIO pin (optional).-o, --bus-off: Bus-off indicator GPIO pin (optional).twai_deinitStops and de-initializes the TWAI driver.
Usage:
twai_deinit <controller>
twai_sendSends a standard, extended, RTR, or TWAI-FD frame.
Usage:
twai_send <controller> <frame_str>
Frame Formats:
123#DEADBEEF (11-bit ID)12345678#CAFEBABE (29-bit ID)456#R or 456#R8 (Remote Transmission Request)123##{flags}{data} (FD-capable chips only)
0..F
0x1) = BRS (Bit Rate Switch, accelerate data phase)0x2) = ESI (Error State Indicator). separators allowed (e.g. 11.22.33)123##1DEADBEEF (BRS enabled, data = DE AD BE EF)twai_dumpMonitors TWAI bus messages with filtering and candump-style output. This command runs in the background.
Usage:
twai_dump [-t <mode>] <controller>[,filter...]
twai_dump <controller> --stop
Options:
-t <mode>: Timestamp mode. Output format is (seconds.microseconds) with 6-digit microsecond precision, e.g. (1640995200.890123).
a: Absolute time (esp_timer microseconds since boot)d: Delta time between frames (time since previous frame)z: Zero-relative time from start (time since dump started)n: No timestamp (default)--stop: Stop monitoring the specified controller.
Filter Formats:
id:mask: Mask filter (e.g., 123:7FF).low-high: Range filter (e.g., 100-200, FD-capable chips only).twai0,123:7FF,100-200).twai_infoDisplays the TWAI controller's configuration and real-time status.
Usage:
twai_info <controller>
Output Includes:
twai_recoverInitiates recovery for a controller that is in the Bus-Off state.
Usage:
twai_recover <controller> [-t <ms>]
Options:
-t <ms>: Recovery timeout.
-1: Block indefinitely until recovery completes (default).0: Asynchronous recovery (returns immediately).>0: Timeout in milliseconds.Notes:
twai_info <controller> to check current node statetwai_info to monitor recovery progressTypical Command Sequence:
twai_init - Initialize controllertwai_info - Check statustwai_dump - Start monitoring (optional)twai_send - Send framestwai_recover - Recover from errors (if needed)twai_deinit - CleanupBasic usage example:
# Initialize controller 0 (bitrate 500 kbps, specify TX/RX pins)
twai> twai_init twai0 -b 500000 -t 4 -r 5
# Display controller information
twai> twai_info twai0
TWAI0 Status: Running
Node State: Error Active
Error Counters: TX=0, RX=0
Bitrate: 500000 bps
GPIOs: TX=GPIO4, RX=GPIO5
# Send standard frame on controller 0
twai> twai_send twai0 123#DEADBEEF
# Start monitoring controller 0 (accept all frames)
twai> twai_dump twai0
# Example received frame display (with default no timestamps)
twai0 123 [4] DE AD BE EF
# Initialize controller 0 with TWAI-FD enabled
twai> twai_init twai0 -b 1000000 -t 4 -r 5 -B 2000000
twai> twai_info twai0
TWAI0 Status: Running
Node State: Error Active
Error Counters: TX=0, RX=0
Bitrate: 1000000 bps (FD: 2000000 bps)
GPIOs: TX=GPIO4, RX=GPIO5
# Send FD frame with BRS on controller 0
twai> twai_send twai0 456##1DEADBEEFCAFEBABE1122334455667788
To test bidirectional communication between ESP32 and PC, set up a SocketCAN environment on Ubuntu:
sudo apt update
sudo apt install -y can-utils
# Verify installation
candump --help
cansend --help
# Classic CAN setup (500 kbps)
sudo ip link set can0 up type can bitrate 500000
# CAN-FD setup (1M arbitration, 4M data) - requires FD-capable adapter
sudo ip link set can0 up type can bitrate 1000000 dbitrate 4000000 fd on
# Verify interface
ip -details link show can0
# Terminal 1: Monitor
candump can0
# Terminal 2: Send test frame
cansend can0 123#DEADBEEF
# Send FD frame (if FD adapter available)
cansend can0 456##1DEADBEEFCAFEBABE
Once both PC and ESP32 are set up:
ESP32 to PC:
# PC: Start monitoring
candump can0
# ESP32: Initialize controller 0 and send frame
twai> twai_init twai0 -t 4 -r 5
twai> twai_send twai0 123#DEADBEEF
# PC shows: can0 123 [4] DE AD BE EF
# ESP32 shows: twai0 123 [4] DE AD BE EF
PC to ESP32:
# ESP32: Start monitoring controller 0
twai> twai_dump twai0
# PC: Send frame
cansend can0 456#CAFEBABE
# ESP32 shows: twai0 456 [4] CA FE BA BE
# Stop monitoring
twai> twai_dump twai0 --stop
123#DEADBEEF (11-bit ID)12345678#CAFEBABE (29-bit ID)456#R8 (Remote Transmission Request)123##1DEADBEEF (FD with flags, FD-capable chips only)123#DE.AD.BE.EF (dots ignored)TWAI-FD frames use two # characters: ID##{flags}{data}.
0..F). Bit meanings:
0x1 BRS: Enable Bit Rate Switch for the data phase0x2 ESI: Error State Indicator. separators for readability (ignored by the parser).# FD frame without BRS (flags = 0) on controller 0
twai> twai_send twai0 123##0DEADBEEFCAFEBABE1122334455667788
# FD frame with BRS (flags = 1, higher data speed)
twai> twai_send twai0 456##1DEADBEEFCAFEBABE1122334455667788
# FD frame with ESI (flags = 2)
twai> twai_send twai0 789##2DEADBEEF
# FD frame with BRS + ESI (flags = 3)
twai> twai_send twai0 ABC##3DEADBEEF
# Large FD frame (up to 64 bytes)
twai> twai_send twai0 DEF##1000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F
# Monitor controller 0 (accept all frames)
twai> twai_dump twai0
twai0 123 [4] DE AD BE EF
twai0 456 [2] CA FE
twai0 789 [8] 11 22 33 44 55 66 77 88
# Monitor with absolute timestamps
twai> twai_dump -t a twai0
(1640995200.890123) twai0 123 [4] DE AD BE EF
(1640995200.895555) twai0 456 [2] CA FE
(1640995200.901000) twai0 789 [8] 11 22 33 44 55 66 77 88
# Monitor with delta timestamps (time between frames)
twai> twai_dump -t d twai0
(0.000000) twai0 123 [4] DE AD BE EF
(0.005432) twai0 456 [2] CA FE
(0.005445) twai0 789 [8] 11 22 33 44 55 66 77 88
# Monitor with zero-relative timestamps (from start of monitoring)
twai> twai_dump -t z twai0
(0.000000) twai0 123 [4] DE AD BE EF
(0.005432) twai0 456 [2] CA FE
(0.010877) twai0 789 [8] 11 22 33 44 55 66 77 88
# Monitor without timestamps (default)
twai> twai_dump -t n twai0
twai0 123 [4] DE AD BE EF
twai0 456 [2] CA FE
twai0 789 [8] 11 22 33 44 55 66 77 88
# Monitor controller 0 with exact ID filter (only receive ID=0x123)
twai> twai_dump twai0,123:7FF
Mask Filter 0: ID=0x00000123, mask=0x000007FF, STD
twai0 123 [4] DE AD BE EF
# Monitor controller 0 with ID range 0x100-0x10F (mask filter approach)
twai> twai_dump twai0,100:7F0
Mask Filter 0: ID=0x00000100, mask=0x000007F0, STD
# Monitor controller 0 with range filter (0xa to 0x15) - FD-capable chips only
twai> twai_dump twai0,a-15
Range Filter 0: 0x0000000a - 0x00000015, STD
# Monitor controller 0 with range filter (0x000 to 0x666)
twai> twai_dump twai0,000-666
Range Filter 0: 0x00000000 - 0x00000666, STD
# Monitor controller 0 with mixed filters (mask + range)
twai> twai_dump twai0,123:7FF,a-15
Mask Filter 0: ID=0x00000123, mask=0x000007FF, STD
Range Filter 0: 0x0000000a - 0x00000015, STD
# Monitor controller 0 with dual filters
twai> twai_dump twai0,020:7F0,013:7F8
Mask Filter 0: ID=0x00000020, mask=0x000007F0, STD
Mask Filter 1: ID=0x00000013, mask=0x000007F8, STD
# Monitor controller 0 with multiple range filters
twai> twai_dump twai0,10-20,100-200
Range Filter 0: 0x00000010 - 0x00000020, STD
Range Filter 1: 0x00000100 - 0x00000200, STD
# Monitor all frames on controller 0 (no filter)
twai> twai_dump twai0
# Stop monitoring controller 0
twai> twai_dump twai0 --stop
Filter Types (FD-capable chips only):
id:mask format - Uses bitwise matching with configurable masklow-high format - Hardware range filtering for ID rangesNo Transceiver Mode (Testing without external hardware):
# Use same GPIO for TX and RX with loopback and self-test
twai> twai_init twai0 -t 4 -r 4 --loopback --self-test
twai> twai_dump twai0
twai> twai_send twai0 123#DEADBEEF
# Frame appears immediately in dump output:
twai0 123 [4] DE AD BE EF
twai> twai_dump twai0 --stop
Note: This mode is perfect for testing TWAI functionality without external transceivers or wiring. The same GPIO is used for both TX and RX, and the combination of --loopback and --self-test flags ensures frames are properly transmitted and received internally.
Loopback mode (with external transceiver):
twai> twai_init twai0 -t 4 -r 5 --loopback
twai> twai_dump twai0
twai> twai_send twai0 123#54455354
# Frame appears immediately in dump output:
twai0 123 [4] 54 45 53 54
# Stop monitoring when done
twai> twai_dump twai0 --stop
# FD loopback test (FD-capable chips only)
twai> twai_init twai0 -t 4 -r 5 --loopback -B 2000000
twai> twai_dump twai0
twai> twai_send twai0 456##1DEADBEEFCAFEBABE1122334455667788
twai0 456 [16] DE AD BE EF CA FE BA BE 11 22 33 44 55 66 77 88 # FD frame (BRS)
# Stop monitoring
twai> twai_dump twai0 --stop
Listen-only mode:
twai> twai_init twai0 -t 4 -r 5 --listen
twai> twai_dump twai0
# Can receive but cannot send frames
# Stop with: twai_dump twai0 --stop
Bus-Off Recovery:
The TWAI controller can enter a Bus-Off state due to excessive error conditions. Use the twai_recover command to initiate recovery:
# Basic recovery (default: block until complete)
twai> twai_recover twai0
I (1234) cmd_twai_core: Starting recovery from Bus-Off state...
I (1345) cmd_twai_core: Waiting for recovery to complete...
I (1456) cmd_twai_core: Recovery completed successfully in 100 ms
# Recovery with custom timeout
twai> twai_recover twai0 -t 5000
I (1234) cmd_twai_core: Starting recovery from Bus-Off state...
I (1345) cmd_twai_core: Waiting for recovery to complete...
I (1456) cmd_twai_core: Recovery completed successfully in 150 ms
# Asynchronous recovery (return immediately)
twai> twai_recover twai0 -t 0
I (1234) cmd_twai_core: Starting recovery from Bus-Off state...
I (1245) cmd_twai_core: Recovery initiated (async mode)
# If node is not in Bus-Off state
twai> twai_recover twai0
I (1234) cmd_twai_core: Recovery not needed - node is Error Active
Enhanced Status Information:
The twai_info command now displays real-time dynamic status information:
twai> twai_info twai0
TWAI0 Status: Running
Node State: Error Active
Error Counters: TX=0, RX=0
Bitrate: 500000 bps
GPIOs: TX=GPIO4, RX=GPIO5
Status and Node State Interpretations:
Restoring Default Configuration:
Use twai_deinit <controller> followed by twai_init <controller> to reset the driver to default settings.
Bus-Off Recovery Issues:
twai_info to check current node state.-t option (e.g., -t 15000 for 15 seconds).TWAI-FD specific issues:
PC CAN issues:
# Reset PC interface
sudo ip link set can0 down
sudo ip link set can0 up type can bitrate 500000
# For FD mode
sudo ip link set can0 up type can bitrate 1000000 dbitrate 4000000 fd on
No communication:
--loopback --self-test flagsQuick diagnostic with no-transceiver mode:
# Test if basic TWAI functionality works
twai> twai_init twai0 -t 4 -r 4 --loopback --self-test
twai> twai_send twai0 123#DEADBEEF
# If this fails, check ESP-IDF installation and chip support
Common Error Messages:
# Controller ID missing
twai> twai_send 123#DEADBEEF
E (1234) cmd_twai_send: Controller ID is required
# Interface not initialized
twai> twai_send twai0 123#DEADBEEF
E (1234) cmd_twai_send: TWAI0 not initialized
# Invalid frame format
twai> twai_send twai0 123DEADBEEF
E (1456) cmd_twai_send: Frame string is required (format: 123#AABBCC or 12345678#AABBCC)
# Invalid controller ID
twai> twai_init twai5 -t 4 -r 5
E (1678) cmd_twai_core: Invalid controller ID