DMA(Direct Memory Access)直接存储器传输,是指将外设的数据不经过微处理器直接传送到存储器中,或者,从存储器不经过微处理器直接将数据传送至外部设备。一次DMA传输只需要执行一个DMA周期(相当于一个总线时钟周期),因而能显著提高数据传输速度,以满足某些告诉外设的需求。在FPGA中,在进行DMA传输时需要一个DMA控制器,来协调外设接口和存储器的数据传输。SOPC Builder内部集成了一个DMA控制器部件,可非常容易的将其添加到SOPC系统,对于Nios II处理器,DMA控制器IP核的设备驱动程序在HAL系统库中提供。
在Nios II HAL的DMA设备模型中,DMA传输归为两类:发送和接收。因此,HAL也提供了两套驱动分别完成DMA的发送和接收通道。发送通道负责将数据从源设备发送到目标设备,接收通道负责从源设备接收数据并存放于目标设备。
DMA传输按照原设备和目标设备的不同分为以下3中类型:
1. 外设——>存储器,接收传输
2. 存储器——>外设,发送传输
3. 存储器之间,同时实现发送和接受传输
在Nios II HAL的API中,对于存储器一方,即传输时产生地址自增的一方,需要打开一个接收或发送的通道。如果是地址固定的一方(外设),则不需要打开通道。以下为3种方式创建通道的代码:
1. 外设 ----> 存储器
// 打开接收通道 rx
rx = alt_dma_rxchan_open("/dev/dma_0");
// 指定源设备地址 source_addr
alt_dma_rxchan_ioctl(rx, ALT_DMA_RX_ONLY_ON, (void*)source_addr);
// 指定目标设备地址 rx_buf、传输数据块长度length以及DMA中断处理函数dma_done
dma_res = alt_dma_rxchan_prepare(rx, rx_buf, length, dma_done, NULL);
2. 存储器 ----> 外设
// 打开发送通道 tx
tx= alt_dma_txchan_open("/dev/dma_0");
// 指定目标备地址 dst_addr
alt_dma_txchan_ioctl(tx, ALT_DMA_TX_ONLY_ON, (void*)dst_addr);
// 指定目标设备地址 tx_buf、传输数据块长度length以及DMA中断处理函数dma_done
dma_res = alt_dma_txchan_prepare(tx, tx_buf, length, dma_done, NULL);
3. 存储器 ----> 存储器
// 打开接收通道 rx
rx = alt_dma_rxchan_open("/dev/dma_0");
// 指定目标设备地址 rx_buf、传输数据块长度length以及DMA中断处理函数dma_done
dma_res = alt_dma_rxchan_prepare(rx, rx_buf, length, dma_done, NULL);
// 打开发送通道 tx
tx= alt_dma_txchan_open("/dev/dma_0");
// 指定目标设备地址 tx_buf、传输数据块长度length以及DMA中断处理函数dma_done
dma_res = alt_dma_txchan_prepare(tx, tx_buf, length, dma_done, NULL);
例程:
#include <stdio.h>
#include <string.h>
#include "system.h"
#include "sys/alt_dma.h"int dma(void)
{
alt_dma_rxchan rx;
//创建DMA接收通道
rx = alt_dma_rxchan_open("/dev/dma");
//如果信道创建成功
if(rx != NULL)
{
printf("Dma transition start.\n");
while(1)
{
//设置DMA传输的数据位宽
alt_dma_rxchan_ioctl(rx, ALT_DMA_SET_MODE_8, NULL);
//指定从uart接收数据
alt_dma_rxchan_ioctl(rx, ALT_DMA_RX_ONLY_ON, (void*)UART_BASE);
//提交DMA接收请求,指定接收数据的位置(SDRAM)以及传输数据量
if(alt_dma_rxchan_prepare(rx,
SDRAM_BASE,
1024,
NULL,
NULL) < 0
)
{
printf("Error: failed to post receive request\n");
}
//关闭DMA接收信道
alt_dma_rxchan_close(rx);
usleep(100*1000);
}
}
return 0;
}