打印
[菜农助学交流]

【sun1986821第一帖】【250活动笔记】【PDMA初探】

[复制链接]
2327|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
DMA, pd, UART, ST, ck
本帖最后由 sun1986821 于 2011-10-26 18:47 编辑

前记:
因为之前有点忙,所以收到板子已经有段时间了(应该没超过3个月大限把 = = ),一直没有时间写笔记。不过实验到时做了有些。现在发帖估计赶不上我那轮的选美了,不知道能不能把我排到下一轮选美。不行的话就算了,拿回我的100押金我还是倍感欣慰的~~~闲话少说,开始上帖!

正文:

DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,他允许不同速度的硬件装置来沟通,而不需要依于CPU的大量中断负载。否则,CPU需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU对于其他的工作来说就无法使用。DMA传输将数据从一个地址空间复制到另外一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA传输对于高效能嵌入式系统算法和网络是很重要的。以上内容转自百度百科。
Nuvoton里面的DMA功能叫做PDMAPeripheral 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通道 实现SPIMemoryUART。前者使用PDMA1,后者用PDMA2。当PDMA1发生中断则在中断服务函数中使能一次PDMA2PDMA2执行完继续回到PDMA1的传输中。不过还不清楚是否可行,因为担心SPI的数据源源不断涌进来的话,整个流程就乱了。这个以后考虑吧,这次先到这。下次打算做一下EEPROMIIC通信。




相关帖子

沙发
hotpower| | 2011-10-26 18:25 | 只看该作者
记得iic没有PDMA

使用特权

评论回复
板凳
sun1986821|  楼主 | 2011-10-26 18:35 | 只看该作者
没 我里面写的是SPI的PDMA。下次写I2C跟PDMA无关的。 2# hotpower

使用特权

评论回复
地板
sun1986821|  楼主 | 2011-10-26 18:44 | 只看该作者
http://photo.163.com/sun1986821@126/op/7307476881.html

实验图片不知道怎么传过来 貌似回帖传不了 给个相册传送门吧

使用特权

评论回复
5
sun1986821|  楼主 | 2011-10-26 18:48 | 只看该作者
传上来了

使用特权

评论回复
6
weshiluwei6| | 2011-10-26 19:23 | 只看该作者
看看 支持 学习

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

21

帖子

1

粉丝