Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)

Crc校验在CAN报文中的实际应用介绍:

        Crc在报文传输过程中的实际应用如下(在汽车中,Crc一般是对8个字节进行校验,目前我接触到的是这样):

        ECU-A和ECU-B之间进行CAN报文的传输,双方规定ECU-A发出的0x123报文为64个字节,该报文中的Byte1-Byte7要进行Crc校验,校验结果放到Byte0中,Alivecounter为Byte7的低四位(范围为0-14)。其余的Byte8-Byte64不进行校验。校验范围如下图所示

Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第1张图片

        因此,ECU-A往CAN总线发出这帧报文之前,要对每帧报文的Alivecounter按照0-14进行不断自增、循环。然后进行Crc校验并把校验结果存放到这帧报文的Byte0中,最后通过CAN总线发出这帧报文数据。

        ECU-B接收到这帧报文后,由于Byte8-Byte64不在校验范围内,因此接收到这帧报文后这个范围内的数据可以直接使用。但Byte0-Byte7为校验范围,因此ECU-B按照双方规定好的Crc算法对Byte1-Byte7进行校验,校验结果跟接收到的Byte0进行对比,若对比结果一致,则使用这帧报文的Byte1-Byte7的数据,否则丢弃这些数据。

        这就是Crc算法在CAN报文中的具体使用。


E2E和Crc的区别

        接下来就是Autosar的E2E(End-to-End,可以理解为数据从一个ECU传到另一个ECU)。

        刚开始接触的时候,我总没搞明白所谓的E2E和CRC到底有啥区别,因为在开发过程中,只关心两件事:Checksum计算是否正确、Counter的值是否按照要求进行递增并循环。

        后来在不断的学习和深入开发的才知道:

                Crc仅仅是一个校验算法

                E2E是Autosar官方定义的标准,它包含了Crc算法、要求了Counter的值如何进行递增、并在Counter出错时会记录对应的错误状态等等。


E2E的各参数及解析:

        这些参数一般都是客户那边给出的需求。不然你想想,客户人家规定这帧报文的Checksum位置是Byte0,但是你这边又弄成Byte7。或者人家客户规定用算法A,你用了算法B,那最终校验肯定是不通过的。

typedef struct {
	uint16 CounterOffset;
	uint16 CRCOffset;
	uint16 DataID;
	uint16 DataIDNibbleOffset;
	E2E_P01DataIDMode DataIDMode;
	uint16 DataLength;
	uint8 MaxDeltaCounterInit;
	uint8 MaxNoNewOrRepeatedData;
	uint8 SyncCounterInit;
} E2E_P01ConfigType;

1、CounterOffset

        AliveCounter在64个bit中的位置


2、CRCOffset

        Checksum在64个bit中的位置


3、DataID

        DataID的值


4、DataIDNibbleOffset

        官方定义如下

Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第2张图片

        这个参数只有在DataID模式选择为“E2E_P01_DATAID_NIBBLE ”是会用到。目前我没用到,所以我也不知道这玩意干啥用的(看半天也没看懂-_-''')....


5、E2E_P01DataIDMode

        DataID的模式,共有四种模式可选:    

                E2E_P01_DATAID_BOTH
                E2E_P01_DATAID_ALT
                E2E_P01_DATAID_LOW
                E2E_P01_DATAID_NIBBLE


6、DataLength

        数据校验段的长度(8个字节)


7、MaxDeltaCounterInit

        官方解释如下:Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第3张图片

        简单来说就是说最大容忍Counter的间隔(,因为Counter是按1递增的,因此这参数即最大容忍丢失帧数)。正如它的例子说:如果MaxDeltaCounterInit配置为1,那么当在接收到上一帧的Counter为1的时候(下一帧若counter为2就不说了,因为Counter为2即没有丢帧),下一帧可以接收counter为3,但不能counter为4。因为1与3直接差了一帧(也就是丢失一帧了)。1与4直接已经差了2帧(也就是丢失两帧了),所以Counter为4不在容忍范围内了。

        图形解释如下:Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第4张图片


8、MaxNoNewOrRepeatedData

         Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第5张图片

        当接收到重复数据次数小于该配置参数,则接收端不需要执行数据同步处理

        
9、SyncCounterInit

        当执行数据同步处理时,接收到正确数据次数必须大于该配置参数,才能将状态有同步状态转移到OK状态

Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第6张图片

上诉各参数使用Vector工具配置报文E2E如下:

Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第7张图片


 E2E状态:

        比如,当E2E状态为E2E_P01STATUS_WRONGCRC,说明CRC校验不通过。又比如E2E状态为E2E_P01STATUS_OKSOMELOST,说明前后两帧报文的Counter间隔超出容忍范围。       

        接收到含E2E报文后,对E2E报文的检查结果就会有对应的E2E状态供应用层读取,应用层根据E2E状态决定接收到的数据是否使用,并根据E2E状态记录相关的故障,如Checksum校验错误故障等。

typedef enum {
        E2E_P01STATUS_OK = 0x00,
        E2E_P01STATUS_NONEWDATA = 0x1,
        E2E_P01STATUS_WRONGCRC = 0x2,
        E2E_P01STATUS_SYNC = 0x03,
        E2E_P01STATUS_INITIAL = 0x4,
        E2E_P01STATUS_REPEATED = 0x8,
        E2E_P01STATUS_OKSOMELOST = 0x20,
        E2E_P01STATUS_WRONGSEQUENCE = 0x40
} E2E_P01CheckStatusType;


         Autosar官方标准文档有如下所示报文接收检查流程图:

Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第8张图片

Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第9张图片

Autosar BSW层CAN通讯开发------08(Autosar的E2E开发-----以E2E Profile01为例)_第10张图片


以下代码运行即可得到以Autosar官方标准的E2E_Profil01计算的结果。其中:

Checksum位置为Byte0

Counter位置为Byte7的低四位(即Bit56)

DataID模式为DATAID_BOTH且DataID=0x00AD。

注:以下代码仅仅是进行校验,没有E2E的状态处理。

代码如下:

main.c

#include 
#include "typedef_datatype.h"
#include "E2E_Config.h"




uint16 DataID = 0x00AD;//DataID_Low = 0xAD    DataID_High = 0x00    
uint8 Test_Data_Array[8] = { 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x73, 0x20 }; //Byte0-Byte7   Test Data
E2E_P01ConfigType E2E_Profile01_Test_Config = {
	56,						//CounterOffset
	0,						//CRCOffset
	177,					//DataID
	0,					//DataIDNibbleOffset
	E2E_P01_DATAID_BOTH,	//DataIDMode
	64,						//DataLength
	0,					//MaxDeltaCounterInit
	0,					//MaxNoNewOrRepeatedData
	0					//SyncCounterInit
};


void main(void)
{
	for (uint8 counter = 0; counter < 15; counter++)
	{
		Test_Data_Array[7] = (Test_Data_Array[7] & 0xF0) | counter;
		Test_Data_Array[0] = E2E_P01ComputeCRC(Test_Data_Array, &E2E_Profile01_Test_Config, 0xFF);
		for (uint8 i = 0; i < 8; i++)
		{
			printf("%x ", Test_Data_Array[i]);
		}
		printf("\n");
	}
	
}

E2E_Config.h

#ifndef E2E_Config_H_
#define E2E_Config_H_

#include 
#include "typedef_datatype.h"

/* For CRC 8*/
#define CRC8_START_VALUE        0xFFU
#define CRC8_XOR                0xFFU
/* CRC 8 Configuration
 * Possible values and the mode decides what method to be used
 */
#define CRC_8_HARDWARE (0x01) /* Not supported */
#define CRC_8_RUNTIME  (0x02)
#define CRC_8_TABLE    (0x04) /* Default value */


#define CRC_8_MODE      CRC_8_RUNTIME



 /* E2E Profile01 */
#define CRC8_POLYNOMIAL			0x1DU

typedef enum {
	E2E_P01_DATAID_BOTH = 0x0,
	E2E_P01_DATAID_ALT = 0x1,
	E2E_P01_DATAID_LOW = 0x2,
	E2E_P01_DATAID_NIBBLE = 0x3
} E2E_P01DataIDMode;

typedef struct {
	uint16 CounterOffset;
	uint16 CRCOffset;
	uint16 DataID;
	uint16 DataIDNibbleOffset;
	E2E_P01DataIDMode DataIDMode;
	uint16 DataLength;
	uint8 MaxDeltaCounterInit;
	uint8 MaxNoNewOrRepeatedData;
	uint8 SyncCounterInit;
} E2E_P01ConfigType;



uint8 Crc_CalculateCRC8(const uint8* Crc_DataPtr, uint32 Crc_Length, uint8 Crc_StartValue8, boolean Crc_IsFirstCall);
uint8 E2E_P01ComputeCRC(const uint8* Crc_DataPtr, const E2E_P01ConfigType* ConfigPtr, uint8 Counter);

#endif

E2E.c

#include "E2E_Config.h"



static uint8 CalculateCRC8(const uint8* message, uint32 nBytes, uint8 start, uint8 poly)
{
	uint8  remainder = start;
	uint8  bit;
	uint8  topbit = 0x80;

	/* Perform modulo-2 division, a byte at a time. */
	for (uint32 byte = 0; byte < nBytes; byte++) {
		/* Bring the next byte into the remainder. */
		remainder ^= *message;
		message++;

		/* Perform modulo-2 division, a bit at a time. */
		for (bit = 8; bit > 0; bit--) {

			/* Try to divide the current data bit. */
			if ((remainder & topbit) != 0u) {
				remainder = (uint8)(remainder << 1) ^ poly;
			}
			else {
				remainder = (remainder << 1u); /*lint !e734 Lint exception: Intentional */
			}
		}
	}

	return remainder;
}



uint8 Crc_CalculateCRC8(const uint8* Crc_DataPtr, uint32 Crc_Length, uint8 Crc_StartValue8, boolean Crc_IsFirstCall)
{
	uint8 crc = 0;    /* Default return value if NULL pointer */

	if (Crc_DataPtr != NULL)
	{

		crc = (TRUE == Crc_IsFirstCall) ? CRC8_START_VALUE : (Crc_StartValue8 ^ CRC8_XOR);

#if CRC_8_MODE == CRC_8_RUNTIME
		crc = CalculateCRC8(Crc_DataPtr, Crc_Length, crc, CRC8_POLYNOMIAL);
#elif CRC_8_MODE == CRC_8_TABLE
		for (uint32 byte = 0; byte < Crc_Length; byte++)
		{
			crc = crc8_tab[crc ^ *Crc_DataPtr];
			Crc_DataPtr++;
		}
#endif

		/* Only XOR value if any calculation was done */
		crc = crc ^ CRC8_XOR;

	}

	return crc;

}


uint8 E2E_P01ComputeCRC(const uint8* DataPtr, const E2E_P01ConfigType* ConfigPtr, uint8 Counter)
{
	uint8 crc;
	uint8 CrcLength;
	uint8 LocalDataID[2];
	uint16 CalculatedOffset;
	uint16 CalculatedLength;

	switch (ConfigPtr->DataIDMode)
	{
	case E2E_P01_DATAID_BOTH:
	{
		LocalDataID[0] = (uint8)(ConfigPtr->DataID);
		LocalDataID[1] = (uint8)(ConfigPtr->DataID >> 8u);
		CrcLength = 2;
		break;
	}
	case E2E_P01_DATAID_LOW:
	{
		LocalDataID[0] = (uint8)ConfigPtr->DataID;
		CrcLength = 1;
		break;
	}
	case E2E_P01_DATAID_NIBBLE:
	{
		LocalDataID[0] = (uint8)ConfigPtr->DataID;
		LocalDataID[1] = 0;
		CrcLength = 2;
		break;
	}
	case E2E_P01_DATAID_ALT:
	{
		CrcLength = 1;
		if ((Counter & 0x01u) == 0u)
		{
			LocalDataID[0] = (uint8)ConfigPtr->DataID;
		}
		else
		{
			LocalDataID[0] = (uint8)(ConfigPtr->DataID >> 8u);
		}
		break;
	}
	default:
		LocalDataID[0] = 0u;
		CrcLength = 0u;
		break;

	}

	crc = Crc_CalculateCRC8(LocalDataID, CrcLength, 0xFF, FALSE);

	CalculatedOffset = ConfigPtr->CRCOffset >> 3u;
	if ((CalculatedOffset) > 0u)
	{
		crc = Crc_CalculateCRC8(DataPtr
			, CalculatedOffset
			, crc
			, FALSE
		);
	}

	CalculatedLength = ConfigPtr->DataLength >> 3u;
	if (CalculatedOffset < (CalculatedLength - 1u))
	{
		crc = Crc_CalculateCRC8(&DataPtr[CalculatedOffset + 1u]
			, (uint32)CalculatedLength - CalculatedOffset - 1u
			, crc
			, FALSE
		);
	}

	return crc ^ 0xFFu;

}

参考:AUTOSAR E2E 简介_Archieeeeee的博客-CSDN博客_autosar e2e

你可能感兴趣的:(c语言,开发语言,autosar,汽车)