mbed as USB2CAN adapter project

23 Feb 2011

Hello there,

I'm trying to set up my mbed as a USB2CAN adapter. I've made a little program that is able to send a list of messages on regular intervals and I'm working on an addition that makes it possible to compile the messages from data you send from your terminal application.

However, my eventual goal is to be able to link the mbed to CANfestival. This is an open source program that you can use to easily setup virtual nodes on your PC. It has an Object Dictionary Editor and such, to make it easier.

I want to set up a simple master node on my Ubuntu PC that sends the basic nodeguarding messages. Further more I'd like to be able to read the entire Object Dictionary of the Servomotor I have connected to the mbed canbus.

CANFestival, like the mbed, lets you set the ID, data, length, type and format (msgdata) of a CANmessage and sends it according to protocol. So I'm thinking, once I have a master node set up to transmit through USB to the mbed, I can just stringcopy the message to the mbed canbus somehow?

If string copy doesn't work I'll have to extract the msgdata from the usb transmission somehow and use the mbed to compile a new canmessage out of it.

I want to keep it as simple as possible though.

Are there any tips on how to transfer the USB data to a mbed can message?

Also is there any way of printing the full message through can.read(msg)? So far I'm only able to print the msgdata, but not the whole frame.

I'll post my progress and upload the code once it's done, so other people can use the mbed as an adapter as well!

Thanks in advance for any tips you might have!

Melchior

24 Feb 2011

First working version, lets you send commands from your terminal. I've been messing around with the serial.readable() and can.read() quite a bit. But in the end they are working together nicely.

Import programUSB2CAN

First version of a mbed USB2CAN adapter Let\'s you send can messages via can. Type as !format_type_ID_length_d0_d1_d2_d3_d4_d5_d6_d7 (! is used to recognize valid messages, anything without a ! in front of it is dumped) All messages transmitted over cCAN are printed to your terminal as well.

Any code tips are welcome.

The next step will be to implement a CANFestival application!

Melchior

24 Feb 2011

I downloaded it and will play with it over the weekend and let you know my comments.

Melchior Pau wrote:

First version of a mbed USB2CAN adapter Let\'s you send can messages via can.

I think you meant to say "send can messages via USB"?

Melchior Pau wrote:

The next step will be to implement a CANFestival application!

What do you mean by "CANFestival"?

25 Feb 2011

Hey Freddie,

Enjoy the play :) You'll need an external powersource and 2 CAN transceivers and all that in order to run it. And ofcourse a CAN compatible device is handy to see if there's any responces to the messages. But you can also just monitor the messages that you are sending. Don't need to have a device connected to the CAN network in order for the program to work.

  • Via usb yea, will fix that in the next version! You type the messages in your terminal and it sends it via usb. The mbed converts it into a CANMessage.
  • CANFestival is a open source program with which you can read and write your Object Dictionaries. It has a couple of example programs with which you can set up your desired virtual master node that will operate your CAN network. There's a few GUI's but most of it's source code (drivers, libraries and examples) which you have to compile. I have it installed on my Ubuntu machine but I still need to find out allot about it. As I said that'll be the next step :) And it might be a big one too! (http://canfestival.org for more information)

Looking forward to hear from you! Have a nice weekend.

Melchior

10 Mar 2011

A simple .c file, compiled with Eclipse Helios, that you can run to send some messages. It requires you to change line 60 (in the pc_msg_read function) to pc.scanf("%[^\x0d]s",pc_msg);

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>

int input;
int output;
char *commando;

main() {
   input = open("/dev/ttyACM0",  O_RDONLY | O_NOCTTY | O_NDELAY);      //open the terminal keyboard
   output = open("/dev/ttyACM0",  O_WRONLY | O_NOCTTY | O_NDELAY);     //open the terminal screen

   if (!input || !output) {
      fprintf(stderr, "Unable to open /dev/ttyACM0\n");
      exit(1);
   }
   commando="!0 0 0 2 81 3 0 0 0 0 0 0\x0d";
   write(output,commando,strlen(commando));
   sleep(1);
   commando="!0 0 0 2 1 3 0 0 0 0 0 0\x0d";
   write(output,commando,strlen(commando));
   sleep(1);
   commando="!0 0 771 5 fd ff ff ff ff 0 0 0\x0d";
   write(output,commando,strlen(commando));
   sleep(1);
   commando="!0 0 771 5 f 0 0 0 0 0 0 0\x0d";
   write(output,commando,strlen(commando));
   sleep(1);
   commando="!0 0 771 5 93 ff 0 0 0 0 0 0\x0d";
   write(output,commando,strlen(commando));
}  //end of main

With your terminal open, also connected to ttyACM0, you can see the messages beeing sent perfectly.

Entered:0 0 0 2 81 3 0 0 0 0 0 0
Sent: [ ID: 0 length: 2 data: 81 3 0 0 0 0 0 0 type: 0 format: 0 ]
Message compiled and sent.
Please enter any additional commands in the same manner.
Read: [ ID: 0 Length: 2 Data: 81 3 0 0 0 0 0 0 Type: 0 Format: 0 ]
Read: [ ID: 1795 Length: 1 Data: 0 3 0 0 0 0 0 0 Type: 0 Format: 0 ]
Entered:0 0 0 2 1 3 0 0 0 0 0 0
Sent: [ ID: 0 length: 2 data: 1 3 0 0 0 0 0 0 type: 0 format: 0 ]
Message compiled and sent.
Please enter any additional commands in the same manner.
Read: [ ID: 0 Length: 2 Data: 1 3 0 0 0 0 0 0 Type: 0 Format: 0 ]
Entered:0 0 771 5 fd ff ff ff ff 0 0 0
Sent: [ ID: 771 length: 5 data: fd ff ff ff ff 0 0 0 type: 0 format: 0 ]
Message compiled and sent.
Please enter any additional commands in the same manner.
Read: [ ID: 771 Length: 5 Data: fd ff ff ff ff 0 0 0 Type: 0 Format: 0 ]
Entered:0 0 771 5 f 0 0 0 0 0 0 0
Sent: [ ID: 771 length: 5 data: f 0 0 0 0 0 0 0 type: 0 format: 0 ]
Message compiled and sent.
Please enter any additional commands in the same manner.
Read: [ ID: 771 Length: 5 Data: f 0 0 0 0 0 0 0 Type: 0 Format: 0 ]
Entered:0 0 771 5 93 ff 0 0 0 0 0 0
Sent: [ ID: 771 length: 5 data: 93 ff 0 0 0 0 0 0 type: 0 format: 0 ]
Message compiled and sent.
Please enter any additional commands in the same manner.
Read: [ ID: 771 Length: 5 Data: 93 ff 0 0 0 0 0 0 Type: 0 Format: 0 ]
10 Mar 2011

A few of the baseboards listed support CAN. As noted above, most if not all CAN transceivers do require a 5v supply. self-plug: I designed a baseboard based on a specific need for CAN. You may find the schematic or the test code useful.

15 Mar 2011

Melchior,

You can actually loop back your CAN (1 or 2) device without being the can driver chip in place by simply connecting the tx pin to it's corresponding rx pin via an 270 ohm resistor in this way I had dry tested my coding effort before I received the CAN bus driver chip and had a target to monitor, in this way you don't need to use the second CAN device and will be able to send / monitor using one CAN device

Hope this helps in testing your code / interface

Paul

22 Mar 2011

The code is missing allot of data on the CANbus. Installed an IXXAT USB2CAN adapter to compare the data. the IXXAT sees allot more then my mbed monitor. Will try to fix this.

I fixed it in my ETH2CAN project.

Import programETH2CAN

A program that allows you to send CANMessages from your PC via ethernet.

It seems that the pc.readable() is fighting the can.read() in the USB2CAN project tho. Will have to look at that later.

22 Mar 2011

Melchior,

You may want to investigate the code example from SKPang http://www.skpang.co.uk/catalog/product_info.php?products_id=741 being the ecu_reader, I have added a function raw read to it which seems to capture all data (but only if engine is running !) code is:

#define PID_REQUEST         0x7DF
#define PID_REPLY           0x7E8

#define TIMEOUT 200

// Use a timer to see if things take too long
Timer CANTimer; 

unsigned char raw(unsigned char pid,  char *buffer) {
    
    int can_ts;

    CANTimer.reset();
    CANTimer.start();
       
    while(CANTimer.read_ms() < TIMEOUT) {

        if (can2.read(can_MsgRx)) {
                        
            can_ts = FR_Timer.read_us();

            sprintf(buffer, " %4x | %2x %2x %2x %2x %2x %2x %2x %2x | %d | %d | %d | %10.6f\r\n", can_MsgRx.id,  can_MsgRx.data[0], \
            can_MsgRx.data[1], can_MsgRx.data[2], can_MsgRx.data[3], can_MsgRx.data[4], can_MsgRx.data[5], \
            can_MsgRx.data[6], can_MsgRx.data[7], can_MsgRx.len, can_MsgRx.type, can_MsgRx.format, (double) can_ts/1000000);
                        
            return 1;
        }
    }
    return 0;
}

mind that the first argument is a dummy while the second returns a formatted string to me being

char buffer[96];

int main(){
printf(" ID   | Data (CAN Msg byte 0-7) | L | T | F | Time (uSec)\r\n");
printf("      | MD xx PID A  B  C  D xx |   |   |   |            \r\n");
printf("------+-------------------------+---+---+---+------------\r\n")
while (1) {
    if(raw(ENGINE_RPM,buffer) == 1) {
         printf(buffer);
    }
}
}

Hope this helps you getting all data, obviously the code isn't complete but holds the main parts needed.

Have fun, my first attempt to convert the scan driven data gathering to be interrupt driven resulted in an MIL code on the car ! so for now I'm doing scan only, as this example is based on.

Paul