STM32 DMA数据转运

DMA简介

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

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

12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)

每个通道都支持软件触发和特定的硬件触发

STM32F103C8T6 DMA资源:DMA1(7个通道)

DMA是数据转运助手,主要用来协助CPU,完成数据转运的工作

存储器映像

STM32中的存储器

计算机系统的五大组成部分:运算器、控制器、存储器、输入设备和输出设备,运算器和控制器合在一起叫做CPU,所以计算机的核心关键部分就是CPU和存储器

存储器:存储器内容与存储器地址

ROM:只读存储器,是一种非易失性、掉电不丢失的存储器

RAM:随机存储器,是一种易失性、掉电丢失的存储器

DMA框图

DMA总线:用于访问各个存储器的DMA总线

内部的多个通道:可以进行独立的数据转运

仲裁器:用于调度各个通道,防止产生冲突

AHB从设备:用于配置DMA参数

DMA请求:用于硬件触发DMA的数据转运

DMA基本结构图

函数介绍

恢复缺省设置

cs 复制代码
void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);

初始化

cs 复制代码
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

结构体初始化

cs 复制代码
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);

使能

cs 复制代码
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

中断输出使能

cs 复制代码
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);

DMA设置当前寄存器,这个函数,就是给传输计数器写数据的

cs 复制代码
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 

DMA获取当前数据寄存器,这个函数就是返回传输计数器的值,如果想看看还剩多少数据没有转运,可以调用这个函数

cs 复制代码
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

这四个函数是获取标志位状态、清除标志位、获取中断状态、清除中断挂起位

cs 复制代码
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
void DMA_ClearFlag(uint32_t DMAy_FLAG);
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
void DMA_ClearITPendingBit(uint32_t DMAy_IT);

代码编写

1.定义结构体变量

bash 复制代码
//定义结构体变量
 DMA_InitTypeDef DMA_InitStructure;//定义DMA结构体变量

2.RCC开启时钟

开启DMA的时钟

bash 复制代码
//开启RCC时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启DMA1的时钟

3.调用DMA_Init

初始化参数包括外设和存储器站点的起始地址、数据宽度、地址是否自增、方向、传输计数器、是否需要自动重装、选择触发源、通道优先级

bash 复制代码
//配置DMA
//外设站点
DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;//外设站点的基地址,这里要写一个32位的地址
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);

4.开关控制

使能DMA_Cmd,给指定的通道使能

bash 复制代码
//使能
DMA_Cmd(DMA1_Channel1,DISABLE);//使能DMA

功能代码

实现数据转运功能,将数组DataA的数据转运到数组DataB中,并实时更新

这里需要定义一个全局变量Size,将初始化里的Size用到功能函数里

cs 复制代码
void MyDMA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);//失能DMA
	DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);//转运数据
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
	//等待转运完成
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
	DMA_ClearFlag(DMA1_FLAG_TC1);//清除标志位
}

整体代码

cs 复制代码
uint16_t MyDMA_Size;

void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{
	MyDMA_Size = Size;
	//定义结构体变量
	 DMA_InitTypeDef DMA_InitStructure;//定义DMA结构体变量
	
	
	//开启RCC时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启DMA1的时钟
	
	
	//配置DMA
	//外设站点
	DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;//外设站点的基地址,这里要写一个32位的地址
	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);//使能DMA
	
	
	
}

void MyDMA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);//失能DMA
	DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);//转运数据
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
	//等待转运完成
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
	DMA_ClearFlag(DMA1_FLAG_TC1);//清除标志位
}

主函数

cs 复制代码
#include "MyDMA.h"
int main(void)
{

	uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04};
	uint8_t DataB[] = {0, 0, 0, 0};
	OLED_Init();
	MyDMA_Init((uint32_t)DataA, (uint32_t)DataB, 4);
	OLED_ShowString(1, 1, "DateA:");
	OLED_ShowString(3, 1, "DataB:");
	OLED_ShowHexNum(1, 8, (uint32_t)DataA, 8);
	OLED_ShowHexNum(3, 8, (uint32_t)DataB, 8);

	while(1)
	{
		DataA[0] ++;
		DataA[1] ++;
		DataA[2] ++;
		DataA[3] ++;
		
		OLED_ShowHexNum(2, 1, DataA[0], 2);
		OLED_ShowHexNum(2, 4, DataA[1], 2);
		OLED_ShowHexNum(2, 7, DataA[2], 2);
		OLED_ShowHexNum(2, 10, DataA[3], 2);
		OLED_ShowHexNum(4, 1, DataB[0], 2);
		OLED_ShowHexNum(4, 4, DataB[1], 2);
		OLED_ShowHexNum(4, 7, DataB[2], 2);
		OLED_ShowHexNum(4, 10, DataB[3], 2);
		
		Delay_ms(1000);
		
		MyDMA_Transfer();
		
		OLED_ShowHexNum(2, 1, DataA[0], 2);
		OLED_ShowHexNum(2, 4, DataA[1], 2);
		OLED_ShowHexNum(2, 7, DataA[2], 2);
		OLED_ShowHexNum(2, 10, DataA[3], 2);
		OLED_ShowHexNum(4, 1, DataB[0], 2);
		OLED_ShowHexNum(4, 4, DataB[1], 2);
		OLED_ShowHexNum(4, 7, DataB[2], 2);
		OLED_ShowHexNum(4, 10, DataB[3], 2);
		Delay_ms(1000);
		
		
	}
	
	
}
相关推荐
define菜鸟#1 小时前
51单片机实验四:键盘检测原理及应用实现
单片机·嵌入式硬件
lin辰傍边的风3 小时前
关于STM32G030和G070未初始化看门狗,程序里面喂狗会导致擦除Flash失败或进入‘HardFault_Handler’
stm32·单片机·嵌入式硬件
冻结的鱼3 小时前
STM32N6 平台如何使用 MCO2 输出 Clock
stm32·单片机·嵌入式硬件
FreakStudio4 小时前
一文速通Python并行计算:09 Python多进程编程-进程之间的数据同步-基于互斥锁、递归锁、信号量、条件变量、事件和屏障
单片机·嵌入式·大学生·面向对象·多进程·技术栈·并行计算·电子diy
Rousson4 小时前
硬件学习笔记--57 MCU相关资源介绍
笔记·单片机·mcu·学习
XINVRY-FPGA5 小时前
XCZU7EG‑L1FFVC1156I 赛灵思XilinxFPGA ZynqUltraScale+ MPSoC EG
c++·嵌入式硬件·阿里云·fpga开发·云计算·fpga·pcb工艺
电子艾号哲8 小时前
Vscode开发STM32标准库
ide·vscode·stm32
双叶8368 小时前
(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)
c语言·数据库·单片机·嵌入式硬件·mongodb·51单片机·nosql
wutianxin09 小时前
硬件测试项之电源纹波的测量和纹波的要求、纹波的抑制
嵌入式硬件·硬件工程
格里姆肖9 小时前
HAL库通过FATFS和SDIO+DMA写入SD卡数据错误
c语言·stm32·单片机