AVR CAN Bus Project – Status Update 1

I got the circuit wired up yesterday:

The 6-pin jumper on the left lets me select one of the 3 CAN buses on the Nissan Leaf accessible via the OBD-II connector.

I hacked up some code quickly, and was pleasantly surprised that it actually worked! Woohoo! The part I thought was going to be most difficult – getting the CAN interface firmware working – turned out to be the easiest. Here’s my first capture of live data from the EV CAN bus:

Schematic and source code will follow.

Previous: AVR CAN Bus Project โ€“ Step 2: Programming Low Fuse
Next: AVR CAN Bus Project – Step 3: CANSpy CAN Bus Monitor

There are 17 Comments to "AVR CAN Bus Project – Status Update 1"

  • chris says:

    Hello, we are getting a LEAF soon and are looking for a way to passively collect driving data – from the ODB port or otherwise – interested in logging the time series of velocity, odometer, etc. etc. power. Have you had any luck decoding the messages?? Your blog and what you’ve done so far is very impressive. Your next step will be to determine which ID’s contain what messages – and what signals – this is often called the ‘CAN signal configuration’, For example – you need to find out that 0x1DA message contains a ‘Signal’ representing instantaneous Power over a 16 bit encoding, written using the Motorolla word orientation, and that the real power value range is -10000 W to +60000 W so your normalization is 70000. That kind of thing…. So – do you have any leads on decoding of the LEAF data stream?? I would be very interested

    • lincomatic says:

      Hi, yes there is a lot of progress in decoding the CAN bus messages. Take a look at the CAN Bus subforum in mynissanleaf.com. Also, have a look at Gary’s CAN-do software. Sorry, I’ve been too busy to update the blog lately. I’ll try to do it soon… with my preliminary Arduino code. While no one has found an odometer message, there’s someone on MNL who claims to have figured out how to calculate distance based on an RPM message in the CAN bus data.

  • yann says:

    have you seen this: http://en.wikipedia.org/wiki/OBD-II_PIDs
    pretty sure you already did, but it could be useful. I’m interested in doing this project too and was wondering if you could share de schematics ana bit of code? ๐Ÿ™‚

    • lincomatic says:

      Yes, unfortunately, those PID’s don’t work on the Nissan Leaf, which is the car I’m working with.
      Sorry for the delay, I’ll be posting the code & schematic soon.

  • Jorge L. says:

    Hi ! Nice work and writeup ๐Ÿ˜‰ Iยดll be following your track …

    Do you have the original zip from SuperCow ? Iยดd like to take a look at it but his server seems to be dead …

    • lincomatic says:

      I don’t have the original. The only changes I made were to add the entries for USBtinyISP, so just my copy, which I linked above.

  • endrigo says:

    hello my friend, I am looking for a CAN interface, with virtual interface for the PC too, want to read the CAN bus of the Chevrolet Cruze, and then the bus will read from VW, Ford, Toyota, Mitsubishi, I will cite an example: I want to connect the CAN bus of the car, I open the door, close door, turn arrow, climb glass, I’ll copy the codes for identifying who is going round each code, code corresponding to the action that I did in the car, then I want to send to the car via PC the code to make sure the code is right, you own this product?
    has with other protocols in order to use other brands?

    I looked at this product and its seemed to be what I try, there’s another more detailed?

    Thank you.

    • lincomatic says:

      The hardware should be able to do what you want. You would need to just change the software. Also, to allow injection of CAN messages, the circuit needs to be modified slightly.

  • norm says:

    Do you know how to decode the VIN on the Leaf. I’d like to add the vin to the log function.

  • Richard Mansell says:

    I’ve enjoyed using my AT90CAN128 thanks to your blog/info and now I’ve moved onto trying out a CAN-bus between two AT90CAN128’s. I noticed in the “can_lib.h” file that CAN_INPUT_PIN is defined as #6 and CAN_OUTPUT_PIN is defined as #5. Since the actual CAN_RX and CAN_TX physical pins are #31 & #30 respectively, did you have to modify the “can_lib.h” file to reflect those pins for the CAN-bus to work?

    • lincomatic says:

      The physical pin numbers don’t matter. In can_lib.h we have:
      #define CAN_PORT_IN PIND
      #define CAN_PORT_DIR DDRD
      #define CAN_PORT_OUT PORTD
      #define CAN_INPUT_PIN 6
      #define CAN_OUTPUT_PIN 5

      CAN_PORT_xxx are all specified for Port D. CAN_INPUT_PIN and CAN_OUTPUT_PIN are offsets into Port D. So the input pin is PD6 and output is PD5.

      • Richard Mansell says:

        Thanks for the reply. That makes sense. I’m just trying to figure out why my AT90CAN128 isn’t initiating the CAN code correctly. My wiring between the AT90CAN128 and the MCP2551 matches yours exactly (which I’ve also triple checked against other sources) and I’m using your CANspy code. The problem is that it hangs at

        while ((CAN_PORT_IN & (1<<CAN_INPUT_PIN)) != 0);

        Since there is no activity on the CAN-bus at the time, I thought I could just comment that line out and force it farther into the program. However it next hangs at

        CAN.init(0);

        I'm trying to get two AT90CAN128's (I'm using the same breakout boards as yours in this blog) to communicate with each other via a CAN-bus. (I do have CAN-bus line termination resistors.)

        • lincomatic says:

          it hangs up because it’s waiting for a CAN message on the bus. you need to generate a CAN message for it to read. It also does the same thing in CAN.init(). The code assumes that there is activity on the bus.. I think it uses it to autobaud in CAN.init(). Sorry, I based my code on an example, and I haven’t even ever tested writing to the bus. CANspy is based on code from Atmel’s examples in http://www.atmel.com/dyn/resources/prod_documents/at90CANLIB_3_2.zip. Perhaps you can figure out how to get it working from the sample code there. They have sample code that writes to the bus. If you get it working, please report back.

  • Richard Mansell says:

    Okay, I was wondering if that was the case. It made sense that your code would work if it was trying to read an already running bus like from your car. The problem with my setup is probably that both AT90CAN128’s were waiting for the other one to say something! ๐Ÿ™‚

    I’ll work on two things then: #1. I’ll start playing around with some TXing on the CAN-bus and #2. A friend of mine has agreed to let me use the CANspy & my modules to listen in on one of his vehicle’s CAN-buses. I’ll let you know how it turns out.

  • Richard Mansell says:

    Okay, got it working! I loaded one AT90CAN128 with my version of your CANspy program. It is exactly the same except for two differences:
    #1. I added code to use an LED to let me know if it was receiving successfully or not.
    #2. I changed

    CAN.set_baudrate(CAN_AUTOBAUD);

    to

    CAN.set_baudrate(500);

    I ended up setting both AT90CAN128’s to a 500 baudrate.

    Here is the main parts of the sending code:

    #include

    #include
    void Sprintf(char *fmt, ... ){
    char tmp[128]; // resulting string limited to 128 chars
    va_list args;
    va_start (args, fmt );
    vsnprintf(tmp, 128, fmt, args);
    va_end (args);
    Serial.print(tmp);
    }

    uint8_t i,tmp;
    //dataLen is how long the actual message will be
    uint8_t dataLen=8;

    void spy_printing(st_cmd_t* msg)
    {
    uint8_t indx;

    if (msg->ctrl.ide) {
    Sprintf ("%02X%02X: 0x%08lX(Ext.), L=%d, ", CANSTMH, CANSTML, msg->id.ext, msg->dlc);
    }
    else {
    Sprintf ("%04X:%03X %d ",(uint16_t)millis(), msg->id.std, msg->dlc);
    }
    if (msg->ctrl.rtr) {
    Sprintf ("Remote\r\n");
    }
    else {
    for(indx=0; indxdlc-1); indx++) {
    Sprintf ("%02X", *(msg->pt_data + indx));
    }
    Sprintf ("%02X\r\n", *(msg->pt_data + indx));
    }
    }

    void CANinit()
    {
    //Setting up the CAN module for TXing
    CAN_PORT_DIR &= ~(1<<CAN_INPUT_PIN );
    CAN_PORT_DIR &= ~(1<<CAN_OUTPUT_PIN);
    CAN_PORT_OUT |= (1<<CAN_INPUT_PIN );
    CAN_PORT_OUT |= (1<=254)
    {
    i=1;
    }

    //assigning the message id number to the message
    msg.id.ext=i;

    //assinging the length of the message to the message
    msg.dlc=dataLen;

    //here is where I add some info to the message data itself. This can be anything you want it to be!
    buffer[6]=CANSTMH;
    buffer[7]=CANSTML;
    buffer[0]=i;

    //assigning the message data to the message itself
    msg.pt_data = &buffer[0];

    //not sure if this is needed yet, or not, but left it in the code
    memset(buffer,sizeof(buffer),0);

    // assigning the Tx Command to this message
    msg.cmd = CMD_TX_DATA;

    // here I tell it to send the message on the CAN-bus!
    CAN.cmd(&msg);

    // this code is to let me know if the message was successfully received or not.
    while(1) {
    Serial.print("before getting message\r\n");
    tmp = CAN.get_status(&msg);

    if(tmp==0)Serial.print("completed\r\n");
    if(tmp==1)Serial.print("not completed\r\n");
    if(tmp==2)Serial.print("error\r\n");

    break; // Out of while
    }

    // I put a delay in just so that I would have a manageable amount of time to read my own output!
    delay(10);

    // This prints out the info concerning the message
    spy_printing(&msg);
    }

    Again I deleted my LED signalling code and a lot of my own comments for clarity. You can see that I didn’t have to “include” any other files than that you already used in CANspy. Hopefully this code will help others set up a simple CAN sending program.

    • Richard Mansell says:

      Looking back over that code, I can see that it is missing some things from when I copied it. I’ll see if I can redo it. Do you want me to some how get it to you so you can add to your github?

Write a Comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>