Recent changes
Order
tag order
CMSIS RTOS
RTOS
mbed Website Releases
Help
Firmware
Homepage
From the mbed microcontroller Handbook.  

CAN

CAN or Controller-area Network is a bus standard designed to allow microcontrollers and devices to communicate with each other without a host computer.

Hello World!

Loopback example

#include "mbed.h"

Ticker ticker;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
CAN can1(p9, p10);
CAN can2(p30, p29);
char counter = 0;

void send() {
    printf("send()\n");
    if(can1.write(CANMessage(1337, &counter, 1))) {
        printf("wloop()\n");
        counter++;
        printf("Message sent: %d\n", counter);
    } 
    led1 = !led1;
}

int main() {
    printf("main()\n");
    ticker.attach(&send, 1);
    CANMessage msg;
    while(1) {
        printf("loop()\n");
        if(can2.read(msg)) {
            printf("Message received: %d\n", msg.data[0]);
            led2 = !led2;
        } 
        wait(0.2);
    }
}

This example sends from one CAN bus (can1) an counter while it is listen on the other CAN bus (can2) to receive a packet. Each bus controller should be connected to a CAN bus transceiver. These should be connected together at a CAN bus.

API

API summary

CANMessage
Functions
CANMessageCreates empty CAN message.
CANMessageCreates CAN message with specific content.
CANMessageCreates CAN remote message.
Variables
idThe message id.
dataSpace for 8 byte payload.
lenLength of data in bytes.
formatDefines if the message has standard or extended format.
typeDefines the type of a message.
CANA can bus client, used for communicating with can devices
Functions
CANCreates an CAN interface connected to specific pins.
frequencySet the frequency of the CAN interface
writeWrite a CANMessage to the bus.
readRead a CANMessage from the bus.
resetReset CAN interface.
monitorPuts or removes the CAN interface into silent monitoring mode
rderrorReturns number of read errors to detect read overflow errors.
tderrorReturns number of write errors to detect write overflow errors.
attachAttach a function to call whenever a CAN frame received interrupt is generated.
class CANMessage : public CAN_Message
CANMessage()
Creates empty CAN message.
unsigned int id
The message id.
unsigned char data[8]
Space for 8 byte payload.
unsigned char len
Length of data in bytes.
CANFormat format
Defines if the message has standard or extended format.
CANType type
Defines the type of a message.
class CAN : public Base
A can bus client, used for communicating with can devices
CAN(PinName rd,
PinName td)
Creates an CAN interface connected to specific pins.
int frequency(int hz)
Set the frequency of the CAN interface
int write(CANMessage msg)
Write a CANMessage to the bus.
int read(CANMessage &msg)
Read a CANMessage from the bus.
void reset()
Reset CAN interface.
void monitor(bool silent)
Puts or removes the CAN interface into silent monitoring mode
unsigned char rderror()
Returns number of read errors to detect read overflow errors.
unsigned char tderror()
Returns number of write errors to detect write overflow errors.
void attach(void (*fptr)(void))
Attach a function to call whenever a CAN frame received interrupt is generated.

Details

The CAN Interface can be used on mbed pins p9/p10 and p30/p29

The CAN Interface can be used to write data words out of a CAN port and will return the data received from another CAN device. The CAN clock frequency can be configured.

Resources




calendar Page history
Last modified 16 Oct 2010, by   user Simon Ford   tag No tags | 28 comments  

28 comments on CAN:

16 Aug 2010

I'm glad so there is one more CAN in mbed, but you could repair that picture :) http://mbed.org/media/uploads/simon/mbedmicrocontrollerpinout4.png There is drawn only one CAN

16 Oct 2010

The "Details" note says - The CAN Interface can be used on mbed pins p9/p19 and p30/p29. but should say The CAN Interface can be used on mbed pins p9/p10 and p30/p29.

16 Oct 2010

In the example, ticker activates Send, and Send has the stack variable "counter" which is initialized to zero on each entry. Am I missing something that the value of counter will always be sent as zero? When successfully sent, the value is incremented, but then the Send function exits, and that value is lost to the stack frame.

16 Oct 2010

Thanks, fixed.

28 Oct 2010

whats the wiring for this example to work? I also posted this question in the forums.

08 Dec 2010

I plan to control a power-servo-motor (220V) via CANopen. Are there any libraries for CANopen around? Thank you, Juergen

20 Dec 2010

What is the default frequency? how it can be changed?

14 Jan 2011

Is there a way to specify the crc polynomial?

18 Jan 2011

yes, there is a spec for CAN V2.0B: http://www.hehlhans.de/bilder/autos/cdi270/comand/can2spec.pdf The polynome is discribed at Part A - page 13

But you do not need to know this! This polynome is calculated from the CAN-HW-Controller, and, if the crc is wrong on the transmission of a can frame, the HW will automaticaly repeat the can frame again, to enshure, that it will be transmitted correctly. All this stuf is done by the CAN-HW, and you need not think about it on sw side. This is the benefit from a can controller.

20 Jan 2011

Can this example be tested by simply wiring 9 to 30 and 10 to 29? or do I need a CAN bus tranceiver in the middle

20 Jan 2011

I think it should work, but don't forget to cross TX & RX.

if you do use two CAN trancivers, you will also need 250 Ohms bus loading.

06 Feb 2011

Can the CAN API be modified to include another variation of attach, similar to ticker:

template<typename T> void attach_us( T * tptr, void (T::*mptr)(void) )

Attach a function to call whenever a CAN frame received interrupt is generated.

Variables tptr pointer to the object to call the member function on mptr pointer to the member function to be called

06 Feb 2011

Hi David,

Sounds like a good request; now added to the Bugs and Suggestions page.

Thanks, Simon

14 Feb 2011

"Hello World"

I want to put a CAN frame in a .txt file. When i write can_MsgRx.id in a table,my program compile and run but the mbed is not recognize by my computer. Do you have any idea ? I'm sorry for my english, i'm french.

Thanks

François

18 Mar 2011

user dedo T wrote:

yes, there is a spec for CAN V2.0B: http://www.hehlhans.de/bilder/autos/cdi270/comand/can2spec.pdf The polynome is discribed at Part A - page 13

But you do not need to know this! This polynome is calculated from the CAN-HW-Controller, and, if the crc is wrong on the transmission of a can frame, the HW will automaticaly repeat the can frame again, to enshure, that it will be transmitted correctly. All this stuf is done by the CAN-HW, and you need not think about it on sw side. This is the benefit from a can controller.

I just read up on your reply on changing a CAN CRC, it turns out that the mbed has the CRC hard coded and it can't be modified. The only way is to get an external Controller and communicate to it over SPI.

Lame...

06 Jun 2011

Could someone build, test, and confirm the minimal CAN sample is working for them?

I may have damaged the CAN interface on my mbed, and an independent verification would help. This is confusing, because I can wiggle the CAN pins as DigitalInOut signals, but even simple CAN code fails to communicate successfully.

CAN hardware: I have MCP2551 transceivers wired to each channel, powered by +5v, RS tied low, terminated w/120 ohm, and the CAN pairs tied together (H to H, L to L). This configuration was working for me a while back and verified with a USB to CAN adapter as the 3rd node on a baseboard I designed. I turned to other experiments, and a couple months later I came back to this and cannot seem to get CAN to work - even with the mbed on a protoboard. Quite confusing.

Confusing questions in my mind -

  1. how could I have damaged CAN in the LPC1768, but can still control the IO pins? [seems unlikely]
  2. was there an mbed library update that went backwards?
  3. damaged MCP2551 [possible]
  4. some other blind-spot I'm having... [most likely]
06 Jun 2011

Hi David, From ywhat you said, it seems the problem is in the hardware connections (since you said it was working before) Also, it is important to know that the CAN tranceiver is eletrostatic device...so it could be possible that your MCP2551 is damaged!

10 Jun 2011

user David Smart wrote:

Could someone build, test, and confirm the minimal CAN sample is working for them?

Have you seen this page with a minimal setup including transceiver or did you mean that with "confirm the minimal CAN sample" *confused* ? http://mbed.org/projects/cookbook/wiki/CanBusExample1

11 Jun 2011

Hi Kevin, I was hoping that somebody had the simple configuration of CAN 1 wired to CAN 2 and a serial port to the PC. Then the sample at the top of this page should work and could be confirmed.

This would quickly eliminate possibility #2 from my list of possible failure modes (I numbered them for reference). #3 (damaged CAN transceiver) is the most likely problem, and I'll be pursuing that path later today.

I have never tried looping CAN 1 to CAN 2 w/o a CAN transceiver in the path, but this would then let me plug the mbed into the white proto-block and eliminate my [soldered in] hardware.

11 Jun 2011

I can confirm that the loopback example (top of this page) works.
see edit below

  • Hardware configuration:
    DIP pin 10 (CAN_TX1) directly wired to DIP pin 30 (CAN_RX2)
    and
    DIP pin 9 (CAN_RX1) directly wired to DIP pin 29 (CAN_TX2)
    (pin-name-source: mbed-002.1.pdf, page 2)

  • My MBED:
    mbed NXP LPC2368
    Board rev: mbed-002.2 with Firmware version: 16457

  • Software:
    copy&paste of the code above into a new project. (mbed lib@rev28))

  • Serial line output:

Code

[...]
loop()
loop()
send()
wloop()
Message sent: 38
loop()
loop()
loop()
loop()
loop()
send()
wloop()
Message sent: 39
loop()
[...]



edit:
whoops.. dumb c&p without reading the code.. :(
It seems that the message is never received by can2..

Code

if(can2.read(msg))

is never true..

is there any initialization missing? .. i don't see it at the moment..

14 Jun 2011

Hi Kevin, Unfortunately, your test probably isn't valid without the transceivers. CAN will simultaneously receive while it transmits. As you described the wiring, it won't see the network while it transmits. Also, towards the tail end of a packet is a special bit period where other nodes on the network actively "ack" the receipt of the packet. This informs the transmitter that at least one node saw the message. Without these extra elements working as designed, the CAN controller will end up in an error condition. This circuit would work - CAN Feedback test

If you tried connecting the pairs of RD and TD together, then you would have two output pins fighting each other, so this is not recommended.

15 Jun 2011

Hi David, thanks for clarifying. - I should have known that this would not work... embarrassing.
So far I've never tried it without a transceiver and was just curious and did not think much about it..
At the moment i don't have 2 transceivers next to me, sorry.
(If there is anything else i can test, feel free to ask.)

22 Jun 2011

Suggestion - can we have a way to set the CAN network frequency in the class's constructor (either another parameter, or in a constructor/initializer)?

I'm worried about initializing a CAN connection on a "live" CAN bus without setting the frequency at the same time - the mbed's CAN controller could possibly start transmitting error frames to other nodes on the network before it hits the frequency() statement, as we currently have to do it.

Thanks!

23 Jun 2011

user Hakam abubaha wrote:

What is the default frequency? how it can be changed?

Hakam,

I measure a default bit time as 10 μs. That would make the default frequency 100 kHz.

moments ago

Hello,

how can i force my MBED to tx data (from array) to the bus. Always the compiler stops with message that the constructor does not match my code:

void send1000ms () { data_ptr_msg_tx2[7] = 0x80;

build can message from unsigned char data_ptr_msg_tx2[8] = {0,0,0,0,0,0,0,0}; CANMessage can_msg_tx2(0x585, &data_ptr_msg_tx2, 8); system info

can transmission if (can2.write(can_msg_tx2) == 1) { message transmitted led2 = 1; }

} end of void send1000ms ()

25 Feb 2012

Hi Patrick, please use the <<code>> and <</code>> tags to keep source code readable. See Editing tips below.

I think what your tried to do is this:

Code

void send1000ms () {
  //define the databytes of the CAN message
  unsigned char data_ptr_msg_tx2[8] = {0,0,0,0,0,0,0,0};

  // build can message from system info
  data_ptr_msg_tx2[7] = 0x80;

  CANMessage can_msg_tx2(0x585, &data_ptr_msg_tx2, 8); 

  // can transmission
  if (can2.write(can_msg_tx2) == 1) {
    // message transmitted
    led2 = 1;
  }

} // end of void send1000ms ()

The problem is in the constructor for CANMessage:

Code

  CANMessage can_msg_tx2(0x585, &data_ptr_msg_tx2, 8); 

The second parameter should be a pointer to the databytes. You have defined data_ptr_msg_tx2 as an array of 8 bytes. You now need a pointer to the array. That is in fact just the name of the array 'data_ptr_msg_tx2' or a pointer to the first element if that array: &data_ptr_msg_tx2[0].

So try this:

Code

  CANMessage can_msg_tx2(0x585, data_ptr_msg_tx2, 8); 
25 Feb 2012

Hello Wim,

thank you, with your help i could fix my problem. Next time i will use the tags to kepp code readable.

Best regards, Patrick

19 Mar 2012

In case anyone is wondering how to convert other datatypes (float, double, etc.) to char arrays in order to transmit through CAN, here's how it's done. Just make sure to match the correct number of bytes for the datatype.

Code

float p = 1.23;
if(can1.write(CANMessage(1337, (char *)&p, 4))) {
    printf("Message sent: %f\n\r", p);
}

if(can2.read(msg)) {
    printf("Message received: %f\n\r", *((float *)msg.data));
} 

Please login to post comments.