Search code examples
pythonnumpycan-buscrccapl

How to calculate CRC for ISO CAN-FD frames


I'm working on a study about CRC in ISO CAN-FD but I'm having issues with the calculation of the actual check sequence.

First of all, I have carefully read the specification ISO 11898-1:2015 that states how the calculation has to be carried out.

Then, I have defined a frame to try and calculate the CRC on:

sequence of bits to work on

Note that the red zeros are stuff-bits.

The same frame has been added to a CANalzyer configuration, and my CAPL script prints the FrameCRC = 0x6bd.

I have implemented the algorithm described in the ISO document using Numpy, but my result doesn't match what CANalyzer returns.

My code is the following (it probably isn't perfect numpy-ic coding, I'm new to this library):

def crc(data):
    gen_poly = np.array([1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1])
    crc_reg = np.array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

    for bit in data:
        crc_next = abs(bit - crc_reg[0])
        crc_reg = np.roll(crc_reg, -1)      # Shift one position left (1)
        crc_reg[-1] = 0                     # Shift one position left (2)
        if crc_next == 1:
            reg_new = abs(crc_reg - gen_poly)
            crc_reg = np.copy(reg_new)
    return crc_reg.copy()

I also thought that maybe I misunderstood the document, and crc_reg and gen_poly have to be 18 bits long. So I modified the code this way:

  • added 18 bits at zero at the end of the frame, instead of 17;
  • gen_poly = np.array([1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1]);
  • crc_reg = np.array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) (18 total bits);

but it didn't work as well. I really can't figure out where I'm making mistakes. I've reviewed everything many times.

Edit: as suggested by @Reinderien, I'm providing the input data and the expected output arrays:

input_data = np.array([
    0,  # SOF
    1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0,    # ID
    0,  # RTR
    0,  # IDE
    1,  # EDL
    0,  # RES
    1,  # BRS
    0,  # ESI
    1, 0, 0, 0,     # DLC
    1, 1, 1, 1, 1, 0, 1, 1, 1,          # Byte 1
    1, 1, 0, 1, 1, 1, 1, 1, 0, 1,       # Byte 2
    1, 1, 1, 1, 0, 1, 1, 1, 1,          # Byte 3
    1, 0, 1, 1, 1, 1, 1, 0, 1, 1,       # Byte 4
    1, 1, 1, 0, 1, 1, 1, 1, 1, 0,       # Byte 5
    1, 1, 1, 1, 1, 0, 1, 1, 1,          # Byte 6
    1, 1, 0, 1, 1, 1, 1, 1, 0, 1,       # Byte 7
    1, 1, 1, 1, 0, 1, 1, 1, 1,          # Byte 8
    1, 1, 0, 0,     # StuffCount + Parity
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0     # 17 bits at zero
])

expected_output = np.array([0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1])    # 0x6bd

Solution

  • You do not process the 17 bits of zeros where the CRC goes. (Just delete or comment out that line in your input.) Then your python code outputs [0 0 0 0 0 0 1 1 0 1 0 1 1 1 1 0 1].