在 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的基本使用即可完成了,并没有相信中的这么复杂。

  1. #include <stdio.h>
  2. #include "altera_avalon_sgdma_descriptor.h"
  3. #include "altera_avalon_sgdma_regs.h"
  4. #include "altera_avalon_sgdma.h"
  5. #include "system.h"
  6. #include "alt_types.h"
  7. //注意包含这几个头文件
  8. alt_sgdma_dev *sgdma_tx_dev; //sgdma_tx设备文件
  9. alt_sgdma_dev *sgdma_rx_dev; //sgdma_rx设备文件
  10. alt_sgdma_descriptor *desc; //descriptor memory指针
  11. char buf[1000]; //SG-DMA传送缓存,暂定1000字节做测试
  12. alt_u32 rx_payload[256]; //SG-DMA接收缓存
  13. void sgdma_rx_isr(void * context, u_long intnum);
  14. //我们的基本思路就是,先配置好sgdma_rx和sgdma_tx的基本配置,然后设置好sgdma_rx的回调函数。
  15. //即接收数据完成之后调用的函数,最后启动sgdma_tx完成dma发送。在这个过程中涵盖了sgdma_tx和sgdma_rx的基本使用
  16. int main()
  17. {
  18. int i;
  19. int timeout = 0;
  20. for(i=0; i<1000; i++) //填充缓存数据
  21. buf[i] = i%256;
  22. //重定义desc DISCRIPTOR_MEMORY_BASE定义在system.h中,即descriptor_memory的基地址
  23. desc = (alt_sgdma_descriptor *)DESC_MEM_BASE;
  24. //打开sgdma_tx和sgdma_rx
  25. sgdma_tx_dev = alt_avalon_sgdma_open("/dev/tx_sgdma");
  26. if(!sgdma_tx_dev)
  27. {
  28. printf("[triple_speed_ethernet_init] Error opening TX SGDMA\n");
  29. return -1;
  30. }
  31. sgdma_rx_dev = alt_avalon_sgdma_open("/dev/rx_sgdma");
  32. if(!sgdma_rx_dev)
  33. {
  34. printf("[triple_speed_ethernet_init] Error opening RX SGDMA\n");
  35. return -1;
  36. }
  37. /* Reset RX-side SGDMA */
  38. IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
  39. IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, 0x0);
  40. /* Reset TX-side SGDMA */
  41. IOWR_ALTERA_AVALON_SGDMA_CONTROL(TX_SGDMA_BASE, 0);
  42. IOWR_ALTERA_AVALON_SGDMA_STATUS(TX_SGDMA_BASE, 0xFF);
  43. //注册sgdma_rx回调函数
  44. alt_avalon_sgdma_register_callback(
  45. sgdma_rx_dev,
  46. (alt_avalon_sgdma_callback) &sgdma_rx_isr,
  47. //ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK | //每个描述符数据传输完产生中断
  48. ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK | //所有描述符数据传输完时产生中断
  49. ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK //开中断
  50. ,
  51. 0);
  52. //填充接收decriptor memory 并不需要自己填充,调用函数就好了。
  53. alt_avalon_sgdma_construct_stream_to_mem_desc(
  54. &desc[0], //主描述字
  55. &desc[1], //次描述字
  56. rx_payload, //接收地址
  57. 0, //length,为0时当收到EOP时结束
  58. 0); //write_fixed
  59. //填充发送decriptor memory
  60. alt_avalon_sgdma_construct_mem_to_stream_desc(
  61. &desc[2], //主描述字
  62. &desc[3], //次描述字
  63. (unsigned int*)buf, //发送指针
  64. (256), //发送字数
  65. 0, //read_fixed
  66. 0, //不发送SOP
  67. 0, //不发送EOP
  68. 0); //暂不支持
  69. alt_avalon_sgdma_construct_mem_to_stream_desc(
  70. &desc[3], //主描述字
  71. &desc[4], //次描述字
  72. (unsigned int*)(buf+256), //发送指针
  73. (256), //发送字数
  74. 0,
  75. 1, //发送SOP
  76. 1, //发送EOP
  77. 0);
  78. //启动sgdma_rx和sgdma_tx
  79. alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);
  80. alt_avalon_sgdma_do_sync_transfer(sgdma_tx_dev, &desc[2]);
  81. for(i=0; i<256; i++)
  82. printf("%x ",rx_payload[i]);
  83. printf("\n\n\n\n");
  84. }
  85. //回调函数,负责处理接收后数据,并重置sgdma_rx,本例中并未对数据进行处理
  86. void sgdma_rx_isr(void * context, u_long intnum)
  87. {
  88. int i;
  89. alt_sgdma_descriptor *currdescriptor_ptr = &desc[0];
  90. if(alt_avalon_sgdma_check_descriptor_status(&desc[0])==0)
  91. {
  92. printf("RX descriptor reported OK\n");
  93. }
  94. else
  95. {
  96. printf("RX descriptor reported error\n");
  97. }
  98. }

或者也可以这样

  1. #include <stdio.h>
  2. #include "altera_avalon_sgdma_descriptor.h"
  3. #include "altera_avalon_sgdma_regs.h"
  4. #include "altera_avalon_sgdma.h"
  5. #include "system.h"
  6. #include "alt_types.h"
  7. //注意包含这几个头文件
  8. alt_sgdma_dev *sgdma_tx_dev; //sgdma_tx设备文件
  9. alt_sgdma_dev *sgdma_rx_dev; //sgdma_rx设备文件
  10. alt_sgdma_descriptor *desc; //descriptor memory指针
  11. char buf[1000]; //SG-DMA传送缓存,暂定1000字节做测试
  12. alt_u32 rx_payload[256]; //SG-DMA接收缓存
  13. void sgdma_rx_isr(void * context, u_long intnum);
  14. //我们的基本思路就是,先配置好sgdma_rx和sgdma_tx的基本配置,然后设置好sgdma_rx的回调函数。
  15. //即接收数据完成之后调用的函数,最后启动sgdma_tx完成dma发送。在这个过程中涵盖了sgdma_tx和sgdma_rx的基本使用
  16. int main()
  17. {
  18. int i;
  19. int timeout = 0;
  20. for(i=0; i<1000; i++) //填充缓存数据
  21. buf[i] = i%256;
  22. //重定义desc DISCRIPTOR_MEMORY_BASE定义在system.h中,即descriptor_memory的基地址
  23. desc = (alt_sgdma_descriptor *)DESC_MEM_BASE;
  24. //打开sgdma_tx和sgdma_rx
  25. sgdma_tx_dev = alt_avalon_sgdma_open("/dev/tx_sgdma");
  26. if(!sgdma_tx_dev)
  27. {
  28. printf("[triple_speed_ethernet_init] Error opening TX SGDMA\n");
  29. return -1;
  30. }
  31. sgdma_rx_dev = alt_avalon_sgdma_open("/dev/rx_sgdma");
  32. if(!sgdma_rx_dev)
  33. {
  34. printf("[triple_speed_ethernet_init] Error opening RX SGDMA\n");
  35. return -1;
  36. }
  37. /* Reset RX-side SGDMA */
  38. IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
  39. IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, 0x0);
  40. /* Reset TX-side SGDMA */
  41. IOWR_ALTERA_AVALON_SGDMA_CONTROL(TX_SGDMA_BASE, 0);
  42. IOWR_ALTERA_AVALON_SGDMA_STATUS(TX_SGDMA_BASE, 0xFF);
  43. //注册sgdma_rx回调函数
  44. alt_avalon_sgdma_register_callback(
  45. sgdma_rx_dev,
  46. (alt_avalon_sgdma_callback) &sgdma_rx_isr,
  47. //ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK | //每个描述符数据传输完产生中断
  48. ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK | //所有描述符数据传输完时产生中断
  49. ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK //开中断
  50. ,
  51. 0);
  52. //填充接收decriptor memory 并不需要自己填充,调用函数就好了。
  53. alt_avalon_sgdma_construct_stream_to_mem_desc(
  54. &desc[0], //主描述字
  55. &desc[1], //次描述字
  56. rx_payload, //接收地址
  57. 0, //length,为0时当收到EOP时结束
  58. 0); //write_fixed
  59. //填充发送decriptor memory
  60. alt_avalon_sgdma_construct_mem_to_stream_desc(
  61. &desc[2], //主描述字
  62. &desc[3], //次描述字
  63. (unsigned int*)buf, //发送指针
  64. (256), //发送字数
  65. 0, //read_fixed
  66. 0, //不发送SOP
  67. 1, //发送EOP
  68. 0); //暂不支持
  69. alt_avalon_sgdma_construct_mem_to_stream_desc(
  70. &desc[3], //主描述字
  71. &desc[4], //次描述字
  72. (unsigned int*)(buf+256), //发送指针
  73. (256), //发送字数
  74. 0,
  75. 1, //发送SOP
  76. 1, //发送EOP
  77. 0);
  78. //启动sgdma_rx和sgdma_tx
  79. alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);
  80. alt_avalon_sgdma_do_sync_transfer(sgdma_tx_dev, &desc[2]);
  81. for(i=0; i<256; i++)
  82. printf("%x ",rx_payload[i]);
  83. printf("\n\n\n\n");
  84. }
  85. //回调函数,负责处理接收后数据,并重置sgdma_rx,本例中并未对数据进行处理
  86. void sgdma_rx_isr(void * context, u_long intnum)
  87. {
  88. int i;
  89. alt_sgdma_descriptor *currdescriptor_ptr = &desc[0];
  90. if(alt_avalon_sgdma_check_descriptor_status(&desc[0])==0)
  91. {
  92. printf("RX descriptor reported OK\n");
  93. }
  94. else
  95. {
  96. printf("RX descriptor reported error\n");
  97. }
  98. alt_avalon_sgdma_construct_stream_to_mem_desc(
  99. &desc[0], //主描述字
  100. &desc[1], //次描述字
  101. rx_payload+64, //接收地址
  102. 0, //length,为0时当收到EOP时结束
  103. 0); //write_fixed
  104. // Re-start SGDMA (always, if we have a single descriptor)
  105. alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);
  106. }

nios sgdma(Scatter-Gather dma)示例的更多相关文章

  1. JAVA NIO Scatter/Gather(矢量IO)

    矢量IO=Scatter/Gather:   在多个缓冲区上实现一个简单的IO操作.减少或避免了缓冲区拷贝和系统调用(IO)   write:Gather 数据从几个缓冲区顺序抽取并沿着通道发送,就好 ...

  2. 转:Java NIO系列教程(四) Scatter/Gather

    Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作.分散(sc ...

  3. java的nio之:java的nio系列教程之Scatter/Gather

    一:Java NIO的scatter/gather应用概念 ===>Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Chann ...

  4. Java基础知识强化之IO流笔记75:NIO之 Scatter / Gather

    1. Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作. 分 ...

  5. Java NIO中的通道Channel(二)分散/聚集 Scatter/Gather

    什么是Scatter/Gather scatter/gather指的在多个缓冲区上实现一个简单的I/O操作,比如从通道中读取数据到多个缓冲区,或从多个缓冲区中写入数据到通道: scatter(分散): ...

  6. NIO相关概念之Scatter / Gather

    Scatter /Gather 是java NIO中用来对channel的读取或者写入操作的特殊的形式的描述 Scatter(发散) 是指在读操作的时候,从chanel读取到的数据,写入到多个buff ...

  7. Java NIO系列教程(四) Scatter/Gather

    Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作.分散(sc ...

  8. 【Java NIO的深入研究6】JAVA NIO之Scatter/Gather

    Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作. 分散(s ...

  9. Java NIO(四) Scatter/Gather

    Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作.分散(sc ...

随机推荐

  1. Microsoft Visual Studio 2015打开TFS大量报错问题解决方案

    用vs2015打开项目出现如图错误,尝试对XX项执行 添加 操作时遇到 XX 个错误,因为公司项目比较大,这个错误一直在弹,搜索了下,没有找到出现类似问题的解决方案. 因为这个路径是TFS(Team ...

  2. 学习爬虫:《Python网络数据采集》中英文PDF+代码

    适合爬虫入门的书籍<Python网络数据采集>,采用简洁强大的Python语言,介绍了网络数据采集,并为采集新式网络中的各种数据类型提供了全面的指导.第一部分重点介绍网络数据采集的基本原理 ...

  3. 数组中出现一次的两个数(三个数)& 求最后一位bit为1

    对于两个数,对于结果中,剩余bit1来异或区分. 下面的解法,非常精简: int lastBitOf1(int number) { ); } void getTwoUnique(vector<i ...

  4. lower_bound与upper_bound

    昨天一道题目用了lower_bound,大致了解了lower_bound指的是第一个>=x的位置.但是之前对于upper_bound有误解,其实upper_bound指的是第一个>x的位置 ...

  5. Axure7.0在OS X Yosemite(10.10)中不能用的问题

    电脑升级到了10.10后发现axure7.0不能使用.解决办法也非常easy,就是又一次下载一个新的axure版本号,下载地址:http://www.axure.com/release-candida ...

  6. C# 蚁群优化算法实现

    C# 蚁群优化算法实现 需求为(自己编的,非实际项目): 某配送中心进行揽货,目标客户数为50个客户,配送中心目前的运力资源如下: 现有车辆5台 单台运力最大行驶距离200千米 单台运力最大载重公斤1 ...

  7. Xfce4里添加登录后程序自动运行

    Xfce4里添加登录后程序自动运行 (注意该方法在登录桌面环境后才会自动运行程序. 在XUbuntu下测试过, Ubuntu下应该是类似的) 方法1: 找到这个东西, 自动添加一下 方法2: 在 .c ...

  8. BZOJ 4551 HEOI 2016 树 (并查集)

    思路: 考虑时光倒流 这不就是并查集裸题了-----. //By SiriusRen #include <cstdio> #include <cstring> #include ...

  9. Android 自定义的开关按钮——SwitchButton

    本文转自:http://blog.csdn.net/swust_chenpeng/article/details/19967501 我将原文的控件进行了一些修改,去掉了原来控件的外边框,只留下重要的遮 ...

  10. net实现ping的方法

    class ServicePinger { private static readonly ILog log = LogManager.GetLogger(typeof(ServicePinger)) ...