嵌入式课程设计系别:计算机与通信工程学院班级:通信工程08-1班姓名:####学号:33333333333郑州轻工业学院计算机与通信工程学院2011年12月郑州轻工业学院课程设计任务书题目DMA传送编程专业、班级通信工程08-1学号 3333333姓名333主要内容、基本要求、主要参考文献等:1、主要内容(1) 编写单字节方式、双字节方式和四字节方式常规内存拷贝及时间检测程序(2) 编写DMA方式内存拷贝及时间检测程序(3) 比较DMA方式内存拷贝及常规内存拷贝的效率2、基本要求(1) 掌握S3C44B0 DMA控制器的使用(2) 掌握DMA软件编程方法3、主要参考文献【1】马忠梅,马广云,徐英惠,田泽.ARM嵌入式处理器结构与应用基础.北京:北京航天航空大学出版社,2002【2】田泽.嵌入式系统开发与应用实验教程.北京航空航天大学出版社,2004【3】周立功.ARM微控制器基础与实战[M].北京航天航空大学出版社,2003完成期限:指导教师签名:张涛张彦课程负责人签名:张涛张彦目录一、课程设计的基本任务----------------------------4二、课程设计的基本要求----------------------------4三、预备知识--------------------------------------------4四、实验设备--------------------------------------------4五、基础知识--------------------------------------------4六、课程设计说明书----------------------------------7七、程序代码-------------------------------------------8DMA 传送编程.一、课程设计的基本任务了解DMA传送原理掌握S3C44B0 DMA控制器的使用掌握DMA软件编程方法二、课程设计的基本要求编写单字节方式、双字节方式和四字节方式常规内存拷贝及时间检测程序编写DMA方式内存拷贝及时间检测程序比较DMA方式内存拷贝及常规内存拷贝的效率三、预备知识了解ADT集成开发环境的基本功能了解DMA的原理以及处理步骤四、实验设备JX44B0教学实验箱ADT1000仿真器和ADT IDE集成开发环境串口连接线五、基础知识直接数据存储- DMADMA方式当高速外设要与系统内存或者要在系统内存的不同区域之间,进行大量数据的快速传送时,查询方式和中断方式可能不能满足要求直接存储器存取(DMA)就是为解决这个问题提出的采用DMA方式,在一定时间段内,由DMA控制器取代CPU,获得总线控制权,来实现内存与外设或者内存的不同区域之间大量数据的快速传送典型的DMA控制器(以下简称DMAC)的工作电路DMA数据传送的工作过程1) DMAC发出DMA传送请求2) DMAC通过连接到CPU的HOLD信号向CPU提出DMA请求3) CPU在完成当前总线操作后会立即对DMA请求做出响应CPU的响应包括两个方面:CPU将控制总线、数据总线和地址总线浮空,即放弃对这些总线的控制权CPU将有效的HLDA信号加到DMAC上,以通知DMACCPU已经放弃了总线的控制权4) CPU将总线浮空,即放弃了总线控制权后,由DMAC接管系统总线的控制权,并向外设送出DMA的应答信号5) DMAC送出地址信号和控制信号,实现外设与内存或内存之间大量数据的快速传送6) DMAC将规定的数据字节传送完之后,通过向CPU发HOLD信号,撤消对CPU的DMA请求。
CPU收到此信号,一方面使HLDA无效,另一方面又重新开始控制总线,实现正常取指令、分析指令、执行指令的操作。
DMA传送方式I/O接口到存储器存储器到I/O接口存储器到存储器I/O接口到存储器的传送当进行由I/O接口到存储器的数据传送时,来自I/O接口的数据利用DMAC送出的控制信号,将数据输送到系统数据总线D0~D7上,同时,DMAC送出存储器单元地址及控制信号,将存在于D0~D7上的数据写入所选中的存储单元中。
这样就完成了由I/O接口到存储器一个字节的传送。
同时DMAC修改内部地址及字节数寄存器的内容。
存储器到I/O接口与前一种情况类似,在进行这种传送时,DMAC送出存储器地址及控制信号,将选中的存储单元的内容读出放在数据总线D0~D7上,接着,DMAC送出控制信号,将数据写到规定的(预选中)端口中去,而后MDAC自动修改内部的地址及字节数寄存器的内容S3C44B0的DMA控制器S3C44B0集成了4个通道的DMA控制器:两个ZDMA控制器ZDMA0/1:可以用于存储器到存储器、储存器到I/O设备、I/O设备之间的DMA传送;两个BDMA控制器BDMA0/1:用于储存器与I/O 设备之间的传输。
S3C44B0中与DMA控制器有关的寄存器ZDMA0/1控制寄存器ZDMA0起始地址、目的地址寄存器DMA计数器寄存器ZDMA0/1控制寄存器ZDMA0起始地址、目的地址寄存器DMA计数器寄存器六、课程设计说明书本实验通过DMA方式实现存储器到存储器间的数据传送,并将其与常规的内存拷贝操作进行比较拷贝动作的计时处理采用定时器进行计时处理,采用函数Timer_Start启动计时处理,参数divider 表示定时时间间隔,0 : 16 us1 : 32 us2 : 64 us3 : 128 us操作完成时调用Timer_Stop停止定时器计数,其返回值为计数值,该值乘以时间间隔(128us)即为计时时间Timer_Start(3); /* 128 us */time=Timer_Stop(); /* 停止定时器*/Uart_Printf("Copy Bytes :time=%f\n",time*128E-6);常规的内存拷贝操作字节拷贝*(unsigned char*)(dstAddr) = *(unsigned char*)(srcAddr);双字节拷贝*(unsigned short*)(dstAddr) = *(unsigned short*)(srcAddr);字节拷贝*(unsigned int*)(dstAddr) = *(unsigned int*)(srcAddr);DMA的内存拷贝操作清除传输完毕标志zdma0Done=0;设置DMA传输的起止地址和长度rZDISRC0=srcAddr|(dw<<30)|(1<<28);/* dw 为DMA传输宽度*/rZDIDES0=dstAddr|( 2<<30)|(1<<28);rZDICNT0=length |( 2<<28)|(1<<26)|(3<<22)|(1<<20);启动DMA传输并开始计时rZDCON0=0x1;Timer_Start(3);DMA的内存拷贝操作等待传输完成,传输完成标记将在DMA中断服务程序中置位while(zdma0Done==0);返回当前定时计数器中的值time=Timer_Stop();Uart_Printf("ZDMA0 :time=%f\n",time*128E-6);关中断rINTMSK=BIT_GLOBAL;DMA中断处理函数void isr_dma0(void){rI_ISPC=BIT_ZDMA0;/* 设置传输完毕标志*/zdma0Done = 1;}实验报告要求什么叫DMA传送方式?试说明DMA方式传送数据的主要步骤。
试比较DMA传输、查询式传输及中断方式传输之间的优缺点和适用场合?七、程序代码:/**************************************************************//* */ /* FILE NAME VERSION */ /* */ /* DMA.C 1.0 */ /* */ /*DESCRIPTION */ /* */ /* JX44B0(S3C44B0X)DMA实验*/ /* */ /* */ /* DATA STRUCTURES */ /* */ /* FUNCTIONS : */ /* 在JX44B0教学实验箱进行DMA方式内存拷贝的实验*/ /* */ /* DEPENDENCIES */ /* JX44B0-1 */ /* JX44B0-2 */ /* JX44B0-3 */ /* */ /* */ /* NAME: */ /* REMARKS: */ /* */ /* Copyright (C) 2003 Wuhan CVTECH CO.,LTD */ /**************************************************************//**************************************************************/ /* 学习ARM处理器中DMA方式的处理方法:*/ /* DMA方式:内存->内存DMA方式传输数据*/ /* 注意: 学习该实验之前请先学习interrupt中断处理实验*/ /**************************************************************/ /* 包含文件*/#include "44b.h"#include "44blib.h"#include "rtc.h"typedef (*ISR_ROUTINE_ENTRY)(void);#define Printf Uart_Printf/* functions */void Zdma0(int srcAddr,int dstAddr,int length);void Zdma0Done(void);void Test_Zdma0(void);void isr_dma0(void);/* globals */volatile int zdma0Done;void IsrIRQ() __attribute__ ((interrupt("IRQ")));/**************************************************************/ // Function name : IsrIRQ// Description : 非矢量方式下中断的查表处理// 中断地址表位于0x0c7fff00开始的256字节// Return type : void// Argument : void**************************************************************/ void IsrIRQ(){int count = 0;unsigned int isr_pending;unsigned int isr_mask = 0x00000001;unsigned int isr_mask_set = rINTMSK;ISR_ROUTINE_ENTRY isr_routine_entry = (ISR_ROUTINE_ENTRY)0x0;__asm__ ("STMFD SP!, {r1,r4-r8} @ SA VE r1,r4-r10 \n""nop \n");isr_pending = (rINTPND & ~isr_mask_set);while(isr_mask){if(isr_pending&isr_mask){isr_routine_entry = (ISR_ROUTINE_ENTRY)(*(int*)(HandleADC+count));break;}count+=4;isr_mask <<= 1;}if(isr_routine_entry) (*isr_routine_entry)();__asm__ ("LDMFD SP!, {r1,r4-r8} @ RESTORE r1,r4-r10 \n""nop \n");}/**************************************************************/ // Function name : init_interrupt_handler// Description : 非矢量方式下中断向量表初始化处理// Return type : void// Argument : irq_handler// 中断处理函数入口**************************************************************/ void init_interrupt_handler(unsigned int irq_handler){int i;rINTPND = 0x00000000; /* 清除所有未决的中断*/rI_ISPC = 0x03FFFFFF;for( i = 0; i < 256; i+=4) /* 清除中断表*/{*(unsigned int*)(_ISR_STARTADDRESS+i) = 0;}*(unsigned int*)(HandleIRQ) = irq_handler; /* 设置IRQ模式处理函数*/ }/**************************************************************/ // Function name : install_isr_handler// Description : 非矢量方式下中断向量的安装// Return type : void// Argument : irq_no, 中断号// irq_routine, 中断处理函数地址**************************************************************/ void install_isr_handler(int irq_no, void* irq_routine){*(unsigned int*)(irq_no) = (unsigned int)irq_routine;}/**************************************************************/ // Function name : Main// Description : DMA测试程序主函数// 内存->内存DMA方式传输数据// 传输完毕引发DMA中断// 注册中断源:BIT_ZDMA0// Return type : int// Argument : void**************************************************************/ int Main(void){Uart_Select(0);Uart_Init(MCLK, 115200);Uart_Printf("DMA TEST PROGRAM\n");rINTCON=0x7; /* Non-vect,IRQ disable,FIQ disable*/init_interrupt_handler((unsigned int)IsrIRQ);install_isr_handler(HandleZDMA0, (void*)isr_dma0);rINTMOD=0x0; /*设置所有中断为IRQ模式 */rINTMSK=(0x07ffffff&~(BIT_GLOBAL|BIT_ZDMA0)); /* 使能TICK中断*/rINTCON=0x5; /* 打开IRQ模式的中断*/Test_Zdma0();while(1);}/*************************************************************/ // Function name : Test_Zdma0// Description : test zdma 0// Return type : void// Argument : void**************************************************************/ void Test_Zdma0(void){unsigned char *src, *dst;int i;unsigned int memSum;Uart_Printf("[ZDMA0 MEM2MEM Test]\n");dst=(unsigned char *)malloc(0x80000);src=(unsigned char *)malloc(0x80000);/* 将dst区域设置为非Cacheable区域,关闭Cache */rNCACHBE1=(((((unsigned)dst+0x100000)>>12)+1 )<<16 )|((unsigned)dst>>12);Uart_Printf("dst=%x,src=%x\n",(int)dst,(int)src);Zdma0((int)src,(int)dst,0x80000);free(src);free(dst);}/*************************************************************/ // Function name : Zdma0// Description : 以三种不同的方式进行数据拷贝,检查其时间消耗// Return type : void// Argument : srcAddr,拷贝数据的起始地址// dstAddr,拷贝数据的目的地址// length,拷贝数据的长度**************************************************************/ void Zdma0(int srcAddr,int dstAddr,int length){int time;/* 将目标地址设置为非Cache区*/rNCACHBE1 = (((((unsigned)dstAddr+0x100000)>>12) +1 )<<16 ) | ((unsigned)dstAddr>>12);/* 测试单字节方式的拷贝时间*//* 启动定时器,精度128us,用于计时*/Timer_Start(3);for( time = 0; time < length; time++){*(unsigned char*)(dstAddr+time) = *(unsigned char*)(srcAddr+time);}/* 返回当前定时计数器中的值*/time=Timer_Stop();/* 输出拷贝的时间*/Uart_Printf("Copy Bytes :time=%f\n",time*128E-6);/* 测试双字节方式的拷贝时间*/Timer_Start(3);for( time = 0; time < length; time+=2){*(unsigned short*)(dstAddr+time) = *(unsigned short*)(srcAddr+time);}time=Timer_Stop();Uart_Printf("Copy short words :time=%f\n",time*128E-6);/* 测试字节方式的拷贝时间*/Timer_Start(3);for( time = 0; time < length; time+=4){*(unsigned long*)(dstAddr+time) = *(unsigned long*)(srcAddr+time);}time=Timer_Stop();Uart_Printf("Copy words :time=%f\n",time*128E-6);/* 清除传输完毕标志*/zdma0Done=0;/* 设置DMA传输的起止地址和长度*/rZDISRC0=srcAddr|( 2<<30)|(1<<28);rZDIDES0=dstAddr|( 2<<30)|(1<<28);rZDICNT0=length |( 2<<28)|(1<<26)|(3<<22)|(1<<20);/* 启动DMA传输*/rZDCON0=0x1;Timer_Start(3);/* 等待传输完成*/while(zdma0Done==0);/* 返回当前定时计数器中的值*/time=Timer_Stop();/* 输出一次传送的时间*/Uart_Printf("ZDMA0 :time=%f\n",time*128E-6);rINTMSK=BIT_GLOBAL;}/*************************************************************/ // Function name : isr_dma0// Description : DMA0 中断处理例程// Return type : void// Argument : void***************************************************************/ void isr_dma0(void){rI_ISPC=BIT_ZDMA0; /* 清除DMA中断标志*/zdma0Done = 1; /* 设置传输完毕标志*/}。