Pages: 1 ... 22 23 [24] 25 26 ... 29   Go Down
Author Topic: Building a CAN API for Arduino DUE  (Read 124813 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
God Member
*****
Karma: 26
Posts: 610
Always making something...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

can I use SN65HVD230 based can boards on arduino nano/pro micro?

No, not in any way that might actually work.  Arduino Nano and Sparkfun's Pro Micro do not have CAN bus support, so connecting only a transceiver chip would be pointless.
Logged

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

No, not in any way that might actually work.  Arduino Nano and Sparkfun's Pro Micro do not have CAN bus support, so connecting only a transceiver chip would be pointless.
not good for me....
can you prove list of arduino which has CAN bus support? (DUE comparable)
thanks in advance.
Logged

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

can you prove list of arduino which has CAN bus support? (DUE comparable)

I believe Due is the only official Arduino board that has CAN bus.  Clones of Due, like Udoo and DigiX, should have CAN bus, assuming they've copied Due closely.

On 3rd party boards, ChipKit Max32 has dual CAN bus.  As far as I know, it's currently the only other board that attempts some form of Arduino compatibility and has a published CAN library.  I looked at their library some time ago, and my initial impression was the API was even more complex and convoluted that the older version of Due's CAN library!

Teensy 3.1 has a single CAN bus, but there is currently no CAN library for Teensy 3.1 (full disclosure: I'm the creator of Teensy).  Some Maple boards might have CAN bus, but as far as I know, no easy-to-use libraries are available and there may be interrupt conflicts with USB.  I've seen conversation about people using Keil's example code.
Logged

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

Thanks Collin,

Are you sure about this statement (below). I've never heard of this and I don't know how it could work. I know that diagnostic CAN devices work very differently to normal CAN communication around a vehicle - is this what you mean?
A diagnostic device will send an incomplete (no data) frame that the target device (vehicle ECU, body control module etc) should complete and reply with. Under normal circumstances however, vehicle modules communicate by sending repeated frames at a (nearly) constant rate - for instance, engine speed from ECU to Instrument panel, Traction control torque requests from ABS module to ECU etc etc. The frames are 'broadcast' on the network and I don't think there is anything in the physical layer that could confirm frame receipt.

....The first possibility shouldn't actually drop the frame because canbus resends until somebody acks the frame. ....

Logged

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

Yes, I am sure. Here is the reasonably quick version:

Canbus is transferred such that bits are transferred by either leaving the bus alone (recessive state) or pulling H and L lines apart (dominant state). This is actually one of the reasons for the terminating resistors - they pull H and L together when nothing is asserting the dominant state. So, recessive bits are transferred when no one is doing anything to the bus and dominant bits are transferred when at least one device is asserting dominance on the bus. Back to the point at hand - ack bit. Every frame has a single bit designated as the acknowledge bit - it is basically the last bit transferred. This bit is transferred as recessive by the transmitting device. If another device properly receives the frame (has properly gotten every bit before the ack bit) then it will assert dominance on the bus and the bit will switch to dominant. The transmitting device can detect this and will know that the frame was received. If nobody sets ACK then the transmitting node will normally try to resend. It has the option of never resending, trying to resend a couple of times, or resend forever.  You can see this behavior very easily. Put an oscilloscope on an isolated device (still use a terminating resistor) and try to send a frame. You'll see the oscilloscope light up constantly without ceasing as the device tries to resend the same frame over and over looking for acknowledgement.

Thus, usually frames won't drop on the network because the transmitting node should automatically resend. The catch is that you can turn this behavior off so there isn't a guarantee that the transmitting node is attempting resends even though it could.

Thanks Collin,

Are you sure about this statement (below). I've never heard of this and I don't know how it could work. I know that diagnostic CAN devices work very differently to normal CAN communication around a vehicle - is this what you mean?
A diagnostic device will send an incomplete (no data) frame that the target device (vehicle ECU, body control module etc) should complete and reply with. Under normal circumstances however, vehicle modules communicate by sending repeated frames at a (nearly) constant rate - for instance, engine speed from ECU to Instrument panel, Traction control torque requests from ABS module to ECU etc etc. The frames are 'broadcast' on the network and I don't think there is anything in the physical layer that could confirm frame receipt.

....The first possibility shouldn't actually drop the frame because canbus resends until somebody acks the frame. ....
Logged

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

Thanks Colin, I'll look out for that.
Logged

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

1. CAN.get_rx_buff() grabs the first canbus frame in the receive buffer. The receive buffer is filled as frames come in to the RX mailboxes. There is currently no way to easily figure out which mailbox the frame came from.  The mailboxes are automatically cleared as soon as their frame is placed into the receive buffer. 

can I use CAN.mailbox_read() to get a frame from a specific mailbox? I can't work out the syntax CAN2.mailbox_read(0,frameRx0);

won't compile:

 " error: no matching function for call to 'CANRaw::mailbox_read(int, CAN_FRAME&)'
C:\Program Files (x86)\Arduino\hardware\arduino\sam\libraries\due_can/due_can.h:236: note: candidates are: uint32_t CANRaw::mailbox_read(uint8_t, volatile CAN_FRAME*) "

Logged

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

can I use CAN.mailbox_read() to get a frame from a specific mailbox? I can't work out the syntax CAN2.mailbox_read(0,frameRx0);

won't compile:

 " error: no matching function for call to 'CANRaw::mailbox_read(int, CAN_FRAME&)'
C:\Program Files (x86)\Arduino\hardware\arduino\sam\libraries\due_can/due_can.h:236: note: candidates are: uint32_t CANRaw::mailbox_read(uint8_t, volatile CAN_FRAME*) "

Yes, you can directly call mailbox_read in order to grab frames from any mailbox. However, the library automatically sets itself up for interrupt driven reception so you will have to disable that or you'll never have anything in mailboxes (the interrupt will snag it first). Clarification: Interrupts are not enabled for RX until you use SetRXFilter to create a filter. This sets up the interrupt for the mailbox that the filter is placed on. So, you can avoid this function and directly use mailbox_set_accept_mask and mailbox_set_id or you can call disable_interrupt(getMailboxIer(mailboxnum));

Then, the call to mailbox_read takes the mailbox number (0-7) and a pointer to the structure to fill. So, you'd probably want to make the call like this: CAN.mailbox_read(0, &myStruct);
Note that the function call expects the structure to already be in memory - it doesn't allocate one. So, your best bet is to allocate the structure like this: CAN_FRAME myStruct;
Logged

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

I know this might be nitpicking and it's probably far too late to change now, but...

A common convention for names in all caps and with underscores (eg, "CAN_FRAME") is for constants from #define.
Logged

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

I know this might be nitpicking and it's probably far too late to change now, but...

A common convention for names in all caps and with underscores (eg, "CAN_FRAME") is for constants from #define.

Yes, you're right. It's not a particularly great thing that the structure is named like a constant. I don't remember the how or why of how this happened. Maybe there was some insanely good reason but likely it is a mistake that never got corrected. I suppose in the interim I could create a typedef or #define to remap it to a more correct convention like CanFrame and then eventually make the actual switch.
Logged

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

Hi,

I've downloaded the library from https://github.com/collin80/due_can and trying to compile the "CAN_EchoTest" example with Arduino 1.5.6rc2 IDE without much luck. Here is the compile log, any idea ? How should this library be installed ?

Thank you!

Code:
sketch_feb22a.ino:7:21: error: variant.h: No such file or directory
In file included from C:\Users\Seb\Documents\Arduino\libraries\DueCAN/due_can.h:72,
                 from sketch_feb22a.ino:8:
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:34: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:37: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:39: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:40: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:41: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:43: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:44: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:46: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:47: error: 'uint32_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/sn65hvd234.h:48: error: expected `)' before 'Rs'
In file included from sketch_feb22a.ino:8:
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/due_can.h:76: error: 'uint8_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/due_can.h:77: error: 'uint8_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/due_can.h:131: error: 'uint64_t' does not name a type
C:\Users\Seb\Documents\Arduino\libraries\DueCAN/due_can.h:133: error: 'uint32_t' does not name a type
...
sketch_feb22a.ino: In function 'void setup()':
sketch_feb22a.ino:29: error: 'SerialUSB' was not declared in this scope
sketch_feb22a.ino: In function 'void loop()':
sketch_feb22a.ino:36: error: 'SerialUSB' was not declared in this scope
sketch_feb22a.ino:45: error: 'class CANRaw' has no member named 'init'
sketch_feb22a.ino:46: error: 'class CANRaw' has no member named 'init'
sketch_feb22a.ino:53: error: 'struct CAN_FRAME' has no member named 'id'
sketch_feb22a.ino:54: error: 'struct CAN_FRAME' has no member named 'length'
sketch_feb22a.ino:56: error: 'union BytesUnion' has no member named 'low'
sketch_feb22a.ino:58: error: 'union BytesUnion' has no member named 'high'
sketch_feb22a.ino:69: error: 'class CANRaw' has no member named 'get_rx_buff'
sketch_feb22a.ino:71: error: 'SerialUSB' was not declared in this scope
sketch_feb22a.ino:72: error: 'union BytesUnion' has no member named 'low'
sketch_feb22a.ino:73: error: 'union BytesUnion' has no member named 'high'
Logged

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

Did you select Arduino Due in the Tools > Boards menu?

Those errors look suspiciously like the kind that occur when compiling Due-specific code for an AVR-only board.
Logged

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

That was it. Thank you Paul!
Logged

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

Yes, you can directly call mailbox_read in order to grab frames from any mailbox. However, the library automatically sets itself up for interrupt driven reception so you will have to disable that or you'll never have anything in mailboxes (the interrupt will snag it first). Clarification: Interrupts are not enabled for RX until you use SetRXFilter to create a filter. This sets up the interrupt for the mailbox that the filter is placed on. So, you can avoid this function and directly use mailbox_set_accept_mask and mailbox_set_id or you can call disable_interrupt(getMailboxIer(mailboxnum));

Then, the call to mailbox_read takes the mailbox number (0-7) and a pointer to the structure to fill. So, you'd probably want to make the call like this: CAN.mailbox_read(0, &myStruct);
Note that the function call expects the structure to already be in memory - it doesn't allocate one. So, your best bet is to allocate the structure like this: CAN_FRAME myStruct;

This worked well, thankyou. I'll post some code soon

I don't quite understand how Rx'd frames are distributing into the mailboxes yet, bit more experimentation to do there.

One crucial question for me: is there any quick way of determining if the frame in a mailbox has already been read? CAN.mailbox_read(0, &canframe) doesn't seem to clear the mailbox.

Thanks so much for the help, much appreciated
Logged

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

One crucial question for me: is there any quick way of determining if the frame in a mailbox has already been read? CAN.mailbox_read(0, &canframe) doesn't seem to clear the mailbox.

Hello MarkOne,

The mailbox_get_status function checks the status of the mailbox and it can be used in conjunction with a mailbox status register (CAN_MSR_MRDY) to determine whether a mailbox has received a data frame. For example, the mailbox 4 of the CAN controller 2 receives data when the following condition is TRUE:

Quote
CAN2.mailbox_get_status(4) & CAN_MSR_MRDY

I borrowed the above condition from the CANX_Handler of the original Atmel ASF CAN library.

Also, the function mailbox_int_handler will handle a mailbox interrupt but, I've not try that yet.

Regards, Palliser
Logged

Pages: 1 ... 22 23 [24] 25 26 ... 29   Go Up
Jump to: