简述单片机的DMA转运数据原理和编程实现

这篇博客介绍了如何在STM32和GD32单片机中配置ADC和DMA,实现ADC自动扫描多个通道并将转换结果通过DMA传输到数组中。详细步骤包括设置ADC扫描模式、DMA通道配置、规则组设定以及启动转换。这种配置适用于需要连续获取AD转换数据的场景。

【本文发布于https://blog.youkuaiyun.com/Stack_/article/details/115948212,未经许可不得转载,转载须注明出处】


在GD32F30x中,ADC0对应DMA0的通道0.

在初始化了ADC0和DMA0_CH0后,ADC0每转换完规则组中的一个通道,将转换结果存至RDATA寄存器,并向DMA0发出请求。

DMA0响应,从ADC0_RDATA寄存器读走AD值并存入我们预先开辟的一段内存空间(例如定义的一个数组),并将地址指向下一个数据位以备下一次写入(如此次从RDATA读出存入数组array[0],下次存入array[1])。

然后ADC0继续转换规则组中的下一个通道,转换完成再次发起dma请求,直到该规则组所有ADC通道被转换完。如果ADC0使能了连续模式,DMA使能了循环模式,将不断自动扫描AD通道并更新数组中的数据。



ADC规则组举例说明作用:

向规则序列寄存器写入该序列的待转换通道数量,并写入各个通道编号。

如RL写入4(表明该序列有5个待转换通道),RSQ0-RSQ4依次写入编号ADC_CHANNEL_11,ADC_CHANNEL_1,ADC_CHANNEL_3,ADC_CHANNEL_12,ADC_CHANNEL_13共5个通道)

然后将ADC配置为扫描模式,ADC将依次转换该序列的通道CH_11,CH_1,CH_3,CH12,CH_13。


在这里插入图片描述





编程实现ADC0自动扫描5个通道,AD值由DMA0自动转运至数组中,CPU直接从数组中读取对应通道AD值。

一、ADC0配置

  1. 使能ADC0扫描模式;
  2. 使能ADC0的DMA请求;
  3. 允许连续模式(ADC0扫描至RSQ4并完成之后自动折返从RSQ0开始顺序转换);
  4. 如上面所述配置规则组;

二、DMA0通道0配置

  1. 选择数据搬运方向为外设到存储器;
  2. 将ADC0_RDATA寄存器(AD转换结果寄存器)的地址写入DMA0通道0的外设基地址寄存器;
  3. 定义一个全局数组如uint16_t array[5] = {0x00};并将该数组的首地址写入DMA0通道0的存储器基地址寄存器;
  4. 配置数据传输总量(和ADC0规则组通道数对应);
  5. 使能循环模式(写到array[4]后折返array[0]继续写);
  6. 外设地址算法选择固定模式,因为固定从RDATA读出数据;
  7. 存储器地址算法选择增量模式即自动增加,写入array[0]后自动指向array[1]以备下次写入;
  8. 外设和存储器位宽均选择16位,因为为12位AD值,所以定义的数组为uint16_t;

三、使能ADC0和DMA0通道0

四、如果只需要一直转换AD值,则使能ADC0外部触发并向ETSRC写入7触发转换(软件触发)。



配置完成后,ADC0将循环转换5个通道数据并请求DMA0,DMA0循环将5个通道转换结果依次存入array[0] ~ array[4].



STM32配置此功能的步骤与上述类似。

### DMA 工作原理详解 DMA(Direct Memory Access,直接内存访问)是一种允许外设与内存之间直接进行数据传输的技术,而无需 CPU 的频繁干预。以下是 DMA 工作原理的详细解析: #### 配置阶段 在 DMA 传输开始之前,需要对 DMA 控制器进行初始化配置。这包括设置传输方向、传输大小、数据宽度、源地址目标地址等参数[^1]。此外,还需要指定是否启用中断功能以及配置通道优先级。 #### 数据传输阶段 一旦 DMA 控制器接收到外设发出的请求信号,它将接管总线控制权,并根据预先配置的参数执行数据传输操作。具体过程如下: - 外设向 DMA 控制器发送 DMA 请求。 - DMA 控制器根据通道优先级处理请求,并向请求方发送应答信号[^3]。 - 在接收到应答信号后,DMA 控制器启动传输,从源地址读取数据并写入目标地址。 - 每成一次数据传输,DMA 控制器会更新源地址目标地址(如果启用了自动递增模式),并减少剩余传输计数器的值。 #### 链式 DMA 传输 对于需要传输多个离散内存块的情况,可以采用链式 DMA 传输方式。这种方式通过构建一个描述符表来管理各个内存块的信息,每个描述符包含当前内存块的地址、长度以及指向下一个描述符的指针[^2]。链式传输的主要优点是能够一次性成多个内存块的数据传输,从而提高效率。 #### 中断处理 当 DMA 传输成后,控制器可以生成一个中断信号通知 CPU。CPU 可以通过查询 DMA 状态寄存器获取传输结果,并决定是否需要采取进一步行动。此外,在传输过程中如果发生错误(如访问越界或奇偶校验错误),DMA 控制器也会触发相应的异常中断[^1]。 #### 性能优化 为了提升 DMA 的传输性能,可以从以下几个方面入手: - 使用更宽的数据总线以增加每次传输的数据量。 - 合理分配 DMA 通道优先级,确保高优先级任务得到及时响应。 - 减少不必要的中断开销,例如仅在传输结束时产生一次中断,而不是每传输一个数据单元就产生一次中断。 ```python # 示例:基于 HAL 库的 STM32 DMA 配置代码 dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; # 设置传输方向 dma_handle.Init.PeriphInc = DMA_PINC_DISABLE; # 禁用外设地址递增 dma_handle.Init.MemInc = DMA_MINC_ENABLE; # 启用内存地址递增 dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; # 外设数据对齐方式 dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; # 内存数据对齐方式 dma_handle.Init.Mode = DMA_CIRCULAR; # 循环模式 dma_handle.Init.Priority = DMA_PRIORITY_HIGH; # 设置优先级为高 HAL_DMA_Init(&dma_handle); # 初始化 DMA 控制器 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值