Skip to content

Commit da8960b

Browse files
committed
Add support for ESP32 boards using the native TWAI (CAN) driver.
Changes: - Add ODriveESP32TWAI.hpp interface that calls twai_transmit/twai_receive directly - Add IS_ESP32_TWAI option to SineWaveCAN example - Add esp32 PlatformIO target
1 parent c6d4731 commit da8960b

3 files changed

Lines changed: 129 additions & 2 deletions

File tree

examples/SineWaveCAN/SineWaveCAN.ino

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
// #define IS_ARDUINO_BUILTIN // Arduino boards with built-in CAN interface (e.g. Arduino Uno R4 Minima)
2222
// #define IS_MCP2515 // Any board with external MCP2515 based extension module. See below to configure the module.
2323
// #define IS_STM32_BUILTIN // STM32 boards with built-in CAN interface (e.g. STM32F4 Discovery).
24+
// #define IS_ESP32_TWAI // ESP32 boards with built-in TWAI (CAN) interface. Directly uses the ESP-IDF TWAI driver.
2425

2526

2627
/* Board-specific includes ---------------------------------------------------*/
2728

28-
#if defined(IS_TEENSY_BUILTIN) + defined(IS_ARDUINO_BUILTIN) + defined(IS_MCP2515) + defined(IS_STM32_BUILTIN) != 1
29+
#if defined(IS_TEENSY_BUILTIN) + defined(IS_ARDUINO_BUILTIN) + defined(IS_MCP2515) + defined(IS_STM32_BUILTIN) + defined(IS_ESP32_TWAI) != 1
2930
#warning "Select exactly one hardware option at the top of this file."
3031

3132
#if CAN_HOWMANY > 0 || CANFD_HOWMANY > 0
@@ -65,6 +66,12 @@ struct ODriveStatus; // hack to prevent teensy compile error
6566
#include "ODriveSTM32CAN.hpp"
6667
#endif // IS_STM32_BUILTIN
6768

69+
#ifdef IS_ESP32_TWAI
70+
// See https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/twai.html
71+
#include "driver/twai.h"
72+
#include "ODriveESP32TWAI.hpp"
73+
#endif // IS_ESP32_TWAI
74+
6875

6976

7077
/* Board-specific settings ---------------------------------------------------*/
@@ -160,6 +167,54 @@ bool setupCan() {
160167
#endif // IS_STM32_BUILTIN
161168

162169

170+
/* ESP32 boards with built-in TWAI (CAN) */
171+
172+
#ifdef IS_ESP32_TWAI
173+
174+
// Pins used to connect to CAN bus transceiver
175+
#define ESP32_TWAI_TX_PIN 5
176+
#define ESP32_TWAI_RX_PIN 4
177+
178+
ESP32TWAIIntf can_intf;
179+
180+
bool setupCan() {
181+
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(
182+
(gpio_num_t)ESP32_TWAI_TX_PIN,
183+
(gpio_num_t)ESP32_TWAI_RX_PIN,
184+
TWAI_MODE_NORMAL
185+
);
186+
187+
twai_timing_config_t t_config;
188+
switch (CAN_BAUDRATE) {
189+
case 1000000: t_config = TWAI_TIMING_CONFIG_1MBITS(); break;
190+
case 800000: t_config = TWAI_TIMING_CONFIG_800KBITS(); break;
191+
case 500000: t_config = TWAI_TIMING_CONFIG_500KBITS(); break;
192+
case 250000: t_config = TWAI_TIMING_CONFIG_250KBITS(); break;
193+
case 125000: t_config = TWAI_TIMING_CONFIG_125KBITS(); break;
194+
case 100000: t_config = TWAI_TIMING_CONFIG_100KBITS(); break;
195+
case 50000: t_config = TWAI_TIMING_CONFIG_50KBITS(); break;
196+
case 25000: t_config = TWAI_TIMING_CONFIG_25KBITS(); break;
197+
default: t_config = TWAI_TIMING_CONFIG_250KBITS(); break;
198+
}
199+
200+
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
201+
202+
if (twai_driver_install(&g_config, &t_config, &f_config) != ESP_OK) {
203+
return false;
204+
}
205+
206+
if (twai_start() != ESP_OK) {
207+
twai_driver_uninstall();
208+
return false;
209+
}
210+
211+
can_intf.initialized = true;
212+
return true;
213+
}
214+
215+
#endif // IS_ESP32_TWAI
216+
217+
163218
/* Example sketch ------------------------------------------------------------*/
164219

165220
// Instantiate ODrive objects

platformio.ini

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,10 @@ build_flags =
4646
; See https://github.com/pazi88/STM32_CAN
4747
-DHAL_CAN_MODULE_ENABLED
4848
lib_deps =
49-
https://github.com/pazi88/STM32_CAN.git#1.2.0
49+
https://github.com/pazi88/STM32_CAN.git#1.2.0
50+
51+
[env:esp32]
52+
platform = espressif32
53+
board = esp32dev
54+
framework = arduino
55+
build_flags = -DIS_ESP32_TWAI

src/ODriveESP32TWAI.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// CAN glue layer for ESP32 platforms using the native TWAI driver.
2+
// See ODriveHardwareCAN.hpp for documentation.
3+
4+
#pragma once
5+
6+
#include "ODriveCAN.h"
7+
#include "driver/twai.h"
8+
9+
// Simple struct to hold TWAI interface state. Unlike other platforms, ESP32's
10+
// TWAI driver uses global functions rather than a class instance.
11+
struct ESP32TWAIIntf {
12+
bool initialized = false;
13+
};
14+
15+
struct CanMsg {
16+
uint32_t id;
17+
uint8_t len;
18+
uint8_t buffer[8];
19+
};
20+
21+
// Must be defined by the application
22+
void onCanMessage(const CanMsg& msg);
23+
24+
static bool sendMsg(ESP32TWAIIntf& intf, uint32_t id, uint8_t length, const uint8_t* data) {
25+
if (!intf.initialized) {
26+
return false;
27+
}
28+
29+
twai_message_t tx_msg = {};
30+
tx_msg.identifier = id;
31+
tx_msg.data_length_code = length;
32+
tx_msg.extd = (id > 0x7FF) ? 1 : 0;
33+
tx_msg.rtr = (data == nullptr) ? 1 : 0;
34+
35+
if (data) {
36+
for (int i = 0; i < length; ++i) {
37+
tx_msg.data[i] = data[i];
38+
}
39+
}
40+
41+
return twai_transmit(&tx_msg, pdMS_TO_TICKS(100)) == ESP_OK;
42+
}
43+
44+
static void onReceive(const CanMsg& msg, ODriveCAN& odrive) {
45+
odrive.onReceive(msg.id, msg.len, msg.buffer);
46+
}
47+
48+
static void pumpEvents(ESP32TWAIIntf& intf, int max_events = 100) {
49+
if (!intf.initialized) {
50+
return;
51+
}
52+
53+
// max_events prevents an infinite loop if messages come at a high rate
54+
twai_message_t rx_msg;
55+
while (twai_receive(&rx_msg, 0) == ESP_OK && max_events--) {
56+
CanMsg msg;
57+
msg.id = rx_msg.identifier;
58+
msg.len = rx_msg.data_length_code;
59+
for (int i = 0; i < rx_msg.data_length_code && i < 8; ++i) {
60+
msg.buffer[i] = rx_msg.data[i];
61+
}
62+
onCanMessage(msg);
63+
}
64+
}
65+
66+
CREATE_CAN_INTF_WRAPPER(ESP32TWAIIntf)

0 commit comments

Comments
 (0)