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!

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.

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);
    }
}

API

API summary

» Import latest build into a program

Public Member Functions

  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.
template<typename T >
void  attach (T *tptr, void(T::*mptr)(void))
  Attach a member 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

/media/uploads/chris/pinout-thumbnails_lpc.jpg
See the Pinout page for more details

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




4 related questions:

42 comments:

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:

[...]
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..

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.

25 Feb 2012

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:

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:

  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:

  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.

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));
} 
26 May 2012

Using two transceiver chips, pin 8 tied to ground on both, with a 100 ohm resistor between the two CAN bus lines (H&L), and the frequency set to 500,000 baud, I was able to send every 0.5 ms on both lines and receive (via the "attach" interrupt) on both lines.

Very nice work on the CAN library, thanks.

31 May 2012

What value puts the CAN channel into monitor mode? 0 or 1?

Prototype: void monitor( bool silent )

02 Jun 2012

Pull RS high to be silent, whenever you are just reading an existing CAN bus that already has both a Sender and a Receiver (and already has the required 120 ohm terminations).

However, to test Send to Read, CREATING a CAN bus between two transceivers, the RECEIVER must be ACTIVE, to write the final "ack" bit. So, for testing in this way, BOTH transceivers must be active, one to transmit the message, and the other to "send" the "ack" bit. Thus, both RS inputs to the transceiver chips must be "low" (active mode). Terminating this short bus usually requires two 120 ohm resistors, or one 60 ohm resistor, but usually one 100 ohm resistor would work for testing.

Just connecting the TX and RX pins of the Mbed will not work because of this requirement for the Received message to have a valid "ack" bit on the end (that the SENDER does not supply).

02 Jun 2012

Presumably a monitor(1) is Silent Mode, to Receive but not generate the "ack" bit.

If the transceiver has RS high (the HARDWARE silent mode) then the software mode would not matter.

In the Send-Receive test mode, once you have it working, setting the RECEIVER to "Silent" should stop it working.

02 Jun 2012

Question about the "attach(&myReceiver)" function:

Since a "Message Received" INTERRUPT causes myReceiver subroutine to be run, I assume that the myReceiver subroutine is running at some Interrupt level. What level?

Then, when receiving from TWO CAN buses at the same time, and I "attach" myRecv1 and myRecv1, then these two subroutines will NOT interrupt each other?

THANKS

08 Jun 2012

I'm Japanese student and not good at writing English.

When you send a frame at a time, the frame continues to flow indefinitely in the Bus. I want send a frame few times. So what can you do for an appropriate response.

09 Jun 2012

When you send a Message on the CAN bus, some receiver of that message on the same bus must "write" a final "ack" bit just exactly at the end of the message, or the sender will think that nobody received the message, and might try to re-send the same message.

So, the sender AND the receiver must have their CAN-Transceiver in ACTIVE mode. Then, the sender writes the message, the receiver writes the "ack" bit, the sender reads the "ack" bit, and the Good-Sending is finished.

14 Jun 2012

- Question removed -

UDATE: Problem solved. Wiring was not correct...

17 Aug 2012

Hi,

opening the "API Summary" links gives me an "HTTP 404" Error, anyone else with the same issue?

Maybe connected to yesterdays downtime.

17 Aug 2012

Hi Jens,

Sorry about that. It is fixed now.

Steve

25 Sep 2012

Hello,

As i understand if i want wire LPC1768 to can bus i need a tranceiver between controller and bus to converts CANRX CANTX to CANH CANL?

25 Sep 2012

Right, one CAN transceiver is needed for each CAN port. Thus, two transceivers if you are reading or writing two CAN buses.

07 Feb 2013

i need to know how to listen the CAN adress at 0x316 wich is containing the engine RPM.

07 Feb 2013

http://mbed.org/users/pangsk/code/ecu_reader/

Hi Renato , there is a nice application board for OBDII and Ecu reader code by Sukkin Pang here Regards , Christos

Posting comments for this page has been disabled