Pages: 1 ... 18 19 [20] 21 22 ... 29   Go Down
Author Topic: Building a CAN API for Arduino DUE  (Read 118056 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Germany
Offline Offline
Jr. Member
**
Karma: 0
Posts: 57
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
 
Logged

Venezuela
Offline Offline
God Member
*****
Karma: 16
Posts: 515
Ground, ground, always ground
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I am not sure if the Time Trigger Mode mentioned in the Atmel doc11057 is related to the FTTC (Flexible Time-Triggered communication) high level layer extension to the CAN protocol (also known as TTCAN) specified in the ISO 11898-4 in 2004 for ECU devices. If so, I haven't implemented so far a test code solution, although it would be a good question for the Atmel AT91SAM support.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,
I tried to run the Sample_1 only with one sn65hvd234 on CAN0 and connected the transceiver with an CAN-USB-Interface. I only want wo test the TX connection from Arduino -> PC. Until now without success. Does this sample work for my test application

On Pc I run a CAN diagnostic tool, which display each incoming message.
Logged

Venezuela
Offline Offline
God Member
*****
Karma: 16
Posts: 515
Ground, ground, always ground
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello arduhanno,

Even though the current CAN bus library and examples were ported considering the Arduino DUE architecture and the Arduino IDE, the data that DUE spits or bites is pure CAN, thus, It shouldn't be so hard to make it work via USB.
I have done what you are trying to do but only via serial(DUE -> CAN Transceiver -> CAN-to-Serial converter -> PC).
I used a CAN Analyzer from an Italian brand (ADFweb). As a reference, for the serial communication I had to consider the following default parameters:
-Serial COM port.
-CAN bus protocol type: 11 bit
-CAN Baudrate: 1000K BPS

If you let me know the brand/model of the interface you are using, I could go through the documentation and see how they implemented it using USB. Regards!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello Palliser,

I am not sure but I really think you misunderstood me. The USB-Interface is an external device with an USB connector and an SUB-D 9 pol. connector. It is for connecting a CAN Bus on PC with a diagnostic software and API. So I know from other application that this device is working and will display every Frame received via CAN. I also can send any Frames from PC to can.

My problem is that I build my own PCB with transceiver on CAN0 and it does not work. I am not sure whether it is a hard- or software problem. Therefore I want to use a Sample only for sending data that I can see Frames on PC. Can I use the Sample 1?

Other question: After this will work, I want to send and receive CAN data both over CAN0. Is this a problem?
Logged

Venezuela
Offline Offline
God Member
*****
Karma: 16
Posts: 515
Ground, ground, always ground
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You shouldn't have problems with the CAN examples (1,2,3 or 4). The idea behind the ported CAN project from Atmel to Arduino was to test the two CAN controllers (CAN0 and CAN1) doing the loop as you may have seen in this post. Assuming that your CANBUS side is OK, in the CAN side you should verify the following for the CAN0 transceiver (SN65HVD234):

1. Verify that pin 1 of the transceiver is connected to the CANTX pin of the DUE.
2. Verify that pin 4 of the transceiver is connected to the CANRX pin of the DUE.
3. Verify that pins 2 and 8 of the transceiver are connected to GROUND.
4. Verify that pins 3 and 5 of the transceiver are connected to +3V3.
5. Verify that the terminal resistor (120 ohm) is connected between CANH and CANL terminals.

See picture on reply #33
http://forum.arduino.cc//index.php?PHPSESSID=sd97s9v75d5d3d2r0fc23mcqu2&topic=131096.30

One more thing. Some CAN converters are aimed for low speed CAN networks, thus, you could try also to change the default CAN speed of 1Mbit to a lower value. For example to change the speed to 250Kbit, replace the following lines of the samples:

Code:
CAN.init(SystemCoreClock, CAN_BPS_1000K);
 CAN2.init(SystemCoreClock, CAN_BPS_1000K);

with

Code:
CAN.init(SystemCoreClock, CAN_BPS_250K);
 CAN2.init(SystemCoreClock, CAN_BPS_250K);

I hope this help. regards!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hellp Palliser,

tanks a lot for helping. Now, it works fine. One soldering at transceiver was fault.....  smiley-wink

The test app works and I can see transmitted data on PC. Now, I want to use the lib from my program. Therefore I want to use this functionality and do not know if I have to use mailboxes or how I can realize it with the lib.

One function should be something like
Code:
send_frame(int ID, int len, int d1, ....., int d8)

In an other loop part I want to get all received Frames in the same structure.
How can I do this with the lib? Is there a documention for the lib?

I have to do both receive and send over CAN0.

regards
« Last Edit: October 24, 2013, 05:33:08 am by arduhanno » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don’t know whether this is the right use of lib but the send function works:
Code:
int can_senden(int id, int len, int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7)
{
CAN.mailbox_set_id(1, id, false);
CAN.mailbox_set_datalen(1, len);
CAN.mailbox_set_databyte(1, 0, d0);
CAN.mailbox_set_databyte(1, 1, d1);
CAN.mailbox_set_databyte(1, 2, d2);
CAN.mailbox_set_databyte(1, 3, d3);
CAN.mailbox_set_databyte(1, 4, d4);
CAN.mailbox_set_databyte(1, 5, d5);
CAN.mailbox_set_databyte(1, 6, d6);
CAN.mailbox_set_databyte(1, 7, d7);
CAN.global_send_transfer_cmd(CAN_TCR_MB1);
return 0;
}
This is my setup code:
Code:

CAN.reset_all_mailbox();
//Rx-Setup
CAN.mailbox_set_mode(0, CAN_MB_RX_MODE);
CAN.mailbox_set_id(0, TEST1_CAN_TRANSFER_ID, false);
//Tx-Setup
CAN.mailbox_set_mode(1, CAN_MB_TX_MODE);
CAN.mailbox_set_priority(1, TEST1_CAN0_TX_PRIO);
CAN.mailbox_set_accept_mask(1, 0x1FFFFFFF, false);

can_senden(TEST1_CAN_TRANSFER_ID + 0x200, 7, 'A', 'R', 'D', 'U', 'I', 'N', 'O', 0);

CAN.enable_interrupt(CAN_IER_MB0);
And this is Code for incoming frame interpretation (only test structure, I will implement bitwise interpretation). How can I receive all incoming frames with every ID or ID from 100-200? I tried to set accept mask without success. It only works with ID set in mailbox_set_id.
Code:

if (CAN.rx_avail())
{
CAN.get_rx_buff(&inFrame);
Serial.print("CAN message received= ");
Serial.print(inFrame.data[0]);
Serial.print(inFrame.data[1]);
Serial.print(inFrame.data[2]);
Serial.print(inFrame.data[3]);
Serial.print(inFrame.data[4]);
Serial.print(inFrame.data[5]);
Serial.print(inFrame.data[6]);
Serial.println(inFrame.data[7]);

if (inFrame.data[0] == 0x11)
{
LED_on();
can_senden(TEST1_CAN_TRANSFER_ID + 0x200, 6, 'L', 'E', 'D', ' ', 'O', 'N', 0, 0);
}

if (inFrame.data[0] == 0x22)
{
LED_off();
can_senden(TEST1_CAN_TRANSFER_ID + 0x200, 7, 'L', 'E', 'D', ' ', 'O', 'F', 'F', 0);
}
}

« Last Edit: October 30, 2013, 03:06:31 am by arduhanno » Logged

Earth
Offline Offline
Sr. Member
****
Karma: 14
Posts: 326
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is my setup code:
Code:

CAN.reset_all_mailbox();
//Rx-Setup
CAN.mailbox_set_mode(0, CAN_MB_RX_MODE);
CAN.mailbox_set_id(0, TEST1_CAN_TRANSFER_ID, false);
//Tx-Setup
CAN.mailbox_set_mode(1, CAN_MB_TX_MODE);
CAN.mailbox_set_priority(1, TEST1_CAN0_TX_PRIO);
CAN.mailbox_set_accept_mask(1, 0x1FFFFFFF, false);

can_senden(TEST1_CAN_TRANSFER_ID + 0x200, 7, 'A', 'R', 'D', 'U', 'I', 'N', 'O', 0);

CAN.enable_interrupt(CAN_IER_MB0);
And this is Code for incoming frame interpretation (only test structure, I will implement bitwise interpretation). How can I receive all incoming frames with every ID or ID from 100-200? I tried to set accept mask without success. It only works with ID set in mailbox_set_id.

Overall your code looked pretty decent. It should work fine. But, you wanted to know how you might accept every frame 100 to 200. I assume you mean in hex (0x100 to 0x200) and not decimal. The basic process works the same anyway.

To accept a range of message ids you need to figure out which bits they always have in common and which they do not. So, turn 0x100 and 0x200 into binary:

0x100 = 1 0000 0000
0x200 = 10 0000 0000

In between these two the bottom 8 bits will vary from 0000 0000 to 1111 1111. There is a predicament here. It would be easy to accept all frames from 0x100 to 0x1FF but 0x200 is in a different range. If it would be OK to just accept 0x100 through 0x1FF then you'd set your mask to 0x700 and your ID to match against as 0x100. This way any incoming frames are AND with the mask then compared to the match ID. Any frame 0x100 to 0x1FF will pass this test. Any other frame will not. Try it: 0x253 AND 0x700 = 0x200 (doesn't match), 0x070 AND 700 = 0 (doesn't match). 0x1B5 AND 700 = 0x100 (matches!)
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I sent a message to Palliser but I figured I'd post here as well:

I'm working on using the due can library to read the can bus of a battery management system and motor controllers for an electric racecar. I've built two shields with transceivers which appear to be functional. My setup is two dues, each using CAN0, or the labeled cantx and canrx lines. One is set up to transmit over the bus and the other is set up to receive. The setup looks like this:

https://www.dropbox.com/s/lrf63pz3mfl6s85/2013-10-26%2017.03.02.jpg
https://www.dropbox.com/s/ma2ak5gbajj547n/2013-10-26%2017.03.16.jpg

When running my code, it would seem to me from the oscilloscope that the bus is only clocking or syncing and not actually sending any data.

When probes are hooked to the pins on the arduino (cantx on transmitter, canrx on receiver) the output looks like so:

https://www.dropbox.com/s/nmzru0i89r6r11t/2013-10-26%2017.03.40.jpg

And canh and canl lines look like so:

https://www.dropbox.com/s/vic7v8wugrr4gwc/2013-10-26%2017.08.17.jpg

At this point, I'm stuck. I can't figure out what is wrong with my code or if there is something wrong with my physical setup. Can anyone see anything wrong here?

Thanks for your help,
Shep
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Anybody?

Here's my CAN_RX code if that helps (can't find the CAN_TX at the moment, I will have to search around for that if it's needed):

CAN_RX.ino:
Code:
// CAN_RX.ino
// Arduino Due - CAN Test based on CAN Sample 3
// RX Side
 
// Required libraries
#include "variant.h"
#include <due_can.h>
 
#define TEST1_CAN_COMM_MB_IDX    0
#define TEST1_CAN_TRANSFER_ID    0x07
#define TEST1_CAN0_TX_PRIO       15
#define CAN_MSG_DUMMY_DATA       0x55AAAA55
 
// CAN frame max data length
#define MAX_CAN_FRAME_DATA_LEN   8
 
uint32_t receivedFrames;
 
void setup() {
 
// start serial port at 115200 bps:
  Serial.begin(115200);
 
  // Verify CAN0 initialization, baudrate is 1Mb/s:
  if (CAN.init(SystemCoreClock, CAN_BPS_1000K)) {
 
    // Disable all CAN0 interrupts
    CAN.disable_interrupt(CAN_DISABLE_ALL_INTERRUPT_MASK);
 
    // Configure and enable interrupt of CAN0, as the tests will use receiver interrupt
    NVIC_EnableIRQ(CAN0_IRQn);
  }
  else {
    Serial.println("CAN initialization (sync) ERROR");
  }
 
}
 
// Test the transmission from CAN0 Mailbox 0 to CAN1 Mailbox 0
static void test_1(void)
{
  //Reset all CAN0 and CAN1 mailboxes:
  CAN.reset_all_mailbox();
 
  //setup four receive mailboxes that each accept a different frame id
  for (uint8_t count = 0; count < 4; count++)
  {
    CAN.mailbox_set_mode(count, CAN_MB_RX_MODE);
    CAN.mailbox_set_accept_mask(count, 0x7FF, false); //only accept the exact ID
    CAN.mailbox_set_id(count, TEST1_CAN_TRANSFER_ID + count * 4, false);
    Serial.print("ID: ");
    Serial.print(TEST1_CAN_TRANSFER_ID + count * 4);
    Serial.print("\n");
   
  }
 
  // Enable interrupt for mailboxes 0-3 on first canbus
  CAN.enable_interrupt(CAN_IER_MB0 | CAN_IER_MB1 | CAN_IER_MB2 | CAN_IER_MB3);
 
  // Wait for the communication to come in.
  Serial.print("Waiting for a frame...\n");
  Serial.print(CAN.rx_avail());
  while (!CAN.rx_avail()) { //while no frame is received
  }
 
  RX_CAN_FRAME inFrame;
  while (CAN.rx_avail()) {
      CAN.get_rx_buff(&inFrame);
      receivedFrames++;
  }
}
 
// can_example application entry point
void loop()
{
 
// Run test
while (Serial.available() == 0)
{
  Serial.print("Testing...\n");
  test_1();
  delay(8);
  Serial.print(" R: ");
  Serial.println(receivedFrames);
  Serial.print("\n");
}
 
// Disable CAN0 Controller
CAN.disable();
 
while (1) {
        }
}
Logged

Earth
Offline Offline
Sr. Member
****
Karma: 14
Posts: 326
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your CANH/L signals look awful. There is way too much slope on those signals. Are you terminating each end with 120 ohm resistors? Your pictures look to have something like 100k and 22k resistors (it's hard for me to make out all the colors) which doesn't seem to make sense unless I'm looking at the wrong thing.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your CANH/L signals look awful. There is way too much slope on those signals. Are you terminating each end with 120 ohm resistors? Your pictures look to have something like 100k and 22k resistors (it's hard for me to make out all the colors) which doesn't seem to make sense unless I'm looking at the wrong thing.

Looks like that's the error... accidentally read that off the schematic as a 120k (didn't have any in stock which is why I had the 120k+22k series combo). I'll have to solder in a 120ohm and see if it works.

Thanks for your help,
Shep
Logged

0
Offline Offline
God Member
*****
Karma: 26
Posts: 606
Always making something...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This may be a silly question, but I'd like to ask about the status of this library's API....

Specifically, is this really the final "official" API for CAN on Arduino?

The reason I ask is because this API seems to disregard many of the common conventions and the overall style of Arduino APIs.  Most communication libraries inherit Stream or mimic Stream.  The init(), rx_avail(), get_rx_buff() and sendFrame() are pretty close, but they do require users to deal with structs, which is not commonly done with Arduino APIs.  The mailbox API seems to be particularly complex, and tied to Due's specific hardware, rather than attempting to provide a simplified abstraction that most Arduino users expect, with just a few easy-to-learn functions which cover most common needs.

Another common design feature of many Arduino APIs is the use of hardware neutral base classes.  Stream doesn't neatly fit CAN.  The closest is probably Udp.h, which Arduino 1.0 added to the core library.  The idea is you can write a UDP-based library or sketch using the base class functions, and then it will work when used with different libraries (eg, both Ethernet and Wifi).  Perhaps CAN needs its own abstract base class?  This sort of abstraction seems particularly valuable for developing the higher level protocols, like ODB-II.

So my question is whether this API is now forever fixed, or if it's still in significant development, and if it is, would a migration towards a more Arduino-like API be welcome?
Logged

Pages: 1 ... 18 19 [20] 21 22 ... 29   Go Up
Jump to: