找回密码
 立即注册
查看: 523|回复: 1

有关DMA双缓冲的一些思考

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:458
  • 最近打卡:2025-05-01 07:48:22
已绑定手机
已实名认证

110

主题

2219

回帖

5452

积分

版主

积分
5452
发表于 2024-9-26 21:24:21 | 显示全部楼层 |阅读模式
      今天在论坛看到有网友提出了对串口DMA接收上的一些改进建议。大致是,如果考虑高速持续的串口数据情况下,重装串口DMA会浪费掉一定的时间。这个时间内有可能出现数据接受被丢弃的情况。网友的建议是做自动切换的双缓冲区DMA,但是我有一点不一样的想法。
截图202409262123112001.jpg
双缓冲示意图
      按道理讲,肯定是直接用串口中断实时性最好,但是串口中断又有点过于消耗系统资源,频繁打断主程序也对其他功能运行不利。所以DMA有没有办法做出类似串口中断的用法呢?

      我的想法是通过设定一块较大的缓冲区,然后利用DMA_DONE寄存器读取已经完成存储的字节,因为此时读取完成的数据部分和DMA正在读取占用的内存区域不一样,所以应该是不会产生控制冲突(这部分我在论坛上搜索了一下,似乎有例程实现了环形读取缓冲区,那么应该是没问题的),所以此时就可以通过处理已经读取的部分,并且记下当前处理到的字节数。等待下次查询的时候继续处理新接收到的一部分。这样,就可以实现边采样边接收。处理数据的时间大大增加,也就不必等到全部接受完再进行处理了。
截图202409262123236086.jpg
      不过上面这个方法仍然会存在重新配置DMA时,万一来了数据丢失问题。这部分我的建议是通过使用给DMA_CR寄存器中加入一个独立的标志位DMA_CIRC。如果启动DMA时,打开了这个标位置,则DMA刷新到设定的xdata区域最后时,可以自动跳回其实区域继续刷新。比如可以通过到最后通过清零地址偏移实现重新绕回初始地址(这部分不知是否容易实现?),进而创造一个大小可控的环形DMA数据区域。而程序中通过记忆上次处理到的位置和读取最新的DMA_DONE即可处理增量的数据区域。
      这样,既不用死等数据到来,也不用像串口中断那样频繁打断,每次处理一部分的数据,即可实现CPU算力的最高效利用。并且,这个功能还可以通过串口超时中断进行配合使用。
      比如,检测到串口超时中断后,再处理这一整个的数据帧(至少要比缓冲区小的多)。处理完成后,只需要记忆自己处理到了哪里,就可以继续完成其他任务,并不需要关心串口接收数据到哪里了,可以继续等下次超时中断自动触发。并且也不需要重复配置DMA寄存器,实现一块缓冲区的的循环使用。

      如此一来,相信DMA用来进行接收数据的等待将更加易用。

回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:458
  • 最近打卡:2025-05-01 07:48:22
已绑定手机
已实名认证

110

主题

2219

回帖

5452

积分

版主

积分
5452
发表于 2024-9-26 21:27:17 | 显示全部楼层
一点小小的建议:
通过使用给DMA_CR寄存器中加入一个独立的标志位DMA_CIRC。
如果启动DMA时,打开了这个标志位,则DMA刷新到设定的xdata区域最后时,可以自动跳回其实区域继续刷新。

进而实现全自动的环形缓冲区,这个比双缓冲区更灵活一些。
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 02:30 , Processed in 0.127057 second(s), 51 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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