nios sgdma(Scatter-Gather dma)示例
在 Quartus7.2之后的版本中,除了原有的基于avalon-mm总线的DMA之外,还增加了Scatter-Gather DMA这种基于avalon-ST流总线的DMA IP核,它更适合与大量数据流传输的场合,使用起来比较灵活,增加了与外设流器件配合的能力。由于网上关于SG-DMA介绍的资料比较少,因此这里简单介 绍一下SG-DMA的使用,利用它可以搭配Altera的千兆网MAC核来实现千兆网方面的应用。
SG-DMA的 数据手册已经介绍得非常详细(见Scatter-Gather DMA Controller Core
),具体的相关寄存器和功能可能查阅相关手册。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流接口数据手册,依照需要设置接 口。由于在本例中只有一个通道,也不校验错误,所以我们都设置为零。

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"
- //注意包含这几个头文件
- 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 *)DESC_MEM_BASE;
- //打开sgdma_tx和sgdma_rx
- sgdma_tx_dev = alt_avalon_sgdma_open("/dev/tx_sgdma");
- if(!sgdma_tx_dev)
- {
- printf("[triple_speed_ethernet_init] Error opening TX SGDMA\n");
- return -1;
- }
- sgdma_rx_dev = alt_avalon_sgdma_open("/dev/rx_sgdma");
- 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(RX_SGDMA_BASE, ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
- IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, 0x0);
- /* Reset TX-side SGDMA */
- IOWR_ALTERA_AVALON_SGDMA_CONTROL(TX_SGDMA_BASE, 0);
- IOWR_ALTERA_AVALON_SGDMA_STATUS(TX_SGDMA_BASE, 0xFF);
- //注册sgdma_rx回调函数
- alt_avalon_sgdma_register_callback(
- sgdma_rx_dev,
- (alt_avalon_sgdma_callback) &sgdma_rx_isr,
- //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, //length,为0时当收到EOP时结束
- 0); //write_fixed
- //填充发送decriptor memory
- alt_avalon_sgdma_construct_mem_to_stream_desc(
- &desc[2], //主描述字
- &desc[3], //次描述字
- (unsigned int*)buf, //发送指针
- (256), //发送字数
- 0, //read_fixed
- 0, //不发送SOP
- 0, //不发送EOP
- 0); //暂不支持
- alt_avalon_sgdma_construct_mem_to_stream_desc(
- &desc[3], //主描述字
- &desc[4], //次描述字
- (unsigned int*)(buf+256), //发送指针
- (256), //发送字数
- 0,
- 1, //发送SOP
- 1, //发送EOP
- 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]);
- for(i=0; i<256; i++)
- printf("%x ",rx_payload[i]);
- printf("\n\n\n\n");
- }
- //回调函数,负责处理接收后数据,并重置sgdma_rx,本例中并未对数据进行处理
- void sgdma_rx_isr(void * context, u_long intnum)
- {
- int i;
- alt_sgdma_descriptor *currdescriptor_ptr = &desc[0];
- if(alt_avalon_sgdma_check_descriptor_status(&desc[0])==0)
- {
- printf("RX descriptor reported OK\n");
- }
- else
- {
- printf("RX descriptor reported error\n");
- }
- }
或者也可以这样
- #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"
- //注意包含这几个头文件
- 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 *)DESC_MEM_BASE;
- //打开sgdma_tx和sgdma_rx
- sgdma_tx_dev = alt_avalon_sgdma_open("/dev/tx_sgdma");
- if(!sgdma_tx_dev)
- {
- printf("[triple_speed_ethernet_init] Error opening TX SGDMA\n");
- return -1;
- }
- sgdma_rx_dev = alt_avalon_sgdma_open("/dev/rx_sgdma");
- 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(RX_SGDMA_BASE, ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
- IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, 0x0);
- /* Reset TX-side SGDMA */
- IOWR_ALTERA_AVALON_SGDMA_CONTROL(TX_SGDMA_BASE, 0);
- IOWR_ALTERA_AVALON_SGDMA_STATUS(TX_SGDMA_BASE, 0xFF);
- //注册sgdma_rx回调函数
- alt_avalon_sgdma_register_callback(
- sgdma_rx_dev,
- (alt_avalon_sgdma_callback) &sgdma_rx_isr,
- //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, //length,为0时当收到EOP时结束
- 0); //write_fixed
- //填充发送decriptor memory
- alt_avalon_sgdma_construct_mem_to_stream_desc(
- &desc[2], //主描述字
- &desc[3], //次描述字
- (unsigned int*)buf, //发送指针
- (256), //发送字数
- 0, //read_fixed
- 0, //不发送SOP
- 1, //发送EOP
- 0); //暂不支持
- alt_avalon_sgdma_construct_mem_to_stream_desc(
- &desc[3], //主描述字
- &desc[4], //次描述字
- (unsigned int*)(buf+256), //发送指针
- (256), //发送字数
- 0,
- 1, //发送SOP
- 1, //发送EOP
- 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]);
- for(i=0; i<256; i++)
- printf("%x ",rx_payload[i]);
- printf("\n\n\n\n");
- }
- //回调函数,负责处理接收后数据,并重置sgdma_rx,本例中并未对数据进行处理
- void sgdma_rx_isr(void * context, u_long intnum)
- {
- int i;
- alt_sgdma_descriptor *currdescriptor_ptr = &desc[0];
- if(alt_avalon_sgdma_check_descriptor_status(&desc[0])==0)
- {
- printf("RX descriptor reported OK\n");
- }
- else
- {
- printf("RX descriptor reported error\n");
- }
- alt_avalon_sgdma_construct_stream_to_mem_desc(
- &desc[0], //主描述字
- &desc[1], //次描述字
- rx_payload+64, //接收地址
- 0, //length,为0时当收到EOP时结束
- 0); //write_fixed
- // Re-start SGDMA (always, if we have a single descriptor)
- alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);
- }
nios sgdma(Scatter-Gather dma)示例的更多相关文章
- JAVA NIO Scatter/Gather(矢量IO)
矢量IO=Scatter/Gather: 在多个缓冲区上实现一个简单的IO操作.减少或避免了缓冲区拷贝和系统调用(IO) write:Gather 数据从几个缓冲区顺序抽取并沿着通道发送,就好 ...
- 转:Java NIO系列教程(四) Scatter/Gather
Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作.分散(sc ...
- java的nio之:java的nio系列教程之Scatter/Gather
一:Java NIO的scatter/gather应用概念 ===>Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Chann ...
- Java基础知识强化之IO流笔记75:NIO之 Scatter / Gather
1. Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作. 分 ...
- Java NIO中的通道Channel(二)分散/聚集 Scatter/Gather
什么是Scatter/Gather scatter/gather指的在多个缓冲区上实现一个简单的I/O操作,比如从通道中读取数据到多个缓冲区,或从多个缓冲区中写入数据到通道: scatter(分散): ...
- NIO相关概念之Scatter / Gather
Scatter /Gather 是java NIO中用来对channel的读取或者写入操作的特殊的形式的描述 Scatter(发散) 是指在读操作的时候,从chanel读取到的数据,写入到多个buff ...
- Java NIO系列教程(四) Scatter/Gather
Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作.分散(sc ...
- 【Java NIO的深入研究6】JAVA NIO之Scatter/Gather
Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作. 分散(s ...
- Java NIO(四) Scatter/Gather
Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作.分散(sc ...
随机推荐
- 2013-11-02 【webrebuild广州站】分享会纪要
为了不让自己沉浸个人的技术研究当中,也为了多去接触业界新技术新思想,今天去参加了webrebuild广州站的一个分享交流会,效果不错,有一些获益.听了四个主题,依据个人获取信息的情况来做个纪要(比较粗 ...
- HDU-2896 病毒侵袭 字符串问题 AC自动机
题目链接:https://cn.vjudge.net/problem/HDU-2896 题意 中文题 给一些关键词和一个字符串,问字符串里包括了那几种关键词 思路 直接套模版 改insert方法,维护 ...
- MHA搭建及故障维护
MHA是一种方便简单可靠的MySQL高可用架构,具体的介绍我在这里就不多说了,下面是我在网上找的一个教程,我在此基础上进行了一些修改: 大致步骤 (一).环境介绍 (二).用ssh-keygen实现四 ...
- 紫书 例题8-19 UVa 12265 (扫描法+单调栈)
首先可以用扫描法处理出一个height数组, 来保存从当前行开始, 每一个格子可以向上延伸的最大长度. 这种"延伸"的问题用扫描法, 因为往往这个时候可以利用前一次的结果来更新当前 ...
- bzoj 1040 1040: [ZJOI2008]骑士
1040: [ZJOI2008]骑士 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 5210 Solved: 1987[Submit][Status ...
- Qt之QFileIconProvider(根据扩展名获取文件图标、类型)
简述 在Qt之QFileIconProvider一节中已经讲解关于如何获取文件图标与类型.但只仍针对本地已存在的文件,此节,我们主要运用前面分享的内容,讲述如何通过任意后缀或本地不存在的文件来获取相关 ...
- reactor模式与java nio
Reactor是由Schmidt, Douglas C提出的一种模式,在高并发server实现中广泛採用. 改模式採用事件驱动方式,当事件出现时,后调用对应的事件处理代码(Event Handl ...
- 走进Java(一)J2SE
一.Java是什么 Java是Java语言和Java平台的总称.Java语言和C#一样.核心都是oo.并且比較而言,Java做的更好. Java由四方面组成: • Java编程语言,即 ...
- Unity 3D本地公布WebPlayer版时"Failed to download data file"解决方式
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlzZW55YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
- 在Linux的终端中显示BMPString的内容
在上一篇博文中,介绍了怎样在 Windows 的控制台界面下输出 BMPString 的内容,可是那里的方法在 Linux 下不适用.假设将那里的演示样例代码放到 Linux 下运行.输出的结果为乱码 ...