打印
[DSP]

FPGA+DSP SRIO通信(三)——基于LSU的数据传输

[复制链接]
445|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhangmangui|  楼主 | 2019-11-24 21:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、LSU寄存器基本介绍
SRIO用来高速传输大量数据,用的就是LSU,LSU的全称是Load/Store Unit,一共有8个LSU(Load/Store Unit),每个LSU都有自己的7个寄存器,即LSU_REG0-LSU_REG6,REG0-REG4用来存储控制信息,REG5、REG6用来存储命令和状态信息。除了REG6,其它寄存器都是可读可写的,只有REG6有只读和只写两种模式。


所有关于SRIO传输的重要属性都在LSU的7个寄存器中,我们所要做的,就是对这7个寄存器赋上不同的值,以实现我们的目的。对于这7个寄存器的说明,都在我之前的博客里,说的不清楚的地方,在文末的参考文献里有详细说明。


LSU的这7个寄存器就像摩托车的零件,每一个零件都有不同的功能,但是只有组装起来,成为一辆完整的车架,才能有具体功能。


而对于这7个寄存器的赋值,TI官方给出的两种方式,我都提供出来:
1、对每一个寄存器单独赋值,这需要知道每个寄存器的每个域的具体功能,才能得心应手地配置。因为我的ti文件夹安装在c盘,所以我的SRIO文档的路径为:


C:/ti/pdk_C6678_1_1_2_6/packages/ti/csl/docs/doxygen/html/csl__srio_aux_8h.html


该文档中有以下API是用来对每个寄存器单独赋值的(截图):

任意点开上面的一个API,就会有其使用方式,这里我以reg0为例,提供其使用方式:

2、对指定的功能进行编辑
这种配置方式只需要知道一些特定名词,如bytecount,即传输的字节数,dstID,即目的地的deviceID等等。该方式的API也可以在下面的路径中找到。


C:/ti/pdk_C6678_1_1_2_6/packages/ti/csl/docs/doxygen/html/csl__srio_aux_8h.html


下面是一段示例程序,我的工程中采用的就是这种配置方法,简明易懂,也比较推荐这种方法:


    CSL_SrioHandle     hSrio;//声明一个SRIO句柄
    SRIO_LSU_TRANSFER  lsuTransfer;//声明一个LSU传输


    // Open the CSL SRIO Module 0
    hSrio = CSL_SRIO_Open (0);//打开CSL SRIO模块0
    ...
    // 对该LSU传输的信息进行赋值.
    lsuTransfer.rapidIOMSB    = 0x0;
    lsuTransfer.rapidIOLSB    = (Uint32)&tx_buffer[0];
    lsuTransfer.dspAddress    = (Uint32)&rx_buffer[0];
    lsuTransfer.bytecount     = 256;
    lsuTransfer.doorbellValid = 0;
    lsuTransfer.intrRequest   = 1;
    lsuTransfer.supInt        = 0;
    lsuTransfer.xambs         = 0;
    lsuTransfer.priority      = 2;
    lsuTransfer.outPortID     = 1;
    lsuTransfer.idSize        = 1;
    lsuTransfer.srcIDMap      = 0;
    lsuTransfer.dstID         = 0xDEAD;
    lsuTransfer.ttype         = 4;
    lsuTransfer.ftype         = 5;
    lsuTransfer.hopCount      = 0;
    lsuTransfer.doorbellInfo  = 0;


    // 赋值完成之后,用下面的函数完成对整个传输的启动和配置
    CSL_SRIO_SetLSUTransfer (hSrio, 1, &lsuTransfer);
    ...
二、LSU传输流程
知道了如何组装LSU,我们还需要知道LSU具体是如何运作的。关于LSU的运作,我之前的**SRIO学习(六)——Direct I/O 操作(一)也详细说过,具体分3个步骤:


1、查询REG6来确定LSU是否繁忙,如果繁忙则等待,如果不繁忙,则通过对REG6的写入来锁定LSU。
2、对REG0-REG4进行写入,来确定具体传输的目标,地址等信息。
3、对REG5进行写入,写明包类型(Ftype、Ttype),并触发传输。


三、LSU方式_发送代码的实现
综上所述,我们在最终使用LSU传输时,就要融合上面提到的两方面内容,一是LSU寄存器编辑,二是LSU数据传输流程。具体见以下代码:


    /*首先包含一些公共的库,大家用的时候粘贴一下就行*/
    #include <stdio.h>
    #include <stdint.h>
    #include <math.h>
    #include <string.h>
    #include <c6x.h>


    /* CSL Chip Functional Layer */
    #include <ti/csl/csl_chipAux.h>
    #include <ti/csl/csl_chip.h>


    /* PSC CSL Include Files */
    #include <ti/csl/csl_psc.h>
    #include <ti/csl/csl_pscAux.h>


    /* CSL SRIO Functional Layer */
    #include <ti/csl/csl_srio.h>
    #include <ti/csl/csl_srioAux.h>
    #include <ti\csl\csl_srioAuxPhyLayer.h>


    #include <ti/csl/tistdtypes.h>
    #include <ti/csl/cslr_device.h>
    #include <ti/csl/csl_tsc.h>
    #include <ti/csl/csl_cacheAux.h>


    SRIO_LSU_TRANSFER  lsuTransfer0;//声明一个LSU传输对象


    /* 函数名:Lsu0_Init
     * 函数作用:对LSU传输对象LsuTransfer0进行配置
     * 在配置LSU时本身不需要这么多参数,一般只设置几个参数就行,在博客最后我会给出简化版配置  */


    void Lsu0_Init()
    {
        lsuTransfer0.rapidIOMSB    = 0x0;//传输目标地址扩展高32bit域,即如果地址位数比32bit多时,会用到它,一般为0
        //lsuTransfer0.rapidIOLSB    = (unsigned int)0x00100000;//传输目标地址低32bit,一般情况的目标地址就是这个
        //lsuTransfer0.bytecount     = 32768;//LSU传输多少个byte
        //lsuTransfer0.dspaddress    = 0x32c00000;//需要LSU发送的数的地址
        lsuTransfer0.doorbellValid = 0;//是否需要在传输完成后发送doorbell,0表示不需要
        lsuTransfer0.intrRequest   = 1;//传输完成后是否需要产生中断,1表示需要
        lsuTransfer0.supInt        = 0;//是否需要“压制”传输完成后的中断,0表示不压制
        lsuTransfer0.xambs         = 0;//指明扩展地址最高位,一般情况下不需要
        lsuTransfer0.priority      = 0;//LSU传输的优先级,该属性只有在多个LSU传输时才有意义
        lsuTransfer0.outPortID     = 0;//LSU要用哪个port传出,由CPU和nodeID共同决定
        lsuTransfer0.idSize        = 1;//DEVICEID使用8bit还是16bit格式的。1表示使用16bit格式。
        lsuTransfer0.srcIDMap      = 0;//确定在该LSU中使用哪个srcID映射寄存器
        lsuTransfer0.dstID         = 0xABCD;//LSU传输目标的DEVICEID,可以看到这里是16bit格式的
        lsuTransfer0.ttype         = 4;//包的类型由ttype和ftype同时决定,一般主要有写、读、带响应写、带响应读等包类型。具体见参考文献
        lsuTransfer0.ftype         = 2;
        lsuTransfer0.hopCount      = 0;//Hop Count域是为类型8的维护包准备的。
        lsuTransfer0.doorbellInfo  = 0;//DRbll Info域是为类型10的包(doorbell包)准备的。具体包类型见下文中的Table2-23
        }


    /*
     * 函数名:SRIO_READ
     * 函数功能:配置好LSU的源地址、目的地址、传输总字节数,并启动传输
     */


    void SRIO_READ(unsigned int SRC_ADDR,unsigned int BYTES,unsigned int DST_ADDR)
{
        int print = 0;
        unsigned char               context;
        unsigned char               transID;
        unsigned char               count;
        unsigned char               compCode = 1;
        unsigned char               contextBit = 0;
        lsuTransfer0.dspAddress   = SRC_ADDR;
        lsuTransfer0.bytecount    = BYTES;
        lsuTransfer0.rapidIOLSB   = DST_ADDR;
        // 得到LSU背景传输信息
        CSL_SRIO_GetLSUContextTransaction (hSrio, &context, &transID);


        // 在LSU0上启动传输
        CSL_SRIO_SetLSUTransfer (hSrio, 0, &lsuTransfer0);


        // 循环直到LSU传输完成.
        while (1)
        {
            if (CSL_SRIO_IsLSUBusy (hSrio, 0) == FALSE)
                break;
        }
        //得到完成码(调试用)
        CSL_SRIO_GetLSUCompletionCode (hSrio, 1, transID, &compCode, &contextBit);
}


    /*
     * main.c
     */
void main(void) {
    /*
     * 对于函数enable_srio,SrioDevice_init,都在我在上篇**中提到的device_srio_loopback.c文件中,主要就是通道配置和DEVICEID配置,前两篇博客也都讲述过。文末会附上该文件的下载地址。
     */


    /* 给SRIO模块供电 */
    if (enable_srio () < 0)
    {
        printf ("Error: SRIO PSC Initialization Failed\n");
        return;
    }


    /* 初始化SRIO */
    if (SrioDevice_init() < 0)
        return;


    /* SRIO已经能够操作了. */
    printf ("SRIO Driver has been initialized\n");


    Lsu0_Init();


    /* 从地址0x00000001 发送256bytes数据到 deviceID为0xABCD的设备上的地址0x00000002去 */
    SRIO_READ(0x00000001, 256, 0x00000002);
    }

注意图中的包类型指的是Ftype的值,而不是最前面的标号。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:欢迎进入【TI DSP 论坛】 & 【DSP 技术】           TI忠诚粉丝!

935

主题

26376

帖子

589

粉丝