搜索
bottom↓
回复: 40

dma crc,令人吃惊的性能,计算1k个值竟然在0.2us内完成

  [复制链接]

出0入0汤圆

发表于 2015-3-12 00:49:33 | 显示全部楼层 |阅读模式
本帖最后由 myxiaonia 于 2015-3-12 00:51 编辑

dma实在太强大,stm32f1的crc计算,使用dma传输,在72m主频下,1k次竟然在0.2us内完成。。。。。。。。。。作为对比的软件传递方法,用时128us,这个差距,简直爆出翔了

不敢私藏代码,愿把测试代码奉上,希望对大家有用(计时是用的mdk调试模式时寄存器窗口中的时间值)

  1. #define CRC_START(src, len)     CRC->CR = CRC_CR_RESET;                 \
  2.                                {DMA_Channel_TypeDef *ps = DMA2_Channel1;  \
  3.                                                                 while(ps->CCR & DMA_CCR1_EN);    \
  4.                                 ps->CMAR         = (uint32_t)src;   \
  5.                                 ps->CNDTR         = len;             \
  6.                                 ps->CCR     |= DMA_CCR1_EN; }


  7. void CRC_DMA_Configuration(void)
  8. {
  9.     RCC->AHBENR          |= 0
  10.                          | RCC_AHBENR_CRCEN
  11.                          | RCC_AHBENR_DMA2EN
  12.                          ;
  13.     DMA2_Channel1->CPAR   = (uint32_t)&CRC->DR;
  14.         DMA2_Channel1->CCR         = 0
  15.                          | DMA_CCR1_MEM2MEM              //M2M模式传送
  16.                          | DMA_CCR1_PLVH                 //优先级最高
  17.                          | DMA_CCR1_MSIZE32              //外设位宽32位
  18.                          | DMA_CCR1_PSIZE32              //缓冲区位宽32位
  19.                          | DMA_CCR1_MINC                //缓冲区地址自增
  20. //                         | DMA_CCR1_PINC                //外设地址不变
  21. //                         | DMA_CCR1_CIRC                //非循环模式
  22.                          | DMA_CCR1_DIR                 //存储器到外设
  23.                          | DMA_CCR1_TEIE                //传输错误中断
  24. //                         | DMA_SxCR_HTIE
  25.                          | DMA_CCR_TCIE                //开启传输完成中断
  26. //                         | DMA_SxCR_EN                  //DMA流使能
  27.                          ;
  28. }


  29. void DMA2_Channel1_IRQHandler(void)
  30. {
  31.     DMA_Channel_TypeDef *pch = DMA2_Channel1;
  32.     DMA_TypeDef *pdma = DMA2;
  33.    
  34.     pch->CCR    &=~DMA_CCR1_EN;
  35.     pdma->IFCR   = DMA_IFCR_CGIF1;
  36. }

  37. uint32_t clc_crc(const uint32_t *ptr,uint32_t length)
  38. {
  39.         CRC->CR=CRC_CR_RESET;
  40.         for( ; length; --length)
  41.                 CRC->DR = *ptr++;
  42.         return CRC->DR;
  43. }

  44. int main(void)
  45. {
  46.     NVIC_SetPriority(DMA2_Channel1_IRQn,NVIC_EncodePriority(3,6,0));
  47.         NVIC_EnableIRQ(DMA2_Channel1_IRQn);
  48.         CRC_DMA_Configuration();
  49.         while(1)
  50.         {
  51.                 clc_crc((uint32_t *)0x2000c000,1024);
  52.                 CRC_START((void *)0x2000c000,1024);
  53.         }
  54. }
复制代码

出0入0汤圆

 楼主| 发表于 2015-3-12 09:00:06 | 显示全部楼层
NJ8888 发表于 2015-3-12 08:32
怎么可能,dma也要靠时钟,DMA的时钟不会快于你的系统时钟72MHz,13ns*1000=13us呐,反正我不信 ...

其实我也不相信,太不可思议了。。。。。我现在在项目代码测试的话,dma传输1K是160us,比软件传输还慢了,其中这个才是符合预期的,网上有人比较过dma代替memcpy,速度也是比不上的

我也很奇怪怎么会相差这么多,但是crc计算值确实是对的,我现在把这个测试例程发上来,大家看看到底哪里出了问题,为什么会这么快

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2015-3-12 01:11:51 | 显示全部楼层
收藏着,下次再看。正准备学习DMA~~~

出0入0汤圆

发表于 2015-3-12 02:25:28 | 显示全部楼层
感谢Lz的思路与数据.
感觉只有电子跟计算机的这么晚还不睡。

出0入0汤圆

 楼主| 发表于 2015-3-12 07:30:29 | 显示全部楼层
ghostxdy 发表于 2015-3-12 02:25
感谢Lz的思路与数据.
感觉只有电子跟计算机的这么晚还不睡。

早上还这么早上班了,是不是很悲摧

出0入0汤圆

发表于 2015-3-12 08:13:17 | 显示全部楼层
myxiaonia 发表于 2015-3-12 07:30
早上还这么早上班了,是不是很悲摧

收藏.可怜的电工.睡得比狗晚,起的比鸡早.

出0入0汤圆

发表于 2015-3-12 08:18:24 来自手机 | 显示全部楼层
睡那么晚研究这点东西,以后身体垮了,会后悔的

出5入8汤圆

发表于 2015-3-12 08:20:16 | 显示全部楼层
高性能   现在好多单片机内置硬crc了

出0入0汤圆

发表于 2015-3-12 08:23:45 | 显示全部楼层
忽然想起一个问题,stm32的crc能不能实现modbus的crc校验?如果这样,用自带的crc模块来计算校验,会快很多啊

出0入0汤圆

发表于 2015-3-12 08:24:48 | 显示全部楼层
你说我能相信么

出0入0汤圆

发表于 2015-3-12 08:30:04 | 显示全部楼层
cyr_hongfeng 发表于 2015-3-12 08:18
睡那么晚研究这点东西,以后身体垮了,会后悔的

的确如此......

出0入0汤圆

发表于 2015-3-12 08:32:09 | 显示全部楼层
怎么可能,dma也要靠时钟,DMA的时钟不会快于你的系统时钟72MHz,13ns*1000=13us呐,反正我不信

出0入0汤圆

发表于 2015-3-12 08:41:09 | 显示全部楼层
好方法,有机会找个和帧校验的程序里试一试。

出0入42汤圆

发表于 2015-3-12 08:53:47 | 显示全部楼层
果真如此强大吗?!

出0入0汤圆

发表于 2015-3-12 08:55:19 | 显示全部楼层
MARK.


出0入0汤圆

发表于 2015-3-12 08:56:09 | 显示全部楼层
我也表示怀疑,DMA的搬运也是有clock的,最大应该到72M,估计是哪儿算错了

出0入0汤圆

发表于 2015-3-12 09:06:35 | 显示全部楼层
如果你经常这样,程序快不快不知道,你倒是要快了

出0入0汤圆

 楼主| 发表于 2015-3-12 09:06:48 | 显示全部楼层
cyr_hongfeng 发表于 2015-3-12 08:18
睡那么晚研究这点东西,以后身体垮了,会后悔的

确实太纠结了,项目中掉电检测保存的数据用crc校验的,而crc模块程序中又有使用,用的fifo队列计算crc,我需要评估crc计算fifo满时的时间,尽管我提前知道了crc dma不会比软件传输快,我还是想看看真实的时间,结果测试代码中就出现了这样的情况

不应该搞这么迟了,切记切记

出0入0汤圆

 楼主| 发表于 2015-3-12 09:09:53 | 显示全部楼层
xhcyfc 发表于 2015-3-12 08:23
忽然想起一个问题,stm32的crc能不能实现modbus的crc校验?如果这样,用自带的crc模块来计算校验,会快很多 ...

不行的,f1的是以太网crc32,而且要真正兼容以太网crc的话,传输字节序还要调整,相当麻烦

飞思卡尔的crc模块好像可以调整crc多项式,f1的局限性比较大

出0入0汤圆

发表于 2015-3-12 10:24:58 | 显示全部楼层
lryxr2507 发表于 2015-3-12 08:13
收藏.可怜的电工.睡得比狗晚,起的比鸡早.

应该是睡得比鸡晚

出0入0汤圆

发表于 2015-3-12 14:12:17 | 显示全部楼层
72M, 1US只有72个时钟啊,

出0入0汤圆

发表于 2015-3-12 14:13:05 | 显示全部楼层
0.2US岂不是只有10多个时钟

出0入0汤圆

 楼主| 发表于 2015-3-12 14:37:58 | 显示全部楼层
huangqi412 发表于 2015-3-12 14:13
0.2US岂不是只有10多个时钟

所以我也觉得很神奇,关键是调试模式下就是那么点时间就完成了,计算的crc值和软件方法一样 我也是醉了  这到底是什么原因

你如果你兴趣,看看我上传的测试程序,是不是这样

出0入0汤圆

发表于 2015-3-12 14:48:03 | 显示全部楼层
myxiaonia 发表于 2015-3-12 14:37
所以我也觉得很神奇,关键是调试模式下就是那么点时间就完成了,计算的crc值和软件方法一样 我也是醉了   ...

额,为何不是用定时器记录时间。

出0入442汤圆

发表于 2015-3-12 16:17:11 | 显示全部楼层
myxiaonia 发表于 2015-3-12 09:09
不行的,f1的是以太网crc32,而且要真正兼容以太网crc的话,传输字节序还要调整,相当麻烦

飞思卡尔的cr ...

曾经花了一些时间研究CRC,1位CRC改一下字就行了,通常在传输过程中就算好了。并行的则一般用于后校验用。8位CRC字每周期出1字节,占256字(字,不是字节,32位CRC要占1KB),几乎没有16位并行的吧,要占256KB,而且没有加快多少。估计NAND,GMII用8位并行,RGMII用4位并行。其实多位并行的原理很简单,就是单位计算N步然后提特征字。超过8位的,我感觉是用了双倍时钟去算的,要不然表占的内存绝对会让人头疼。

出0入0汤圆

发表于 2015-3-12 18:17:45 | 显示全部楼层
楼主的时间是用cpu算出来的吧?其实dma工作时跟cpu的时间根本不是同步的,所以说这个时间不对

出0入0汤圆

 楼主| 发表于 2015-3-12 19:30:46 来自手机 | 显示全部楼层
wye11083 发表于 2015-3-12 16:17
曾经花了一些时间研究CRC,1位CRC改一下字就行了,通常在传输过程中就算好了。并行的则一般用于后校验用 ...

你是说硬件crc原理么,那个不是像移位寄存器一样一位位算的

出0入0汤圆

 楼主| 发表于 2015-3-12 19:35:10 来自手机 | 显示全部楼层
9509238 发表于 2015-3-12 18:17
楼主的时间是用cpu算出来的吧?其实dma工作时跟cpu的时间根本不是同步的,所以说这个时间不对 ...

那个寄存器窗口时间是通过指令数计算的,我用ms中断测过,非常准,我在dma开启处和中断入口打断点,这个没有问题

出300入477汤圆

发表于 2015-3-12 21:46:37 来自手机 | 显示全部楼层
myxiaonia 发表于 2015-3-12 19:35
那个寄存器窗口时间是通过指令数计算的,我用ms中断测过,非常准,我在dma开启处和中断入口打断点,这个 ...

外设是不会被调试器断下来的。调试器只能中断cpu,
所以让cpu断下来或者单步运行的时候,来数外设的时间都是不准的。
正确方法是在运行中由程序自身来读计数器的时间,存放在某个变量里,开始结尾各读一次相减。然后调试器直接查看那个变量来得到运行时间。

出0入76汤圆

发表于 2015-3-12 21:55:04 | 显示全部楼层
按理来说,应该不可能的

出0入8汤圆

发表于 2015-3-12 21:57:54 来自手机 | 显示全部楼层
wye11083 发表于 2015-3-12 16:17
曾经花了一些时间研究CRC,1位CRC改一下字就行了,通常在传输过程中就算好了。并行的则一般用于后校验用 ...

还有一种并行的非查表算法

出0入442汤圆

发表于 2015-3-12 23:33:15 | 显示全部楼层
myxiaonia 发表于 2015-3-12 19:30
你是说硬件crc原理么,那个不是像移位寄存器一样一位位算的

呵呵,把8次的值综合一下,就是8位并行CRC了。16位同理。如果占用的ROM小于计算理论值,则说明厂商使用了全新的算法。

出0入442汤圆

发表于 2015-3-12 23:41:40 | 显示全部楼层
canspider 发表于 2015-3-12 21:57
还有一种并行的非查表算法

确实。CRC的下一个状态只和初始状态和输入有关(一个什么状态机),这个在用查表法时就代表这个含义。而下一个状态实际上是表值与初始状态异或的结果,因此完全可以根据输入数据求出表值(也就是一大堆比特异或的结果),然后再和初始值相异或。

回头研究一下,然后也做个并行无状态的CRC IP。工作条件也很简单,输入初值+数据,输出CRC值。

出0入0汤圆

 楼主| 发表于 2015-3-13 09:18:42 | 显示全部楼层
redroof 发表于 2015-3-12 21:46
外设是不会被调试器断下来的。调试器只能中断cpu,
所以让cpu断下来或者单步运行的时候,来数外设的时间 ...

其实我就是用了中断断点,在dma完成中断入口下断点,在dma crc开启的最后一个代码处全速运行,这样就可以算出时间差了

其实最奇怪的是 项目代码用类似的方法,时间是很长的,比软件慢,为何这个测试例程里反而快的离谱了

出0入0汤圆

发表于 2015-3-13 09:27:42 | 显示全部楼层
是否算错了?抽空我也去试下。

出300入477汤圆

发表于 2015-3-13 10:26:45 | 显示全部楼层
myxiaonia 发表于 2015-3-13 09:18
其实我就是用了中断断点,在dma完成中断入口下断点,在dma crc开启的最后一个代码处全速运行,这样就可以 ...

整个运行过程只要你用了断点,调试器自带的周期计数就不准了。
正确方法是开个定时器,在crc开启的时候读一次,在dma完成中断里面再读一次相减,得到时间差,在此之间不可有任何调试器断点。
读到时间差后,就可以用调试器断下来看时间数字了,直到这个时候才能有断点。

出0入0汤圆

 楼主| 发表于 2015-3-13 11:04:46 | 显示全部楼层
redroof 发表于 2015-3-13 10:26
整个运行过程只要你用了断点,调试器自带的周期计数就不准了。
正确方法是开个定时器,在crc开启的时候读 ...

可是我用ms中断,在中断里下断点,1ms却相当的准确。。。

出0入0汤圆

 楼主| 发表于 2015-4-2 10:04:49 | 显示全部楼层
lryxr2507 发表于 2015-3-12 08:13
收藏.可怜的电工.睡得比狗晚,起的比鸡早.

赚的比农民工还少,哈哈哈

出0入0汤圆

发表于 2015-4-2 16:04:40 | 显示全部楼层
redroof 发表于 2015-3-13 10:26
整个运行过程只要你用了断点,调试器自带的周期计数就不准了。
正确方法是开个定时器,在crc开启的时候读 ...

楼主后来有用过redroof上面的方法再测次时间么,是否还是0.2us?

出0入0汤圆

 楼主| 发表于 2015-4-2 22:34:10 来自手机 | 显示全部楼层
maninblack 发表于 2015-4-2 16:04
楼主后来有用过redroof上面的方法再测次时间么,是否还是0.2us?

0.2us肯定是不对的,至于问题在哪里没找到,有例程可以试试

出0入362汤圆

发表于 2019-2-28 09:47:19 | 显示全部楼层
本帖最后由 tomzbj 于 2019-2-28 15:11 编辑

不错,我也试了下,速度是常规方法的2倍左右
不过奇怪的是,只能用DMA1, 换成DMA2就卡死。mcu是stm32f072。
-----------------------糊涂了,stm32f072没有DMA2...
  1. unsigned long CRC32_Calc(unsigned long initial, const void* msg, int size)
  2. {
  3.     static DMA_InitTypeDef DMA_InitStructure;
  4.     static int first_run = 1;

  5.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  6.     DMA_DeInit(DMA1_Channel1);
  7.     initial = ((initial >> 1) & 0x55555555) | ((initial & 0x55555555) << 1);
  8.     initial = ((initial >> 2) & 0x33333333) | ((initial & 0x33333333) << 2);
  9.     initial = ((initial >> 4) & 0x0f0f0f0f) | ((initial & 0x0f0f0f0f) << 4);
  10.     initial = ((initial >> 8) & 0x00ff00ff) | ((initial & 0x00ff00ff) << 8);
  11.     initial = (initial >> 16) | (initial << 16);                         //    st提供了源操作数按位反转,却没有提供初值也按位反转的功能。。。

  12.     CRC_SetInitRegister(initial);
  13.     CRC_ResetDR();

  14.     if(first_run) {
  15.         DMA_StructInit(&DMA_InitStructure);
  16.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  17.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  18.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  19.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  20.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  21.         DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  22.         DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
  23.         DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned long)CRC_BASE;
  24.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  25.     }
  26.     DMA_InitStructure.DMA_MemoryBaseAddr = (unsigned long)(msg);
  27.     DMA_InitStructure.DMA_BufferSize = size;
  28.     DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  29.     DMA_Cmd(DMA1_Channel1, ENABLE);

  30.     ( {  while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);});
  31.     first_run = 0;
  32.     return CRC_GetCRC();
  33. }
复制代码
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-5 11:12

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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