8 DMA直接存储器存取

江科大stm32 p8 DMA直接存储器存取

DMA简介

  • 可以直接访问STM32内部的存储器,包括运行内存SRAM,程序存储器Flash和寄存器等等

STM32中的存储器

  • ROM:只读存储器,非易失性,掉电不丢失
    • 程序存储器,主闪存Flash
    • 系统存储器和选项字节的存储介质也是Flash,但是我们一般说的Flash指的是主闪存,而不是这两块区域
  • RAM:随机存储器,易失性,掉电丢失
    • 外设寄存器介质也是SRAM,但是我们一般把运行内存叫SRAM
    • 内核外设就是NVIC和SysTick

DMA结构框图

DMA访问Flash只可读不可写

简化结构图

  • DMA的转运可以从外设到存储器也可以反过来,也可以从存储器到存储器 ,但不可以写Flash
  • M2M控制触发模式:
    • 置1软件触发,一般是存储器到存储器的转运。以最快的速度将传输计数器清0,不能和自动重装一起用,否则DMA会停不下来
    • 置0硬件触发,触发源可以选择ADC、串口、定时器等等,一般都是和外设有关的转运
  • 写传输计数器时,必须要先关闭DMA
  • 复制转运,原数据不会消失

DMA请求映像

  • 每个通道都有特定触发源
    • 选择哪个触发源取决于开起了哪个外设的DMA输出,比如ADC_DMACmd

数据对齐

例子

  • 外设地址:DataA首地址
  • 存储器地址:DataB首地址
  • 数据宽度:8    
  • 地址自增:双方地址都要自增
  • 方向:DataA到DataB
  • 传输计数器:7
  • 自动重装:失能
  • 触发选择M2M:1软件触发
  • 使能DMA:DMA_Cmd
#include "stm32f10x.h"                  // Device header

uint8_t MyDMA_Size;

void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t size)
{
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	MyDMA_Size = size;
	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_PeripheralDataSize_Byte;			//存储器数据宽度
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;						//存储器地址自增
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;							//方向
	DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;									//存储器到存储器,软件触发
	DMA_InitStructure.DMA_BufferSize = size;									//传输计数器
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;								//操作模式,是否自动重装,自动重装和软件触发不能同时启用
	DMA_InitStructure.DMA_Priority = DMA_Priority_Low;							//优先级
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1, ENABLE);
}

void MyDMA_Transfer()
{
	DMA_Cmd(DMA1_Channel1, DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);				//先失能再更改传输计数器
	DMA_Cmd(DMA1_Channel1, ENABLE);

	while(RESET == DMA_GetFlagStatus(DMA1_FLAG_TC1));				//等待转运完成
	DMA_ClearFlag(DMA1_FLAG_TC1);									//清除标志位
}

  • 外设地址:ADC_DR
  • 存储器地址:ADValue首地址
  • 数据宽度:16     32bit处理器,它的字是32bit的。半字是16bit;
  • 地址自增:外设地址自增,存储器地址自增
  • 方向:外设到存储器
  • 传输计数器:7
  • 自动重装:取决于ADC是连续扫描还是单次扫描
  • 触发选择M2M:0硬件触发,ADC单个通道转换完成时,ADC在这种情况下没有标志位,但是有DMA请求,可以触发硬件请求
  • 使能DMA:DMA_Cmd

#include "stm32f10x.h"                  // Device header

uint16_t AD_Value[3];

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);	//6分频		72M ADC最高14M 只能选6或8分频
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);	// (多菜单)通道0 放到序列1
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;					// 连续模式启用,只需触发一次,就会一直转换
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;						// 扫描模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;					// 独立模式还是双AD模式
	ADC_InitStructure.ADC_NbrOfChannel = 3;								// 规则组转换列表里通道的数目
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 不使用外部触发源,即软件触发
	ADC_Init(ADC1, &ADC_InitStructure);
	
	//DMA转运数据防止覆盖
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;				// (0x4001244C)
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	// 只要DR寄存器低16位的数据
	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_M2M = DMA_M2M_Disable;								// 不使用软件触发
	DMA_InitStructure.DMA_BufferSize = 3;										// 传输计数器,3个ADC通道,传输3次
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;								// 操作模式,是否自动重装,否则要手动重装(重新给传输计数器赋值)
	DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
	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));
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);				// 软件启动ADC转换触发
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值