Building a CAN API for Arduino DUE

Hello friends

I've been programming for a while with the API and there are some questions that I don't get very well.

These are my questions for the gurus:

  1. I wasn't able to find the structure of "can_mb_conf_t" and the correspondence of the different elements with the CAN Register mapping (Section 41.9 of SAM3XA of Atmel documentation) so I get a little lost...
  2. I also would appreciate a list with all defined parameters.

Thats all by this time.

Thank you a lot!!!

Lufe

No problem Lufe,

typedef struct {
	uint32_t ul_mb_idx;
	uint8_t uc_obj_type;  //! Mailbox object type, one of the six different objects.
	uint8_t uc_id_ver;    //! 0 stands for standard frame, 1 stands for extended frame.
	uint8_t uc_length;    //! Received data length or transmitted data length.
	uint8_t uc_tx_prio;   //! Mailbox priority, no effect in receive mode.
	uint32_t ul_status;   //! Mailbox status register value.
	uint32_t ul_id_msk;   //! No effect in transmit mode.
	uint32_t ul_id;       //! Received frame ID or the frame ID to be transmitted.
	uint32_t ul_fid;      //! Family ID.
	uint32_t ul_datal;
	uint32_t ul_datah;
} can_mb_conf_t;

This can be found within the can.h file in the libsam files.

Here are some other relevant structures which are found in component_can.h in the CMSIS files:

typedef struct {
  RwReg  CAN_MMR;       // (CanMb Offset: 0x0) Mailbox Mode Register
  RwReg  CAN_MAM;       // (CanMb Offset: 0x4) Mailbox Acceptance Mask Register
  RwReg  CAN_MID;       /**< \brief (CanMb Offset: 0x8) Mailbox ID Register 
  RwReg  CAN_MFID;      /**< \brief (CanMb Offset: 0xC) Mailbox Family ID Register
  RwReg  CAN_MSR;       /**< \brief (CanMb Offset: 0x10) Mailbox Status Register 
  RwReg  CAN_MDL;       /**< \brief (CanMb Offset: 0x14) Mailbox Data Low Register 
  RwReg  CAN_MDH;       /**< \brief (CanMb Offset: 0x18) Mailbox Data High Register 
  RwReg  CAN_MCR;       /**< \brief (CanMb Offset: 0x1C) Mailbox Control Register 
} CanMb;
/** \brief Can hardware registers
#define CANMB_NUMBER 8
typedef struct {
  RwReg  CAN_MR;        /**< \brief (Can Offset: 0x0000) Mode Register 
  WoReg  CAN_IER;       /**< \brief (Can Offset: 0x0004) Interrupt Enable Register 
  WoReg  CAN_IDR;       /**< \brief (Can Offset: 0x0008) Interrupt Disable Register 
  RoReg  CAN_IMR;       /**< \brief (Can Offset: 0x000C) Interrupt Mask Register 
  RoReg  CAN_SR;        /**< \brief (Can Offset: 0x0010) Status Register 
  RwReg  CAN_BR;        /**< \brief (Can Offset: 0x0014) Baudrate Register 
  RoReg  CAN_TIM;       /**< \brief (Can Offset: 0x0018) Timer Register 
  RoReg  CAN_TIMESTP;   /**< \brief (Can Offset: 0x001C) Timestamp Register 
  RoReg  CAN_ECR;       /**< \brief (Can Offset: 0x0020) Error Counter Register 
  WoReg  CAN_TCR;       /**< \brief (Can Offset: 0x0024) Transfer Command Register 
  WoReg  CAN_ACR;       /**< \brief (Can Offset: 0x0028) Abort Command Register 
  RoReg  Reserved1[46];
  RwReg  CAN_WPMR;      /**< \brief (Can Offset: 0x00E4) Write Protect Mode Register 
  RoReg  CAN_WPSR;      /**< \brief (Can Offset: 0x00E8) Write Protect Status Register 
  RoReg  Reserved2[69];
  CanMb  CAN_MB[CANMB_NUMBER]; /**< \brief (Can Offset: 0x200) MB = 0 .. 7 
} Can;

If you look in the files I referenced you'll find a whole bunch of definitions. You can reference back and forth between those things and section 41 of the SAM3XA docs to figure things out.

However, the whole point of the canbus library is to make it so that you don't have to worry about all of these details. Palliser, I, and others have already been working on the library so that you don't have to worry about all these low-level details. My hope is that soon nobody will really wonder about can_mb_conf_t or any of the other low level structures. In my version of the lib I already basically removed all references and uses of that struct since it seems overly tied to hardware and complex to work with.

Thank you a lot!

I appreciate very much your work. I know how difficult it is to write libraries that match the needs of everybody. I will give a good use of this info!

I grow up in engineering through pages and pages of datasheets (when you had to get them in paper, long long time ago...) so although it is not the Arduino Spirit, sometimes I prefer go to a low level...

In any case THANK YOU!!!!! You guys have my full respect!

Lufe

Hello all, firstly may I please apologise if this appears to be a daft question, I am new to Arduino Can Bus on the Due.

I've had a look at the examples given and the library and the SAM manual section 41.7.2.1, but I'm at a loss to understand how to setup the Due to receive ALL messages regardless of id.

Or if it was setup to receive SAE J1939 messages (29 bit messages) that uses a 3 bit priority, then a 18 bit Parameter Group Number (PGN), and then an 8 bit source address for the message. The PGN allows for destination specific communication and broadcast communication. How to set it up to receive a range or all PGN messages or a bank of PGN messages.

Thanks for your time & advice in advance.

Rob

Hello Rob,

Above all, I would like to know if you are referring to AdderD last example updates in the CAN library.
If not, I would recommend you to download his zip file (see reply #118 in this thread).

What I understand from you question is that you need a kind of CAN traffic reader or so.
I believe AdderD can answer better your question but what I know from a CAN node as receiver independent from ID
is that, at least, you have to set the following parameters:

  1. Controller: You have to chose controller 0 or 1 as receiver.
  2. Protocol: You have to chose Standard or Extended.
  3. Baud rate: You have to chose the kBit/s of the emitter.

Examples 1-3 work in standard mode and example 4 in extended.

In reference to the ISO definition: Our CAN library implemented for Arduino Due is defined under ISO/11898A (2.0 Part A and 2.0 Part B) standards for high speeds and ISO/11519-2 for low speeds. The standard you mentioned (SAE J1939) is equivalent to ISO 11992, thus, I need to check if that definition works. I.E. in my personal case, I have a Honda Odyssey that uses ISO 14230-4, ISO 9141-2 (also called K-line protocol) that sadly doesn't work with the library.

Just one note to think. Even though SAE J1939 includes CAN 2.0b, also defines higher layers (above the Physical and Data Link layers), that in my opinion, lie beyond the reach of the CAN here.

Hello AdderD,
Any ideas? Thank you.

robertspark:
Hello all, firstly may I please apologise if this appears to be a daft question, I am new to Arduino Can Bus on the Due.

I've had a look at the examples given and the library and the SAM manual section 41.7.2.1, but I'm at a loss to understand how to setup the Due to receive ALL messages regardless of id.

If you want to receive all messages then one easy way to do that is to just set your mask to all zeros. In example 4 you can see lines like this:
  CAN.mailbox_set_accept_mask(0, 0x1FFFFFFF, true);.
Well, setting the accept mask to zero makes it totally accepting.

Or if it was setup to receive SAE J1939 messages (29 bit messages) that uses a 3 bit priority, then a 18 bit Parameter Group Number (PGN), and then an 8 bit source address for the message. The PGN allows for destination specific communication and broadcast communication. How to set it up to receive a range or all PGN messages or a bank of PGN messages.

Once again, you would set the acceptance mask. However, for these examples you would also need to set an ID to match against. I know it will probably be easier if I give some examples. I don't remember J1939 off hand but lets say the top three bits are the priority, the next 18 PGN and the lowest 8 the source. So, with that in mind lets say you want to accept only messages with PGN of 0x3946B. You don't care about the priority and you don't care about the source. So, anything you don't care about should be a 0 in the bit mask and everything you do care about should be a 1. You want to match only one PGN so you want to match every bit in the PGN. This makes your acceptance mask: 0b00000011111111111111111100000000 = 0x3FFFF000. You then set the ID for the mailbox to be the ID you want to accept. You have to keep in mind that the PGN is shifted up 8 bits in the canbus ID so you take your desired ID of 0x3946B and shift it up 8 bits to yield 0x3946B00. This value goes in the ID field. The result looks like this:

CAN.mailbox_set_accept_mask(0, 0x3FFFF000, true);
CAN.mailbox_set_id(0, 0x3946B00, true);

In that code the true's at the end mean to use extended addresses. False would have meant standard (11 bit) IDs.

Now, what if you know that there a group of PGNs you want to receive. Let's say you need to accept PGN 0x39460 - 0x3946F (16 PGN codes) and further that you only want to accept from a source address that ranges from 0x50 - 0x57. So, you want to match everything but the last 4 bits of the PGN which you'll allow to be whatever (this gives you the 16 PGN codes listed above.) You also want to match everything but the last 3 bits of the source. So, this makes your acceptance mask 0b00000011111111111111000011111000 which is 0x3FFF0F8. You make your ID that you set be the lower bounds of the two values (PGN = 0x49460 and source = 0x50). This makes your ID 0x4946050. So, the relevant code would be:

CAN.mailbox_set_accept_mask(0, 0x3FFF0F8, true);
CAN.mailbox_set_id(0, 0x3946050, true);

If you need to accept ranges that aren't possible with a single bit pattern then you need to set up multiple mailboxes, each with the separate settings to accept each discrete pattern.

AdderD, thank you very much, perfect explanation, just what I was looking for, I'm a whole lot clearer on the MAMx, and MIDx registers. The SAM manual appears to have errors in it.

Looking at table 41.9.15, Can Message Acceptance Mask Register (CAN_MAMx), the table below refers to MIDvA & MIDvB.... which is actually the table for 41.9.16, Can Message ID Register (CAN_MIDx).

Palliser, thanks for your help, I'm basically looking to use SAE J1939 as the PGN arrangement seems to offer everything I'm looking for to be able to transmit quite a bit of multiple sensor / input data in a single CAN message.

The following file may be of interest to someone : http://gurtam.com/files/ftp/CAN/j1939-71.pdf.

Many thanks to both of you again,

This is a very interesting topic to me, but I cannot see a way to get this library so I can start playing with it. I can figure out how to download the whole fork, but not just the CAN library. Do I need all of it? I have the latest 1.5.x and was hoping to just add this library so I could start investigating.

I want to create a version of this:

but using Due as a basis instead of the LPC chip.

Looking for help to get started with this.

Keith

I have since broken out my version of the canbus library to its own github repo. Here it is: git://github.com/collin80/due_can.git

It is renamed so as to not conflict with the official Arduino Canbus library. Make no mistake, mine is not official, just the one I use. It's more object oriented and, I think, easier to use. But, it's your choice. There is an officially sanctioned library but you have to check out the can branch of the Arduino IDE on github (the whole thing).

But, and this is a big but, you probably have to download the official canbus library branch anyway. There are changes to some of the libsam files that are necessary for both canbus libraries to properly compile. I suppose I really should figure out what those changes are and import them into my library so that stock 1.5.2 will work. I'll try to do that within a few days. So, it might be best to wait a few days.

AdderD

Thanks! I'll wait and see what happens. Please post back to this thread when you get it resolved.

Regards,

Keith

Ok, I just checked into GIT a fix to allow the due_can library to work with stock 1.5.2. So, you don't need to check out the Arduino code from git to use it anymore.

Heres the link again: git://github.com/collin80/due_can.git

If you don't want to use git you can just download the zip of the master at this link: https://github.com/collin80/due_can/archive/master.zip

Just want to say thanks for the work you're putting in AdderD. Dropped the delay to 10 microseconds and made it report to serial every 50,000 instead and it's whirring along at over 30 million packets after a few minutes.

Started putting together my own code using the samples as a base, and I've come across something that has me stumped although that could be as much to do with the time as anything else.

The second sample says it uses interrupts rather than polling, but as far as I see in the code it runs the 'test1()' function after enabling the interrupt. The test1() function sends data from CAN2 then hits a while loop waiting for CAN to have received data - isn't this still polling rather than using interrupts? I was hoping to be able to do something else whilst waiting for data to be received...

Sherlock3112:
The second sample says it uses interrupts rather than polling, but as far as I see in the code it runs the 'test1()' function after enabling the interrupt. The test1() function sends data from CAN2 then hits a while loop waiting for CAN to have received data - isn't this still polling rather than using interrupts? I was hoping to be able to do something else whilst waiting for data to be received...

It is using interrupts. The interrupt puts the frame into a software buffer. Then you poll for new messages when you're ready to receive them. This is better than normal polling in that multiple messages can come in and you don't have to worry about checking frequently enough to prevent overruns. So, I suppose you could say that both interrupts and polling are taking place. The alternative is callbacks. This breaks into your code and won't always happen at an opportune time.

Great, thanks for the clarification. I was concerned that if I'm doing other things before checking for the message then I might miss some off the bus. :slight_smile:

By default the canbus library (well, my version) has a 32 entry rolling receive buffer so you can afford to have that many messages come in while you are busy. Changes are you won't be getting that many behind your back unless the bus is really busy.

Also, FWIW, I just updated the library. I fixed the examples to call the proper header and added keywords.txt so things are actually highlighted/colored properly.

Hi Everyone

Ive been reading up on this thread for a while now.
I tinker around with old cars, and have been wanting to figure out how to put a gauge cluster out of a 09 Corvette into my current project.
Im a software developer by day and junk yard mechanic by night :slight_smile:

I would like to get started with the Arduino DUE to tinker with the can bus on the cluster.
Its GMLAN which I read that they have a Highspeed and low speed can bus in there system.

Im about to order the DUE, but what other hardware should I order to get me started using the CAN API.
I come from a OO background so I probably will look into AdderD branch of the CAN API, since he mention its a little more structured for OO

I saw earlier post that people are making a shield with SN65HVD243.. I search online a bit and havnt found a place to order these...
What other fun stuff will I need to order ? And possibly from where if its allowed to be posted ..

Thanks in advance! Cant wait to get started
Allen

I ordered most of my stuff from Mouser. The transceiver chip ends in 234 which is maybe why you can't find it. Here it is at Mouser: http://www.mouser.com/_/?Keyword=SN65HVD234&FS=True

You will need one of those chips for each canbus port (so, two per Due) and some misc other goodies (60 or 120 ohm resistors, small value capacitors, etc). Also, use a schmartboard 1.27mm arduino board which is part # 206-0004-02 (also available at mouser). This board has a place to put the transceiver chips as well as having pins that go into a normal arduino board. It is not the proper size for a Due but you can run jumper wires to the proper pins of the Due. It's sort of a cobble job at the moment but it does work.

AdderD:
I ordered most of my stuff from Mouser. The transceiver chip ends in 234 which is maybe why you can't find it. Here it is at Mouser: http://www.mouser.com/_/?Keyword=SN65HVD234&FS=True

You will need one of those chips for each canbus port (so, two per Due) and some misc other goodies (60 or 120 ohm resistors, small value capacitors, etc). Also, use a schmartboard 1.27mm arduino board which is part # 206-0004-02 (also available at mouser). This board has a place to put the transceiver chips as well as having pins that go into a normal arduino board. It is not the proper size for a Due but you can run jumper wires to the proper pins of the Due. It's sort of a cobble job at the moment but it does work.

Hi AdderD

Thank you for the links and info.
The page with the transceiver chip has different ones.
Which one do I need and whats the difference between these ?
SN65HVD234D
SN65HVD234DG4

Can you recommend a Arduino bread board start kit also ?

Thanks Again
Allen

Thanks for your earlier support AdderD, and the continued development. I've got the Due happily taking data off a 1MHz bus with a DTA ECU and accelerometer spamming it.

CAN message received:
13036	0x2000	0x1EFF	Ext	8b	0 0 5C 0 14 0 12 0  
13042	0x498	0x1EFF	Std	8b	7F CD 7F 4F 88 34 80 7  
13049	0x2001	0x1EFF	Ext	8b	64 0 3 2 0 0 11 0  
13055	0x2002	0x1EFF	Ext	8b	2C 1 3C 0 79 0 0 0  
13061	0x2003	0x1EFF	Ext	8b	0 0 0 0 0 0 0 0  
13067	0x2004	0x1EFF	Ext	8b	CD E 0 0 0 0 0 0  
13073	0x2005	0x1EFF	Ext	8b	0 0 0 0 1F 1 42 3

Working a treat. I don't suppose anyone knows if there's some industry standard for converting data put out by the ECU to something useable? I know our ECU has 6 data frames (0x2000-0x2005), each 8-byte with 2 bytes for each value (engine rpm, throttle position etc) but not sure if there's a standard way to turn this into something useable (0x5C00 doesn't mean much as an idle throttle position!) or if I'm going to have to ask the ECU manufacturer nicely to give us some help converting.

Hello Sherlock3112,

I am very happy seen your progress with Due and CAN.

Based on my experience, most manufacturers of devices/equipment with CAN capability, should have available what is called "CAN matrix" of the correspondent device/equipment. Such CAN matrix should contain, among other things, CAN identifiers, Length, Byte and Bit descriptions, access (read or write only), range, resolution, units, etc.. I believe, a good step for you is to contact the ECU manufacturer. We could make also time to help you but we need from your device at least the Brand, Model and firmware version/revision (if apply). Good luck!