千兆网接口学习之-------SG-DMA的使用

       

        DMA分两种,一个是普通的,另一个就是SG-DMA了。


        先介绍一下Altera的总线互联模式,Altera一共自己定义了三种总线互联方式。一种是Avalon-MM,这个跟我们通常说的CPU总线很类似了,有读写信号,地址,片选等;另外一种是Avalon-ST,没有地址线,是基于数据包传输的一种高速接口,俗一点说就是FIFO接口;还有一种是Atlantic接口,这个接口用到的很少,有少数的IP核(比如说SPI4.2)用了这个接口,这个接口跟Avalon-ST接口很像,也是基于FIFO的这种互联模式。

       普通的DMA就是读写端都是Avalon-MM总线。

 
       SG-DMA呢,就是可以做Avalon-MM到Avalon-ST,Avalon-ST到Avalon-ST的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. 然后我们直接进入主题,看在AlteraSOPC中如何连接使用SG-DMA器件。

M-to-M模式就不做介绍了,这里主要介绍M-to-SS-to-M这两种方式。我们添加两个SG-DMA器件,让它们分别工作在这两个工作方式下。连接示意如下所示。注意到其中的descriptor memory的设置,原则上只要带有avalon-mm接口的存储器都可以用来做descriptor memroy,因此我们可以将decriptor memory与主存分离,亦可以直接使用主存的一部分作为descriptor memroy。但为了不影响主存的使用,最好将descriptor memroy分离。另外SG-DMA的有关设置,例如channelerror的位数控制可以参考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"
//注意包含这几个头文件

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_rxsgdma_tx的基本配置,然后设置好sgdma_rx的回调函数。
//
即接收数据完成之后调用的函数,最后启动sgdma_tx完成dma发送。在这个过程中涵盖了sgdma_txsgdma_rx的基本使用
int main()
{
  
inti;
  
inttimeout= 0;
  
for(i=0; i<1000; i++)  //填充缓存数据
        buf[i]= i%256;

   
//重定义descDISCRIPTOR_MEMORY_BASE定义在system.h中,即descriptor_memory的基地址
    desc= (alt_sgdma_descriptor*)DISCRIPTOR_MEMORY_BASE;

  
//打开sgdma_txsgdma_rx
    sgdma_tx_dev= alt_avalon_sgdma_open(SGDMA_TX_NAME); //SGDMA_TX_NAME定义为"/dev/sgdma_tx"
   if(!sgdma_tx_dev)
    
{
        printf("[triple_speed_ethernet_init] Error opening TXSGDMA\n");
      
return-1;
   
}
    sgdma_rx_dev= alt_avalon_sgdma_open(SGDMA_RX_NAME);
  
if(!sgdma_rx_dev)
    
{
        printf("[triple_speed_ethernet_init] Error opening RXSGDMA\n");
      
return-1;
   
}
  
    /*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);

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

  
//启动sgdma_rxsgdma_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);
{
  
intsgdma_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 singledescriptor)
       alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev,&desc[0]);
 
  }
}

转载自:

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

 

 

在本系统中是和Triple_Speed_ethernet的IP核配合使用,所以SGDMA必须成对出现,作为接受和发送的空间,下图是自己的系统。

 

 

 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值