Building a CAN API for Arduino DUE

Thanks Palliser, works great

Is there any way at all to get more than 8 total mailboxes?

CAN.global_send_transfer_cmd(CAN_TCR_MB0 | CAN_TCR_MB1 | CAN_TCR_MB2 | CAN_TCR_MB3 | CAN_TCR_MB4 | CAN_TCR_MB5 | CAN_TCR_MB6 | CAN_TCR_MB7 | CAN_TCR_MB8 | CAN_TCR_MB9 | CAN_TCR_MB10 | CAN_TCR_MB11 | CAN_TCR_MB12);
dueCAN4.ino: In function 'void loop()':
dueCAN4:475: error: 'CAN_TCR_MB8' was not declared in this scope
dueCAN4:475: error: 'CAN_TCR_MB9' was not declared in this scope
dueCAN4:475: error: 'CAN_TCR_MB10' was not declared in this scope
dueCAN4:475: error: 'CAN_TCR_MB11' was not declared in this scope
dueCAN4:475: error: 'CAN_TCR_MB12' was not declared in this scope

I tried this in the library... but not sure what is going on

due_can.cpp

void CANRaw::interruptHandler() {

	uint32_t ul_status = m_pCan->CAN_SR; //get status of interrupts

	if (ul_status & CAN_SR_MB0) { //mailbox 0 event
		mailbox_int_handler(0, ul_status);
	}
	if (ul_status & CAN_SR_MB1) { //mailbox 1 event
		mailbox_int_handler(1, ul_status);
	}
	if (ul_status & CAN_SR_MB2) { //mailbox 2 event
		mailbox_int_handler(2, ul_status);
	}
	if (ul_status & CAN_SR_MB3) { //mailbox 3 event
		mailbox_int_handler(3, ul_status);
	}
	if (ul_status & CAN_SR_MB4) { //mailbox 4 event
		mailbox_int_handler(4, ul_status);
	}
	if (ul_status & CAN_SR_MB5) { //mailbox 5 event
		mailbox_int_handler(5, ul_status);
	}
	if (ul_status & CAN_SR_MB6) { //mailbox 6 event
		mailbox_int_handler(6, ul_status);
	}
	if (ul_status & CAN_SR_MB7) { //mailbox 7 event
		mailbox_int_handler(7, ul_status);
	}
	if (ul_status & CAN_SR_MB8) { //mailbox 7 event
		mailbox_int_handler(8, ul_status);
	}
	if (ul_status & CAN_SR_MB9) { //mailbox 7 event
		mailbox_int_handler(9, ul_status);
	}
	if (ul_status & CAN_SR_MB10) { //mailbox 7 event
		mailbox_int_handler(10, ul_status);
	}
	if (ul_status & CAN_SR_MB11) { //mailbox 7 event
		mailbox_int_handler(11, ul_status);
	}
	if (ul_status & CAN_SR_MB12) { //mailbox 7 event
		mailbox_int_handler(12, ul_status);
	}

keywords.txt

CAN_TCR_MB0	LITERAL1
CAN_TCR_MB1	LITERAL1
CAN_TCR_MB2	LITERAL1
CAN_TCR_MB3	LITERAL1
CAN_TCR_MB4	LITERAL1
CAN_TCR_MB5	LITERAL1
CAN_TCR_MB6	LITERAL1
CAN_TCR_MB7	LITERAL1
CAN_TCR_MB8	LITERAL1
CAN_TCR_MB9	LITERAL1
CAN_TCR_MB10	LITERAL1
CAN_TCR_MB11	LITERAL1
CAN_TCR_MB12	LITERAL1

I didn't know I was so limited in this respect and am almost ready for this project and just hit an enormous wall!

Hello zabaat.

According to Atmel doc11057 (page 1207) http://www.atmel.com/Images/doc11057.pdf, each of the two CAN controllers inside SAM3X8E has 8 mailboxes implemented. Thus, you have 16 mailboxes available which is more than enough for a general purpose CAN project. It is a hardware limitation of the MCU. Notice also that the component_can.h file from the CMSIS library on the Arduino Due...

(...\arduino-1.5.2-windows\arduino-1.5.2\hardware\arduino\sam\system\CMSIS\Device\ATMEL\sam3xa\include\component)

... there are only 8 defined mailboxes per CAN controller (MB0->MB7). On the other hand, you could optimize the use of the mailboxes implementing the Producer<->Consumer mode where you need half of the amount of mailboxes as compared to the clasical Transmit<->Receive mode. Can you tell us more about you application?. Why more than 16 mailboxes? Regards!

Thank you for the great response! Would it be possible for me to roll through different can ids and data locations as I looped? so in other words I could still have 8 mailboxes per loop but have toggle that redirected the mailboxes after each send? I'll try this tomorrow

Yes, you can reconfigure the mailboxes any time you want. You can change what a mailbox does every loop if you want to.

Hi guys,
here's a quick update of my CAN OBD analyzer:

The software is still under construction, I use a simulator from Ozen Elektronik (a turkish brand) instead of my car. The Display is a Touch-LCD from lcd-module.de.
Speed, rpm, coolant temp and vehicle frame number are readable (multi-frame transfer took me a while to fiddle with).
I only use the DUE hardware, software is a modified can example for the SAM3X-EK board.

DUE rocks!

Hello, Can anyone please explain the function of mailbox_set_accept_mask(); both in case of transmitter as well as receiver mailbox.

Thanks,

Owais.

Owais:
Hello, Can anyone please explain the function of mailbox_set_accept_mask(); both in case of transmitter as well as receiver mailbox.

Thanks,

Owais.

Sure. For transmission mailboxes it means absolutely nothing. The examples might call that function but it is just for completeness and not because you have to. Transmissions will go out no matter how you have the accept mask set.

Now, such is not the case for receiving mail boxes. That's where the accept mask comes into play. It works like this:

  1. A frame is sent over the wire and picked up by the Due.
  2. The ID of the frame is logical AND with the accept mask
  3. This new value is then compared to the id you set for the RX mailbox (mailbox_set_id). If the IDs match then the frame is accepted and available for your program to inspect.

Here is an example. Let's say you set your accept mask to 0x7F0 and your ID to 0x230 (assume only standard frames). Now, a frame with ID 0x232 comes in. So, take 0x232 AND 0x7F0 = 0x230. Compare this to the mailbox ID you set (0x230) and find out that it matches. So, the frame is accepted by your program. Now, if a frame with ID 0x23A comes in then the same thing will happen. If 0x240 comes in then it will be rejected.

In a nutshell: the accept mask allows you to accept a range of frame IDs with a single mailbox. In the example above it allows a range of 16 IDs through 0x230 - 0x23F. The traditional use for this is to tailor acceptance to only frames you care about. Canbus traffic can get busy and you don't want to have to deal with every frame on the bus.

Thank you very much Collin80 its crystal now.

Hi guys,
today I compiled the due_can project the first time with Visual Micro + AS6.1. The second example from Collin brought:

Compiling 'Arduino_Due_CAN_Sample_2' for 'Arduino Due (Programming Port)'
Binary sketch size: 73052 bytes (used 14% of a 524288 byte maximum) (11,29 secs)

which is a huge amount of code for this little example. Even my complete CAN OBD-II project (with a small GUI and an estimated far more than thousand lines of code) written in pure C is only 43k in size. I wonder what's going on here. Also the Visual Micro hides all compiler warnings which yield additional confusings when debugging. I haven't found any settings for tweaking the IDE yet. Don't know if it is really that useful for developing CAN stuff...

Arduino code for the Due seems to be gigantic. It takes 10,076 for the blink sketch. AnalogInOutSerial takes 26,712. The size you got for the canbus example is pretty typical for the examples. They just seem to come out that large. However, it doesn't seem to enlarge a whole lot thereafter. My whole VCU project takes up less than 100K of flash space. It has a whole lot more code than the canbus library but only takes up about 30K extra. So, I think that the arduino core library can just be a bit large. I've wondered if there is something that could be done about this but have not actually taken the time to try to figure it out. I'm being lazy because there is still all sorts of available flash space. If my sketches were getting toward 450K in size then I'd worry about how to save space.

Hi guys,
I think I need a idea.

I try to communicate with my OBD simulator with 29-bit EX-ID frame. 11-bit mode work fine but in 29-bit mode the sim doesn't resond. I looked on my scope and I saw the exact time for 29bit frame with 8byte payload which I calculated before. But the sim plays possum.

Here is a chunk of my code which derived from the Atmel Code example. It works fine for 11bit frame mode (I send/receive with CAN_0). Did I forget something?

void getECUData(can_mb_conf_t *p_sc_mailbox_rx, can_mb_conf_t *p_sc_mailbox_tx) {	
		can_reset_all_mailbox(CAN0);		
		reset_mailbox_conf(p_sc_mailbox_rx);

		/* Init CAN0 Mailbox 1 to Reception Mailbox. */
		p_sc_mailbox_rx->ul_mb_idx = TEST1_CAN_COMM_MB_IDX + 1;  //mailbox 1
		p_sc_mailbox_rx->uc_obj_type = CAN_MB_RX_MODE;
		p_sc_mailbox_rx->ul_id_msk = CAN_MAM_MIDvA_Msk | CAN_MAM_MIDvB_Msk; //CAN 2.0A + B		
		if (!eepromData[EEPROM_CAN_11_29_BIT_ID]){
			p_sc_mailbox_rx->ul_id = CAN_MID_MIDvA(0x7E8);  //get 7E8 from engine control module
			p_sc_mailbox_rx->uc_id_ver = 0; // 0/1: standard/extended frame	
		}
		else  {
			p_sc_mailbox_rx->ul_id = CAN_MID_MIDvB(0x7E8);  //get 7E8 from engine control module		
			p_sc_mailbox_rx->uc_id_ver = 1; // Ver. A/B 0/1: standard/extended frame
		}	
		can_mailbox_init(CAN0, p_sc_mailbox_rx);
		
// problem starts here ---------------------------------------	

		/* Init CAN0 Mailbox 0 to Transmit Mailbox. */
		p_sc_mailbox_tx->ul_mb_idx = TEST1_CAN_COMM_MB_IDX;		//mailbox 0
		p_sc_mailbox_tx->uc_obj_type = CAN_MB_TX_MODE;
		p_sc_mailbox_tx->uc_tx_prio = TEST1_CAN0_TX_PRIO;
		if (!eepromData[EEPROM_CAN_11_29_BIT_ID]){
			p_sc_mailbox_tx->uc_id_ver = 0; // 0/1: standard/extended frame
		}
		else {
			p_sc_mailbox_tx->uc_id_ver = 1; // Ver. A/B 0/1: standard/extended frame
			printf ("DEBUG: in getECUData(); 29bit frame mode\r\n");
		}	
		p_sc_mailbox_tx->ul_id_msk = CAN_MAM_MIDvA_Msk | CAN_MAM_MIDvB_Msk; //CAN 2.0A + B
		can_mailbox_init(CAN0, p_sc_mailbox_tx);
		
		/* Write transmit information into mailbox. */
		if (!eepromData[EEPROM_CAN_11_29_BIT_ID]){  //EEPROM_CAN_11_29_BIT_ID, bit0:  0: 11bit, 1: 29bit
			p_sc_mailbox_tx->ul_id = CAN_MID_MIDvA(0x7DF);  // engine control module
		}
		else {
			p_sc_mailbox_tx->ul_id = CAN_MID_MIDvB(0x7DF);  // engine control module
			printf ("DEBUG: in getECUData(); 29bit frame mode\r\n");
		}	
		//p_sc_mailbox_tx->ul_datal = ...; set by caller
		//p_sc_mailbox_tx->ul_datah = ...;
		p_sc_mailbox_tx->uc_length = MAX_CAN_FRAME_DATA_LEN; // 8bytes
		can_mailbox_write(CAN0, p_sc_mailbox_tx);
		
// problem ends here ---------------------------------------	
	
		can_enable_interrupt(CAN0, CAN_IER_MB1);
		
		/* Send out the information in the mailbox. */
		can_global_send_transfer_cmd(CAN0, CAN_TCR_MB0);

		/* Wait until TX Mailbox empty. */
		while (!(CAN_MSR_MRDY == (CAN_MSR_MRDY &
			 can_mailbox_get_status(CAN0, TEST1_CAN_COMM_MB_IDX))));
}

Hi,
I'm so glad I found this thread! Thanks for all the hard work you guys have done. It's a little bit confusing as to which repository is the best/latest API. Can someone point me to the place where I can find it. I see this link https://github.com/arduino/Arduino/tree/can/hardware/arduino/sam/libraries/CAN but it seems a little bit out of date.

Thanks! :grin: :grin:

Hello M2319,
The updated version is here:

Regards!

Hello,
I am in the process of understanding the CAN library created for DUE. I am having trouble in figuring out this exact declaration :
Can* m_pCan;

I have seen the typ def Can in the beginning of " due_can.h " but it is only as a reference as to how the struct is defined besides that there is no other definition available of this type. Can someone please clear this up for me.

Regards.

Owais:
Hello,
I am in the process of understanding the CAN library created for DUE. I am having trouble in figuring out this exact declaration :
Can* m_pCan;

I have seen the typ def Can in the beginning of " due_can.h " but it is only as a reference as to how the struct is defined besides that there is no other definition available of this type. Can someone please clear this up for me.

Regards.

Hello Owais,

Can* m_pCan is a parameter of a Can function. More specifically, a defined address.
For the two Can controllers inside Arduino Due's SAM3X8E, the current CAN library (originally ported from Atmel) has defined two CAN addresses: CAN0 (0x400B4000U) and CAN1 (0x400B8000U). See sam3x8e.h file at

...\arduino-1.5.2-windows\arduino-1.5.2\hardware\arduino\sam\system\CMSIS\Device\ATMEL\sam3xa\include

Let's dissect a bit the Can* m_pCan parameter:

Can: is a structure that contains the Can hardware registers, and it is part of the component_can.h file

...\arduino-1.5.2-windows\arduino-1.5.2\hardware\arduino\sam\system\CMSIS\Device\ATMEL\sam3xa\include\component

m_pCan: is the Pointer to a CAN peripheral instance.

When we declare Can* m_pCan, m_pCan is a variable that stores the address of a variable of the structure Can.
If for example, we want to enable the CAN controller 0. Then in the main, the function call looks like:

CAN.enable();

And that's it! but... to get a better understanding (as you requested) of the parameter, let's take a look at the original function (before the CANRaw class was created).

The call of the old function looks like:

can_enable(CAN0);

And the old function itself:

void can_enable(Can*  m_pCan)
{
	m_pCan->CAN_MR |= CAN_MR_CANEN;
}

Where...

CAN_MR_CANEN is the CAN controller enable register. Bit 0 (0x1u << 0)
CAN_MR is the CAN mode hardware register inside the Can structure.

Thus, when we type can_enable(CAN0); we are declaring the call of the can enable function that points to the CAN controller 0 that SET the bit 0 of the enable register in the can mode hardware register inside the can structure.

Notice that all of this is transparent for the user given that all the Can functions are handle for the CANRaw class.

I hope this helps. Regards!

Thank you Palliser for taking the time to write a detailed response to my question it has helped me clear my understanding.

Just one more thing, as you have mentioned that the Can structure is from the file " component_can.h ", how/where do link this to our "due_can.h" so that the compiler knows where to look for Can structure?

Owais:
Just one more thing, as you have mentioned that the Can structure is from the file " component_can.h ", how/where do link this to our "due_can.h" so that the compiler knows where to look for Can structure?

Hello Owais,
I don't know which version of the IDE 1.5.x you are using but if you do a simple excercise of changing the name of the component_can.h file located at

...\arduino-1.5.x-windows\arduino-1.5.x\hardware\arduino\sam\system\CMSIS\Device\ATMEL\sam3xa\include\component

Let's say i.e. renaming as componen_can1.h, you will find the debugging chain showing the error. Here the simplify chain:

due_can.h->sn65hvd234.h->variant.h->Arduino.h->chip.h->sam.h->sam3.h->sam3xa.h->sam3x8e.h->component_can.h

Notice that it starts with due_can.h and then through the transceiver driver points to the variant file and so on until reach the component_can.h file that contains the Can structure.

Regards!

Thank you once again and excuse me if I am missing the obvious. I have now gone through the files and have somewhat basic understanding of the library. Moreover, I have read about Time Triggered CAN and gone through the Atmel datasheet for SAM3X, I have seen the function " void enable_time_triggered_mode(); " in the " due_can.h " and would like to implement a test code for it. Since it is Time Triggered I figure that I will have to implement the code out of the " void Loop() ". Any suggestions as to how I should implement the Time Triggered mode?

Regards.

Hi,
there are a lot of possibillities to do trigger a time event on the CAN-bus.
You can use the rtc, one of the timers or simply use the standard Cortex system timer - which is by far the most easy-to-use timer as it is always scintillating in the background of the core. Have you installed the Atmel Software framework yet? There are plenty of examples and many of them use this particular system timer, for example in the "Getting-Started Application on SAM - Arduino Due/X" - which by the way use TC0 additionally (at least I think so), too.

Hope this helps,

Joachim