Building a CAN API for Arduino DUE

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.

Just starting to try out!

Thanks!

Hi guys,

After being successful in the test between CAN bus 0 and 1 in Arduino Due, I've tried to receive messages from an ECU. This ECU sends 13 CAN frames of 64 bytes each one. I'm able to read the first frame but I have no idea about how to read the rest of them. By reading, I guess that the ECU is working with extended frame so I've been trying to mask the whole ID (CAN_ID and frame_ID), setting uc_id_ver=1 and some other options but nothing worked... Am I right with the extended frame CAN bus version? Has anybody experience on that? Is this library working with this kind of CAN bus?

Thanks!!

jeancarlo19:
After being successful in the test between CAN bus 0 and 1 in Arduino Due, I've tried to receive messages from an ECU. This ECU sends 13 CAN frames of 64 bytes each one.

Something is not right with this statement. You cannot send more than 8 bytes per frame. It is totally against the spec. This is not to mention that it is impossible to even set a DLC of more than 15 since it only uses 4 bits. So, you either mean 64 bits (8 bytes) or you mean that the ECU uses some form of higher level protocol to send messages as a series of frames. In the latter case there is no support for higher level protocols so that might be a problem.

I'm able to read the first frame but I have no idea about how to read the rest of them. By reading, I guess that the ECU is working with extended frame so I've been trying to mask the whole ID (CAN_ID and frame_ID), setting uc_id_ver=1 and some other options but nothing worked... Am I right with the extended frame CAN bus version? Has anybody experience on that? Is this library working with this kind of CAN bus?
Thanks!!

Yes, if you are using the official version of the library then uc_id_ver being set to 1 means extended frame. To tell you the truth, I have not tried the library (either the official one or the newer one I've worked on) with extended frames. It should work but I just haven't tested.

If you use my newer/modified version of the canbus library you will get hardware interrupts and a software buffer so you can just keep reading new frames out of the software buffer and not worry about messing with mailboxes. If you are using the official version then you need to check for whether a given mailbox has a new message and grab it if so. The act of grabbing the message clears the box to accept another message. So, that part is handled for you. Below are the relevant lines necessary to grab a message. If they're put in a loop you should be able to keep grabbing new messages as they come in.

  // Wait for CAN1 mailbox 0 to receive the data
  while (!(CAN.mailbox_get_status(CAN1, 0) & CAN_MSR_MRDY)) {
  }

  // Read the received data from CAN1 mailbox 0
  CAN.mailbox_read(CAN1, &can1_mailbox);

Of course, I'm going to suggest that you download the version of the library I posted a few messages back and use that. To me it's easier to work with. It will require quite a bit of changing your code around though since I changed so much. As luck would have it, I did update the examples so it should be pretty easy to get up to speed with the different way of doing things.

I will try to do some testing with extended frames to make sure that the library is working with them as well.

Hello chamo jeancarlo19,

please, confirm if your ECU is working with extended frames.

By default, all the CAN sample sketches work in the standard frame mode. For extended frames you will have to change the Mailbox ID register to CAN_MID_MIDvB instead of CAN_MID_MIDvA. This register CAN_MID_MIDvB needs to be SET for the mailbox to handle the extended format. Don't worry about the acceptance masking (MAM). The samples ORit depending on the format type.

In the same way as AdderD, I will be revising the extended format and try to bring an example using it. Regards!

Ok, I made a 4th example sketch in my copy of the canbus library. It turns out that extended frames do work fine already with the library. The sketch is a ping/pong type where the two canbus devices are set up to fire and receive frames pointing at each other so one sends, the other receives,then that one sends and the first receives, back and forth. Currently I have 100uS delay between each sending to slow things down a bit. I have tested this to be pretty stable. Right now I am looking at a serial monitor showing 5 million ping/pongs in a row. If I take the 100us delay out it will work VERY quickly but usually lock up after around 1 million ping/pongs. I don't know why quite yet, I assume the speed is causing it to sometimes miss setting things right and even one failed send will stop the sequence from happening.

Word to the wise, I test with a canbus to usb dongle also connected so I can see the traffic. I don't have a dongle that can handle 100,000 frames per second and you probably don't either. But, it appears the Due can do it. So, you kind of have to trust that the sent and received counters are accurate because it's hard to find another piece of hardware to verify.

I've attached the newest version of the library with the above 4th example.

Edit: I tested up to 100 million successful ping/pongs and quit. If it's stable to that much it seems stable enough. It would be good if someone wanted to try testing how little delay you can add and still have the traffic stay stable.

CAN.zip (26.5 KB)

Hi AllerD,

You're right... it's out of specs but frame format is 64 bytes and I'm supposed to received 13 frames of 64 bytes each one. In fact, by changing MAX_CAN_FRAME_DATA_LEN to 64 I'm received all bytes and reading the first frame. I guess ECU is using some higher level of protocol... I'll have to investigate. In any case, I'll download your library to test the extended version.

Hi Palliser,

I've already tested to change the Mailbox ID register to CAN_MID_MIDvB and everything worked the same way, I mean, I received the first frame as before but I don't know how to get the other 12 frames...

Whatever, I'll have to investigate further before continuing.

Thanks for your help!