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

  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.     
  38.     /* Reset RX-side SGDMA */
  39.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
  40.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, 0x0);
  41.     /* Reset TX-side SGDMA */
  42.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(TX_SGDMA_BASE, 0);
  43.     IOWR_ALTERA_AVALON_SGDMA_STATUS(TX_SGDMA_BASE, 0xFF);
  44.     //注册sgdma_rx回调函数
  45.     alt_avalon_sgdma_register_callback(
  46.                         sgdma_rx_dev,
  47.                         (alt_avalon_sgdma_callback) &sgdma_rx_isr,
  48.                         //ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK | //每个描述符数据传输完产生中断
  49.                         ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK | //所有描述符数据传输完时产生中断
  50.                         ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK //开中断
  51.                         ,
  52.                         0);
  53.     //填充接收decriptor memory 并不需要自己填充,调用函数就好了。
  54.     alt_avalon_sgdma_construct_stream_to_mem_desc(
  55.                         &desc[0], //主描述字
  56.                         &desc[1], //次描述字
  57.                         rx_payload, //接收地址
  58.                         0, //length,为0时当收到EOP时结束
  59.                         0); //write_fixed
  60.                         
  61.     //填充发送decriptor memory 
  62.     alt_avalon_sgdma_construct_mem_to_stream_desc(
  63.                         &desc[2], //主描述字
  64.                         &desc[3], //次描述字
  65.                         (unsigned int*)buf, //发送指针
  66.                         (256), //发送字数
  67.                         0, //read_fixed
  68.                         0, //不发送SOP
  69.                         0, //不发送EOP
  70.                         0); //暂不支持
  71.                         
  72.     alt_avalon_sgdma_construct_mem_to_stream_desc(
  73.                         &desc[3], //主描述字
  74.                         &desc[4], //次描述字
  75.                         (unsigned int*)(buf+256), //发送指针
  76.                         (256), //发送字数
  77.                         0, 
  78.                         1, //发送SOP
  79.                         1, //发送EOP
  80.                         0); 
  81.     //启动sgdma_rx和sgdma_tx
  82.     alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);
  83.     alt_avalon_sgdma_do_sync_transfer(sgdma_tx_dev, &desc[2]);
  84.     
  85.     for(i=0; i<256; i++)
  86.         printf("%x ",rx_payload[i]);
  87.     printf("\n\n\n\n");
  88. }
  89. //回调函数,负责处理接收后数据,并重置sgdma_rx,本例中并未对数据进行处理
  90. void sgdma_rx_isr(void * context, u_long intnum)
  91. {
  92.     int i;
  93.     alt_sgdma_descriptor *currdescriptor_ptr = &desc[0];
  94.     if(alt_avalon_sgdma_check_descriptor_status(&desc[0])==0)
  95.     {
  96.         printf("RX descriptor reported OK\n");
  97.     } 
  98.     else 
  99.     {
  100.         printf("RX descriptor reported error\n");
  101.     } 
  102.    
  103. }

或者也可以这样

  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.     
  38.     /* Reset RX-side SGDMA */
  39.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
  40.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(RX_SGDMA_BASE, 0x0);
  41.     /* Reset TX-side SGDMA */
  42.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(TX_SGDMA_BASE, 0);
  43.     IOWR_ALTERA_AVALON_SGDMA_STATUS(TX_SGDMA_BASE, 0xFF);
  44.     //注册sgdma_rx回调函数
  45.     alt_avalon_sgdma_register_callback(
  46.                         sgdma_rx_dev,
  47.                         (alt_avalon_sgdma_callback) &sgdma_rx_isr,
  48.                         //ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK | //每个描述符数据传输完产生中断
  49.                         ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK | //所有描述符数据传输完时产生中断
  50.                         ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK //开中断
  51.                         ,
  52.                         0);
  53.     //填充接收decriptor memory 并不需要自己填充,调用函数就好了。
  54.     alt_avalon_sgdma_construct_stream_to_mem_desc(
  55.                         &desc[0], //主描述字
  56.                         &desc[1], //次描述字
  57.                         rx_payload, //接收地址
  58.                         0, //length,为0时当收到EOP时结束
  59.                         0); //write_fixed
  60.                         
  61.     //填充发送decriptor memory 
  62.     alt_avalon_sgdma_construct_mem_to_stream_desc(
  63.                         &desc[2], //主描述字
  64.                         &desc[3], //次描述字
  65.                         (unsigned int*)buf, //发送指针
  66.                         (256), //发送字数
  67.                         0, //read_fixed
  68.                         0, //不发送SOP
  69.                         1, //发送EOP
  70.                         0); //暂不支持
  71.                         
  72.     alt_avalon_sgdma_construct_mem_to_stream_desc(
  73.                         &desc[3], //主描述字
  74.                         &desc[4], //次描述字
  75.                         (unsigned int*)(buf+256), //发送指针
  76.                         (256), //发送字数
  77.                         0, 
  78.                         1, //发送SOP
  79.                         1, //发送EOP
  80.                         0); 
  81.     //启动sgdma_rx和sgdma_tx
  82.     alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);
  83.     alt_avalon_sgdma_do_sync_transfer(sgdma_tx_dev, &desc[2]);
  84.     
  85.     for(i=0; i<256; i++)
  86.         printf("%x ",rx_payload[i]);
  87.     printf("\n\n\n\n");
  88. }
  89. //回调函数,负责处理接收后数据,并重置sgdma_rx,本例中并未对数据进行处理
  90. void sgdma_rx_isr(void * context, u_long intnum)
  91. {
  92.     int i;
  93.     alt_sgdma_descriptor *currdescriptor_ptr = &desc[0];
  94.     if(alt_avalon_sgdma_check_descriptor_status(&desc[0])==0)
  95.     {
  96.         printf("RX descriptor reported OK\n");
  97.     } 
  98.     else 
  99.     {
  100.         printf("RX descriptor reported error\n");
  101.     } 
  102.     
  103.     alt_avalon_sgdma_construct_stream_to_mem_desc(
  104.                         &desc[0], //主描述字
  105.                         &desc[1], //次描述字
  106.                         rx_payload+64, //接收地址
  107.                         0, //length,为0时当收到EOP时结束
  108.                         0); //write_fixed 
  109.     // Re-start SGDMA (always, if we have a single descriptor)
  110.     alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);
  111.     
  112. }

转载于:https://www.cnblogs.com/lueguo/p/3414852.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值