| 
 
| 本帖最后由 sun1986821 于 2011-10-26 18:47 编辑 
 前记:
 因为之前有点忙,所以收到板子已经有段时间了(应该没超过3个月大限把 = = ),一直没有时间写笔记。不过实验到时做了有些。现在发帖估计赶不上我那轮的选美了,不知道能不能把我排到下一轮选美。不行的话就算了,拿回我的100押金我还是倍感欣慰的~~~闲话少说,开始上帖!
 
 正文:
 
 DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,他允许不同速度的硬件装置来沟通,而不需要依于CPU的大量中断负载。否则,CPU需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU对于其他的工作来说就无法使用。DMA传输将数据从一个地址空间复制到另外一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA传输对于高效能嵌入式系统算法和网络是很重要的。以上内容转自百度百科。
 Nuvoton里面的DMA功能叫做PDMA(Peripheral Direct Memory Access 外设直接内存存取)和传统的DMA略有区别,大概是指这个DMA通道只能为少数几种特定的外围设备提供吧,这是本人的理解。作为一个低端高性价比芯片,能够做到在几个外设之间进行数据传递而不占用CPU也已经算很不错了。以下是我做的一个小实验,把一个普通的数组数据作为例子通过PDMA通道传递到UART0,在由UART0输出。
 
 //#include <stdio.h>
 #include "Driver\DrvUART.h"
 #include "Driver\DrvGPIO.h"
 #include "Driver\DrvSYS.h"
 #include "Driver\DrvPDMA.h"
 #include "Driver\DrvSPI.h"
 #include "NUC1xx.h"
 
 /* 为简化步骤,只用了一个简单的8位字符数组作为要传输的源数据 */
 uint8_t Flash_Buffer[8] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
 STR_PDMA_T sPDMA;
 /* PDMA2的一个callback函数 用于一次传递完后产生中断调用 */
 void PDMA2_Interrupt_Callback();
 
 int main(){
 
 STR_PDMA_T
 PDMA_ConfigStruct;
 STR_UART_T
 UartParam;
 /* 对时钟、串口进行必要的初始化 */
 UNLOCKREG();
 
 /** Enable GPIO block clock */
 DrvSYS_SetOscCtrl(E_SYS_XTL12M,ENABLE);
 /* Waiting for 12M Xtal stalble */
 DrvSYS_Delay(5000);
 /* Run 48Mhz */
 DrvSYS_Open(48000);
 DrvSYS_Delay(5000);
 
 DrvGPIO_InitFunction(E_FUNC_UART0);
 UartParam.u32BaudRate
 = 9600;
 UartParam.u8cDataBits
 = DRVUART_DATABITS_8;
 UartParam.u8cStopBits
 = DRVUART_STOPBITS_1;
 UartParam.u8cParity
 = DRVUART_PARITY_NONE;
 UartParam.u8cRxTriggerLevel
 = DRVUART_FIFO_1BYTES;
 /* Select UART Clock Source From 12Mhz */
 DrvSYS_SelectIPClockSource(E_SYS_UART_CLKSRC,0);
 /* Open the UART */
 DrvUART_Open(UART_PORT0, &UartParam);
 
 /* 输出一句初始化完毕 */
 DrvUART_Write(UART_PORT0,"\nfinish init\n", 13);
 DrvSYS_Delay(5000);
 
 /* 对PDMA功能进行初始化 */
 DrvPDMA_Init ();
 DrvPDMA_SetCHForAPBDevice(eDRVPDMA_CHANNEL_2, eDRVPDMA_UART0, eDRVPDMA_WRITE_APB);
 /** 填入PDMA设置参数 */
 PDMA_ConfigStruct.sSrcCtrl.u32Addr
 = (uint32_t)Flash_Buffer;
 PDMA_ConfigStruct.sDestCtrl.u32Addr
 = UART0_BASE;
 PDMA_ConfigStruct.u8TransWidth
 = eDRVPDMA_WIDTH_8BITS;
 PDMA_ConfigStruct.sSrcCtrl.eAddrDirection
 = eDRVPDMA_DIRECTION_INCREMENTED;
 PDMA_ConfigStruct.sDestCtrl.eAddrDirection = eDRVPDMA_DIRECTION_FIXED;
 PDMA_ConfigStruct.u8Mode
 
 = eDRVPDMA_MODE_MEM2APB;
 PDMA_ConfigStruct.i32ByteCnt
 = 8;
 DrvPDMA_Open(eDRVPDMA_CHANNEL_2,&PDMA_ConfigStruct);
 /** 使能PDMA2中断 */
 DrvPDMA_EnableInt(eDRVPDMA_CHANNEL_2, eDRVPDMA_BLKD );
 /** 装入中断回调函数 */
 DrvPDMA_InstallCallBack(eDRVPDMA_CHANNEL_2, eDRVPDMA_BLKD, (PFN_DRVPDMA_CALLBACK) PDMA2_Interrupt_Callback );
 
 /** 使能PDMA2的数据传输功能 */
 DrvPDMA_CHEnableTransfer(eDRVPDMA_CHANNEL_2);
 
 DrvUART_EnablePDMA(UART_PORT0);
 while(1);
 return 0;
 }
 
 /** 当传输任务执行完毕,输出一句“f I n i s h”表示任务结束 */
 void PDMA2_Interrupt_Callback(){
 DrvUART_Write(UART_PORT0,"\nf i n i s h\n", 13);
 while(1);
 }
 
 本来作为一个深化想写一段从SPI设备到UART设备之间的PDMA数据传输程序的,因为时间有限没能完成。 大概的思想就是开通两个PDMA通道 实现SPI→Memory→UART。前者使用PDMA1,后者用PDMA2。当PDMA1发生中断则在中断服务函数中使能一次PDMA2,PDMA2执行完继续回到PDMA1的传输中。不过还不清楚是否可行,因为担心SPI的数据源源不断涌进来的话,整个流程就乱了。这个以后考虑吧,这次先到这。下次打算做一下EEPROM的IIC通信。
 
 
 
 
 
 | 
 
×本帖子中包含更多资源您需要 登录 才可以下载或查看,没有账号?注册 
  |