STM32采用的CRC校验模块使用的校验算法与主流CRC32校验算法不同。
下面是一个CRC在线校验网站:
http://www.ip33.com/crc.html
主流32位校验算法包括CRC-32 和 CRC-32/MPEG-2两种,而STM32采用的校验算法与这两种都不同,尽管形式上很像CRC-32/MPEG-2,但STM32是32为逐位计算的,而主流算法都是按字节计算的。
STM32CRC权值为0x4C11DB7,初始值为0xFFFFFFFF,,输入值和输出值不需要反转,输出值不需要异或运算,形式和 CRC-32/MPEG-2相同,但计算结果却不同。
以下为官方文档中给出的CRC计算单元的C语言描述:
DWORD dwPolynomial= 0x04c11db7;
DWORD cal_crc(DWORD *ptr, int len)
{
DWORD xbit;
DWORD data;
DWORD CRC= 0xFFFFFFFF; // init
while (len--)
{
xbit=1 << 31;
data= *ptr++;
for (int bits= 0; bits< 32; bits++)
{
if(CRC & 0x80000000)
{
CRC <<= 1;
CRC ^= dwPolynomial;
}
else
CRC <<= 1;
if (data & xbit)
CRC ^= dwPolynomial;
xbit >>= 1;
}
}
return CR;
}
以下为C#中CRC-32/MPEG-2算法:
private UInt32 CRC32_MPEG_2(uint[] data, int length)
{
uint i;
UInt32 crc = 0xffffffff, j = 0;
while ((length--) != 0)
{
crc ^= (UInt32)data[j] << 24;
j++;
for (i = 0; i < 8; ++i)
{
if ((crc & 0x80000000) != 0)
crc = (crc << 1) ^ 0x04C11DB7;
else
crc <<= 1;
}
}
return crc;
}
此代码和上述网址中CRC-32/MPEG-2计算结果一致。
以下是笔者根据STM32官方CRC单元C语言代码更改的C#代码:
UInt32 cal_crc(byte []ptr)
{
UInt32 data1 = 1;
UInt32 xbit;
UInt32 data;
UInt32 CRC = 0xffffffff;
uint[] CRC32_Data;
int len = ptr.Length;
CRC32_Data = new uint[len];
for (int i = 0; i < len; i++)
CRC32_Data[i] = ptr[i];
for (int i = 0; i < len; i++)
{
xbit = data1 << 31;
data = CRC32_Data[i];
for (int bits = 0; bits < 32; bits++)
{
if ((CRC & 0x80000000) != 0)
{
CRC = (CRC << 1) ^ 0x04C11DB7;
}
else
{
CRC = CRC << 1;
}
if ((data & xbit) != 0)
{
CRC = CRC ^ 0x04C11DB7;
}
xbit >>= 1;
}
}
return CRC;
}
计算结果和STM32计算结果一致。
STM32F10x、FL1x、F2x、F4x系列CRC模块使用起来比较简单,只需调用官方库中的函数:
//使能CRC模块时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
//复位CRC寄存器为初始值
CRC_ResetDR();
//计算data32位数组CRC校验值
CRC1 = CRC_CalcBlockCRC(data, length);
//计算一个32为数的CRC校验值
x=CRC_CalcCRC(Data);
而STM32F0x、F30x、F37x系列比较复杂,可以更改CRC校验多项式。
笔者根据C#CRC算法和STM32F103硬件CRC单元组成上位机和下位机通讯,校验结果相同。