当前位置:首页 >> 信息与通信 >>

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


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<stdio.h> #include"altera_avalon_sgdma_descriptor.h" #include"altera_avalon_sgdma_regs.h" #include"altera_avalon_sgdma.h" #include"system.h" #include"alt_types.h" //注意包含这几个头文件 *sgdma_tx_dev; //sgdma_tx 设备文件 *sgdma_rx_dev; //sgdma_rx 设备文件 *desc; //descriptor memory 指针 //SG-DMA 传送缓存,暂定1000字节做测试 //SG-DMA 接收缓存

alt_sgdma_dev alt_sgdma_dev

alt_sgdma_descriptor

char buf[1000]; alt_u32 rx_payload[256];

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= "/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; } alt_avalon_sgdma_open(SGDMA_TX_NAME); //SGDMA_TX_NAME 定 义 为 //填充缓存数据

/* 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,

0); //填充发送 decriptor memory 并不需要自己填充,调用函数就好了。 alt_avalon_sgdma_construct_stream_to_mem_desc( &desc[0], &desc[1], rx_payload, 0, 0); //填充接收 decriptor memory alt_avalon_sgdma_construct_mem_to_stream_desc( &desc[2], &desc[3], //主描述字 //次描述字 //主描述字 //次描述字

(unsignedint*)buf, //发送指针 (256), 0, 1, 1, 0); //启动 sgdma_rx 和 sgdma_tx alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev,&desc[0]); alt_avalon_sgdma_do_sync_transfer(sgdma_tx_dev,&desc[2]); } //发送字数

//回调函数,负责处理接收后数据,并重置 sgdma_rx,本例中并未对数据进行处理 void sgdma_rx_isr(void * context, u_long intnum); { int sgdma_status= IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE); alt_sgdma_descriptor *currdescriptor_ptr= &desc[0];

if(sgdma_status& (ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK| ALTERA_AVALON_SGDMA_STATUS_DESC_COMPLETED_MSK) ) { desc_status= IORD_ALTERA_TSE_SGDMA_DESC_STATUS(currdescriptor_ptr); if( (desc_status& (ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK| ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK| ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK| ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK| ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK| ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK| ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK ) )== 0) {

printf("RX descriptor reported OK\n"); } else { printf("RX descriptor reported error\n"); } IOWR_32DIRECT(&(currdescriptor_ptr->write_addr),0, (alt_u32)(rx_payload));

IOWR_32DIRECT(&(currdescriptor_ptr->actual_bytes_transferred),0, (alt_u32) ((ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK| ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK)<< 24) );

// Re-start SGDMA (always, if we have a single descriptor) alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev,&desc[0]); } }

http://www.cnblogs.com/scnutiger/archive/2010/02/06/1664980.html



相关文章:
更多相关标签: