当前位置: 首页 > news >正文

嵌入式面试总结(十七)——DMA总线

一、引言

DMA(Direct Memory Access,直接存储器访问)是嵌入式系统中一项至关重要的核心技术,它允许外设与内存之间直接进行数据传输,而无需 CPU 的全程干预。在传统的程序控制或中断驱动的 I/O 方式中,CPU 需要频繁地参与每一个数据单元的搬运,这不仅消耗了宝贵的 CPU 周期,也限制了系统的整体吞吐量。DMA 技术的出现,正是为了解决这一瓶颈。

其核心思想是:CPU 仅需在传输开始前,对 DMA 控制器进行初始化配置(如设置源地址、目标地址、传输数据量等),随后便可“抽身”去执行其他计算任务。数据传输过程则由 DMA 控制器接管系统总线,在外设与内存之间直接完成。待整个数据块传输完毕,DMA 控制器再通过中断通知 CPU。这种方式将 CPU 从繁琐的、重复性的数据搬运工作中解放出来,显著提高了系统效率,降低了 CPU 占用率,尤其适用于音频/视频流处理、高速数据采集、网络通信等对实时性和带宽要求高的场景。

理解 DMA 的工作原理、工作模式及其在嵌入式系统中的应用,是嵌入式软件工程师面试中的高频考点,也是进行高性能系统设计的基础。本文将从 DMA 的基本概念出发,系统梳理其工作原理、传输模式、控制器结构、典型应用,并解答常见的面试问题。

二、DMA 工作原理

DMA(直接存储器访问)的核心在于将 CPU 从繁重的数据搬运任务中解放出来,实现外设与内存之间的高效、直接数据传输。其工作原理可以概括为“CPU 配置,DMA 执行,中断通知”。

一次完整的 DMA 传输通常包含以下五个关键步骤:

  1. CPU 初始化配置:CPU 作为“导演”,首先对 DMA 控制器进行编程。这包括设置源地址(数据从哪里来,如外设数据寄存器)、目标地址(数据到哪里去,如内存缓冲区)、传输数据量(字节数或字数)以及传输模式(单次、块传输等)。配置完成后,CPU 使能 DMA 通道,准备开始传输。
  2. 外设发起传输请求:当外设(例如 UART 收到一个字节、ADC 完成一次转换)准备好数据或需要发送数据时,它会向 DMA 控制器发出一个硬件信号——DMA 请求(DREQ)。这相当于外设“举手”示意自己已就绪。
  3. DMA 控制器接管系统总线:收到 DREQ 后,DMA 控制器作为“总线主设备”,会向 CPU 发出总线保持请求(HOLD 或类似信号)。CPU 在当前总线周期结束后,会响应此请求,释放对地址总线、数据总线和控制总线的控制权,并通过总线保持应答(HLDA)信号通知 DMA 控制器:“总线现在归你使用”。这个过程称为总线仲裁
  4. DMA 执行数据传输:获得总线控制权后,DMA 控制器开始独立工作。它直接操纵总线,从源地址读取数据,然后写入目标地址。每完成一次传输(如一个字节),它会自动递增(或递减)地址寄存器,并递减字节计数器。这个过程完全由硬件完成,CPU 在此期间可以执行其他任务(前提是不需要访问被 DMA 占用的总线)。
  5. 传输完成与中断通知:当字节计数器减为零,表示预设的数据量已全部传输完毕。DMA 控制器会撤销总线请求(HOLD),将总线控制权交还给 CPU。同时,它通常会向 CPU 发出一个传输完成中断(TCI),通知 CPU 本次 DMA 传输已经结束。CPU 响应该中断后,便可对传输完成的数据进行处理(例如,处理内存缓冲区中已接收到的完整数据包)。

核心优势:在整个数据传输的“核心阶段”(步骤4),CPU 无需像中断方式那样,为每个数据单元执行保存现场、搬运数据、恢复现场等一系列指令。DMA 通过硬件接管总线,实现了数据的“直接”搬移,从而大幅降低了 CPU 开销,显著提升了系统整体吞吐量和实时性

三、DMA 传输模式

DMA 控制器支持多种传输模式,以适应不同的外设特性和应用场景。理解这些模式对于合理配置 DMA、优化系统性能至关重要。

1. 单次传输模式

每次外设请求只传输一个数据单元(如一个字节或一个字),传输完成后 DMA 控制器释放总线,CPU 重新获得控制权。适用于低速、非连续的外设。

实战代码示例(STM32 HAL 库配置单次传输)

// 以 STM32 UART 接收 DMA 单次传输为例 #include "stm32f4xx_hal.h" UART_HandleTypeDef huart2; DMA_HandleTypeDef hdma_usart2_rx; uint8_t rx_buffer[1]; // 单字节缓冲区 void MX_DMA_Init(void) { __HAL_RCC_DMA1_CLK_ENABLE(); HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); } void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart2); } void Start_DMA_Single_Transfer(void) { // 配置 DMA 为单次模式 hdma_usart2_rx.Instance = DMA1_Stream5; hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4; hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart2_rx.Init.Mode = DMA_NORMAL; // 单次模式 hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_Init(&hdma_usart2_rx); // 关联 DMA 到 UART 接收 __HAL_LINKDMA(&huart2, hdmarx, hdma_usart2_rx); // 启动 DMA 接收(单次传输一个字节) HAL_UART_Receive_DMA(&huart2, rx_buffer, 1); } // DMA 传输完成中断回调 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART2) { // 处理接收到的单字节数据 rx_buffer[0] // 如需继续接收,需重新调用 HAL_UART_Receive_DMA } }

2. 块传输模式

DMA 控制器在一次总线占用期间,连续传输整个数据块(多个数据单元),直到计数器减为零。传输效率高,但会长时间占用总线。

实战代码示例(STM32 ADC 多通道扫描 DMA 块传输)

// STM32 ADC 多通道扫描,使用 DMA 块传输搬运数据 #include "stm32f4xx_hal.h" ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; uint16_t adc_buffer[3]; // 存储 3 个通道的转换结果 void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig = {0}; hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = ENABLE; // 扫描模式 hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 3; hadc1.Init.DMAContinuousRequests = ENABLE; // DMA 连续请求 hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; HAL_ADC_Init(&hadc1); // 配置通道 0、1、2 sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; HAL_ADC_ConfigChannel(&hadc1, &sConfig); sConfig.Channel = ADC_CHANNEL_1; sConfig.Rank = 2; HAL_ADC_ConfigChannel(&hadc1, &sConfig); sConfig.Channel = ADC_CHANNEL_2; sConfig.Rank = 3; HAL_ADC_ConfigChannel(&hadc1, &sConfig); } void Start_ADC_DMA_Block_Transfer(void) { // 配置 DMA 为循环模式(块传输的连续形式) hdma_adc1.Instance = DMA2_Stream0; hdma_adc1.Init.Channel = DMA_CHANNEL_0; hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式,持续传输 hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH; hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_Init(&hdma_adc1); __HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1); // 启动 ADC 并开始 DMA 传输(块传输 3 个通道数据) HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 3); } // DMA 传输完成中断(半传输和全传输) void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if (hadc->Instance == ADC1) { // adc_buffer 中已更新了 3 个通道的最新数据 // 可在此进行数据处理 } }

3. 请求传输模式

传输由外设的 DREQ 信号控制。只要 DREQ 有效,DMA 就持续传输;DREQ 无效则暂停,总线交还 CPU。适用于数据产生速率不固定的场景。

实战场景说明

在请求传输模式下,DMA 控制器会持续监测外设的 DREQ(DMA 请求)信号。例如,一个外部传感器通过 GPIO 引脚产生不规则的数据就绪信号。当 DREQ 为高时,DMA 启动一次传输;传输完成后,若 DREQ 仍为高,则继续下一次传输;若 DREQ 变低,则暂停并释放总线。这种模式常见于需要根据外部事件节奏进行数据传输的场合,如从 FIFO 读取数据。

4. 级联模式

多个 DMA 控制器级联,扩展通道数。一个主 DMA 控制器可以管理多个从 DMA 控制器。

配置要点

  • 主 DMA 控制器的通道配置为级联模式,其“外设”实际上是另一个(从)DMA 控制器。
  • 从 DMA 控制器负责实际的数据传输,其传输完成信号会触发主 DMA 控制器。
  • 这种方式可以扩展出更多的 DMA 通道,用于非常复杂的多外设、多缓冲区场景。

模式选择建议

传输模式适用场景CPU 占用总线占用
单次传输低速外设、非连续数据(如按键扫描、单字节 UART)低(每次传输后释放总线)短时占用
块传输高速、连续数据流(如 ADC 多通道采样、LCD 刷新)极低(传输期间 CPU 可执行缓存内代码)长时间连续占用
请求传输数据产生速率不定(如外部传感器、FIFO 读取)低(仅在 DREQ 有效时占用)间歇性占用
级联模式需要大量 DMA 通道的复杂系统低(由主从 DMA 协同)取决于从 DMA 配置

四、DMA 控制器结构

DMA 控制器是执行 DMA 传输的核心硬件模块,其内部结构决定了 DMA 的功能和性能。一个典型的 DMA 控制器主要由寄存器组地址生成单元计数器单元控制逻辑以及总线接口单元构成。

1. 核心寄存器组

寄存器是 CPU 与 DMA 控制器交互的接口,也是 DMA 控制器工作的依据。典型的 DMA 控制器包含以下关键寄存器:

  • 基地址寄存器(Base Address Register):存放传输的源起始地址或目标起始地址。在传输开始前由 CPU 写入。
  • 当前地址寄存器(Current Address Register):存放当前正在传输的地址。每次传输完成后,该寄存器的值会根据配置自动递增或递减,指向下一个要访问的单元。
  • 基字节计数寄存器(Base Byte Count Register):存放本次 DMA 传输需要搬运的总数据量(字节数或字数)。
  • 当前字节计数寄存器(Current Byte Count Register):存放剩余待传输的数据量。每完成一次传输,该计数器自动递减。当减为零时,表示传输完成,通常会触发中断。
  • 控制寄存器(Control Register):用于配置 DMA 传输的各种参数,例如:
    • 传输方向:内存到外设(Memory-to-Peripheral, M2P)、外设到内存(P2M)或内存到内存(M2M)。
    • 传输模式:单次、块传输、请求传输或循环模式。
    • 地址递增/递减:设置每次传输后源地址和目标地址是递增、递减还是保持不变。
    • 数据宽度:字节(8位)、半字(16位)或字(32位)。
    • 优先级:在多通道 DMA 中设置通道的优先级。
    • 中断使能:使能传输完成中断、半传输中断或错误中断。
  • 状态寄存器(Status Register):反映 DMA 控制器的当前工作状态,例如传输完成标志、错误标志、通道使能状态等。CPU 可通过轮询此寄存器或结合中断来获知传输进度。

2. 地址生成与计数器单元

这两个单元是 DMA 控制器自动执行传输的“引擎”。

  • 地址生成单元:根据控制寄存器的配置,在每次传输后自动更新当前地址寄存器。例如,若配置为“地址递增”,则在每次传输后,地址寄存器会加上数据宽度对应的字节数(如+1、+2、+4)。
  • 计数器单元:负责管理当前字节计数寄存器。每完成一次数据传输,计数器减1(或根据数据宽度减相应的值)。当计数器减为零时,产生“传输完成”信号,并可能触发中断。

3. 控制逻辑与仲裁器

  • 控制逻辑:解析控制寄存器的配置,协调寄存器组、地址生成单元、计数器单元和总线接口单元的工作时序,生成内部控制信号。
  • 仲裁器(Arbiter):当多个 DMA 通道同时请求总线时,仲裁器根据预设的优先级(固定优先级或轮询)决定哪个通道获得总线使用权。这是实现多通道 DMA 并发或顺序工作的关键。

4. 总线接口单元

这是 DMA 控制器与系统总线(地址总线、数据总线、控制总线)交互的物理接口。它负责:

  • 在获得总线控制权后,驱动地址总线和控制总线,发出读写信号。
  • 在数据总线上读取源地址的数据或写入数据到目标地址。
  • 实现与 CPU 之间的总线请求(HOLD)和总线应答(HLDA)握手协议。

5. 现代 DMA 控制器的增强特性

随着技术的发展,现代 MCU/SoC 中的 DMA 控制器往往集成了更高级的功能:

  • 多通道独立配置:一个 DMA 控制器通常包含多个独立的通道,每个通道拥有自己的一套寄存器,可以同时或分时处理不同外设的传输请求。
  • 链接模式(Linked List)或描述符模式:支持将多个传输任务(描述符)链接成一个链表。DMA 控制器可以自动从一个描述符跳转到下一个,实现复杂的、非连续的数据块传输(即 Scatter/Gather DMA),无需 CPU 反复介入配置。
  • 双缓冲区(Double Buffer)支持:允许配置两个目标缓冲区。当 DMA 向其中一个缓冲区写入数据时,CPU 可以安全地读取另一个缓冲区已满的数据,实现“乒乓”操作,避免数据竞争。
  • 内存保护(MPU)集成:部分高端控制器集成了内存保护单元,可以限制 DMA 访问的地址范围,防止错误配置导致的内存覆盖,提升系统安全性。

理解 DMA 控制器的内部结构,有助于我们更深入地掌握其工作原理,并在实际编程中正确、高效地配置相关寄存器,充分发挥 DMA 的性能优势。

五、DMA 在嵌入式系统中的典型应用

DMA 技术极大地提升了嵌入式系统的 I/O 效率,其应用场景遍布各类外设与内存之间的数据搬运。以下是几个典型的应用实例,并附上关键配置思路或代码片段。

1. UART 串口通信

在串口通信中,使用 DMA 可以避免 CPU 为每个字节的收发产生中断,尤其适合高速或大数据量传输。

  • 应用场景:Modbus 通信、GPS 模块数据接收、调试日志输出。
  • 配置要点
    • 接收:配置 DMA 为外设到内存(Peripheral-to-Memory)模式,源地址为 UART 数据寄存器(如 USARTx→DR),目标地址为内存缓冲区。
    • 发送:配置 DMA 为内存到外设(Memory-to-Peripheral)模式,源地址为待发送数据缓冲区,目标地址为 UART 数据寄存器。
    • 通常使用循环模式(Circular Mode)实现持续接收,或单次/普通模式(Normal Mode)发送固定长度数据。
// STM32 HAL 库示例:UART1 使用 DMA 接收不定长数据(空闲中断 + DMA) // 关键步骤简述: // 1. 初始化 UART 和 DMA(方向 PERIPH_TO_MEMORY,循环模式)。 // 2. 启动 DMA 接收:HAL_UART_Receive_DMA(&huart1, rx_buffer, BUFFER_SIZE); // 3. 使能 UART 空闲中断:__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); // 4. 在空闲中断回调中,计算已接收数据长度并处理。 void HAL_UART_IdleCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { // 计算本次接收到的数据长度 uint32_t remaining = __HAL_DMA_GET_COUNTER(huart->hdmarx); uint32_t received_len = BUFFER_SIZE - remaining; if (received_len > 0) { process_rx_data(rx_buffer, received_len); // 处理数据 } // 重新启动 DMA 接收(循环模式下缓冲区自动回绕) } }

2. ADC 模数转换数据搬运

ADC 转换速率往往很高,使用 DMA 可以将转换结果自动搬运到指定数组,供 CPU 后续处理,避免丢失采样点。

  • 应用场景:多通道传感器采样、音频采集、电源监控。
  • 配置要点
    • 配置 ADC 为扫描模式(Scan Mode)和连续转换模式(Continuous Conversion Mode)。
    • 配置 DMA 为外设到内存模式,源地址为 ADC 数据寄存器(如 ADCx→DR),目标地址为数组。
    • 使能 DMA 连续请求(DMA Continuous Requests),确保 ADC 转换完成立即触发 DMA 传输。
    • 通常使用循环模式实现持续采样,结合双缓冲区(Double Buffer)半传输/全传输中断实现“乒乓”操作,确保数据处理时 DMA 正在写入另一个缓冲区。
// STM32 HAL 库示例:ADC1 三通道扫描,DMA 循环传输 // 关键配置: // hadc1.Init.ScanConvMode = ENABLE; // hadc1.Init.ContinuousConvMode = ENABLE; // hadc1.Init.DMAContinuousRequests = ENABLE; // hadc1.Init.NbrOfConversion = 3; // hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式 // 启动:HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 3); // 在 DMA 传输完成中断(HAL_ADC_ConvCpltCallback)中处理 adc_buffer 数据。

3. SPI/I2C 总线通信

SPI 和 I2C 常用于连接传感器、存储器等外设。在大块数据读写时,DMA 能显著提升吞吐量。

  • 应用场景:读写 SD 卡、Flash 存储器、高分辨率传感器(如摄像头)、OLED 屏数据更新。
  • 配置要点
    • SPI:全双工通信时,需同时使能 TX 和 RX 的 DMA。注意 SPI 时钟相位和极性的匹配。
    • I2C:部分 MCU 的 I2C 外设支持 DMA(如 STM32 的 I2C 与 DMA 联动)。需注意 I2C 的时钟拉伸(Clock Stretching)特性。
    • 通常使用内存到外设(发送)外设到内存(接收)的组合。
// STM32 示例:SPI1 使用 DMA 发送数据到外部 Flash // 初始化 SPI 和 DMA(方向 MEMORY_TO_PERIPHERAL) // 启动传输:HAL_SPI_Transmit_DMA(&hspi1, tx_buffer, size); // 在传输完成中断(HAL_SPI_TxCpltCallback)中处理后续逻辑(如切换片选)。

4. 内存到内存(Memory-to-Memory)拷贝

某些 DMA 控制器支持在两个内存区域之间直接搬运数据,速度远高于 CPU 的逐字节拷贝。

  • 应用场景:图像处理中的缓冲区交换、数据块搬移、加密/解密前的数据准备。
  • 配置要点
    • 配置 DMA 通道为内存到内存模式
    • 设置源地址和目标地址均为内存地址(如 SRAM 中的两个数组)。
    • 数据宽度通常设置为字(32位)以获得最佳性能。
    • 注意源和目标地址的对齐,不对齐可能降低性能或需要特殊处理。
// STM32 内存到内存 DMA 拷贝示例(伪代码) // hdma_memtomem.Init.Direction = DMA_MEMORY_TO_MEMORY; // hdma_memtomem.Init.PeriphInc = DMA_PINC_ENABLE; // 源地址递增 // hdma_memtomem.Init.MemInc = DMA_MINC_ENABLE; // 目标地址递增 // HAL_DMA_Start(&hdma_memtomem, (uint32_t)src, (uint32_t)dst, size); // HAL_DMA_PollForTransfer(&hdma_memtomem, HAL_DMA_FULL_TRANSFER, 1000); // 或使用中断

5. LCD 显示刷新

图形界面需要持续向 LCD 控制器发送帧缓冲区数据,使用 DMA 可以解放 CPU,实现流畅的动画效果。

  • 应用场景:TFT-LCD 屏驱动、OLED 屏刷新、图形用户界面(GUI)。
  • 配置要点
    • 通常通过 FSMC(Flexible Static Memory Controller)或专用 LCD 控制器接口(如 LTDC)连接 LCD。
    • 配置 DMA 为内存到外设模式,源地址为帧缓冲区(Frame Buffer),目标地址为 LCD 数据寄存器。
    • 使用循环模式或配合垂直/水平同步信号触发 DMA 传输,实现自动刷新。
    • 结合双缓冲区技术,避免屏幕撕裂(Tearing Effect)。

6. 音频流处理

音频数据的实时采集和播放对时序要求严格,DMA 能确保数据流的连续性。

  • 应用场景:麦克风录音、扬声器播放、音频编解码器(Codec)数据搬运。
  • 配置要点
    • 使用 I2S 或 SAIAI 接口连接音频 Codec。
    • 配置两个 DMA 流:一个用于接收(录音),一个用于发送(播放)。
    • 使用循环模式双缓冲区,结合半传输中断(Half Transfer Complete)全传输中断(Transfer Complete)实现“乒乓”缓冲,确保音频流无中断。
// 音频 DMA 双缓冲区“乒乓”操作示意 // 定义两个缓冲区:buffer[0] 和 buffer[1] // 启动 DMA 循环传输,目标为 I2S 数据寄存器,长度为单个缓冲区大小。 // 在 DMA 半传输中断中,处理 buffer[0] 的数据(已填满前半部分)。 // 在 DMA 全传输中断中,处理 buffer[1] 的数据(已填满后半部分)。 // 如此循环,实现连续音频流处理。

总结与选型建议:在选择 DMA 应用模式时,需综合考虑外设特性、数据量、实时性要求以及系统总线负载。对于低速、零星数据,单次传输模式即可;对于高速连续流(如音频、视频),块传输或循环模式是首选;对于数据产生不规律的场景(如外部传感器),请求传输模式更为合适。合理运用 DMA 可以大幅降低 CPU 负载,提升系统整体性能和响应能力。

六、面试常见问题

1. DMA 相比中断方式传输数据有何优势?

:中断方式每次传输一个数据单元都需要 CPU 介入,进行保存现场、处理数据、恢复现场等操作,开销大。DMA 将 CPU 从繁琐的 I/O 操作中解放出来,仅在传输开始和结束时参与,大大降低了 CPU 占用率,提高了数据传输效率,尤其适合大批量、高速的数据传输。

2. DMA 传输过程会占用系统总线,这会影响 CPU 访问内存吗?

:会。在 DMA 传输期间,DMA 控制器作为总线主设备,CPU 对内存的访问会被暂时挂起(等待或插入等待周期)。这称为“周期窃取”。现代系统通常采用总线仲裁内存控制器来优化,例如支持并发访问的存储器、设置 DMA 传输的优先级、利用 CPU 缓存减少总线争用等,以最小化对 CPU 性能的影响。

3. 如何防止 DMA 传输覆盖关键内存区域?

  • 硬件层面:一些高级 MCU/MPU 的 DMA 控制器支持内存保护单元(MPU),可以配置 DMA 可访问的内存地址范围。
  • 软件层面:驱动程序在配置 DMA 源/目标地址时,必须进行严格的边界检查,确保地址位于合法的缓冲区范围内。同时,操作系统(如 Linux)会通过 I/O 内存管理单元(IOMMU)或类似机制,为 DMA 分配专用的、受保护的物理内存区域。

4. 解释一下“分散/聚集”(Scatter/Gather)DMA。

:这是一种高级 DMA 模式。传统 DMA 要求数据在物理内存中是连续的。“分散/聚集” DMA 允许 DMA 控制器通过一个描述符链表来执行一次传输。每个描述符包含一个内存块的起始地址和长度。DMA 控制器可以自动按顺序从一个不连续的物理内存区域(聚集)读取数据,并传输到外设;或者从外设读取数据,并写入到多个不连续的内存块(分散)。这极大地提高了处理碎片化缓冲区的效率,常见于网络数据包处理、文件 I/O 等场景。

七、总结

DMA(直接存储器访问)作为嵌入式系统性能优化的核心技术,其核心价值在于将 CPU 从繁重的数据搬运任务中解放出来,实现外设与内存之间的高效、直接数据传输。通过“CPU 配置,DMA 执行,中断通知”的工作流程,DMA 大幅降低了 CPU 开销,提升了系统整体吞吐量和实时性。

本文系统梳理了 DMA 的关键知识点:

  • 工作原理:基于总线仲裁与周期窃取,实现 CPU 与 DMA 控制器的协同工作。
  • 传输模式:包括适用于低速外设的单次传输、适合高速连续流的块传输、适应不规则数据节奏的请求传输以及用于扩展通道的级联模式
  • 控制器结构:由寄存器组、地址生成与计数器单元、控制逻辑与仲裁器、总线接口单元构成,现代控制器还集成了多通道、描述符链表、双缓冲区、内存保护等增强特性。
  • 典型应用:涵盖 UART、ADC、SPI/I2C、内存拷贝、LCD 刷新、音频流处理等场景,并提供了关键配置思路与代码片段。
  • 面试要点:深入探讨了 DMA 相比中断的优势、总线占用影响、内存保护机制以及高级的分散/聚集(Scatter/Gather)DMA 模式。

掌握 DMA 技术,不仅要求理解其底层硬件机制,更需要结合具体外设和实际场景进行灵活配置与优化。在嵌入式系统设计中,合理运用 DMA 能够显著提升 I/O 效率,降低 CPU 负载,是构建高性能、低功耗、高实时性系统的关键技能。建议读者在理解本文概念的基础上,动手实践文中的代码示例,并在实际项目中根据数据特性、时序要求和系统资源,选择最合适的 DMA 传输模式与配置策略。

http://www.jsqmd.com/news/1394756/

相关文章:

  • 热水系统安装完毕别急着用,关键调试几步到位保舒心
  • 避开影视培训大坑!大学生择校避坑与高薪就业实测攻略 - 生活动态圈
  • 2026行业**级无人机维修培训机构 优良铸就可靠好信誉 - 湖南阳光技术
  • Lettertrace 新手入门与实战指南
  • 中小企业采购策略:珠三角热镀锌无缝管批量订购建议
  • 重庆配眼镜推荐,散光人群配镜时要注意哪些细节 - 配眼镜新资讯
  • 开源游戏增强工具如何免费解锁Wand高级功能?三步配置加手机远程控制全攻略
  • 嵌入式面试总结(十八)——JTAG调试
  • AI Infra 大厂专题【左扬精讲】—— 2026 大厂 AI Infra 岗位招聘技术要求与用户画像分析
  • 办理出生公证认证:证天下几步搞定,无需单独对接(附问题解答)
  • 数据库之间的“专职快递员”:一文说透数据库(mysql,postgresql)流复制用户
  • 挑选无人机维修培训不用愁 靠谱名校稳居行业领先地位 - 湖南阳光技术
  • 重新定义数据接口:3个突破性场景让通达信数据读取更智能
  • 2026年苏州本土铜箔服务商头部:优质供应商推荐
  • 深圳双诚智能:如何选到靠谱热收缩包装机公司?
  • Honeywell 900RR0-0101 PLC 机架底盘
  • 虚拟机和docker网络对比
  • 2026健身蛋白粉怎么选?看清吸收率与配料表的真实差距 - 资讯报道
  • 2026简支梁冲击试验机品质评选 - 资讯报道
  • 嵌入式面试总结(十九)——内存泄露
  • OpenClaw预配置版快速上手教程,TopClaw免设置三步启用自带大模型
  • 2026年7月铜箔供应商权威推荐:苏州本土厂商选购攻略
  • 7字重免费商用:思源宋体CN开源字体完整配置终极指南
  • Spring Security + JWT的应用
  • 内景 空间站内部 中国空间站 太空 内仓
  • 【潮流优化】基于粒子群算法优化92 节点辐射型 20kV 配电网无功补偿容量,最小化网损 电压偏差附matlab代码
  • TokenPocket钱包官方网站代码全流程
  • 一文读懂快消WMS怎么选?2026年国内外10大主流WMS品牌盘点
  • 从IT运维角度聊聊东莞复印机租赁的选型问题
  • 上海君澜律师事务所孙青律师团队——上海房产分割诉讼业务介绍 - 孙青律师13681945561