德州仪器(TI)的达芬奇(DaVinci)数字媒体技术平台包括四大部分:芯片(处理器)、开发工具或开发套件、软件及技术支持。其中软件开发涉及到操作系统、音视频编解码算法及ARM和DSP之间的分工协作,让很多工程师感到比较复杂。
为此TI推出了一系列软件模块和工具来建立Davinci软件开发的框架,方便工程师在此基础上快速的开发自己的产品。这些软件模块和工具包含在TI的基于达芬奇技术的数字视频评估板的软件开发包中。
一般的视频应用系统中,Davinci的ARM负责操作系统应用,DSP负责运行音视频codec算法处理,ARM通过TI的Codec Engine机制调用DSP侧的codec。那么怎样把不同的codec算法集成到一个DSP可执行程序(称为DSP Server)中,又保证它们占用的资源不冲突?本文从Davinci软件结构入手,介绍如何构建DSP Server,及如何通过DSP Server的配置文件配置FC(Framework Component),以便通过FC管理DSP的资源。
达芬奇DMSoC软件概述
一般来讲,软件系统分为应用层、信号处理层和I/O层三部分,TI提供的达芬奇参考软件框架就是基于这样的结构,如图1所示。Davinci的应用工程师 可以在系统的用户空间在系统功能性上添加和发挥自己的特色。信号处理层通常都运行在DSP一侧负责信号处理,包括音视频编解码算法、Codec Engine、DSP的实时操作系统DSP/BIOS及和ARM通信的模块。I/O层就是我们通常所说的驱动,是针对Davinci外设模块的驱动程序。
其中应用层通过Codec Engine的VISA(Video, Image, Speech, Audio)API来调用DSP侧的算法,通过EPSI(Easy Peripheral Software Interface)API来访问和操作Davinci的外设。这三个部分通常对应三个Davinci软件开发小组。当然还需要一个系统集成工程师把这三 个部分集成起来,不过VISA API和EPSI API的存在已经大大简化了集成工作的复杂程度。
如图2所示,DaVinci的软件开发通常需要四个步骤(本文以codec运行在DSP为例):
图2:软件系统分为应用层、信号处理层和I/O层三部分,达芬奇软件开发通常需要以上四个步骤。
第一步,工程师需要基于DSP利用CCS开发自己的音视频编解码算法,编译生成一个编解码算法的库文件*.lib(等同于Linux环境下的 *.a64P,直接在Linux环境下修改文件后缀名即可)。如果要通过Codec Engine调用这个库文件中的算法函数,那么这些算法实现需要符合xDM(xDAIS(eXpress DSP Algorithm Interface Standard) for Digital Media)标准;Codec Engine机制下不符合xDM标准的算法实现需要创建算法自己的Stub和Skeleton(具体请参考spraae7.pdf)。
第二步,生成一个在DSP上运行的可执行程序*.x64P(即.out文件),也就是DSP Server。本文将详细介绍这一步。
第三步,根据DSP Server的名字及其中包含的具体的音视频编解码算法创建Codec Engine的配置文件*.cfg。这个文件定义Engine的不同配置,包括Engine的名字、每个Engine里包括的codecs及每个 codec运行在ARM还是DSP侧等等(具体说明,请参考sprue67.pdf的第5章Integrating an Engine)。
最后,应用工程师收到不同的codec包、DSP Server和Engine配置文件*.cfg,把自己的应用程序通过编译、链接,最终生成ARM侧可执行文件。
Codec Engine概述
前面我们提到,应用工程师通过调用Codec Engine的API来调用和运行符合xDAIS的算法(关于API的具体信息,请参考sprue67.pdf第4章)。在Davinci软件中,符合 xDAIS的音视频编解码算法(即xDM算法)的调用是通过Codec Engine的VISA API完成的。Codec Engine通过这套API为算法的执行提供了一个标准的软件架构和接口,体现在以下几个方面:
1. 通过Codec Engine API调用的算法可以运行在本地(ARM侧)或者远端(DSP侧);
2. Codec Engine可以基于ARM+DSP、DSP或ARM上运行;
3. 无论Codec Engine运行在ARM还是DSP上,对应的Codec Engine API都是完全一致的;
4. Codec Engine的API与操作系统无关。比如Linux、VxWorks和WinCE环境下的Codec Engine API都是完全一致的。
Codec Engine是介于应用程序和具体算法之间的软件模块,其中的VISA API通过stub和skeleton访问Engine SPI最终调用具体的算法。因此,Codec Engine的工作是通过完成VISA API的任务来体现的。VISA API分为四部分VISA create/control/process/delete,我们以codec算法运行在DSP为例,通过VISA API的执行过程了解Codec Engine的工作原理。
在调用VISA API之前需要在应用程序中通过Engine_open()这个Engine API把DSP的可执行程序加载到DSP的memory,同时把DSP从复位状态释放,这时DSP开始运行DSP Server的初始化程序在DSP侧创建一个优先级最低的任务RMS(Remote Management Server),RMS负责管理和维护对应到具体codec算法的Instances。如图3所示,应用程序调用VISA create API,相应的VISA create函数到Engine SPI中的Codec table中查到这个codec运行在远端DSP侧。
接着Engine SPI通过OSAL(Operating System Abstraction Layer)、DSP Link把VISA create的命令传到DSP侧的RMS。RMS通过DSP侧Engine SPI的codec table找到要调用的codec算法后,就会在RMS中创建一个相应的Instance(即一个DSP/BIOS系统中的任务)。VISA create会返回一个Instance的Handle,以便于给这个Instance做后续的VISA control/process/delete提供信息。VISA delete和VISA create原理类似,只是RMS删除掉相应的codec算法的Instance和执行codec算法的任务。
图3:VISA create/delete流程说明图。
概括来说,VISA control用来动态的修改codec instance的属性,VISA process用来对算法的输入数据流做处理并返回一个输出数据流。如图4所示,应用程序在调用VISA process/control时会通过xDM Stub把传递给codec算法的参数收集起来,并且转换成DSP可以识别的物理地址。Stub把这些参数和相关的命令通过Engine SPI、OSAL和DSP Link传递到DSP侧的Instance。Instance再通过Skeleton把传递过来的参数和命令解析出来,通过DSP侧VISA control/process对codec算法执行control/process。
对Codec Engine有了基本工作原理的了解之后,我们就会更清楚的理解DSP的软件怎样配合应用程序工作及DSP Server中除算法之外还应该包括哪些内容。
创建DSP Server
对达芬奇的软件来说,DSP Server也叫Codec Server。其中“codec”是一组算法。从图3和4可以看到,除算法之外,DSP Server还集成了其他的软件模块(如DSP/BIOS、DSP Link、Codec Engine等)。
1. xDC简介
达芬奇的软件开发环境中,有一个DSP工程师比较陌生的工具xDC(Express DSP Component)。和gmake类似,xDC根据一套build指令build生成可执行文件。xDC同时也会build依赖文件,并且可以一次 build多个目标对象的可执行文件(如图5中的hello.x64P是DSP的可执行文件,hello.x470MV是ARM的可执行文件)。xDC的 源文件可以是C程序、C++程序、汇编程序和库文件等。
如图5所示,xDC按照build指令,对DSP Server的源文件进行build(类似于make)生成DSP Server .x64P文件。这个过程可以分为三部分:创建DSP Server的源文件;设置xDC的配置文件;执行“make”生成可执行文件。
|
图5:xDC按照构建指令,对DSP Server的源文件进行构建生成DSP Server .x64P文件。 |
图5:xDC按照构建指令,对DSP Server的源文件进行构建生成DSP Server .x64P文件。
2. DSP Server的源文件
以Codec Engine_1_02中的video_copy为例,如图6我们可以看到video_copy的DSP Server中包括和图5对应的源文件main.c、video_copy.tcf和link.cmd。图5中的packages是指图3和图4中的 codecs、RMS、Engine SPI和OSAL。接下来,我们可以通过xDC的配置文件看到如何把packages添加到Server中。
要构建DSP Server首先就需要创建main.c和server的DSP BIOS配置文件.tcf及link.cmd。我们提到engine_open会把DSP从复位状态释放,DSP Server程序开始运行初始化等等。这个初始化就是DSP Server main.c(见图7)中的CERuntime_init()。除此之外在main.c中还可以打开Codec Engine的trace功能,读取或更改main函数的参数等。
DSP BIOS的配置文件.tcf中定义DSP的memory map、设置DSP的复位/中断向量表并且创建和初始化BIOS程序需要的各种数据对象(如图8的.tcf)。在.tcf中我们只能定义编译器默认的 sections(如.text和.bss等)。但是,我们可以在link.cmd中定义自己的sections(如图8 link.cmd中.tables和.csl_vect等)。
3. xDC文件
在Linux中我们用make命令根据makefile来生成可执行文件,xDC也有类似的生成脚本文件(我们统称为xDC文件)。如图6所示,其中 package.bld、package.xdc和video_copy.cfg三个文件就是提供给xDC build DSP Server的xDC文件。
在package.xdc中声明DSP Server的名字、它的路径及Server的依赖文件。Package.bld文件的功能类似于Linux中的makefile,它会告诉xDC怎么样 build DSP Server的源文件。如图9所示在package.bld中定义target是C64P DSP、要生成针对target的可执行程序,其中配置脚本文件是video_copy.tcf(与图8中的.tcf类似)、链接选项是链接 link.cmd(与图8中的link.cmd类似)文件,同时还要生成main.c的目标代码。
xDC的强大之处还在于它提供给系统集成工程师一个强大的工具,这个工具可以用来把各种各样的代码模块组合成自己的最终产品。其中xDC的配置文件就是 DSP Server中的.cfg(例如图5中的video_copy.cfg)负责系统级的管理。请注意这里的.cfg文件不同于第一章提到的Codec Engine的.cfg文件(例如 CE_INSTALL_DIR/examples/apps/video_copy/dualcpu/ceapp.cfg),下文中提到的.cfg都是指 DSP Server的.cfg文件。
xDC会根据以上提到的配置文件生成package.mak(类似于makefile),并最终运行它来生成图5所示的包括可执行文件的package。 我们可以打开查看package.mak,但不能修改。因为重新运行xDC之后会生成新的package.mak。
4. 设置xDC的配置文件
既然.cfg文件负责系统级的管理,我们需要先了解什么需要管理?当然是DSP的资源,无非就是CPU cycles、memory及DMA。针对Davinci上DSP的软件开发,TI提供了Framework Components来方便DSP软件工程师使用DSP的memory和DMA资源。xDM和xDAIS算法的Instance都向FC提出自己的资源请 求,比如请求1KByte的memory或一个DMA通道。FC中的DSKT2和DMAN3就通过标准的、可以配置的方法给算法的instances分配 资源(包括instances之间可以共享的资源)。举例来说,有了DSKT2负责不同算法开发的工程师就不必担心自己要用的某一段memory是否已经 被别的算法占用等一系列问题,因为每一个算法的memory都是由DSKT2分配的。
a. DSKT2 Framework
DSKT2负责管理系统中所有xDAIS算法的memory需求,它和应用层的接口非常简单“Create, Execute, Delete”。系统集成工程师需要用所有可以利用的memory初始化DSKT2模块。DSKT2模块包括两种类型的memory,永久性的 memory(只要这个算法存在,它就会占用的memory)和scratch memory(算法之间可以共享的memory)。当一个算法被创建的时候,永久性memory才会被DSKT2分配给这个算法,在算法被删除的时候,这 段memory被返回到heap。当一个算法申请scratch memory时,会被分配一个memory 'pool',这个pool被拥有同一个scratch pool ID的其它算法共享。也就是说,共享scratch memory的算法属于同一个优先级,不能中断对方。
b. 配置DSP Server的.cfg文件
在.cfg文件中可以做以下三个部分的配置。
(1) Codec配置:每一个codec都被包含在各自的线程中; 配置每一个codec线程的属性(线程优先级、堆栈大小和堆栈的memory资源)。具体请参考CE_INSTALL_DIR/xdoc/index.html。
(2) DSKT2配置: 把所有的IALG memory类型结合到可用的DSP memory;定义缺省的scratch组的memory大小。
(3) DMAN3配置:定义DMAN3可以管理的DMA通道号;定义DMAN3可以提供给算法的TCC号。
以video_copy.cfg为例,对应到图4所示的DSP Server部分,.cfg文件中对OSAL和codecs模块做了声明和定义。我们可以看到video_copy的server中包括 VIDDEC_COPY和VIDENC_COPY两个codec。
接着对server进行配置,包括各个线程的属性配置。Codec engine将自动匹配算法的scratch memory ID和算法线程的优先级,保证安全操作。
对DSKT2的配置,参看下面的例子。需要注意的是这里的每一个scratch memory pool的大小通过数组的形式定义,数组的第一个元素对应scratch pool ID0,第二个元素对应scratch pool ID2,依次类推。
以下是DMAN3的配置例子。因为DMA需要memory存放PARAM和其他的通道配置,所以在DMAN3分配有heap(分为internal heap和external heap)。DMAN3的PARAM是通过它自己的base index和数量分配的,本例分配给DMAN3 48个PARAM。从这个例子中我们还可以看到DMAN3有8个可用的QDMA通道,tcc是通过bit mask来分配的。
5. xDC的build 过程
xDC的调用是通过执行命令 XDC完成的。在此之前,我们需要做以下几步:
a. 在config.bld中定义平台(ARM或DSP),config.bld所在路径由xdcbuildcfg定义;
b. 在package.xdc中定义package,package.xdc在当前路径下(如图6的video_copy示例);
c. 在package.bld中定义要build的可执行文件和库文件,package.bld在当前路径下(如图6的video_copy示例);
d. 按照前面的介绍根据自己的应用修改server的.cfg文件。
执行XDC后先产生package.mak,XDC再运行package.mak生成包含可执行文件的package。
本文小结
以上的介绍基于工程师在实际开发过程中遇到的一些问题。我们希望通过这篇文章可以先理清思路,然后工程师可以有针对性的进一步研究和学习。要想了解更多的构建DSP Server的细节还请大家参考sprued5.pdf及文中提到的用户手册和应用文档。