STM32 —— DMA 发送与接收数据详解

这篇具有很好参考价值的文章主要介绍了STM32 —— DMA 发送与接收数据详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32 —— DMA 发送与接收数据详解

简介

DMA(Direct Memory Access) :直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU ,即在传输数据的时候,CPU 可以干其他的事情,好像是多线程一样。数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH

DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输

功能详解

功能框图

DMA 控制器基于复杂的总线矩阵架构,将功能强大的双 AHB 主总线架构与独立的 FIFO 结合在一起,优化了系统带宽

stm32dma 收发,stm32,单片机,嵌入式硬件
stm32dma 收发,stm32,单片机,嵌入式硬件

功能描述

DMA 控制器和 Cortex™-M3 核心共享系统数据总线,执行直接存储器数据传输。当 CPU 和 DMA 同时访问相同的目标( RAM 或外设)时, DMA 请求会暂停 CPU 访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证 CPU 至少可以得到一半的系统总线(存储器或外设)带宽

DMA 处理

在发生一个事件后,外设向 DMA 控制器发送一个请求信号。 DMA 控制器根据通道的优先权处理请求。当 DMA 控制器开始访问发出请求的外设时, DMA 控制器立即发送给它一个应答信号。当从 DMA 控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求, DMA 控制器同时撤销应答信号。如果有更多的请求时,外设可以启动下一个周期

总之,每次 DMA 传送由 3 个操作组成:

· 从外设数据寄存器或者从当前外设/存储器地址寄存器指示的存储器地址取数据,第一次传输时的开始地址是 DMA_CPARx 或 DMA_CMARx 寄存器指定的外设基地址或存储器单元

· 存数据到外设数据寄存器或者当前外设/存储器地址寄存器指示的存储器地址,第一次传输时的开始地址是 DMA_CPARx 或 DMA_CMARx 寄存器指定的外设基地址或存储器单元

· 执行一次 DMA_CNDTRx 寄存器的递减操作,该寄存器包含未完成的操作数目

简单来说就是先通过 DMA_SxPAR 或 DMA_SxM0AR 寄存器两次寻址,从外设数据寄存器或存储器单元中加载数据,并讲加载的数据存储进去,最后 DMA_SxNDTR 计数器在数据存储结束后递减,该计数器中包含仍需执行的事务数

DMA 通道

DMA 有 DMA1 和 DMA2 两个控制器, DMA1 有 7 个通道, DMA2 有 5 个通道,不同的 DMA 控制器的通道对应着不同的外设请求,虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个

这决定了我们在软件编程上该怎么设置,具体见 DMA 请求映像表:

各个通道的DMA1请求一览:

外设 通道1 通道2 通道3 通道4 通道5 通道6 通道7
ADC1 ADC1
SPI/I²S SPI1_RX SPI1_TX SPI/I2S2_RX SPI/I2S2_TX
USART USART3_TX USART3_RX USART1_TX USART1_RX USART2_RX USART2_TX
I²C I2C2_TX I2C2_RX I2C1_TX I2C1_RX
TIM1 TIM1_CH1 TIM1_CH2 TIM1_TX4
TIM1_TRIG
TIM1_COM
TIM1_UP TIM1_CH3
TIM2 TIM2_CH3 TIM2_UP TIM2_CH1 TIM2_CH2
TIM2_CH4
TIM3 TIM3_CH3 TIM3_CH4
TIM3_UP
TIM3_CH1
TIM3_TRIG
TIM4 TIM4_CH1 TIM4_CH2 TIM4_CH3 TIM4_UP

各个通道的DMA2请求一览:

外设 通道1 通道2 通道3 通道4 通道5
ADC3(2); ADC3
SPI/I2S3 SPI/I2S3_RX SPI/I2S3_TX
UART4 UART4_RX UART4_TX
SDIO(1) SDIO
TIM5 TIM5_CH4
TIM5_TRIG
TIM5_CH3
TIM5_UP
TIM5_CH2 TIM5_CH1
TIM6/DAC通道1 TIM6_UP/DAC通道1
TIM7/DAC通道2 TIM7_UP/DAC通道2
TIM8(1) TIM8_CH3
TIM8_UP
TIM8_CH4
TIM8_TRIG
TIM8_COM
TIM8_CH2 TIM8_CH2

1. ADC3、 SDIO和TIM8的DMA请求只在大容量的产品中存在。

*注意: *ADC2 没有 DMA 功能,其中 ADC3、 SDIO 和 TIM8 的 DMA 请求只在大容量产品中存在,这个在具体项目时要注意

可编程的数据量

每个通道都可以在有固定地址的外设寄存器和存储器地址之间执行 DMA 传输。 DMA 传输的数据量是可编程的,最大达到 65535 ,包含要传输的数据项数量的寄存器,在每次传输后递减

外设和存储器的传输数据量可以通过 DMA_CCRx 寄存器中的 PSIZE 和 MSIZE 位编程

可编程的数据传输宽度、对齐方式和数据大小端:当PSIZE和MSIZE不相同时, DMA模块按照下表进行数据对齐

可编程的数据传输宽度和大小端操作(当PINC = MINC = 1):

stm32dma 收发,stm32,单片机,嵌入式硬件
指针增量

通过设置 DMA_CCRx 寄存器中的 PINC 和 MINC 标志位,外设和存储器的指针在每次传输后可以有选择地完成自动增量

当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决与所选的数据宽度为 1、 2 或 4 。第一个传输的地址是存放在 DMA_CPARx/DMA_CMARx 寄存器中地址。在传输过程中,这些寄存器保持它们初始的数值,软件不能改变
和读出当前正在传输的地址(它在内部的当前外设/存储器地址寄存器中)

当通道配置为非循环模式时,传输结束后(即传输计数变为0)将不再产生DMA操作。要开始新的 DMA 传输,需要在关闭 DMA 通道的情况下,在 DMA_CNDTRx 寄存器中重新写入传输数目。在循环模式下,最后一次传输结束时,DMA_CNDTRx 寄存器的内容会自动地被重新加载为其初始数值,内部的当前外设/存储器地址寄存器也被重新加载为 DMA_CPARx/DMA_CMARx 寄存器设定的初始基地址

通道配置过程

下面是配置DMA通道x的过程(x代表通道号):

  1. 在 DMA_CPARx 寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将是数据传输的源或目标

  2. 在 DMA_CMARx 寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数据将从这个地址读出或写入这个地址

  3. 在 DMA_CNDTRx 寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减

  4. 在 DMA_CCRx 寄存器的 PL[1:0] 位中设置通道的优先级

  5. 在 DMA_CCRx 寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外设和存储器的数据宽度、传输一半产生中断或传输完成产生中断

  6. 设置 DMA_CCRx 寄存器的 ENABLE 位,启动该通道。

一旦启动了 DMA 通道,它既可响应连到该通道上的外设的 DMA 请求。

当传输一半的数据后,半传输标志(HTIF)被置 1,当设置了允许半传输中断位(HTIE)时,将产生一个中断请求。在数据传输结束后,传输完成标志(TCIF)被置 1,当设置了允许传输完成中断位(TCIE)时,将产生一个中断请求

循环模式

循环模式用于处理循环缓冲区和连续的数据传输(如 ADC 的扫描模式)。在 DMA_CCRx 寄存器中的 CIRC 位用于开启这一功能。当启动了循环模式,数据传输的数目变为 0 时,将会自动地被恢复成配置通道时设置的初值,DMA 操作将会继续进行

存储器到存储器模式

DMA 通道的操作可以在没有外设请求的情况下进行,这种操作就是存储器到存储器模式。当设置了 DMA_CCRx 寄存器中的 MEM2MEM 位之后,在软件设置了 DMA_CCRx 寄存器中的 EN 位启动 DMA 通道时,DMA 传输将马上开始。当 DMA_CNDTRx 寄存器变为 0 时,DMA 传输结束。存储器到存储器模式不能与循环模式同时使用

仲裁器

仲裁器根据通道请求的优先级来启动外设/存储器的访问

当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器管理

优先权管理分2个阶段:

  1. 软件:每个通道的优先权可以在 DMA_CCRx 寄存器中设置,有4个等级:

· 最高优先级

· 高优先级

· 中等优先级

· 低优先级
2. 硬件:如果 2 个或以上请求有相同的软件优先级(即 DMA 通道请求设置的优先级一样),则他们优先级取决于通道编号,较低编号的通道比较高编号的通道有较高的优先权。举个例子,通道2优先于通道4

注意:在大容量产品和互联型产品中, DMA1控制器拥有高于DMA2控制器的优先级

DMA 请求映像

DMA1

从外设(TIMx[x=1、 2、 3、 4]、 ADC1、 SPI1、 SPI/I2S2、 I2Cx[x=1、 2]和USARTx[x=1、 2、 3])产生的 7 个请求,通过逻辑或输入到 DMA1 控制器,这意味着同时只能有一个请求有效

外设的 DMA 请求,可以通过设置相应外设寄存器中的 DMA 控制位,被独立地开启或关闭

具体细节看下面的 DMA1 请求影响图解:

stm32dma 收发,stm32,单片机,嵌入式硬件
DMA2

从外设(TIMx[5、 6、 7、 8]、 ADC3、 SPI/I2S3、 UART4、 DAC通道1、 2和SDIO)产生的 5 个请求,经逻辑或输入到 DMA2 控制器,这意味着同时只能有一个请求有效

外设的 DMA 请求,可以通过设置相应外设寄存器中的 DMA 控制位,被独立地开启或关闭

注意:DMA2控制器及相关请求仅存在于大容量产品和互联型产品

具体细节看下面的 DMA2 请求影响图解:

stm32dma 收发,stm32,单片机,嵌入式硬件

DMA 寄存器

寄存器地址映像如下:

stm32dma 收发,stm32,单片机,嵌入式硬件

stm32dma 收发,stm32,单片机,嵌入式硬件

注意:在以下列举的所有寄存器中,所有与通道 6 和通道 7 相关的位,对 DMA2 都不适用,因为 DMA2 只有 5 个通道

中断状态寄存器 DMA_ISR

stm32dma 收发,stm32,单片机,嵌入式硬件
stm32dma 收发,stm32,单片机,嵌入式硬件

中断标志清除寄存器 DMA_IFCR

stm32dma 收发,stm32,单片机,嵌入式硬件

通道 x 配置寄存器 DMA_CCRx (x = 1…7)

stm32dma 收发,stm32,单片机,嵌入式硬件
stm32dma 收发,stm32,单片机,嵌入式硬件

通道 x 传输数量寄存器 DMA_CNDTRx (x = 1…7)

stm32dma 收发,stm32,单片机,嵌入式硬件

通道 x 外设地址寄存器 DMA_CPARx (x = 1…7)

stm32dma 收发,stm32,单片机,嵌入式硬件

通道 x 存储器地址寄存器 DMA_CMARx (x = 1…7)

stm32dma 收发,stm32,单片机,嵌入式硬件
stm32dma 收发,stm32,单片机,嵌入式硬件

数据配置

使用 DMA,最核心就是配置要传输的数据,包括数据从哪里来,要到哪里去,传输的数据的单位是什么,要传多少数据,是一次传输还是循环传输等等

从哪里来到哪里去

我们知道 DMA 传输数据的方向有三个:从外设到存储器,从存储器到外设,从存储器到存储器。具体的方向 DMA_CCR 位 4 DIR 配置: 0 表示从外设到存储器, 1 表示从存储器到外设。这里面涉及到的外设地址由 DMA_CPAR 配置,存储器地址由 DMA_CMAR 配置

外设到寄存器

当我们使用从外设到存储器传输时,以 ADC 采集为例

DMA 外设寄存器的地址对应的就是 ADC 数据寄存器的地址, DMA 存储器的地址就是我们自定义的变量(用来接收存储 AD 采集的数据)的地址。方向我们设置外设为源地址

存储器到外设

当我们使用从存储器到外设传输时,以串口向电脑端发送数据为例

DMA 外设寄存器的地址对应的就是串口数据寄存器的地址, DMA 存储器的地址就是我们自定义的变量(相当于一个缓冲区,用来存储通过串口发送到电脑的数据)的地址。方向我们设置外设为目标地址

存储器到存储器

当我们使用从存储器到存储器传输时,以内部 FLASH 向内部 SRAM 复制数据为例

DMA 外设寄存器的地址对应的就是内部 FLASH(我们这里把内部 FALSH 当作一个外设来看)的地址, DMA 存储器的地址就是我们自定义的变量(相当于一个缓冲区,用来存储来自内部 FLASH 的数据)的地址。方向我们设置外设(即内部 FLASH)为源地址

跟上面两个不一样的是,这里需要把 DMA_CCR 位 14: MEM2MEM:存储器到存储器模式配置为 1,启动 M2M 模式

要传多少,单位是什么

当我们配置好数据要从哪里来到哪里去之后,我们还需要知道我们要传输的数据是多少,数据的单位是什么

以串口向电脑发送数据为例,我们可以一次性给电脑发送很多数据,具体多少由 DMA_CNDTR 配置,这是一个 32 位的寄存器,前16位为数据传输数量,一次最多只能传输 65535 个数据

要想数据传输正确,源和目标地址存储的数据宽度还必须一致,串口数据寄存器是 8 位的,所以我们定义的要发送的数据也必须是 8 位。外设的数据宽度由 DMA_CCR 的 PSIZE[1:0] 配置,可以是 8/16/32 位,存储器的数据宽度由 DMA_CCR 的 MSIZE[1:0] 配置,可以是 8/16/32 位

在 DMA 控制器的控制下,数据要想有条不紊的从一个地方搬到另外一个地方,还必须正确设置两边数据指针的增量模式。外设的地址指针由 DMA_CCRx 的 PINC 配置,存储器的地址指针由 MINC 配置。以串口向电脑发送数据为例,要发送的数据很多,每发送完一个,那么存储器的地址指针就应该加 1,而串口数据寄存器只有一个,那么外设的地址指针就固定不变。具体的数据指针的增量模式由实际情况决定

什么时候传输完成

数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。每个 DMA 通道在 DMA 传输过半、传输完成和传输错误时都会有相应的标志位,如果使能了该类型的中断后,则会产生中断。有关各个标志位的详细描述请参考 DMA 中断状态寄存器 DMA_ISR 的详细描述

传输完成还分两种模式,是一次传输还是循环传输,一次传输很好理解,即是传输一次之后就停止,要想再传输的话,必须关断 DMA 使能后再重新配置后才能继续传输。循环传输则是一次传输完成之后又恢复第一次传输时的配置循环传输,不断的重复。具体的由 DMA_CCR 寄存器的 CIRC 循环模式位控制

传输参数

我们知道,数据传输,首先需要的是1 数据的源地址 2 数据传输位置的目标地址 ,3 传递数据多少的数据传输量 ,4 进行多少次传输的传输模式 DMA所需要的核心参数,便是这四个

当用户将参数设置好,主要涉及源地址、目标地址、传输数据量这三个,DMA控制器就会启动数据传输,当剩余传输数据量为0时 达到传输终点,结束DMA传输 ,当然,DMA 还有循环传输模式 当到达传输终点时会重新启动DMA传输

也就是说只要剩余传输数据量不是0,而且DMA是启动状态,那么就会发生数据传输

参考文档

  1. 【STM32】HAL库 STM32CubeMX教程十一---DMA (串口DMA发送接收)

  2. STM32 DMA详解

  3. 16、STM32——DMA详解

  4. STM32中DMA用法文章来源地址https://www.toymoban.com/news/detail-639204.html

到了这里,关于STM32 —— DMA 发送与接收数据详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32笔记】STM32的串口数据收发基础(四)(USART DMA模式)

         在STM32中编写串口通信数据收发有三种方式: 轮询模式 (阻塞方式), 中断模式 (非阻塞方式)以及 DMA模式 。      打开STM32CubeMX,前部分配置流程如串口数据收发基础(三)节里一样。配置好USART1的基本参数,开启定时器中断后,接下来就要开启USART1的DMA。

    2024年02月03日
    浏览(40)
  • STM32 串口DMA接收数据(高效接收数据)

    极度不推荐在使用DMA的时候按照传统的方式进行重定义!!! 非常简单,轮询方式整个CPU 在串口发送时处于等待状态,但是使用DMA时无法确保当前DMA已经传输完成。 有同学可能会认为可以通过判断DMA的传输标志位来进行等待,但如果这样的话就丧失了DMA的设计意图: 再次使

    2024年02月16日
    浏览(52)
  • 【STM32+HAL库+CubeMX】UART轮询收发、中断收发、DMA收发方法及空闲中断详解

    Author: DrinkCat(szt@drinkcat.com) Copyright © 2023 DrinkCat Original link: DrinkCat’s Blog UART是一种异步串行通信接口,常用于通过串口与外部设备进行通信。它通过发送和接收数据帧来实现数据传输,使用起来相对简单。UART通常包含发送器(Transmitter)和接收器(Receiver),通过两根信号线

    2024年02月10日
    浏览(40)
  • STM32实现DMA接收串口数据

    一..首先我们得配置DMA和USARAT,我们的原理是DMA1的通道5为USART1的RX引脚。  1.USART1的配置 2.DMA的配置 二.中断进行数据处理(stm32f10x_it.c) 我们可以串口打印出数组中的数据,验证DMA是否正常工作。可以到数据处理那个地方进行处理。USART1在初始化中就已经波特率为115200.我们可以

    2024年02月16日
    浏览(47)
  • STM32 串口 DMA 接收任意长度数据

    DMA 传输完成会产生中断告知 CPU,这对于固定长度的数据是没什么问题的。但是对于不定长的数据就不行了,DMA 一定要接收到足够多(设定的长度)的数据时才产生完成中断,如果接收到的数据量小于设定的长度,这个时候 CPU 就无法通过中断方式取处理这点数据了。那 CPU

    2024年02月11日
    浏览(44)
  • STM32 cubemx配置DMA+空闲中断接收不定长数据

    本篇文章给大家讲解一下DMA+串口空闲中断接收串口不定长数据,之前我们也是讲解过串口接收不定长数据的,那么本篇文章的话将使用DMA来接收不定长数据。 串口空闲中断是指在串口接收到数据后,在数据的传输结束之后,在一段连续的空闲时间内没有接收到新数据时触发

    2024年02月19日
    浏览(56)
  • STM32F407以太网DMA描述符和数据链路层收发数据

    本文主要介绍STM32F407单片机MAC内核的DMA描述符,以及如何实现以太网二层的数据收发。这一篇先实现数据链路层的正常收发,下一篇再去介绍如何把LWIP移植到单片机上。大部分资料都是把LWIP移植和以太网卡驱动放在一起介绍,对新手不友好。所以我在这篇文章先把网卡驱动

    2024年02月10日
    浏览(63)
  • STM32+UART串口+DMA收发

    目录 1、cubemax端配置 1.1 初始化配置 1.2 GPIO配置  1.3 UART配置 1.3.1 串口基础配置 1.3.2 DMA配置 2、keil端代码设计 2.1 初始化配置 2.2 DMA接收初始化配置 2.3 DMA发送配置  2.4 接收回调函数设置 2.5 回调函数内容代码编写 2.5.1 接收回调函数 2.5.2 发送回调函数 2.6 回调函数内容代码优化

    2024年02月07日
    浏览(43)
  • STM32 F4串口空闲中断 + DMA实现数据发送

    最近在做 STM32 + ROS车的项目,STM32与ROS之间通信由于数据量大,所以在 STM32端 使用 空闲中断 + DMA 的方案来减轻 CPU 的压力。 一、空闲中断 空闲中断 顾名思义为空了,闲了,没事了进的中断,在 没有数据流 的时候会进入进行读取。 在我们串口进行发送时实则为连续发送,两

    2024年02月16日
    浏览(64)
  • stm32串口+DMA环形缓冲收发保姆级

    首先在此感谢开源项目,以及大佬们的无私奉献,让每一个逐梦人能够免费学习,再次感谢! 发布只为记录,记性不够,笔记来凑。记得点赞哦 具体实现原理讲起来确实挺复杂,不过用起来还是很NICE的!可以直接移植! 1.1、选择单片机型号 2、配置时钟和串口 或者直接在

    2024年02月10日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包