ESPHome 2026.5.1
Loading...
Searching...
No Matches
esp32_can.cpp
Go to the documentation of this file.
1#ifdef USE_ESP32
2#include "esp32_can.h"
3#include "esphome/core/log.h"
4
5#include <driver/twai.h>
6
7// WORKAROUND, because CAN_IO_UNUSED is just defined as (-1) in this version
8// of the framework which does not work with -fpermissive
9#undef CAN_IO_UNUSED
10#define CAN_IO_UNUSED ((gpio_num_t) -1)
11
13
14static const char *const TAG = "esp32_can";
15
16static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config) {
17 switch (bitrate) {
18#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) || \
19 defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || \
20 defined(USE_ESP32_VARIANT_ESP32S3)
22 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_1KBITS();
23 return true;
25 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_5KBITS();
26 return true;
28 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_10KBITS();
29 return true;
31 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_12_5KBITS();
32 return true;
34 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_16KBITS();
35 return true;
37 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_20KBITS();
38 return true;
39#endif
41 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_25KBITS();
42 return true;
44 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_50KBITS();
45 return true;
47 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_100KBITS();
48 return true;
50 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_125KBITS();
51 return true;
53 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_250KBITS();
54 return true;
56 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_500KBITS();
57 return true;
59 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_800KBITS();
60 return true;
62 *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_1MBITS();
63 return true;
64 default:
65 return false;
66 }
67}
68
70 static int next_twai_ctrl_num = 0;
71 if (static_cast<unsigned>(next_twai_ctrl_num) >= SOC_TWAI_CONTROLLER_NUM) {
72 ESP_LOGW(TAG, "Maximum number of esp32_can components created already");
73 this->mark_failed();
74 return false;
75 }
76
77 // Select TWAI mode based on configuration
78 twai_mode_t twai_mode = (this->mode_ == CAN_MODE_LISTEN_ONLY) ? TWAI_MODE_LISTEN_ONLY : TWAI_MODE_NORMAL;
79
80 if (this->mode_ == CAN_MODE_LISTEN_ONLY) {
81 ESP_LOGI(TAG, "CAN bus configured in LISTEN_ONLY mode (passive, no ACKs)");
82 }
83
84 twai_general_config_t g_config =
85 TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, twai_mode);
86 g_config.controller_id = next_twai_ctrl_num++;
87 if (this->tx_queue_len_.has_value()) {
88 g_config.tx_queue_len = this->tx_queue_len_.value();
89 }
90 if (this->rx_queue_len_.has_value()) {
91 g_config.rx_queue_len = this->rx_queue_len_.value();
92 }
93
94 twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
95 twai_timing_config_t t_config;
96
97 if (!get_bitrate(this->bit_rate_, &t_config)) {
98 // invalid bit rate
99 this->mark_failed();
100 return false;
101 }
102
103 // Install TWAI driver
104 if (twai_driver_install_v2(&g_config, &t_config, &f_config, &(this->twai_handle_)) != ESP_OK) {
105 // Failed to install driver
106 this->mark_failed();
107 return false;
108 }
109
110 // Start TWAI driver
111 if (twai_start_v2(this->twai_handle_) != ESP_OK) {
112 // Failed to start driver
113 this->mark_failed();
114 return false;
115 }
116 return true;
117}
118
120 // In listen-only mode, we cannot transmit
121 if (this->mode_ == CAN_MODE_LISTEN_ONLY) {
122 ESP_LOGW(TAG, "Cannot send messages in LISTEN_ONLY mode");
123 return canbus::ERROR_FAIL;
124 }
125
126 if (this->twai_handle_ == nullptr) {
127 // not setup yet or setup failed
128 return canbus::ERROR_FAIL;
129 }
130
131 if (frame->can_data_length_code > canbus::CAN_MAX_DATA_LENGTH) {
133 }
134
135 uint32_t flags = TWAI_MSG_FLAG_NONE;
136 if (frame->use_extended_id) {
137 flags |= TWAI_MSG_FLAG_EXTD;
138 }
139 if (frame->remote_transmission_request) {
140 flags |= TWAI_MSG_FLAG_RTR;
141 }
142
143 twai_message_t message = {
144 .flags = flags,
145 .identifier = frame->can_id,
146 .data_length_code = frame->can_data_length_code,
147 .data = {}, // to suppress warning, data is initialized properly below
148 };
149 if (!frame->remote_transmission_request) {
150 memcpy(message.data, frame->data, frame->can_data_length_code);
151 }
152
153 if (twai_transmit_v2(this->twai_handle_, &message, this->tx_enqueue_timeout_ticks_) == ESP_OK) {
154 return canbus::ERROR_OK;
155 } else {
157 }
158}
159
161 if (this->twai_handle_ == nullptr) {
162 // not setup yet or setup failed
163 return canbus::ERROR_FAIL;
164 }
165
166 twai_message_t message;
167
168 if (twai_receive_v2(this->twai_handle_, &message, 0) != ESP_OK) {
169 return canbus::ERROR_NOMSG;
170 }
171
172 frame->can_id = message.identifier;
173 frame->use_extended_id = message.flags & TWAI_MSG_FLAG_EXTD;
174 frame->remote_transmission_request = message.flags & TWAI_MSG_FLAG_RTR;
175 frame->can_data_length_code = message.data_length_code;
176
177 if (!frame->remote_transmission_request) {
178 size_t dlc =
179 message.data_length_code < canbus::CAN_MAX_DATA_LENGTH ? message.data_length_code : canbus::CAN_MAX_DATA_LENGTH;
180 memcpy(frame->data, message.data, dlc);
181 }
182
183 return canbus::ERROR_OK;
184}
185
186} // namespace esphome::esp32_can
187
188#endif
void mark_failed()
Mark this component as failed.
canbus::Error read_message(struct canbus::CanFrame *frame) override
optional< uint32_t > rx_queue_len_
Definition esp32_can.h:39
TickType_t tx_enqueue_timeout_ticks_
Definition esp32_can.h:37
optional< uint32_t > tx_queue_len_
Definition esp32_can.h:38
canbus::Error send_message(struct canbus::CanFrame *frame) override
bool setup_internal() override
Definition esp32_can.cpp:69
const char * message
Definition component.cpp:35
uint16_t flags
static void uint32_t
uint8_t can_data_length_code
Definition canbus.h:60