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.

In order to use CAN, you need transceivers, which change the digital signal (RD/TD), outputted by the LPC1768 into a differential signal, which is transmitted along the CAN bus to the other nodes. As well as this, you need two 120 Ohm terminating resistors at either end of the bus. Without both the transceivers and the terminating resistors, the bus will not work properly. Below is an example circuit, which demonstrates how to set up a CAN bus, which simply loops the data between the mbed LPC1768's two CAN buses.

/media/uploads/melse/canexample.png

Information

If using the LPC1768, or the LPC11C1X series, the transceivers are not included on the chip, so the two transceivers are required. However, if you are using the LPC11C2X series, you do not need transceivers, as they are already present on the chip. In both cases, you need terminating resistors.

Warning

The mbed's pins are 5V tolerant, so this example will work. However, do not assume that the chip you are using has 5V tolerant pins, so consult with the user manual/datasheet of your device to check this. If it is not 5V tolerant, a logic level converter can be used, to lower the logic levels to 3.3V logic.

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 library

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, int handle=0)
  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.
int  mode (Mode mode)
  Change CAN operation to the specified mode.
int  filter (unsigned int id, unsigned int mask, CANFormat format=CANAny, int handle=0)
  Filter out incomming messages.
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), IrqType type=RxIrq)
  Attach a function to call whenever a CAN frame received interrupt is generated.
template<typename T >
void  attach (T *tptr, void(T::*mptr)(void), IrqType type=RxIrq)
  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/img/boardlogos/lpc1768/pinout.png
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




5 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

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?
  2. was there an mbed library update that went backwards?
  3. damaged MCP2551
  4. some other blind-spot I'm having...

Update: I had damaged the CAN transceiver. All was well with a replacement.

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

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

Posting new comments for this page has been disabled