Hi all,
I've been bashing my head against an issue with CAN for a while and was hoping someone here might have some advice.
I originally started this project with a Teensy 4.0 chip, but have replicated the issue on an ESP32-WROOM as well, specifically the following devkit:
I am trying to set up a CAN communication system using multiple Arduinos, the idea being that each "node" can shout on the same bus and different nodes can listen in using an ID based filtering. However I end up running into some really early issues that have been stumping me.
I am using the SN65HVD230 chip on a breakout board, similar to the following posting:
I believe these chips include the 120 ohm resistor, since a multimeter shows the expected resistance between CANH and CANL and I can identify an SMD resistor code 121 on the board between the high and low buses. I have also verified that my pinout is correct (Some of these boards are known to have bad labels).
I have written multiple scripts to basically have two MCUs shout at each other over the bus, with an example using the ACAN-ESP32 library from Pierre Molinaro on GitHub.
#include "ESP32_CAN_Test.h"
#include <ACAN_ESP32.h>
#include <Streaming.h>
void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN, OUTPUT);
#if SERIAL_OUT
Serial_Out.begin(115200);
while (!Serial_Out);
#endif
Serial_Out << "Initializing CAN Device." << endl;
ACAN_ESP32_Settings settings(1000000);
settings.mRxPin = RX_PIN;
settings.mTxPin = TX_PIN;
uint32_t errorCode = ACAN_ESP32::can.begin(settings);
if (errorCode == 0) {
Serial_Out << "Can Device successfully initialized." << endl;
}
else {
Serial_Out << "Can Device failed to initialize with error code " << _HEX(errorCode) << "." << endl;
}
}
void loop() {
// put your main code here, to run repeatedly:
static uint32_t timer = millis();
if (millis() - timer > 500) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
#if CAN_TRANSMIT
CANMessage msg;
msg.id = 0x123;
msg.rtr = false;
msg.len = 8;
for (uint8_t i = 0; i < 8; i++) { msg.data[i] = i+1; }
Serial_Out << "Sending CAN Message with ID " << _HEX(msg.id) << "." << endl;
if (ACAN_ESP32::can.tryToSend(msg)) {
Serial_Out << "CAN Message sent successfully." << endl;
}
else {
Serial_Out << "CAN Message failed to send." << endl;
}
#endif
timer = millis();
}
// Catch received messages
// TODO: Use ISR
CANMessage frame;
if (ACAN_ESP32::can.receive (frame)) {
Serial_Out.print ("**** Received ") ;
Serial_Out.print (frame.ext ? "extended " : "standard ") ;
Serial_Out.print (frame.rtr ? "remote " : "data ") ;
Serial_Out.print ("frame, id 0x") ;
Serial_Out.println (frame.id, HEX) ;
}
}
Along with the following header:
#ifndef _ESP32_CAN_Test_H
#define _ESP32_CAN_Test_H
// Pins for usage with CAN
#define TX_PIN GPIO_NUM_22
#define RX_PIN GPIO_NUM_23
#define CAN_TRANSMIT true
#define SERIAL_OUT true
class NullOut {
public:
void print(const char*) { return; }
void println(const char*) { return; }
void println(uint32_t, int) { return; }
};
template<class T>
NullOut &operator <<(NullOut &stream, T arg) {
return stream;
}
NullOut null_out;
#if SERIAL_OUT
#define Serial_Out Serial
#else
#define Serial_Out null_out
#endif
// Pin name for the built in LED on the ESP32 board
#define LED_BUILTIN 2
// Struct for message contents, will be merged into boilerplate code
typedef struct {
uint8_t buf[8];
uint32_t id;
} CAN_message;
#endif
I'm doing some weird stuff for debugging output, but I've also see the issue without those being present.
When I run this script on two different MCUs (I see the same behavior with a different script on Teensy 4.0s with the FlexCAN_T4 library), wired into the SN65HVD230 chip, I can see the message being sent on both the TX and RX pins of the chip that is transmitting, however it shows a NAK at the end of the sequence and it doesn't appear that the message manages to cross the bus. I'm using the Digilent Analog Discovery 2 with Waveforms to observe scope readings and I've attached a photo of what my message frame looks like on the TX and RX pins below:
I feel like I'm missing something simple, but having shown this to multiple friends and people at my university over weeks/months of on and off work with this has repeatedly stumped myself and everyone else. I haven't covered everything I've done to debug this here, but I'm happy to add information (I've tried so much stuff I could probably write a 50 page report at this point -_-). Any help would be greatly appreciated!