安德鲁

[转载].基于Nios II的DMA传输.[Memory][Nios II]

0
阅读(2727)

转自金瑞兄的博文:http://www.cnblogs.com/menjr/archive/2010/05/04/1727226.html

关于DMA传输的实验。

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

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

1、 存储器到存储器

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


01 //打开发送通道
02
03 tx = alt_dma_txchan_open("/dev/dma_0");
04
05 //tx_buf是源地址、传输数据块长度是length
06
07 dma_res = alt_dma_txchan_send(tx, tx_buf, length, NULL, NULL);
08
09 //打开接收通道
10
11 rx = alt_dma_rxchan_open("/dev/dma_0");
12
13 //rx_buf是目标地址、传输数据块长度是length、dma_done()是DMA完成后被调用的回调函数
14
15 dma_res = alt_dma_rxchan_prepare(rx, rx_buf, length, dma_done, NULL);

2、 存储器到外设

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


1 tx = alt_dma_txchan_open("/dev/dma_0");// 打开发送通道
2
3 alt_dma_txchan_ioctl(tx, ALT_DMA_TX_ONLY_ON, (void*)dst_addr);// dst_addr是目标地址
4
5 dma_res = alt_dma_txchan_send(tx, tx_buf, length, dma_done, NULL);// tx_buf是源地址

3、 外设到存储器

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


1 rx = alt_dma_rxchan_open("/dev/dma_0");// 打开接收通道
2
3 alt_dma_rxchan_ioctl(rx, ALT_DMA_RX_ONLY_ON, (void*)source_addr);// source_addr是源地址
4
5 dma_res = alt_dma_rxchan_prepare(rx, rx_buf, length, dma_done, NULL);// rx_buf是目标地址

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

以下是基于DMA通过UART发送和接收数据的例子,注意DMA_0 为接受通道,DMA_1为发送通道。当然可以将dma的read_master和writer_master同时连在uart_0和sdram_0的从端 口上,这样是可以用一个dma对两者读写操作,但是不能同时做双向传输。


01 #include
02 #include
03 #include "system.h"
04 #include "sys/alt_dma.h"
05 #include "unistd.h"
06
07 intmain(void)
08 {/*
09 alt_dma_rxchan rx;
10 //创建DMA接收信道
11 rx = alt_dma_rxchan_open("/dev/dma_0");
12 //当信道创建成功
13 if(rx != NULL)
14 {
15 printf("Dma transition start.");
16 while(1)
17 {
18 //设置DMA传输的数 据位宽 本例中为8位
19 alt_dma_rxchan_ioctl(rx,ALT_DMA_SET_MODE_8,NULL);
20 //指定从uart接收数据
21 alt_dma_rxchan_ioctl(rx,ALT_DMA_RX_ONLY_ON,(void*)UART_0_BASE);
22
23 //提交DMA接收请求 指定接收数据的位置(sdram)以及传输数据量
24 if(alt_dma_rxchan_prepare(rx,
25 SDRAM_0_BASE,
26 1024,
27 NULL,
28 NULL) < 0)
29 {
30 printf ("Error: failed to post receive request\n");
31 }
32 //关闭DMA接收信道
33 alt_dma_rxchan_close(rx);
34 usleep(1000000);
35 }
36 }
37
38 */
39 alt_dma_txchan tx;
40 tx = alt_dma_txchan_open("/dev/dma_1");
41 if(tx != NULL)
42 {
43 printf("Dma transition start.");
44 while(1)
45 {
46 alt_dma_txchan_ioctl(tx,ALT_DMA_SET_MODE_8,NULL);
47 alt_dma_txchan_ioctl(tx,ALT_DMA_TX_ONLY_ON,(void*)(UART_0_BASE+2));
48
49 //注意是 UART_0_BASE+2,因为UART的txdata寄存器在rxdata之后,偏移量为一个rxdata的长度(16位,2个字节)
50 if(alt_dma_txchan_send(tx,
51 SDRAM_0_BASE,
52 1024,
53 NULL,
54 (void*) NULL) < 0)
55 {
56 printf("Error: failed to post transmit request\n");
57 }
58 //关闭DMA发送信道
59 alt_dma_txchan_close(tx);
60 usleep(1000000);
61 }
62 }
63 return0;
64 }
Baidu
map