cubeIDE开发, stm32的CRC计算CubeMX配置及HAL库底层实现分析

news2024/7/4 5:50:35

一、stm32的CRC

        1.1 CRC的简介及MCU关联说明

        STM32的CRC(Cyclic Redundancy Check,循环冗余校验)计算单元使用一个固定的多项式发生器,从一个32位的数据字产生一个CRC码。在业务开发应用中,会基于CRC的技术用于验证数据传输或存储完整性。在EN/IEC60335-1标准的范围内,它们提供了一种验证闪存(flash)完整性的方法。CRC计算单元帮助计算运行时软件的签名,并与在链接和生成该软件时产生的签名比较验证。

        基于CRC的技术用于验证数据传输一致性。

        CRC计算单元由CRC计算寄存器和CRC用户数据寄存器组成,前者用于从后者读取相关设置及芯片ID等信息进行计算,后者用于存储用户标记或临时数据。

        本文采用的是STM32L496xx系列MCU芯片,该系列是96bit的芯片ID编码,每个芯片编码是唯一的,出厂时固化,不可修改。芯片编码作用主要与产品安全相关,可用于产品序列号; 可用来作为密码,提高安全性;可用来保护程序的不可复制。

              CRC计算单元在MCU正常、低功耗及睡眠等运行模式下均有效,如下图。

         CRC计算单元挂接在AHB总线上,其RCC时钟采用APB1时钟频率。

         CRC计算单元在写入及读取都是指向同一数据寄存器,但读取及写入数据内容却不相同。

          CRC计算单元在MCU内占据1024bit(0X3FF)寄存器空间。

         1.2 CRC的CubeMX配置说明

        在STM32CubeMX配置中,开启CRC计算功能只要选择激活按键就可以开通,激活后,可以配置5项参数,如下图所示。

         多项式配置参数,是一个32位的参数,主要用来标识多项式的幂值,是用于CRC计算单元的重要参数,例如,参数0X01000200,其二进制是0000 0001 0000 0000 0000 0010 0000 0000,则多项式计算公式为X^24 + X^9,即二进制数里那个位值为1,则其数据位值就作为幂函数的整数因变量。CubeMX的CRC计算功能的多项式配置选择默认配置时,该参数默认值是一个32bit的数据,其值为0x04C11DB7,其多项式则为X^32 + X^26 + X^23 + X^22 + X^16 + X^12 + X^11 + X^10 +X^8 + X^7 + X^5 + X^4 + X^2+ X +1。

        若关闭默认配置,CubeMX将支持用户自定义多项式参数值,在基于默认参数值基础上做调整,如下图,数据长度支持7、8、16、32bit的选择,相应的,多项式也会限制在7、8、16、32的最大整数因变量:

         CRC初值默认是0xFFFFFFFF,CubeMX还支持用户关闭默认值及自定义CRC初值,如下图所示。

         输入数据反转模式支持NONE、BYTE、HALFWORD、WORD四种模式选择,默认是NONE模式。如果我们开启BYTE模式,输入数据0X12345678时。其二进制是0001 0010 0011 0100 0101 0110 0111 1000,因为是BYTE模式,就是每8bit做高低位反转,就是每8位二进制数由原来的高到底次序,变更为底到高次序,就案例数据来说分为4组8bit数据,前8bit数据变为0100 1000,接着后面8bit数据变为0010 1100 ,第三组变为0110 1010 ,最后一组变为0001 1110,则组合在一起是0100 1000 0010 1100 0110 1010 0001 1110,采用16进制表示就是0X482C6A1E。类似的如果是HALFWORD模式,则将数据分为2组16bit数据反转,则为0X2C281E6A;若选择WORD模式,则是一组32bit的数据反转,则为0X1E6A2C48。

         数据输入格式可以选择BYTES、HALFWORDS、WORDS三种格式,HLA库的CRC计算,会根据数据输入格式选择8bit、16bit、32bit分组数据进行CRC计算。

        输出数据反转模式只有开启和关闭两种选择,开启时,输出数据会进行反转,还是以输出数据是0X12345678为例,开启输出反转后,实际输出数据是0X1E6A2C48,即类似输入数据反转的32bit作为一组数据反转。

 二、CRC计算工程配置及HLA源码分析

        2.1 CRC测试工程创建及配置

        本文为采用的是stm32L496VGTx-ali开发板来建立测试工程,并按本专栏前面的博文移植好了lpuart1串口调试及按键功能,请自行参考。

cubeIDE开发, stm32调试信息串口通信输出显示_py_free的博客-CSDN博客_调试信息输出到串口

        现双击.ioc文件,打开CubeMX配置界面,开启CRC计算功能,参数保持默认设置。

         保存及生成输出代码

        2.2 CRC的HLA库分析

        cubeMX生成代码时,会在Core源码目录下的Inc及Src目录,分别生成crc.h和crc.c驱动文件。

        在crc.c文件中,主要定义了MX_CRC_Init函数和HAL_CRC_MspInit函数。MX_CRC_Init主要做两件事情,一是将CubeMX上配置的参数传递给CRC缓存Init和生成CRC句柄Instance(寄存器),二是调用HLA库的HAL_CRC_Init来实现真正的初始化设定。HAL_CRC_MspInit是HLA内的弱函数,根据实际配置CubeMX会生成新的函数,完成真正的MCU底层设置任务(MspInit,MCU Specific Package init,即指和MCU相关的初始化),覆盖原来的弱函数,而在HAL_CRC_Init函数中会调用到HAL_CRC_MspInit函数。

         在stm32l4xx_hal_crc.c源文件中定义了HAL_CRC_Init函数,它做以下事情:诊断配置参数是否合规;调用HAL_CRC_MspInit函数完成CRC时钟开启;最后将依据参数写入CRC寄存器,如果采用默认多项式参数,写入默认多项式数值,否则调用多项式配置函数,写入用户定义数值。

         再回到crc.c内,HAL_CRC_MspInit函数实现了CRC时钟启动设置。

         另外HLA库提供了用户自定义设置多项式参数、输入数据反转及输入数据反转的函数,方便开发这在程序代码中按需变更CRC计算方式,这些函数作为扩展功能放置在stm32l4xx_hal_crc_ex.h/c内。

         2.3 CRC计算功能及调用设计

        在stm32l4xx_hal_crc.c源文件除了定义初始化功外,还定义了CRC计算功能函数HAL_CRC_Accumulate和HAL_CRC_Calculate,HAL_CRC_Accumulate函数使用先前的CRC值和新的CRC值的组合来计算8、16或32位数据缓冲器的7、8、16和32位CRC值;HAL_CRC_Calculate独立于先前的CRC值,计算8、16或32位数据缓冲器的7、8、16和32位CRC值,因此它不同于HAL_CRC_Accumulate的部分是每次计算一组数据前,都会进行数据寄存器重置

         在main.c文件中,加入驱动文件支持

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "../../ICore/key/key.h"
#include "../../ICore/led/led.h"
#include "../../ICore/print/print.h"
#include "../../ICore/usart/usart.h"
#include "../../ICore/delay/delay.h"
/* USER CODE END Includes */

        在main.c文件中,加入CRC句柄(寄存器)声明

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern CRC_HandleTypeDef hcrc;
/* USER CODE END 0 */

        在main函数中,加入外设驱动启用(主要是串口调试中断开启)及相关初始设置,添加了一组3个长度32bit宽的数据数组用于测试。

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_LPUART1_UART_Init();
  MX_CRC_Init();
  /* USER CODE BEGIN 2 */
  ResetPrintInit(&hlpuart1);
  HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
  HLPUSART_RX_STA = 0;
  //
  printf("app restart now!\r\n");
  uint32_t crc_input[3] = {0X12345678,0X23456789,0X34567890};
  uint32_t crc_output = 0x00;
  uint32_t crc_index = 0;
  uint8_t crc_mode = 0;
  /* USER CODE END 2 */

        在main函数循环体中,通过按钮调用CRC计算功能,并通过lpuar1串口输出显示计算结果。

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  	  if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
  		  //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
  		  HLPUSART_RX_STA=0;//接收错误,重新开始
  		  HAL_Delay(100);//等待
  	  }
	  if(KEY_0())
	  {
		  crc_output = HAL_CRC_Accumulate(&hcrc,crc_input,3);
		  printf("crc_Accumulate_output:0X%08lX\r\n",crc_output);
	  }
	  if(KEY_1())
  	  {
		  crc_output = HAL_CRC_Calculate(&hcrc,crc_input,3);
		  printf("crc_Calculate_output:0X%08lX\r\n",crc_output);
  	  }
	  if(KEY_2())
  	  {
		  crc_mode = (crc_index)%6;
		  switch(crc_mode){
		  case 0:
			  HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_ENABLE);
			  printf("Output_Data_Reverse:0X%08lXU\r\n",CRC_OUTPUTDATA_INVERSION_ENABLE);
			  break;
		  case 1:
			  HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_DISABLE);
			  printf("Output_Data_Reverse:0X%08XU\r\n",CRC_OUTPUTDATA_INVERSION_DISABLE);
			  break;
		  case 2:
			  HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_BYTE);
			  printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_BYTE);
		  	  break;
		  case 3:
			  HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_HALFWORD);
			  printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_HALFWORD);
			  break;
		  case 4:
			  HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_WORD);
			  printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_WORD);
		  	  break;
		  case 5:
			  HAL_CRCEx_Polynomial_Set(&hcrc,DEFAULT_CRC32_POLY,CRC_POLYLENGTH_16B);
			  printf("Polynomial_Set:0X%04XU\r\n",DEFAULT_CRC32_POLY);
		  	  break;
		  default:
			  break;
		  }
		  crc_index++;
  	  }
    /* USER CODE END WHILE */

三、编译及测试

        3.1 编译下载

        3.2 测试

        程序开启时,默认多项式参数是0x04C11DB7U,无输入、输出反转。每按键一次KEY2改变输入反转模式或输出反转模式或多项式参数 ,然后各按键一次KEY0和KEY1, log输出如下:

         案例只是抛砖引玉,更多CRC功能及应用拓展请自行上手代码实践。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/136102.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python基础_05】面向对象1_对象和类、魔术方法

文章目录1. 类和对象1.1 使用对象组织数据的模版1.2 成员变量和成员方法1.3 实现代码2. 内置方法(魔术方法)2.1 构造方法: __init__()2.2 __call__()2.3 __len__()2.3 __str__()2.4 __getitem__()2.5 __setitem__()2.6 __delitem__()2.7 __lt…

【从零开始学习深度学习】35. 门控循环神经网络之门控循环单元(gated recurrent unit,GRU)介绍、Pytorch实现GRU并进行训练预测

在循环神经网络中,当时间步数较大或者时间步较小时,循环神经网络的梯度较容易出现衰减或爆炸。上一篇文章中介绍的裁剪梯度可以应对梯度爆炸,但无法解决梯度衰减的问题。因此,循环神经网络在实际中较难捕捉时间序列中时间步距离较…

Elastic-Job分布式任务调度(1):概述

1 什么是任务调度 我们可以先思考一下下面业务场景的解决方案: 某电商系统需要在每天上午10点,下午3点,晚上8点发放一批优惠券。某银行系统需要在信用卡到期还款日的前三天进行短信提醒。某财务系统需要在每天凌晨0:10结算前一天的财务数据…

【自学Python】Linux安装Python

Linux安装Python Python下载 Python下载地址 https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xzPython下载 我们在 Linux 终端中,直接使用 wget 命令,下载 Linux 版 Python 的安装包,我们在终端输入以下命令: wg…

PAT乙级|1094 谷歌的招聘

题源https://pintia.cn/problem-sets/994805260223102976/exam/problems/1071785997033074688 提交1:一个用例没过 提交2:AC 错因:输出需为字符串,例如在 200236 中找 4 位素数,解是0023 关键:第33行代码…

linphone android sdk 源码下载编译

前言 前面的有写过Android 使用Linphone SDK开发SIP客户端相关的文章, 在后续的开发过程中, 为了更深入了解linphone, 便尝试下载SDK源码自行编译. 关于linphone这里不作过多介绍, 可以参考前面的文章. Linphone-SDK 是一个将 Liblinphone 及其依赖项捆绑为 git 子模块的项目&a…

HTC FOCUS3在PC端串流FOHEART H1数据手套(手柄)

本教程介绍使用FOHEART H1数据手套与HTC手柄驱动VR中的虚拟手运动,实现手部的追踪及定位。 本教程内容与之前使用腕带定位(HTC FOCUS3在PC端串流FOHEART H1数据手套(腕带))不同,这次我们使用头显中自带的…

【Kuangbin简单DP】挤奶时间

4561. 挤奶时间 - AcWing题库 题意: 思路: 一开始的思路是把这么多的区间当作物品,然后选与不选,这样去搞线性DP 显然是不行的,因为这样答案就不知道怎么统计了 而且,我们是设阶段!&#xf…

HSK汉语考试变革,您需要了解以下几点

2023年HSK考试可能有哪些变化汉语考试难度增加了还是减低了? 对现在的课程和教材有影响? 汉语老师怎么样应对?HSK考试变化猜想1.HSK3级考试和HSKK初级结合在一起 2.HSK4级考试和HSKK中级结合在一起 3.HSK5,6级考试和HSKK高级结合在一起HSKK考…

INTERSPEECH 2022|面向零样本声音克隆的内容相关细粒度说话人表征方法

本文由清华大学与腾讯 AI Lab、香港中文大学合作。 零样本说话人自适应(zero-shot speaker adaptation),或称为零样本声音克隆,旨在根据任意一条参考语音(reference speech)合成训练过程中从未见过的说话人…

Leetcode:239. 滑动窗口最大值(C++)

目录 问题描述: 实现代码和解析: 暴力法(会超时): 原理思路: 单调队列法: 原理思路: 单调队列: 模拟过程: 问题描述: 给你一个整数数组…

Python基础知识(二)

目录 顺序语句 条件语句 条件语句书写格式一及对比:if条件语句 条件语句书写格式二及对比:if...else...语句 条件语句书写格式三及对比:if...elif...else语句 空语句pass 条件语句的总结: 循环语句 while循环 与c/java/…

对于Muduo主从Reactor模式的理解

从12月20号开始看Muduo网络库,到28号的时候弄懂了EventLoop, Poller, Channel是怎么一回事,一番琢磨之后觉得还是应该发到博客上跟大家分享,特此记录。 对照linyacool那个webserver的实现,再看了一遍muduo的EventLoop, Poller ,C…

IDEA快速启动多个微服务模块 -idea如何开启Run DashBoard

文章目录 缘起 Run DashBoard面板如何开启开启 Run DashBoard 注意: 缘起 在idea里面如果需要启动多个项目的话,尤其是是比如微服务项目,动辄要启动五六个七八个应用,如果通过右上角那边启动会很不方便,你需要选择…

基于GIS简单处理世界土壤数据库(HWSD)的中国土壤数据集

来源:GIS前沿 一、 数据介绍 土壤属性表主要字段包括(图1):详细描述请参考Harmonized World Soil Database (version 1.1).pdf文件,其中以T开头的土壤属性表示土壤上层的属性(0-30cm)&#xff…

【曲线全局逼近】

曲线全局逼近 本文是基于 这篇文章 翻译而来的,仅学习。 在插值中,插值曲线以给定的顺序通过所有给定的数据点。正如在全局插值页面中所讨论的,插值曲线可能会在所有数据点上摆动,而不是紧紧跟随数据多边形。为了克服这个问题&…

包装类的使用

文章目录一、单元测试方法的使用步骤二、包装类的使用基本数据类型、包装类、String类型之间的相互转化基本数据类型——>包装类注意包装类——>基本数据类型自动装箱与自动拆箱(jdk5.0后)基本数据类型、包装类——>String类型String类型——&g…

史上最全 Appium 自动化测试从基础到框架实战精华学习笔记(一)

1080402 31.8 KB 对测试人来说,Appium 是非常重要的一个开源跨平台自动化测试工具,它允许测试人员在不同的平台(iOS、Android 等)使用同一套 API 来写自动化测试脚本,这样可大幅提升代码复用率和工作效率。 本文汇总了…

郭盛华:警惕家庭智能扬声器中潜在的窃听风险

一名安全研究人员因识别Google Home智能扬声器中的安全问题而获得了107500美元的漏洞赏金,这些问题可能被用来安装后门并将其变成窃听设备。 国际知名网络黑客安全专家、东方联盟创始人郭盛华在一篇技术文章中透露:这些漏洞“允许无线附近的攻击者在设备…

服务的雪崩以及解决方案

文章目录一、什么是服务的雪崩二、服务雪崩形成的原因三、雪崩解决方案3.1 设置超时时间3.2 线程隔离(舱壁模式)3.3 熔断器(断路器)3.4 限流四、总结一、什么是服务的雪崩 服务的雪崩效应是一种因服务提供者不可用导致服务调用者…