STM32F10x 学习笔记3之CRC计算单元

发布者:老桃子最新更新时间:2020-11-21 来源: eefocus关键字:STM32F10x  CRC  计算单元 手机看文章 扫描二维码
随时随地手机看文章

STM32F 系列的单片机内部带了CRC32 计算单元。这个内置CRC模块的方法使用非常简单。其操作如下图所示。

图 1 CRC计算单元框图


归纳起来有如下几步操作:


1. 开启CRC单元的时钟。RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE)

2. 复位CRC模块(设置CRC_CR=0x01),这个操作把CRC余数初始化为0xFFFFFFFF

3. 把要计算的数据按逐个地写入CRC_DR寄存器

4. 写完所有的数据字后,从CRC_DR寄存器读出计算的结果

STM32F10x StdPeriph Driver 中提供了几个函数。


CRC_ResetDR(void) 

用来复位CRC模块。


uint32_t CRC_CalcCRC(uint32_t Data)

将一个数据写入CRC_DR寄存器,返回值为计算结果。


uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength)

计算一个数组的CRC 值。


uint32_t CRC_GetCRC(void)

读取CRC_DR寄存器的结果。


另外,CRC 模块中还有个独立数据寄存器(CRC_IDR)。这是个单字节的寄存器,用于临时存放1字节的数据,不受复位操作影响。相应的操作函数有两个。


void CRC_SetIDRegister(uint8_t IDValue)

uint8_t CRC_GetIDRegister(void)

分别是写CRC_IDR和读 CRC_IDR 寄存器。


虽然STM32F 上的CRC 单元用起来很简单,但是似乎它计算出来的结果与传统的CRC32算法得到的结果有些不同。

下面是个简单的例子。


#include "stm32f10x.h"  

  

int main(void)  

{  

    uint32_t j;  

    uint32_t str[11] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', ' '};  

      

    SystemInit();  

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);  

    CRC_ResetDR();  

  

    str[9] = CRC_CalcBlockCRC(str, 1);  

    CRC_ResetDR();  

    CRC_CalcCRC(0xA5A5A5A5);  

    j = CRC_GetCRC();  

    CRC_CalcCRC(j);  

    for(;;)  

    {  

    }     

}  

。还指出了这个CRC 单元计算的结果与常见的CRC32 算法得到的结果不相同。但是为什么不相同,是什么原因造成的却没有写出来。这里再补一篇,把这些都说清楚。

下面先给个crc32的计算函数,这个函数计算的结果与STM32F 单片机上硬件单元的计算结果相同。


uint32_t crc32(uint32_t *addr, int num, uint32_t crc)  

{  

    int i;  

    for (; num > 0; num--)                

    {  

        crc = crc ^ (*addr++);       

        for (i = 0; i < 32; i++)               

        {  

            if (crc & 0x80000000)              

                crc = (crc << 1) ^ POLY;     

            else                            

                crc <<= 1;                   

        }                               

        crc &= 0xFFFFFFFF;              

    }                                 

    return(crc);                     

}  


在我写的文章《写给嵌入式程序员的循环冗余校验(CRC)算法入门引导》(http://blog.csdn.net/liyuanbhu/article/details/7882789) 中给了个利用查表法计算crc 的程序。那个程序稍微修改一点就能计算CRC32。下面给出改动后的程序。


//crc32.h  

  

#ifndef CRC32_H_INCLUDED  

#define CRC32_H_INCLUDED  

  

#ifdef __cplusplus  

#if __cplusplus  

extern "C"{  

    #endif  

    #endif /* __cplusplus */  

  

  

#include  

  

/* 

* The CRC parameters. Currently configured for CRC32. 

* CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+X0 

*/  

  

#define POLYNOMIAL          0x04C11DB7  

#define INITIAL_REMAINDER   0xFFFFFFFF  

#define FINAL_XOR_VALUE     0x00000000  

  

/* 

* The width of the CRC calculation and result. 

* Modify the typedef for an 8 or 32-bit CRC standard. 

*/  

typedef uint32_t width_t;  

#define WIDTH (8 * sizeof(width_t))  

#define TOPBIT (1 << (WIDTH - 1))  

  

/** 

 * Initialize the CRC lookup table. 

 * This table is used by crcCompute() to make CRC computation faster. 

 */  

void crcInit(void);  

  

/** 

 * Compute the CRC checksum of a binary message block. 

 * @para message, 用来计算的数据 

 * @para nBytes, 数据的长度 

 * @note This function expects that crcInit() has been called 

 *       first to initialize the CRC lookup table. 

 */  

width_t crcCompute(unsigned char * message, unsigned int nBytes, width_t remainder);  

  

  

#ifdef __cplusplus  

    #if __cplusplus  

}  

#endif  

#endif /* __cplusplus */  

  

#endif // CRC32_H_INCLUDED  


对应的C程序如下:


#include "crc32.h"  

/* 

* An array containing the pre-computed intermediate result for each 

* possible byte of input. This is used to speed up the computation. 

*/  

static width_t crcTable[256];  

  

/** 

 * Initialize the CRC lookup table. 

 * This table is used by crcCompute() to make CRC computation faster. 

 */  

void crcInit(void)  

{  

    width_t remainder;  

    width_t dividend;  

    int bit;  

    /* Perform binary long division, a bit at a time. */  

    for(dividend = 0; dividend < 256; dividend++)  

    {  

        /* Initialize the remainder.  */  

        remainder = dividend << (WIDTH - 8);  

        /* Shift and XOR with the polynomial.   */  

        for(bit = 0; bit < 8; bit++)  

        {  

            /* Try to divide the current data bit.  */  

            if(remainder & TOPBIT)  

            {  

                remainder = (remainder << 1) ^ POLYNOMIAL;  

            }  

            else  

            {  

                remainder = remainder << 1;  

            }  

        }  

        /* Save the result in the table. */  

        crcTable[dividend] = remainder;  

    }  

} /* crcInit() */  

  

/** 

 * Compute the CRC checksum of a binary message block. 

 * @para message, 用来计算的数据 

 * @para nBytes, 数据的长度 

 * @note This function expects that crcInit() has been called 

 *       first to initialize the CRC lookup table. 

 */  

width_t crcCompute(unsigned char * message, unsigned int nBytes, width_t remainder)  

{  

    unsigned int offset;  

    unsigned char byte;  

    //width_t remainder = INITIAL_REMAINDER;  

    /* Divide the message by the polynomial, a byte at a time. */  

    for( offset = 0; offset < nBytes; offset++)  

    {  

        byte = (remainder >> (WIDTH - 8)) ^ message[offset];  

        remainder = crcTable[byte] ^ (remainder << 8);  

    }  

    /* The final remainder is the CRC result. */  

    return (remainder ^ FINAL_XOR_VALUE);  

} /* crcCompute() */  


不过用这个程序直接计算得到的CRC 值与STM32 给出的并不相同。之所以会这样是因为字节序的原因。可以举个例子来说明这个问题。比如我们有一片内存区域要计算CRC值。这片内存区域的起始地址是 0x1000,共有8个字节。用 crcCompute() 函数计算时是按照地址顺序依次传入各个字节。也就是先计算0x1000 处的字节,再计算0x0001 处的字节,以此类推最后计算0x1007 地址处的字节。而 STM32 的硬件CRC单元是以32位的字为单位计算的。我们知道CRC 实际上是个多项式的除法运算,而除法运算是从高位算起的。也就是相当于它是按照 0x1003、0x1002、0x1001、0x1000 这个顺序计算第一个字,然后按照0x1007、0x1006、0x1005、x1004 的顺序计算第二个字。因此。我们要是预先将字节序调换一下得到结果就没有问题了。这就有了下面的改造。其中 remainder 传入 0xffffffff。因为STM32 中的CRC余数初始值为0xffffffff。


uint32_t stm32crc32(uint32_t * message, unsigned int nWords, uint32_t remainder)  

{  

    unsigned int offset;  

    unsigned char byte;  

    unsigned char *p = (unsigned char *)message;  

    //width_t remainder = INITIAL_REMAINDER;  

    /* Divide the message by the polynomial, a byte at a time. */  

    for( offset = 0; offset < nWords; offset++)  

    {  

        byte = (remainder >> (WIDTH - 8)) ^ p[3];  

        remainder = crcTable[byte] ^ (remainder << 8);  

  

        byte = (remainder >> (WIDTH - 8)) ^ p[2];  

        remainder = crcTable[byte] ^ (remainder << 8);  

  

        byte = (remainder >> (WIDTH - 8)) ^ p[1];  

        remainder = crcTable[byte] ^ (remainder << 8);  

  

        byte = (remainder >> (WIDTH - 8)) ^ p[0];  

        remainder = crcTable[byte] ^ (remainder << 8);  

[1] [2]
关键字:STM32F10x  CRC  计算单元 引用地址:STM32F10x 学习笔记3之CRC计算单元

上一篇:STM32F10x 学习笔记之SysTick 定时器
下一篇:STM32F10x 学习笔记之独立看门狗IWDG 模块

推荐阅读最新更新时间:2024-11-10 22:02

keil5+STM32F10x 使用ST-Link烧写程序;使用FlyMcu烧写程序
ST-Link 这个是J-Link调试,应该差不多: https://www.cnblogs.com/sovagxa/p/8997388.html 淘宝店家给的调试器是ST-Link的: 运行后,首先先连接: 之后打开要下载的.hex文件,图中对应按钮打开文件: 设置settings,选择SWD: 之后点击编程并校验: FlyMcu usb连接时,要注意usb1是可以下载程序的,usb2不行 选择对应的端口,选项是校验与编程后执行,RTS的高电平复位DTR低电平进BootLoader 之后选择一个.hex文件,点击开始编程:
[单片机]
keil5+STM32F10x 使用ST-Link烧写程序;使用FlyMcu烧写程序
2018CSH暨全球异构系统架构标准(HSA CRC)研讨会在湖南召开
2018年5月29日,中国异构系统架构标准(CSH)暨全球异构系统架构标准(HSA CRC)研讨会在湖南理工学院圆满召开。本次会议由中国电子技术标准研究院、全球异构系统架构联盟中国区域委员会(HSA CRC)主办,中国异构系统架构标准工作组(CSH)和湖南理工学院承办。来自HSA联盟会员单位、中国异构系统架构标准工作组成员单位、相关高校、科研院所及企事业单位的50余名专家学者出席了本次会议。 近年来,异构计算作为高端可编程芯片、低功耗软件定义芯片、嵌入式计算、高性能计算等领域的研究热点和主流计算机体系架构的发展方向,受到国内外广泛关注。本次会议围绕国内和国际异构计算标准研究的最新进展及异构计算在人工智能、智能安防、智能机
[嵌入式]
2018CSH暨全球异构系统架构标准(HSA <font color='red'>CRC</font>)研讨会在湖南召开
40位以内任意长度的CRC计算及校验的实现
1 引言    循环冗余校验码,简称CRC码,是常用的检测错误码,它在数据通信中得到了非常广泛的应用。不同CRC码的生成多项式各不相同,CRC码的比特数也不同,且在有的通信协议中要求将余数寄存器先初始化为全0,另外的则须初始化为全1。因此,在程序设计时必须充分利用CRC码的共性及所用DSP的指令特点。 2 用TMS320C5000实现不同CRC计算的设计思想 CRC码的计算及校验都用到模2的多项式除法,而多项式除法可以采用带反馈的移位寄存器来实现,因此,用DSP来实现CRC计算的关键是通过DSP来模拟一个移位寄存器(也就是模拟手写多项式除法)。考虑到TMS320C5000系列DSP的累加器A和B均为40位,因此,可以用一个40
[单片机]
40位以内任意长度的<font color='red'>CRC</font><font color='red'>计算</font>及校验的实现
PIC单片机实现CRC算法的小程序
PIC单片机实现CRC的小程序 PIC单片机实现Dallas的iButton通讯时,编了段产生和校验CRC的子程序。 #include P16CE625.INC ;------------------------------- cblock 0x20 datBuff:8 ;assign 8 byte data buffer bit_cnt ;bit counting CRC_COUNT ;number of bytes for CRC CRC_RESULT ;CRC resulr crc_temp ;temporary data buffer during CRC e
[单片机]
Stm32f10x 新建工程详解
环境: STM32F10x 3.5固件库。下载地址 http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32f10x_stdperiph_lib.zip MDK4.23 编译器 一、第一步新建工程 取名 NewProject 图1 二、选择芯片型号 图2 三、点否,不加载启动文件(后面我们自己手动添加) 图3 四、在工程下新建STM32LIB,OBJ,LIST,APP四个文件夹(文件名可自定)。 在STM32LIB文件夹下新建M3文件夹。 复制STM32F10x_StdPeriph_Lib_V3.5.0\Li
[单片机]
<font color='red'>Stm32f10x</font> 新建工程详解
[单片机] crc32
// Referenced from http://www.w3.org/TR/PNG/#D-CRCAppendix #ifdef MAKE_CRC32_TABLE static unsigned long crc_table ; static int crc_table_computed = 0; static void make_crc_table(void) { unsigned long c; unsigned long n, k; for (n = 0; n 256; n++) { c = n; for (k = 0; k 8; k++) { if (c & 1
[单片机]
STM32F10x 学习笔记之USART实现串口通讯 DMA 方式
STM32F10x 的USART 支持DMA 方式,并且在DMA完成后可以产生中断。这对于需要接收或发送大量数据的应用情景是很有帮助的。 在普通的8位或16位单片机中很少有包含DMA控制器的,所以可能许多嵌入式程序员对DMA方式并不熟悉。简单的说,直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。由于无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。 STM32F10x 上具有两个DMA控制器,共有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。
[单片机]
<font color='red'>STM32F10x</font> 学习笔记之USART实现串口通讯 DMA 方式
自学STM32F10x单片机需要注意的地方
由于之前一直使用PIC和51的芯片,从没接触过STM32系列的芯片,近期着手学习STM32F10x的芯片,通过学习后发现STM32的中断系统比较特殊(与PIC和51相比较........),有着不同的响应方式,看了几遍相关的手册和视频资料,还是有些稀里糊涂,通过实际写代码配置芯片后,逐渐有点眉目了,因此想记录下来,算是总结笔记。当然文章中有存在描述错误和不足的地方,还请大家指正。(可能有些地方理解的方式存在问题,望指教。) STM32采用了ARM Cortex_M3内核,而Cortex_M3内核具有256个中断源,其中内核自己的有16个中断源和外部设备的(最多)240个中断源,每个中断源都具有自己独立的中断优先级控制寄存器,该
[单片机]
自学<font color='red'>STM32F10x</font>单片机需要注意的地方
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved