[应用相关] 如何高效的使用DMA?

[复制链接]
12619|71
 楼主| ifree64 发表于 2008-9-25 22:46 | 显示全部楼层 |阅读模式
我对DMA的理解是:
它用于把CPU从忙等待的数据传输中解脱出来,使得CPU可以利用数据传输的时间来执行其他操作。

使用DMA以前,代码也许是这样:

for(i = 0; i < 512; ++i){
    while(数据没有准备好);    // 等待
    *buff++ = 数据源
}
处理buff中的数据;

在把数据传输到buff这个过程中,cpu在忙等待,或者即便没有等待也要由cpu来完成把数据源拷贝到buff这个任务。
但是,如果使用DMA来传输数据就可以节约下这些CPU时间。

使用DMA的代码也许是这样:

设置DMA传输的数据源地址;
设置DMA传输的数据目标地址;
设置传输数据的数目;
启动DMA传输;
等待DMA传输完毕;               // ??我的疑问在这里
处理数据;


如果用while循环来等待DMA传输完毕,那么CPU时间仍然浪费了。正确的做法应该是DMA传输的过程中,CPU去做其他的事情。如果有操作系统,可能这里就是一个阻塞自己的系统调用,操作系统进行任务的切换做其他的事情去了,等到DMA完成再由操作系统把自己给唤醒。另外一方面,如果没有其他事情需要做,用不用DMA都是没有关系的。对吗?

这样来看,是不是说要发挥DMA的价值,就得给单片机移植一个操作系统,进行任务的管理?

谢谢了。
luomh98 发表于 2008-9-26 10:42 | 显示全部楼层

re:

要发挥DMA的价值,也可以不用操作系统
把DMA中断用好就行
 楼主| ifree64 发表于 2008-9-26 10:56 | 显示全部楼层

可不可以给一个例子看看?

香水城 发表于 2008-9-26 12:27 | 显示全部楼层

对于并行的系统,不能使用串行系统的概念来设计

举个例子:一个系统要求每个一段时间需要把RAM中数据备份到外部EEPROM,你就可以启动DMA传送数据到外部EEPROM后,把CPU让出来处理其它事情,通过中断管理数据块的备份,而不必操心备份何时完成。
 楼主| ifree64 发表于 2008-9-26 14:32 | 显示全部楼层

谢谢香版

也就是有的任务本身就是并行的,这些任务用dma来做就很方便了。

但有的任务如从SD卡中读出数据,再处理,就属于串行任务,要用DMA来提高性能是不是就离不开阻塞了?
香水城 发表于 2008-9-26 14:47 | 显示全部楼层

重要的是你能不能把串行的任务通过合理的安排变为并行的

例如需要从SD卡读出数据送到MP3解码器进行播放,如果用并行的方法可以是这样:
 1)用DMA从SD卡读一个数据块到RAM缓冲器1
 2)等待读数据块完成
 3)送RAM缓冲器1至解码器
 4)用DMA从SD卡读下一个数据块到RAM缓冲器2
 5)等待解码结束
 6)送RAM缓冲器2至解码器
 7)用DMA从SD卡读下一个数据块到RAM缓冲器1
 8)等待解码结束
 9)返回3)循环

这里DMA操作与解码并行进行,并没有阻塞。
 楼主| ifree64 发表于 2008-9-26 15:41 | 显示全部楼层

我的意思是在上面的第2步,第5步,第8步CPU仍然在忙等待

DMA在数据传输了,CPU本来可用来做其他工作,但是现在仍然是在忙等待而未作任何事。

香水城 发表于 2008-9-26 16:15 | 显示全部楼层

如果你有其它事情要做就去做,否则可以等待

例如在上面说的等待的地方可以进行键盘扫描、显示刷新、歌词处理;总之,CPU的时间被省下来,可以进行其它处理,如果没有事情做正好休息一下。

注意这里的等待是因为无事可做,而不是一定要等待。
 楼主| ifree64 发表于 2008-9-26 17:42 | 显示全部楼层

谢谢香版的耐心解答

我就是想知道如何“你有其它事情要做就去做,否则可以等待”。
代码如何写?
香水城 发表于 2008-9-26 18:24 | 显示全部楼层

9楼的问题就要靠你自己了,等碰到了你自然就知道了

这个问题没有定式的!
zhaoxinzxzx 发表于 2008-9-27 07:50 | 显示全部楼层

DMA还可以避免频繁地中断CPU

我的理解是:数据传输、A/D转换或者其他操作中,为了避免频繁地中断CPU,可以使用DMA来传输数据到设定的Buffer中,频繁地中断CPU会浪费大量的处理时间,解放CPU应该是DMA的初衷
 楼主| ifree64 发表于 2008-9-27 14:11 | 显示全部楼层

我把问题提得再具体点吧。

如果要实现一个SD卡上的文件系统。函数调用关系可能是:

f_read  --->   disk_read   --->    spi_read_write

disk_read通常是调用512次spi_read_write来读取一个sd卡上的扇区,如果512bytes数据还没有读取完毕,disk_read不应该返回,除非读取出错了。

如果改用通过dma读取数据,disk_read中设置好dma参数,启动dma传输后,能返回吗?
如果返回,dma还没有读取完数据,如果不返回,改为等待dma传输完毕,这和cpu自己做这件事相比又有什么区别呢?性能并没有得到提高啊。我能想出的方案就是利用操作系统来阻塞自己,切换到其他任务,dma完毕,操作系统唤醒自己,disk_read返回。

采用dma传输完毕中断通知?怎么做,想不出来。
 楼主| ifree64 发表于 2008-9-27 14:14 | 显示全部楼层

我不可能在disk_read函数里去做键盘扫描、歌词处理等操作吧

香水城 发表于 2008-9-27 19:02 | 显示全部楼层

启动DMA后返回,CPU去执行其它任务,DMA传输结束会产生中断

在DMA中断中处理数据或设置标志待其它任务完成后通过判断这个标志获知数据可用。
avocationA 发表于 2008-9-30 11:36 | 显示全部楼层

复习!学习!

Sober393 发表于 2008-10-1 11:45 | 显示全部楼层
xddl 发表于 2009-12-2 22:55 | 显示全部楼层
这两天也在学习DMA的事情,如果有一个这样的应用:
从串口1读取数据,再从串口2送出,使用DMA方式的话,岂不是效率更低了?
ST_ARM 发表于 2009-12-3 17:23 | 显示全部楼层
楼主对如何正确使用DMA还很模糊,何来谈有效地使用DMA?
使用DMA的目的是让MCU有更多时间去处理相关的工作,不要停留在数据搬移这种低级操作上,DMA操作完成后进入中断,用户可在中断程序中处理相关事件,或置标志位,退出中断后,在主循环中判断标志位,再进行相关处理,如:
while(1)
{
      if (标志位 == 1)
        {
              相关处理;
         标志位 = 0;
        }
        else
        {
             MCU执行其他操作;
        }
}
sinadz 发表于 2009-12-4 08:55 | 显示全部楼层
还不知道如何使用DMA,在学习中
logokfu 发表于 2012-3-22 22:02 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

159

帖子

0

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