【STM32自学笔记-DMA】

一、DMA介绍

DMA叫做直接存储器存取,DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源。
DMA具有12个独立可配置的通道:其中 DMA1(7个通道), DMA2(5个通道)每个通道都支持软件触发和特定的硬件触发,DMA2 只存在于大容量产品和互联型产品中。

二、DMA功能框图

DMA功能框图主要由3部分组成

第一部分是DMA请求:

        外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA 请求,DMA请求针对于不同的外设所申请的DMA通道也是不一样的,在实际使用中根据DMA请求映像表来申请。DMA 收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。

第二部分是通道:

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

第三部分是仲裁器:

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

三、DMA配置流程

 DMA 数据配置主要分3部。

1.选择DMA的传输方向,传输方向主要有从外设到存储器,从存储器到外设,从存储器到存储器这3种。存储器到外设主要由存储器传输数据给串口。存储器到存储器传输主要指的是FLASH中的值传输到SRAM中。外设到存储器主要由ADC采集数据传输给存储器。

2.选择要传输的长度和单位。其中传输一次长度的最大值为65535个数据。源地址和目标地址的数据宽度必须保持一致。同时还得设置源地址和目标地址是否需要变化。

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

四、存储器(FLASH)传输数据到存储器(SRAM)

DMA_MTM头文件
#ifndef  __DMA_MTM_H
#define  __DMA_MTM_H

#define     SIZE                   5
#define     RCC_AHBPeriph_DMAX   RCC_AHBPeriph_DMA1
#define     DMAy_Channelx        DMA1_Channel1



void DMA_MTM_Init(void);

uint8_t CMP(const uint32_t* A1,uint32_t* A2,uint8_t lenght);

#endif

DMA_MTM源文件
#include "stm32f10x.h"                  
#include "dma_mtm.h"

const uint32_t AddrA[SIZE]={0x11,0x22,0x33,0x44,0x55};//Flash

uint32_t AddrB[SIZE];//SRAM

void DMA_MTM_Init(void)
{
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMAX,ENABLE);
   
   DMA_InitTypeDef DMA_InitStructure;
   DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)AddrA;//外设存储器地址
   DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设存储器数据大小
   DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable;//外设存储器是否递增
   
   DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)AddrB;//存储器地址
   DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//存储器数据大小
   DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器是否递增
   
   DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//工作模式为单次传输
   DMA_InitStructure.DMA_BufferSize=SIZE;//传输的数据大小
   DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//指定外设递增为源地址
   DMA_InitStructure.DMA_M2M=DMA_M2M_Enable;//开启存储器到存储器模式
   DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道的软件优先级
   DMA_Init(DMAy_Channelx,&DMA_InitStructure);
   
   DMA_ClearFlag(DMA1_FLAG_TC1);
   
   DMA_Cmd(DMAy_Channelx,ENABLE);//开启DMA
}

uint8_t CMP(const uint32_t* A1,uint32_t* A2,uint8_t lenght)//循环比较2个数组的值
{
   while(lenght--)
   {
    if(*A1++==*A2++)
    {
     return 1;
    }
    else
    {
    return 0;
    }
   } 
}
mian函数
#include "stm32f10x.h"                  // Device header
#include "led.h"   
#include "DMA_MTM.h"  

extern const uint32_t AddrA[SIZE];//Flash
extern uint32_t AddrB[SIZE];//SRAM

int main(void)
{
   uint8_t flag;
   LED_Init();
   DMA_MTM_Init();
   while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);//等待DMA传输数据完成
   while(1)
	{
      flag=CMP(AddrA,AddrB,5);
      if(flag==1)
      {
      LED_OFF();
      }
      else
      {
      LED_ON();
      }
	}
}

五、存储器(SRAM)传输数据到外设(串口)

DMA_MTP头文件
#ifndef __DMA_MTP_H
#define __DMA_MTP_H

#include "stdio.h"


//RCC
#define   RCC_APB2Periph_GPIOX     RCC_APB2Periph_GPIOA
#define   RCC_APB2Periph_USARTX    RCC_APB2Periph_USART1
//GPIO
#define   USART_GPIO               GPIOA
#define   USART_GPIO_TX            GPIO_Pin_9
#define   USART_GPIO_RX            GPIO_Pin_10
//USART
#define    USARTX                  USART1


//DMA
#define     USART1_ADDR                 (USART1_BASE+0x04)
#define     SIZE                   20
#define     RCC_AHBPeriph_DMAX   RCC_AHBPeriph_DMA1
#define     DMAy_Channelx        DMA1_Channel4



void DMA_MTP_Init(void);

void Serial_Init(void);


void SerialByte(uint16_t Date);

void SerialDoubleByte(uint16_t Date);

void SerialArray(uint16_t* Date,uint16_t lenght);

void SerialString(uint8_t* Str);
#endif
DMA_MTP源文件
#include "stm32f10x.h"     
#include "DMA_MTP.h"
#include <stdarg.h>

extern uint32_t ADDRB[SIZE];

void Serial_Init(void)
{
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOX,ENABLE); 
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USARTX,ENABLE);
     
   GPIO_InitTypeDef GPIO_InitStructure;
   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//选择工作模式为复用推挽输出模式
   GPIO_InitStructure.GPIO_Pin=USART_GPIO_TX;//选择对应的引脚
   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//配置工作频率
   GPIO_Init(USART_GPIO,&GPIO_InitStructure);//初始化结构体
   
   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//选择工作模式为复用推挽输出模式
   GPIO_InitStructure.GPIO_Pin=USART_GPIO_RX;//选择对应的引脚
   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//配置工作频率
   GPIO_Init(USART_GPIO,&GPIO_InitStructure);//初始化结构体
   
   
   USART_InitTypeDef  USART_InitStructure;
   USART_InitStructure.USART_BaudRate=9600;//波特率设置
   USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//不开启硬件流
   USART_InitStructure.USART_Mode=USART_Mode_Tx | USART_Mode_Rx;//串口工作模式选择发送与接收
   USART_InitStructure.USART_Parity=USART_Parity_No;//不设置校验位
   USART_InitStructure.USART_StopBits=USART_StopBits_1;//设置1个停止位
   USART_InitStructure.USART_WordLength=USART_WordLength_8b;//设置数据长度为8位
   USART_Init(USARTX,&USART_InitStructure);
   
//   USART_ITConfig(USARTX,USART_IT_RXNE,ENABLE);//启动串口中断
//   
//   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//   
//   NVIC_InitTypeDef NVIC_InitStructure;
//   NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
//   NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
//   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
//   NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
//   NVIC_Init(&NVIC_InitStructure);

  
   USART_Cmd(USARTX,ENABLE);//启用指定的串口
   
}  

void SerialByte(uint16_t Date)//发送一个字节
{
  USART_SendData(USARTX,Date);
  while(USART_GetFlagStatus(USARTX,USART_FLAG_TXE)==RESET);//判断发送标志位状态
}


void SerialDoubleByte(uint16_t Date)//发送2个字节
{
  uint8_t DateH,DateL; 
  DateH=(Date &0xFF00)>>8;
  DateL=(Date & 0xFF);
  USART_SendData(USARTX,DateH);
  while(USART_GetFlagStatus(USARTX,USART_FLAG_TXE)==RESET);
   
  USART_SendData(USARTX,DateL);
  while(USART_GetFlagStatus(USARTX,USART_FLAG_TXE)==RESET);
}

void SerialArray(uint16_t* Date,uint16_t lenght)//发送数组
{
 uint8_t i;
 for(i=0;i<lenght;i++)
 {
   SerialByte(Date[i]);
 }
}

void SerialString(uint8_t* Str)//发送字符串
{
  while(*Str!='\0')
  {
  SerialByte(*Str++);
  }
}

int fputc(int ch,FILE *f)//重写print
{
  USART_SendData(USARTX,(uint16_t)ch);
  while(USART_GetFlagStatus(USARTX,USART_FLAG_TXE)==RESET);
   return ch;
}

int fgetc(FILE *f)//重写getchar
{
    while(USART_GetFlagStatus(USARTX,USART_FLAG_RXNE)==RESET);
	return (uint16_t)USART_ReceiveData(USARTX);
}

void DMA_MTP_Init(void)
{
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMAX,ENABLE);
   
   DMA_InitTypeDef DMA_InitStructure;
   DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)USART1_ADDR;//外设存储器地址
   DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;//外设存储器数据大小
   DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable ;//外设存储器地址不递增
   
   DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)ADDRB;//存储器地址
   DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word;//存储器数据大小
   DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器地址递增
   
   DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//工作模式为单次传输
   DMA_InitStructure.DMA_BufferSize=SIZE;//传输的数据大小
   DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;//指定外设递增为目的地地址
   DMA_InitStructure.DMA_M2M=DMA_M2M_Disable ;//关闭存储器到存储器模式
   DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道的软件优先级
   DMA_Init(DMAy_Channelx,&DMA_InitStructure);
   
   DMA_ClearFlag(DMA1_FLAG_TC1);//清除传输完成标志位
   
   DMA_Cmd(DMAy_Channelx,ENABLE);//开启DMA
}
main函数
#include "stm32f10x.h"                  // Device header
#include "led.h"   
#include "DMA_MTP.h"  
#include "delay.h"  

uint32_t ADDRB[SIZE];

int main(void)
{
   uint8_t i=0;
   for(i=0;i<SIZE;i++)
   {
    ADDRB[i]='A';
   }
   
   LED_Init();
   Serial_Init();
   DMA_MTP_Init();
   
   USART_DMACmd(USARTX,USART_DMAReq_Tx,ENABLE);//开启串口发送DMA请求
   
   while(1)
	{
    LED_ON();
    Delay(0xFFFFF);  
    LED_OFF();
    Delay(0xFFFFF);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值