stm32——DMA简介

本文笔者学习江科大stm32过程中强化学习效果所写,同时希望对大家有所帮助,若有错误恳请指正,谢谢!!!!

DMA(Direct Memory Access)直接存储器存取

功能:DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源。

12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)(注意支持软件触发和特定的硬件触发)

存储器映像地址分配

 DMA框图介绍

1.总线矩阵左边的是主动单元右边的是被动单元(即右边的被左边的控制),其中DCode总线是专门访问FLASH的

2.DMA里面有7个独立的通道(各个通道可以分别设置他们的源地址和目标地址),由仲裁器决定哪一个通道使用DMA总线 (注意:如果DMA和CPU访问的目标相同,DMA会暂停CPU的访问,但会保留一半的总线带宽,使CPU能正常的工作)

3.AHB从设备可以完成DMA的相应配置,从AHB总线可以看出DMA既是主动单元又是被动单元

4.DMA请求连接了可以触发DMA的硬件触发源

注意:FLASH是ROM的一种,是只读存储器,DMA总线只能对他进行读取不能进行写入,寄存器中有些是只读的有些是可读可写的,但是数据寄存器是可以进行读写的。

DMA基本结构图介绍

 1.DMA两大工作站:即外设寄存器和存储器站点

转运的方向:外设到存储器,存储器到外设,存储器到存储器(例如FLASH到SRAM或者SRAM到SRAM)

注意:FLASH是只读的不能进行FLASH到FLASH,SRAM到FLASH的转运操作

2.转运参数的配置(以外设和存储器为例)

外设的起始地址和存储器的起始地址:决定数据从哪来到哪去(注意此处的外设和存储器仅为代号,我们可以在外设写存储器地址,也可以在存储器写外设地址都是可以的)

数据宽度:指定一次转运要按多大的数据宽度来进行(可选字节,字,半字分别对应8位,16位,32位)

地址是否自增:即转运一次结束后源地址和目标地址是否需要自增

3.传输计数器:指定转运次数,每转运一次传输计数器就会-1,当它减到0以后DMA就不会进行数据转运,之前自增的地址就会回到起始地址的位置

4.自动重装器:即当传输计数器减到0以后,就会给它自动恢复初始值

5.触发源:分为硬件触发和软件触发,触发源的选择由M2M(Memory to Memory)数据位控制

软件触发:以最快的速度执行DMA转运,实现传输计数器的尽快清0(注意不能和循环模式使用,否则转运停不下来),一般用于存储器到存储器的转运

硬件触发:触发源可以选择ADC,串口,定时器等等,一般是和外设有关的转运,转运需要一定的时机。

6.开关控制:给DMA_Cmd()函数使能以后DMA就准备就绪可以开始转运了

DMA转运条件

1.开关控制,即DMA_Cmd()函数使能

2.传输计数器必须大于0

3.触发源有触发信号

当计数器为0且没有自动重装时,我们需要修改传输计数器的值就要先使开关控制失能,然后修改计数器的值后再使能开关控制

DMA请求(以DMA1为例)

该图中EN是数据选择器的开关控制位,M2M是软件触发的控制位,当它为1时是软件触发。硬件触发每一个通道对应的请求信号是不同的 。具体选择哪一个触发源是由对应的外设是否开启DMA转运来控制的,由类似于ADC_Cmd的函数决定。

数据宽度与对齐

1.当数据宽度一致时,按位进行读写

2.源端宽度小于目标宽度时,在目标地址写入高位进行扩展后的数据

3. 源端宽度大于目标宽度时,在目标地址保留舍弃高位后的数据

示例

1.数据转运+DMA

示例代码

#include "stm32f10x.h"                  // Device header
uint16_t MyDMA_Size;
void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{
	MyDMA_Size=Size;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr=AddrA;//外设站点的起始地址
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设站点的数据宽度
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable;//外设站点是否自增
	DMA_InitStructure.DMA_MemoryBaseAddr=AddrB;//存储器站点的起始地址
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//存储器站点的数据宽度
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器站点是否自增
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//传输方向
	DMA_InitStructure.DMA_BufferSize=Size;//传输大小,这个参数给多少就传输几次
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//传输模式
	DMA_InitStructure.DMA_M2M=DMA_M2M_Enable;//选择硬件触发还是软件触发
	DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;//优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1,DISABLE);
}
void MyDMA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
	DMA_ClearFlag(DMA1_FLAG_TC1);
}

2.ADC扫描+DMA

示例代码

#include "stm32f10x.h"                  // Device header
uint16_t AD_Value[4];
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHZ/6=12MHZ
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStructure.ADC_NbrOfChannel=4;
	ADC_InitStructure.ADC_ScanConvMode=ENABLE;
	ADC_Init(ADC1,&ADC_InitStructure);
	
	
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//外设站点的起始地址
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//外设站点的数据宽度
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设站点是否自增
	DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)AD_Value;//存储器站点的起始地址
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//存储器站点的数据宽度
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器站点是否自增
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//传输方向
	DMA_InitStructure.DMA_BufferSize=4;//传输大小,这个参数给多少就传输几次
	DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//传输模式
	DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//选择硬件触发还是软件触发
	DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;//优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1,ENABLE);
	ADC_DMACmd(ADC1,ENABLE);
	ADC_Cmd(ADC1,ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET);
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	
}

 

  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值