STM32F103之DMA

发布者:SparkStar22最新更新时间:2016-12-26 来源: eefocus关键字:STM32F103  DMA 手机看文章 扫描二维码
随时随地手机看文章

一、背景:

    需要使用STM32的DAC,例程代码中用了DMA,对DMA之前没有实际操作过,也很早就想知道DMA到底是什么,因此,

看了一下午手册,代码和网上的资料,便有了此篇文章,做个记录。


二、正文:

    DMA(Direct Memory Access),直接翻译为"直接存储器存取",数据手册对其定义为:提供在"外设和存储器

之间"或者"存储器和存储器之间"的高速数据传输,无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源

来做其他操作。

    既然说了DMA是两个寄存器之间的数据直接交换,都有哪些形式的数据交换呢?

    > 外设到SRAM(IIC的数据,直接放到SRAM内等);

    > SRAM到外设(SRAM内的数据自动传输到DAC输出等);

    > 存储器到存储器之间;

    > 闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标——意味着外设间也可传输?

    > 其他待发现······

    STM32F103有两路DMA,12个通道,DMA1有7个,DMA2有5个,每个通道专门用来管理来自于一个或多个外设对

存储器访问的请求。既然同时有多路通道,多个请求,所以还有一个仲裁器来协调各个DMA请求的优先权,也就意味着,

当多个通道同时有请求时,只能优先权最高的先独占DMA资源,其用完后,再留给低优先权的使用。

    DMA的优先权分配分为"硬优先权"和"软优先权"。

    > 软优先权:通过软件配置为最高优先级/高优先级/中等优先级/低优先级;

    > 硬优先权:通道号低的优先级更高。

    综合来说,既先比较软优先权,软优先权高优先使用DMA,若软优先权相同,则通道号低的优先使用DMA。

    

    DMA,既然是直接存储存取,那么只要初始化正确,就可以不用管它,它会自行做事,配置DMA又需要哪些内容可

以使其正常工作呢?以下为数据手册写的配置DMA通道x的过程(x代表通道号):

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

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

      或写入这个地址。 

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

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

    > 在DMA_CCRx寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外设和存储器的数据宽度、

    传输一半产生中断或传输完成产生中断。 

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

    DMA的工作过程既是,当DMA通道启动后,根据DMA_CCRx寄存器设置的方向(从外设到内存,或者内存到外设)

,DMA会自动将DMA_CPARx设置的外设寄存器地址内的数据传输到DMA_CMARx的地址内,或者反之,每次拿取的大

小为DMA_CCRx设置的数据值,总的数据量为DMA_CNDTRx设置的数据量。每传输一次DMA_CNDTRx的值就会减少,直

到其减为零,根据DMA_CCRx内设置的循环模式来选择接下来的操作。如果选择普通模式,那么当寄存器DMA_CNDTRx

的值减为零时,DMA传输就自动停止了,若需要继续此DMA,那需要再进行配置,重新使能对应DMA;若是选择为循环模

式的话,那么当寄存器DMA_CNDTRx的值减为零时,它会恢复成配置的初值,重新开始DMA操作。

    *注意:当DMA操作为存储器到存储器模式的话,即DMA_CCRx的MEM2MEM(Memory to memory)位设置了后,那

么DMA传输不需要外设请求,就能在DMA通道使能后,立即开始传输,当DMA_CNDTRx设置的总纯数据量减为"0"时,DMA

传输也就停止,但是,其不能使用循环传输模式。

    关于DMA通道的中断,数据手册说明如下:

    一旦启动了DMA通道,它既可响应连到该通道上的外设的DMA请求。 当传输一半的数据后,半传输标志(HTIF)被置

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

置了允许传输完成中断位(TCIE)时,将产生一个中断请求。

    现在则以将SRAM内的数据自动传输到DAC输出为例。以DMA初始化库函数代码为模版进行详细说明。

    首先是打开对应的DMA时钟:

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1|RCC_AHBPeriph_DMA2, ENABLE);


    其次,初始化DMA,DMA初始化库函数如下:

    DMA_Init(DMA2_Channel4, &DMA_InitStructure);

    该函数原型如下:

    void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

    参数 1:DMA_Channel_TypeDef* DMAy_Channelx

            为要初始化的通道号。具体值为:DMA1_Channel1->DMA1_Channel7/

                       DMA2_Channel1->DMA2_Channel5

    参数 2:DMA_InitTypeDef* DMA_InitStruct.

            为要初始化的DMA的详细参数,其详细结构体如下:

            typedef struct

            {

                /* DMA通道外设地址 

                   此处填写DAC寄存器的值 "DAC_DHR12RD_Address"。

                    #define DAC_DHR12RD_Address      0x40007420    // DAC寄存器的起始地址

                   相信很多刚接触MCU的朋友会困惑这个地址是如何来的?

                   其实这个就是DAC寄存器组基址"0x4007400"加上"DAC_DHR12RD"的偏移地址"0x20",

                   即得到地址。

                */

                uint32_t DMA_PeripheralBaseAddr;

                // DMA存储器地址寄存器;

                // 在此处就是一个数组的地址。

                uint32_t DMA_MemoryBaseAddr;    

                /* 数据传输方向

                   从外设读     "DMA_DIR_PeripheralSRC"

                   从存储器读   "DMA_DIR_PeripheralDST"

                   此处DAC输出,因此是从存储器读,配置为"DMA_DIR_PeripheralDST"。

                */

                uint32_t DMA_DIR;               

                // 数据传输总量(手册规定大小为0~65535 bytes)。

                // 此处的值既是数组大小,32bytes

                uint32_t DMA_BufferSize;        

                /* 外设地址增量模式

                   > 执行外设地址增量模式   "DMA_PeripheralInc_Enable"

                   > 不执行外设地址增量模式 "DMA_PeripheralInc_Disable"

                */

                uint32_t DMA_PeripheralInc;     

                /* 存储器地址增量模式

                   > 执行存储器地址增量模式     "DMA_MemoryInc_Enable"     

                   > 不执行存储器地址增量模式   "DMA_MemoryInc_Disable"

                */

                /* 对于地址增量模式,数据手册如是说:

                   外设和存储器的指针在每次传输后可以有选择地完成自动增量。当设置为增量模式时,

                   下一个要传输的地址将是前一个地址加上增量值,增量值取决与所选的数据宽度为

                   1、2或4。                

                   以一个实际例子解释:

                   若是需要同时采集ADC通道11,通道12的数据到buffer里,则在使能了增量模式后,采集

                   到通道11数据到buffer后并且采集的数据全部完成后,外设地址自动增加,接下来采集

                   到的是通道12的数据。

                   本例程只有一个DAC,所以不需要增量模式。

                */

                uint32_t DMA_MemoryInc;         

                /* 外设数据宽度:

                   > "DMA_PeripheralDataSize_Byte"

                   > "DMA_PeripheralDataSize_HalfWord"

                   > "DMA_PeripheralDataSize_Word"

                   本例程为"DMA_PeripheralDataSize_Word"

                */ 

                uint32_t DMA_PeripheralDataSize;

                /* 存储器数据宽度:

                   > "DMA_MemoryDataSize_Byte"

                   > "DMA_MemoryDataSize_HalfWord"

                   > "DMA_MemoryDataSize_Word"

                */ 

                // 注意:相互传输间的数据传输宽度一定要一致,否则DMA无法正常工作

                uint32_t DMA_MemoryDataSize;    

                /* > 循环模式 "DMA_Mode_Circular"

                   > 正常模式 "DMA_Mode_Normal"

                */ 

                uint32_t DMA_Mode;              

                /* 优先级,前文已述,

                   > "DMA_Priority_VeryHigh"

                   > "DMA_Priority_High"

                   > "DMA_Priority_Medium"

                   > "DMA_Priority_Low"

                   此处的值为"DMA_Priority_High",设置为次高优先级。

                */

                uint32_t DMA_Priority;          

                /* 是否为存储器到存储器模式

                   > "DMA_M2M_Disable"

                   > "DMA_M2M_Enable"

                */

                uint32_t DMA_M2M;               

            }DMA_InitTypeDef;


    最后,初始化完成后,使能对应的DMA通道:

    DMA_Cmd(DMA2_Channel4, ENABLE);


    接着,14通道的DMA就会自动循环的将buffer内的值给DAC,使DAC输出buffer内的值。


至此记录完毕。


关键字:STM32F103  DMA 引用地址:STM32F103之DMA

上一篇:NVIC中断控制 函数实现
下一篇:STM32 NVIC笔记

推荐阅读最新更新时间:2024-03-16 15:27

【STM32】DMA基本原理、寄存器、库函数(2)
05 DMA中断状态寄存器(DMA_ISR) 作用:可以获取DMA传输的状态标志。 注意:此寄存器为只读寄存器,所以在这些位被置位后只能通过其他的操作来清除。 06 DMA中断标志清除寄存器(DMA_IFCR) 作用:通过往寄存器内写1来清除DMA_ISR被置位的位。 DMA通道配置过程 下面是配置DMA通道x的过程(x代表通道号): 在DMA_CPARx寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将是数据传输的源或目标; 在DMA_CMARx寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数据将从这个地址读出或写入这个地址; 在DMA_CNDTRx寄存器中设置要传输的数据量
[单片机]
STM32 DMA发送完成标志位的查询
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma) { uint32_t flag_it = hdma- DmaBaseAddress- ISR; uint32_t source_it = hdma- Instance- CCR; /* Half Transfer Complete Interrupt management ******************************/ if ((RESET != (flag_it & (DMA_FLAG_HT1 hdma- ChannelIndex))) && (RESET != (source_it & DMA_IT
[单片机]
STM32F103 系统各部分时钟设置
STM32F103 系统各部分时钟设置 /******************************************************************************* * 函数名 : RCC_Configuration * 函数描述 : 设置系统各部分时钟 * 输入参数 : 无 * 输出结果 : 无 * 返回值 : 无 *******************************************************************************/ void RCC_Configuration(void) { /* 定义枚举类型变量
[单片机]
STM32CubeMX配置STM32F103-RTC遇到的问题
在rtc.c文件中对RTC进行初始化Cube的BUG: 需要将函数void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle) (这个调用的是LL库中的函数) 替换成函数void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc) 1 配置pinout 2 时钟配置 3 生成工程文件 为了使生成的代码层次分明一些,习惯性我通常是把这个选项勾选上的,不过这次工程代码在RTC初始化上莫名调用了两句引用LL库的语句。 结果是编译不通过,后来把这个选项去掉。代码则编译正常了。 后期试了一下在第一种方式下把出错的那两条语句替换掉后,程序也可
[单片机]
STM32CubeMX配置<font color='red'>STM32F103</font>-RTC遇到的问题
STM32串口工作在DMA模式下有时接收异常
前言 客户反馈在使用STM32F205的串口工作在DMA模式时,有时能够接收数据,有时完全没有数据,但如果换成中断模式来接收又能100%正常收到数据。 一 复现现象 问题背景 与客户沟通,客户使用的是STM32F2标准库V1.1.0,串口波特率为1.408Mbps,不经过串口RS232,直接连接主CPU和从MCU(STM32F205)的串口发送和接收引脚,如下图所示: 尝试重现问题 由于客户使用的是主从架构,实验采用两块STM3220G-EVAL评估板来重现现象。一块用来不间断发送串口数据,另一块采用串口DMA进行接收,直接通过杜邦线连接串口PIN脚并共地,不使用评估板上的RS232收发器。接收端使用STM32F2xx_Std
[单片机]
STM32串口工作在<font color='red'>DMA</font>模式下有时接收异常
STM32F4 HAL库DMA学习
用了一段时间HAL库,不知道是不是用外设固件库时间长一点的原因,个人感觉没有固件库来的直接。看DMA部分看的有点乱,捋一下。 DMA的使用方法及细节直接看官方的手册就可以了,注意的是如果原地址和目的地址的数据长度不一样的话只能使用FIFO模式,直接模式下原地址和目的地址的数据长度必须一致。 主要是简单整理一下使用DMA的初始化过程,以串口发送使用DMA为例: (1) 定义一个外设的句柄,对外设的基本参数、IO、时钟、中断等进行初始化。 UART_HandleTypeDef UART1_Handler; .... HAL_UART_Init(&UART1_Handler); 调用外设的初始
[单片机]
基于STM32F103——DS1302日期时间+串口打印
最近终于又腾出时间写写学习笔记了,其实当时写是最好的,能对出的问题更深刻,现在呜呜呜。忘差不多了。主要的问题就是 STM32不像51 不需要设置输入输出模式,直接操作IO就行,但是STM32 得设置,就是因为对这个不了解 所以卡了一两天。STM32要根据不用应用状态设置不同的模式。 DS1302时钟模块相关介绍 基本介绍 概述 DS1302 可慢速充电实时时钟芯片包含实时时钟/日历和 31 字节的非易失性静态 RAM。它经过一个简单的串行接口与微处理器通信。实时时钟/日历可对秒,分,时,日,周,月,和年进行计数,对于小于31 天的月,月末的日期自动进行调整,还具有闰年校正的功能。时钟可以采用 24 小时格式或带 AM(上午)/
[单片机]
基于<font color='red'>STM32F103</font>——DS1302日期时间+串口打印
STM32的DMA简介
DMA是MCU一个非常重要的部分,它提供了一种直接、高效、快速的方式来传输数据,而不需要CPU的介入,大大提高了MCU的工作效率。 我们先来看一下没有DMA,数据是怎么流动的。 如图所示,红色线表示外设数据的读写,蓝色线表示内存数据的读写。数据必须要先加载到内核,然后再通过内核写入外设或内存,读写操作都需要内核做很多工作,虽然C代码可能就一行语句,但是汇编可不止一条。我们知道在程序执行的过程中这样的数据传输操作非常频繁,如果都这样处理,内核将花费太多时间在搬运数据上,无法集中精力处理更为重要的计算和中断事件,处理速度和效率就会非常的低。 使用DMA后,数据的流动变成了下图所示方式。 数据的传输工作由DMA控制器接管,假
[单片机]
STM32的<font color='red'>DMA</font>简介
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved