DSP的C语言编程

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

第15章DSP的C语言编程15.1DSPC语言简介DSP生产厂商及第三方为DSP软件开发提供了C编译器,使得利用高级语言实现DSP程序的开发成为可能。在TI公司的DSP软件开发平台CCS中,又提供了优化的C编译器,可以对C语言程序进行优化编译,提高程序效率,目前在某些应用中C语言优化编译的结果可以达到手工编写的汇编语言效率的90%以上。DSP生产厂商和相关公司也在不断对C优化编译器进行改进设计,相信日后C语言程序优化编译的效果会有进一步的改善。TMS320C2000系列提供有优化的C编译器,它支持ANSI(AmericanNationalStandardsInstitute,美国国家标准委员会)开发的C语言标准,该C语言标准是使用最广泛的C语言标准,ANSI标准具有一些受目标处理器、运行期环境或主机环境影响的C语言特性,从有效性或实现上的考虑,这些特征在各种标准的C编译器之间可能有不同。15.2DSPC语言特性15.2.1TMS320C2000C语言的特征(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_CALLED15.2.2TMS320C2000C语言的数据类型注:在TMS320C2x/C2xx/C5xC语言中,字节长度为16位,sizeof操作符返回的对象长度是以16位为字节长度的字节数。例如sizeof(int)=1。15.2.3TMS320C2000C语言的关键字•const(常数)•ioport(I/O端口)•interrupt(中断)•near(近)•far(远)•volatile(可变的)15.2.4寄存器变量TMS320C2000C编译器在一个函数中最多可以使用两个寄存器变量。寄存器变量的声明必须在变量列表或函数的起始处进行,在嵌套块中声明的寄存器变量被处理为一般的变量。编译器使用AR6和AR7作为寄存器变量:•AR6被赋给第一个寄存器变量•AR7被赋给第二个寄存器变量寄存器变量的地址会被放入分配的寄存器中,这样变量的访问速度会更快。16位类型的变量(char、short、int和指针)都可以被定义为寄存器变量。但在运行时,设置一个寄存器变量大约需要4条指令,为了更有效地使用这个功能,仅当变量被访问超过2次时,才使用寄存器变量。程序优化编译器也会定义寄存器变量,但使用方式不同。编译器会自己决定哪些变量作为寄存器变量,程序中声明的寄存器变量会全部被忽略。声明的格式为:registertypereg;15.2.5pragma伪指令pragma伪指令通知编译器的预处理器如何处理函数。TMS320C2000C编译器支持下列pragma:•CODE_SECTION•DATA_SECTION•FUNC_EXT_CALLED1.CODE_SECTION这个伪指令在名称为sectionname的命名段中为symbol分配空间。语法为:#pragmaCODE_SECTION(symbol,“sectionname”);2.DATA_SECTION这个伪指令在名称为sectionname的命名段中为symbol分配空间。语法为:#pragmaDATA_SECTION(symbol,“sectionname”);3.FUNC_EXT_CALLED当使用-pm选项时,编译器将使用程序级的优化。在这个优化层次中,编译器将删除所有未被main函数直接或间接调用的函数。而用户程序里可能包含要被手工编写的汇编语言程序调用而没有被main函数调用的函数,这时就应该用FUNC_EXT_CALLED来通知编译器保留此函数和被此函数调用到的函数,这些函数将作为C程序的入口点。这个伪指令必须出现在对要保留的函数的任何声明或引用之前,其语法为:#pragmaFUNC_EXT_CALLED(func);15.2.6asm语句TMS320C2000C编译器可以在编译器输出的汇编语言程序中直接输出汇编指令或语句。利用asm语句嵌入汇编语言程序,可以实现一些C语言难以实现或实现起来比较麻烦的硬件控制功能。asm语句在语法上就象是调用一个函数名为asm的函数,函数参数是一个字符串:asm(“assemblertext”);编译器会直接将参数字符串复制到输出的汇编语言程序中,因此必须保证参数双引号之间的字符串是一个有效的汇编语言指令。双引号之间的汇编指令必须以空格、制表符(TAB)、标记符(LABEL)或注释开头,这和汇编语言编程的要求是一致的。编译器不会检查此汇编语句是否合法,如果语句中有错误,在汇编的过程中会被汇编器指出。使用asm指令的时候应小心不要破坏C语言的环境。如果C代码中插入跳转指令和标记符可能会引起不可预料的操作结果。能够改变段或其它影响C语言环境的指令也可能引起麻烦。对包含asm语句的程序使用优化器时要特别小心。尽管优化器不能删除asm指令,但它可以重新安排asm指令附近的代码顺序,这样就可能会引起不期望的结果。15.2.7访问I/O空间读写I/O空间的功能是TMS320C2000C编译器对标准C的扩展,是利用关键字ioport(I/O端口)来实现的。该关键字的用法为:ioporttypeporthexnum;•ioport指示这是定义一个端口变量的关键字。•type(类型)必须是char(字符)、short(短整型)、int(整型)或对应的无符号类型。•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);/*引用传递无效!*/15.2.8访问数据空间访问DSP数据空间是利用指针来实现的:*(unsignedint*)0x1000=a;/*将a的值写入数据空间1000h地址*/b=*(unsignedint*)0x1000;/*读出数据空间1000h地址的值,赋给b*/可见访问DSP数据空间地址不需要对要访问的单元预先定义,利用指针直接访问就可以了。这样,访问数据空间很容易实现循环结构。for(i=0;icnt;i++){tmp=*(unsignedint*)(org+i);*(unsignedint*)(org+offset+i)=tmp;}15.2.9中断服务函数同传统的单片机中断处理方式类似,DSP中断的处理也有两种方式:(1)查询法:可以更好地对程序进程进行控制,对中断的处理可以完全按照程序预定的方式进行,一般不会出现中断丢失或中断嵌套的问题,但由于中断发生时不会暂停当前正在执行的程序,而程序可能正处于复杂的处理或运算状态,只有结束当前处理才会去检查中断标志,因此中断实时性不容易保证。(2)回调法:程序结构更为清晰,而且当有中断发生的时候会暂停当前正在执行的程序,中断实时性可以得到保证,但如果中断处理函数实现不当容易造成中断丢失或中断嵌套问题,影响系统的正常运行。采用回调法处理DSP中断需要定义中断服务函数,有两种方法:(1)用关键字intterupt(中断)来实现。它的用法是:interruptvoidisr(void);(2)任何具有名为c_intd的函数(d为0到9的数),都被假定为一个中断程序。如:voidc_int1(void);无论用哪种方法定义中断服务函数,都须注意以下问题:(1)中断处理函数必须是void类型,而且不能有任何输入参数。(2)进入中断服务函数,编译器将自动产生程序保护所有必要的寄存器,并在中断服务函数结束时恢复运行环境。(3)进入中断服务函数,编译器只保护与运行上下文相关的寄存器,而不是保护所有的寄存器。中断服务函数可以任意修改不被保护的寄存器,如外设控制寄存器等。(4)要注意IMR、INTM等中断控制量的设置。通常进入中断服务程序要设置相应寄存器将中断屏蔽,退出中断服务程序时再打开,避免中断嵌套。(5)中断处理函数可以被其他C程序调用,但是效率较差。(6)多个中断可以共用一个中断服务函数,除了c_int0。c_int0是DSP软件开发平台CCS提供的一个保留的复位中断处理函数,不会被调用,也不需要保护任何寄存器。(7)使用中断处理函数和一些编译选项冲突,注意避免对包含中断处理函数的C程序采用这些编译选项。(8)中断服务函数可以和一般函数一样访问全局变量、分配局部变量和调用其它函数等。(9)要利用中断向量定义将中断服务函数入口地址放在中断向量处以使中断服务函数可以被正确调用。(10)中断服务函数要尽量短小,避免中断丢失、中断嵌套等问题。15.2.10动态分配内存TMS320C2000C语言程序中可以调用malloc、calloc或realloc函数来动态分配内存。unsignedint*data;data=(unsignedint*)malloc(100*sizeof(unsignedint));动态分配的内存将分配在.system段。动态分配的内存只能通过指针进行访问。将大数组通过这种方式来分配可以节省.bss段的空间。通过链接器的-heap选项可以定义.system段的大小。15.2.11系统初始化C程序开始运行时,必须首先初始化C运行环境,这是通过c_int0函数完成的。c_int0函数是复位中断的中断服务函数,这个函数在运行支持库(rts,runtime-supportlibrary)中提供。链接器会将这个函数的入口地址放置在复位中断向量处,使其可以在初始化时被调用。c_int0函数进行以下工作以建立C运行环境:(1)为系统堆栈产生.stack段,并初始化堆栈指针。(2)从.cinit段将初始化数据复制到.bss段中相应的变量。(3)调用main函数,开始运行C程序。用户的应用程序可以不用考虑上述问题,同利用其他开发平台开发C语言程序类似,认为程序从main函数开始执行就可以。用户可以对c_int0函数进行修改,但修改后的函数必须完成以上任务。15.3DSPC语言与汇编语言混合编程C语言编写DSP程序对底层的了解要求较低,流程控制灵活,开发周期短。程序可读性、可移植性好,程序修改、升级方便。某些硬件控制功能不如汇编语言灵活,程序实时性不理想,很多核心程序可能仍然需要利用汇编语言来实现。利用两种语言进行混合编程主要有以下四种方式:(1)C程序调用汇编函数;(2)内嵌汇编语句;(3)C程序访问汇编程序变量;(4)修改C编译器输出。15.3.1程序运行环境在C语言和汇编语言混

1 / 62
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功