本文介绍了TI的ARM+C6000 DSP异构多核平台(如Davinci系列,OMAP3系列,OMAP-L系列)的通信机制,包括Codec Engine、IUNIVERSAL API、C6Accel、C6Run、RPMSG、RCM和OpenCL等。从底层的通信(CMEM+DSPLINK/SYSLINK)到高层的封装和构建系统。
Overview
本文介绍了TI的ARM+C6000 DSP异构多核平台(如Davinci系列,OMAP3系列,OMAP-L系列)的通信机制,包括Codec Engine、IUNIVERSAL API、C6Accel、C6Run、RPMSG、RCM和OpenCL等。从底层的通信(CMEM+DSPLINK/SYSLINK)到高层的封装和构建系统。
Codec Engine相关的软件部件可以从如下地址下载: http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/index.html。
Codec
Engine (CE)是一个简化了使用xDM通用API的编解码器和算法的框架,能够用于算法本地运行(即算法和算法CEApp在同一个处理器上运行)或者远端运行(即在不同处理器上运行),可以用于同构或者异构的处理器(OMAP3、DM644x,DM64x,DM643x,DM3555,DM365等,以及多核C6472,C6474等)。集成的应用程序调用Codec
Engine API。在Codec Engine内部,反应XDM API的VISA
API用于实际的编解码的调度。如果算法运行于远端,VISA有stub和skeleton来实现一个远端程序调度(RPC,remote
procedure call,DSP/BIOS LINK或者syslink用于底层的IPC(inter-processor
communication)通信)。为了能够采用Codec Engine,需要实现定义在XDM algorithm standard和XDAIS
Algorithm Standard中的算法接口规范。下图是一个ARM+DSP的通信协同示意图。Codec Engine是介于应用层(ARM侧的应用程序)和信号处理层(DSP侧的算法)之间的软件桥梁。ARM应用程序调用Codec
Engine的VISA (Video, Image, Speech, Audio)API( VIDENC_process(a,
b, c ))。Codec Engine的stub (ARM侧)会把参数a,
b, c以及要调用DSP侧process这个信息打包,通过消息队列(message
queue)传递到DSP。Codec Engine的skeleton(DSP侧)会解开这个参数包,把参数a,
b, c转换成DSP侧对应的参数x, y, z(比如ARM侧传递的是虚拟地址,而DSP只能认物理地址),DSP侧的server(优先级较低,负责和ARM通信的任务)会根据process这一信息创建一个DSP侧的process(x,
y, x)任务最终实现VIDENC_process(a, b, c)的操作。
图1. Codec Engine应用和算法调用示意图
Codec Engine软件模块和组件
在每款提供了Codec Engine的TI DSP的DVSDK开发包中还提供了如下软件模块和工具配合使用:
- Framework Components是TI提供的一个软件模块,负责DSP侧的memory 和DMA资源管理。他底层会有如DSKT2(用于创建和访问xDAIS算法)、RMAN(通用的资源管理器,内存和外设资源管理)、ECPY(与RMAN资源管理器协调工作的基于DMA的内存拷贝函数库)、DMAN3(EDMA3设备中共享QDMA通道)、ACPY3(基于DMA的内存拷贝函数库,在FC
3.23中被废弃)。
xDAIS 是一个标准,它定义了TI DSP算法接口的标准。这样大大提高了DSP算法软件的通用性。DSP算法工程师要写出能被ARM通过Codec
Engine调用的算法,必须保证自己的算法接口符合这个标准。
XDC Tools
XDC Tools和gmake类似,是一个工具。XDC根据用户定义的一套build指令,通过调用用户指定的ARM 工具链(Tool
Chain)和DSP编译器(C6x Code Generation Tools )build出ARM侧和DSP侧的可执行文件。可以先不必细究这个工具,只需通过编Codec
Engine的例子,知道如何设置build指令就可以了。
图2. xDC build系统
DSP/BIOS Link是实现ARM和DSP之间通信的底层软件,Codec
Engine就是建立在这个底层软件之上。在修改系统内存分配(缺省是256MB的DDR2)时,DSP/BIOS
Link 1.38版本的用户需要修改DSP/BIOS Link的配置文件,并重新build DSP/BIOS Link。而DSP/BIOS
Link 1.40版本以后的用户就无需此操作。
DSP/BIOS Link包括了PROC的基本的处理器控制(如GPP绑定DSP,GPP加载DSP的可执行程序,GPP启动DSP,GPP停止,GPP接绑定DSP)、IPC通信机制(Message
Queue消息队列MSGQ、基于事件回收的流模型CHNL、基于流的循环缓冲的RingIO)、IPC通信构建模块(底层的内存管理分配的POOL、多处理器互斥访问的MPCS、对于DSP内存读写的PROC_read/PROC_write)。
CMEM:
http://processors.wiki.ti.com/index.php/CMEM_Overview
提供内存管理,用户能定义的大小固定、连续地址的POOL。在cmem 2.0之后还引入了Heap,CMEM地址空间在POOL之后的都认为是HEAP。用户可以通过在cmem的内核驱动加载时设置参数,如modprobe
cmemk phys_start=0x83000000 phys_end=0x85200000 pools=21x4096,具体的cmem内存分配的pool和heap可以从cat
/proc/cmem来得到具体的状态。
C6x Code Generation Tools :
C6x Code Generation Tools是Linux环境下C6000系列DSP的编译器。我们用CCS开发DSP时都是用的Windows环境下的DSP编译器。
DSP/BIOS是TI 免费提供的DSP实时操作系统。和上面C6x
Code Generation Tools一样,这里的DSP/BIOS也是Linux环境下的版本。
图3. TI BIOS系统的组件
MontaVista Linux PSP
TI开发板的u-boot、Linux
Kernel版本。
Codec Engine软件开发流程
开发ARM+协处理器的平台软件需要算法在协处理端的开发、算法的集成、ARM段APP程序的开发几个方面。
DSP算法开发
对于DSP算法,处理算法性能和效率外,从算法的集成需要让ARM可以通过Codec
Engine来调用DSP算的算法。因而需要1)、熟悉xDAIS和xDM标准。需要先了解xDAIS,xDM只是xDAIS的扩展。xDAIS
6.10及其以后的版本,包含了一个工具QualiTI,可以检查您的DSP算法是否满足xDAIS标准(但不会检查是否满足xDM)。具体请参考:http://processors.wiki.ti.com/index.php?title=QualiTI_XDAIS_Compliance_Tool 。2)、熟悉Framework
Components。 Framework Components主要包括两个模块DSKT2和DMAN3,它们分别负责DSP侧的memory 和EDMA资源管理。DSP算法使用的memory必须是先向DSKT2提出申请并由DSKT2分配得到的。同样DSP算法使用的EDMA通道也是向DMAN3申请并由DMAN3分配得到的。而关于QDMA的操作,是通过ACPY3这个模块实现的。这样的好处是很容易对DSP侧不同的算法做整合,不同的算法之间不用担心资源(Memory和EDMA)的冲突问题。Codec
Engine DSP侧会涉及到Cache一致性的问题。请参考:http://wiki.davincidsp.com/index.php?title=Cache_Management
DSP系统集成
通常DSP算法工程师都会把自己的符合xDM标准算法编成一个.lib文件(或 .a64P),供DSP系统工程师调用。DSP系统工程师最终build出一个DSP
Server(也就是DSP的可执行程序.x64P,和CCS下编译生成的.out类似)。(参考http://focus.ti.com/lit/ug/sprued5b/sprued5b.pdf ,这个文档会讲到.xdc和.bld等文件,Codec
Engine1.20及以上版本的用户可以先不细究,后面介绍工具帮您自动生成这些文件。)
1) 如果现在有一个.lib文件(或 .a64P)(算法必须符合xDM标准),如何生成自己的DSP
Server呢?下面URL有详细的关于RTSC Codec and Server Package Wizard工具介绍,教您如何把一个.lib文件封装成RTSC
Codec 包和RTSC DSP Server包,并最终build出DSP的可执行程序.x64P。
http://processors.wiki.ti.com/index.php?title=RTSC_Codec_And_Server_Package_Wizards
http://processors.wiki.ti.com/index.php?title=I_just_want_my_video_codec_to_work_with_the_DVSDK
2) 如果您使用的是Codec
Engine 1.20以前的版本,请参考Codec Engine安装路径下examples/servers/video_copy这个例子。这时就需要搞清楚sprued6c.pdf和sprued5b.pdf中提到的.xdc和.xs等文件的功能,也可以在video_copy中的相关文件的基础上修改手动创建出自己的RTSC
Codec包和RTSC DSP server包。
3) 创建好RTSC Codec 和RTSC
DSP Server包之后,就是如何build出.x64P的问题了。其中关键是修改user.bld和xdcpaths.mak文件,设置Codec
Engine依赖的其它软件模块和工具的正确路径。
4) 如果自己的硬件DDR2大小和例子中的256Mbytes不一致,需要修改DSP的.tcf文件和其他配置。还有些工程师不清楚如何分配memory及如何决定具体段,如:DDRALGHEAP和DDR的大小,以及如何配置./loadmodules里的参数都请参考: http://wiki.davincidsp.com/index.php?title=Changing_the_DVEVM_memory_map。
ARM端应用程序开发
ARM应用工程师需要调用Codec Engine的VISA
API,最终编出ARM侧的可执行程序,因此,必须根据自己的应用学习相关的VISA API、如何创建应用侧Codec
Engine的package及配置文件。(参考http://focus.ti.com/lit/ug/sprue67d/sprue67d.pdf ,这个文档也涉及到如何调试Codec
Engine的内容)。
1)了解ARM应用程序调用Codec
Engine的流程、VISA API和其他Codec Engine API。可以参考Codec
Engine安装路径下examples/apps/video_copy的例子(较简单)或者DVSDK安装路径下demos里的encode/decode/encodedecode例子(较复杂)。
http://wiki.davincidsp.com/index.php?title=Configuring_Codec_Engine_in_Arm_apps_with_createFromServer
2) 了解ceapp.cfg文件。sprue67d.pdf有相关介绍,可以先读懂examples/apps/video_copy/ceapp.cfg。
3) 用4.2 3)中提到的方法学习如何build
ARM侧的可执行程序。
4) 如何在多线程中调用codec
engine,参考:
http://wiki.davincidsp.com/index.php?title=Multiple_Threads_using_Codec_Engine_Handle
5)还可以参考以下三个文档了解更多TI demo的ARM应用程序的结构、线程调度等具体的问题。
C6Accel
C6EZAccel能提供ARM+DSP架构的SOC的调用DSP端算法的ARM端应用程序的快速开发。适用于OMAP-L137/
OMAP-L138/OMAP3530/OMAP3525/DM3730/DM6446/DM8168/DM8148等处理器。C6EZAccel包括了符合TI算法标准XDAIS的基于Codec
Engine的算法库的快速集成。C6EZAccel还包括了ARM端应用程序来启动这些DSP端算法。这些DSPlib库用codec
engine的IUNIVERSAL API做了封装方便ARM端调用。iUniversal
APIs类似VISA API,能通过Codec Engine接口传递函数参数和返回值等。
图4. C6EZAccel通过IUNIVERSAL API调用框架
http://processors.wiki.ti.com/index.php/C6EZAccel
C6Run
C6EZRun本质上讲是一个build系统,即通过对程序的编译结果后处理,首先用codec
engine tools来编译源代码,得到的目标文件用code sourcery的gcc-arm重新编译链接,该方法适用于OMAP-L137/
OMAP-L138/OMAP3530/OMAP3525/DM3730/DM6446/DM8168/dm3725等处理器。
C6RunLib
c6runlib-cc是一个Bash shell脚本,编译C代码产生DSP端的C6000目标文件,首先调用C6000的编译器并合理的处理命令行选项(c6runlib-cc命令行的语法符合开源GCC编译器的语法),c6runlib-cc工具目前只支持C源文件。经由c6runlib-cc编译和汇编的文件会再次分析产生2个额外的源文件,即2个RPC
stub,一个在ARM端(后缀名为".gpp_stub.o"),一个在DSP端(扩展名为".dsp_stub.o")。输出的目标文件会由c6runlib-ar进行压缩打包。这个库中包含了自动的RPC调用,屏蔽了底层的DSPLINK和其他的TI组件。
图5. C6RunLib工具编译链接图示
C6RunApp
C6RunApp-cc是一个Bash shell的脚本,能编译C代码产生C6000的目标文件。首先调用TI
C6000的编译器cl6x,当然会对命令行选项进行合适的处理。然后c6runapp-cc还用来链接C6000目标文件产生一个ARM/Linux的应用程序。即c6runapp-cc工具合理的利用cl6x的编译器和ARM
GCC的编译器来产生镜像可执行文件。目前的c6runapp-cc的工具只支持C源代码。
图6. C6RunApp工具编译链接图示
图1. C6RunApp常用的命令行选项
--C6Run:replace_malloc
替换标准C的malloc APIs为共享CMEM的heap
--C6Run:no_replace_malloc
不替换malloc APIs (默认)
--C6Run:debug
使用debug模式的库
--C6Run:release
使用release模式的库 (默认)
--C6Run:save_dsp_image
保存DSP端的可执行程序和相应的内存映射文件。
图7. 从ARM端的开发到ARM+DSP端的开发
RPMSG
http://www.omappedia.com/wiki/RPMsg_Kernel_Sources
http://omappedia.org/wiki/RPMsg_BIOS_Sources
RPMSG是开源的IPC通信框架,开发于2011年,用于Android
4.0,首次出现在Linux 3.0的内核里。它简化了SysLink 2.0的一些特性,提供更为简单的用户接口。可以视为SysLink
3.0.
RPMsg的特性:
设备管理:远端处理器的全集管理,包括设备初始化、加在可执行程序,内存管理,运行时电源管理,远端处理器的trace的log,严重错误和异常管理,错误恢复等。
信息框架(Messaging Framework): Linux消息框架来在处理器间交换固定大小的控制信息;
资源管理:申请和释放远端的外设和硬件加速器、带宽频率和延迟管理。
RPMSG的基本组件
remoteproc:管理远端处理器设备状态的驱动。设备的加载和启动、功耗控制、异常管理和错误恢复。平台相关的驱动接口。
rpmsg: 远端处理器的消息队列驱动,提供消息传递机制。
rpmsg-resmgr:管理时钟和各种外设的请求限制的客户端驱动;
rpmsg-omx:用户空间的接口与TI的OMX框架交互的客户端驱动,可以把部分的OMX框架的负荷转交给协处理器。
RPMSG底层驱动机制
iommu:OMAP远端协处理的MMU管理驱动
mailbox: 管理OMAP处理器内的邮箱外设的驱动,提供不同的处理器子系统间的通信;
hwspinlock: 硬件外设的自旋锁,提供不同处理器间的硬件外设的仲裁;
virtio:支持虚拟化的VirtIO框架
RCM
图8. RCM服务器server端和客户端client端通信示意
http://processors.wiki.ti.com/index.php/RCM_Overview
一些软件架构组件如DSP Bridge、Codec Engine需要把一些任务发送worker线程到远端处理器执行包括创建线程、得到CPU的负荷、分配远端内存等。RCM提供了通用的远端客户端和服务器模型来实现平台间任务的分配。RCM构建在XDC之上,使用IPC的MessageQ服务来实现底层通信。TI81xx的Distributed
OpenMax就是基于RCM实现的。
OPENCL