CAN bus

I've started working with CAN bus for a new project I'm doing, using Microchip's MCP2515 CAN controller and MCP2551 CAN transceiver. In this blog post I'll explain how the CAN bus works at the bit level, to make it easier for us to debug when something isn't working.

CAN bus on a breadboard

I hooked up a quick circuit using an ATmega32 and the two CAN bus chips. I used SPI to send a single CAN data frame to the target ID 0x555, and then captured the frame using a logic analyzer.

CAN bus frame format

Working Backwards

Let's pick through our message and understand where each of the bits came from. The bit stream that we captured with the logic analyzer was

010101010101000001001100111010011001011111111

which corresponds to the Start of Frame marker, Arbitration Field, Control Field (including Data Length Code), CRC sequence (including CRC delimiter), ACK field, and End Of Frame (EOF) delimiter. Note that the Control Field contains a run of five 0 bits, which means a 1 bit has been stuffed into the value. So we know that we should remove that extra 1 bit from the Data Length Code to get the correct value of 0000. So this message has a payload of 0 bytes. The "Arbitration Field" is just another name for the "Identifier", so our extracted identifier is 10101010101 or 0x555.

The first three bits of the Control Field are the RTR bit, IDE bit, and "r0" reserved bit. In our message these three bits are all 0. The RTR bit represents whether this CAN frame is a Remote Transmission Request or not. Apart from error handling, every CAN frame is either a Remote Frame (the sender is requesting some kind of reply from the receiving node), or is a data frame. The IDE (ID Extension) bit represents whether this data frame is addressed to an extended ID (an extended CAN message). Some manufacturers decided that 11 bits couldn't address all of their devices (211 = 2048). So they took an unused bit from the old CAN bus Control Field and called it the IDE bit. When the IDE bit is set, the message structure is slightly longer, and there is an additional 18-bit Identifier field meaning that an extended CAN message can address up to 229 = 536870912 different devices on the same bus (wow!). Alternatively, these ID bits can be split up among several fields (priority, category, sender type, etc). For now we'll ignore extended IDs, because we sent ourselves a standard CAN bus data frame (IDE bit = 0).

Since our Data Length is 0, we have 0 bytes of payload. So the next field is the CRC sequence, and the CRC delimiter. To understand where the CRC sequence came from, we need to understand a little bit about CRC checksums. I will assume that you've read up on how CRC works. The polynomial that CAN bus uses for the CRC calculation is x15+ x14+ x10+ x8+ x7+ x4+ x3+ x0  (according to the official documentation). We then checksum all the bits from the Start of Frame Marker until just before the CRC sequence, except for any stuffed bits that have been inserted to break up long runs of the same bit value. So after we remove the stuffed bit that was inserted into the Data Length field, we get the bit sequence 0101010101010000000, or 0x2AA80. We can use an online tool to help us perform the CRC calculation, and we will find that the generated value is 0b110011101001100, which is the same value that was contained in the original CAN frame. The CRC delimiter is always 1 (recessive state).

The first bit of the ACK field (the ACK bit) is transmitted as 1 (recessive state) by the sender of a data frame, and anyone who has heard the message and verified its CRC checksum pulls the bus into a dominant state (0 bit) during the message's ACK bit, which tells the sender that at least one receiver has successfully read the message. Note that we can't tell how many other nodes successfully received the message -- we can only tell if nobody received it, or at least one node got it. Most CAN controllers are configured to repeat a message until it gets received by someone. The second bit of the ACK field is always 1 (recessive).

Finally, the End Of Frame (EOF) delimiter marks the end of a CAN frame with 7 recessive bits.

That wasn't so bad!

UPDATE: I've added a bit of code to perform the CANbus CRC calculation below:

#include <stdio.h>
#include <stdint.h>

uint16_t can_crc_next(uint16_t crc, uint8_t data)
{
    uint8_t i, j;

    crc ^= (uint16_t)data << 7;

    for (i = 0; i < 8; i++) {
        crc <<= 1;
        if (crc & 0x8000) {
            crc ^= 0xc599;
        }
    }

    return crc & 0x7fff;
}

int main()
{
    int i;
    uint8_t data[] = {0x02, 0xAA, 0x80};
    uint16_t crc;

    crc = 0;

    for (i = 0; i < sizeof(data); i++) {
        crc = can_crc_next(crc, data[i]);
    }

    printf("%x\n", crc);
}
  • pari

    how can i write c code in code vision for calculation crc 15 bit?????

  • qartis

    I updated the post and added a bit of example code to show how to calculate the CRC.

  • pari

    thanks for your help,but i dont understand how i can calculated crc for every data????and have out put by byneri format

  • Successful Engineer

    This is one of the best most concise explanations I've seen, thanks mate.

  • Sajith P

    Better you should use #define for raw values, Eg #define polynomial c599

    Readability would be more....!!

  • Dwayne

    Did you ever get anywhere with this project? I'm a computer science student with 20 years truck repair experience. I'm taking an SAE seminar on the CAN data link found in trucks. I'm hoping to write a project at may incorporate any of this material if it is available, Like wiring schematics ext. I'm not stealing ideas but rather looking for similar ideas. Thanks dwayne.barsotta@gmail.com