DSP的C语言编程实用教案

上传人:壹****1 文档编号:568571393 上传时间:2024-07-25 格式:PPT 页数:89 大小:1.84MB
返回 下载 相关 举报
DSP的C语言编程实用教案_第1页
第1页 / 共89页
DSP的C语言编程实用教案_第2页
第2页 / 共89页
DSP的C语言编程实用教案_第3页
第3页 / 共89页
DSP的C语言编程实用教案_第4页
第4页 / 共89页
DSP的C语言编程实用教案_第5页
第5页 / 共89页
点击查看更多>>
资源描述

《DSP的C语言编程实用教案》由会员分享,可在线阅读,更多相关《DSP的C语言编程实用教案(89页珍藏版)》请在金锄头文库上搜索。

1、1TMS320C2000系列提供有优化的C编译器,它支持ANSI( American National Standards Institute,美国(mi u)国家标准委员会)开发的C语言标准,该C语言标准是使用最广泛的C语言标准,ANSI标准具有一些受目标处理器、运行期环境或主机环境影响的C语言特性,从有效性或实现上的考虑,这些特征在各种标准的C编译器之间可能有不同。第1页/共88页第一页,共89页。215.2 DSP C语言特性语言特性(txng)15.2.1 TMS320C2000 C语言的特征(tzhng)(1)标识符和常数所有标识符的前100个字符有意义(yy),区分大小写。源(主机

2、)和执行(目标)字符集为ASCII码,不存在多字节字符。具有多个字符的字符常数按序列中最后一个字符来编码,例如:abc = = c第2页/共88页第二页,共89页。3(2) 数据转换(zhunhun), 浮点到整数的转换(zhunhun)取整数部分。指针和整数可以自由转换(zhunhun)。(3) 表达式当两个有符号整数相除时,若其中一个为负,则其商为负,余数的符号与分子的符号相同。斜杠(/)用来求商,百分号(%)用来求余数。例如:10/-3 = -3, -10/3 = -3, 10%-3 = 1,-10%3 = -1第3页/共88页第三页,共89页。4(4)声明寄存器变量对所有char,sh

3、ort,int和指针类型(lixng)有效。Interrupt(中断函数)关键字仅可用于没有参量的void函数。(5)编译预处理编译预处理器忽略任何不支持的#pragma命令。预处理器支持的伪指令包括: CODE_SECTOIN DATA_SECTION FUNC_EXT_CALLED第4页/共88页第四页,共89页。515.2.2 TMS320C2000 C语言的数据类型注:在TMS320C2x/C2xx/C5x C语言中,字符长度为16位,sizeof操作符返回的对象(duxing)长度是以16位为长度的数值。例如sizeof(int) = 1。第5页/共88页第五页,共89页。615.2

4、.3 TMS320C2000 C语言的关键字 const(常数(chngsh)) ioport(I/O端口) interrupt(中断) near(近) far(远) volatile(可变的)第6页/共88页第六页,共89页。7关键字const 该关键字可以优化存储器的分配。加const 到任何变量的定义(dngy)可以确保其内的值不变。关键字volatile 该关键字所定义的变量是可变的,可以被其他硬件修改,而不仅仅只能由C程序修改。优化器会尽量减少存储器的访问,所以有时必须禁止优化,特别(tbi)是循环控制变量。例子 volatile unsigned int *ctrl; while(

5、*ctrl != 0xff) ; /循环等待,直到 ctrl 地址的内容为0xff第7页/共88页第七页,共89页。8关键字interrupt 该扩展关键字用来(yn li)说明函数是一个中断函数。 中断函数被定义成返回void类型,而且无参数调用,例如,interrupt void int_handler( )unsigned int flags;第8页/共88页第八页,共89页。9关键字far C/C+编译器的默认寻址空间是64K。所有指针的默认大小为16位。C28x支持(zhch)的寻址空间达4M字, 即22位。加上far关键字限定符的指针大小为22位,可以寻址4M字空间。第9页/共88

6、页第九页,共89页。1015.2.4 寄存器变量(binling)TMS320C2000 C编译器在一个函数中最多可以使用两个寄存器变量。寄存器变量的声明必须在变量列表或函数的起始处进行,在嵌套块中声明的寄存器变量被处理为一般(ybn)的变量。编译器使用AR6和AR7作为寄存器变量: AR6被赋给第一个寄存器变量 AR7被赋给第二个寄存器变量第10页/共88页第十页,共89页。11寄存器变量的地址会被放入分配的寄存器中,这样变量的访问速度会更快。16位类型的变量(char、short、int和指针)都可以被定义为寄存器变量。但在运行时,设置一个寄存器变量大约需要4条指令,为了更有效地使用(sh

7、yng)这个功能,仅当变量被访问超过2次时,才使用(shyng)寄存器变量。程序优化编译器也会定义寄存器变量,但使用(shyng)方式不同。编译器会自己决定哪些变量作为寄存器变量,程序中声明的寄存器变量会全部被忽略。声明的格式为:register type reg;第11页/共88页第十一页,共89页。1215.2.5 pragma编译(biny)预处理命令pragma命令又称伪指令通知(tngzh)编译器的预处理器如何处理函数。TMS320C2000 C编译器支持下列pragma: CODE_SECTION DATA_SECTION FUNC_EXT_CALLED1. CODE_SECTIO

8、N这个伪指令在名称为section name的命名段中为symbol分配空间。语法为:#pragma CODE_SECTION (symbol, “section name”);第12页/共88页第十二页,共89页。132. DATA_SECTION这个伪指令在名称为section name的命名段中为symbol分配空间。语法(yf)为:#pragma DATA_SECTION (symbol, “section name”);3. FUNC_EXT_CALLED当使用-pm选项时,编译器将使用程序级的优化。在这个优化层次中,编译器将删除所有未被main函数直接或间接调用的函数。第13页/共

9、88页第十三页,共89页。14而用户程序里可能包含要被手工编写的汇编语言程序调用而没有被main函数调用的函数,这时就应该(ynggi)用FUNC_EXT_CALLED来通知编译器保留此函数和被此函数调用到的函数,这些函数将作为C程序的入口点。这个伪指令必须出现在对要保留的函数的任何声明或引用之前,其语法为:#pragma FUNC_EXT_CALLED (func);第14页/共88页第十四页,共89页。1515.2.6 asm语句(yj)C2000 C编译器可以在编译器输出的汇编语言程序中直接输出汇编指令或语句。利用asm语句嵌入汇编语言程序,可以实现一些C语言难以实现或实现起来(q li

10、)比较麻烦的硬件控制功能。asm语句在语法上就象是调用一个函数名为asm的函数,函数参数是一个字符串:asm (“ assembler text”); 例如, asm (“ CLRC INTM”) /开放中断编译器会直接将参数字符串复制到输出的汇编语言程序中,因此必须保证参数双引号之间的字符串是一个有效的汇编语言指令。双引号之间的汇编指令必须以空格、制表符(TAB)、标记符(LABEL)或注释开头,这和汇编语言编程的要求是一致的。编译器不会检查此汇编语句是否合法,如果语句中有错误,在汇编的过程中会被汇编器指出。第15页/共88页第十五页,共89页。16使用asm指令的时候应小心不要破坏C语言的

11、环境。如果C代码中插入跳转指令和标记符可能会引起不可预料的操作结果。能够改变段或其它影响C语言环境的指令也可能引起麻烦。对包含asm语句的程序使用优化器时要特别小心。尽管(jn gun)优化器不能删除asm指令,但它可以重新安排asm指令附近的代码顺序,这样就可能会引起不期望的结果。第16页/共88页第十六页,共89页。1715.2.7 访问(fngwn)I/O空间读写I/O空间的功能是TMS320C2000 C编译器对标准C的扩展,是利用关键字ioport(I/O端口)来实现(shxin)的。该关键字的用法为:ioport type porthexnum; ioport指示这是定义一个端口变

12、量的关键字。 type(类型)必须是char(字符)、short(短整型)、int(整型)或对应的无符号类型。 porthexnum为定义的端口变量,其格式必须是“port”后面跟一个16进制数,如“port000A”是定义访问I/O空间地址0Ah的变量。第17页/共88页第十七页,共89页。18所有(suyu)I/O端口的定义必须在文件级完成,不支持在函数级声明的I/O端口变量。利用ioport关键字定义的I/O端口变量可以象一般变量一样进行赋值操作:ioport unsinged port10; /*访问I/O空间10h的变量*/.port10 = a; /*将a写到端口10h*/.b =

13、 port10; /*从端口10h读入b*/.第18页/共88页第十八页,共89页。19端口变量的使用(shyng)不仅限于赋值操作,事实上,用ioport关键字定义的I/O端口变量可以象其它变量一样用在表达式中:a = port10 + b; /*读端口10h,加上b,结果赋给a*/port10 += a;/*读端口10h,加上a,结果写回到端口10h*/在进行函数调用的时候,可以做I/O端口变量的值传递,而不是引用:call (port10); /*读端口10h,将其值传递给函数调用*/call (&port10); /*引用传递无效!*/第19页/共88页第十九页,共89页。2015.2

14、.8 访问数据(shj)空间访问DSP数据空间(kngjin)是利用指针来实现的,例如*(unsigned int *)0x1000 = a; /*将a的值写入数据空间(kngjin) 1000h地址*/ b = *(unsigned int *)0x1000; /*读出数据空间(kngjin)1000h地址 的值,赋给b*/可见访问DSP数据空间(kngjin)地址不需要对要访问的单元预先定义,利用指针直接访问就可以了。这样,访问数据空间(kngjin)很容易实现循环结构。例如(lr) for (i=0; icnt; i+)tmp = *(unsigned int *) (org + i);

15、*(unsigned int *) (org + offset +i) = tmp;第20页/共88页第二十页,共89页。21例,编程将DARAM中的201H开始的4个单元(dnyun)的内容送到301H开始的4单元(dnyun)。main( )int * pInt, * pDes; int i; pInt= (int * ) 0x201; pDes= (int * ) 0x301; for(i = 0;i4;i+) * (pInt+i) = i+1; for(i=0;i4; i+) * (pDes+i) = * (pInt+i); while(1) ;第21页/共88页第二十一页,共89页。

16、22用C语言访问数据(shj)存储器(或片内外设寄存器)可以用指针方法实现。可以用指针方法实现。例如,一种方法定义例如,一种方法定义volatile unsigned int *IMR= (volatile unsigned int *)0x0004这时,这时,IMR为指针,则给为指针,则给IMR赋值可以用以下赋值可以用以下(yxi)语句语句 *IMR=0x0010 或者,另一种方法定义或者,另一种方法定义define IMR * (volatile unsigned int *)0x0004这时,这时,IMR为变量,则给为变量,则给IMR赋值可以用以下赋值可以用以下(yxi)语句语句 IMR

17、=0x0010 一般将这些定义存放到一个头文件,例如一般将这些定义存放到一个头文件,例如 regs2407c.h,使用时,用编译预处理命令使用时,用编译预处理命令 include “regs2407c.h”第22页/共88页第二十二页,共89页。2315.2.9 中断服务函数同传统的单片机中断处理方式类似,DSP中断的处理也有两种方式:(1)查询法:可以更好地对程序进程进行控制,对中断的处理可以完全按照程序预定的方式进行,一般不会出现中断丢失或中断嵌套的问题,但由于中断发生时不会暂停(zn tn)当前正在执行的程序,而程序可能正处于复杂的处理或运算状态,只有结束当前处理才会去检查中断标志,因此

18、中断实时性不容易保证。第23页/共88页第二十三页,共89页。24(2)回调法:程序结构更为清晰(qngx),而且当有中断发生的时候会暂停当前正在执行的程序,中断实时性可以得到保证,但如果中断处理函数实现不当容易造成中断丢失或中断嵌套问题,影响系统的正常运行。采用回调法处理DSP中断需要定义中断服务函数,有两种方法:(1)用关键字intterupt(中断)来实现。它的用法是:interrupt void isr (void);(2)任何具有名为c_intd 的函数(d为0到9的数),都被假定为一个中断程序。如:void c_int1 (void); 第24页/共88页第二十四页,共89页。25

19、无论用哪种方法定义中断服务函数,都须注意以下问题:(1)中断处理函数必须是void类型,而且不能有任何输入参数。(2)进入中断服务函数,编译器将自动产生程序保护所有必要的寄存器,并在中断服务函数结束时恢复运行(ynxng)环境。(3)进入中断服务函数,编译器只保护与运行(ynxng)上下文相关的寄存器,而不是保护所有的寄存器。中断服务函数可以任意修改不被保护的寄存器,如外设控制寄存器等。第25页/共88页第二十五页,共89页。26(4)要注意IMR、INTM等中断控制量的设置。通常进入中断服务程序要设置相应寄存器将中断屏蔽,退出(tuch)中断服务程序时再打开,避免中断嵌套。(5)中断处理函数

20、可以被其他C程序调用,但是效率较差。(6)多个中断可以共用一个中断服务函数,除了c_int0。c_int0是DSP软件开发平台CCS提供的一个保留的复位中断处理函数,不会被调用,也不需要保护任何寄存器。第26页/共88页第二十六页,共89页。27(7)使用中断处理函数和一些编译选项冲突,注意避免对包含中断处理函数的C程序采用这些编译选项。(8)中断服务函数可以和一般函数一样访问全局变量、分配局部变量和调用其它函数等。(9)要利用中断向量定义将中断服务函数入口地址(dzh)放在中断向量处以使中断服务函数可以被正确调用。(10)中断服务函数要尽量短小,避免中断丢失、中断嵌套等问题。第27页/共88

21、页第二十七页,共89页。2815.2.10 动态(dngti)分配内存TMS320C2000 C语言程序中可以调用malloc、calloc或realloc函数来动态分配内存。例如unsigned int *data;data =(unsigned int *) malloc (100 * sizeof(unsigned int);动态分配的内存将分配在.sysmem段。动态分配的内存只能(zh nn)通过指针进行访问。将大数组通过这种方式来分配可以节省.bss段的空间。通过链接器的-heap(堆)选项可以定义.sysmem段的大小。第28页/共88页第二十八页,共89页。2915.2.11

22、系统(xtng)初始化C程序开始运行时,必须首先初始化C运行环境,这是通过c_int0函数完成的。c_int0函数是复位中断的中断服务函数,这个函数在运行时支持库(rts, runtime-support library)中提供。链接器会将这个函数的入口地址放置在复位中断向量处,使其可以在初始化时被调用。c_int0函数进行以下工作以建立C运行环境:(1)为系统堆栈产生.stack段,并初始化堆栈指针。(2)从.cinit段将初始化数据复制到.bss段中相应的变量。(3)调用main函数,开始运行C程序。用户(yngh)的应用程序可以不用考虑上述问题,同利用其他开发平台开发C语言程序类似,认为

23、程序从main函数开始执行就可以。用户(yngh)可以对c_int0函数进行修改,但修改后的函数必须完成以上任务。第29页/共88页第二十九页,共89页。3015.3 DSP C语言与汇编语言语言与汇编语言(hu bin y yn)混合编程混合编程C语言编写DSP程序对底层的了解要求较低,流程控制灵活,开发周期短。程序可读性、可移植性好,程序修改、升级方便。某些硬件控制功能不如汇编语言灵活,程序实时性不理想(lxing),很多核心程序可能仍然需要利用汇编语言来实现。利用两种语言进行混合编程主要有以下四种方式:(1)C程序调用汇编函数;(2)内嵌汇编语句;(3)C程序访问汇编程序变量;(4)修改

24、C编译器输出。第30页/共88页第三十页,共89页。3115.3.1 程序运行环境(hunjng)在C语言和汇编语言混合编程中,必须保证C程序运行环境不会被汇编程序破坏,所有代码必须维护该环境,否则将难以保证C程序的正常执行。1. 存储器模型TMS320C2000的C编译器将存储器作为程序存储器和数据存储器两个线性区来处理(chl):程序存储器:包含可执行的代码和常量、变量初值。数据存储器:包含外部变量、静态变量和系统堆栈。第31页/共88页第三十一页,共89页。32(1)段的存储器分配编译器产生可重新定位的代码段和数据,包括:a. 已初始化的段:包含数据和代码。包括.text、.cinit、

25、.switch等 。b. 未初始化的段:为全局变量和静态变量保留空间。包括.bss、.stack、.sysmem等。用户(yngh)可以利用CODE_SECTION和DATA_SECTION伪指令来创建另外的段。第32页/共88页第三十二页,共89页。33 编译器对C语言编译后除了生成2个基本段,即.text、.bss外,还生成其他一些段。 可分为初始化段和未初始化段。 初始化段包含可执行代码或常数表。C编译器产生的初始化段有 .pint、.const、.text、.cinit、.switch 。.text段,包含可执行代码和常量(constant)。.cinit段和.pint段,包含初始化变

26、量和常量。.const段,包含串常量,全局变量、静态变量的声明(shngmng)和初始化。.switch段,包含switch语句表。第33页/共88页第三十三页,共89页。34未初始化段用于保留存储器(通常为RAM)空间。C编译器产生的为初始化段有.bss、.stack、.sysmem段。.bss段,为全局和静态变量保留空间。.stack段,为C系统堆栈。用于保护函数(hnsh)的返回地址、分配局部变量、调用函数(hnsh)时传递参数。.sysmem段,为动态存储器分配保留空间, malloc函数(hnsh)使用。第34页/共88页第三十四页,共89页。35段的存储分配(fnpi)和页的指定段

27、段 存储器存储器类型类型页页.textROM或或RAM 0.cinitROM或或RAM 0.switchROM或或RAM 0.constROM或或RAM 1.bssRAM1.stackRAM1.sysmemRAM1第35页/共88页第三十五页,共89页。36(2) 系统堆栈C编译器使用软件堆栈进行如下工作: 分配局部变量 向函数传递参数(cnsh) 保存处理器状态 保存函数的返回地址 保存暂时的结果 保存寄存器第36页/共88页第三十六页,共89页。37堆栈从较低地址向较高地址生长,编译器使用两个寄存器管理堆栈: AR1:堆栈指针(SP, stack pointer),指向当前堆栈顶。 AR2

28、:帧指针(FP, frame pointer), 指向当前帧的起始点。每一个函数都会在堆栈顶部建立一个新的帧,用来保存局部(jb)的或临时的变量。C语言环境自动操作这两个寄存器。如果编写用到堆栈的汇编语言程序,一定要注意正确使用这两个寄存器。用-stack连接选项可以指定软件堆栈的大小,用C编写DSP程序一定注意保留足够的堆栈空间!注意:编译器不会检查堆栈溢出情况,堆栈溢出会破坏DSP运行环境,导致程序失败。编写DSP程序和配置DSP存储器资源要注意防止堆栈溢出的发生。第37页/共88页第三十七页,共89页。382. 寄存器规则TMS320C2x/C2xx/C5x运行环境对寄存器的使用有严格的

29、规则,如果编写涉及到寄存器的汇编程序,必须严格遵守这些规则,否则可能造成系统工作异常。寄存器规则规定了编译器如何使用寄存器,和寄存器在函数调用的过程中如何进行保护。寄存器按照保护方式分为(fn wi)两种:调用保存(save on call),调用其它函数的函数负责保存这些寄存器的内容。入口保存(save on entry),被调用的函数负责保存这些寄存器的内容。注:无论是否使用优化编译,都必须遵守这些寄存器规则。第38页/共88页第三十八页,共89页。39寄存器的使用(shyng)和保护第39页/共88页第三十九页,共89页。40状态(zhungti)寄存器(ST0、ST1)单元对于有设定值

30、(为0或为1)的状态(zhungti)寄存器单元,在进行函数调用和函数返回时必须保证其值为设定值。第40页/共88页第四十页,共89页。413个寄存器堆栈指针(SP)、帧指针(FP)和局部变量指针(LVP)管理堆栈和局部帧。AR6和AR7作为寄存器变量的寄存器。AR6被分配(fnpi)给第一个变量,AR7分配(fnpi)给第二个变量。编译器使用不用于寄存器变量的寄存器来计算表达式的值并保存临时结果。当函数的返回值是一个标量类型(整型、指针或浮点型)时,该值在函数返回时被放入累加器中。16位的数据类型(字符型、短整型、整型或指针型)连同正确的符号扩展被装载到累加器中。第41页/共88页第四十一页

31、,共89页。423. 函数结构和调用规则C编译器对函数的调用有一系列严格的规定。除了特殊的运行(ynxng)支持函数外,任何调用者函数和被调用函数都要遵守这些规则,否则可能会破坏C环境并导致程序失败。(1)函数如何产生调用一个函数(调用者函数)在调用其他函数(子函数)时执行以下任务。注意,ARP必须设置为1。a. 调用者函数将参数以颠倒的顺序压入堆栈(最右边声明的参数第一个压入堆栈,最左边的参数最后一个压入堆栈)。即函数调用时,最左边的参数放在栈顶单元。b. 调用者函数调用子函数。c. 调用者函数假定当子函数执行完成返回时,ARP将被置为1。d. 完成调用后,调用者函数将参数弹出堆栈。第42页

32、/共88页第四十二页,共89页。43(2)被调用函数如何响应a. 将返回地址从硬件堆栈中弹出,压入软件堆栈。b. 将FP压入软件堆栈。c. 分配局部帧。d. 如果函数修改了AR6和AR7,则将它们压入堆栈,其他的任何寄存器可以不用保存,任意修改。e. 实现(shxin)函数功能。f. 如果函数返回标量数据,将它放入累加器。g. 将ARP设定为AR1。h. 如果保护了AR6、AR7,恢复这两个寄存器。i. 删除局部帧。j. 恢复FP。k. 从软件堆栈中弹出返回地址并压入硬件堆栈。l. 返回。第43页/共88页第四十三页,共89页。44(3)被调用函数的特殊情况被调用的函数有三种特殊情况:a. 返

33、回(fnhu)的是一个结构体:当函数的返回(fnhu)值为一个结构时,调用者函数负责分配存储空间,并将存储空间地址作为最后一个输入参数传递给被调用函数。被调用函数将要返回(fnhu)的结构拷贝到这个参数所指向的内存空间。b. 不将返回(fnhu)地址移到软件堆栈中:当被调用函数不再调用其它函数,或者确定调用深度不会超过8级,可以不用将返回(fnhu)地址移动到软件堆栈。c. 不分配局部帧:如果函数没有输入参数,不使用局部变量,就不需要修改AR0(FP),因此也不需要对其进行保护。第44页/共88页第四十四页,共89页。45第45页/共88页第四十五页,共89页。4615.3.2 C语言调用汇编

34、(hubin)函数a. 所有的函数,无论是C函数还是汇编语言函数,都必须遵循寄存器规则。b. 必须保存被函数修改的任何专用寄存器,包括(boku):AR0(FP)、AR1(SP)、AR6、AR7。如果正常使用堆栈,则不必明确保存SP。也就是说,用户可以自由地使用堆栈,弹出被压入的所有内容。用户可以自由使用所有其他的寄存器,而不必保留它们的内容。c. 如果改变了任何一个寄存器位域状态的设定值,则必须确保恢复其设定值。尤其注意ARP应该被指定为AR1。d. 中断子程序必须保存所有使用的寄存器。e. 在从汇编语言中调用C函数时,将参数以倒序压入堆栈,函数调用后弹出堆栈。第46页/共88页第四十六页,

35、共89页。47f. 调用C函数时,只有专用的寄存器内容被保留,C函数可以改变其他任何寄存器的内容。g. 函数必须返回累加器中的值。h. 汇编模块使用.cinit段只能用于全局变量的初始化。boot.c中的启动子程序假定.cinit段完全是由初始化表组成。在.cinit段中放入其他的信息会破坏初始化表而导致(dozh)无法预知的后果。i. 编译器将在所有的C语言对象标识符的开头添加下划线“_”。在C语言中和汇编语言都要访问的对象必须在汇编语言中以下划线“_”作为前缀。例如,C语言中名为x的对象在汇编语言中为_x。仅在汇编语言模块中使用的对象可以使用不加下划线的标识符,不会和C语言中的标识符发生冲

36、突。j. 在C中被访问的任何汇编语言对象或在C中被调用的任何汇编语言函数必须在汇编代码中使用.global伪指令声明。这将声明该符号是外部的,允许链接器解决对它的引用。第47页/共88页第四十七页,共89页。4815.3.3 内嵌汇编(hubin)语句在TMS320C2000 C语言中,可以使用asm语句在编译器产生的汇编语言文件(wnjin)中嵌入单行的汇编语句。一系列的asm语句可以将顺序的汇编语句插入到编译器的输出代码中。使用中的几点注意事项:a. asm语句使用户可以访问某些用C语句无法访问的硬件特性。 例如, asm (“ CLRC INTM”) /开放中断b. 在使用asm语句的时

37、候,要防止破坏C环境。编译器不会对嵌入代码进行检查和分析。c. 在asm语句中使用跳转语句或标记符(LABEL)可能会产生无法预知的结果。第48页/共88页第四十八页,共89页。49g. 调用C函数时,只有专用的寄存器内容被保留,C函数可以改变(gibin)其他任何寄存器的内容。h. 函数必须返回累加器中的值。d. 不要改变C变量的值,但可以安全地读取任何变量的当前值。e. 不要使用asm语句嵌入汇编伪指令,这会破坏汇编语言(hu bin y yn)环境。f. 在编译器的输出代码中嵌入注释时,asm语句是很有用的。可以用星号(*)作为汇编代码的开头,如: asm (“ * this is an

38、 assembly language comment.”);第49页/共88页第四十九页,共89页。50i. 汇编模块使用.cinit段只能用于全局变量的初始化。boot.c中的启动子程序假定.cinit段完全是由初始化表组成。在.cinit段中放入其他的信息会破坏初始化表而导致无法(wf)预知的后果。j. 编译器将在所有的C语言对象标识符的开头添加下划线“_”。在C语言中和汇编语言都要访问的对象必须在汇编语言中以下划线“_”作为前缀。例如,C语言中名为x的对象在汇编语言中为_x。仅在汇编语言模块中使用的对象可以使用不加下划线的标识符,不会和C语言中的标识符发生冲突。k. 在C中被访问的任何汇

39、编语言对象或在C中被调用的任何汇编语言函数必须在汇编代码中使用.global伪指令声明。这将声明该符号是外部的,允许链接器解决对它的引用。第50页/共88页第五十页,共89页。5115.3.4 C程序访问汇编程序(hu bin chn x)变量有时候需要在C程序中访问(fngwn)汇编语言变量,这通常有两种方式:访问(fngwn).bss段中的变量:将要访问(fngwn)的变量定义在.bss段中。用.golbal声明要访问(fngwn)的变量。在汇编语言中以下横线“_”为前缀声明要访问(fngwn)的变量。在C语言中将变量声明为外部变量(extern),就可以进行正常访问(fngwn)。第51

40、页/共88页第五十一页,共89页。52例,在C程序中访问(fngwn)在.bss段中定义的变量。汇编程序:.bss _var,1;定义变量.global _var;声明为全局变量C程序:extern int var/声明为外部变量var=1/访问(fngwn)变量 第52页/共88页第五十二页,共89页。53访问非.bss段中的变量:要访问非.bss段中的变量,通常的办法是在汇编语言中定义一个查找表,然后在C语言中通过指针来访问。首先定义变量,而且最好放在独立的初始化块中。定义一个全局的标识指向对象(duxing)的起始点,这样对象(duxing)可以分配在存储器空间的任何位置。在C程序中将这

41、个对象(duxing)定义为外部对象(duxing)(extern),并且对象(duxing)名称不带下横线“_”前缀,就可以对其进行正常访问。第53页/共88页第五十三页,共89页。54例,在C程序中访问不在.bss段中定义的变量(binling)。汇编程序:.global _sine;声明为全局变量(binling).sect “sine_tab”;建立一个独立的段_sine:;常数表起始地址.float 0.0.float 0.015987.float 0.022145C程序:extern float sine/声明为外部变量(binling)float *sine_p=sine;/声明

42、一个指针指向该变量(binling)f=sine_p4; /作为普通数组访问sine数组第54页/共88页第五十四页,共89页。5515.3.5 修改(xigi)C编译器的输出用户可以编译源程序,然后在汇编前对编译输出的汇编语言(hu bin y yn)代码进行手动检查和修改。这种情况下,在C代码中利用asm语句插入适当的注释对理解C编译器输出的汇编语言(hu bin y yn)代码是非常有帮助的。第55页/共88页第五十五页,共89页。5613.4 运行支持运行支持(zhch)函数函数 (rts)一个C程序所执行的一些任务(如输入/输出、动态存储器配置、字符串操作以及三角函数等)不是C语言的

43、一部分。TMS320C2000 C编译器可以提供除了用于处理意外情况和地域相关问题(如基于(jy)当地的语言、民族或文化的程序)的工具之外的全部ANSI的标准库的内容。使用ANSI的标准库可以确保有一套统一的函数。a. rts2xx.lib:运行期支持目标库,包含: ANSI C标准库 系统启动程序_c_int0 允许C访问特殊指令的函数和宏b. rts.src:运行期支持资源库。包含运行期支持目标库的C语言和汇编语言程序源代码。第56页/共88页第五十六页,共89页。5713.5.1 快速(kui s)傅里叶变换 傅里叶变换是一种将时域信号变换为频域信号的变换形式。在频域分析中,信号的频率及

44、对应的幅值、相位(统称为频谱)反映了系统的性能。快速傅里叶变换(Fast Fourier Transform, FFT)是离散(lsn)傅里叶变换(Discrete Fourier Transform, DFT)的快速实现方法 。13.5 常用常用(chn yn)数字信数字信号处理程序号处理程序FFT、FIR等,实际应用中最好用汇编语言实现,有丰富的资料可供参考。第57页/共88页第五十七页,共89页。58序列(xli)x(n)的离散傅里叶变换(DFT) 非周期(zhuq)连续时间信号x(t)的傅里叶变换为 第58页/共88页第五十八页,共89页。59 一个N点的DFT可以分解为两个N/2点的

45、DFT,每个N/2点的DFT又可以分解为两个N/4点的DFT。当N为2的整数(zhngsh)次幂时,由于每分解一次降低一次幂阶,通过M次分解,最后全部成为一系列2点DFT运算。 快速(kui s)傅里叶变换第59页/共88页第五十九页,共89页。60例,时间(shjin)抽取的FFT算法DSP C语言实现实例。FFT运算函数与主函数为#includemath.h/数学(shxu)函数头文件#define PI 3.1415926#define N 128/采样次数Nvoid InitForFFT( );/FFT初始化函数void MakeWave( );/波形发生函数void finv(int

46、 N1, float *xr, float *xi);/倒序运算函数f(N1,Xr,Xi),对输入序列倒序int INPUTN, DATAN;float fWaveRN, fWaveIN, wN;float sin_tabN,cos_tabN;/正余弦函数表int Mum; /Mum为蝶形运算的级数第60页/共88页第六十页,共89页。61void FFT(float XrN,float XiN) /时间抽取法FFT程序,要求采样点数N为2的整数(zhngsh)幂次方/Xr , Xi 分别为输入序列的实部和虚部int S,B;/S为旋转因子的幂数, B为蝶形运算输入数据的距离,/也即各级旋转因

47、子的个数int m, j, k;float X,Y;finv(N, Xr, Xi); /倒序运算函数,对输入序列倒序for (m=1; m=Mum; m+)B=(int)(pow(2,m-1)+0.5); /B=2(m-1)for(j=0; jB; j+) /每级需要进行B种蝶形运算S=j*(int)(pow(2,Mum-m)+0.5);/S=2(Mum-1)for(k=j; k=N-1; k+=(int)(pow(2,m)+0.5)第61页/共88页第六十一页,共89页。62/每种蝶形运算在某一级中需要进行N/pow(2,m)次 /蝶形运算展开,结果的实部和虚部 /分别存储(cn ch)在原

48、实部和虚部位置X=Xrk+B*cos_tabS+Xik+B*sin_tabS;Y=Xik+B*cos_tabS-Xrk+B*sin_tabS;Xrk+B=Xrk-X;Xik+B=Xik-Y;Xrk=Xrk+X;Xik=Xik+Y;for ( m=0;mN/2;m+ ) wm=sqrt(Xrm*Xrm+Xim*Xim); /计算功率普 第62页/共88页第六十二页,共89页。63main()int i;InitForFFT( ); /FFT初始化函数MakeWave( ); /波形(b xn)发生函数for ( i=0;iN;i+ )fWaveRi=INPUTi;fWaveIi=0.0; wi=

49、0.0;Mum=(int)(0.5+log(N)/log(2);/Mum为蝶形运算的级数, N=2MumFFT(fWaveR,fWaveI);for ( i=0;iN;i+ ) DATAi=wi;while ( 1 ); 第63页/共88页第六十三页,共89页。64void InitForFFT()/FFT初始化函数,建立正余弦函数表int i;for ( i=0;iN;i+ )sin_tabi=sin(PI*2*i/N);cos_tabi=cos(PI*2*i/N);void MakeWave()/波形发生(fshng)函数int i;for ( i=0;iN;i+ )INPUTi=sin(

50、PI*2*i/N*3)*1024; /f=3Hz, 正弦函数第64页/共88页第六十四页,共89页。65FFT函数包含的函数finv(N,Xr,Xi)为倒序运算,函数代码如下。/倒序运算函数finv(N1,Xr,Xi),对输入序列倒序/N1为序列长度; Xr , Xi 分别(fnbi)为输入序列的实部和虚部/倒序原理:倒序数的加1是在最高位加1,/满2向次高位进1,最高位变0,依次往下/从当前倒序值可求下一倒序值void finv(int N1, float *xr, float *xi)/倒序运算函数f(N1,Xr,Xi),对输入序列倒序int m, n,N2,k;/ m为正序数;n为到序数

51、;k为各个权值;N2为最高位的权值float T;/临时变量TN2=N1/2;/最高位加1相当于十进制加上最高位的权N1/2n=N2;/第一个倒序值for (m=1; m=N1-2;m+)/第0个和最后一个不倒序第65页/共88页第六十五页,共89页。66if(mn) /为了避免(bmin)再次调换,只需对m=k)n=n-k;/次高位位1,继续上下进位,满2置0k=(int)(k/2+0.5); /向下权值依次比上级减半n=n+k;/得到下一倒序值 第66页/共88页第六十六页,共89页。6713.5.2 FIR数字(shz)滤波器 在数字信号处理中,数字滤波占有极其重要的地位。无限冲击响应(

52、Finite Impulse Response, FIR)数字滤波器(Digital Filter)是一种常用数字信号处理算法。利用窗函数法设计(shj)FIR滤波器,可以实现线性相位的数字滤波器 。1. FIR数字滤波器的设计(shj)方法设FIR数字滤波器的单位冲击响应为h(n),则传递函数H(z)为 第67页/共88页第六十七页,共89页。68FIR数字(shz)滤波器的系数h(n) w(n)为窗函数。理想(lxing)单位冲击响应h1(n)可以根据给定的理想(lxing)频率响应求得FIR数字(shz)滤波器的差分方程为 式中,x(i)为输入序列,y(i)为输出序列, N为滤波器阶数。

53、 第68页/共88页第六十八页,共89页。69 滤波器差分(ch fn)方程为y(i)=0.001x(i-2)- 0.002x(i-3)- 0.002x(i-4)+ 0.01x(i-5)-0.009x(i-6)-0.018x(i-7)+0.049x(i-8)- 0.02x(i-10)+ 0.11x(i-11)+0.28x(i-12)+0.64x(i-13)+0.28x(i-14)- 0.11x(i-15)- 0.02x(i-16)-0.049x(i-17)-0.018x(i-18)-0.009x(i-19)+0.01x(i-20)- 0.002x(i-21)-0.002x(i-22)+ 0.0

54、01x(i-23 例,实现一个低通FIR数字滤波器。要求带通边缘(binyun)频率为10kHz, 阻带边缘(binyun)频率为22kHz,阻带衰减为75dB,采样频率为fs=50kHz。 数字(shz)滤波器程序参见教材。 第69页/共88页第六十九页,共89页。7013.6 闪存编程闪存编程在DSP控制程序编写、调试完成后,需要将程序 编 译、链接所得到的可执行文件(.out)编程到DSP的程序存储器中,使DSP可以摆脱开发系统运行, 所开发的系统成为一套独立的系统。对于TMS320LF2407而言,应该(ynggi)将软件开发得到的可执 行文件编程到内部闪存(Flash)中,即进行 F

55、lash编程。烧写DSP程序也要利用硬件仿真器来实现,仿真器制 造商会提供相应的烧写程序。要注意不同型号的 DSP往往使用不同的烧写程序,不同类型的仿真器 对烧写环境也会有不同的要求,使用前要详细阅 读相应说明(readme)。注意MP/MC*模式置为微计算机模式,仿真RAM不被PS*信号选中。第70页/共88页第七十页,共89页。71DSP烧写步骤(bzhu):清除flash内容(bc0.bat, bc1.bat)。将FLASH(EEPROM)中的所有位清零(set to 0)。擦除flash内容(be0.bat, be1.bat)。将FLASH(EEPROM)中的所有位置位(set to

56、1)。把目标程序写进flash中(bp16k.bat, bp32k.bat)。将FLASH(EEPROM)中的所有选中的位清零(set to 0)。第71页/共88页第七十一页,共89页。72在实际应用中,仿真调试通过的程序编程到DSP中独立运行的结果往往与仿真的状态有差异,甚至可能系统完全不能正常运行,这是由于仿真过程中的程序运行情况(qngkung)和DSP独立运行时的程序运行情况(qngkung)不同所引起的。在将程序编程到DSP内部之前,需要对以下几个问题深入考虑,以保证编程后系统的正常运行:(1)电路元件初始化同步问题:由于外部元件初始化可能较慢,DSP初始化完成后要延时一段时间再访

57、问外部慢速器件,通常要在控制程序的主函数中添加一段循环延时程序。第72页/共88页第七十二页,共89页。73(2)用仿真器调试时程序执行(zhxng)速度比较慢,循环时间比较长,而烧写到DSP中可能时间比较短,要对决定循环时间的循环次数重新考虑。(3)用仿真器调试的时候,DSP运行的一些资源(如堆栈等)用的是仿真器中的资源,烧写到DSP中执行(zhxng)必须利用DSP本身的资源,烧写前必须对链接命令文件(.cmd文件)中定义的各种资源进行详细考虑。第73页/共88页第七十三页,共89页。74(4)浮点数运算的问题:浮点型变量考虑(kol)使用全局变量,因为局部变量都是在堆栈里生成的,过多的浮

58、点数变量对软件堆栈要求太多,容易造成堆栈溢出问题。(5)复位问题:利用仿真器进行调试的时候,DSP程序通过仿真环境启动,不需要复位信号;而闪存编程后DSP的运行中,复位要通过电路板上复位电路来实现,如果电路板上复位电路有问题,不能保证DSP的正常复位,会造成仿真通过的程序编程到DSP中后完全无法正常执行。第74页/共88页第七十四页,共89页。75(6)时钟问题:利用仿真(fn zhn)器进行仿真(fn zhn)调试时时钟由硬件仿真(fn zhn)器提供,而闪存编程后DSP运行时钟由电路板时钟电路提供,如果电路板时钟电路有问题,编程后的DSP将无法正常工作。闪存编程之后DSP独立运行的时候出现

59、的很多问题都是由于时序配合引起的,这就需要调整程序中的各种延时,甚至可能要经过反复调整来寻求最佳的延时设置,以保证系统功能的正常实现。第75页/共88页第七十五页,共89页。7613.7 程序设计程序设计(chn x sh j)举例举例15.7.1 功能(gngnng)要求按照一定的频率控制四个发光二极管的点亮状 态,采用定时器中断(zhngdun)C语言编程。要求如下:(1)四个发光二极管依次循环显示 0000b1111b;(2)发光二极管显示刷新频率10Hz(周期100ms);(3)发光二极管的控制映射在I/O空间0xC的低四 位,写1点亮;(4)显示刷新频率的控制利用定时器T1(100m

60、s)实现。第76页/共88页第七十六页,共89页。7715.7.2 工程(gngchng)组成分析功能要求,对发光二极管的控制可以通过对I/O空间的端口读写来实现,而显示频率的控制要利用定时器来实现。由于程序功能要求简单,流程控制容易实现,采用定时器中断方式。由此,此控制程序的工程中应该包含如下文件:(1)链接命令文件.cmd,配置资源映射;(2)头文件.h,定义(dngy)2407的片内外设控制寄存器;(3)汇编代码文件.asm,定义(dngy)中断向量表;(4)C代码文件.c,程序文件。第77页/共88页第七十七页,共89页。7815.7.3 链接(lin ji)命令文件(led.cmd)

61、-l rts2xx.libMEMORY PAGE 0:VECS :o=0, l=40hPROG :o=9000h, l=2000hPAGE 1:IDATA1:o=300h, l=100hIDATA2:o=0c00h, l=400hREG_MEM: o=7000h, l=1000h SECTIONS .vectors :VECS PAGE 0.text :PROG PAGE 0.cinit :PROG PAGE 0.data :PROG PAGE 0.stack :IDATA2 PAGE 1.bss :IDATA2 PAGE 1.reg240x : REG_MEM PAGE 1 第78页/共88

62、页第七十八页,共89页。7915.7.4 头文件头文件2407c.h主要定义TMS320LF2407的片内外设控制寄存器。参见附录(fl)。此文件在利用TMS320LF2407进行的各种开发中可以通用。15.7.5 汇编文件示例程序中没有利用汇编语言编写控制程序,但由于对定时器中断的处理采用回调方式,需要编写汇编文件(vectors.asm)定义中断向量表。.ref _gptime1,_c_int0.sect .vectorsRSVECT B _c_int0 ; Reset VectorINT1 B PHANTOM ; Interrupt Level 1INT2 B _gptime1 ; In

63、terrupt Level 2INT3 B GISR3 ; Interrupt Level 3第79页/共88页第七十九页,共89页。8015.7.6 C文件(wnjin)(led.c)(1)声明部分(2)主函数(3)初始化定时器函数(4)定时器中断(zhngdun)服务函数gp_init第80页/共88页第八十页,共89页。81/声明部分#include “2407c.h”/*包含头文件*/#define T1MS 0x93cf/*周期寄存器值4000-1,1ms=0.025us*4000*/void interrupt gptime1 (void);/中断服务函数(hnsh)声明void

64、gp_init (void)/T1初始化函数(hnsh)声明ioport unsigned int port000c;/I/O口声明unsigned int nCount, uWork,uWork1;/变量声明第81页/共88页第八十一页,共89页。82main ( )/主函数 nCount=0, nWork1=0;asm(“ setc INTM”) /*关中断(zhngdun)*/*WDCR=0x6f;*WDKEY=0X5555;*WDKEY=0XAAA;/*关闭看门狗*/*SCSR1=0x81fe;/*设置DSP运行频率为40MHz,4倍频*/*MCRB=0/*配置I/O口,PC口为I/O

65、口*/gp_int();/*初始化定时器*/*IMR=0x02; /* 使能定时器中断(zhngdun)(INT2)*/*IFR=0xffff; /* 清除中断(zhngdun)标志 */asm(“ clrc INTM”)/*开中断(zhngdun)*/while (1) ;/*等中断(zhngdun)*/第82页/共88页第八十二页,共89页。83void gp_init (void)/T1初始化函数 *EVAIMRA=0x80; /* 使能T1PINT定时器1周期中断*/*EVAIFRA=0xffff; /* 清除(qngch)中断标志 */*GPTCON=0x0000;*T1PR=T1M

66、S;/*周期寄存器值4000,1ms=0.025us*4000*/*T1CNT=0;/*计数初值=0*/*T1CON=0x1040;/*T1初始化, 连续增方式,定标TPS=1*/*启动定时器*/第83页/共88页第八十三页,共89页。84void interrupt gptime1 (void)/中断服务函数,每100ms刷新显示uWork= *PIVR ; /* 读外设中断向量寄存器*/switch(uWork) case 0x27: /* T1PINT,0x27为定时器1的周期中断的向量值 */ *EVAIFRA=0x80; /* 清除中断标志(biozh)T1PINT */nCount

67、+;if(nCount=100)/*计数100次,100ms=100*1ms=0.1s*/port000c=nWork1+;/*显示,00001111*/uWork1%=0x100;nCount=0;break;第84页/共88页第八十四页,共89页。8515.7.7 实例(shl)总结实例功能要求虽然简单,却包含了DSP控制程序设计中的许多问题,包括:(1)各种文件的编写:头文件(2407.h)、链接命令文件(led.cmd)、汇编代码文件(vectors.asm)、C源文件(led.c);(2)数据空间的读写,对各种片内外设控制寄存器的设置都是通过数据空间的写操作实现的;(3)I/O空间的

68、读写,四个发光二极管的显示(xinsh)控制就是通过对I/O空间的写操作实现的;第85页/共88页第八十五页,共89页。86(4)中断服务函数的编写,程序中的gptime1函数是一个中断服务函数,从函数定义到两级中断服务函数的结构都是DSP C语言编程中常用的中断处理方法;(5)中断向量表的定义,虽然实例程序中只有一个自定义中断服务函数,但中断向量表的定义方法在各种DSP应用中是类似的。实例程序已经覆盖到了DSP控制程序设计中大多数常见的问题,而在实际应用中可能存在的各种复杂(fz)问题的解决方法则需要在应用中深入研究。第86页/共88页第八十六页,共89页。87思考题与习题(xt)(xt)1

69、.DSPC语言有哪些特点?2.C24xDSP编译器有哪些数据类型?3.如何访问片内外设寄存器的某些位?4.如何直接访问存储器单元?5.pragma编译预处理命令有什么用途?6.C语言与汇编语言混合编程有哪些方法?7.C24xDSP的C编译器扩展了哪几个关键字?8.1个LED指示灯接到DSP的通用(tngyng)I/O引脚GPIOB4。采用通用(tngyng)定时器T1中断方式定时200ms,用C语言编程使之闪烁,XCLKIN=10MHz,CLKOUT=40MHz。9.如何用DSPC语言编程实现常用的FFT与FIR信号处理算法?第87页/共88页第八十七页,共89页。88感谢您的欣赏(xnshng)!第88页/共88页第八十八页,共89页。内容(nirng)总结1。具有多个字符的字符常数按序列中最后一个字符来编码,例如:。.switch段,包含switch语句表。c. 如果改变了任何一个寄存器位域状态的设定值,则必须确保(qubo)恢复其设定值。c. 在asm语句中使用跳转语句或标记符(LABEL)可能会产生无法预知的结果。用户可以编译源程序,然后在汇编前对编译输出的汇编语言代码进行手动检查和修改。利用窗函数法设计FIR滤波器,可以实现线性相位的数字滤波器。感谢您的欣赏第八十九页,共89页。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号