DSP

TI NDK应用开发过程中的一点经验及改进

2019-07-13 11:47发布

最近在TI的处理器上做软件开发,项目需要网络通讯功能,而在TI的处理器上做网络编程只能使用TI自家的NDK,除非是非常专业的选手,否则用户几乎没有其他选择。
本文假设设计者熟悉TI的集成开发环境Code Composer Studio v6,因此一些基本的工程、项目、软件包的配置说明将被略过,若有需要了解请移步TI官网查询。
本人项目中使用的处理器是TI C6457 DSP,软件包有NDK v2.24.03.35,SYS/BIOS v6.42.02.29。其中NDK需要SYS/BIOS的支持,因此SYS/BIOS是必选项。

一.NDK的配置

1.系统配置

NDK使用SYS/BIOS的Clock模块对NDK内部的工作进行计时驱动,这一模块的实例在NDK中被设计为动态创建得到,虽然NDK自带一套不依赖于系统动态内存管理功能的内存管理单元,并且有自己的堆内存,但Clock的实例却不能在其中创建,只能在系统的全局对中创建。因此SYS/BIOS中的内存堆必须分配足够的大小,且必须将SYS/BIOS的动态内存分配功能使能,否则编译工具将无法产生正确的Clock动态创建代码,而程序也无法正常启动NDK服务。

2.模块配置

按项目需求,需要使用芯片的网络接口设备,因此NDK配置选择了EMAC模块;又因为主要使用UDP协议通信,所以添加了IP模块;其他的TELNET、HTTP、FTP等上层服务一概不选。

3.底层驱动配置

底层驱动分别需要EMAC驱动和NIMU Ethernet驱动,另外CSL库是必须的,它们都可以在针对C64PLUS芯片的MCSDK中找到。这个软件包集合可以安装CSL、PDK、MCSDK三个包,CSL包不必说了,PDK中可以找到EMAC驱动,NIMU Ethernet驱动在MCSDK包中,后两个最好用CCS打开工程自己编译一下,然后需要手动将它们(包括CSL包)的lib文件及include路径添加到自己的工程中。其他的配置略过。

二.基于NDK的部分UDP编程经验

1.基于NDK的socket编程代码必须在Task中执行,原因有:

(1).NDK的启动、初始化以及后台守护任务都在Task中执行;
(2).socket编程需要文件描述符的支持,SYS/BIOS实现了一个简化版的文件描述符,但必须在Task中打开(用fdOpenSession)和关闭(用fdCloseSession)。

2.使用socket编程的用户Task不可一直占用CPU的执行时间,必须以合适的时间间隔自动阻塞,原因有:

(1).SYS/BIOS的Tasks并不是以分片时间自动调度执行,而是按优先级自动重入执行,对相同优先级的Tasks仅在当前执行的Task通过结束任务或者阻塞来主动放弃执行时间后,等待执行的Task才有机会获得执行时间。
(2).NDK的守护任务在完成初始化后即会自动降低Task优先级至最低的IDLE Task级,若用户Task执行在高于IDLE的优先级,且一直不通过阻塞来主动放弃执行时间的话,则NDK的数据报队列状态将一直得不到更新,从而导致用户Task的socket函数无法正常接收和发送数据报。

3.setsockopt应谨慎改变NDK的自定义属性SOL_BLOCKING,否则socket API recv和recvfrom无法正常接收数据报,原因目前未明。

4.recv、recvfrom、send、sendto函数的查询模式实现

这些函数虽然自带阻塞功能,但在一些需要使用查询的应用中并不合适,而多Task的方案又较为复杂,增加了程序设计的难度。实际上可以为它们的flag参数传递MSG_DONTWAIT来防止函数进入阻塞状态,此时这些函数将返回工作失败状态,用fdError()查询可得错误状态码为EWOULDBLOCK。另外在查询模式下,需要编程者手动调整Task的执行时间,或者按后面的方法对NDK进行一点小的改进。

5.在连接以Windows作为操作系统的PC机的网络接口时sendto函数有时会返回错误状态

这是因为Windows系统服务在网络接口连接后会断断续续的发送一些报文,这些报文会暂时占据NDK的数据报队列,导致查询模式下的sendto函数失败,此时fdError()会返回ENOBUFS状态。这种情况下,将Task阻塞一小段时间,再sendto就会成功了。

三.适应执行时间紧张应用场景的NDK小改进

正如上文所说,在查询模式下需要编程者手动调整Task的执行时间,以预留足够的时间给NDK守护任务用于刷新数据报队列,这在应用执行时间比较紧张的情况下将带来额外的调试任务和难度。
为解决这个问题,可考虑将NDK的守护任务执行函数在用户主Task中按合适的时间频度调用,但这可能引入更多的Task间的互斥同步编程,且可能与守护任务的执行上下文产生冲突,因此有必要采用更安全的做法。
我的做法是:在调用socket通信函数(recv、recvfrom、send、sendto等)发现NDK资源不足时,临时提高一次NDK守护任务的优先级,在守护任务执行完一次刷新任务后,又将自身的优先级降回IDLE。这需要对NDK的源代码做一点小更改,并重新编译。
涉及的NDK源码更改为: /* (NDK安装目录)/packages/ti/ndk/netctrl/netctrl.c中的NetScheduler函数前添加自定义的API函数 */ static int netStartTaskPri = 0; static HANDLE hTaskNetService = 0; void NC_tmpRaiseNetServicePri(void) { if (hTaskNetService) { TaskSetPri( hTaskNetService, netStartTaskPri ); } } /* 更改NetScheduler函数的实现代码 */ static void NetScheduler( uint const SerilCnt, uint const EherCnt) { register int fEvents; /* Set the Scheduler priority */ register HANDLE hTaskSelf = hTaskNetService = TaskSelf();/* 获取和保存守护Task的句柄 */ netStartTaskPri = TaskSetPri( hTaskSelf, SchedulerPriority );/* 设置守护Task优先级为SchedulerPriority(默认为IDLE级),并保存原来的优先级 */ /* * 说明:NetScheduler所在的Task在执行NetScheduler之前执行的是NDK的初始化任务,默认情况下该Task的 * 优先级高于用户Task的优先级,直到初始化任务完毕后,在NetScheduler函数中才将自身优先级降为IDLE。 * 因此上面的代码中将原来的优先级和Task句柄一并保存,在自定义的API函数NC_tmpRaiseNetServicePri中 * 即可恢复守护Task的优先级,从而使守护Task从用户Task中重入并得以执行。 */ /* Enter scheduling loop */ while( !NetHaltFlag ) { .../* 原循环代码省略 */ /* 检查守护Task的优先级,并根据需要重设优先级至SchedulerPriority */ if (TaskGetPri( hTaskSelf ) != SchedulerPriority) { TaskSetPri( hTaskSelf, SchedulerPriority ); } } } /* (NDK安装目录)/packages/ti/ndk/inc/netctrl/netctrl.h中添加自定义API函数的声明 */ _extern void NC_tmpRaiseNetServicePri(void); 用法示例: SOCKET s; struct sock_addr_in from; int fromLen; ... int ret = recvfrom(s, recvBuff, recvBytes, MSG_DONTWAIT, (struct sock_addr*)&from, &fromLen); if (ret == INVALID_SOCKET) { ret = fdError(); if (ret == EWOULDBLOCK || ret == ENOBUFS) { NC_tmpRaiseNetServicePri(); } } ...

四.吐槽

想要分门别类的分别来说,但最后仍然是无力吐槽的感觉,于是想到哪儿说哪儿吧,主要是想抱怨一下的TI的各种支持。
这NDK我前后花了近3各月的时间才调试通过,一切都是从零开始,一头雾水。C6457的各种驱动软件包只提供有匹配CCS v4的版本,最新SYS/BIOS、NDK等软件包都需要CCS v6的支持,询问TI的技术支持也无法得到匹配CCS v6的驱动软件,原因是TI的工程师都去忙着做新的C66X系列芯片的软件开发了,C6457这样的老型号芯片没人管!实在是无语!虽然最后自己摸索终于用旧的软件包调通了,但这中间浪费了多少时间哪!我一篇像样的驱动移植GuideLine都没找到。说到这不得不再抱怨一下TI官网的搜索引擎,想搜一个软件包愣是搜不到,只能自己凭着感觉一个页面一个页面的找(别告诉我可以通过CCS的AppCenter联网下载,我所在公司的调试用计算机禁止接入互联网,AppCenter就是个摆设),当初为了下一个兼容版本的xdctools,最后是跑到百度上去搜的下载链接,太无语了。