16、DMA直接存储区访问

news/2024/11/23 5:43:18/

0x01、DMA简介

DMA(Direct Memory Access)一直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以于其他的事情,好像是多线程一样数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是FLASH。DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1有7个通道,DMA2有5个通道,这里的通道可以理解为传输数据的一种管道。要注意的是DMA2只存在于大容量的单片机中。

0x02、DMA功能框图

DMA 控制器独立于内核,属于一个单独的外设,结构比较简单,从编程的角度来看,我们只需掌握功能框图中的三部分内容即可,具体见图 DMA 框图: DMA控制器的框图。

0x0001、DMA请求

如果外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA 请求,DMA 收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。

0x0002、通道

DMA 具有12个独立可编程的通道,DMA有DMA1和DMA2 两个控制器,其中 DMA1有7个通道,DMA2有5个通道,每个通道对应不同的外设的 DMA 请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

DMA1有7个通道,DMA2有5个通道,不同的DMA控制器的通道对应着不同的外设请求,这决定了我们在软件编程上该怎么设置,具体见 DMA 请求映像表

DMA1表:

DMA2表:

 

 其中ADC3、SDIO 和 TIM8 的 DMA 请求只在大容量产品中存在,这个在具体项目时要注意。

 0x0003、仲裁器

当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在 DMA_CCRx 寄存器中设置,有4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高比如通道0高于通道 1。在大容量产品和互联型产品中,DMA 控制器拥有高于 DMA2 控制器的优先级。

0x03、DMA数据配置

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

0x0001、从哪里来到哪里去

我们知道DMA 传输数据的方向有三个: 从外设到存储器,从存储器到外设,从存储器到存储器具体的方向 DMA_CCR 位 4 DIR 配置:  表示从外设到存储器,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 模式 

0x0002、要传多少,单位是什么

当我们配置好数据要从哪里来到哪里去之后,我们还需要知道我们要传输的数据是多少,数据的单位是什么。
以串口向电脑发送数据为例,我们可以一次性给电脑发送很多数据,具体多少由 DMA_CNDTR配置,这是一个 32 位的寄存器,一次最多只能传输 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,而串口数据寄存器只有一个,那么外设的地址指针就固定不变。具体的数据指针的增量模式由实际情况决定。

0x0003、什么时候传输完成

数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。每个 DMA 通道在 DMA 传输过半、传输完成和传输错误时都会有相应的标志位,如果使能了该类型的中断后则会产生中断。有关各个标志位的详细描述请参考 DMA 中断状态寄存器 DMA ISR 的详细描述传输完成还分两种模式,是一次传输还是循环传输,一次传输很好理解,即是传输一次之后就停止,要想再传输的话,必须关断DMA 使能后再重新配置后才能继续传输。循环传输则是一次传输完成之后又恢复第一次传输时的配置循环传输,不断的重复。具体的由 DMA_CCR 寄存器的CIRC 循环模式位控制。

0x04、DMA初始化结构体详解 

标准库函数对每个外设都建立了一个初始化结构体 xxx InitTypeDef(xxx 为外设名称),结构体成员用于设置外设工作参数,并由标准库函数 xxx Imit0 调用这些设定参数进入设置外设相应的寄存器,达到配置外设工作环境的目的。
结构体 xxx InitTypeDef 和库函数 xxx Init 配合使用是标准库精所在,理解了结构体xxx_InitTypeDef 每个成员意义基本上就可以对该外设运用自如。结构体 xxx InitTypeDef 定义在stm32f10x xxx.h(后面xxx 为外设名称)文件中,库函数xxx Init 定义在 stm32f10x xxx.c 文件中编程时我们可以结合这两个文件内注释使用。

/** * @brief  DMA Init structure definition*/typedef struct
{uint32_t DMA_PeripheralBaseAddr; // 外设地址uint32_t DMA_MemoryBaseAddr;     // 存储器地址uint32_t DMA_DIR;                // 传输方向uint32_t DMA_BufferSize;         // 传输数目uint32_t DMA_PeripheralInc;      // 外设地址增量模式                                 uint32_t DMA_MemoryInc;          // 存储器地址增量模式 uint32_t DMA_PeripheralDataSize; // 外设数据宽度uint32_t DMA_MemoryDataSize;     // 存储器数据宽度uint32_t DMA_Mode;               // 模式选择uint32_t DMA_Priority;           // 通道优先级uint32_t DMA_M2M;                // 存储器到存储器模式              
}DMA_InitTypeDef;
  1. DMA PeripheralBaseAddr: 外设地址,设定 DMA_CPAR 寄存器的值;一般设置为外设的数据寄存器地址,如果是存储器到存储器模式则设置为其中一个存储器地址。
  2. DMA_Memory0BaseAddr: 存储器地址,设定 DMA_CMAR 寄存器值;一般设置为我们自定义存储区的首地址。
  3. DMA DIR: 传输方向选择,可选外设到存储器、存储器到外设。它设定 DMA_CCR 寄存器的DIR[1:0] 位的值。这里并没有存储器到存储器的方向选择,当使用存储器到存储器时,只需要把其中一个存储器当作外设使用即可。
  4. DMA_BulferSize: 设定待传输数据数目,初始化设定 DMA_CNDTR 寄存器的值
  5. DMA_Peripheralnc: 如果配置为 DMA Peripherallnc_Enable,使能外设地址自动递增功能,它设定 DMA_CCR 寄存器的 PINC 位的值;一般外设都是只有一个数据寄存器,所以一般不会使能该位。
  6. DMA MemoryInc:如果配置为 DMA MemoryInc_Enable,使能存储器地址自动递增功能,它设定 DMA_CCR 寄存器的 MINC 位的值;我们自定义的存储区一般都是存放多个数据的,所以要使能存储器地址自动递增功能。
  7. DMA PeripheralDataSize: 外设数据宽度,可选字节(8 位)、半字(16 位)和字(32 位),它设定DMA CCR 寄存器的 PSIZE[1:0] 位的值。
  8. DMA MemoryDalaSize: 在储器数据宽度,可选字节(8 位)、半字(16 位)和字(32 位),它设定DMA_CCR 寄存器的 MSIZE[1:0] 位的值。当外设和存储器之间传数据时,两边的数据宽度应该设置为一致大小。
  9. DMA_Mode: DMA 传输模式选择,可选一次传输或者循环传输,它设定 DMA_CCR 寄存器的CIRC 位的值。例程我们的 ADC 采集是持续循环进行的,所以使用循环传输模式。
  10. DMA_Priority: 软件设置通道的优先级,有 4个可选优先级分别为非常高、高、中和低,它设定 DMA_CCR 寄存器的 PL[1:0] 位的值。DMA 通道优先级只有在多个 DMA 通道同时使用时才有意义,如果是单个通道,优先级可以随便设置。
  11. DMA_M2M: 存储器到存储器模式,使用存储器到存储器时用到,设定 DMA CCR 的位14MEN2MEN 即可启动存储器到存储器模式。 

0x05、串口1通过DMA发送试验

1、通过DMA_InitStructure结构体配置串口1发送的DMA

#define  USART1_TX_DMA_CHANNEL    DMA1_Channel4          // 串口1发送对应的DMA请求通道4
#define  USART_DR_ADDRESS         (USART1_BASE + 0x04)   // 外设寄存器地址 串口1的数据寄存器USART_DR地址  偏移量4
#define  SENDBUFF_SIZE            5000                   // 一次发送的数据量void USART1_DMA_Config(void)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                       // 开启DMA时钟DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;             // 设置DMA源地址:串口数据寄存器地址DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t )SendBuff;          // 内存地址(要传输的变量的指针)DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralDST;        // 方向:从内存到外设DMA_InitStructure.DMA_BufferSize         = SENDBUFF_SIZE;                // 传输大小DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;    // 外设地址不增DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;         // 内存地址自增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  // 外设数据单位DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;	     // 内存数据单位
//    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal ;             // DMA模式,一次模式DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;            // DMA模式,循环模式DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;          // 优先级:中DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;              // 禁止内存到内存的传输DMA_Init(USART1_TX_DMA_CHANNEL, &DMA_InitStructure);                     // 配置DMA通道DMA_Cmd (USART1_TX_DMA_CHANNEL,ENABLE);                                  // 使能DMA
}

这里有几个参数是通过#define定义的

第一个是串口1发送的DMA通道,在参考手册中查表可知该通道为DMA1_Channel4;

第二个是DMA源地址即串口数据寄存器地址USART_DR_ADDRESS,它的地址是串口1的基地址加4即USART1_BASE + 0x04;

第三个是一次发送的数据量,这个可由使用者自由定义,这里定位为5000个字节

2、通过USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);函数请求DMA串口发送数据 

总结:整个过程中比较重要的两步就是上诉的两步,一是DMA的配置,二是向DMA请求发送


http://www.ppmy.cn/news/278377.html

相关文章

JavaScript全解析——Ajax(下)

Ajax(下) ●http 传输协议 ○http(s) 协议规定了, 只能由前端主动发起 ○并且在传输的过程中, 只能传递 字符串 ●http 协议过程 1.建立连接 浏览器和服务器进行连接建立 基于 TCP/IP 协议的三次握手 2.发送请求 要求前端必须以 请求报文 的形式发送 报文由浏览器组装,…

相机靶面尺寸与镜头尺寸之间的选择关系

为保证画面整体的可应用性,选用镜头的像面尺寸应大于相机芯片的对角线尺寸(以下简称靶面),否则会出现边缘暗角/黑角等情况,影响使用。 ———————————————— 版权声明:本文为博主「hackpig」…

工业相机的镜头接口知识介绍

工业相机的镜头接口知识介绍 物镜的接口尺寸是有国际标准的,共有三种接口型式,即F型、C型、CS型。F型接口是通用型接口,一般适用于焦距大于25mm的镜头;而当物镜的焦距约小于25mm时,因物镜的尺寸不大,便采用…

机器视觉工业相机和镜头选型

一、视野计算 1、倍率芯片尺寸(靶面)/视野----远心镜头选择 2、焦距倍率x相机高度(工作距离) 2、像素精度要求检查精度/(3-5)个像素 3、相机分辨率视野/像素精度 4、芯片尺寸(靶面)…

工业相机及镜头的相关概念与相机及镜头的选型

工业相机及镜头的相关概念与相机及镜头的选型 一、相机的主要参数 1.像素(pixel) ​ 像素是图像上的最小组成单元。图像由小方格即像素组成的,这些小方块都有一个明确的位置和被分配的色彩数值,小方格颜色和位置就决定该图像所…

工业相机、镜头、选型计算方式

1. 面阵相机和镜头选型 已知:被检测物体大小为AB,要求能够分辨率小于C,工作距离为D [1]相机选型步骤: (1). 相机的最低分辨率(AB)/(CC) , (2). 相机在选型时,最好缺陷的面积在3到5个像素以上,在选择相机时&…

视觉-相机、镜头选择

文章目录 成像系统模型机器视觉成像系统中的相关参数 镜头镜头技术参数镜头分辨率视场角景深接口 相机常用接口相机设置 相机/镜头选择流程 成像系统模型 机器视觉成像系统中的相关参数 视场:摄像头能观测到的最大范围 工作距离:镜头的下端到物体表面的…

机器视觉中如何选择工业相机与合适的相机镜头(how to choose camera and lens)

相机和镜头是计算机视觉中重要的组成部分,合适的相机和镜头决定了系统的好坏。但是大部分的计算机视觉工程师对如何选择工业用相机和合适的镜头上犯了难。本文主要介绍如何选择相机与对应的镜头。如果有错误的地方,请大家交流指正。 关注公众号&#xff…