实验(八):DMA应用:DMA 存储器到存储器模式/外设模式实验设计

一、实验目的与任务

实验目的:

1. 学习对DMA的使用;

2. 掌握KEIL5的仿真与调试。

任务:

1. 根据要求编写程序,并写出原理性注释;

2. 将检查程序运行的结果,分析一下是否正确;

3. 完成所建工程的验证调试。

二、实验要求

存储器到存储器模式可以实现数据在两个内存的快速拷贝。我们先定义一个静态的源数据,存放在内部 FLASH,然后使用 DMA 传输把源数据拷贝到目标地址上(内部 SRAM),最后对比源数据和目标地址的数据,看看是否传输准确。

DMA 存储器到存储器实验不需要其他硬件要求,只用到 RGB 彩色灯用于指示程序状态。

三、实验内容及步骤

1. 软件设计

①  实验新建文件步骤:

运行Keil 5开发环境。这个实验代码比较简单,主要程序代码都在 main.c 文件中。

②  编程要点:

  • 使能 DMA 时钟;
  • 配置 DMA 数据参数;
  • 使能 DMA,进行传输;
  • 等待传输完成,并对源数据和目标地址数据进行比较。

2. 实验步骤

(1)运行Keil uVision5开发环境,建立一个项目工程。

(2)在工程中添加main.c文件,因需要用到LED灯和OLED显示屏,所以将之前实验写好的LED、OLED文件移植到该工程中,然后在main.c中调用,如图1所示。

图1 移植程序

(3)在工程中添加DMA转换相关文件,因此需要创建MyDMA.c文件,初始化DMA配置,同时在文件内编写功能函数MyDMA_Transfer (),进行数据转换,如图2所示。

图2 编写AD.c代码

(4)编写MyDMA.h程序,方便以后工程文件以移植,使项目工程工具有移植性,如图3所示。

图3 AD.h程序

(5)编写main.c程序,调用MyDMA_Transfe ()函数进行DMA数据转运,当等待转运时,LED0亮,成功转运时,LED1亮,同时OLED显示屏显示转运数据,如图4所示。

图4 main.c程序

运行并调试成功并无错误和警告。

3. 调试验证及结果

(1)将开发板连接到电脑上,使用STLINK将程序烧录到STM32中。

(2)DMA转运处于等待状态时,观察LED灯和OLED数据,如图5所示:

图5 DMA转运处于等待状态

(3)当DMA转运处于转运完成状态时,观察LED灯和OLED数据,如图6所示:

图6 DMA转运处于转运完成状态

四、实验代码分析

(1)DMA初始化程序:

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);
	
}

(2)DMA功能函数程序:

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);
}	

(3)main函数程序:

#include "stm32f10x.h"                  // Device header
#include "Delay.h" 
#include "OLED.h" 
#include "MyDMA.h"
#include "LED.h"

uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04};
uint8_t DataB[] = {0, 0, 0, 0};

int main(){
	OLED_Init();
	LCD_Init();
	MyDMA_Init((uint32_t)DataA, (uint32_t)DataB, 4);//MDA初始化
	
	OLED_ShowString(1, 1, "DataA");
	OLED_ShowString(3, 1, "DataB");
	OLED_ShowHexNum(1, 8, (uint32_t)DataA, 8);
	OLED_ShowHexNum(3, 8, (uint32_t)DataB, 8);
	
	while(1){
		LED0_on();
		LED1_off();
		//显示转换前数据
		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();//DMA数据转运
		LED1_on();
		LED0_off();
		//显示转换后数据
		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);
		
		DataA[0] ++;
		DataA[1] ++;
		DataA[2] ++;
		DataA[3] ++;
	}
}

五、实验总结

本次实验主要是关于DMA存储器到存储器操作的实验。通过使用KEIL5进行仿真和调试,学习了DMA的使用方法,掌握了对DMA的配置和控制,同时也了解了如何在KEIL5中对程序进行仿真和调试。以下是本次实验的实验总结。

在程序编写中,我们首先需要定义源数据和目标地址的存储器地址,然后配置DMA控制器进行传输。具体的步骤如下:

  • 定义源数据和目标地址的存储器地址。在程序中,我们首先需要定义源数据和目标地址的存储器地址。在本次实验中,源数据存放在内部FLASH中,因此需要定义一个指向内部FLASH的指针,将其作为源地址。目标地址为内部SRAM,因此需要定义一个指向内部SRAM的指针,将其作为目标地址。
  • 配置DMA控制器。DMA控制器的配置包括DMA传输模式、传输数据类型、传输数据长度、源地址和目标地址等。在本次实验中,我们选择存储器到存储器模式,因此需要设置传输模式为存储器到存储器模式。传输数据类型为半字,因为源数据和目标地址都是16位的。传输数据长度为静态数据长度,即需要传输的数据的长度。源地址为内部FLASH的地址,目标地址为内部SRAM的地址。在配置完DMA控制器后,需要使能DMA控制器。
  • 运行程序并验证结果。在程序编写完成后,需要进行代码的编译和下载。在下载完成后,需要在KEIL5中进行仿真和调试。在仿真过程中,我们可以通过观察CPU的寄存器值和内存值来检查程序是否运行正确。在调试过程中,我们可以使用单步执行和断点调试等功能来调试程序。在程序运行完成后,需要对比源数据和目标地址数据,以验证传输是否准确。

在本次实验中,我们成功地实现了DMA存储器到存储器操作,并将源数据从内部FLASH传输到了内部SRAM中。通过对比源数据和目标地址数据,可以看出传输结果是准确的。在调试过程中,我们发现有时候程序运行不稳定,原因是DMA传输完成后没有及时关闭DMA控制器,导致程序出现异常。通过增加关闭DMA控制器的代码,可以解决这个问题。

本次实验让我对DMA存储器到存储器操作有了更深入的了解,并学习了在KEIL5中进行程序的仿真和调试。同时也学会了处理一些常见的问题,例如程序的运行不稳定等。通过实验,我发现对于初学者来说,程序的编写和调试并不是一件容易的事情。需要耐心地进行代码的调试和优化,才能使程序运行稳定,并达到预期的效果。

在实验中,我还遇到了一些问题,例如DMA传输时出现了错误,程序运行不稳定等。这些问题主要是由于对DMA控制器的理解不够深入,导致配置不正确。通过查找资料和向老师请教,我逐渐解决了这些问题,并对DMA控制器有了更深入的理解。

总之,本次实验让我掌握了DMA存储器到存储器操作的使用方法,并学会了在KEIL5中进行程序的仿真和调试。同时也让我认识到了程序的编写和调试并不是一件容易的事情,需要不断地学习和实践才能掌握。通过本次实验的经验,我会在以后的学习和工作中更加注重对DMA控制器的理解和应用,以更好地应对类似问题。

源码:实验8

猜你喜欢

转载自blog.csdn.net/qq_61228493/article/details/131211358