[转载].基于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 |
} |
转门金瑞兄的博文: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 |
} |