SG DMA与普通DMA(block DMA)的区别

时间:2022-12-31 00:16:52

一、Scatter-gather DMA方式是与block DMA方式相对应的一种DMA方式。在DMA传输数据的过程中,要求源物理地址和目标物理地址必须是连续的。但是在某些计算机体系中,如IA架构,连续的存储器地址在物理上不一定是连续的,所以DMA传输要分成多次完成。如果在传输完一块物理上连续的数据后引起一次中断,然后再由主机进行下一块物理上连续的数据传输,那么这种方式就为block DMA方式。Scatter-gather DMA方式则不同,它使用一个链表描述物理上不连续的存储空间,然后把链表首地址告诉DMA master。DMA master在传输完一块物理连续的数据后,不用发起中断,而是根据链表来传输下一块物理上连续的数据,直到传输完毕后再发起一次中断。很显然,scatter-gather DMA方式比block DMA方式效率高。

二、其工作方式差异性也主要体现在以下几个方面

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

 

SG DMA与普通DMA(block DMA)的区别

图1. Memory-to-Stream

SG DMA与普通DMA(block DMA)的区别

图2. Stream-to-Memory

SG DMA与普通DMA(block DMA)的区别

图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流接口数据手册,依照需要设置接口。由于在本例中只有一个通道,也不校验错误,所以我们都设置为零。

SG DMA与普通DMA(block DMA)的区别

图4. SOPC连接示意图

要使得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.   
  9. alt_sgdma_dev    *sgdma_tx_dev;  //sgdma_tx设备文件  
  10. alt_sgdma_dev    *sgdma_rx_dev;  //sgdma_rx设备文件  
  11. alt_sgdma_descriptor    *desc;        //descriptor memory指针  
  12.   
  13. char buf[1000];                         //SG-DMA传送缓存,暂定1000字节做测试  
  14. alt_u32 rx_payload[256];         //SG-DMA接收缓存  
  15.   
  16. void sgdma_rx_isr(void * context, u_long intnum);  
  17. //我们的基本思路就是,先配置好sgdma_rx和sgdma_tx的基本配置,然后设置好sgdma_rx的回调函数。  
  18. //即接收数据完成之后调用的函数,最后启动sgdma_tx完成dma发送。在这个过程中涵盖了sgdma_tx和sgdma_rx的基本使用  
  19. int main()  
  20. {  
  21.     int i;  
  22.     int timeout = 0;  
  23.     for(i=0; i<1000; i++)   //填充缓存数据  
  24.         buf[i] = i%256;  
  25.   
  26.      //重定义desc DISCRIPTOR_MEMORY_BASE定义在system.h中,即descriptor_memory的基地址  
  27.     desc = (alt_sgdma_descriptor *)DISCRIPTOR_MEMORY_BASE;  
  28.   
  29.     //打开sgdma_tx和sgdma_rx  
  30.     sgdma_tx_dev = alt_avalon_sgdma_open(SGDMA_TX_NAME);  //SGDMA_TX_NAME定义为"/dev/sgdma_tx"  
  31.     if(!sgdma_tx_dev)   
  32.     {  
  33.         printf("[triple_speed_ethernet_init] Error opening TX SGDMA\n");  
  34.         return -1;  
  35.     }  
  36.     sgdma_rx_dev = alt_avalon_sgdma_open(SGDMA_RX_NAME);  
  37.     if(!sgdma_rx_dev)   
  38.     {  
  39.         printf("[triple_speed_ethernet_init] Error opening RX SGDMA\n");  
  40.         return -1;  
  41.     }  
  42.       
  43.     /* Reset RX-side SGDMA */  
  44.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE, ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);  
  45.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE, 0x0);  
  46.     /* Reset TX-side SGDMA */  
  47.     IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_TX_BASE, 0);  
  48.     IOWR_ALTERA_AVALON_SGDMA_STATUS(SGDMA_TX_BASE, 0xFF);  
  49.   
  50.     //注册sgdma_rx回调函数  
  51.     alt_avalon_sgdma_register_callback(  
  52.              sgdma_rx_dev,  
  53.              (alt_avalon_sgdma_callback) &sgdma_rx_isr,  
  54.              (alt_u16)ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK | \  
  55.                             ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK | \   
  56.                             ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK,  
  57.              0);  
  58.   
  59.     //填充发送decriptor memory 并不需要自己填充,调用函数就好了。  
  60.     alt_avalon_sgdma_construct_stream_to_mem_desc(  
  61.                         &desc[0],             //主描述字  
  62.                         &desc[1],             //次描述字  
  63.                         rx_payload,  
  64.                         0,  
  65.                         0);  
  66.     //填充接收decriptor memory   
  67.     alt_avalon_sgdma_construct_mem_to_stream_desc(  
  68.                         &desc[2],                 //主描述字  
  69.               &desc[3],                 //次描述字  
  70.               (unsigned int*)buf,  //发送指针  
  71.                         (256),                       //发送字数  
  72.                         0,  
  73.                         1,   
  74.                         1,  
  75.                         0);  
  76.   
  77.     //启动sgdma_rx和sgdma_tx  
  78.     alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);  
  79.     alt_avalon_sgdma_do_sync_transfer(sgdma_tx_dev, &desc[2]);  
  80. }  
  81.   
  82. //回调函数,负责处理接收后数据,并重置sgdma_rx,本例中并未对数据进行处理  
  83. void sgdma_rx_isr(void * context, u_long intnum);  
  84. {  
  85.     int sgdma_status = IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE);  
  86.     alt_sgdma_descriptor  *currdescriptor_ptr = &desc[0];  
  87.       
  88.     if(sgdma_status & (ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK |   
  89.                      ALTERA_AVALON_SGDMA_STATUS_DESC_COMPLETED_MSK) )   
  90.     {  
  91.         desc_status = IORD_ALTERA_TSE_SGDMA_DESC_STATUS(currdescriptor_ptr);  
  92.         if( (desc_status &   
  93.               (ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK |   
  94.                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK |   
  95.                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK |  
  96.                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK |   
  97.                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK |   
  98.                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK |   
  99.                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK ) ) == 0)  
  100.         {  
  101.             printf("RX descriptor reported OK\n");  
  102.         }          
  103.         else   
  104.         {  
  105.             printf("RX descriptor reported error\n");  
  106.         }  
  107.         IOWR_32DIRECT(&(currdescriptor_ptr->write_addr), 0,   
  108.                 (alt_u32)(rx_payload));               
  109.   
  110.         IOWR_32DIRECT(&(currdescriptor_ptr->actual_bytes_transferred), 0,   
  111.                 (alt_u32) ((ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK |  
  112.                       ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK) << 24) );  
  113.           
  114.         // Re-start SGDMA (always, if we have a single descriptor)  
  115.         alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, &desc[0]);  
  116.     }  



没有符合的翻译结果!

请确认选中的文本是完整的单词或句子。

目前仅谷歌翻译支持汉译英。