DM642 DSP内存管理的一点经验
可恶的DSP又吞没了我的假期。先整理个经验,碰到类似问题可以获得些启发的:
俺的程序是QC_LDPC,传说中最占内存的信道编码,所以程序和内存的矛盾是这个程序的主要矛盾。
1. 本想在一个函数里建立一个很大的数组,函数运行完会自动删掉,但那是没法做到的,这个大数组最好是声明为全局变量,并且把它存到外部扩展内存里,不要让它占用有限的片上内存,不然程序很容易跑飞。C语言本身的跑飞现象比较好查,而因为内存问题而跑飞,很隐秘,很难查。
声明存到外扩的片子上:#pragma DATA_SECTION(G, ".G");
然后在.cmd文件里写:.G > CE0
或者也可以改.stack,把整个堆栈放到CE0去。但是这样会严重减慢系统速度。不要相信扩展内存会比片上内存快。
2. 一般数组的名字代表它的首地址,但是CCS里有些别扭的地方。
如果数组G是在其他文件里声明的,在本文件中想用的话直接extern int G;就可以了。但是要想用一个指针指向这个G,如:G_pointer要指向G,则应写成G_pointer=&G;若写成G_pointer=G;将提示错误。
如果G是本文件定义的静态变量,用指针指向它,可以写成:G_pointer=G;
3. 把大数组作为静态变量并给它独立分配内存空间的必要性:
如果大数组在函数内部定义,其数据会出现莫名其妙的异常,还会经常变化。其实不是你程序的错,是内存的缘故,所以硬着头皮,把他们统统放到程序前面去吧。
4. 程序中的printf无法起作用:
当然还是内存的问题。网上唯一一篇相关**说是-heap的问题,让把heap改成0x400,俺的heap本来就是400,后来改成800也没用。最后把.stack移到片外内存后,printf才好用,光改option里的stack改到800也无济于事.
不改.stack也行,把option里的stack改成0x1000,heap还是0x400,printf可以用。
像LDPC这样消耗内存较多的程序,最好stack设成0x3000,heap不要管它。
stack大小设错或者放到CE0上,都可能导致程序结果出错,是在内存存取时被无意识改写了,具体原因和对策有待分析。
5. 没有板子的同志就别做了,光靠pc上的simulator太慢,不太现实。
6. 调用函数中用到的,其他文件已经定义过的,外部静态变量数组,必须用指针调用,不支持G[]的形式。
但是,这个G如果是在本文件中定义的,可以用G[]。定义G时候好像要加static,调用时才可以用G[],不知道没有static行不行。
7. C语言里还有一种用far定义的变量,没用过,不知道怎么用,也不知道用了有什么好处,请高人指教!!查了一下.map文件,上面显示说:静态数都存在.far中了,可能CCS会自动识别far和near的变量吧。
还有一个什么内存对齐的问题:#pragma DATA_ALIGN(highpoint, 8),好像用不用效果都是一样的,为什么要对齐呀?
8. 对于CCS来说,对于外部变量G,初始化的语句int G[100]={0};并不能使G的元素变
成 0,所以还是老老实实用memset语句进行初始化吧。
但是对于动态变量{0}用于初始化是可以的。
9. VC中一个指针是unsigned int型还是int型都无所谓,都意味着指针+1跳4个字节,但是CCS中则很严格,G如果是unsigned int型的,他的指针一定要定义成unsigned int *。
10.不同文件的声明部分:CCS中每一个文件都要写声明,如文件A需要include <stdio.h>,文件B也需要,则A,B两文件都要写include <stdio.h>,编译器不会自动找的。还包括:
#define......, #pragma DATA_ALIGN等声明。
11. CCS的printf确实不太好用,比如printf("%f,%d",a,b);则b将会显示出错,显示出来一个莫名其妙的值,所以在CCS上应用printf一个变量用一个pirntf。修改stack大小也是没用的。
12. 如果程序中用的数组超大(通信程序经常是这样), 编译到最后link时会出现relocation value truncated 0xxxx in section .text, file 字样。一般的办法是前面说的将大数组声明在一个特定的内存空间中,声明存到外扩的片子上:#pragma DATA_SECTION(G, ".G");如果这样还不行,就修改Build option, 进入advance项,把memory mode 改成“far”,把RTS calls改成“are far”就行了。
13. 需要非常注意:CCS有自动优化功能,即build option中选择 -o1~-o3,会有不同程度的优化效果。但是优化之后,CCS会将程序的循环体变成DSP喜欢的流水线形式,所以用优化过的程序进行程序调试是不明智的,因为你的循环变量counter将不再显示它本来的值,而且单步运行时,很可能不会按照程序一步一步走下去,因为优化会带来程序的跳转。所以正确的方法是,处在调试阶段的程序不进行优化,调试成功,结果正确,再进行优化。优化效果非常明显哦。
14. 2011年5月7日,今天一个很简单的程序在DSP上给跑飞掉了,不知道怎么回事。最后发现是头文件的问题,不是没包含头文件,而是头文件定义太多次了。我将所有头文件和声明都放到一个config.h文件中,里面用了ifndef, endif等伪指令,在所有C程序中包含这个头文件,问题就解决了。先开始以为这种写法是一种简炼的写法,没想到还有防止DSP跑飞的作用,看来算是一种标准的写法。
注:过了几天发现,第14个问题的这种解决方法只是表象,其实质是CCS中用的fp = fopen();函数,CCS并不能很好地支持这里文件处理函数,经常会出现问题,包括第15个问题。更奇怪的是:我将这些文件处理函数注释掉后,程序仍然跑飞,而将这些注释掉的程序删除,程序就正常运转了,这说明fopen()等函数即便是被注释掉,对于CCS的程序仍然有影响,真是诡异,但这是事实。
15. 对CCS进行fprintf操作,输出一个文本时它是很不给力的,有可能保存不了文本。这时我们要清楚,CCS中保存文本以来 -heap(堆)的大小,在build option中将heap的大小由默认的0x400改为0x700或0x1000可以解决此类问题。
|