FPGA实现CAN通信CRC校验

该博客介绍了如何在FPGA中实现CAN通信的CRC校验,包括并行和串行两种计算方法。并行方案适用于网络通信的32位CRC校验,而串行方案遵循CAN2.0协议,考虑到数据收发中的翻转电平参与计算。文中提供了详细的C语言实现和FPGA Verilog代码示例,经过验证,这些方案已被证明有效。
摘要由CSDN通过智能技术生成

FPGA实现CAN通信CRC校验

检验本质上是CRC检验生成多项式
理解CRC校验,首先需要了解生成多项式的概念,生成多项式也就是发送方和接受方约定的一个除数而已,发送方和接收方都使用这一个相同的除数进行模2运算,计算结果相同则说明传输数据没有问题,而如果计算结果不同可能传输的数据就出现了问题,目的就是为了保证数据传输的可靠性。
上面提到的模二计算本质上就是异或运算,相同的位为0,不同的位为1,也就是不考虑进位、错位的二进制加减法运算,例如:10011011 + 11001010 = 01010001.
常见的生成多项式:
CRC8 = X8 + X5 + X4 +1
CRC12 = X12 + X11 + X3 + X2 + 1
CRC16 = X16 + X15 + X5 +1
CRC15 =X15 + X14 + X10 + X8 + X7 + X4 + X3 + X0.
CRC32 = X32 + X26 + X23 + X22 + X16 + X12 + X11 + X10 + X8 + X7 + X5 + X4 + X2 + X1 + 1
每一个生成多项式都是与一个代码相对应的,比如CRC8对应的代码就是100110001

比如在实现网络通信时C语言校验实现如下

uint cal_crc(uchar *ptr, uchar len) { 
    uint crc; 
    uchar i; 
    crc=0; 
    while (len--!=0) { 
        for (i=0x80; i!=0; i/=2) { 
            if ((crc&0x8000)!=0){
                crc*=2; crc^=0x1021;
            } else crc*=2; 
            if ((*ptr&i)!=0)
                crc^=0x1021; 
        } 
    ptr++; 
    } 
    return(crc); 
}

用FPGA实现32位网络通信CRC检验码并行计算如下


`timescale 1ns / 1ps
module crc (Clk, Reset, Data, Enable, Crc,CrcNext);
parameter Tp = 1;
input Clk;
input Reset;
input [0:3] Data;
input Enable;
output [31:0] Crc;
reg  [31:0] Crc;
output [31:0] CrcNext;
assign CrcNext[0] = Enable & (Data[0] ^ Crc[28]); 
assign CrcNext[1] = Enable & (Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29]); 
assign CrcNext[2] = Enable & (Data[2] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[30]); 
assign CrcNext[3] = Enable & (Data[3] ^ Data[2] ^ Data[1] ^ Crc[29] ^ Crc[30] ^ Crc[31]); 
assign CrcNext[4] = (Enable & (Data[3] ^ Data[2] ^ Data[0] ^ Crc[28] ^ Crc[30] ^ Crc[31])) ^ Crc[0]; 
assign CrcNext[5] = (Enable & (Data[3] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[31])) ^ Crc[1]; 
assign CrcNext[6] = (Enable & (Data[2] ^ Data[1] ^ Crc[29] ^ Crc[30])) ^ Crc[ 2]; 
assign CrcNext[7] = (Enable & (Data[3] ^ Data[2] ^ Data[0] ^ Crc[28] ^ Crc[30] ^ Crc[31])) ^ Crc[3]; 
assign CrcNext[8] = (Enable & (Data[3] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[31])) ^ Crc[4]; 
assign CrcNext[9] = (Enable & (Data[2] ^ Data[1] ^ Crc[29] ^ Crc[30])) ^ Crc[5]; 
assign CrcNext[10] = (Enable & (Data[3] ^ Data[2] ^ Data[0] ^ Crc[28] ^ Crc[30] ^ Crc[31])) ^ Crc[6]; 
assign CrcNext[11] = (Enable & (Data[3] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[31])) ^ Crc[7]; 
assign CrcNext[12] = (Enable & (Data[2] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[30])) ^ Crc[8]; 
assign CrcNext[13] = (Enable & (Data[3] ^ Data[2] ^ Data[1] ^ Crc[29] ^ Crc[30] ^ Crc[31])) ^ Crc[9]; 
assign CrcNext[14] = (Enable & (Data[3] ^ Data[2] ^ Crc[30] ^ Crc[31])) ^ Crc[10]; 
assign CrcNext[15] = (Enable & (Data[3] ^ Crc[31])) ^ Crc[11]; 
assign CrcNext[16] = (Enable & (Data[0] ^ Crc[28])) ^ Crc[12]; 
assign CrcNext[17] = (Enable & (Data[1] ^ Crc[29])) ^ Crc[13]; 
assign CrcNext[18] = (Enable & (Data[2] ^ Crc[30])) ^ Crc[14]; 
assign CrcNext[19] = (Enable & (Data[3] ^ Crc[31])) ^ Crc[15]; 
assign CrcNext[20] = Crc[16]; 
assign CrcNext[21] = Crc[17]; 
assign CrcNext[22] = (Enable & (Data[0] ^ Crc[28])) ^ Crc[18]; 
assign CrcNext[23] = (Enable & (Data[1] ^ Data[0] ^ Crc[29] ^ Crc[28])) ^ Crc[19]; 
assign CrcNext[24] = (Enable & (Data[2] ^ Data[1] ^ Crc[30] ^ Crc[29])) ^ Crc[20]; 
assign CrcNext[25] = (Enable & (Data[3] ^ Data[2] ^ Crc[31] ^ Crc[30])) ^ Crc[21]; 
assign CrcNext[26] = (Enable & (Data[3] ^ Data[0] ^ Crc[31] ^ Crc[28])) ^ Crc[22]; 
assign CrcNext[27] = (Enable & (Data[1] ^ Crc[29])) ^ Crc[23]; 
assign CrcNext[28] = (Enable & (Data[2] ^ Crc[30])) ^ Crc[24]; 
assign CrcNext[29] = (Enable & (Data[3] ^ Crc[31])) ^ Crc[25]; 
assign CrcNext[30] = Crc[26]; 
assign CrcNext[31] = Crc[27]; 


always @ (posedge Clk or posedge Reset)
begin
  if (Reset)
    Crc <= #1 32'hffffffff;
  else if(Enable)
    Crc <= CrcNext;
end


endmodule

在实现CAN通信时是采用15位校验码。由于CAN在数据的收发中存在插入一个翻转电平,这个翻转电平实际上也是参与CRC计算的,因此采用并行的计算方法存在一定的问题,根据CAN2.0协议提供的串行实现方案来用FPGA实现。
CAN协议C语言实现方案如下

U16 Can_FD_Analyzer::MakeCRC15(std::vector<BitState> &bits, U32 num_bits)
{
    //X15 + X14 + X10 + X8 + X7 + X4 + X3 + X0.
    U16 CRC[15] = { 0 };
    for (U32 i = 0; i < num_bits; i++) {
        U32 DoInvert = (bits[i] == mSettings->Recessive()) ^ CRC[14]; //XOR required?
        CRC[14] = (CRC[13] ^ DoInvert); //14
        CRC[13] = CRC[12];
        CRC[12] = CRC[11];
        CRC[11] = CRC[10];
        CRC[10] = (CRC[9] ^ DoInvert); //10
        CRC[9] = CRC[8];
        CRC[8] = (CRC[7] ^ DoInvert); //8
        CRC[7] = (CRC[6] ^ DoInvert); //7
        CRC[6] = CRC[5];
        CRC[5] = CRC[4];
        CRC[4] = (CRC[3] ^ DoInvert); //4
        CRC[3] = (CRC[2] ^ DoInvert); //3
        CRC[2] = CRC[1];
        CRC[1] = CRC[0];
        CRC[0] = DoInvert;
    }
 
    U16 result = 0; // CRC Result
    for (U32 i = 0; i < 15; i++) {
        result = result | (CRC[i] << i);
    }
    return (U16)result;
}

FPGA串行方案实现如下:
这个是采用标准帧格式,8个字节数据的发送。

//
CIC
	

always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
can_data_crc		<= 'b0							;
end else if (can_data_in_en==1'b1) begin
can_data_crc		<= {1'b0,in_can_id[11:1],1'b0,2'b0,in_can_dlc,in_can_data};
end	
	
end 


always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
can_crc_en_flag		<= 'b0							;
end else if (can_data_in_en==1'b1) begin
can_crc_en_flag		<= 1'b1							;
end	
else if (can_crc_cont>=can_crc_contdata) begin 
can_crc_en_flag		<= 1'b0							;
end		
end 

always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
can_crc_en_flag_t		<= 'b0							;
end else  begin
can_crc_en_flag_t		<= can_crc_en_flag				;
end	
end 


always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
can_crc_contdata		<= 18							;
end else if (can_data_in_en==1'b1) begin
can_crc_contdata		<= 18 + {in_can_dlc,3'b0};
end	
else if (can_crc_cont>=can_crc_contdata) begin 
can_crc_contdata		<= 18							;
end	
end 

always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
can_crc_cont		<= 1'b0							;
end else if (can_crc_en_flag==1'b1) begin
can_crc_cont		<= can_crc_cont + 1'b1			;
end	
else begin 
can_crc_cont		<= 1'b0							;
end	
end 


always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
can_data_crc_t		<= 1'b0							;
end else if (can_data_in_en==1'b1) begin
can_data_crc_t		<= {1'b0,in_can_id[11:1],1'b0,2'b0,in_can_dlc,in_can_data}			;
end
else if (can_crc_en_flag==1'b1) begin
can_data_crc_t		<= {can_data_crc_t[81:0],1'b1}			;
end	
else  begin 
can_data_crc_t		<= 1'b0							;
end	
end 

reg				[14:0]		crc_now_data			;

always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
crc_now_data		<= 1'b0							;
end else if (can_crc_en_flag==1'b1) begin
crc_now_data		<= crc_now_next			;
end
else  begin 
crc_now_data		<= 1'b0							;
end	
end


always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
crc_now		<= 1'b0							;
end else if ((can_crc_en_flag==1'b0)&&(can_crc_en_flag_t==1'b1)) begin
crc_now		<= crc_now_data			;
end
else if (tx_eof_flag==1'b1) begin 
crc_now		<= 1'b0							;
end	
end


assign		crc_first     	   =can_data_crc_t[82] ^ crc_now_data[14] ; 
assign		crc_now_next[14]   =  (	crc_now_data[13] ^ crc_first) ; 
assign		crc_now_next[13]   =  	crc_now_data[12]				 ; 
assign		crc_now_next[12]   =  	crc_now_data[11]				 ; 
assign		crc_now_next[11]   =  	crc_now_data[10]				 ; 
assign		crc_now_next[10]   =  (	crc_now_data[9] ^ crc_first)	 ; 
assign		crc_now_next[9]    =  	crc_now_data[8]				 ; 
assign		crc_now_next[8]    =  (	crc_now_data[7] ^ crc_first)	 ; 
assign		crc_now_next[7]    =  (	crc_now_data[6] ^ crc_first)	 ; 
assign		crc_now_next[6]    =  	crc_now_data[5]				 ; 
assign		crc_now_next[5]    =  	crc_now_data[4]				 ; 
assign		crc_now_next[4]    =  (	crc_now_data[3] ^ crc_first)	 ; 
assign		crc_now_next[3]    =  (	crc_now_data[2] ^ crc_first)	 ; 
assign		crc_now_next[2]    =  	crc_now_data[1]				 ; 
assign		crc_now_next[1]    =  	crc_now_data[0]				 ; 
assign		crc_now_next[0]    =  crc_first					 ; 


上述FPGA实现CAN串行方案和网络32位CRC检验已经过长时间验证,可以使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值