天南地北客
发表于: 2016-10-19 09:48:36 | 显示全部楼层

STM32F0系列相对于STM32F1系列来说,CRC功能有所增强。当然,这个CRC功能在F7啊什么这些高端系列也有。STM32系列各个功能之间的区别具体可以看看手册,如:STM32微控制器应用程序移植和兼容性检测指导手册

img_57b9c0f4b85e0.png

CRC运算对于人来说,费力不讨好,但对于机器来说,都是XOR啊,太简单了。以下这个是CRC32验证过的程序:

  1. uint32_t crc32(uint32_t *ptr, uint32_t len)
  2. {
  3.     uint32_t        xbit;
  4.     uint32_t        data;
  5.     uint32_t        CRC32 = 0xFFFFFFFF;
  6.     uint32_t  bits;
  7.     const uint32_t dwPolynomial = 0x04c11db7;
  8.     uint32_t        i;

  9.     for(i = 0; i < len; i ++)
  10.     {
  11.         xbit = 1 << 31;
  12.         data = ptr[i];
  13.         for (bits = 0; bits < 32; bits++)
  14.         {
  15.             if (CRC32 & 0x80000000)
  16.             {
  17.                 CRC32 <<= 1;
  18.                 CRC32 ^= dwPolynomial;
  19.             }
  20.             else
  21.                 CRC32 <<= 1;
  22.             if (data & xbit)
  23.                 CRC32 ^= dwPolynomial;

  24.             xbit >>= 1;
  25.         }
  26.     }
  27.     return CRC32;
  28. }
复制代码

ST官方也专门演示了一下CRC的计算过程,不过不是特别的好看,->链接地址

img_57b9c1de83675.png

比如通过这个方法来计算一次CRC数据:

  1. static const uint32_t aDataBuffer[1] = {0x00001021};
  2. static const uint32_t bDataBuffer[1] = {0x00001021};

  3. uwCRCValue = HAL_CRC_Calculate(&CrcHandle, (uint32_t *)aDataBuffer, 1);
  4. uwExpectedCRCValue = crc32((uint32_t *)bDataBuffer, 1);

  5. if (uwCRCValue != uwExpectedCRCValue)
  6. {
  7.     Error_Handler();
  8. }
  9. else
  10. {
  11.     App_Handler();
  12. }
复制代码

控制寄存器如下(输出不翻转,输入不翻转,32位长。CRC_INIT确实怎么都返回0,但是没改过):

img_57b9c37c75729.png

计算结果符合预期:

img_57b9c3dd1a306.png

对了,F0的CRC功能就是比F1强大。强在哪里呢?就是输入翻转,输出翻转,长度可调,多项式可调。

比如我现在输入翻转,0x00001021翻转,怎么处理呢?比如整WORD翻转。

img_57b9c4ec324b9.png

所以我们的翻转结果是这样的。

img_57b9c59147e37.png

程序改成这样:

  1. static const uint32_t aDataBuffer[1] = {0x00001021};
  2. static const uint32_t bDataBuffer[1] = {0x84080000};

  3. uwCRCValue = HAL_CRC_Calculate(&CrcHandle, (uint32_t *)aDataBuffer, 1);
  4. uwExpectedCRCValue = crc32((uint32_t *)bDataBuffer, 1);

  5. if (uwCRCValue != uwExpectedCRCValue)
  6. {
  7.     Error_Handler();
  8. }
  9. else
  10. {
  11.     App_Handler();
  12. }
复制代码

寄存器设置:

img_57b9c5df4ea33.png

计算结果:

img_57b9c601c3419.png

可见翻转方法就是这样的。当然还可以按照半字,Byte翻转。

img_57b9c62dcdbc7.png

还可以翻转输出。具体寄存器估计大家都已经明白了.。我抄了一个简单的翻转函数,用来翻转我人工计算结果.。这么魔性的函数源于:http://aggregate.org/MAGIC/#Bit%20Reversal

  1. uint32_t reverse(uint32_t x)
  2. {
  3.     x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
  4.     x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
  5.     x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
  6.     x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
  7.     return ((x >> 16) | (x << 16));
  8. }
复制代码

然后我的代码变成:

  1. static const uint32_t aDataBuffer[1] = {0x00001021};
  2. static const uint32_t bDataBuffer[1] = {0x84080000};

  3. uwCRCValue = HAL_CRC_Calculate(&CrcHandle, (uint32_t *)aDataBuffer, 1);
  4. uwExpectedCRCValue = crc32((uint32_t *)bDataBuffer, 1);
  5. uwExpectedCRCValue = reverse(uwExpectedCRCValue);

  6. if (uwCRCValue != uwExpectedCRCValue)
  7. {
  8.     Error_Handler();
  9. }
  10. else
  11. {
  12.     App_Handler();
  13. }
复制代码

当然,我抄翻转方法已经非常MAGIC,但是还是不够CRC自带的翻转快啊。因为:

img_57b9c7f1b7aa9.png

人家是一个机器周期都不用啊。

img_57b9c802123bc.png

我们再还原CR里面的所有配置,试试批量计算:

  1. static const uint32_t aDataBuffer[BUFFER_SIZE] =
  2. {
  3.     0x00001021, 0x20423063, 0x408450a5, 0x60c670e7, 0x9129a14a, 0xb16bc18c,
  4.     0xd1ade1ce, 0xf1ef1231, 0x32732252, 0x52b54294, 0x72f762d6, 0x93398318,
  5.     0xa35ad3bd, 0xc39cf3ff, 0xe3de2462, 0x34430420, 0x64e674c7, 0x44a45485,
  6.     0xa56ab54b, 0x85289509, 0xf5cfc5ac, 0xd58d3653, 0x26721611, 0x063076d7,
  7.     0x569546b4, 0xb75ba77a, 0x97198738, 0xf7dfe7fe, 0xc7bc48c4, 0x58e56886,
  8.     0x78a70840, 0x18612802, 0xc9ccd9ed, 0xe98ef9af, 0x89489969, 0xa90ab92b,
  9.     0x4ad47ab7, 0x6a961a71, 0x0a503a33, 0x2a12dbfd, 0xfbbfeb9e, 0x9b798b58,
  10.     0xbb3bab1a, 0x6ca67c87, 0x5cc52c22, 0x3c030c60, 0x1c41edae, 0xfd8fcdec,
  11.     0xad2abd0b, 0x8d689d49, 0x7e976eb6, 0x5ed54ef4, 0x2e321e51, 0x0e70ff9f,
  12.     0xefbedfdd, 0xcffcbf1b, 0x9f598f78, 0x918881a9, 0xb1caa1eb, 0xd10cc12d,
  13.     0xe16f1080, 0x00a130c2, 0x20e35004, 0x40257046, 0x83b99398, 0xa3fbb3da,
  14.     0xc33dd31c, 0xe37ff35e, 0x129022f3, 0x32d24235, 0x52146277, 0x7256b5ea,
  15.     0x95a88589, 0xf56ee54f, 0xd52cc50d, 0x34e224c3, 0x04817466, 0x64475424,
  16.     0x4405a7db, 0xb7fa8799, 0xe75ff77e, 0xc71dd73c, 0x26d336f2, 0x069116b0,
  17.     0x76764615, 0x5634d94c, 0xc96df90e, 0xe92f99c8, 0xb98aa9ab, 0x58444865,
  18.     0x78066827, 0x18c008e1, 0x28a3cb7d, 0xdb5ceb3f, 0xfb1e8bf9, 0x9bd8abbb,
  19.     0x4a755a54, 0x6a377a16, 0x0af11ad0, 0x2ab33a92, 0xed0fdd6c, 0xcd4dbdaa,
  20.     0xad8b9de8, 0x8dc97c26, 0x5c644c45, 0x3ca22c83, 0x1ce00cc1, 0xef1fff3e,
  21.     0xdf7caf9b, 0xbfba8fd9, 0x9ff86e17, 0x7e364e55, 0x2e933eb2, 0x0ed11ef0
  22. };

  23. uwCRCValue = HAL_CRC_Calculate(&CrcHandle, (uint32_t *)aDataBuffer, BUFFER_SIZE);
  24. uwExpectedCRCValue = crc32((uint32_t *)aDataBuffer, BUFFER_SIZE);

  25. if (uwCRCValue != uwExpectedCRCValue)
  26. {
  27.     Error_Handler();
  28. }
  29. else
  30. {
  31.     App_Handler();
  32. }
复制代码

结果也是正确的:

img_57b9ca5482b0a.png

CRC应用非常广泛。比如可以校验一下你Flash内容有没有被改动,传输数据包有没有问题,他是检错码,但不是纠错码。另外,默认用的是以太网标准的CRC-32。和使用工具计算的结果一致,如下图:

img_57b9ca98bf98f.png

STM32F0的CRC还可以让计算初值不是0xFFFFFFFF,如图配置:

img_57b9cc46b81da.png

与初值0xFFFFFFFF计算出来结果就完全不一样了。

img_57b9cc9861110.png

其实库函数里面还有一个叫HAL_CRC_Accumulate的函数。他的作用是累积CRC计算数值,执行一次时候,结果是一样的,但是,执行两次就不是了,因为他不清空之前的数值。

img_57b9cec6d0849.png

如果执行两次,结果如下:

img_57b9cf797eaf6.png

如果使用HAL_CRC_Calculate函数,就不会有问题,因为每次都清空.

img_57b9cfb0dd0f4.png

他们函数内只差了这么一句.

img_57b9cfe3cb960.png

累积的函数里面这一句是没有的.

img_57b9cff66ca41.png

CRC长度可以自定义等等,也是挺方便的,可以用于加密。CRC碰撞概率并不会很低,虽然说32位CRC是40亿才重复一次,但是那是特别理想情况,实际上远比这个要低。当然,如果合理的通过公式改变,输入数据改变,达到校验目的,也不是特别难的事情。


原文链接http://www.lijingquan.net/2016/08/28/stm32f0-rcr/


跳转到指定楼层
yongbutingzhi11
发表于: 2019-11-4 15:34:37 | 显示全部楼层

厉害厉害厉害厉害厉害
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 49 | 回复: 80



手机版|

GMT+8, 2024-12-23 08:08 , Processed in 0.061578 second(s), 8 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表