DSP的C语言编程
一、DSP的C语言简介:
DSP生产厂商及第三方为DSP软件开发提供了C编译器,使得利用高级语言实现DSP程序的开发成为可能。在TI公司的DSP软件开发平台CCS中,又提供了优化的C编译器,可以对C语言程序进行优化编译,提高程序效率,目前在某些应用中C语言优化编译的结果可以达到手工编写的汇编语言效率的90%以上。DSP生产厂商和相关公司也在不断对C优化编译器进行改进设计,相信日后C语言程序优化编译的效果会有进一步的改善。
TMS320C2000系列提供有优化的C编译器,它支持ANSI(American National Standards Institute,美国国家标准委员会)开发的C语言标准,该C语言标准是使用最广泛的C语言标准,ANSI标准具有一些受目标处理器、运行期环境或主机环境影响的C语言特性,从有效性或实现上的考虑,这些特征在各种标准的C编译器之间可能有不同。
二、DSP的C语言特性
2.1 TMS320C2000 C语言的特征
(1)标识符和常数
所有标识符的前100个字符有意义,区分大小写。
源(主机)和执行(目标)字符集为ASCII码,不存在多字节字符。
具有多个字符的字符常数按序列中最后一个字符来编码,例如:
‘abc’= = ‘c’
(2)数据转换
浮点到整数的转换取整数部分。指针和整数可以自由转换。
(3)表达式
当两个有符号整数相除时,若其中一个为负,则其商为负,余数的符号与分子的符号相同。斜杠(/)用来求商,百分号(%)用来求余数。例如:
10/-3 = -3,-10/3 = -3,10%-3 = 1,-10%3 = -1
(4)声明
寄存器变量对所有char,short,int和指针类型有效。interrupt关键字仅可用于没有参量的void函数。
(5)预处理
预处理器忽略任何不支持的#pragma伪指令。预处理器支持的伪指令包括:
·CODE_SECTOIN
·DATA_SECTION
·FUNC_EXT_CALLED
2.2 TMS320C2000 C语言的数据类型
注:在TMS320C2x/C2xx/C5xC语言中,字节长度为16位,sizeof操作符返回的对象长度是以16位为字节长度的字节数。例如sizeof(int) = 1。
2.4 寄存器变量
TMS320C2000 C编译器在一个函数中最多可以使用两个寄存器变量。寄存器变量的声明必须在变量列表或函数的起始处进行,在嵌套块中声明的寄存器变量被处理为一般的变量。编译器使用AR6和AR7作为寄存器变量:
AR6被赋给第一个寄存器变量,AR7被赋给第二个寄存器变量。
寄存器变量的地址会被放入分配的寄存器中,这样变量的访问速度会更快。16位类型的变量(char、
short、int和指针)都可以被定义为寄存器变量。但在运行时,设置一个寄存器变量大约需要4条指令,为了更有效地使用这个功能,仅当变量被访问超过2次时,才使用寄存器变量。
程序优化编译器也会定义寄存器变量,但使用方式不同。编译器会自己决定哪些变量作为寄存器变量,程序中声明的寄存器变量会全部被忽略。
声明的格式为:
register type reg;
2.5 pragma伪指令
pragma伪指令通知编译器的预处理器如何处理函数。TMS320C2000 C编译器支持下列pragma:CODE_SECTION、DATA_SECTION、FUNC_EXT_CALLED。
1. CODE_SECTION
这个伪指令在名称为section name的命名段中为symbol分配空间。语法为:#pragmaCODE_SECTION (symbol, “section name”);
2. DATA_SECTION
这个伪指令在名称为section name的命名段中为symbol分配空间。语法为:#pragmaDATA_SECTION (symbol, “section name”);
3. FUNC_EXT_CALLED
当使用-pm选项时,编译器将使用程序级的优化。在这个优化层次中,编译器将删除所有未被main函数直接或间接调用的函数。
而用户程序里可能包含要被手工编写的汇编语言程序调用而没有被main函数调用的函数,这时就应该用FUNC_EXT_CALLED来通知编译器保留此函数和被此函数调用到的函数,这些函数将作为C程序的入口点。
这个伪指令必须出现在对要保留的函数的任何声明或引用之前,其语法为:
#pragmaFUNC_EXT_CALLED (func);
2.6 asm语句
TMS320C2000 C编译器可以在编译器输出的汇编语言程序中直接输出汇编指令或语句。利用asm语句嵌入汇编语言程序,可以实现一些C语言难以实现或实现起来比较麻烦的硬件控制功能。
asm语句在语法上就象是调用一个函数名为asm的函数,函数参数是一个字符串:asm(“assembler text”);
汇编语言转c语言的软件 编译器会直接将参数字符串复制到输出的汇编语言程序中,因此必须保证参数双引号之间的字符串是一个有效的汇编语言指令。双引号之间的汇编指令必须以空格、制表符(TAB)、标记符(LABEL)或注释开头,这和汇编语言编程的要求是一致的。编译器不会检查此汇编语句是否合法,如果语句中有
错误,在汇编的过程中会被汇编器指出。
使用asm指令的时候应小心不要破坏C语言的环境。如果C代码中插入跳转指令和标记符可能会引起不可预料的操作结果。能够改变段或其它影响C语言环境的指令也可能引起麻烦。
对包含asm语句的程序使用优化器时要特别小心。尽管优化器不能删除asm指令,但它可以重新安排asm指令附近的代码顺序,这样就可能会引起不期望的结果。
2.7 访问I/O空间
读写I/O空间的功能是TMS320C2000 C编译器对标准C的扩展,是利用关键字ioport(I/O端口)来实现的。
该关键字的用法为:ioporttype porthexnum;
(1)ioport指示这是定义个端口变量的关键字。
(2)type(类型)必须是char(字符)、short(短整型)、int(整型)或对应的无符号类型。
(3)porthexnum为定义的端口变量,其格式必须是“port”后面跟一个16进制数,如“port000A”是定义访问I/O空间地址0Ah的变量。
所有I/O端口的定义必须在文件级完成,不支持在函数级声明的I/O端口变量。
利用ioport关键字定义的I/O端口变量可以象一般变量一样进行赋值操作:
ioportunsingedport10;/*访问I/O空间10h的变量*/
{...
port10 = a; /*将a写到端口10h*/
.
..
b = port10; /*从端口10h读入b*/
...}
端口变量的使用不仅限于赋值操作,事实上,用ioport关键字定义的I/O端口变量可以象其它变量一样用在表达式中:
a = port10 + b;/*读端口10h,加上b,结果赋给a*/
port10 += a;/*读端口10h,加上a,结果写回到端口10h*/
在进行函数调用的时候,可以做I/O端口变量的值传递,而不是引用:
call (port10);/*读端口10h,将其值传递给函数调用*/
call (&port10);/*引用传递无效!*/
2.8 访问数据空间
访问DSP数据空间是利用指针来实现的:
*(unsigned int*)0x1000 = a; /*将a的值写入数据空间1000h地址*/
b = *(unsigned int*)0x1000; /*读出数据空间1000h地址的值,赋给b*/
可见访问DSP数据空间地址不需要对要访问的单元预先定义,利用指针直接访问就可以了。这样,访问数据空间很容易实现循环结构。
for (i=0; i<cnt; i++)
{
tmp= *(unsigned int*) (org + i);
*(unsigned int*) (org + offset +i) = tmp;
}
2.9 中断服务函数
同传统的单片机中断处理方式类似,DSP中断的处理也有两种方式:
(1)查询法:可以更好地对程序进程进行控制,对中断的处理可以完全按照程序预定的方式进行,一般不会出现中断丢失或中断嵌套的问题,但由于中断发生时不会暂停当前正在执行的程序,而程序可能正处于复杂的处理或运算状态,只有结束当前处理才会去检查中断标志,因此中断实时性不容易保证。
(2)回调法:程序结构更为清晰,而且当有中断发生的时候会暂停当前正在执行的程序,中断实时性可以得到保证,但如果中断处理函数实现不当容易造成中断丢失或中断嵌套问题,影响系统的正常运行。
采用回调法处理DSP中断需要定义中断服务函数,有两种方法:
(1)用关键字intterupt(中断)来实现。它的用法是:
interrupt void isr(void);
(2)任何具有名为c_intd的函数(d为0到9的数),都被假定为一个中断程序。如:void c_int1 (void);
无论用哪种方法定义中断服务函数,都须注意以下问题:
(1)中断处理函数必须是void类型,而且不能有任何输入参数。
(2)进入中断服务函数,编译器将自动产生程序保护所有必要的寄存器,并在中断服务函数结束时恢复运行环境。
(3)进入中断服务函数,编译器只保护与运行上下文相关的寄存器,而不是保护所有的寄存器。中断服务函数可以任意修改不被保护的寄存器,如外设控制寄存器等。
(4)要注意IMR、INTM等中断控制量的设置。通常进入中断服务程序要设置相应寄存器将中断屏蔽,退出中断服务程序时再打开,避免中断嵌套。
(5)中断处理函数可以被其他C程序调用,但是效率较差。
(6)多个中断可以共用一个中断服务函数,除了c_int0。c_int0是DSP软件开发平台CCS提供的一个保留的复位中断处理函数,不会被调用,也不需要保护任何寄存器。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论