07.DMA传输

1.DMA传输概念

DMA--直接存储器存取

直接内存访问(DMA,Direct Memory Access)是一些计算机总线架构提供的功能,它能使数据从附加设备(如磁盘驱动器)直接发送到计算机主板上的内存,不需要CPU干预。

DMA主要是用于帮助CPU传输数据,DMA可以加快数据传输的速率,提高CPU工作效率。

在所有电子设备,主要有处理器的,我们大家关注的最重要的一方面就是设备运行的流畅度,也就是数据的处理能力。

应用场景: 

1.串口(重要)--使用DMA,可以帮助我们快速的传输数据,保证数据的完整性。DMA中有缓存区的概念,而且DMA可以加快数据传输的速度,避免因为阻塞造成的数据丢失问题。

2.ADC--在有多个通道需要传输的时候,比如 检测电阻 检测光照,检测电压,使用多通道,但是多个通道的数据会汇总到一个DR寄存器中,DMA就可以解决多通道传输的问题,DMA中可以开辟缓存区,用于保存数据。

2.STM32F1系列的单片机中--DMA

直接存储器存取(DMA)作用:    

提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。

无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。两个DMA控制器有12个通道(DMA1有7个通道, DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。

DMA控制器数量:2个

DMA1通道:7个

DMA2通道:5个

优先级:很高、高、中等和低

数据宽度:字节、半字(16bit)、全字(32Bit)

ADC数据宽度--12位,数据寄存器--16位。选择半字

串口--8bit,选择字节

3个事件标志:DMA半传输(传输一半)、 DMA传输完成(数据传输结束)和DMA传输出错。

传输方向:存储器和存储器间的传输、外设和存储器、存储器和外设之间的传输

外设到外设---错误(CPU不需要干预数据传输,但是数据传输的开始和结束都是需要CPU把控的)。

外设和存储器分类:闪存、 SRAM、外设的SRAM(存储器)、 APB1、 APB2和AHB外设(片上外设)均可作为访问的源和目标。

数据传输数量:可编程的数据传输数目:最大为65535

外设资源:

DMA框架:

使用串口的接收功能+DMA:

传输方向:外设---》存储器(内存)

源(外设):串口--数据寄存器(DR)

目标(内存):内存--我们工程师自己定义的存储空间,可以是一个char类型变量,也可以是一个数组

使用ADC采集数据+DMA功能:

传输方向:外设---》存储器(内存)

源(外设):ADC--数据寄存器(DR)

目标(内存):内存--我们工程师自己定义的存储空间,可以是一个short/float/int类型变量,也可以是一个数组。

DMA处理:

需要三个步骤:

DMA_CPARx:外设地址寄存器

DMA_CMARx:存储器地址寄存器

可编程的数据量

接收和发送双方的数据宽度必须保持一致

CCR寄存器中:

指针增量

以串口为例:

接受DMA

源--数据寄存器 USART_DR(我们的数据是8Bit)

目标--缓存区(内存),char rx_buff[100];

当数据接受的时候,rx_buff如何偏移?此时就需要用到指针增量,每次rx_buff需要偏移数据宽度个字节,在我们串口中一次偏移1个字节。

DMA的配置流程:

循环模式:一旦有数据传输,就不停的接收或者发送

单次模式:当设置的传输的数据量减为0,即停止。

DMA中断:

DMA中断触发事件:传输过半、传输完成、传输错误。

3.串口接收DMA配置

DMA1_CH5--USART1_RX

1.打开时钟

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)

2.配置DMA的工作模式

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

DMA_InitTypeDef结构体内容:

typedef struct
{
    u32 DMA_PeripheralBaseAddr;
    u32 DMA_MemoryBaseAddr;
    u32 DMA_DIR;
    u32 DMA_BufferSize;
    u32 DMA_PeripheralInc;
    u32 DMA_MemoryInc;
    u32 DMA_PeripheralDataSize;
    u32 DMA_MemoryDataSize;
    u32 DMA_Mode;
    u32 DMA_Priority;
    u32 DMA_M2M;
} DMA_InitTypeDef;

3.使能DMA控制器

void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

4.接收数据

什么时候接收数据??

FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)
void DMA_ClearFlag(uint32_t DMAy_FLAG);

假如需要使用中断:

void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
void DMA_ClearITPendingBit(uint32_t DMAy_IT);

编写串口的接收DMA代码,必须有串口驱动

#include "my_dma.h"
#include "stdio.h"

char rx_data=0;//接收缓存区(一个字节)


void DMA1_Config(void)
{
DMA_InitTypeDef DMA_InitSources;
    //打开时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    /*
    typedef struct
{
    u32 DMA_PeripheralBaseAddr;
    u32 DMA_MemoryBaseAddr;
    u32 DMA_DIR;
    u32 DMA_BufferSize;
    u32 DMA_PeripheralInc;
    u32 DMA_MemoryInc;
    u32 DMA_PeripheralDataSize;
    u32 DMA_MemoryDataSize;
    u32 DMA_Mode;
    u32 DMA_Priority;
    u32 DMA_M2M;
} DMA_InitTypeDef;
    */
    DMA_InitSources.DMA_PeripheralBaseAddr=(u32)&(USART1->DR);//外设地址
    DMA_InitSources.DMA_MemoryBaseAddr=(u32)&rx_data;//内存地址
    DMA_InitSources.DMA_DIR=DMA_DIR_PeripheralSRC;//外设作为源,内存目标
    DMA_InitSources.DMA_BufferSize=1;//缓存区大小
    DMA_InitSources.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
    DMA_InitSources.DMA_MemoryInc=DMA_MemoryInc_Disable;
    DMA_InitSources.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设数据宽度
    DMA_InitSources.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//内存数据宽度
    DMA_InitSources.DMA_Mode=DMA_Mode_Circular;//循环模式
    DMA_InitSources.DMA_Priority=DMA_Priority_High;//优先级
    DMA_InitSources.DMA_M2M=DMA_M2M_Disable;//不适用内存到内存。
    //配置DMA的工作模式
    DMA_Init(DMA1_Channel5,&DMA_InitSources);
    //使能
    DMA_Cmd(DMA1_Channel5,ENABLE);
    //串口接收DMA使能
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
}

void Get_Data(void)
{
    //判断DMA是否接收完成
    if(DMA_GetFlagStatus(DMA1_FLAG_TC5))
    {
        DMA_ClearFlag(DMA1_FLAG_TC5);
        printf("USART1_RX_DMA--->%x\r\n",rx_data);
    }
}

 
 .h文件
 #ifndef _MY_DMA_H_
#define _MY_DMA_H_

#include "stm32f10x.h" //stm32f1头文件
void DMA1_Config(void);
void Get_Data(void);
#endif

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码是用于配置和启用DMA1通道1的功能,实现ADC采集数据的自动传输。 具体的意思如下: 1. DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; 配置DMA传输的外设地址为ADC1的数据寄存器地址。 2. DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue; 配置DMA传输的存储器地址为ADC_ConvertedValue变量的地址,即将采集到的数据存储到ADC_ConvertedValue数组中。 3. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 配置DMA传输方向为从外设到存储器。 4. DMA_InitStructure.DMA_BufferSize = 2; 配置DMA传输数据的数量为2,即每次传输两个半字(16位)的数据。 5. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 配置DMA传输过程中外设地址不自增。 6. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 配置DMA传输过程中存储器地址自增。 7. DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; 配置DMA传输数据宽度为半字(16位)。 8. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 配置DMA传输数据宽度为半字(16位)。 9. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 配置DMA传输模式为循环传输。 10. DMA_InitStructure.DMA_Priority = DMA_Priority_High; 配置DMA传输的优先级为高。 11. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 配置DMA传输模式为非存储器到存储器传输。 12. DMA_Init(DMA1_Channel1, &DMA_InitStructure); 将以上配置应用到DMA1通道1上。 13. DMA_Cmd(DMA1_Channel1, ENABLE); 启用DMA1通道1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值