[转载].基于Nios II的DMA传输
转门金瑞兄的博文: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 <stdio.h> |
02 | #include <string.h> |
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 | } |