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

17 thoughts on “AVR CAN Bus Project – Status Update 1”

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Leave a Reply