关于DMA的配置与用法详解(以下是本人结合工程经验关于自己的理解)

上一节我谈到USART的配置与应用,这节主要来说DMA的一些事宜。关于什么是DMA已经有很多网友的解释,主要就是说DMA可以将所有外设映射的寄存器“连接”起来。就是让以前没有关系的外设或者闪存之间"架起一座沟通的桥"。想要明白还得从配置入手:

上一节我们提到要实现某个功能就要熟悉其配置流程;

首先我们要配置DMA的时钟,STM32之所以强大和功耗低就是因为它可以有选择性的让某个你希望工作的模块在你的配置下按照你的要求去工作。

废话不再多讲,开始配置:

#define USART1_DR_Adress ((u32)0x40013804)//定义外设地址,0x40013804是USART1的数据发送端口地址(即Tx)

void DMA_Configuration(void)
{
 DMA_InitTypeDef DMA_InitStructure;

 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//开启时钟 这是必须的

  //UART1  TX  DMA
 DMA_DeInit(DMA1_Channel4);  //将DMA的通道4寄存器重设为缺省值
 DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Adress; //以定义DMA外设基地址  这就是我把USART1的TX作为我的数据输出端口
 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_Send_buf ; //定义DMA内存基地址USART1_Send_buf是我存储数据的缓存区用于接收串口数据的
 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //外设作为数据传输的目的  这是说把USART1_DR_Adress当做目标
 DMA_InitStructure.DMA_BufferSize = 256; //定义指定DMA通道的DMA缓存的大小,单位为数据单位
 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变  因为是发送地址 所以不能变
 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增  根据数据的变化的
 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据8位  HalfWord—>16位 Word—>32位
 DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位
 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在 模式
 DMA_InitStructure.DMA_Priority = DMA_Priority_High;  //DMA通道4拥有高优先级 DMA_Priority_VeryHigh->非常高优先级  Medium->中等优级Low->低优先级
 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
 DMA_Init(DMA1_Channel4, &DMA_InitStructure);

 DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);  //传输完成中断 开启DMA中断

//DAM_IT_TC  传输完成中断屏蔽   DMA_IT_HT 传输过半中断屏蔽  DMA_IT_TE 传输错误中断屏蔽

(其实说白了就是把两个地址连接起来,这只是个人看法)

}

void DMA1_Channel7_IRQHandler(void) 

 IsU2TxEmpty = 1;
 if(U2SendBufPo != U2SendBufPi)
 {
  U2SendCn = 0; //串口发送计数器清零
  while(U2SendBufPo != U2SendBufPi)
  {
   USART2_Send_buf[U2SendCn] = U2SendBuf[U2SendBufPo];  // 发送数据
   U2SendBufPo = (U2SendBufPo+1)%U2SendBuf_Len; 
   U2SendCn ++;
   if(U2SendCn>=U2FIFO_Len)
   {
    break;
   }
  }        
  DMA1_Channel7->CCR &= 0xfffffffe;  //关闭DMA
  DMA1_Channel7->CMAR = (u32)USART2_Send_buf;  //重置传输地址
  DMA1_Channel7->CNDTR = U2SendCn;     //设置数据传输量
  DMA1_Channel7->CCR |= 0x01;  //开启DMA

  IsU2TxEmpty = 0;
 }
 DMA_ClearITPendingBit(DMA1_IT_TC7);//清中断
}

int U2OutFrameBuf(void )
{
    //这个函数是我实际工程中的,其他的代码已经拿掉,只留下执行动作。就是当主函数调用到这个函数时并且ISU2TxEmpty满足条件时,它才会执行DMA
    if(IsU2TxEmpty == 1)
  {
   // USART1_Printf("U2OutFrameBuf"); 
   DMA1_Channel7_IRQHandler(); 
  }  

 } 
 
    return TRUE;
}

原文地址:https://www.cnblogs.com/zhangjixiao/p/zhangjixiao.html