嵌入式 CPU 中的 DMA 有什么意义?

电器工程 微控制器 mbed DMA
2022-01-20 02:07:12

我最近在用 mbed (LPC1768) 做一个项目,使用 DAC 输出各种波形。我阅读了部分数据表,其中谈到了它如何为许多外围设备提供 DMA。这似乎很有用,但在进一步阅读时,我发现 DMA 使用与 cpu 相同的数据总线(我猜这是正常的)。这是否意味着 CPU 在 DAC 获取数据时无法与任何内存交互?此外,由于 DAC 没有缓冲区(据我所知),因此必须经常进行 DMA,那么 DMA 的意义何在?如果 CPU 不能做内存事务,它还能做些什么吗?

4个回答

总而言之,DMA 允许 CPU 有效地以其本机速度运行,而外设可以有效地以其本机速度运行。示例中的大多数数字都是虚构的。

让我们比较两个从 ADC 定期收集数据的选项:

  1. 您可以将 ADC 设置为中断的一部分(定期或其他)
  2. 您可以创建一个缓冲区,并告诉 DMA 将 ADC 读数传输到缓冲区。

让我们将 1000 个样本从 ADC 传输到 RAM。

使用选项 1:对于每个样本

  • 进入中断用了 12 个周期
  • 读取 adc
  • 存储在内存中
  • 12 个周期用于退出中断

假设这个中断函数有 76 条指令,整个例程有 100 条指令,假设单周期执行(最佳情况)。这意味着选项 1 将花费 100,000 个 CPU 时间周期来执行。

选项 2:DMA 配置为收集 1000 个 ADC 样本。假设 ADC 有一个来自定时器计数器的硬件触发。

  • ADC 和 DMA 将 1000 个样本数据传输到 ram
  • DMA 在 1000 个样本后中断您的 CPU
  • 进入中断用了 12 个周期
  • 代码发生(假设它告诉 DMA 覆盖 RAM)
  • 12 个周期用于退出中断

假装整个中断(具有进入和退出开销)是 100 条单周期指令。使用 DMA,您只需花费 100 个周期即可保存相同的 1000 个样本。

现在,每次DMA访问总线时,是的,CPU和DMA之间可能会发生争执。CPU 甚至可能被迫等待 DMA 完成。但是等待 DMA 完成比锁定 CPU 为 ADC 提供服务要短得多。如果 CPU 内核时钟是 2x 总线时钟,那么 CPU 可能会浪费几个内核周期等待 DMA 完成。这意味着传输的有效执行时间在 1000(假设 CPU 从不等待)到 9000 个周期之间。仍然比 100,000 次循环好得多。

我找到的LPC1768 数据表有以下引用(强调我的):

AHB 多层矩阵上的八通道通用 DMA 控制器 (GPDMA),可与 SSP、I2S 总线、UART、模数和数模转换器外设、定时器匹配信号以及存储器到-内存转移。

分离式 APB 总线允许高吞吐量,CPU 和 DMA 之间的停顿很少

第 6 页上的框图显示了在 AHB 矩阵之间具有多个通道的 SRAM,以下引用支持了这一点:

LPC17xx 包含总共 64 kB 的片上静态 RAM 存储器。这包括主 32 kB SRAM,可通过高速总线上的 CPU 和 DMA 控制器访问,以及两个附加的 16 kB SRAM 块,位于AHB 多层矩阵上的单独从端口上。这种架构允许 CPU 和 DMA 访问分布在三个可以同时访问的独立 RAM 上

以下引用加强了这一点:

GPDMA 支持外设到内存、内存到外设、外设到外设和内存到内存的事务。

因此,您可以将数据从单独的 SRAM 块之一或从不同的外设流式传输到 DAC,同时将主 SRAM 用于其他功能。

这种外设-外设 DMA 在内存接口非常简单的较小部分中很常见(与现代英特尔处理器相比)。

如果在给定的周期内,处理器和 DMA 控制器需要访问同一条总线,则其中一个必须等​​待。然而,许多系统包含多个带有独立总线的内存区域以及一个总线“桥”,该总线“桥”将允许 CPU 访问一个内存,而 DMA 控制器访问另一个内存。

此外,许多 CPU 可能不需要在每个周期都访问存储设备。如果 CPU 通常只需要在三个周期中的两个周期访问内存,则低优先级 DMA 设备可能能够利用内存总线空闲时的周期。

即使在每个 DMA 周期都会导致 CPU 停顿一个周期的情况下,如果数据以足够慢的速度到达以使 CPU 应该能够在传入数据项之间执行其他操作,DMA 仍然非常有用,但速度足够快,需要最小化每个项目的开销。例如,如果 SPI 端口以每 16 个 CPU 周期一个字节的速率向设备提供数据,则每次传输都中断 CPU 可能会导致它几乎将所有时间都花在进入中断服务程序和从中断服务程序返回上,而没有做任何实际工作。然而,使用 DMA,即使每次 DMA 传输导致 CPU 停顿两个周期,开销也可以减少到 13%。

最后,一些 CPU 允许在 CPU 休眠时执行 DMA。使用基于中断的传输将要求系统为传输的每个数据单元完全唤醒。然而,使用 DMA,睡眠控制器可能会在每次输入一个字节时为内存控制器提供几个时钟,但让其他所有内容保持睡眠状态,从而降低功耗。

作为程序员,DMA 是一种在支持它的外设之间传输数据的选项。对于通过 SPI 或 UART 等串行外设移动大型缓冲区或从 ADC 收集大量样本的经典示例,您可以使用三种移动数据的方法:

  1. 轮询方式。这是您等待寄存器标志以允许您移入/移出下一个字节的地方。问题是您在等待此操作时正在阻止 CPU 的所有执行。或者,如果您必须在操作系统中共享 CPU 时间,那么您的传输速度将大大减慢。

  2. 中断方法。您可以在此处编写一个随每个字节传输执行的中断服务例程 (ISR),并在 ISR 中编写管理传输的代码。这样 CPU 效率更高,因为 CPU 只会在需要时为您的 ISR 提供​​服务。它在除 ISR 之外的所有其他时间免费使用。就传输速度而言,ISR 也是进行传输的较快选项之一。

  3. DMA。您可以使用源/目标指针、传输次数和关闭它来配置 DMA。它会窃取总线周期和 CPU 时间来完成传输,同时 CPU 可以自由地做其他事情。您可以配置一个标志或中断来指示传输何时完成。它通常比 ISR 快一点,通常是您最快的传输选项。

作为一名程序员,我更喜欢 DMA,因为它最容易编码,而且本质上是进行传输的最快技术。通常,您只需要为源/目标指针和传输次数配置几个寄存器即可。我在 ISR 代码中花费的时间比在 DMA 加速代码中花费的时间要多得多,因为 ISR 代码需要关键的设计技能,并且必须进行编码、测试、验证等。DMA 代码要小得多,而且我必须自己编写代码相对微不足道,而且我在讨价还价中获得了最大的传输速度。

根据我的经验,最近使用 Atmel SAM3/4 处理器时,DMA 的运行速度比我自己设计的高效 ISR 快一点。我有一个应用程序,它每 5 毫秒从 SPI 读取一堆字节。后台任务中发生了大量浮点数学运算,因此我希望 CPU 尽可能地空闲用于这些任务。最初的实现是 ISR,然后我转向 DMA 进行比较并尝试在样本之间购买更多的 CPU 时间。传输速度增益略有提高,但只有一点点。在 o-scope 上几乎无法测量。

这是因为在我看到的最近的微处理器上,ISR 和 DMA 以几乎相同的方式运行——它们根据需要占用 CPU 周期,并且 DMA 与 CPU 执行的操作基本上与我在高效 ISR 中编写的操作相同.

在极少数情况下,我看到外设具有自己的 RAM 区域,只能由 DMA 访问。这是在以太网 MAC 或 USB 上。