0x09 DMA

本文的大部分内容来自B站up主 江协科技, 此文只供本人学习记录用途, 侵删

一、DMA

  • DMA(Direct Memory Access)直接存储器存取
  • DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
  • DMA完成的功能就是把外设(可以是任何地址)里的东西搬到另一个你想要的地址
  • 12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)每个通道都支持软件触发和特定的硬件触发
  • STM32F103C8T6 DMA资源:DMA1(7个通道)

二、存储器映像

DMA的作用就是把指定地址里的数据搬运到另一处地址

可以把他当成赋值, 但这次赋值可以软件触发, 也可以硬件触发, 当某个标志位被置位时自动运行的赋值, 这就大大节省了软件资源(不用在事件结束后进中断)

image-20231102082204579

三、内存搬运示例

配置框图

image-20231102083709337

image-20231102083804231

以下代码实现了存储器到存储器的搬运, 使用软件手动搬运

void MyDMA_Init(uint8_t* arr1,uint8_t* arr2,uint8_t	Size){
	RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1EN,ENABLE);//开启时钟
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)arr2; //目标地址
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)arr1; //外设地址
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; //目标数据宽度
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte; //外设目标宽度
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//指定目标地址是否自增
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable;//指定外设地址是否自增
	                 
	DMA_InitStructure.DMA_BufferSize=Size;  //传输多少个数据
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//设置外设站点为源端(也可以是目的地)
	DMA_InitStructure.DMA_M2M=DMA_M2M_Enable;  //使用软件触发(存储器到存储器)
     //指定传输计数器不自动重装(软件触发不能自动重装)
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority=DMA_Priority_High;//指定转运优先级
	
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1,DISABLE);
}

//手动搬运
void MyDMA_Transfer(uint8_t	Size){
	DMA_Cmd(DMA1_Channel1,DISABLE);//使能DMA
	DMA_SetCurrDataCounter(DMA1_Channel1, Size); //重新装填DMA
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
	
    //等待转运完成
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
	DMA_ClearFlag(DMA1_FLAG_TC1);
}

四、ADC+DMA多通道

image-20231102084510240

//自己开一个数组放数据
void AD_Init(uint16_t *ADvelue){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1EN,ENABLE);//开启时钟
	RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC时钟分频
	
	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_Pin_3;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    //PA0(ADC12_IN0) PA1(ADC12_IN1) PA2(ADC12_IN2) PA3(ADC12_IN3)模拟输入 
	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规则组通道配置
    	ADC1 没啥好说
    	ADC_Channel_0 选择通道0 
    	1 代表这个通道在规则组的序列1
        ADC_SampleTime_55Cycles5 采样时间为55.5个CLK周期
    */
    
	ADC_InitTypeDef ADC_InitStructure;
	ADC_StructInit(&ADC_InitStructure);//先初始化用不到的参数
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None ;
	ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;
	ADC_InitStructure.ADC_ScanConvMode=ENABLE;
	ADC_InitStructure.ADC_NbrOfChannel=4;
	ADC_Init(ADC1, &ADC_InitStructure);
	/*
		ADC_Mode_Independent: ADC为独立模式, 其他参数都为双ADC
		ADC_DataAlign_Right: 数据右对齐
		ADC_ExternalTrigConv_None: 关闭外部触发, 这里用软件触发
		ADC_ContinuousConvMode = ENABLE 开启连续模式
		ADC_ScanConvMode = ENABLE 开启扫描模式
		ADC_NbrOfChannel=4  规则组通道的数目
	*/
    DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)ADvelue;//目标数组的地址
    //外设地址(ADC的数据寄存器)
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;
    //数据宽度:半字(16Bit)
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
    //目标地址自增, 外设地址固定
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	               
	DMA_InitStructure.DMA_BufferSize=4; //搬运次数: 4(4个模拟输入)
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设地址为源地址
	DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//关闭软件开启
	DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//开启循环模式
	DMA_InitStructure.DMA_Priority=DMA_Priority_High;//设置搬运优先级
	
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
    ADC_DMACmd(ADC1,ENABLE);//使能DMA搬运ADC
	ADC_Cmd(ADC1,ENABLE);//使能ADC
	
    //启动校准
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET);
    //手动开启ADC搬运
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值