Building a CAN API for Arduino DUE

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).

https://github.com/arduino/Arduino/tree/can/hardware/arduino/sam/libraries/CAN/examples

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. :slight_smile:

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 :slight_smile:

234s.JPG

Please, check replay #33.

Arduino Forum.

Regards.

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()
{
Serial.println("-----");
while (Serial.available() > 0) {
CAN_MSG_1 = Serial.parseInt();
if (Serial.read() == '\n') {
Serial.print("Sent value= ");
Serial.println(CAN_MSG_1);
//delay(1000);
}
}
....................

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.

haha2k:
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: OBD-II PIDs - Wikipedia

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:
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:
#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 :slight_smile: 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!!!

haha2k:
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 :slight_smile: 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,

If that's the case then I think what you want is to set one or more mailboxes to receive mode, not consumer mode. In consumer mode it sends a remote frame request on a certain ID and expects a reply back on that ID. I'm not sure how that'd work with OBDII. You merely need to set up a receive box and let traffic flow to it.

As for 100K, I'd guess it's not on the list because it just isn't that common. You should be able to add it though.

Hello jeancarlo19,

Here a procedure that should make the CAN sketches compile OK. I know the following is going to look drastic but it is the easiest way to do it.

Before proceed with the following steps, MAKE SURE to BACKUP your current Arduino 1.5.2 files.

Step 1: copy and replace ALL the folders/files from ...\Arduino-can\Arduino-can*.*
to ...\arduino-1.5.2-windows\arduino-1.5.2*.*

I want to clarify that ...\Arduino-can\Arduino-can\ refers to the CAN github stuff.
and ...\arduino-1.5.2-windows\arduino-1.5.2\ refers to your current arduino 1.5.2 stuff.

Step 2: Open the Arduino IDE 1.5.2

Step 3: Open any CAN sketch (now under ...\arduino-1.5.2-windows\arduino-1.5.2\hardware\arduino\sam\libraries\CAN).

Step 4: Import the CAN library (don't forget to set the Arduino Due (Programming Port) board)

And that's it. Now, you should be able to compile the sketch without errors/warnings.

The reason for the above procedure is because the CAN library was built as Arduino staging using in a prior Ardunio stuff.
Besides the CAN library itself, there are few files that have to be updated in the current 1.5.2 version. I will make time
to find and tell the only necessary files to copy/replace. Regards!

Attached to this post is the newest version of my copy of the canbus library. I've changed a lot but the examples are updated to reflect how it works now. It would be good to get feedback on whether this is a good direction to take the library or not. I'm not totally done with my modifications yet but it is in a usable state currently.

CAN.zip (24.8 KB)

Success!!! AdderD & Palliser thank you both again the priceless HINTS. After an hour of tweaking the code this evening I was able to tap into both the internal and OBD2 bus, the data flowed through into the serial monitor as if a flood gate was opened. Sorry TI for doubting the 3.3V compatibility to 5V (after the disappointment last night I ordered 10pcs of TJA1055/c thinking 3.3V is not what TI claimed to be). Next stop, double back to the consumer mode, set the ACK bit and make DUE as a node on the bus. It's exciting. Again without the inputs from both of you I would still be going in circles. The IRQ worked like charm, it's better than having to loop and loop to get the serial stream from CAN232 and miss 5-10% of the frames. I am SOLD!!!

Hello AdderD,

You are doing an amazing job. Thank you. I haven't get through all the improvements (just a glance) but looks/works very pretty now. Thank you also for adding a third sketch. This is how value is added here.

haha2k
I am happy you are on the move with the CAN library. Keep us posted about your progress.

I invite the CAN bus fans in the forum to join us and let us know how the library is working, picture of the CAN shield, etc. Regards!

Hi Palliser!

Thx for your help. Now it's working!!! I guess I had downloaded a wrong repository because I've already did without good results but I downloaded the repo again and now everything is compiling.

Gracias Pana!!

Here is another zip. I made a mistake in setting the ID for canbus frames and so basically all frames were being sent as ID 0. It works now. Whoops...

CAN.zip (24.9 KB)

Hi guys!

I've been trying out the CAN API and it works all right.

My sincere congrats to all developers. You have done an excellent work!

I have been testing the CAN api and everything works smooth at all speeds up to 1Mbps.

Although I have some comments:

The Can mailbox config structure "can_mb_conf_t" contains only two possible data, datah and datal. Is there any direct way to address individual bytes (B0 - B7) of the CAN message? Obviously the DLC param should has to be correctly set.

I'm using Line Driver SN65HVD232 (without any kind of low power mode, or anytingh else than pure CAN line driving) and I think that it is a little bit unconfortable to start up the transceiver as SSN65HVD234_Data can0_transceiver; instead of just using a generic CAN pin enable. Other options could also be using any 3V-5V line transceiver and using after any standard 5V Can driver.

Thank you again folks!

Lufe

lufegimenez:
Although I have some comments:

The Can mailbox config structure "can_mb_conf_t" contains only two possible data, datah and datal. Is there any direct way to address individual bytes (B0 - B7) of the CAN message? Obviously the DLC param should has to be correctly set.

You must not have downloaded the version I uploaded yesterday. In my new version there is an RX_CAN_FRAME structure which does expose all 8 data bytes.

I'm using Line Driver SN65HVD232 (without any kind of low power mode, or anytingh else than pure CAN line driving) and I think that it is a little bit unconfortable to start up the transceiver as SSN65HVD234_Data can0_transceiver; instead of just using a generic CAN pin enable. Other options could also be using any 3V-5V line transceiver and using after any standard 5V Can driver.

Yes, right now the code basically assumes you will be using a 234 chip. If you use my new version you might be able to set both Rs and En pins to be the same pin number. That would probably work alright for your use. Eventually we should support disabling the use of certain pins so that chips like 232 can be supported without wasting pins.