stm32之DMA详情分析

  一. 对于大容量的STM32芯片有2个DMA控制器,控制器1有7个通道,控制器2有5个通道

  每个通道都可以配置一些外设的地址。



 二. 通道的配置过程:


  1. 首先设置CPARx寄存器和CMARx寄存器。

  通过DMA控制器把一个地址的值复制到另外一个地址,通过DMA控制器自动开启一条通道完成。

  CPARx寄存器存放的是外设的地址

  CMARx寄存器存储的是存储器的地址

  2. 设置数据传输方向,是否循环模式,是不是开启外设和存储器的增量模式,还有数据宽度,是8位,16位还是32位。

  比如设置成存储器的地址增量,那么传输一个数据过去后它的地址自动递增。

  3. 设置要传输的数据量

  4. 设置通道的优先级

  5. 全部设置好后就可以启动DMA通道。

  启动后数据就开始传输,传输的过程中可以读CNDTRx寄存器,可知道当前还剩多少个数据。数据传输到一半或全部传输完毕后有响应的标志位置1,如果开启了中断,可以进入相应的中断程序。

  一。常用的DMA函数


  1.DMA初始化函数

  void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);

//设置要开启的通道,还有一些参数,包括外设基地址,存储器基地址,传输的数据量,增量模式,数据宽度等。

  2.DMA使能函数

  void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState

NewState);

  3.开启相应中断的函数

  void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT,

FunctionalState NewState);

  4.设置CNDTRx和读CNDTRx函数

  void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t

DataNumber);

  uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

  二。常用的外设DMA使能函数

  需要开启外设的DMA使能才能够使用DMA功能。

  这些函数分布在外设各自的头文件中。


  三。DMA初始化函数


  对应下面的代码学习:

  u16 DMA1_MEM_LEN; //保存DMA每次数据传送的长度

  //DMA1的各通道配置

  //这里的传输形式是固定的,这点要根据不同的情况来修改

  //从存储器->外设模式/8位数据宽度/存储器增量模式

  //DMA_CHx:DMA通道CHx

  //cpar:外设地址

  //cmar:存储器地址

  //cndtr:数据传输量

  void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16

cndtr)

  {

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输

  DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值

  DMA1_MEM_LEN=cndtr;

  DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址

  DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设

  DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

//外设地址寄存器不变

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

//数据宽度为8位

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

//数据宽度为8位

  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式

  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输

  DMA_Init(DMA_CHx, &DMA_InitStructure);

//根据DMA_InitStruct中指定的参数初始化DMA的通道

  USART1_Tx_DMA_Channel所标识的寄存器

  }

  四。DMA配置的一般过程


  五。实验

  使用串口1发送DMA

  dma.h文件

  #ifndef __DMA_H

  #define __DMA_H

  #include "sys.h"

  void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16

cndtr);//配置DMA1_CHx

  void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);//使能DMA1_CHx

  #endif

  dma.c文件

  #include "dma.h"

  DMA_InitTypeDef DMA_InitStructure;

  u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度

  //DMA1的各通道配置

  //这里的传输形式是固定的,这点要根据不同的情况来修改

  //从存储器->外设模式/8位数据宽度/存储器增量模式

  //DMA_CHx:DMA通道CHx

  //cpar:外设地址

  //cmar:存储器地址

  //cndtr:数据传输量

  void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16

cndtr)

  {

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输,DMA在AHB总线上

  DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值

  DMA1_MEM_LEN=cndtr;

  DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址

  DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设

  DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

//外设地址寄存器不变

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

//数据宽度为8位

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

//数据宽度为8位

  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式

  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输

  DMA_Init(DMA_CHx, &DMA_InitStructure);

//根据DMA_InitStruct中指定的参数初始化DMA的通道 USART1_Tx_DMA_Channel所标识的寄存器

  }

  //开启一次DMA传输

  void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)

  {

  DMA_Cmd(DMA_CHx, DISABLE ); //关闭USART1 TX DMA1 所指示的通道

  DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小

  DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道

  }

  注:DMA每传输完成一次,要传输的数据量都要自动清零,因此每次开启都要重新设置要传输的数据量。

  主程序中:

  for(i=0;i

  {

  if(t>=j)//加入换行符

  {

  if(mask)

  {

  SendBuff[i]=0x0a;

  t=0;

  }else

  {

  SendBuff[i]=0x0d;

  mask++;

  }

  }else//复制TEXT_TO_SEND语句

  {

  mask=0;

  SendBuff[i]=TEXT_TO_SEND[t];

  t++;

  }

  }

  这一段是 在每个字符串“ALIENTEK WarShip STM32F1 DMA

串口实验”后面添加0x0d和0x0a,也就是自动换行,这样在串口助手中接收到的数据就是ALIENTEK WarShip STM32F1 DMA

串口实验,然后自动换行,另外串口助手sscom程序有bug,不能自动换行,可以换其他串口助手观察。

资料分享便于后期的学习参考

(DMA专题讲解)

http://www.makeru.com.cn/live/1392_1048.html?s=45051

stm32 如何用DMA搬运数据

http://www.makeru.com.cn/live/detail/1484.html?s=45051

(stm32串口应用)

http://www.makeru.com.cn/live/1392_1164.html?s=45051

PWM脉宽调制技术

http://www.makeru.com.cn/live/4034_2146.html?s=45051

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • # STM32之串口DMA接收不定长数据 ## 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,...
    杰杰T_T阅读 3,576评论 0 0
  • DMA简介 DMA(Direct Memory Access)——直接存储器存取,就像其名称一样,DMA的主要作用...
    蜡笔小新没有简书阅读 6,148评论 0 3
  • 姓名:周崇杰 学号:16140120059 专业:机械设计制造及其自动化 转载自:http://blog.csd...
    CJbaby阅读 10,205评论 0 5
  • 姓名:周崇杰 学号:16140120059 专业:机械设计制造及其自动化 转载自:http://blog.csd...
    CJbaby阅读 8,849评论 0 3
  • 在黑夜的无边的原野上 月亮,像 一口井的样子 深邃又晶莹 想从这井里捞起你的目光 你的 千百句温柔的语词 井深过千...
    李榆阅读 1,576评论 6 7

友情链接更多精彩内容