Hi! I wanted to understand the CAN protocol more deeply, so I decided to set up a small test environment. I bought two MCP2515 modules and connected them with two Arduino Uno boards. After that, I used the Cory J. Fowler library and uploaded the sender and receiver example codes just to make sure that my setup is working properly for experimenting with CAN communication.
I’ve also downloaded the CAN specification from Bosch to study the protocol in detail. Now I need some guidance from you, how should I proceed further with my learning? What kind of experiments should I try to really understand the protocol better? Also, I’d like to know how you personally got started with CAN communication.
I most often use the sample sketches usually supplied with the library.
Here is the list of samples (can reach from the ... menu beside the library name)
If you can afford a few more UNOs and the MCP2515 modules great. But first get both of your modules to send and receive. Then do what I call a keep alive and have each one transmit its identity every so often. By adding others you can use one to keep track of the traffic. Then do some code where one sends blink commands just a few blinks different for each to different modules. Then use your monitor one to blink x times for each keep alive it receives. From there you are on the way. Here is a buss sketch,note where the termination resistors are on the physical end of the bus. You only put jumpers at each end, no more. If you power down and measure the bus it should be about 60 ohms.
Yes, the sender and receiver example is working fine. I’ve already tested it successfully. I actually have two Arduino Megas and one extra MCP2515 module as well. Earlier, when I tried setting up communication, it wasn’t working properly, so I bought the extra hardware just to be sure.
Now I have enough components to create a 3-node CAN bus setup, which gives me a good opportunity to run some multi-node experiments and explore the protocol more deeply.
You are on the correct track, it will take time and be informative. Let us know how it goes for you. Using different processors will be good. For now stay with 5V processors. When using the MCP2515 modules check the crystal, there are several different values being sold. They work fine just have to initialize them correctly. You can have each of the modules send messages to each other. The delay()will give you lots of problems, best to avoid it.
suggest you also look a different microcontroller such as the ESP32 which ahs an onboard Two-Wire Automotive Interface (TWAI) CANbus interface
you only require a CAN transceiver such as the TJA1051 to connect to the Canbus
there is a ESP32-TWAI-CAN library which can be used when implementing code with the Arduino IDE
I also find it usful to have a USB-CAN module to monitor the bus traffic using a PC
What do you think about this idea if each node on the CAN bus sends a "keep-alive" message every 100ms, and I open the serial terminal, I should be able to see which node is the source, which node it’s sending the message to, or which node is receiving the message and from which source it received it.
Would that be a good way to monitor and understand CAN communication in a multi-node setup?
Yes, I agree, having a USB-CAN module to monitor bus traffic on a PC would definitely be useful. But for now, I find it a bit expensive for my budget, so I’m trying to manage with what I have and use serial prints for debugging.
fair enough - the USB-CAN modules can be expensive - there are cheaper ones on Ebay but I don't know how good they are
probably worth looking at an ESP32 though
on Ebay in UK ESP32 modules are about £6 and a tja1051 CAN transceiver is £5
thinking again - you could build a point to point network layer on top of Canbus - assigning addresses to nodes and transmitting packets between them
the nodes could use the Can filters to only receive the correctly addressed packets
That is what I was suggesting but you will not be able to follow the display at that speed. I do it about every 30 seconds then when finished about every minute or so. This way I can monitor it with any node that is receiving except the one sending the keep alive message. I usually add a message on the sender each time I send a keep alive "#" just send keep alive message. makes life much easier.
Apologies for the delay in replying. I wanted to take some time to understand the CAN protocol better, so I was going through the documentation and some learning resources.
Now I’d like to explain what I’ve understood so far, and I’d really appreciate your help in verifying it and helping me implement a simple two-node CAN setup.
We have two nodes:
Node A (Sender): Sends CAN messages.
Node B (Receiver): Receives messages and performs an action based on the data for example, blinking an LED.
Are CANBUS busses terminated at "both ends" and can one termination be at an arbitrary node? I see the R60 terminating resistors in your CANBUS drawing.
I am used to seeing differential busses terminated on the "ends," with all devices as nodes. For example, the 1553 bus...
I'm working with two MCP2515 CAN modules connected to Arduino Uno boards one as sender, one as receiver. CANH and CANL are linked between both modules, with 120Ω termination resistors at each end. Ground is shared. I’m attaching a snap of my setup I know it’s a bit messy and hard to follow .
I have verified my setup is working fine by uploading sender and receiver code code example from the mcp_can library and looking output on terminal. if anyone want to check code I can upload
Sender output
?��Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully!
Message Sent Successfully!
Message Sent Successfully!
Yes, only at the physical end or as close as reasonably. The termination resistors need to be 120 Ohm, in the end the bus impedance should be 60 Ohms. Different busses can and are setup at different impedance's.
As far as your setup, I have seen much worse, yours is actually fairly good. I now use jumpers with a mail pin on one end and a female on the other. It appears you have at least a meter of cable in the bus, that is good.
Keep going you have come a long way. Now a tough assignment. Look at the two examples, send and receive. You can make one piece of code that will do both with very few changes. Project: Have each one cause a led on the other to blink at different rates of course.
You have basically done it already. Your example sender code sends 8 bytes, 0x00.. 0x07 so just change that to send 0x00 or 0x01. You can still send 8 bytes, but only the first one is important.
Your receiver code receives the message so just add some code to check the data it receives. If the first byte, e.g. data[0] is 0x00 then turn the led off, it is is 0x01 then turn it on.
How can we set mask and filter in the receiver code using the mcp_can library? I want to accept only specific message IDs, but I'm not sure how to do that correctly.
I also explored the library files, but it’s still unclear to me how to properly set filters and masks using this mcp_can library
Did you look at the example that comes with the library?
The example from the Seeed Can library is a bit easier to understand:
You have to set the masks (there are 2) and then use the filters to only get the IDs that you want to receive
void setup() {
...
//set mask, set both the mask to 0x3ff
CAN.init_Mask(0, 0, 0x3ff);
CAN.init_Mask(1, 0, 0x3ff);
/*
set filter, we can receive id from 0x04 and 0x05, there are 6 filters
*/
CAN.init_Filt(0, 0, 0x04);
CAN.init_Filt(1, 0, 0x05);
...
}
Thank you! I’m beginning to understand it now. When there is more than one node on the CAN bus, the sender broadcasts the message to all nodes. It is up to the receiver to decide whether to accept or ignore a message. The receiver can use masks and filters to accept only the messages it needs.
I tested this by sending two different messages from the sender. On the receiver side, I applied a mask and filter to accept only one of them and it worked perfectly!
By the way, I’m more interested in experimenting with J1939. Do you know which library would be good to start with?