CAN Bus

03 Jun 2010

As you may have gathered, I'm doing various bug fixes and updates to the mbed library; coming up very shortly on my list is the CAN class. Could I ask what devices you, the mbed users, are talking to (or trying to talk to)?

03 Jun 2010 . Edited: 03 Jun 2010

I would like a (.attach/interrupt) (FullCAN messages can generate interrupts) function added to the CAN class

03 Jun 2010

We primarily use the SAE J1939 variant of CAN on vehicle systems talking to engine, transmission, etc.  The extended 29 bit identifier along with a 250k baud rate effectively enables J1939 communication.  I've noticed that if you try to create more than 4 CANMessage objects only the first 4 work, the others don't seem to send messages.  Look at the project can_toolbox_v1 under the account "john_r", I created a J1939 class "J1939Message" that works around the 4 CANMessage object limitation where I am just reusing the same message object for multiple messages.   Having an interrupt notification when a CAN message has been received is also a very good idea.

There is also another apparent bug in the CANMessage object,
in order to set the ID to an extended 29 bit ID you have to use the full
constructor like so:

static CANMessage canmsg_testmsg = CANMessage(0x18FF7027,testmsg_data,8,CANData,CANExtended);

if you try to create a CANMessage object then set the message ID through the field
name like so:

canmsg_tx.id = 0x18FF0027

the id does not get set correctly as shown through external CAN data monitoring.

 

Thanks for working on updating the mBed library.

 

04 Jun 2010

Thanks for mentioning these bugs, I will investigate. I do have to point out that although we do our best to make sure the libraries are correct, they are in no way MISRA compliant, and no static analysis is performed on them.

10 Jun 2010

Hi Jon,

Just in case you haven't seen it, I ran into a problem setting the CAN bus speed:

http://mbed.org/forum/bugs-suggestions/topic/540/?page=1#comment-3367

It would be great if you could make a fix, I think there are 2 issues - the frequency setting command doesn't work for all speeds or tell you if it couldn't set the frequency you ask for and secondly the segment sample point might be wrong (at least if I understood the information I was able to find at the www.kvaser.com website)

TIA

Sophie x

10 Jun 2010

Whilst we're at it, the ability to disable the self reception request by clearing bit 4 of CMR when TXing, please.

11 Jun 2010

I just thought I add this here, so this doesn't get forgotten

 

 

user avatar Jon Ward wrote:

I can confirm that the P0_21,P0_22 and P2_7,P2_8 problem is a bug. I'm working on CAN currently, so this should be fixed in the next release.

The CAN should not require the RTC crystal, it comes off of the system clock.

 

11 Jun 2010 . Edited: 11 Jun 2010

Frequency setting was already filed as a bug (and was the issue that scheduled the CAN for work next in the queue). I've added the self reception issue as another bug.

I am working on the frequency issue(s) right now. It's not set in stone yet, but we will probably do a library release with the bug fixes, and then schedule in the additional features (interrupts, acceptance filters etc.) for a separate release.

BTW - if you hadn't already seen it, there is a nice paper on CAN timings on Bosch's website: http://www.semiconductors.bosch.de/pdf/CiA99Paper.pdf

14 Jun 2010

E B - I'm having a little difficulty replicating the CAN_Message bugs you mention. Could you give me a code example that shows these issues?

14 Jun 2010

Jon,

Unfortunately the code that demonstrated the bugs has been rewritten.  I'll try to recreate it ASAP and point you to some examples.

Thanks,

- Errol

14 Jun 2010

Jon, I hacked the code below together and it demonstrates that only 3 message objects work at a time.  However, I was not able to recreate the problem setting the extended id directly on the [id] member, maybe that got fixed as it was related to some other problem in a previous mbed library version... ??

 

===================================================================

#include "mbed.h"
#include "CAN.h"
Ticker ticker;
DigitalOut can_Pca82c250SlopePin(p26);
CAN can2(p30, p29);


void send() {
static char counter = 0;
// our message data
static char testmsg1_data[8] = {0,0,0,0,0,0,0,1};
static char testmsg2_data[8] = {0,0,0,0,0,0,0,2};
static char testmsg3_data[8] = {0,0,0,0,0,0,0,3};
static char testmsg4_data[8] = {0,0,0,0,0,0,0,4};
static char testmsg5_data[8] = {0,0,0,0,0,0,0,5};
static char testmsg6_data[8] = {0,0,0,0,0,0,0,6};

// an empty object example
static CANMessage canmsg_testmsg1 = CANMessage();
// our completely defined message objects
static CANMessage canmsg_testmsg2 = CANMessage(0x18FF7227,testmsg2_data,8,CANData,CANExtended);
static CANMessage canmsg_testmsg3 = CANMessage(0x18FF7327,testmsg3_data,8,CANData,CANExtended);
static CANMessage canmsg_testmsg4 = CANMessage(0x18FF7427,testmsg4_data,8,CANData,CANExtended);
static CANMessage canmsg_testmsg5 = CANMessage(0x18FF7527,testmsg5_data,8,CANData,CANExtended);
static CANMessage canmsg_testmsg6 = CANMessage(0x18FF7127,testmsg6_data,8,CANData,CANExtended);

// set the empty object fields directly
canmsg_testmsg1.id      = 0x18FF8027;    // this appears to be working now
canmsg_testmsg1.len     = 8;
canmsg_testmsg1.format  = CANExtended;
canmsg_testmsg1.type    = CANData;

// would be nice if we could assign a pointer to the data member
// this doesn't work but is here for illustration
// canmsg_testmsg1.data = &testmsg1_data;
// maybe another way would be:
// canmsg_testmsg1.setData(&testmsg1_data);

// set data bytes
canmsg_testmsg1.data[5] = counter;
testmsg1_data[1] = counter;
testmsg2_data[2] = counter;
testmsg3_data[3] = counter;
testmsg4_data[4] = counter;
testmsg5_data[5] = counter;
testmsg6_data[6] = counter;

// send messages
can2.write(canmsg_testmsg1); // visible on bus
can2.write(canmsg_testmsg2); // visible on bus
can2.write(canmsg_testmsg3); // visible on bus
can2.write(canmsg_testmsg4); // bug: not visible on bus
can2.write(canmsg_testmsg5); // bug: not visible on bus
can2.write(canmsg_testmsg6); // bug: not visible on bus
// increment the counter
counter++;
}
int main() {
can2.frequency(250000);
can_Pca82c250SlopePin = 0;
ticker.attach(&send, 0.250f);
while (1) {
;; // don't end
}
}

==========================================================

 

 

15 Jun 2010 . Edited: 15 Jun 2010

OK, the problem with the 4th message not appearing on the bus, is that the CAN block only has three transmitter nuffers, the .write() method is non-blocking and there is no queue. When you request the 4th .write(), all three transmitter buffers are still busy, which is why the message gets lost. Try adding a small wait between the writes, and the data should appear on the bus.

The .write() method does return a zero if it did not find a free transmitter buffer (and a 1 if it did), so you could check to see if your message did get added (and try again if it did not). I shall investigate modifying the CAN class to assist in making this a all a bit easier.

15 Jun 2010

Further to this, I wrote a little function which spins on the write, to see if it was successful:

void csend(CANMessage cm) {
    int i;
    do {
        i = can2.write(cm);
    } while (!i);
}
I then replaced all the can2.write() calls with csend(). I thus get this out the other end:

Message: ID 18FF8027 length 8 00 00 00 00 00 01 00 00
Message: ID 18FF7227 length 8 00 00 00 00 00 00 00 02
Message: ID 18FF7327 length 8 00 00 00 00 00 00 00 03
Message: ID 18FF7127 length 8 00 00 00 00 00 00 00 06
Message: ID 18FF7427 length 8 00 00 00 00 00 00 00 04
Message: ID 18FF7527 length 8 00 00 00 00 00 00 00 05
Message: ID 18FF8027 length 8 00 00 00 00 00 02 00 00
Message: ID 18FF7227 length 8 00 00 00 00 00 00 00 02
Message: ID 18FF7327 length 8 00 00 00 00 00 00 00 03
Message: ID 18FF7127 length 8 00 00 00 00 00 00 00 06
Message: ID 18FF7427 length 8 00 00 00 00 00 00 00 04
Message: ID 18FF7527 length 8 00 00 00 00 00 00 00 05
Message: ID 18FF8027 length 8 00 00 00 00 00 03 00 00 

15 Jun 2010

I see that your pounding on the write command until it sends the message.  This would work great except for some apps one might not want to block the caller.  I guess I was not aware that the write method returned true on successful send.  Implementing a queue in the CAN class would be very cool.  Then again, your intention may be to expose enough of the CANMessage class that the user can implement those features themselves.

Thanks for working on this Jon!

 

16 Jun 2010 . Edited: 16 Jun 2010

It was only a quick'n'dirty little bit of code, to demonstrate how you could get the messages out as fast as possible. It obviously is not the desired way of doing it in a real system.

I'll close those two bugs (ID's not setting correctly, 4th CAN message not transmitting), but will investigate updating the class to make it easier to check if a transmit buffer is free.

17 Jun 2010

Library version 23 is now live, and should fix the frequency and self-transmit problems. Any problems, drop a line in the Bugs & Suggestions forum!

19 Jun 2010

Sorry for the late post, I just got my mBed.  Maybe this request could make it into the next CAN library release. 

Could you add a timestamp to the CANMessage class type?  The timestamp would be written by the library at the time the message is sent or received on the bus.  The timer could be a free running timer with a resoution of microseconds or milliseconds.  The timer would rollover back to 0 once it reaches it's maximum value.  This would be very useful for CAN BUS monitoring applications and doing precission timing between CAN messages.

The length of the timestamp should be 3 bytes if resolution is milliseconds.  This gives a total span of 279 minutes.

The length of the timestamp should be 4 bytes if resolution is microseconds.  This gives a total span of 71 minutes.

I hope you find this idea useful for implementation!

 

19 Jun 2010

I am extremely reluctant to put that functionality in, for many reasons:

  1. It would require turning the CAN class into an interrupt driven one, which is not desirable as a default (although I am looking at making an interrupt handler an option).
  2. It adds functionality to a class which not everybody needs, but would impact all users of the class.
  3. It starts combining the functionality of existing classes, which really is a user-level operation.

All that being said, I am implementing a CAN Monitoring class for use with my own debugging and when I have something I am happy with, I'll publish it.

19 Jun 2010 . Edited: 19 Jun 2010
user avatar Jon Ward wrote:

I am extremely reluctant to put that functionality in, for many reasons:

  1. It would require turning the CAN class into an interrupt driven one, which is not desirable as a default (although I am looking at making an interrupt handler an option).
  2. It adds functionality to a class which not everybody needs, but would impact all users of the class.
  3. It starts combining the functionality of existing classes, which really is a user-level operation.

All that being said, I am implementing a CAN Monitoring class for use with my own debugging and when I have something I am happy with, I'll publish it.

Thanks for the prompt reply Jon.  I understand your position, your points makes perfect sense.  I'd love to see your CAN monitor when it's completed. 

This is my first mBed and I wanted to tell you guys how much I like it.  I feel like a child on Christmas morning playing with all of the new toys!  The mBed is what I always wanted the Basic Stamp to be- powerful, lots of RAM and C++.  I'm amazed how easy it was to get this thing up and running. 

I could implement the timestamps in my program code but not being sure how the underlying library works makes me question how accurate my timestamps would be.  The time at which the program code fetches the CAN message will likely not be the same time that it actually came in on the bus.  I'm looking for millisecond accuracy so I'm thinking that if I keep the program code in a tight loop I would get that accuracy.  I just need to be careful that my program code does not get too big and I start missing messages.  Full CAN bus at 500K is ~220us per message.  Perhaps the mBed is not the most ideal device for this application but it sure is fun to program this thing- engineering is always a trade-off.

I put together some timestamp test code and it seems to work pretty good. 

EDIT: more quetions, perhaps I should have started a new thread but...

1) Am I using the same basic concept that you were thinking of using in your CAN monitor? 

2) Is there any way to tell if there was a CAN buffer overflow,  to indicate that some of the messages were missed?

3) Are the transmitted and received CAN messages buffered?  If so, how big are the buffers?  If the application code keeps track of the time stamps then the timestamp would not be accurate if the messages are waiting in a buffer to be received or transmitted.

#include "mbed.h"
#include "CAN.h"

Ticker ticker;

DigitalOut led1(LED1);
DigitalOut led2(LED2);

// CAN1 Controller
CAN can1(p9, p10);

// CAN2 Controller
CAN can2(p30, p29);

// USB
Serial pc(USBTX, USBRX); // tx, rx

int main()
{

    // USB Serail Port baud rate
    pc.baud(230400);

    // 125kbit/s
    can1.frequency(200000);

    // 500kbit/s
    can2.frequency(500000);


    // create message object for message reception
    CANMessage can_MsgRx;
   
    // timer
    Timer FreeRunningTimer;
   
    int TimeStamp;

     pc.printf("Connected to mBed...\n\r");
    
     FreeRunningTimer.start();

    while (1)
    {

        if (can2.read(can_MsgRx))
        {
            TimeStamp = FreeRunningTimer.read_us();
           
            pc.printf("%d %04X ", TimeStamp, can_MsgRx.id);
           
            for (char i=0; i<can_MsgRx.len; i++)
            {
                pc.printf("%02X ", can_MsgRx.data[i]);
            }
           
            printf("\n\r");
           
            // any incoming message: toggle led2
            led2 = !led2;
        }

    }
}

 

08 Jul 2010

Version 24 of the library has been released, which adds the attach() method for the CAN, adds a silent monitor mode, and also tweaks the sample point.

24 Nov 2010

John,

Early on, you asked what we're connecting to.  I want to connect to the CAN bus on my Prius hybrid.

I'm having issues with the example CAN code, but haven't done a thorough search on the blogs yet. It seems I never receive anything. I assume 9 connects to 30, 10 to 29 for the direct test (no bus needed).  I've also swapped them and had no luck.

25 Nov 2010

Idea:

Either overloaded frequency command or 'timing' function

with TSeg1, TSeg2, SJW, Prescaler as parameters, allow the user to directly set the Baud rate and timing point.

30 Nov 2010

Jon,

I was wondering if you ever finished that CAN Monitoring Class that you mentioned in your post from 19June2010?  If so, could you share that with us?  Thanks!

04 Feb 2011

Hi,

I'm experiencing the same problem as Dave Filicicchia. When connecting CAN1 directly to CAN2, all I get is: {... loop() send() wloop() Message sent: 132 loop() ...} ((I changed printf to pc.printf, so I can read the messages in moserial(Ubuntu terminal thing)))

I've tried connecting a transceiver with TxD/RxD on p9,10 side and CANH/CANL on the p29,30 side, to no effect. However, when I switch the TxD and RxD around (the way I'm pretty sure they're connected the wrong way around...) I get:

{... loop() Message received: 268468212 loop() Message received: 268468212 send() loop() ...} ((I changed the read code to msg.data (where it was msg.data[0])))

This seems cool, but there's no more actual data being sent, and I'm pretty sure the data received is rubbish, because it looks nothing like the 1337 data that we're sending? I also tried switching the pins around with different counter states, but that doesn't changed the received data, which confirms the thought that the received data has nothing to do with the sent data. Bit of a mystery this one.

Either I'm missing something, or I need a transceiver on both sides... OR because of the CAN protocol, one node can't send and receive at the same time, making this attempt to read our own data futile.

Any thoughts? Also, does anyone have experience with CAN-Festival?

05 Feb 2011

I saw Melchior's message just recently. I ended up going for broke and just connecting to the CAN bus on my Prius. I used the MCP2551 transceiver. No problems receiving plenty of messages at 500k baud; if only I could find the correlation to the addresses and the type of data. Internet searches turn up only data for older Prius messages; none of the addresses match on the 2010 Prius (Generation 3). Does anyone have recent data for what addresses are which function?

The mbed CAN td and rd (pins 29 and 30) connect to the MCP2551 pins 1 and 4 (TXD and RXD) of the transceiver respectively.

Jon, thanks for the silent monitor mode; it works great on the Prius.

Sorry, have not heard of CAN-Festival.

05 Feb 2011

Hello Melchior,

yes, on each CAN canal you need a transceiver and then connect the output of the transceiver = the CAN-Bus itself together CAN-H to CAN-H and CAN-L to CAN-L. In all other cases the CAN is not working!

06 Feb 2011

dedo T wrote:

Hello Melchior,

yes, on each CAN canal you need a transceiver and then connect the output of the transceiver = the CAN-Bus itself together CAN-H to CAN-H and CAN-L to CAN-L. In all other cases the CAN is not working!

You also need to add a 120 Ohm termination resistor between CAN-H and CAN-L at the furthers two ends of the CAN network. Since the network is so short on your breadboard, you can add just one equivalent resistor of 60 Ohms between CAN-H and CAN-L. (remember that two resistors in parallel equate to 1/R = 1/R1 + 1/R2).

07 Feb 2011

CAN-Festival should help in looking into Object Directories on the CANdevices. However, it runs on Linux. I did the ./configure, make and sudo make install thing, but that was as far as my Linux knowledge got me :p It installed, but I can't seem to find anything useful that was installed :\ No applications, nothing.

I'm going to try and set up the CAN network today. And once I got that running I'll try and connect a Servomotor and control it via CAN. Will let you know how it goes.

10 Feb 2011

Hey,

Quote:

So I have 1 transceiver hooked up to p29 and p30 and my terminal says I'm sending messages. Now using the example code, I want to broadcast a status request to all nodes (I have a CAN compatible servomotor hooked up on the bus). I'll change the receiving side of the code to CAN2 as well, so CAN2 is able to write and read messages and send the data received to my terminal. If I change the CANMessage(1337, &counter, 1) to an NMT requesting the state of all nodes, I should receive the servo's ID and status, right?

I assume 1337 translates to 01011011111 as a node ID? So I have to use oct. numbering? So 700Hex = 11100000000b = 3400oct? (700, according to the Peer-to-Peer objects of the CANopen Predefined Master/Slave Connection Set, means NMT error control and is used in the examples of the manual for status requests: http://www.nikhef.nl/pub/departments/ct/po/doc/CANopen30.pdf) Officialy it says to use 700+node_ID, but I don't know the ID of the servo and I have no clue how to acquire it, so I hope 700 will adress all nodes..

CANMessage(node_ID,data,length,type,format)

CANMessage(3400,0?,0?,CANRemote,CANStandard)

Am I in the right direction here?

So in the mean time I have gone back to the original example program and hooked up a second transceiver. I added some printf things to show me all the data of the read message. I've figured out the way the CANMessage is built up. It's all running smoothly.

But now that I have the servomotor connected I can't seem to get it to respond to any of my messages. Also I don't seem to understand how to acquire the servo's node_ID.

Any thoughts?

Thanks,

Melchior

10 Feb 2011

Hey,

Does anyone have an idea how to inquire the node_ID of a servomotor I have connected? http://www.faulhaber-group.com/uploadpk/EN_CANopen_FAULHABER_CAN_im_DFF.pdf I've been reading through that, I don't have the software they use.

On every manual I find they get started on how to start up nodes and put them in opperational mode. And then all of a sudden they start sending messages with Function + node_ID... and I'm like, where on earth did we somehow know what the node_ID is??

I've been trying for a while now :p need a hint in the right direction!

Thanks,

Melchior