【TDA2x学习】番外篇三、VisionSDK开发指南笔记

1、介绍

Vision Software Development Kit (SDK)是一种多处理器、多通道的用于TI家族ADAS SoCs的软件开发平台。该软件框架允许用户创建不同的ADAS应用程序数据流,包括视频捕获、视频预处理、视频分析算法和视频显示。

本文档解释了以下步骤

  • 1、使用Vision SDK
  • 2、开发一个用例应用程序。开发一种新的算法链接

本文假设读者熟悉Vision SDK中使用的链接和链结构的基本知识。

在描述开发用例的过程时,作为示例,给出了一个简单的用例。此用例在Vision SDK发布包中作为示例提供。

在描述算法链的开发和集成过程的同时,给出了两个简单的算法作为实例。这些算法在Vision SDK发布包中作为示例提供。

2、Use Case 开发

通过use Case,我们指的是将链接(links)连接起来形成链(chain),从而构建系统的应用程序。

2.1、usecase示例

在这里插入图片描述
上面显示的示例用例包括图像捕获(在IPU上),接着是算法(在DSP上),然后是图像显示(在IPU上)。为了简单起见,示例算法被选择为从一个缓冲区到另一个缓冲区的帧拷贝。

从这里得出,IPU就是指M4!!!

为了捕获和显示,使用了M4上相应的链接。

对于帧复制算法,选择DSP上对应的算法链路。

由于用例跨越两个不同的核心,所以选择IPC链接在核心之间进行数据交换。通常,需要一对IPC链接(IPC- In /IPC- out)来启用跨CPU边界的数据流。

此用例的主要实现在文件中\vision_sdk\apps\src\rtos\usecases\vip_single_cam_frame_copy\chains_vipSingleCa meraFrameCopy.c

本文档的其余部分解释了构建用例所涉及的各种步骤。

2.2、Chain创建

Use case中也称为chain,chain的创建包括links的创建和连接,下面是创建chain所涉及的子步骤。

2.2.1、目录结构

建议遵循下面的目录结构,以提高代码库的清晰性和模块化程度。

在\vision_sdk\apps\src\rtos\usecases\下创建一个目录,按照新的用例命名(说“new_usecase”)

在\vision_sdk\apps\src\rtos\usecases\new_usecase\下创建一个新的源文件(.c),根据新的用例命名

查看“\vision_sdk\apps\src\rtos\usecases\vip_single_cam_frame_copy”下的chains_vipsinglec_ameraframecopy .c作为参考。

例如,对于“vip_single_cam_frame_copy”,用例是在文件Chains_vipSingleCameraFrameCopy .c中的函数Chains_vipSingleCameraFrameCopy()中实现的。

2.2.2、使用用例生成工具生成用例

请参考docs\VisionSDK_UsecaseGen_Overview.pdf和docs\VisionSDK_UsecaseGen_UserGuide.pdf来使用用例生成工具。

基本的步骤:

  • 1、在.txt文件中编写用例。比如,chains_vipSingleCameraFrameCopy.txt
  • 2、运行用例生成工具。比如,./gensh
  • 3、用例生成工具自动生成如下文件。chains_vipSingleCameraFrameCopy_priv.c、chains_vipSingleCameraFrameCopy_priv.h
  • 4、编写用例的剩余部分。比如,chains_vipSingleCameraFrameCopy.c
  • 5、编译并运行用例

2.2.3、Link ID设置

注意:Link ID代码的设置是由用例生成工具生成的,本节仅供参考。

chain中的每个link都有一个唯一的Link ID。创建chain的第一步是为用例中出现的所有link分配Link ID

例如如下用例,Link ID的设置在函数chains_vipSingleCameraFrameCopy_SetLinkId()中处理【该函数位于chains_vipsinglecameraframecopy_private .c】

对于只能在特定CPU核心上执行的链接,Link ID值仅由宏定义。例:对于只存在于M4内核上的capture link,Link ID如下:pObj->captureLinkId = SYSTEM_LINK_ID_CAPTURE;

参考文件 \vision_sdk\links_fw\include\link_api\system_linkId.h 以获得可用links

对于可以在任何CPU核心上执行的普通links,Link ID值取决于link将运行的处理器核心和link的功能。

例如:对于在给定CPU上运行的IPC,Link ID作为proc Idlink功能的函数获得:pObj->ipcInLink_CPU_Id = SYSTEM_MAKE_LINK_ID(pObj->algLinkProcId, SYSTEM_LINK_ID_IPC_IN_0);

2.2.4、Link参数的默认设置

注意:链接参数的默认设置代码是由用例生成工具生成的,此部分仅供参考。

通常,每个link都有一些创建时间参数的默认值。可以通过调用Vision SDK提供的参数init函数来设置这些默认值(例如:CaptureLink_CreateParams_Init()函数为capture link执行默认参数初始化)

函数调用的所有默认参数值初始化都可以在函数中看到:chains_vipSingleCameraFrameCopy_ResetLinkPrms () [chains_vipSingleCameraFrameCopy_priv.c]

2.2.5、Link参数设置

这里可以根据用例的需要修改默认参数值。

这是在函数chains_vipSingleCameraFrameCopy_SetAppPrms()[chains_vipSingleCameraFrameCopy.c]中完成的

如果与默认值相比,usecase需要不同的值集,则需要对每个链接单独执行此步骤。

用例生成工具还生成代码来设置一些link的参数,所以这些不需要用户来做。用例生成工具为其生成参数的链接有

  • DUP
  • MERGE
  • IPC OUT
  • IPC IN

这是在函数chains_vipSingleCameraFrameCopy_SetPrms() [chains_vipSingleCameraFrameCopy_priv.c] 中完成的。

2.2.6、连接Link

注意:连接Link代码是由用例生成工具生成的,此部分仅供参考。

此步骤以所需的方式配置几个link之间的连接,这只是创建所需的chain。

例如用例,连接link在函数chains_vipSingleCameraFrameCopy_ConnectLinks () [chains_vipSingleCameraFrameCopy_priv.c]中完成。

通过编程输入和输出队列参数的值,将一个link连接到它的前一个和下一个link,这是link创建参数的一部分。

在示例用例中,算法链接与前一个link(IPC In link)和下一个link(IPC out link)的连接操作如下:

pObj->algLinkCreatePrms.inQueParams.prevLinkId = pObj->ipcInLink_CPU_Id; 
pObj->algLinkCreatePrms.inQueParams.prevLinkQueId = 0; 
pObj->algLinkCreatePrms.outQueParams.nextLink = pObj->ipcOutLink_CPU_Id; 

2.2.7、创建Link

注意:Link创建代码是由用例生成工具生成的,此部分仅供参考。

使用System_linkCreate() 这个API创建链接,该API接受Link ID、创建时间参数创建时间参数结构的大小作为参数。资源和内存分配在这个步骤中完成。

例如,Link创建调用出现在函数chains_vipSingleCameraFrameCopy_Create() [chains_vipSingleCameraFrameCopy_priv.c]

例如,捕获链接的创建如下所示:status = System_linkCreate(pObj->captureLinkId, &pObj->capturePrm, sizeof(pObj->capturePrm));

注意

  • 1、通常,每个Link从前面的Link获得一些输入端创建时间参数。例如,会有一些创建时间参数,如输入颜色格式、输入视频帧数据格式、输入帧分辨率、输入音高等,这些参数实际上是由上一个链接控制的。这些参数不对用户配置公开。这些常见的Link参数,前一Link(输出)和当前Link(输入)需要完全相同。在这两个Link上显式地编写这些代码可能容易出错和冗余。为了避免这种情况,这些参数被编程为chain中的第一个(前一个)link的输出端,chain中的后续(下一个)link通过查询前一个link来选择参数。查询前一个link发生在创建阶段。要使查询成功,需要在创建当前link之前成功创建上一个link。因此,link的创建应该按照从源(第一个)link到目的(最后一个)link的顺序进行,与数据/帧的流动方向相同。这个link创建订单是一个困难的要求。
  • 2、link本身将请求link操作所需的内存和其他资源到Vision SDK中的资源管理器。usecase不需要关心这个请求和授予。然而,控制这些请求的一些参数将是link创建时间参数,它们需要在创建阶段由用例适当地设置。例如:给定link的输出缓冲区数量通常是一个创建时间参数,需要根据用例设置。

至此,链的创建就完成了

2.3、Chain启动执行

注意:chain代码的开始执行是由用例生成工具生成的,本节仅供参考。

要开始执行chain,需要启动chain中的所有link。

例如用例,启动链是在函数chains_vipSingleCameraFrameCopy_Start() [chains_vipSingleCameraFrameCopy_priv.c]中实现的。

通过调用API System_linkStart()来开始link的执行,该API接受Link ID作为参数。

例如:开始显示link完成如下:status = System_linkStart(pObj->displayLinkId);

通过这个步骤,整个chain将开始执行。

注意:通常,可以在源link之前启动目标link。link启动顺序与link创建顺序完全相反。同样,这不是一个很难的要求,但是遵循这个指导原则是好的。

2.4、chain的停止和删除

注意:chain代码的停止和删除是由用例生成工具生成的,本节仅供参考。

一旦chain开始执行,就可以根据用户输入或计时器停止它。

例如用例,在以下函数中实现了停止和删除chain:

chains_vipSingleCameraFrameCopy_Stop() [chains_vipSingleCameraFrameCopy_priv.c] 
chains_vipSingleCameraFrameCopy_Delete() [chains_vipSingleCameraFrameCopy_priv.c]

停止和删除chain基本上包括停止和删除chain中存在的每个link。它们是使用函数System_linkStop()和System_linkDelete()来完成的,它们接受Link ID作为参数。

例如:停止和删除算法Link的操作如下

status = System_linkStop(pObj->algLinkId);  
status = System_linkDelete(pObj->algLinkId);  

注意:

  • 1、Link的停止应该与创建顺序相同。所以停止应该从第一个环节到最后一个环节。同样,这不是一个很难的要求,但是遵循这个指导原则是好的
  • 2、删除可以按任何顺序进行。
  • 3、Link操作所使用的内存和其他资源将由Link在删除阶段自动释放。

2.5、构建新的usecase文件

①、在下面创建一个新的构建文件(SRC_FILES.MK),在\vision_sdk\apps\src\rtos\new_usecase\目录下

这个构建文件将把新的用例文件包含到构建流中。否则,新创建的用例文件将不会得到编译和链接。

参考SRC_FILES。有关详细信息/帮助,请查看“vip_single_cam_frame_copy”下的MK文件

②、还需要修改\vision_sdk\apps\的“Makefile”,为新的usecase添加include路径

例如,用例“vip_single_cam_frame_copy”,添加下面一行,

include $(MODULE_SRC_BASE_PATH)/rtos/usecases/vip_single_cam_frame_copy /SRC_FILES.MK

3、Link开发

3.1、什么是Link?

VISION SDK是基于“Links和chains”框架的。Link是视频数据流的基本处理块。Link由一个OS线程和一个消息框组成,该消息框是使用OS信号量实现的。与Link关联的消息框允许用户应用程序以及其他Link与该Link对话。该Link实现了一个特定的接口,允许其他Link直接与该Link交换视频帧和/或位流。

有关Link的更多信息,请参考vision sdk体系结构文档中的特性特定文档。

Link开发涉及到创建一些文件集,并将这些文件添加到make文件中。虽然以这种方式开发Link不是强制性的,但是为了保持接口干净和易于理解的代码流,还是非常推荐使用这种方式。

3.2、Link文件

任何Link都分布在多个文件中。对于开发人员来说,理解每个文件包含的内容是很重要的。这对建立联系以及理解他人建立的联系有很大帮助。下表给出了每个文件的简要说明

序号文件名位置描述备注
1<link_name>Link.h (ex: captureLink.h)\vision_sdk\links_fw\include\link_apiLink的公共接口文件该文件包含与该链接相关的所有用户/应用程序级别配置
2<link_name>Link_priv.h (ex: captureLink_priv.h)\vision_sdk\links_fw\src\rtos\links_<prcoc_name><link_name>\link的私有接口文件这个文件包含所有特定于该link的 宏/头文件/函数 API。用户/应用程序不需要关心这个文件
3<link_name>_tsk.c (ex: captureLink_tsk.c)\vision_sdk\links_fw\src\rtos\links_<prcoc_name><link_name>\等待从应用程序或其他Link接收命令的任务文件这个文件调用驱动程序特定的API来实现特定的任务
4<link_name>_drv.c (ex: captureLink_drv.c)\vision_sdk\links_fw\src\rtos\links_<prcoc_name><link_name>\驱动程序特定的API在这个文件中实现

3.3、创建公共头文件

每个link都可以通过应用程序/用户进行配置。通常,对象中封装了一组link创建参数,在创建link时可以传递这些参数。

由开发人员来为link提供必要的可配置性。开发人员可以在对象中公开link的所有可配置参数,并在创建link时传递这些参数。另外,输入/输出队列信息也封装在这个对象中。

例如,在Dup Link中,输出队列的数量是一个可配置参数,并通过应用程序传递。

3.4、创建私有头文件

link的私有头文件由特定于link的宏和数据结构组成。开发人员可以为link添加数据结构,通常称为<link_name>Obj。

这个对象由link的所有信息组成。这个对象的一些标准内容是,

序号名字描述
1创建参数需要通过Link查阅上一个link和下一个link的信息
2联系信息当前link信息
3上一个link信息之前的link信息
4系统缓冲区这是可选的。如果link需要与其他link交换数据,则使用这些系统缓冲区。另外,还应该为这些缓冲区创建有效负载。

3.5、创建任务文件

每个link都有一个相关的任务文件任务文件的作用类似于状态机。这个任务文件总是在一个无限循环中运行,等待来自应用程序的顶级或任何其他link(通常是来自上一个链接)的命令。任务文件还有一个“init”调用,它在框架中实际注册这个link。这个init必须在框架的启动序列中调用,并且必须在使用该link的所有内核上调用。

例如,Dup link是一种通用link,可用于需要从单个输入数据路径得到多个视频重复输出数据路径的任何核。任何处理核都需要这样一个link,所以它的“init”调用必须在所有需要的核上调用。

每个link都有特定的功能,因此对link的命令可能因link而异。下面列出了大多数link支持的标准命令:

  • 1、SYSTEM_CMD_CREATE

这必须是link的第一个命令。link接收到此命令后将初始化所有与link相关的数据结构。所有的分析变量,如帧接收,帧处理,延迟被初始化。除此之外,如果link使用驱动程序调用与硬件交互,那么所有与驱动程序相关的初始化都在这个调用中完成。通常,这是通过标准FVID2接口完成的。请参考捕获link以获得更多信息。

  • 2、SYSTEM_CMD_START

这个命令是可选的。并不是每个link都需要显式的start命令。通常驱动程序需要显式的启动命令来启动底层硬件。在这种情况下,使用标准的FVID2接口,启动命令被发送给驱动程序。

  • 3、SYSTEM_CMD_NEW_DATA

只要这个link有新数据可用,应用程序或以前的link就会发布这个命令。link接收到此命令后,将对数据进行处理,并将其放入下一个link的输出队列中,向下一个link发送数据可用性的信号。数据的处理是非常特定于link的,并且每个link之间的差异很大。

  • 4、SYSTEM_CMD_STOP

与start命令一样,这个命令也是可选的。

  • 5、SYSTEM_CMD_DELETE

Delete命令必须对在create调用中已初始化的所有数据结构进行反初始化。任何内存分配都必须在这个调用中释放。在此调用之后,与此link关联的任务也会被删除。因此,不能再向该link发出任何其他命令。

3.6、创建驱动程序文件

通常,大多数link与硬件交互以实现特定的任务。例如,VPE link与硬件交互以调整图像的大小,将去交错的视频转换为渐进视频。所有这些功能都是由BSP驱动程序实现的,可以通过标准的FVID2接口访问。这些函数是从任务文件调用的。有关示例驱动程序文件实现,请参阅captureLink_drv.c文件。

3.7、初始化Link

如2.4节中所述,所有link必须在框架中注册后才能使用。一些连接器link,如Dup link,Null link,Syn link等可以运行在任何核上,而有些link,如capture link,VPE link等可以运行在一个特定的核心上(这里,他们只能运行在IPU1-0上)。为了能在核心上创建链接,为了能在核上创建link,

  • 1、它应该在框架中注册。下面的示例代码展示了如何向框架注册DUP link。
for(dupId = 0; dupId < DUP_LINK_OBJ_MAX; dupId++)
{
	pObj = &gDupLink_obj[dupId];
	
	memset(pObj, 0, sizeof(*pObj));
	
	pObj->tskId = SYSTEM_MAKE_LINK_ID(procId,
	SYSTEM_LINK_ID_DUP_0 + dupId);
	
	linkObj.pTsk = &pObj->tsk;
	linkObj.linkGetFullBuffers = DupLink_getFullBuffers;
	linkObj.linkPutEmptyBuffers = DupLink_putEmptyBuffers;
	linkObj.getLinkInfo = DupLink_getLinkInfo;
	
	System_registerLink(pObj->tskId, &linkObj);
	
	sprintf(tskName, "DUP%u", (unsigned int)dupId);
	
	/*
	* Create link task, task remains in IDLE state.
	* DisplayLink_tskMain is called when a message command is received.
	*/
	status = Utils_tskCreate(&pObj->tsk,
							DupLink_tskMain,
							DUP_LINK_TSK_PRI,
							gDupLink_tskStack[dupId],
							DUP_LINK_TSK_STACK_SIZE, pObj, tskName);
	
	UTILS_assert(status == SYSTEM_LINK_STATUS_SOK);
}
  • 2、上面的代码应该从它要运行核的启动序列中调用。DupLink_init()System_initLinks() 调用, DupLink_deInit()System_deInitLinks() 调用。System_initLinks()System_deInitLinks()定义在\vision_sdk\links_fw\src\rtos\links_common\system\system_initDeinitLinks.c文件中,该文件对所有内核都是通用的。DupLink_init()DupLink_deInit()#ifdef links_common_dup 下被调用,并且这个编译标志只在DUP link代码为调用System_initLinks()System_deInitLinks()函数的核心编译时定义。

4、算法link开发

为了将算法集成到Vision SDK框架中,需要开发一个算法link。一旦算法link被开发出来,它就可以像用例中的任何其他link一样被使用。本章描述了开发一个算法link的程序。

4.1、算法link设计概述

为了方便快速地开发算法link,该link被设计为由骨架(portions - Skeleton)和插件功能( plug-in)两部分组成

  • 1、算法link的骨架部分
    • a、由算法link实现部分组成,这些部分在算法之间很常见。
    • b、负责link实现的通用方面,如link创建、link状态机、与其他link的通信等。
    • c、由TI提供,作为Vision SDK框架的一部分
  • 2、插件功能、
    • a、由满足算法相关功能的函数组成
    • b、需要编写,具体到被集成的算法

骨架代码实现和通信API保持相同,独立于处理核心(EVE/DSP/A15/M4)。骨架代码需要根据算法link的状态调用插件函数。插件函数具有创建和使用实际算法函数(由算法提供程序提供)的实现。插件功能可以通过iVision或任何其他接口与算法功能交互。

通过以上设计,开发一种新的算法link,实质上就是开发插件功能并将其集成。

4.2、算法link骨架

本节提供了TI提供的算法link骨架部分的文件组织信息,这种理解对于算法插件的开发是必要的。

序号文件名位置描述备注
1algorithmLink.h\vision_sdk\links_fw\include\link_api接口文件为算法 link开发人员需要在这个文件中为特定的核心添加算法Id
2algorithmLink_algPluginSupport.h\vision_sdk\links_fw\include\link_api接口文件插件函数与算法link交互开发人员根本不需要修改这个文件
3algorithmLink_algPluginSupport.c\vision_sdk\links_fw\src\rtos\links_common\algorithm实现文件以上开发人员根本不需要修改这个文件
4algorithmLink_cfg.h\vision_sdk\links_fw\src\rtos\links_common\algorithm为算法link的私有API/数据结构开发人员可以修改它来增加或减少一个核上的算法link实例的数量。
5algorithmLink_cfg.c\vision_sdk\links_fw\src\rtos\links_common\algorithm算法link的配置\
6algorithmLink_priv.h\vision_sdk\links_fw\src\rtos\links_common\algorithm算法link私有头文件用户根本不需要修改这个文件
7algorithmLink_tsk.c\vision_sdk\links_fw\src\rtos\links_common\algorithm算法link实现文件用户根本不需要修改这个文件
8App_init_\vision_sdk\apps\src\common\app_init应用程序初始化代码在这些文件中添加算法插件init调用

5、移植Vision SDK(PDK)

下面几节将介绍与将Vision SDK移植到定制硬件相关的不同方面。

请注意,本节只涉及特定于Vision SDK的信息。像SBL、BSP等单独的组件将需要更改,作为移植的一部分,这些不在这里讨论。

5.1、使用自定义内存映射

Vision SDK的内存映射定义在文件\vision_sdk\apps\build\tda2xx\mem_segment_definition_.xs

在移植映射文件时要注意的重要事情有:

  • DDR, OCMC & DSP/EVE SRAM 的大小
  • 特定核上 code/data/vecs 的大小
  • 共享帧缓冲池的大小

DDR分为2个部分:缓存和非缓存。缓存部分用于帧缓冲区和核心特定代码/数据和其他部分。非缓存部分用于Vision SDK日志缓冲区、HDVPSS描述符。

5.2、支持自定义核心选择

可以使用vision_sdk/build/Rules.make文件来控制要包含的内核

请通过将核特定定义(PROC_DSP1_INCLUDE等)设置为适当的值(yes/no)来修改该文件。默认情况下,vision_sdk中所有核心(A15_0、IPU1_0、IPU1_1、DSP1、DSP2、EVE1、EVE2、EVE3和EVE4)都是启用的

5.3、支持定制板

为了添加对新板的支持,需要实现特定于板的init、de-init和probe API函数。有关TI EVM的示例,请参考\vision_sdk\apps\src\rtos\board文件夹。

5.4、支持不同的视频捕获设备

为了添加对不同视频捕获设备的支持,需要实现特定于设备的创建、删除和控制 API。视频传感器(OV10635)和HDMI接收器的相关示例请参考 \vision_sdk\apps\src\rtos\devices文件夹。

一旦定义了这些特定的API,就可以根据所需的配置从用例实现(chain)中调用它们。

5.5、支持不同的LCD

为了添加对不同LCD的支持,需要实现LCD特定的API。例如,请参考文件\vision_sdk\apps\src\rtos\devices\ lcd.c文件。

一旦定义了这些特定的API,就可以根据所需的配置从用例实现(chain)中调用它们。

5.6、为BIOS指定自定义核心频率

utils.h中定义的API Utils_getClkHz()用于读取PLL值,然后告诉BIOS编程的核心频率。BIOS需要被告知准确的频率,因为它根据这个频率配置它的计时器。对于特定的核,BIOS配置是通过API Utils_setCpuFrequency()在main()中完成的。

没有行动是需要从用户配置BIOS时,PLL设置是通过SBL改变,除非参考时钟被改变。默认情况下,EVM使用20Mhz参考时钟。如果自定义板使用另一个参考时钟,那么在文件utils_clk.c (vision_sdk\links_fw\src\rtos\utils_common\src)

#define UTILS_SYS_CLK1 (20*1000*1000)

5.7、使用自定义PLL和时钟设置

不同外设的锁相环和时钟设置可以根据需要(基于输入晶体频率和规格)在SBL(用于开箱执行)或gel文件(基于CCS执行)中进行修改。

作为vision sdk的一部分使用的默认频率配置在数据表中被捕获。TI EVM采用20MHz输入晶体。

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页