原创 【原创】基于Nios II的DMA传输总结(附源码)

2008-12-4 20:12 11404 9 25 分类: FPGA/CPLD

Nios II 嵌入式系统硬件设计(五)


    最近练了一段时间的DMA传输,现做如下的总结,分享自己获得心得以及遇到的一些问题。


    在系统运行时,当需要传输大量数据时,可以采用DMA的方式进行传输,以解脱出CPU来处理其他命令。






       Nios II中的DMA传输有以下三种形式:


1、  存储器到存储器


这种情况下需要同时打开发送通道和接收通道,而且源地址和目标地址都是自增的。


tx = alt_dma_txchan_open("/dev/dma_0");//打开发送通道


dma_res = alt_dma_txchan_send(tx, tx_buf, 32, NULL, NULL);  // tx_buf是源地址


rx = alt_dma_rxchan_open("/dev/dma_0");//打开接收通道


dma_res = alt_dma_rxchan_prepare(rx, rx_buf, 32, dma_done, NULL); // rx_buf是目标地址,dma_done()DMA完成后被调用的回调函数。


<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 


2、  存储器到外设


这种情况下只要打开发送通道,而且源地址是自增的,目标地址是固定的。


tx = alt_dma_txchan_open("/dev/dma_0");  // 打开发送通道


alt_dma_txchan_ioctl(tx, ALT_DMA_TX_ONLY_ON, (void *)dst_addr); // dst_addr是目标地址


dma_res = alt_dma_txchan_send(tx, tx_buf, 32, dma_done, NULL); // tx_buf是源地址


 


3、  外设到存储器


这种情况下只要打开接收通道,而且源地址是固定的,目标地址是自增的。


rx = alt_dma_rxchan_open("/dev/dma_0");  // 打开接收通道


alt_dma_rxchan_ioctl(rx, ALT_DMA_RX_ONLY_ON, (void *)source_addr); // source_addr是源地址


dma_res = alt_dma_rxchan_prepare(rx, rx_buf, 32, dma_done, NULL);  // rx_buf是目标地址


 


其中通过alt_dma_txchan_ioctlalt_dma_rxchan_ioctl还可以设置每次发送和接收的字节数。






       下面给出两个实例,说明DMA传输的过程。


 


1、  存储器到存储器


下面程序为SDRAMonchip-memory的数据传输。


硬件连接图示:


点击看大图


程序如下:


#include <stdio.h>


#include <stdlib.h>


#include <sys/alt_dma.h>


#include "system.h"


static volatile int rx_done = 0;


int rc;


alt_dma_txchan txchan;


alt_dma_rxchan rxchan;


static char buff[256];


void* tx_data = (void*) buff; /* 源地址 */


void* rx_buffer = (void*) 0x01801000; /* 目标地址,从上图看到0x01801000onchip-memory的地址*/


//DMA传输结束回调函数


static void done_t(void* handle, void* data)


{


   


    rx_done++;


   


}


 


int main (int argc, char* argv[], char* envp[])


{


 


/* 打开发送通道 */


  if ((txchan = alt_dma_txchan_open("/dev/dma")) == NULL)


  {


    printf ("Failed to open transmit channel\n");


    exit (1);


  }


/* 打开接收通道 */


  if ((rxchan = alt_dma_rxchan_open("/dev/dma")) == NULL)


  {


    printf ("Failed to open receive channel\n");


    exit (1);


  }


/* 开始发送数据 */


  if ((rc = alt_dma_txchan_send (txchan,


                                 tx_data,


                                 128,


                                 NULL,


                                 NULL)) < 0)


  {


    printf ("Failed to post transmit request, reason = %i\n", rc);


    exit (1);


  }


/* 开始接收数据*/


  if ((rc = alt_dma_rxchan_prepare (rxchan,


                                    rx_buffer,


                                    128,


                                    done_t,


                                    NULL)) < 0)


  {


    printf ("Failed to post read request, reason = %i\n", rc);


    exit (1);


  }


/* 等待传输结束 */


  while (!rx_done);


  printf ("Transfer successful!\n");


 


  return 0;


}


程序运行结束后在Nios IDEconsole界面中显示:


Transfer successful!


表明传输成功。


 


2、  存储器到UART


下面程序为SDRAMUART的数据传输


硬件连接图:


点击看大图


程序如下:


#include <stdio.h>


#include <stdlib.h>


#include "sys/alt_dma.h"


#include "altera_avalon_uart_regs.h"


#include "system.h"


#include "alt_types.h"


 


static volatile int tx_done = 0;


volatile static alt_u8 chr[20] = {1,2,3,4,6,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20} ;//待发送的数据


//回调函数


static void done (void* handle)


{


tx_done++;


}


int main()


{


int rc;


alt_dma_txchan txchan;


 


void* source_buff_ptr = (void*) chr; /* 源地址 */


void* destination_buff_ptr = (void*)IOADDR_ALTERA_AVALON_UART_TXDATA(UART_BASE); /* 目标地址IOADDR_ALTERA_AVALON_UART_TXDATA(UART_BASE)函数读出txdata的地 */


 


/* 打开发送通道 */


if ((txchan = alt_dma_txchan_open("/dev/dma")) == NULL)


{


printf ("Failed to open transmit channel\n");


exit (1);


}


/* 设置目标地址固定 */


if ((rc = alt_dma_txchan_ioctl(txchan, ALT_DMA_TX_ONLY_ON, destination_buff_ptr)) < 0)


{


printf ("Failed to set ioctl, reason = %i\n", rc);


exit (1);


}


//设置每次发送一个字节,即8位,因为UART每次只发送8


if((rc = alt_dma_txchan_ioctl(txchan,ALT_DMA_SET_MODE_8 ,NULL))<0)


{


    printf("Failed to set mode 8\n");


    exit(1);


}


/* 开始发送 */


if ((rc = alt_dma_txchan_send(txchan, source_buff_ptr, 20, done, NULL)) < 0)


{


printf ("Failed to post transmit request, reason = %i\n", rc);


exit (1);


}


/* 等待发送结束 */


while (!tx_done);


printf ("Transfer successful!\n");


return 0;


}


不过该程序执行结束后,在串口调试器中显示Transfer successful!却没有显示DMA发送的那20个数字。不知道哪里需要修改,放在这里和大家讨论下。

文章评论16条评论)

登录后参与讨论

用户377235 2012-7-26 16:28

第二个程序应该不行,因为 DMA 以很快的速度一口气把数据组传给了 UART ,而 UART 的速度明显不够,在 UART 里的老数据会被新数据覆盖,或者说是出现了 status register 里的报错位。我看了Master 了 Slave 的接口,一个 Waitrequest ,一个是 ReadyForData,他们之间的 Flow control 并没有实现。所以 UART 应该发不出那个数据组。而DMA 只是一味的向UART 里写,写完就算完事了,done 函数也就被调用了,而没哟考虑 UART 到底有没有接受数据。

用户377235 2012-7-26 16:26

第二个程序应该不行,因为 DMA 以很快的速度一口气把数据组传给了 UART ,而 UART 的速度明显不够,在 UART 里的老数据会被新数据覆盖,或者说是出现了 status register 里的报错位。我看了Master 了 Slave 的接口,一个 Waitrequest ,一个是 ReadyForData,他们之间的 Flow control 并没有实现。所以 UART 应该发不出那个数据组。而DMA 只是一味的向UART 里写,写完就算完事了,done 函数也就被调用了,而没哟考虑 UART 到底有没有接受数据。

用户377235 2011-12-26 15:30

请问博主,nios中dma通过(gpio)向外设送数据(外设为双口ram)不在nios中,ram写需要同步时钟),数据同步怎么办,dma的时钟在哪里得到。

用户414908 2011-4-22 11:10

怎么我的没反应呢?编译也没提示错误,也能下载,也没错误。

用户411603 2011-4-6 15:37

我不知道为什么,但是我知道问题在哪里! (void*)IOADDR_ALTERA_AVALON_UART_TXDATA(UART_BASE); 这样写我也知道是取TXDDATA的偏移地址,但是我不知道为什么不行 (void*)(UART_BASE+2)就可以了,偏移量为一个rxdata的长度(16位,2个字节) 这样就可以了 理论上两者一样,实际上为什么这样我不知道

用户1462585 2009-7-15 15:31

刚刚调试了上面那个程序,发现alt_dma_rxchan_prepare不能调用done_t 函数,博主,能否指点一二? 多谢! 我的邮箱wxkhappy@163.com

用户174501 2009-5-31 16:56

我最近也在整dma,我遇到的问题和博主是一样的,不清楚具体是怎么回事,当我把波特率设置成115200,显示的结果还是一样,请高手指教

用户23547 2009-4-23 18:11

为什么 我按照你的结构图连接后在Quartus下编译不能通过 总是出现project too complex的错误 请麻烦博主能不能详细说明每个组件的参数啊 谢谢!!

用户1394221 2009-3-10 21:52

很佩服博主,我在这里学到了很多东西. DMA串口实验我按照博主的程序做成功了,博主估计是波特率没有设置正确,我设为115200可以全部接收. 谢谢!

用户191384 2009-2-25 21:10

谢谢你的这篇帖子,对我帮助很大。你最后做的串口实验没有成功,我估计是由于DMA发送数据在几个时钟周期内就完成了,而此时串口波特率可能连一个字节都没有发送出来。也就是说DMA把数据一气发给了UART,可UART根本就不可能在这么短的时间把这些数发出去。不知道我说的对不对。
相关推荐阅读
用户1332143 2009-08-16 21:47
时序电路亚稳态分析
这篇文章是我对电子设计中,亚稳态问题的一种分析和总结。文章通过对数字电路中器件的工作机制的介绍,引出亚稳态问题的发生机制。并通过对亚稳态问题发生机制的探讨,用以得到一种能够清楚地,有的放矢地解决亚稳态...
用户1332143 2009-08-16 10:52
【推荐】ADF4350配置软件下载
p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  随着现代半导体工艺的不断发展, 几十纳米级的CMOS工艺给数字电路带来了很大的恩惠, 但对模拟...
用户1332143 2009-08-14 12:47
【原创】基于NiosII及FT245BM的USB接口设计
以前做的一个项目,FPGA接收AD采集数据后,通过串口发送回PC机,由于串口传输速率较低,对于实时性要求较高的场合不太适用,因此站长选用FT245BM芯片来实现USB接口传输,本文主要讲解FT245B...
用户1332143 2009-08-13 14:56
【原创】MAXII:UFM中晶振的使用
MAXII系列CPLD中带有UFM模块,本文主要讲解UFM中晶振的使用,具体内容请点击下面链接MAXII:UFM中晶振的使用...
用户1332143 2009-03-01 21:53
【原创】如何使用FPGA进行信号调制
       最近要做一个通信收发系统项目,以前对收发器的射频前段关注的比较多,而对基带部分的信号处理一直没有仔细研究。因此,正好借这个项目,熟悉整个基带部分的信号处理流程。       基带部分主要...
用户1332143 2009-02-27 21:56
寒假回来——FPGA市场评论
寒假在家里电脑不能上网,好久没来更新自己的博客了,首先感谢大家对我博客的支持。回来后马上开始了一个863项目,一直没有时间来写博客,今天总算有时间,上来看看。回来这段时间关注了下FPGA的相关新闻,发...
EE直播间
更多
我要评论
16
9
关闭 站长推荐上一条 /3 下一条