The first message
Two ESP32-S3 boards, two TK109s and three wires between the terminals. One sketch goes on both, with one line that says which board sends: the sender puts a counter on the bus once a second, and the receiver prints it. Both at 500 kbit/s, the rate the boards were tested at.
What you need
- Two ESP32-S3 dev boards, each on its own USB cable.
- Two TK109 boards, with their 120 Ω left on: two boards are the two ends.
- Jumper wires, and three wires between the two bus connections.
Wire it
Each ESP32-S3 to its own TK109:
| TK109 | ESP32-S3 |
|---|---|
| GND | GND |
| 3V3 | 3V3 |
| CTX | GPIO 8 |
| CRX | GPIO 9 |
Then the bus, board to board: CANH to CANH, GND to GND, CANL to CANL, on the three pins or the screw terminals. CTX and CRX go straight across; nothing is crossed.
Both ends at one rate
CAN has no clock wire. Every controller times the bits itself from the rate its
sketch set, so every sketch on a bus has to use the same timing line. This one
uses TWAI_TIMING_CONFIG_500KBITS().
What it prints
On the receiver:
receiver
got 0x100: 0
got 0x100: 1
got 0x100: 2On the sender:
sender
sent 0, tx errors 0
sent 1, tx errors 0tx errors 0 is the line that proves the bus: every frame was acknowledged. If
you upload the sender first, its count climbs while it waits for the receiver,
then falls back one per good frame once the receiver starts.
The code
Set SENDER to true on one board and false on the other. The sender queues a one-byte frame with identifier 0x100 every second and prints its transmit error counter; the receiver prints every frame it gets.
// TK109 CAN: one sketch for both ESP32-S3 boards.
// Set SENDER true on one board and false on the other.
//
// Wiring, each ESP32-S3 to its own TK109:
// TK109 GND -> ESP32 GND TK109 3V3 -> ESP32 3V3
// TK109 CTX -> GPIO8 TK109 CRX -> GPIO9
// Bus: CANH to CANH, GND to GND, CANL to CANL.
// Keep both 120R fitted: two boards are the two ends.
//
// Arduino IDE: Tools > Board > esp32 > ESP32S3 Dev Module,
// Tools > USB CDC On Boot > Enabled, then Tools > Port.
// Serial Monitor at 115200. No libraries to install.
#include "driver/twai.h"
const bool SENDER = true;
const int CAN_TX = 8, CAN_RX = 9;
const uint32_t ID = 0x100;
void setup() {
Serial.begin(115200);
delay(500);
twai_general_config_t g = TWAI_GENERAL_CONFIG_DEFAULT(
(gpio_num_t)CAN_TX, (gpio_num_t)CAN_RX, TWAI_MODE_NORMAL);
twai_timing_config_t t = TWAI_TIMING_CONFIG_500KBITS();
twai_filter_config_t f = TWAI_FILTER_CONFIG_ACCEPT_ALL();
if (twai_driver_install(&g, &t, &f) != ESP_OK ||
twai_start() != ESP_OK) {
Serial.println("CAN did not start: check the pins");
while (true) delay(1000);
}
Serial.println(SENDER ? "sender" : "receiver");
}
void loop() {
if (SENDER) {
static uint8_t count = 0;
twai_message_t msg = {};
msg.identifier = ID;
msg.data_length_code = 1;
msg.data[0] = count;
twai_transmit(&msg, pdMS_TO_TICKS(100));
delay(1000);
twai_status_info_t s;
twai_get_status_info(&s);
Serial.printf("sent %u, tx errors %lu\n", count++,
(unsigned long)s.tx_error_counter);
} else {
twai_message_t msg;
if (twai_receive(&msg, pdMS_TO_TICKS(1000)) == ESP_OK) {
Serial.printf("got 0x%03lX: %u\n",
(unsigned long)msg.identifier, msg.data[0]);
}
}
}driver/twai.h is Espressif's own CAN driver and comes with the ESP32 core, so there is nothing to install. On a classic ESP32 or an ESP32-C3, change CAN_TX and CAN_RX to two free GPIOs, such as 5 and 4.
When it does not work
Nobody is acknowledging. The receiver is off, still being uploaded, or its CAN controller did not start: open its Serial Monitor and look for the word receiver. Then check its CRX goes to GPIO 9 and the three bus wires join CANH to CANH, CANL to CANL, GND to GND.
twai_driver_install() refused the pins or the driver was already installed. Check CAN_TX and CAN_RX are GPIOs your board has and nothing else in the sketch uses. On a classic ESP32, GPIO 8 and 9 belong to the flash chip; use 5 and 4.
Tools > USB CDC On Boot must be Enabled for Serial to reach the USB port on most ESP32-S3 boards. Set it, upload again, and reopen the Serial Monitor.
The sender's frames are being acknowledged by something, so the bus works, but the receiver's sketch is not reading: check SENDER is false on that board and that both sketches use the same TWAI_TIMING_CONFIG line.
How far 500 kbit/s reaches, and what 1 Mbit/s costs on this board.
Speed and length →Edit this page — content/books/can-bus/first-message.mdx
Questions about this product
See what other owners have asked, and read their solutions.
CAN Bus
Loading discussions…
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.