STM32笔记——DMA直接存储器存取

目录

一、DMA的作用

二、DMA的框图

三、DMA数据转运基本结构

四、实现SRAM数组之间的数据转运

五、ADC转换和DMA转运数据


一、DMA的作用

  • DMA,全称Direct Memory Access,即直接存储器访问。
  • DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。
  • 当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。
  • DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。

二、DMA的框图

  •  DMA是挂在AHB总线上的外设
  •  STM32F103C8T6 DMA资源:DMA1(7个通道)
  • 提供在外设和存储器之间或者存储器和存储器之间的高速数据传输

三、DMA数据转运基本结构

  •  外设和存储器、存储器之间可以进行数据传输,参数包括:起始地址、数据宽度、地址是否自增、传输方向。
  • 传输计数器:存储传输次数,没传输一次数据,计数器减一,减到0,传输停止。
  • 自动重装器:可自动重装传输计数器的数值。
  • M2M:决定是软件触发还是硬件触发。
  • 开关控制:控制DMA的开启和关闭。

四、实现SRAM数组之间的数据转运

  1.  开启DMA时钟。
  2. 初始化DMA。包括:起始站点的地址、传输的数据宽度、地址是否自增;目标站点的地址、传输的数据宽度、地址是否自增;传输方向;传输计数器的设置;是否自动重装计数器;触发方式和优先级的选择。
  3. 选择DMA通道。
  4. 使能DMA。

程序如下:

#include "stm32f10x.h"                  // Device header

void MyDMA_Init(uint32_t ADDR_A,uint32_t ADDR_B,uint16_t size)
{
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr=ADDR_A;//外设站点(起始站点)
	DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//数据宽度
	DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Enable;//是否自增
	DMA_InitStruct.DMA_MemoryBaseAddr=ADDR_B;//存储器站点(目的点站)
	DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//数据宽度
	DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//是否自增
	DMA_InitStruct.DMA_BufferSize=size;//传输次数
	DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;//从外设站点到存储器站点转运
	DMA_InitStruct.DMA_M2M=DMA_M2M_Enable;//软件触发
	DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;//传输计数器不自动重装
	DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;//优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);
	
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
}

五、ADC转换和DMA转运数据

  1.  选择ADC转换模式:连续转换,扫描模式。
  2. 初始化ADC。
  3. 初始化DMA。
  4. 使能DMA。
  5. 设置DMA触发方式为:ADC1硬件触发。(由附图二可知,ADC1能发送DMA请求,ADC2不能)
  6. 使能ADC。
  7. ADC校准。
  8. 启动AD转换

程序如下:

#include "stm32f10x.h"                  // Device header
uint16_t AD_value[4];
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	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_InitStruct;
	ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;//单次转换
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//数据右对齐
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//无外部触发源
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//ADC1和ADC2独立
	ADC_InitStruct.ADC_NbrOfChannel=4;//通道数目
	ADC_InitStruct.ADC_ScanConvMode=ENABLE;//扫描模式
	ADC_Init(ADC1,&ADC_InitStruct);
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//外设站点(起始站点)
	DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//数据宽度
	DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//是否自增
	DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)AD_value;//存储器站点(目的点站)
	DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//数据宽度
	DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//是否自增
	DMA_InitStruct.DMA_BufferSize=4;//传输次数
	DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;//从外设站点到存储器站点转运
	DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;//硬件触发
	DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;//传输计数器自动重装
	DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;//优先级
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);
	
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
	ADC_DMACmd(ADC1,ENABLE);//ADC硬件触发DMA
	ADC_Cmd(ADC1,ENABLE);
	//校准
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET);
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//开始转换
}

六、附图

6.1 附图1:存储器映像

类型

起始地址

存储器

用途

ROM

0x0800 0000

程序存储器Flash

存储C语言编译后的程序代码

0x1FFF F000

系统存储器

存储BootLoader,用于串口下载

0x1FFF F800

选项字节

存储一些独立于程序代码的配置参数

RAM

0x2000 0000

运行内存SRAM

存储运行过程中的临时变量

0x4000 0000

外设寄存器

存储各个外设的配置参数

0xE000 0000

内核外设寄存器

存储内核各个外设的配置参数

6.2 附图2:DMA1硬件触发请求映像

 6.3 数据宽度与对齐

  • 数据宽度: 源端宽度与目标宽度相等时,全部转运。
  • 源端宽度<目标宽度时,目标地址数据高位补0。
  • 源端宽度>目标宽度时,目标地址数据舍去高位。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值