[转载].基于Nios II的DMA传输.[Memory][Nios II]
0赞
发表于 2010/6/21 15:12:16
阅读(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 |
int main( 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 |
return 0; |
64 |
} |