Go Down

Topic: Building a CAN API for Arduino DUE (Read 451509 times) previous topic - next topic


Thanks for the time and effort from all those who have worked on it so far. It'll be great to have something to get our teeth in to. :)


A big thank you to Palliser and CMaglie! This is really cool! Thanks again!


Ok, I've forked the Arduino project and checked out the CAN branch so I'm pretty well good to go there. I looked at the code for the canbus library. It's a good start. Here is what I think should be done in order from first to last:

1. The normal arduino way to instantiate a library seems to be to store everything in the class and instantiate it globally. Right now the can library is constantly needing class references passed to its functions. The Can class should be internal to the CANRaw. This was already done in the code but commented out. I'm guessing that whoever wrote the code just hasn't gotten to it yet. The canbus transceiver class is already a member of the CANRaw function so that's good.
2. It would be nice to make it interrupt driven. Right now it appears to be polling driven. That's OK for testing but you aren't going to be able to put it on a bus with a new message every 600us and have it work right.
3. It would probably be good to be able to use DMA transfers to automatically write canbus frames to a software ring buffer.
4. Filtering should eventually be implemented
5. Then higher level protocols should be supported as well.

I'll try to work on some of this. I won't have any transceiver hardware to test with until Monday.


Thank you AdderD for your notes and insights about the library.

A second CAN sample sketch has been added into the "can" branch. In this example, the two CAN modules work in PRODUCER mode (CAN0 mailbox 0) and CONSUMER mode (CAN1 mailbox 0) and use CAN interrupt handler to check whether the communication has been completed (interrupt is triggered).


Producer Mode:
In this mode, when a remote frame is received, the mailbox data are sent automatically. By enabling this mode, a producer can be done using only one mailbox instead of two: one to detect the remote frame and one to send the answer.

Consumer Mode:
In this mode, after each transfer request, a remote frame is automatically sent. The first answer received is stored in the corresponding mailbox data registers.


Awesome! I just tried both example sketches and have both working on a cobble-job dual canbus shield I made from a schmartshield 1.27mm arduino shield and two sn65hvd234 chips. My shield sucks and I had to enable slope control with a 10k resistor from Rs to ground but now it seems to work reliably enough. This will allow me to actually test code now. :)


Thanks again for providing the sample sketches I have tried both and either worked. By any chance you could please provide the wiring diagrams? I doubt you can make anything out of the pile of spaghetti but please post the diagram. Thank you :)


Thanks again Palliser. After exhausting all possibilities and redid the circuit multiple times I finally figured out the work around. I am suspecting it has something to do with the Serial Monitor on Mac. I inserted a line (cannot be a blank line) right before the while loop and both examples worked.

void loop()
  while (Serial.available() > 0) {
     CAN_MSG_1 = Serial.parseInt();
      if (Serial.read() == '\n') {     
      Serial.print("Sent value= ");


I have done some updates to the canbus library previously posted. I've made it a lot simpler to work with, more object oriented, and more "Arduino" like. I forked the Arduino project and my changes are pushed to my own fork. So, if anyone is interested they'd have to get it from my github account:

I'm working on making it interrupt driven as well. Also, I will try to keep encapsulating functionality into easier to work with classes. I think the next order of business is to work on the mailbox settings. It's not fun to work with all that currently.

I wish there were a better way to share the canbus library. Perhaps I should create a repo for just the library on my account and push just the canbus files there? It would make things a lot smaller and easier to get.


Has anyone gotten this to work with OBD2? I isolated the consumer and producer from the interrupt example and loaded onto 2 DUE and was able to get consume message from the producer. Then tried hooking up the consumer to the OBD2 and nothing. I haven't tried debug through the code just thought I ask. Thanks.


Has anyone gotten this to work with OBD2? I isolated the consumer and producer from the interrupt example and loaded onto 2 DUE and was able to get consume message from the producer. Then tried hooking up the consumer to the OBD2 and nothing. I haven't tried debug through the code just thought I ask. Thanks.

I think you are misunderstanding how OBDII works with canbus. You don't use consumer or producer mode for mailboxes. Really, remote frames have been depreciated for years. I really haven't ever seen that capability used in anything. Anyway, wikipedia has a decent enough reference: http://en.wikipedia.org/wiki/OBD-II_PIDs

Basically, you want to use two mailboxes; one for transmitting, one for receiving. You transmit a PID request on a certain ID and the ECU responds on a different ID which is 8 higher than the ID you sent. If you do this you should see it working.


Hello haha2k.
I am happy you already want to deals with the 'heart of the matter'.

Thanks AddeD for your very pertinent comments.

I would like to add a couple of notes:

- Check the default baud rate in the specifications of your OBD?. Remember, the example default baud rate is 1Mbps. Depending on the OBD factory settings, this value could change to 500K, 250K, etc. If so, you have to change it. I.e. if you baud rate is 125K, then you have to do this:

Code: [Select]

CAN.init(CAN0, SystemCoreClock, CAN_BPS_125K);
CAN.init(CAN1, SystemCoreClock, CAN_BPS_125K);

- Try changing the transfer ID to 0x07DF. this is a standard CAN functional request. Do it as follows:

Code: [Select]
#define TEST1_CAN_TRANSFER_ID    0x07DF

Thank you and keep us posted.


Thank you Palliser and AddeD for the pointer and insight. I think I am truely confuse with the way this is set up. What I am going after at the moment is to just listen/spy on the bus for the traffic. Whether it be OBD2 or vehicle's internal bus I have been able to plug into it via an OBD2 shield in conjunction with UNO or simply a CAN232 without participating as a node and see data flow through. Yes, I am aware of how OBD2 work :) on top of the request and respond the power train CAN in my vehicle contains hundreds of frames per seconds of other propriatary information aside from RPM, speed, temperature, etc. Again, thanks Palliaer I'll give it shot. The OBD2 is at 500 and I had tried them all. Here is another question, how come 100K isn't part of the constants list? Thanks,


Hi guys! Congrats! You've done an excellent job!!!

I wanted to try the CAN library so I've downloaded them, compile it and tried but I get stuck in some compiling issues.

I've tried both examples. The first one fails due to not finding sysclk.h file and the second one fails showing the following errors:


In file included from can_example.ino:2:
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:46: error: ISO C++ forbids declaration of 'Pio' with no type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:46: error: expected ';' before '*' token
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:48: error: 'uint32_t' does not name a type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:51: error: ISO C++ forbids declaration of 'Pio' with no type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:51: error: expected ';' before '*' token
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:53: error: 'uint32_t' does not name a type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:56: error: 'uint32_t' does not name a type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:57: error: 'uint32_t' does not name a type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:58: error: 'uint32_t' does not name a type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:60: error: 'uint32_t' does not name a type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:61: error: 'uint32_t' does not name a type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:63: error: 'uint32_t' does not name a type
C:\Users\jordi\Documents\arduino-can\hardware\arduino\sam\libraries\CAN/sn65hvd234.h:64: error: 'uint32_t' does not name a type
can_example:23: error: 'CANRaw' does not name a type
can_example.ino: In function 'void loop()':
can_example:56: error: 'SN65HVD234_Init' was not declared in this scope
can_example:57: error: 'SN65HVD234_SetRs' was not declared in this scope
can_example:58: error: 'SN65HVD234_SetEN' was not declared in this scope
can_example:60: error: 'SN65HVD234_DisableLowPower' was not declared in this scope
can_example:61: error: 'SN65HVD234_Enable' was not declared in this scope
can_example:76: error: 'CAN' was not declared in this scope
can_example:118: error: 'SN65HVD234_EnableLowPower' was not declared in this scope
can_example:119: error: 'SN65HVD234_Disable' was not declared in this scope

I guess there is something related with the header files from Atmel microprocessor but I'm not sure about it and I haven't been able to download them and try.

Can anybody give me a hint? Thx in advance!!!

Go Up