stm32DMA之存储器向外设传输数据

DMA简介:

直接内存访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率,可以大大节省系统资源;数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是SRAM 或者是FLASH 。DMA 控制器包含了DMA1 和DMA2,其中DMA1 有7 个通道, DMA2 有5 个通道,这里的通道可以理解为传输数据的一种管道。要注意的是DMA2 只存在于大容量的单片机中。

DMA模式数据传输过程:

  1. 如果外设要想通过DMA 来传输数据,必须先给DMA 控制器发送DMA 请求,DMA收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且DMA  控制器收到应答信号之后,就会启动DMA 的传输,直到传输完毕。
  2. DMA 具有12 个独立可编程的通道,其中DMA1 有7 个通道,DMA2 有5 个通道,每 个通道对应不同的外设的DMA  请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。
  3. 当发生多个DMA  通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器来管理。仲裁器管理DMA通道请求分为两个阶段。第一阶段属于软件阶段,可以在 DMA_CCRx 寄存器中设置,有4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的DMA通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高,比如通道1高于通道2。在大容量产品和互联型产品中, DMA1 控制器拥有高于DMA2 控制器的优先级。

DMA数据配置:

DMA传输数据的方向有三个:从外设到存储器,从存储器到外设,从存储 器到存储器。具体的方向DMA_CCR 位4 DIR 配置:0 表示从外设到存储器,1表示从存储器到外设。这里面涉及到的外设地址由DMA_CPAR 配置,存储器地址由DMA_CMAR 配置。

  1. 外设到存储器 :当我们从外设到存储器传输时,以ADC采集为例。DMA外设寄存器的地址对应的就是ADC数据寄存器的地址,DMA存储器的地址就是我们自定义的变量(用来接收存储AD 采集的数据)的地址。设置外设为源地址。
  2. 存储器到外设 :当我们使用从存储器到外设传输时,以串口向电脑端发送数据为例。DMA 外设寄存器的地址对应的就是串口数据寄存器的地址,DMA 存储器的地址就是我们自定义的变量 (相当于一个缓冲区,用来存储通过串口发送到电脑的数据)的地址。设置外设为目标地址。
  3. 存储器到存储器 :当我们使用从存储器到存储器传输时,以内部FLASH  向内部SRAM 复制数据为例。DMA 外设寄存器的地址对应的就是内部FLASH                  (我们这里把内部FALSH 当作一个外设来看)的地址,DMA 存储器的地址就是我们自定义的变量(相当于一个缓冲区,用来存储来自内部FLASH  的数据)的地址。设置外设(即内部FLASH )为源地址。跟上面两个不一样的是,这里需要把DMA_CCR  位 14:MEM2MEM:存储器到存储器模式配置为1,启动M2M 模式。

 bsp_dma_usart.h文件:

#ifndef __DMA_USART1_
#define __DMA_USART1_

#include "stm32f10x.h"
#include "stdio.h"

#define USARTx                 USART1
#define USART_CLK              RCC_APB2Periph_USART1
#define USART_BAUDRATE              115200

#define USART_GPIO_CLK         RCC_APB2Periph_GPIOA
#define USART_TX_GPIO_PORT     GPIOA
#define USART_TX_GPIO_PIN      GPIO_Pin_9
#define USART_RX_GPIO_PORT     GPIOA
#define USART_RX_GPIO_PIN      GPIO_Pin_10

#define USART_TX_DMA_CHANNEL   DMA1_Channel4
#define USART_DR_ADDRESS       (USART1_BASE+0X04)
#define SENDBUFF_SIZE          5000

void USART_Config(void);
void USARTx_DMA_Config(void);
#endif

bsp_dma_usart.c文件:

#include "bsp_dma_usart1.h"
uint8_t SendBuff[SENDBUFF_SIZE];
void USART_Config(void)
{
    GPIO_InitTypeDef  GPIO_InitStrcture;
    USART_InitTypeDef USART_InitStructure;
    RCC_APB2PeriphClockCmd(USART_GPIO_CLK,ENABLE);
    RCC_APB2PeriphClockCmd(USART_CLK,ENABLE);
    GPIO_InitStrcture.GPIO_Pin=USART_TX_GPIO_PIN;
    GPIO_InitStrcture.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStrcture.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(USART_TX_GPIO_PORT,&GPIO_InitStrcture);
    
    GPIO_InitStrcture.GPIO_Pin=USART_RX_GPIO_PIN;
    GPIO_InitStrcture.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    GPIO_Init(USART_RX_GPIO_PORT,&GPIO_InitStrcture);
    
    USART_InitStructure.USART_BaudRate=USART_BAUDRATE;
    USART_InitStructure.USART_WordLength=USART_WordLength_8b;
    USART_InitStructure.USART_StopBits=USART_StopBits_1;
    USART_InitStructure.USART_Parity=USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USARTx, &USART_InitStructure);
    USART_Cmd(USARTx,ENABLE);
}

void USARTx_DMA_Config()
{
    DMA_InitTypeDef  DMA_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    DMA_InitStructure.DMA_PeripheralBaseAddr=USART_DR_ADDRESS;
    DMA_InitStructure.DMA_MemoryBaseAddr=(u32)SendBuff;
    DMA_InitStructure.DMA_BufferSize=SENDBUFF_SIZE;
    DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;//存储器向外设传输数据 
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;    
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//一次 
    //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环    
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    //禁止存储器向存储器传输 
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);    
    DMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
      
}

main.c文件:

#include"stm32f10x.h"
#include"bsp_led.h"
#include"bsp_dma_usart1.h"
extern uint8_t SendBuff[SENDBUFF_SIZE];
static void Delay(__IO u32 nCount); 
int main(void)
{
    uint16_t i;
    USART_Config();
    USARTx_DMA_Config();
    LED_GPIO_Config();
    //uint16_t i;放在这里会报错 
    for(i=0;i<SENDBUFF_SIZE;i++)
  {
    SendBuff[i]     = 'L';
    
  }
  //串口向DMA发送TX请求 
    USART_DMACmd(USARTx, USART_DMAReq_Tx, ENABLE);
    while(1)
    {
        red(ON);
        Delay(0xFFFFF);
        red(OFF);
        green(ON);
        Delay(0xFFFFF);
        green(OFF);
    }
}
static void Delay(__IO uint32_t nCount)     
{
    for(; nCount != 0; nCount--);
}

以上即为有效程序的主体代码。

猜你喜欢

转载自www.cnblogs.com/lzd626/p/9220792.html