STM32单片机DMA存储器详解

文章目录

1. DMA概述

2. 存储器映像

3. DMA框架图

4. DMA请求

5. 数据宽度与对齐

6. DMA数据转运

7. ADC扫描模式和DMA

8. 代码示例


1. DMA概述

DMA(Direct Memory Access)可以直接访问STM32内部的存储器,DMA是一种技术,允许外设和存储器之间直接传输数据,而无需通过CPU进行数据搬运。这种技术大大提高了数据传输效率,减少了CPU的负担,使CPU能够专注于其他计算任务。

DMA可以提供外设(外设寄存器,⼀般是外设的数据寄存器DR(Data Register),比如ADC的数据寄存器,串口的数据寄存器)和存储器(运行内存(SRAM)和程序存储器(Flash)是存储变量数组和程序代码的地方)或者存储器与存储器之间的高速数据传输,非常适合用于需要高带宽数据流的应用,例如音频数据传输、图像处理等。

STM32系列一共有12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)。但是在STM32F103C8T6中,只有一个个DMA1控制器。每个通道都可以配置为不同的外设或存储器数据传输。

例如:DMA1的通道1可以配置为ADC(模数转换器)数据传输通道,DMA1的通道2可以配置为USART(通用同步/异步收发器)数据传输通道等。

每个通道都支持软件触发和特定的硬件触发,存储器到存储器的数据转运,⼀般用软件触发,外设到存储器的转运⼀般用硬件触发。

  • 软件触发:可以通过编程控制DMA的启动,例如在需要传输数据时,通过软件命令触发DMA操作。
  • 硬件触发:一些外设(例如ADC转换完成、USART接收到数据)可以配置为在特定事件发生时自动触发DMA进行数据传输。这种硬件触发机制可以进一步提高系统的实时性能。

2. 存储器映像

类型起始地址存储器用途
ROM

0x0800 0000

程序存储器Flash

存储C语言编译后的程序代码。这个区域主要用于存储用户的应用程序代码,通常是通过编程器或BootLoader进行烧录。

0x1FFF F000

系统存储器

存储BootLoader,用于串口下载。这个区域包含了STM32内部的系统启动加载程序,用户可以通过串口等方式下载新程序。

0x1FFF F800

选项字节

存储一些独立于程序代码的配置参数。这些配置参数包括读保护、写保护等安全设置。
RAM

0x2000 0000

运行内存SRAM

存储运行过程中的临时变量。这个区域用于程序运行时的堆栈、全局变量、动态分配的内存等。

0x4000 0000

外设寄存器

存储各个外设的配置参数。这个区域用于映射STM32的各个外设的寄存器地址,程序通过访问这些地址来配置和控制外设。

0xE000 0000

内核外设寄存器

存储内核各个外设的配置参数。这个区域主要包含Cortex-M3核心的系统控制寄存器、调试接口等。

计算机系统的五大组成部分

  1. 运算器:负责执行计算和逻辑操作,是计算机进行数据处理的主要部件。
  2. 控制器:负责指挥和协调计算机各部分的工作,控制指令的执行顺序和操作。
  3. 存储器:用于存储数据和程序,是计算机的重要组成部分,分为主存储器和辅助存储器。
  4. 输入设备:用于将外部信息输入到计算机中,如键盘、鼠标、扫描仪等。
  5. 输出设备:用于将计算机处理结果输出到外部,如显示器、打印机等。

存储器的分类

存储器主要分为两大类:只读存储器(ROM)和随机存储器(RAM)。

ROM(只读存储器)

ROM是一种非易失性存储器,即使在断电后,其内容也不会丢失。可以分为以下几种:

  • 程序存储器(Flash):主要用于存储经过编译的程序代码。一般情况下,程序从主闪存开始运行。
  • 系统存储器:存储启动加载程序(BootLoader),该程序通常在芯片出厂时写入,不允许用户修改。
  • 选项字节:用于存储配置数据,如Flash的读写保护设置和看门狗配置等。尽管它们也属于ROM范畴,但其存储介质也是Flash。

RAM(随机存储器)

RAM是一种易失性存储器,断电后其内容会丢失。主要分为以下几种用途:

  • 运行内存(SRAM):用于存储程序中定义的变量、数组和结构体等临时数据。
  • 外设寄存器:用于存储初始化各个外设的配置数据,以及外设运行时读写的数据。这些寄存器的存储介质也是SRAM。
  • 内核外设:例如NVIC(中断控制器)和SysTick(系统定时器)的存储器,这些也是用来控制和管理计算机的外设功能。

3. DMA框架图

 左上角是Cortex-M3内核,其中包含了CPU和内核外设,其他部分可以视为存储器。Flash是主闪存,SRAM是运行内存,各个外设可以看成寄存器,它们也是一种SRAM存储器。寄存器是一种特殊的存储器,CPU可以像读写内存一样对寄存器进行操作。同时,寄存器的每一位连接着控制外设电路的导线,用于控制引脚的高低电平、导通和断开等。寄存器是软件与硬件的桥梁,通过读写寄存器,软件实际上在控制硬件。

为了高效管理存储器,设计了一个总线矩阵。总线矩阵的左边是主动单元(具有存储器访问权),右边是被动单元(只能被动读取)。内核中有DCode总线(专门访问Flash)和系统总线(访问其他存储器)。DMA作为主动单元,也需要总线访问权,有自己的总线(DMA1和DMA2),它们分别有7个和5个通道,负责设置数据的源地址和目标地址。仲裁器决定通道的优先级,确保公平访问。

在总线矩阵中,如果DMA和CPU同时访问同一目标,DMA会暂停CPU的访问,但总线仲裁器会保证CPU得到一半的总线带宽。DMA本身也有自己的配置寄存器,连接在AHB总线上,因此DMA既是主动单元也可以作为被动单元接受访问。DMA请求是硬件触发信号,用于在ADC转换完成或串口接收到数据时,触发DMA进行数据转运。

Flash是ROM的一种,通过总线直接访问时,无论是CPU还是DMA,都只能读取数据,不能写入。如果DMA的目标地址是Flash区域,会导致转运错误。写入Flash需要通过接口控制器,先擦除再写入数据。

DMA的数据转运可以从外设到存储器,也可以从存储器到外设,还可以在存储器之间进行。每个站点(外设或存储器)有三个参数:

  1. 起始地址:包括外设端的起始地址和存储器端的起始地址,决定数据从哪里来,到哪里去。
  2. 数据宽度:指定一次转运的数据宽度,可以是字节(8位),半字(16位),或字(32位)。例如,ADC的数据为16位(uint16_t),因此应选择半字。
  3. 地址自增:决定每次转运后,地址是否移动到下一个位置。例如,在ADC扫描模式下,外设地址不需自增,而存储器地址需要自增,以防止数据覆盖。

传输计数器与自动重装器

  • 传输计数器:指定总共转运的次数,是一个自减计数器。例如,设置为5,则DMA只能转运5次,每次转运后计数器减1。当计数器减到0后,DMA停止转运,并恢复到起始地址。
  • 自动重装器:决定计数器减到0后是否自动恢复到初始值。如果使用自动重装器,DMA会在计数器减到0后自动重装初始值,实现循环模式;否则是单次模式。

DMA触发控制

DMA的触发源有硬件触发和软件触发,通过M2M参数选择。当M2M为1时,使用软件触发,DMA以最快速度连续不断地触发,直到传输计数器清0。软件触发和循环模式不能同时使用,因为软件触发清零后不重装,循环模式清零后自动重装。

当M2M为0时,使用硬件触发,常用于与外设有关的转运。例如,ADC转换完成、串口接收到数据或定时时间到时,硬件触发DMA进行转运。

DMA启用条件

DMA准备进行转运的条件包括:

  1. 开关控制:DMA_Cmd必须使能。
  2. 传输计数器:必须大于0。
  3. 触发源:必须有触发信号。每次触发,传输计数器自减1。当计数器等于0且无自动重装时,DMA停止转运。此时,需要禁用DMA(DMA_Cmd给DISABLE),重设传输计数器,然后重新启用DMA(DMA_Cmd给ENABLE),才能继续工作。写传输计数器时,必须先关闭DMA,再进行设置。

4. DMA请求

 这张图显示了DMA1的请求映像,其中包括DMA的7个通道。每个通道都有一个数据选择器,可以选择硬件触发或软件触发。左边列出了硬件触发源,每个通道的硬件触发源是不同的。例如:

  • 若要选择ADC1来触发,则必须选择通道1。
  • 若要选择TIM2的更新事件来触发,则必须选择通道2。

每个通道的硬件触发源是固定的,所以要使用某个硬件触发源,就必须使用其对应的通道。而如果使用软件触发,则可以任意选择通道。

硬件触发与软件触发

  • 硬件触发:每个硬件触发源对应固定的通道。例如,使用ADC1作为触发源时,需要调用库函数ADC_DMACmd来开启ADC1的DMA输出。同理,使用定时器2的通道3时,需要使用TIM_DMACmd函数来控制DMA输出。具体选择哪个触发源,取决于你开启了哪个外设的DMA输出。

  • 软件触发:软件触发时,通道选择是任意的,不受硬件触发源的限制。

优先级仲裁

这7个触发源进入仲裁器,进行优先级判断,最终产生内部的DMA1请求。默认情况下,通道号越小,优先级越高。但是,这个优先级可以在程序中进行配置。

5. 数据宽度与对齐

第一列表示源端宽度,第二列表示目标宽度,第三列表示传输数量。以下是不同情况下的操作:

源端宽度和目标宽度都是8位

  • 源端0位置读数据B0,目标0位置写数据B0。

  • 依次将B1、B2、B3从源端挪到目标端。

源端宽度8位,目标宽度16位

  • 源端读取B0,目标写入00B0。

  • 源端读取B1,目标写入00B1,依此类推。

  • 目标宽度大于源端宽度时,目标数据前面多出来的空位补0。

源端宽度8位,目标宽度32位

  • 类似地,源端读取8位数据,目标写入32位数据时,前面空位补0。

源端宽度16位,目标宽度8位

  • 源端读取B1B0,只写入B0,舍弃高位B1。

  • 源端读取B3B2,只写入B2,舍弃高位B3。

总结

  • 当目标宽度大于源端宽度时,目标数据前面空位补0。

  • 当目标宽度小于源端宽度时,舍弃多余的高位数据。

  • 当源端和目标宽度相同时,数据直接传输,无需额外处理。

6. DMA数据转运

将SRAM中的数组DataA转运到另一个数组DataB中,参数配置如下:

  • 外设地址:DataA数组的首地址

  • 存储器地址:DataB数组的首地址

  • 数据宽度:两个数组的类型都是uint8_t,所以数据宽度为8位(字节)传输

  • 地址自增

    • 如果两个站点的地址都自增,转运完成后,DataB数组的所有数据将与DataA数组相同。
    • 如果源地址(DataA)不自增,而目标地址(DataB)自增,转运完成后,DataB的所有数据都会等于DataA[0]。
    • 如果源地址(DataA)自增,而目标地址(DataB)不自增,DataB[0]将等于DataA的最后一个数,DataB的其他数据保持不变。
    • 如果两个地址都不自增,DataA[0]转到DataB[0],其他数据不变。
  • 方向参数:从外设站点(DataA)转运到存储器站点(DataB)。

  • 传输计数器:设置为7,不需要自动重装。

  • 触发选择:选择软件触发。

最后,调用DMA_Cmd使能DMA,转运7次后,传输计数器减到0,DMA停止,转运完成。需要注意的是,这种数据转运是一种复制转运,转运完成后DataA的数据不会消失。

7. ADC扫描模式和DMA

左边展示的是ADC扫描模式下的转运流程。每次触发后,7个通道依次进行AD转换,并将转换结果存放在ADC_DR寄存器中。每个通道转换完成后,进行一次DMA数据转运,同时自增目标地址,防止数据覆盖。

DMA配置

  1. 外设地址:设置为ADC_DR寄存器的地址。
  2. 存储器地址:在SRAM中定义一个数组ADValue,并将其地址作为存储器地址。
  3. 数据宽度:因为ADC_DR和SRAM数组都使用uint16_t数据类型,数据宽度设置为16位(半字)传输。
  4. 地址自增
    • 外设地址不自增。
    • 存储器地址自增。
  5. 传输方向:从外设站点(ADC_DR)到存储器站点(ADValue数组)。
  6. 传输计数器:设置为7,与通道数量相同。
  7. 自动重装:根据ADC的配置决定。
    • 如果ADC是单次扫描,DMA传输计数器不需要自动重装,完成一次转换后停止。
    • 如果ADC是连续扫描,DMA可以选择自动重装,在ADC启动下一轮转换时,DMA也启动下一轮转运,使ADC和DMA同步工作。
  8. 触发选择:选择ADC的硬件触发。ADC扫描模式在单个通道完成转换后,不会置任何标志位或产生中断,但会产生DMA请求,触发DMA转运。

8. 代码示例

STM32基于DMA数据转运和AD多通道

STM32基于DMA数据转运和AD多通道-CSDN博客

  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TENET-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值