背景

计算CANFD上传输的一帧数据的E2E校验,CRC-8-SAE J1850 - 0x1D (x8 + x4 + x3 + x2 + 1),但具有不同的起始值和 XOR 值(起始值和 XOR 值均为 0x00)。

CANFD数据帧结构

CANFD 数据场总共有DLC 64字节,一般包括 比如(0x100 帧)

时间戳+传输数据 + counter +checkSum +信号更新状态位 等

每一帧数据有一个唯一的Dataid(0x0001,项目前期会定义好),数据长度在如下链接有说明

[PRS_E2E_00085] In E2E Profile 1, with E2E_P01DataIDMode equal to
E2E_P01_DATAID_BOTH or E2E_P01_DATAID_ALT the length of the Data ID shall
be 16 bits (i.e. 2 byte). 

《AUTOSAR_PRS_E2EProtocol》入门1 (持续更新)-CSDN博客

数据排序方式 

一般有motorola 格式和intel 格式,数据排序方式有点不太一样。在取数据的时候,bit位会不一样。

  • Intel 格式:同小端 (Little-endian),低字节在前
  • Motorola 格式:同大端 (Big-endian),高字节在前

E2E校验实例

CRC 算法 1

byte Crc_CalculateCRC8(byte data[],int dataLen,byte Crc_StartValue8)
{
  int i,j;
  byte polynomial;
  byte initValue;
  polynomial = 0x1d;
  initValue = Crc_StartValue8^0X00;
  for(i=0;i<dataLen;i++)
  {
    initValue = initValue ^ data[i];
    for(j=0;j<8;j++)
    {
      if(initValue & 0x80)
      {
        initValue = ((initValue << 1) & 0xff);
        initValue = initValue ^ polynomial;
      }
      else
      {
        initValue = ((initValue << 1) & 0xff);
      }
    }
  }
  initValue = initValue ^ 0x00;
  return(initValue);
}

CRC 算法2

#include <stdint.h>  
  
// 假设CRC-8多项式为0x07  
const uint8_t crc8_table[256] = {  
0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
    0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E, 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
    0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4, 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
    0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19, 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
    0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40, 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
    0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D, 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
    0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7, 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
    0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A, 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
    0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75, 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
    0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8, 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
    0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2, 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
    0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F, 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
    0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66, 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
    0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB, 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
    0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1, 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
    0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C, 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
};  
  
// 使用查找表计算CRC-8  
uint8_t crc8_table_compute(uint8_t *data, size_t length, uint8_t crc) {  
    for (size_t i = 0; i < length; ++i) {  
        crc = crc8_table[crc ^ data[i]];  
    }  
    return crc;  
}  
  
// 使用示例  
int main() {  
    uint8_t data[] = {0x12, 0x34, 0x56, 0x78};  
    uint8_t crc = crc8_table_compute(data, sizeof(data), 0x00); // 初始CRC通常为0  
    // 使用计算出的CRC进行后续操作  
    return 0;  
}

两种算法的优缺点在《AUTOSAR_PRS_E2EProtocol》中有说明

实时计算CRC值

优点

  1. 灵活性:实时计算CRC值的方法不受限于预定义的查找表,因此可以适用于任何CRC多项式。这意味着它可以轻松适应不同的通信协议和数据格式。
  2. 内存占用:对于某些应用,尤其是内存受限的环境,实时计算CRC值可能更为合适,因为它不需要存储大量的查找表数据。

缺点

  1. 计算速度:实时计算CRC值通常涉及复杂的位操作和多项式除法,这可能会比查找表方法慢,特别是在需要频繁计算CRC的场景中。
  2. 资源消耗:对于某些处理器来说,实时计算CRC值可能需要更多的CPU周期,从而增加能源消耗。

查找表(查找数组)方法

优点

  1. 计算速度:查找表方法通过预先计算并存储所有可能的CRC值,可以显著减少实时计算的需求。因此,它在计算CRC时通常更快,适用于需要高速数据传输的场景。
  2. 简化代码:查找表方法简化了CRC计算的代码逻辑,使得实现更为简单和直接。

缺点

  1. 内存占用:查找表方法需要存储大量的预计算CRC值,因此会占用更多的内存空间。这可能在内存受限的应用中成为问题。
  2. 灵活性:查找表方法通常针对特定的CRC多项式进行预计算,因此可能不适用于所有通信协议和数据格式。如果需要适应不同的CRC多项式,可能需要重新生成查找表。

附录1:CRC计算原理

CRC(Cyclic Redundancy Check),即循环冗余检验,是基于数据计算一组校验码码,用于核对数据传输过程中是否被更改或传输错误。假设有一组原始数据:1101011011,如何获取其CRC?见下图右方:

第1步:选取CRC算法,即生成多项式,也就是E2E profiles就采用了CRC-8,CRC-16, CRC-32。像E2E profile 1采用x8 + x4 + x3 + x2 + 1,即1 0001 1101。此处选用4位CRC算法,x4 + x1 + 1,即1 0011。

第2步:因此选用4位CRC算法,1 0011,注意宽度是4位,不是5位,这时原始数据需要在右边填充4位,0000,后面用来存放4位CRC,变为:1101011011 0000。

第3步,使用XOR运算,计算CRC,过程如下图左方:

第4步:将CRC更新到原始数据的右4位,则数据变为:11010110111110。这个数据将发送给其他控制器。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐