DSP编程技巧之29---答疑解惑哪家强之(4)

发布时间:2014-12-15 11:52    发布者:看门狗
关键词: DSP编程
作者:paradoxfx 来源:电子产品世界

22. 除了使用编译器的优化选项之外,还可以使用什么方法提高程序的性能?

  编译器的优化选项,只能在代码满足众多选项的要求时,才能得到较好的优化效果。在我们编程的时候,首先要做到心里有数,尽可能使用一些高效的编程方式,例如使用右移操作代替除以2的倍数的操作,可以大幅度地减少代码运行时间等。这些技巧很多是与C/C++的熟练使用所相关的。此外,根据器件的特点,例如是否包含FPU、CLA等,把特定的代码放在不同的区域执行,也能起到提高程序性能的效果;根据代码对性能的要求,把它们运行在不同的位置,例如RAM快于Flash,Flash又快于XINTF等;在器件包含数学表的情况下,使用内建的数序函数库,而不是标准的C数学库等。在此我们可以给出一些提示:

  1) 代码运行在Flash中

  一定要使能预读缓冲区,并配置适当的等待状态。一般在各个器件的头文件与外设示例包里都有对应的例子。

  2) 把时间关键的代码和/常数数组等从Flash复制到RAM中运行

  在RAM中运行时,最大的指令周期比Flash中运行时要高,其执行速度也要快出不少,所以可以根据需要把实时性能要求较高的程序复制到RAM中运行,具体的方法和实例可以参考http://www.ti.com/general/docs/l ... tureNumber=spra958l下面的《Running an Application from Internal Flash Memory on the TMS320F28xxx DSP》。

  3) 评估代码和数据的存储地址的划分,并根据需要修改链接文件

  i. 如果某段代码和它所读取的数据位于同一个物理内存区间中,则因为它们使用相同的地址总线等资源,无法同时访问,造成了资源的冲突,这会降低程序的性能,所以最好把代码和数据保存在不同的内存区间中。

  ii. 等待状态(wait)会降低系统性能,因为CPU会执行过多的无用状态且在此期间无法处理别的任务:当CPU读取或者访问存储单元或者外设的时候,该存储器或者外设有可能在CPU默认分配的时间内无法完成数据的传输,此时就需要在CPU的ready信号中插入等待状态,直到数据传输完成才能让CPU继续执行别的任务。C28x器件上,大部分的SARAM都是零等待的,但是在C2833x器件中,有一些模块却不是,例如某些Flash/OTP的访问等。

  iii. 如果在代码中大量使用两个数据缓冲区,则把两个数据缓冲区存放在不同的RAM模块中有可能会提高代码的性能,因为大量读写同一块RAM区间会产生更多的流水线停滞,造成性能的降低。

  4) 使用编译器中的统一内存模式--unified_memory

  此模式把所有的存储空间定义为一个整体,这样编译器在编译时就可以使用RPT与PREAD指令来处理大部分的内存复制调用和结构体的分配。

  5) 使用Flash和外部存储器

  如果代码需要在Flash或外部存储器中运行,则在编译时开启-me选项。它将禁止编译器使用快速分支指令(SBF/BF),转而使用普通的跳转指令(SB/B)。BF指令在默认情况下是被启用的,它能够将跳转分支使用的指令周期从7个降低到4个,在零等待状态的SAM中执行时,快速分支指令的预读特性使得它较为高效,但是在非零等待的存储器中执行时,SBF/BF的预读反而造成了性能的下降,此时需要人为地对预读和等待进行规划。

  6) 使用内联函数

  在编译时开启内联函数功能,则编译器会自动把多次调用的函数进行内联,大大减少函数调用和返回操作所带来的开销。当然,根据“空间换时间”的原则,开启内联会增加一定的代码尺寸。

  23. 为什么一个char类型的数组中,每个元素都占用了16bit的地址?

  这是因为在C28x上,字节(byte)和字(word)是等价的:也就是说它们都是16位或者说16比特(bit)宽的,即sizeof(int) == sizeof(char) == 1。

  24. sizeof(int) == sizeof(char) == 1貌似与ANSI标准是相违背的?

  在ANSI/ISO的C定义中,sizeof操作符以字节形式给出了其操作数的存储大小。ANSI/ISO还规定,sizeof操作符取char的值时,返回值为1。因为TMS320C28x中的字节是16位的,char也是16位的,所以sizeof的结果符合ANSI标准的。

  作为补充,选16位,而不是8位或者别的什么位数作为char的宽度,主要是为了统一寻址的便利,虽然在某种程度上说这增加了一定的存储器空间占用,或者说浪费了一些空间,因为它们在存储空间中制造了一些空洞。

  25. 如果char是16位的,那么如何高效地访问8位的值?

  可以使用__byte()和__mov_byte()这样的编译器内联函数。

  26. 编译结果提示undefined symbols,名字中包含$符号,怎么破?

  名字中带美元符号的函数,例如FS$$MPY, FS$$TOL等,都是RTS库里的内置函数,编译器提示我们这些函数未定义,表明我们没有把对应的RTS库给加入到工程中,例如MPY是数学函数,需要添加相关的数学库,例如FPU数学库等。

  27. 链接器提示“_c_int00 is not defined”,怎么破?

  已经分析过了_c_int00的含义。找不到_c_int00的话,说明我们遗漏了包含它的RTS库,例如 rts2800_ml.lib、rts2800_fpu32.lib等待,这些RTS库的具体区别在答疑解惑的第15条中已经有对比了。

  28. 新版本的编译器中,printf()/sprintf()函数貌似要使用更多的栈?

  这是因为printf()函数被重新修改了,以支持多个级别的printf格式说明符支持和修正,以减少代码大小和总内存大小(包括bss)。printf由sprintf()间接调用,它使用一个400个元素的大小的局部数组。为了保存一致性,printf()一直都在使用这么大的内存空间,而编译器也在尽量避免使用malloc()进行内存分配。与老版本所不同的的是,此数组以前是静态的,而现在它被保存在.bss,而不是栈中;这样做的目的是,如果用户使用C I/O,则他们往往会在使用合适尺寸的栈的同时尽量减小.bss的使用。
本文地址:https://www.eechina.com/thread-135072-1-1.html     【打印本页】

本站部分文章为转载或网友发布,目的在于传递和分享信息,并不代表本网赞同其观点和对其真实性负责;文章版权归原作者及原出处所有,如涉及作品内容、版权和其它问题,我们将根据著作权人的要求,第一时间更正或删除。
您需要登录后才可以发表评论 登录 | 立即注册

厂商推荐

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
快速回复 返回顶部 返回列表