1. NIOS2 DMA控制器结构框图
与其它IP外设一样,DMA控制器也是通过AVALON MM总线,实现寄存器配置,数据读写功能。
3. NIOS2 DMA API函数
NIOS2 DMA的API函数原型都定义在alt_dma.h头文件中,常用的API函数如下:
alt_dma_txchan alt_dma_txchan_open (const char* name); static ALT_INLINE int alt_dma_txchan_send (alt_dma_txchan dma, const void* from, alt_u32 length, alt_txchan_done* done, void* handle) { return dma ? dma->dma_send (dma, from, length, done, handle) : -ENODEV; } static ALT_INLINE int alt_dma_txchan_ioctl (alt_dma_txchan dma, int req, void* arg) { return dma ? dma->ioctl (dma, req, arg) : -ENODEV; } alt_dma_rxchan alt_dma_rxchan_open (const char* dev); static ALT_INLINE int alt_dma_rxchan_prepare (alt_dma_rxchan dma, void* data, alt_u32 len, alt_rxchan_done* done, void* handle) { return dma ? dma->prepare (dma, data, len, done, handle) : -ENODEV; } static ALT_INLINE int alt_dma_rxchan_ioctl (alt_dma_rxchan dma, int req, void* arg) { return dma ? dma->ioctl (dma, req, arg) : -ENODEV; }
4. 参考设计——OnchipMenmory to SDRAM
1) Qsys设置
NIOS2代码运行在SDRAM中,OnchipMemory作为一个片上存储外设。
下面两个图是QSYS中的IP设置,图中可以看出DMA支持BURST读写模式,这样效率会大大提高。
在第二张图片中,博主勾选了show signals选项,可以看到,DMA组件定义的信号接口,有一个AVALON MM SLAVE端口,用于配制寄存器,两个AVALON MM MASTER分别实现读写功能,还有一个IRQ中断输出,向CPU产生中断信号。
2)软件源码
//file name: main.c //date: 2016.8.15 //author: shugen.yin //function: DMA, onchip memory to sdram/ddr2 //log: #include <stdio.h> #include <string.h> #include <sys/alt_irq.h> #include "system.h" #include "alt_types.h" #include "sys/alt_dma.h" #define DAT_LEN 32 unsigned int buffer0[DAT_LEN/4]; unsigned int *point=ONCHIP_MEMORY1_0_BASE; static void DMA_Init(void); //初始化DMA unsigned int dma_end_flag = 0; alt_dma_txchan tx; alt_dma_rxchan rx; void dma_done() { dma_end_flag++; } static void DMA_Init(void) { tx = alt_dma_txchan_open("/dev/dma_0"); if(tx != NULL) { printf("DMA transition start\n"); } alt_dma_txchan_ioctl(tx,ALT_DMA_SET_MODE_32,NULL); //point是源地址、传输数据块长度是DAT_LEN alt_dma_txchan_send(tx, point, DAT_LEN, NULL, NULL); rx = alt_dma_rxchan_open("/dev/dma_0"); alt_dma_rxchan_ioctl(rx,ALT_DMA_SET_MODE_32,NULL); //buffer0是目标地址、传输数据块长度是DAT_LEN、dma_done()是DMA完成后被调用的回调函数 alt_dma_rxchan_prepare(rx, buffer0 , DAT_LEN, dma_done, NULL); } int main() { int i; for(i=0;i<DAT_LEN/4;i++) buffer0[i] = 0; for(i=0;i<DAT_LEN/4;i++) *(point+i) = i+1; //初始化DMA DMA_Init(); //等待中断结束,说明传输完成 while(dma_end_flag == 0) { } //打印接收地址的数据 for(i=0;i<DAT_LEN/4;i++) { printf("buffer0[%d]=%d\t",i,buffer0[i]); } alt_dma_txchan_close(tx); alt_dma_rxchan_close(rx); return 0; }