Altera Scatter-Gather DMA (SG-DMA)的简单使用

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Altera Scatter-Gather DMA (SG-DMA)的简单使用

在Quartus7.2之后的版本中,除了原有的基于avalon-mm总线的DMA之外,还增加了Scatter-Gather DMA 这种基于avalon-ST流总线的DMA IP核,它更适合与大量数据流传输的场合,使用起来比较灵活,增加了与外设流器件配合的能力。由于网上关于SG-DMA介绍的资料比较少,因此这里简单介绍一下SG-DMA的使用,利用它可以搭配Altera的千兆网MAC核来实现千兆网方面的应用。

SG-DMA的数据手册已经介绍得非常详细,具体的相关寄存器和功能可能查阅相关手册。Altera为了开发的便利,已经为各个IP核设计好了HAL软件层的代码,SG-DMA也不例外,因此使用的时候我们没有必要逐个配置相关寄存器,直接调用HAL层代码即可。这也是使用这类IP核简便的地方,只是需要清楚这类代码如何调用。

1. 首先我们简单看看SG-DMA的应用环境,从数据手册中截下几张图片简单介绍。

SG-DMA有三种工作方式,可以工作在Memory-to-Stream即存储接口到流接口,或者Stream-to-Memory 即流接口到存储接口,以及Memory-to-Memory的存储器到存储器工作方式。工作在存储器到存储器的工作方式与普通DMA并无差别,没有数据流处理的优势。另外SG-DMA增加了Descriptor Processor,可以实现批量工作,从而进一步减轻Nios处理器的工作。只需要将Descriptor命令字写入到相应的Descriptor memory中。我们简单看看以上的工作方式。

图1. Memory-to-Stream 图2. Stream-to-Memory

图3. Memory-to-Memory

2. 然后我们直接进入主题,看在Altera的SOPC中如何连接使用SG-DMA器件。

M-to-M模式就不做介绍了,这里主要介绍M-to-S和S-to-M这两种方式。我们添加两个SG-DMA器件,让它们分别工作在这两个工作方式下。连接示意如下所示。注意到其中的descriptor memory的设置,原则上只要带有avalon-mm接口的存储器都可以用来做descriptor memroy,因此我们可以将decriptor memory 与主存分离,亦可以直接使用主存的一部分作为descriptor memroy。但为了不影响主存的使用,最好将descriptor memroy分离。另外SG-DMA的有关设置,例如channel和error的位数控制可以参考avalon-st 流接口数据手册,依照需要设置接口。由于在本例中只有一个通道,也不校验错误,所以我们都设置为零。

图4. SOPC连接示意图

3. SG-DMA HAL代码调用。

要使得SG-DMA正式工作起来,我们可以直接调用HAL层代码,省去很多开发时间。下面直接使用一段程序,添加部分注释,相信SG-DMA的基本使用即可完成了,并没有相信中的这么复杂。

#include

#include"altera_avalon_sgdma_descriptor.h"

#include"altera_avalon_sgdma_regs.h"

#include"altera_avalon_sgdma.h"

#include"system.h"

#include"alt_types.h"

//注意包含这几个头文件

alt_sgdma_dev *sgdma_tx_dev; //sgdma_tx设备文件

alt_sgdma_dev *sgdma_rx_dev; //sgdma_rx设备文件

alt_sgdma_descriptor *desc; //descriptor memory指针

char buf[1000]; //SG-DMA传送缓存,暂定1000字节做测试

alt_u32 rx_payload[256]; //SG-DMA接收缓存

void sgdma_rx_isr(void * context, u_long intnum);

//我们的基本思路就是,先配置好sgdma_rx和sgdma_tx的基本配置,然后设置好sgdma_rx的回调函数。

//即接收数据完成之后调用的函数,最后启动sgdma_tx完成dma发送。在这个过程中涵盖了sgdma_tx和sgdma_rx 的基本使用

int main()

{

int i;

int timeout= 0;

for(i=0; i<1000; i++) //填充缓存数据

buf[i]= i%256;

//重定义desc DISCRIPTOR_MEMORY_BASE定义在system.h中,即descriptor_memory的基地址

desc= (alt_sgdma_descriptor*)DISCRIPTOR_MEMORY_BASE;

//打开sgdma_tx和sgdma_rx

sgdma_tx_dev= alt_avalon_sgdma_open(SGDMA_TX_NAME); //SGDMA_TX_NAME定义为"/dev/sgdma_tx"

if(!sgdma_tx_dev)

{

printf("[triple_speed_ethernet_init] Error opening TX SGDMA\n");

return -1;

}

sgdma_rx_dev= alt_avalon_sgdma_open(SGDMA_RX_NAME);

if(!sgdma_rx_dev)

{

printf("[triple_speed_ethernet_init] Error opening RX SGDMA\n");

return -1;

}

/*Reset RX-side SGDMA*/

IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,

ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);

IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,0x0);

/*Reset TX-side SGDMA*/

IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_TX_BASE,0);

IOWR_ALTERA_AVALON_SGDMA_STATUS(SGDMA_TX_BASE,0xFF);

//注册sgdma_rx回调函数

alt_avalon_sgdma_register_callback(

sgdma_rx_dev,

(alt_avalon_sgdma_callback)&sgdma_rx_isr,

(alt_u16)ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK| \

ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK| \

ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK,

相关文档
最新文档