DSP

DSP RF5架构

2019-07-13 14:50发布

RF5是德州仪器TI公司新近推出的DSP软件开发的起步代码参考框架,它以DSP/BIOS为基础,利用其中的数据处理元素和数据通信元素方便快捷地完成DSP软件的设计与开发RF5RF的最新版本,其区别于RF1RF3的显著特点是其支持动态对象创建和支持线程(任务)挂起功能,因此适合系统较复杂的应用场合。    RF5 主要实现三个功能,存储管理,线程模型和通道封装,对于不同的应用,我们只需在这三个元素上做修改,而对于整个应用程序,不用从头设计,这样大大简化了开发者的开发难度,缩短了开发时间。    RF5适用于包含大量的算法,且要求多线程,多通道的应用,如图像处理,多媒体应用等,以Ti提供的实例mpeg2loopback为例,对RF5进行分析。    RF5包含的元素有: 1 线程(Thread)    RF5框架包含四个基本的数据处理元素,处在最顶层的是线程,线程总是顺序的执行所包含的通道,线程在一个比较高级的级别上把数据组织在一起,他们可以与别的线程,设备驱动以及别的类似结构进行通讯,在mpeg2lookback实例中,创建了三个线程分别是tskVideoInputtskVideoOutputtskProcess。每个线程都在不断的等待消息,处理数据,并将结果发送给其他的线程,同时有可能还要发送同步消息给其他线程已实现线程间的通讯,这里使用的机制是SCOM模块。      每个线程都是进行数据处理的一个单元,有的是处理简单的,有的处理是相对复杂的过程,简单的线程可以不包括任何的通道,而进行复杂数据处理的线程有可能包含多个的通道。 2 通道(Channel):        RF5提供了一种通道结构是为了更方便的封装算法,这可以理解通道为并行里的串行,因为线程的执行就是由通道的串行执行来完成的,一个通道包含一组核(Icell),其主要任务就是依次顺序的执行所包含的核,主要执行的流程为:首先需要初始化通道模块,然后建立通道对象,注册该通道所包含的核对象,接着依次执行每个核,执行完成了后就销毁对象,最后退出。每个通道可以包含多个核,每个核都要进行初始化后在调用CHAN_regCell注册。 通道对象的结构如下: typedef struct CHAN_Obj {
      ICELL_Obj *cellSet;           /* set of cells in the channel */
      Uns cellCnt;                  /* number of cells in the cellSet */
      CHAN_State state;             /* state of the channel */
      Bool (*chanControlCB)(CHAN_Handle chanHandle); /* optional control function */
} CHAN_Obj;
     
线程一般不定义通道对象,但是在CHAN_open()调用中初始化它们。CHAN_open()的最后一个参数是通道属性(CHAN_Attrs)结构体的地址。如果最后一个参数是NULL,那么CHAN_open()使用默认的参数。如果要想使用不同的参数,就要声明一个CHAN_Attrs的结构体,并需初始化为CHAN_ATTRS宏所定义的初值,然后根据需要可以修改其中相应的域的值,通常,其中的通道状态参数CHAN_State state域默认为CHAN_ACTIVE,以及通道控制回调函数参数域Bool (*chanControlCB)(CHAN_Handle chanHandle)默认为NULL。如果通道控制回调函数不是空,那么在任何的cell调用执行之前都会先调用此回调函数。

    一个典型的设置,一个线程为每一个通道建立一个CHAN_Obj对象(或者一组类似的对象),并且为每一个cell建立一个ICELL_Obj对象(或者是与每个通道相对应的一组ICCE_Obj对象).在线程初始化ICELL_Obj之后就会调用下面的函数:
备注其中的cell 指向cell 对象的指针, inputIcc/outputIcc是相应的cell ICC 对象,这个调用计算单元需要的空间,并分配给定的ICC对象给单元cell
   CHAN_regCell( cell, inputIcc, 1, outputIcc, 1 );
   当所有的cells都已经创建并初始化之后,线程调用CHAN_open()函数来为每一个指定的通道(chanNum)传递cell对象(cellList)。这个函数创建所有的XDAIS算法,并且如果单元细胞定义了cellOpen函数,则会调用每一个单元细胞的cellOpen函数
,.
   
CHAN_open( chanList[ chanNum ], cellList, numCells, NULL/* default attributes */ );
最后,在运行时,线程为每一个通道(chanNum)调用CHAN_execute函数开始执行:

   CHAN_execute( chanList[ chanNum ], NULL /* arg to cells */ ); 3 核(Icell):      核实际上就是ICELL接口对象,基于RF5的应用常常包含大量的算法和通道,为了便于算法集中到应用中,RF5提出了核的概念,一个核就是包含一种XDAIS算法的容器,一个RF5通道对象可以包含多个核,也即是包含多个算法,通道通过核来调用算法,实际上,真正的数据处理是在XDAIS算法,核只是提供一个调用算法的接口,这大大简化了工作量,便于移植。      该接口包含一个重要的结构:ICELL_Fxns,该结构包含一组函数指针。通道通过调用这些函数来调用算法,其中包含一个关键的函数cellExecute,这个函数的功能是调用XDAIS算法来执行,上面的通道执行函数CHAN_execute就包含了每个cellExecute的调用。 4 ICC模块        ICC模块是用来管理在核之间以及核与其他线程之间的数据通讯,我们知道线程间的数据传输是通过SCOM模块来实现的,每个ICC模块管理一个或者多个ICC对象,每个核都有一组输入和输出ICC对象。这些对象是通过CHAN_regCell()来注册到相应的通道里。 5 同步通讯机制(SCOM)        ThrProcess中包含两个SCOM对象,RF5使用SCOM对象来实现线程的通讯。SCOM消息时用户自定义的一个机构,一个线程通过调用SCOM_putMsg()函数将SCOM消息放置一个SCOM队列中,发送给其他的线程,或者通过调用SCOM_getMsg()函数从队列中获取消息,一般情况下,发送消息指明接收线程所要读取的数据缓冲区的地址(以指针形式),接收消息指明发送线程所要写入的数据缓冲区的地址,在mape2loopback实例中,thrProcess要从thraVideoInput接收消息,并发送消息给thrVideoOutput输出图像。RF5使用SCOM来实现线程间的通讯:thrProcess拥有一些缓冲区,需要thrVideoInput写或thrVideoOutput读,所以thrProcess通过SCOM告诉thrVideoIputthrVideoOutput线程数据缓冲区的地址,同时还要保证两个线程不会同时访问同一个缓冲区。thrProcess创建了两种消息以分别和两个线程进行通讯,scomMsgRxscomMsgTx,scomMsgRx指定了被thrVideoInput写的缓冲区地址,scomMsgTx指定了被thrVideoOutput读的缓冲区地址。      在实际的操作中,可是将SCOM看作是种同步标记,她用来区分模块内存是否正在被其他线程所使用,这样就可以放置内存访问的冲突。整个系统中包含很多存储区,这些内存区很有可能在某一时刻正在被某一线程访问,为了保证在任意时刻只有一个线程访问某一块内存,当前正在访问这一内存块的线程通过发送SCOM消息给与这一内存块有关联的线程,告诉他,我正在访问呢,你等会再来吧。当他访问完后,放弃了这一内存块的占有权,再通过SCOM消息告诉相关联的线程,我用完了,你可以用了。于是相关联的线程就可以访问了。 6 ALGRF模块算法的实例化Algorithm Instantiation ALGRF ModuleDSP/BIOSMEM内存管理器来创建和删除XDAIS算法的模块。参考框架服务简化XDAIS部件的使用。所有符合XDAIS标准的算法都必须使用一个标准的接口——IALG接口。ALGRF使用算法的IALG来实现对XDAIS算法的实例化。任何符合XDAIS标准的算法都可以被ALGRF所使用。 用户代码不必直接的调用ALGRF函数,这个工作由CHAN和其他的库函数来完成。例外的是cell wrappers中的ALGRF_activate/deactivate序列化:如果cell中的XDAIS算法执行IALG_active/deactivate函数,细胞需要调用两个ALGRF函数来完成。 三个模块来简化IALG接口创建算法对象,RF5使用ALGRF模块来创建,配置,删除XDAIS算法实例。ALG模块使用CCStudio作为通用目的使用,并且不用DSP/BIOS MEM模块分配内存.ALGMIN是三个中的最小应用。 一般情况下,三个模块是相互包含的,但是只有一个能在应用程序中使用。ALGRF适于RF5的需要和别的RF级别,而不适合紧凑和底端的如RF1级别的系统。 ALGRFALG相比,有以下的优势: 1 更小的代码脚本(代码量): 作为一个通用的模块,ALG支持malloc/free 运行时库和DSP/BIOS MEM_alloc/MEM_free动态内存分配方式,ALGRF只支持DSP/BIOS分配,这为设计者省了代码空间,另外ALGRF保证没有无用代码的存在.只有被调用的函数才被连接到执行程序中。 2 暂存区支持:   下面的APIALGRF中介绍的实例:
ALGRF_Handle ALGRF_createScratchSupport(IALG_Fxns *fxns, IALG_Handle parent,
IALG_Params *params, Void *scratchBuf, Uns scratchSize)
除了当IALG_SCRATCH内存区域(内部数据缓冲区)被请求,该函数能根据算法请求分配内存。作为替代,scratchBufscratchSize这两个参数表明这一缓冲区已经在应用中存在,而且可以被当前的算法重新使用.这就可以受约束的共享资源有限的内存区。
3 从DSP/BIOS堆标签中做提取:   ALGRF使用DSP/BIOS MEM模块动态分配内存。一个堆标记或内存段名可以传给
MEM_alloc()来表明分配到哪一个堆.如下:
     
/* Configure the ALGRF module to use:
     
* 1st argument - memory for internal heap
     
* 2nd argument - memory for external heap
     
*/
  
ALGRF_setup( INTERNALHEAP, EXTERNALHEAP );
  这让我们可以指定算法的数据分配位置。例如,如果使用EXTERNALHEAP作为两个参数,那么算法的数据就被定位在外部存储器