DMA(直接存储器访问)

DMA全称Direct Memory Access,即直接存储器访问。用来提供外设和存储器之间,或者存储器和存储器之间的高速数据传输。无须CPU控制,数据可以通过DMA传输,它通过硬件为RAM与I/O设备之间开辟一条直接传送数据的通道,这节省CPU的资源,使CPU效率提高。

一、STM32 DMA主要特性

  1. 12个独立的可配置的通道(请求): DMA1有7个通道, DMA2有5个通道。
  2. 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
  3. 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推) 。
  4. 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
  5. 支持循环的缓冲器管理。
  6. 每个通道都有3个事件标志(DMA半传输、 DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。
  7. 存储器和存储器间的传输。
  8. 外设和存储器、存储器和外设之间的传输。
  9. 闪存、 SRAM、外设的SRAM、 APB1、 APB2和AHB外设均可作为访问的源和目标。
  10. 可编程的数据传输数目:最大为65535

二、DMA控制器框图

三、DMA通道请求映像

DMA1控制器从外设(TIMx[x=1、 2、 3、 4]、 ADC1、 SPI1、 SPI/I2S2、 I2Cx[x=1、 2]和USARTx[x=1、 2、 3])产生的7个请求,通过逻辑或输入到DMA1控制器,这意味着同时只能有一个请求有效。外设的DMA请求,可以通过设置相应外设寄存器中的控制位,被独立地开启或关闭。

DMA2控制器从外设(TIMx[5、 6、 7、 8]、 ADC3、 SPI/I2S3、 UART4、 DAC通道1、 2和SDIO)产生的5个请求,经逻辑或输入到DMA2控制器,这意味着同时只能有一个请求有效。外设的DMA请求,可以通过设置相应外设寄存器中的DMA控制位,被独立地开启或关闭

注意:
1. DMA2控制器及相关请求仅存在于大容量产品和互联型产品中。
2. ADC3、SDIO和TIM8的DMA请求只在大容量的产品中存在。

四、DMA仲裁器

仲裁器根据通道请求的优先级来启动外设/存储器的访问。
优先权管理分2个阶段:

● 软件:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级:
[1].最高优先级
[2].高优先级
[3].中等优先级
[4].低优先级

● 硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优
先权。举个例子,通道2优先于通道4

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

五、DMA中断

每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。为应用的灵活性考虑,通过设置寄存器的不同位来打开这些中断。

注意: 在大容量产品中, DMA2通道4和DMA2通道5的中断被映射在同一个中断向量上。在互联型产品中, DMA2通道4和DMA2通道5的中断分别有独立的中断向量。所有其他的DMA通道都有自己的中断向量。

六、DMA核心寄存器简述




七、DMA通道配置步骤

【1】. 设置外设地址

设置外设地址,通过寄存器DMA_CPARx设置,只需在这个寄存器里面写入外设地址值。

【2】. 设置存储器地址

设置存储器基地址,通过寄存器DMA_CMARx设置,只需在这个寄存器里面写入存储器基地址值。假设把数组sDMA作为存储器,那么在该寄存器写入&sDMA 就行。

【3】. 设置传输数据量

通过寄存器DMA_CNDTRx设置DMA通道数据传输量。该寄存器的数值将在DMA启动后自减,每次DMA传输,都重新向该寄存器写入要传输的数据量。

【4】. 设置通道配置信息

配置信息通过寄存器DMA_CCRx设置。设置存储器和外设传输的数据位宽,设置存储器到外设的存储器地址增量模式,传输的通道优先级等等。

【5】. 使能DMA通道启动传输

完成以上配置后,使能DMA_CCRx最低位开启DMA传输。

八、例程代码

【1】主函数

/******************************************************************************************************************************
本例程功能简述:
1.DMA通道CH4传输,存储器 --> 外设(USART1)
2.Key Up传输19200Byte,Key Down传输15360Byte
4.TFT显示已传输数据、剩余数据、完成比例
5.传输基数据为ASCII为0x20到0x7E
******************************************************************************************************************************/
int main(void)
{vSystem_Init();vSendData_DealWith();while(1){vKeyBoard_Service_Handle();}
}
/******************************************************************************************************************************
*函数名: vSystem_Init
*描  述: 系统初始化
******************************************************************************************************************************/
static void vSystem_Init(void)
{SystemInit();vSysTick_Init();                      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//Priority Grouping 4 bitvLED_GPIO_Config();vKEY_GPIO_Config();vUART_Init();                     vTFT_Init();    vDMA_Init();vTIM_Init();#if ( USE_SEGGER_RTT_ENABLE > 0 )//Use segger rtt enableSEGGER_RTT_Init();SEGGER_RTT_printf(0, "STM32F103ZET6 Start Running......\r\n");#endif#if ( USE_KEIL_MACRO_INFO_ENBALE > 0 )//Use Keil macro information enable vKeil_Macro_Information();#endif
}
/******************************************************************************************************************************
*函数名: vSendData_DealWith
*描  述:发送数据处理
******************************************************************************************************************************/
static void vSendData_DealWith(void)
{u8 mDat[ASCII_MAX] = {0};u8 i = 0;for(i=0; i<ASCII_MAX; i++)mDat[i] = 0x20 + i;mDat[94] = 0x0D;mDat[95] = 0x0A;for(i=0; i<SDAT_LEN; i++)memcpy(&sDMA[ASCII_MAX * i], mDat, ASCII_MAX);
}
/********************************************************************************************
*函数名:vKeyBoard_Service_Handle
*描  述:键盘服务处理
********************************************************************************************/
void vKeyBoard_Service_Handle(void)
{float remDat = 0;//remaining datau16   talDat = 0;//total dataif(KeyStr.Modes == Idle)return;switch(KeyStr.Modes){case KeyUpClick :{LED2_SET();talDat = ASCII_MAX * SDAT_LEN;}break;case KeyDownClick :{  LED3_SET();talDat = ASCII_MAX * 160;}break;case KeyLeftClick :{    LED5_CPL();}break;case KeyRightClick :{LED5_CPL();}break;default : break;}if(talDat){vDMA_Transmit_Enable(DMA1_Channel4, talDat);while(1){if(DMA_GetFlagStatus(DMA1_FLAG_TC4) != RESET)//Get DMA Status Flag(transfer complete){DMA_ClearFlag(DMA1_FLAG_TC4);//Clears DMA flags(transfer complete)break; }remDat = DMA_GetCurrDataCounter(DMA1_Channel4);//Current remaining datavTFT_Show_Number(130, 120, 16, (talDat - remDat), 5, GREEN, BLUE);//Finish DatavTFT_Show_Number(130, 140, 16, remDat, 5, GREEN, BLUE);//Residue DatavTFT_Show_Number(130, 160, 16, ((1-(remDat/talDat)) * 100), 3, GREEN, BLUE);//Percentage}remDat = DMA_GetCurrDataCounter(DMA1_Channel4);vTFT_Show_Number(130, 120, 16, (talDat - remDat), 5, GREEN, BLUE);vTFT_Show_Number(130, 140, 16, remDat, 5, GREEN, BLUE);vTFT_Show_Number(130, 160, 16, ((1-(remDat/talDat)) * 100), 3, GREEN, BLUE);   if(KeyStr.Modes == KeyUpClick)LED2_CLR();else if(KeyStr.Modes == KeyDownClick)LED3_CLR();}KeyStr.Modes = Idle;
}

【2】DMA配置

/******************************************************************************************************************************
*函数名: vDMA_Config
*描  述:DMA配置
*输  入: chx      : DAM传输通道 perAddr  : 外设基地址memAddr  : 存储器基地址
******************************************************************************************************************************/
static void vDMA_Config(DMA_Channel_TypeDef*  chx, u32 perAddr, u32 memAddr)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);   //Enable DMA1 clock DMA_DeInit(chx);                                    //DMA Channel registers resetDMA_InitStructure.DMA_PeripheralBaseAddr = perAddr;                       //Peripheral base addressDMA_InitStructure.DMA_MemoryBaseAddr    = memAddr;                        //Memory base addressDMA_InitStructure.DMA_DIR               = DMA_DIR_PeripheralDST;      //DMA transmit directionDMA_InitStructure.DMA_BufferSize         = 0;                          //MDA Channel buffer sizeDMA_InitStructure.DMA_PeripheralInc     = DMA_PeripheralInc_Disable;  //Peripheral address is incrementedDMA_InitStructure.DMA_MemoryInc       = DMA_MemoryInc_Enable;       //Memory address is incrementedDMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //Peripheral data widthDMA_InitStructure.DMA_MemoryDataSize      = DMA_MemoryDataSize_Byte;        //Memory data widthDMA_InitStructure.DMA_Mode                = DMA_Mode_Normal;                //DMAy Channe modeDMA_InitStructure.DMA_Priority             = DMA_Priority_High;          //MDA Channel priorityDMA_InitStructure.DMA_M2M                  = DMA_M2M_Disable;                //Memory-to-memory transferDMA_Init(chx, &DMA_InitStructure);                                       //DMA init
}

【3】DMA传输使能

/******************************************************************************************************************************
*函数名: vDMA_Transmit_Enable
*描  述:DMA传输使能
*输  入: chx      : DAM传输通道 dataSize : 传输字节数
******************************************************************************************************************************/
void vDMA_Transmit_Enable(DMA_Channel_TypeDef*  chx, u16 dataSize)
{USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//Enable USART1 DMADMA_Cmd(chx, DISABLE);                    //DMA disableDMA_SetCurrDataCounter(chx, dataSize); //Current DMA Channel transfer CounterDMA_Cmd(chx, ENABLE);                 //DMA enable
}

【4】DMA初始化

/******************************************************************************************************************************
函数名: vDMA_Init
描  述:DMA初始化
******************************************************************************************************************************/
u8 sDMA[ASCII_MAX * SDAT_LEN] = {0};
void vDMA_Init(void)
{vDMA_Config(DMA1_Channel4, ((u32)(&USART1->DR)), (u32)sDMA);
}

【5】DMA头文件

#define SDAT_LEN                                         200
#define ASCII_MAX                                           96void vDMA_Transmit_Enable(DMA_Channel_TypeDef*  chx, u16 dataSize);   //vDMA_Transmit_Enable
void vDMA_Init(void);                                               //vDMA_Initextern u8 sDMA[ASCII_MAX * SDAT_LEN];

STM32学习——直接存储器访问(DMA)相关推荐

  1. STM32学习:通过DMA读取ADC规则通道多通道转换数据

    1.STM32的DMA简介 直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作. ...

  2. 微雪的stm32学习资料

    http://www.waveshare.net/wiki/Main_Page里面有很多资料 STM32开发软件 目录 编译软件 Keil MDK STM32CubeMX 下载软件 STM32 ISP ...

  3. 《STM32从零开始学习历程》——DMA直接存储区访问实验例程

    <STM32从零开始学习历程>@EnzoReventon DMA-直接存储区访问实验例程 本章节为DMA直接存储区访问的实验例程讲解,以"正点原子"的例程为基础进行讲解 ...

  4. STM32学习笔记——DMA控制器(向原子哥学习)

    一.DMA简介 DMA,全称为:Direct Memory Access,即直接存储器访问,DMA 用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.当 CPU 初始化这个传输动作,传输 ...

  5. 【DSP】直接存储器访问(DMA)控制器——TMS320VC5509A(下篇)

    之前的上篇和中篇是对直接存储器访问(DMA)的一个大体上的讲解,下篇中主要是对一个DMA具体的实例进行讲解. 实例主要是两个文件:dma.c和vectors.s55. dma.c文件 /** Copy ...

  6. DSP原理学习笔记--第七章--增强直接存储器访问(EDMA)

    第七章 增强直接存储器访问(EDMA) 第七章 增强直接存储器访问(EDMA) DMA 数据传输 EDMA的特点 EDMA控制器的结构 EDMA传输中的术语 EDMA传输方式 同步事件 EDMA通道与 ...

  7. STM32学习心得十八:通用定时器基本原理及相关实验代码解读

    记录一下,方便以后翻阅~ 主要内容: 1) 三种定时器分类及区别: 2) 通用定时器特点: 3) 通用定时器工作过程: 4) 实验一:定时器中断实验补充知识及部代码解读: 6) 实验二:定时器PWM输 ...

  8. STM32理论 —— DAC、DMA

    文章目录 1. DAC 1.1 内置DAC 1.2 MCP4725 1.3 可编程信号发生器 - AD9833 1.3.1 控制寄存器 1.3.2 频率和相位寄存器 1.3.3 输出引脚 1.3.4 ...

  9. STM32学习笔记(三)丨中断系统丨EXTI外部中断(对射式红外传感器计次、旋转编码器计次)

    本篇文章包含的内容 一.中断系统 1.1 中断的定义 1.2 中断优先级 1.3 中断的嵌套 1.4 STM32中的中断系统 1.4.1 STM32的中断资源 1.4.2 嵌套中断向量控制器 NVIC ...

  10. STM32学习+步科组态屏

    目录 KEIL5下载.安装... 3 第一步,官网下载https://www.keil.com/. 3 第二步,下载keil5. 3 第三步,下载完成安装keil5. 4 第四步,下载安装stm32固 ...

最新文章

  1. Python去除字符串前后空格
  2. linux 脚本continue,shell中的break和continue
  3. java定义商品金额_老大说:谁要再用double定义商品金额,就自己收拾东西走
  4. 多语言持久性:带有MongoDB和Derby的EclipseLink
  5. LeetCode(#1)————Two Sum
  6. Scala学习笔记(1)-环境搭建
  7. 学生渐进片add如何给_渐进片的那些事「5」——验配之前的问诊
  8. hdfs客户端的学习理解
  9. PHP集锦点,php 函数集锦
  10. 如何跨越线程调用窗体控件?(3)
  11. 编辑器 UEditor 百度富文本web编辑器
  12. python实训目的意义_Python实训三
  13. 手机百度浏览器怎么设置繁体字_嫌百度太花哨?来看看如何让百度变得极简
  14. 网站关键词排行优化技巧
  15. 手欠,给DELL R720加硬盘
  16. Mac 卸载/安装 maven
  17. 4月27日—5月1日四年级课程表
  18. IT审计 独立于IT管理的监督过程(zt)
  19. [转]漫画:混乱的标记语言XHTML2/HTML5(附中文版翻译)
  20. qq空间开场动画代码

热门文章

  1. cart算法 java实现_Java Cart类代码示例
  2. 如何写好一个打动投资人的计划书
  3. office产品密钥如何找回
  4. 美国人物传记电影:巴顿将军
  5. k8s-kubeadm安装(五 网络插件calico)
  6. 水仙花数有哪些?要100到1000之间所有的水仙花数
  7. 关于QQ邮箱登录提示一键登录解决方案
  8. Flink No operators defined in streaming topology. Cannot execute.
  9. 技术文摘11 fang money 技术 资料
  10. NAT alg 和 ASPF