DSP

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

2019-07-13 10:33发布

之前的配置中我们知道如何配置通道速率、设置deviceID。
也就是马路已经铺设好了,我们应该造车了。
搏一搏,单车变摩托!
SRIO不是单车,而是摩托车,我们需要搏一搏,把这个摩托车造出来,在我们已经铺设好的高速路上飞驰。 目录
下面提及的关于LSU寄存器的详细知识,在我的以下两篇博客中都大篇幅详细讲过,如果本文说的不清楚,大家可以看一下我之前的这两篇博客: SRIO学习(六)——Direct I/O 操作(一)
SRIO学习(七)——Direct I/O 操作(二)

一、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 #include #include #include #include /* CSL Chip Functional Layer */ #include #include /* PSC CSL Include Files */ #include #include /* CSL SRIO Functional Layer */ #include #include #include #include #include #include #include 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 "); return; } /* 初始化SRIO */ if (SrioDevice_init() < 0) return; /* SRIO已经能够操作了. */ printf ("SRIO Driver has been initialized "); Lsu0_Init(); /* 从地址0x00000001 发送256bytes数据到 deviceID为0xABCD的设备上的地址0x00000002去 */ SRIO_READ(0x00000001, 256, 0x00000002); } 这里写图片描述
注意图中的包类型指的是Ftype的值,而不是最前面的标号。 SRIO配置文件下载:
device_srio_loopback.c 这样,我们的摩托也完成了,摩托可以载着货物在高速上飞奔了,但是有时候来了个电话,你必须停下来,那要怎么停下来呢?,请看下章——中断系统。 参考文献
http://www.ti.com/cn/litv/pdf/sprugw1b
PS:欢迎大家与我讨论文章中的问题,包括反对我的观点。 本章特别致谢:感谢北航的王悦人学长在我什么都不懂的时候耐心回答我的萌新问题。