Principle of RX CAN traffic handling

Each hardware implementation of a CAN bus has its own set of filters and two FIFOs. Each filter is associated to one of the two FIFOs. The incoming messages are checked against the filters in their numeric order (first filter 0, then filter 1 and so on). The first filter that matches the received message places this message into the configured FIFO A or B. This means that the message will not be checked by any of the subsequent filters anymore. It will only be placed in one of the two FIFOs (not in both).

As mentioned before the described procedure is handled by hardware via DMA (direct memory access) which makes it fast and independent from the application. It also does not burden the processor with the load of handling each message. This is why it is recommend to use CAN filters in your application whenever possible.

CAN bus library implementation

The SAMC21_CAN bus library now provides two ways to handle the CAN bus receive traffic.

  • Either (rather straigth forward) the application configures a number filters first (e.g. in the setup() routine) and then it polls with checkReceive() and readMsgBuf() frequently to receive and handle the incoming messages.
  • Or the application defines a class that is derived from the SAMC21_CAN_RECEIVER class, creates an object of this class and registers this object with the MCAN0 object. The background processes would now distribute the can-messages to the call-back methods of your objects whenever a message comes in that matches your criteria. (it is simpler as it sounds as you will see in the examples).

CAN_Receiver object approach


  • the objects don’t have to poll for new messages but will be informed automatically
  • the background process that receives and distributes messages runs during yield(), delay() and loop() iterations, hence the risk of ‘missing’ messages is reduced.
  • if applicable the program can create more then one instance of your class which might reduce the overall size of your application. In fact the CAN2SER and Datapool libraries are examples that use the CAN_Receiver approach.


  • the object’s call-back method must not use delay, read, write, yield or print functions etc, in order to prevent re-entering. It is common practice to set flags and variables only and return as quickly as possible from call-back functions
  • the asynchronous approach might be a bit harder to control

see examples making use of the object oriented approach
File -> Examples -> DICE -> CAN Bus -> ReceiverClassExample

readMsgBuf() – polling approach


  • programming is straight forward and not asynchronous which makes it easier to implement and control
  • since the code runs within the main loop() it can use all available libraries and functions (like println etc.).


  • the risk of buffer- (FIFO-) overruns are higher if not taken care of in procedures and libraries calls that might block for longer.
  • code is not as reusable as in the object oriented approach

File -> Examples -> DICE -> CAN Bus -> SimpleSendReceive

It is important to understand that a CAN message will only be delivered to one of the two mechanisms above. This means that if the CAN_Receiver has a filter configured that matches the incoming can-message then it will go the the matching CAN_Receiver objects only. It will not be ‘seen’ by readMsgBuf() anymore.

The reason for this is that the CAN_Receiver are using the filters in the lower (= higher priority) range. This mechanism is used e.g. in the CAN2SER traffic to the PC-tools and by inter-node CAN traffic (e.g. the Datapool library). The good effect about this is that the application will not be bothered withe.g. the ‘can2ser’ traffic on the CAN bus.

See also

SAMC21_CAN – Library