本帖最后由 kkhkbb 于 2018-4-3 21:18 编辑
一、概述:
1、DMA简介
DMA的英文拼写是"Direct Memory Access",汉语的意思就是直接内存访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率,可以大大节省系统资源。DMA模式又可以分为Single-Word DMA(单字节DMA)和Multi-Word DMA(多字节DMA)两种。
2、 DMA工作原理
DMA 允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。
DMA 传输主要地将一个内存区从一个装置复制到另外一个。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。所以,DMA传输对于高效能嵌入式系统算法和网络是很重要的。
3、DMA类别
按键主要有两种类型:单字节DMA、多字节DMA。
单字节DMA:一次传送一个字节,效率较低,但它会保证在两次DMA传送之间,CPU有机会获得总线控制权,执行一次CPU总线周期。
多字节DMA:一次请求传送一个数据块,效率高,但在整个DMA传送期间,CPU长时间无法控制总线(无法响应其他DMA请求,无法处理其他中断等)。 二、实验原理: DMA(直接存储器访问)传输不需要占用CPU,可以在存储器至实现高速的数据传输。本实验采用DMA2控制器的数据流0,选用通道0进行数据传输。通过LED的颜色来判断传输是否成功。 三、源代码: 1.主函数及DMA设置 /*
* Name : main
* Description : ---
* Author : ysloveivy.
*
* History
* --------------------
* Rev : 0.00
* Date : 11/21/2015
*
* create.
* --------------------
*/
int main(void)
{
int i,k;
DMA_InitTypeDef DMA_InitStructure;
led.initialize();
dma.initialize();
//测试DMA,测试成功蓝灯闪烁,测试失败,红灯闪烁
DMA_InitStructure.DMA_Channel = DMA_Channel_0; //选择通道0
DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned long int)src_buffer; //DMA外设基地址
DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned long int)dst_buffer; //DMA存储器地址
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory; //方向为存储器到存储器
DMA_InitStructure.DMA_BufferSize = (unsigned long
int)BUFFER_SIZE; //数据传输量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设增量模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //设置外设数据宽度
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //设置存储器数据宽度
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //运行模式为普通模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //优先级级别为高
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //FIFO模式禁止
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; //FIFO阈值
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA2_Stream0
while(DMA_GetCmdStatus(DMA2_Stream0) != DISABLE);
for(i = 0;i < BUFFER_SIZE;i++){
if(dst_buffer[i] != src_buffer[i]){
//测试失败
while(1){
for(k = 0;k < 10000000;k++);
LED_RED_ON;
for(k = 0;k < 10000000;k++);
LED_RED_OFF;
}
}
}
//测试成功
while(1){
for(k = 0;k < 10000000;k++);
LED_BLUE_ON;
for(k = 0;k < 10000000;k++);
LED_BLUE_OFF;
}
}
2.DMA初始化函数 /*
* Name : initialize
* Description : ---
* Author : ysloveivy.
*
* History
* --------------------
* Rev : 0.00
* Date : 11/29/2015
*
* create.
* --------------------
*/
static int initialize(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); //使能DMA2时钟
DMA_DeInit(DMA2_Stream0); //配置DMA2
while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE) //等待DMA可配置
{
}
return 0;
}
3、小知识 在DMA的设置中我们遇到了关于DMA设置的结构体,我们通过配置其相关参数,以实现我们想要的功能,其解释如下: typedef struct
{
uint32_t DMA_Channel; //选择通道
uint32_t DMA_PeripheralBaseAddr; //DMA外设基地址
uint32_t DMA_Memory0BaseAddr; //DMA存储器地址
uint32_t DMA_DIR; //DMA传输方向
uint32_t DMA_BufferSize; //数据传输量
uint32_t DMA_PeripheralInc; //外设增量模式选择
uint32_t DMA_MemoryInc; //存储器增量模式
uint32_t DMA_PeripheralDataSize; //设置外设数据宽度
uint32_t DMA_MemoryDataSize; //设置存储器数据宽度
uint32_t DMA_Mode; //运行模式选择
uint32_t DMA_Priority; //优先级选择
uint32_t DMA_FIFOMode; //FIFO模式选择
uint32_t DMA_FIFOThreshold; //FIFO阀值
uint32_t DMA_MemoryBurst; //存储器突发单次传输
uint32_t DMA_PeripheralBurst; //外设突发单次传输
}DMA_InitTypeDef;
四、实验现象: 试验成功蓝色LED灯闪烁,试验反败红色LED灯闪烁。 五、代码包下载连接: 网盘:http://pan.baidu.com/s/1bcY5JK
|