现在的位置: 首页 > 综合 > 正文

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

2012年12月15日 ⁄ 综合 ⁄ 共 3075字 ⁄ 字号 评论关闭

转载:http://blog.ednchina.com/chactor/185802/message.aspx#92932

 

最近练了一段时间的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完成后被调用的回调函数。

 

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);

}

<

抱歉!评论已关闭.