DSP

如何构建达芬奇的DSP Server

2019-07-13 15:51发布

关键字: DSP Server  Codec Engine  达芬奇  xDC  Framework Component 德州仪器(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的应用工程师可以在系统的用户空间在系统功能性上添加和发挥自己的特 {MOD}。信号处理层通常都运行在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等)。   xDC简介 1. 达芬奇的软件开发环境中,有一个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文件。   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函数的参数等。     图6     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的目标代码。 package.bld中去掉注释后的内容 package servers.video_copy { }     /*======== package.bld ========*/ var serverName = "video_copy"; Pkg.attrs.profile = "debug"; Pkg.uses = ["ti/bios/include"]; for (var i = 0; i < Build.targets.length; i++) {     var targ = Build.targets[i];      if (targ.os == "Linux") {          /* Linux doesn't host remote codecs (yet) */          continue;      }      else {          /* presume we're building a full server executable */          print("building for target " + targ.name + " ...");          Pkg.addExecutable(serverName, targ, targ.platform,              {                  cfgScript: serverName + ".tcf",                  lopts: "-l link.cmd",              }).              addObjects( [                 "main.c",              ] );      } }     其中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的强大之处还在于它提供给系统集成工程师一个强大的工具,这个工具可以用来把各种各样的代码模块组合成自己的最终产品。 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来分配的。       /* set up OSAL */ var osalGlobal = xdc.useModule('ti.sdo.ce.osal.Global'); osalGlobal.runtimeEnv = osalGlobal.DSPLINK_BIOS;   /* activate BIOS logging module */ var LogServer = xdc.useModule('ti.sdo.ce.bioslog.LogServer');   /* get various codec modules; i.e., implementation of codecs */ var VIDDEC_COPY = xdc.useModule('codecs.viddec_copy.VIDDEC_COPY'); var VIDENC_COPY = xdc.useModule('codecs.videnc_copy.VIDENC_COPY');   /* ======== Server Configuration ======== */ var Server = xdc.useModule('ti.sdo.ce.Server'); Server.threadAttrs.stackSize = 2048; Server.threadAttrs.priority = Server.MINPRI; Server.autoGenScratchSizeArrays = true;   Server.algs = [      {name: "viddec_copy", mod: VIDDEC_COPY, threadAttrs: {          stackSize: 4096, stackMemId: 0, priority: Server.MINPRI + 1}      },      {name: "videnc_copy", mod: VIDENC_COPY, threadAttrs: {          stackSize: 4096, stackMemId: 0, priority: Server.MINPRI + 1}      }, ];   /* Note that we presume this server runs on a system with DSKT2 and DMAN3, * so we configure those modules here. */   /* we can use DMA in certain codecs! */ VIDENC_COPY.useDMA = true;   /*   ======== DSKT2 (XDAIS Alg. memory alocation ) configuration ========*/ var DSKT2 = xdc.useModule('ti.sdo.fc.dskt2.DSKT2'); DSKT2.DARAM0      = "DDRALGHEAP"; DSKT2.DARAM1      = "DDRALGHEAP"; DSKT2.DARAM2      = "DDRALGHEAP"; DSKT2.SARAM0      = "DDRALGHEAP"; DSKT2.SARAM1      = "DDRALGHEAP"; DSKT2.SARAM2      = "DDRALGHEAP"; DSKT2.ESDATA      = "DDRALGHEAP"; DSKT2.IPROG       = "DDRALGHEAP"; DSKT2.EPROG       = "DDRALGHEAP"; DSKT2.DSKT2_HEAP = "DDR";   /*   ======== DMAN3 (DMA manager) configuration ======== *   We assume PaRams 0..95 are taken by the Arm drivers. We reserve *   all the rest, up to 127 (there are 128 PaRam sets on DM6446). *   DMAN3 takes TCC's 32 through 63 (hence the High TCC mask is 0xFFFFFFFF *   and the Low TCC mask is 0). */ var DMAN3 = xdc.useModule('ti.sdo.fc.dman3.DMAN3'); DMAN3.heapInternal = "L1DHEAP"; DMAN3.heapExternal = "DDR";   DMAN3.paRamBaseIndex      = 96; DMAN3.numPaRamEntries     = 32; DMAN3.tccAllocationMaskH = 0xffffffff; DMAN3.tccAllocationMaskL = 0x00000000;   Program.main = Program.system = null;     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(Codec Engine Server Integrator's Guide.pdf)及文中提到的用户手册和应用文档。 作者:崔晶 通用DSP技术应用工程师 德州仪器半导体技术(上海)有限公司