[其他ST产品] STM32开发---USART使用DMA时能省多少时间

[复制链接]
 楼主| 实际测量不符 发表于 2023-9-30 23:24 | 显示全部楼层 |阅读模式
DM, DMA, SAR, ST, STM

STM32方案时,常用DMA传输数据,好给MCU省下资源去干干其它的事。

模模糊糊的概念中,DMA 就是又省又快!到底有多快有多少省呢?闲着手痒搞搞测试,结果还真有些惊喜!

将分别测试USART通过printf、DMA两种方式,测试输出数据(TX)时,在耗时、速度上的差别。


 楼主| 实际测量不符 发表于 2023-9-30 23:24 | 显示全部楼层
、测试环境
346365183da3a17b6.png
硬件:  STM32F103C8 (还是这个大爱的板子,贼好用)

软件:  Keil_5.27(5.27!!!)

上位机:  秉火串口调试助手(V1.0最好用)

逻辑分析软件:  pulseview(开源,界面和设置都很简洁)
 楼主| 实际测量不符 发表于 2023-9-30 23:24 | 显示全部楼层
测试用代码
7594765183dbb628a3.png
 楼主| 实际测量不符 发表于 2023-9-30 23:24 | 显示全部楼层
代码三处要点
红点处:自定义的运行时长观察函数,放置在3个地方,获取期间两段运行时长,单位是us ;
 楼主| 实际测量不符 发表于 2023-9-30 23:24 | 显示全部楼层
黄色1: printf(), 就是平时l输出至上位机的 printf(), 其底层fputc已重定向输出至USART1,
 楼主| 实际测量不符 发表于 2023-9-30 23:25 | 显示全部楼层
黄色2:print(), 注意名称少了个f,自定义的函数, USART1通过DMA输出参数传递的字符串;

 楼主| 实际测量不符 发表于 2023-9-30 23:25 | 显示全部楼层
普通发送printf()函数,  fputc的重定向代码
  1. // 重定向fputc函数
  2. // printf的输出,指向fputc,由fputc输出到串口
  3. // 这里使用串口1(USART1)输出printf信息
  4. int fputc(int ch, FILE *f)
  5. {   
  6.     // 重要判断
  7.     if(xFlag.PrintfOK == 0) return 0;    // 判断USART是否已配置,防止在配置前调用printf被卡死
  8.        
  9.     while((USARTx ->SR&0X40)==0);        // 等待上一次串口数据发送完成  
  10.         USARTx ->DR = (u8) ch;                   // 写DR,串口1将发送数据
  11.         return ch;
  12. }
 楼主| 实际测量不符 发表于 2023-9-30 23:25 | 显示全部楼层
DMA配置代码,print()函数

  1. /******************************************************************************
  2. * 函  数: print
  3. * 功  能: UART使用DMA发送数据
  4. * 参  数: u8* charTemp  要发送的字符串首地址
  5. * 返回值:
  6. * 备  注: 魔女开发板团队  资料存放Q群:262901124        最后修改_2020年05月10日
  7. ******************************************************************************/  
  8. void print(char* charTemp)
  9. {
  10.     u32 num = 0;
  11.     char* t=charTemp ;   
  12.     while(*t++ !=0)  num++;
  13.    
  14.         RCC->AHBENR|=1<<0;                                     // 开启DMA1时钟
  15.         DMA1_Channel4->CPAR  = (u32)&USARTx->DR; // 外设地址
  16.         DMA1_Channel4->CMAR  = (u32)charTemp;    // 存储器地址   
  17.         DMA1_Channel4->CNDTR = num;                     // 传输数据量
  18.         DMA1_Channel4->CCR   = 1<<4;                       // 数据传输方向   0:从外设读   1:从存储器读
  19.         DMA1_Channel4->CCR  |= 0<<5;                       // 循环模式       0:不循环     1:循环
  20.         DMA1_Channel4->CCR  |= 0<<6;                      // 外设地址非增量模式
  21.         DMA1_Channel4->CCR  |= 1<<7;                       // 存储器增量模式
  22.         DMA1_Channel4->CCR  |= 0<<8;                       // 外设数据宽度为8位
  23.         DMA1_Channel4->CCR  |= 0<<10;                      // 存储器数据宽度8位
  24.         DMA1_Channel4->CCR  |= 0<<12;                      // 中等优先级
  25.         DMA1_Channel4->CCR  |= 0<<14;                      // 非存储器到存储器模式       
  26.         DMA1_Channel4->CCR  |= 1<<0;             // 开启DMA传输   
  27. }
 楼主| 实际测量不符 发表于 2023-9-30 23:25 | 显示全部楼层
运行耗时 - 测试结果
使用printf()和print()通过USART1输出27个字节, 然后把监察到的运行时长打印到上位机,结果如下: 5673365183df574ed2.png
 楼主| 实际测量不符 发表于 2023-9-30 23:25 | 显示全部楼层
直接数据
     数据处理的耗时相差230倍!!!

     使用DMA省99.5%的耗时!!!
 楼主| 实际测量不符 发表于 2023-9-30 23:25 | 显示全部楼层
理解思考
       printf的耗时,应该耗在每发一个字节,芯片都要while(), 一个字节挨一个字节地while()死等着发送, 计算可知115200波特率下,每一个字节要87us,  那27个字节, 它就要等待27次87us , 就是 2343us了, 加上命令处理时间, 打印中的结果2769us, 差不多是这个时间了.  注意, 这个在等人的主角是芯片, 这个时候它是不能干其它的事情的, 除非有中断突然出现. 特别特别地注意: 如果死等的这个时候有中断出现, 而中断处理时长超过87us, 那就会有另一个头疼的问题:  USART的数据被打断打乱!

 楼主| 实际测量不符 发表于 2023-9-30 23:26 | 显示全部楼层
       而print通过DMA发送,12us的耗时应该就是代码指令操作的时间:主芯片给运输队伍下命令:你们去A地方,把num个纸箱,搬到B地方。几句话, 用时12us.
 楼主| 实际测量不符 发表于 2023-9-30 23:26 | 显示全部楼层
       我们再进一步: 12us是主芯片动动嘴皮下命令的时长,不是运输队伍工作的时长,那它需要工作多长时间呢?

 楼主| 实际测量不符 发表于 2023-9-30 23:26 | 显示全部楼层
、逻辑分析仪 - 测试结果
直接上波形的运行截图, 两个截图都是发送27个字节的波形时长:
 楼主| 实际测量不符 发表于 2023-9-30 23:26 | 显示全部楼层
 楼主| 实际测量不符 发表于 2023-9-30 23:26 | 显示全部楼层
 楼主| 实际测量不符 发表于 2023-9-30 23:26 | 显示全部楼层
可以看到,printf产生波型比DMA耗时, 大概多10%左右的时间, 但两者的波型时长相差很小,

说明尽管在输出数据时处理方式不同, 芯片运行耗时两者相差巨大, 但最终在硬件产生数据波型的工作中, 都得按协议走.
 楼主| 实际测量不符 发表于 2023-9-30 23:26 | 显示全部楼层
计算分析
说说printf产生波型要比DMA耗时多的理解:  上面计算过, 波特率115200时, 每个字节占用10个时钟, 计算数值是每个字节波形长86.8us,  27个字节的波型总长是2343us,  这个计算数值和在DMA传输时的实测数值2344us是一致的;但是使用printf的while死等输出, 27字节的数据波形时长要2579us, 足足多了236us, 应该是每两个字节间得处理死等的判断代码和命令, 造成了字节与字节间的空白浪费;
 楼主| 实际测量不符 发表于 2023-9-30 23:26 | 显示全部楼层
疑问
还有1个小问题, 暂时没找到答案: 在使用自定义的print函数通过DMA发送数据, 200字节左右, 数据都是准确的, 但大约500字节以上时,出现头尾的数据有失真的情况,不是偶然发生, 是每次都在同样的位置出现小量数据错误, 多次排查均没有发现问题所在, 先做个记录, 后续有时间再放灯下挑挑.
gygp 发表于 2023-10-5 09:02 | 显示全部楼层
如果波特率较低,那么即使使用DMA,节省的时间可能相对较少。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

48

主题

605

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部