Some time ago I bought the transceivers for CAN, . It is necessary a CAN controller and a CAN transceiver to have communication, but the
On Arduino you would need a CAN controller, but on ESP32 it is possible to connect directly the CAN transceiver because it has a builtin CAN controller. Espressif calls its CAN bus-compatible controller as TWAI (Two Wire Automotive Interface).
In ESP32:
- Bit rates:
- from 25 Kbit/s to 1 Mbit/s in chip revision v0.0/v1.0/v1.1
- from 12.5 Kbit/s to 1 Mbit/s in chip revision v3.0/v3.1
Connections
Code
Note that you need to uncomment the sender or receiver depending on the board.
ESP32-CAN-Sender-Receiver.ino//==================================================================================//
#include <CAN.h>
#define TX_GPIO_NUM 21 // Connects to CTX
#define RX_GPIO_NUM 22 // Connects to CRX
//==================================================================================//
void setup() {
Serial.begin (115200);
while (!Serial);
delay (1000);
Serial.println ("CAN Receiver/Receiver");
// Set the pins
CAN.setPins (RX_GPIO_NUM, TX_GPIO_NUM);
// start the CAN bus at 500 kbps
if (!CAN.begin (500E3)) {
Serial.println ("Starting CAN failed!");
while (1);
}
else {
Serial.println ("CAN Initialized");
}
}
//==================================================================================//
void loop() {
// canSender();
canReceiver();
}
//==================================================================================//
void canSender() {
// send packet: id is 11 bits, packet can contain up to 8 bytes of data
Serial.print ("Sending packet ... ");
CAN.beginPacket (0x12); //sets the ID and clears the transmit buffer
// CAN.beginExtendedPacket(0xabcdef);
CAN.write ('1'); //write data to buffer. data is not sent until endPacket() is called.
CAN.write ('2');
CAN.write ('3');
CAN.write ('4');
CAN.write ('5');
CAN.write ('6');
CAN.write ('7');
CAN.write ('8');
CAN.endPacket();
//RTR packet with a requested data length
CAN.beginPacket (0x12, 3, true);
CAN.endPacket();
Serial.println ("done");
delay (1000);
}
//==================================================================================//
void canReceiver() {
// try to parse packet
int packetSize = CAN.parsePacket();
if (packetSize) {
// received a packet
Serial.print ("Received ");
if (CAN.packetExtended()) {
Serial.print ("extended ");
}
if (CAN.packetRtr()) {
// Remote transmission request, packet contains no data
Serial.print ("RTR ");
}
Serial.print ("packet with id 0x");
Serial.print (CAN.packetId(), HEX);
if (CAN.packetRtr()) {
Serial.print (" and requested length ");
Serial.println (CAN.packetDlc());
} else {
Serial.print (" and length ");
Serial.println (packetSize);
// only print packet data for non-RTR packets
while (CAN.available()) {
Serial.print ((char) CAN.read());
}
Serial.println();
}
Serial.println();
}
}
//==================================================================================//
Output
Using the driver from spressif
It works, I can receive the messages, but after like 10/20 errors. It seems that the handshake at the beginning is not correctly working. I have tried to trasnmit from the beagle, and from the arduino, and the response is really strange.
Transmit
/* ESP32 TWAI receive example.
Receive messages and sends them over serial.
Connect a CAN bus transceiver to the RX/TX pins.
For example: SN65HVD230
TWAI_MODE_LISTEN_ONLY is used so that the TWAI controller will not influence the bus.
The API gives other possible speeds and alerts:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html
Example output from a can bus message:
-> Message received
-> Message is in Standard Format
-> ID: 604
-> Byte: 0 = 00, 1 = 0f, 2 = 13, 3 = 02, 4 = 00, 5 = 00, 6 = 08, 7 = 00
Example output with alerts:
-> Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.
-> Bus error count: 171
-> Alert: The RX queue is full causing a received frame to be lost.
-> RX buffered: 4 RX missed: 46 RX overrun 0
created 05-11-2022 by Stephan Martin (designer2k2)
*/
#include "driver/twai.h"
// Pins used to connect to CAN bus transceiver:
#define RX_PIN 22
#define TX_PIN 21
// Intervall:
#define POLLING_RATE_MS 10
static bool driver_installed = false;
void setup() {
// Start Serial:
Serial.begin(115200);
// Initialize configuration structures using macro initializers
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_NORMAL);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS(); //Look in the api-reference for other speed sets.
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) {
Serial.println("Driver installed");
} else {
Serial.println("Failed to install driver");
return;
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
Serial.println("Driver started");
} else {
Serial.println("Failed to start driver");
return;
}
// Reconfigure alerts to detect frame receive, Bus-Off error and RX queue full states
uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_RX_QUEUE_FULL;
if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
Serial.println("CAN Alerts reconfigured");
} else {
Serial.println("Failed to reconfigure alerts");
return;
}
// TWAI driver is now successfully installed and started
driver_installed = true;
}
static void handle_rx_message(twai_message_t& message) {
// Process received message
if (message.extd) {
Serial.println("Message is in Extended Format");
} else {
Serial.println("Message is in Standard Format");
}
Serial.printf("ID: %x\nByte:", message.identifier);
if (!(message.rtr)) {
for (int i = 0; i < message.data_length_code; i++) {
Serial.printf(" %d = %02x,", i, message.data[i]);
}
Serial.println("");
}
}
void loop() {
if (!driver_installed) {
// Driver not installed
delay(1000);
return;
}
transmit_sample_message();
delay(1000);
}
void transmit_sample_message(){
//Configure message to transmit
twai_message_t message;
message.identifier = 0xAAAA;
message.extd = 1;
message.data_length_code = 4;
for (int i = 0; i < 4; i++) {
message.data[i] = 0;
}
//Queue message for transmission
if (twai_transmit(&message, pdMS_TO_TICKS(POLLING_RATE_MS)) == ESP_OK) {
Serial.println("Message queued for transmission\n");
} else {
Serial.println("Failed to queue message for transmission\n");
}
}
Receive
/* ESP32 TWAI receive example.
Receive messages and sends them over serial.
Connect a CAN bus transceiver to the RX/TX pins.
For example: SN65HVD230
TWAI_MODE_LISTEN_ONLY is used so that the TWAI controller will not influence the bus.
The API gives other possible speeds and alerts:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html
Example output from a can bus message:
-> Message received
-> Message is in Standard Format
-> ID: 604
-> Byte: 0 = 00, 1 = 0f, 2 = 13, 3 = 02, 4 = 00, 5 = 00, 6 = 08, 7 = 00
Example output with alerts:
-> Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.
-> Bus error count: 171
-> Alert: The RX queue is full causing a received frame to be lost.
-> RX buffered: 4 RX missed: 46 RX overrun 0
created 05-11-2022 by Stephan Martin (designer2k2)
*/
#include "driver/twai.h"
// Pins used to connect to CAN bus transceiver:
#define RX_PIN 22
#define TX_PIN 21
// Intervall:
#define POLLING_RATE_MS 1000
static bool driver_installed = false;
void setup() {
// Start Serial:
Serial.begin(115200);
// Initialize configuration structures using macro initializers
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_LISTEN_ONLY);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS(); //Look in the api-reference for other speed sets.
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) {
Serial.println("Driver installed");
} else {
Serial.println("Failed to install driver");
return;
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
Serial.println("Driver started");
} else {
Serial.println("Failed to start driver");
return;
}
// Reconfigure alerts to detect frame receive, Bus-Off error and RX queue full states
uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_RX_QUEUE_FULL;
if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
Serial.println("CAN Alerts reconfigured");
} else {
Serial.println("Failed to reconfigure alerts");
return;
}
// TWAI driver is now successfully installed and started
driver_installed = true;
}
static void handle_rx_message(twai_message_t& message) {
// Process received message
if (message.extd) {
Serial.println("Message is in Extended Format");
} else {
Serial.println("Message is in Standard Format");
}
Serial.printf("ID: %x\nByte:", message.identifier);
if (!(message.rtr)) {
for (int i = 0; i < message.data_length_code; i++) {
Serial.printf(" %d = %02x,", i, message.data[i]);
}
Serial.println("");
}
}
void loop() {
if (!driver_installed) {
// Driver not installed
delay(1000);
return;
}
// Check if alert happened
uint32_t alerts_triggered;
twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS));
twai_status_info_t twaistatus;
twai_get_status_info(&twaistatus);
// Handle alerts
if (alerts_triggered & TWAI_ALERT_ERR_PASS) {
Serial.println("Alert: TWAI controller has become error passive.");
}
if (alerts_triggered & TWAI_ALERT_BUS_ERROR) {
Serial.println("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.");
Serial.printf("Bus error count: %d\n", twaistatus.bus_error_count);
}
if (alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL) {
Serial.println("Alert: The RX queue is full causing a received frame to be lost.");
Serial.printf("RX buffered: %d\t", twaistatus.msgs_to_rx);
Serial.printf("RX missed: %d\t", twaistatus.rx_missed_count);
Serial.printf("RX overrun %d\n", twaistatus.rx_overrun_count);
}
// Check if message is received
if (alerts_triggered & TWAI_ALERT_RX_DATA) {
// One or more messages received. Handle all.
twai_message_t message;
while (twai_receive(&message, 0) == ESP_OK) {
handle_rx_message(message);
}
}
}