1、 嵌入式 C 语言开发 ADSP21XX 系列 DSP嵌入式 C 语言开发 ADSP21XX 系列 DSPDSP 论文 嵌入式 C 语言开发 ADSP21XX 系列 DSP摘要:详细介绍使用 VisualDSP 开发工具进行 ADSP21XX 的 C 语言编程的方法;分析其 C 语言运行库的结构,并且结合实例介绍 C语言工具的使用方法,包括 C 语言与汇编语言混合编程的方法,从C 运行库提取代码用于自己的汇编语言程序的方法、修改运行库的源代码以适应自己开发需要的方法等。 关键词:DSP VisualDSP 嵌入式 C 语言 汇编语言引言长期以来,在 DSP 系统开发中,一直把汇编语言作为主要的
2、开发工具;但汇编语言与自然语言差距很大,不易常,而且汇编语言是依赖于处理器的,不利于软件的可重复利用和系统的稳定性,程序不易移植,给开发工作带来了很大的困难。随着嵌入式系统复杂程度的不断提高,用汇编语言编写一个巨大的程度将是困难,甚至是不可能的。为此,AD 公司推出了针对 ADSP21XX 系列 DSP 的嵌入式 C 和 C+语言集成开发工具,分别是 VisualDSP 和 VisualDSP+系列,这些开发工具提供了 C 语言和 C+语音的开发功能。以下就以笔者在实际开发中的一些经验,结合 VisualDSP6.1 版本,介绍用C 语言开发 VisualDSP6.1 版本,介绍用 C 语言开
3、发 ADSP21XX 的方法。VisualDSP 提供了一个开放源码软件组织 GNU 的 C 编译器,和一套成熟稳定的 C 运行时间库(C Run time Library)等。GNU 的编译器一向以编译效率高著称,在编译后的代码长度和运行速度方面非常优秀;C 运行时间库则把很多重复性的工作,如浮点运行、三角函数、FFT 等作为 C 语言的库函数,提供给用户,大大提高了用户的开发效率和程序的稳定性,降低了开发难度,另外,由于把这些库函数的源代码提供给了用户,还提高了 C 语言与汇编语言之间的透明性,使用户开发的程序兼具两者的优点。1 Visual DSP 简介VisualDSP 是 AD 公司
4、的 DSP 开发工具,主要由可执行文件、库文件和各种帮助文档组成。6.1 版本还带有一个基于图形界面,针对21XX 系列 DSP 的软件仿真和调试工具。VisualDSP 的可执行文件包括汇编、编译、链接工具以及可执行文件重新格式化工具等,见表 1。表 1 VisualDSP 的可执行文件及用途VisualDSP 套件中的软件仿真调试工具 DEBUGAPP,采用P_lib_prog_term;NOP;第一条指令是调用 C 库函数中的_ _lib_setup_everything 函数作程序启动时的初始化工作。接下来,调用 C 语言程序中的 main_函数,进入 C 程序的主体,也就是进入用户自
5、己程序,开始正常工作。主程序结束后,再调用_lib_prog_term 函数,作程序退出时的结尾工作。由于嵌入式系统的特性,系统绝大多数都在主程序运行时被继电了,所以_lib_prog_term 得到执行的机会很小。其它的中断向量由 C 运行库来管理,汇编指令如下:_Interrupt2:JUMP_lib_int2_ctrl;NOP;NOP;NOP;其中的_lib_int2_crtl 就是 C 语言库中控制 INT2 的函数。如果用户要使用该中断,应先把中断服务程序用一个 C 库函数 Interrupt()把服务函数指针设定好,并打开相应的中断允许位,当该中断发生时,_lib_int2_ctr
6、1 函数就会控制 DSP 跳转到相应的指针位置。VisualDSP 预定义的 C 语言库函数包括数学函数、 FFT 函数、ANSI 标准内存管理和字符串管理函数的一个子集。所有的函数列表可参考 VisualDSP 的联机文档。这些库函数以二进制代码的形式,打包集合在 lib*.a 文件中,用户的 C 语言程序可以像使用自己的子程序一样方便地调用这些库函数。下面是调用库函数的一个例子。#include math.h /包含所需的头文件float a,b,c; /定义所需的变量c=a*sin(b); /数学运算编译后产生的汇编源代码中有 call sin_指令,就是调用 sin 库函数的汇编语言指
7、令语句。从嵌入式开发的角度讲,VisualDSP 的 C 语言工具已经提供了一个操作系统雏形的功能。在 AD 公司的 ADMC 系列 DSP 中,已经把这些库函数和一些电机控制专用的函数,以及程序加载功能,集成在了 DSP 的片内 ROM 中。3 C 语言与汇编语言混合编程方法用 C 语言开发的缺点是不能精确控制程序运行的时间,对于实时性要求较高的应用,必须用汇编语言。VisualDSP 为用户提供了两种与汇编语言的接口方法:用 ASM()方法,直接嵌入汇编语言语句;用汇编语言编写子程序,供 C 语言程序调用。为了支持 C 语言与汇编程序程序的接口,VisualDSP 预定义了诸如FUNCTI
8、ON_ENTRY、 EXIT、SAVE_REG、RESTORE_REG 等 13个宏。限于篇幅,不详细介绍其功能。使用这些宏以前,要包含asm_sprt.h 头文件。3.1 使用 ASM()嵌入行的方法使用这一方法时,一定要注意各寄存器和堆栈当前的状态,以免破坏程序运行的环境,产生错误的结果。VisualDSP 保留了一些内部寄存器供用户的汇编代码使用。用户可以自由地修改其内容,而不会对程序造成破坏。这些寄存器包括AR、 AF、AY1、M5、11、16、MF、MR0 等 18 个。如果不够用,可以用系统定义的宏 save_reg 和 restore_reg 保护现场,得到另外 11个可用寄存器
9、。另外要注意的是,在汇编语言中操作 C 语言中定义的变量时,要在变量名后加下划线。下面是一个嵌套汇编语言的例子:int img228; /定义 C 语言变量asm(“ax0=0x5c;”)asm(“dm(ing228_)=ax0”); /用汇编语言赋值要将 Img228 变成Img228_img228=0x5c; /直接用 C 语言赋值编译后的汇编语言代码是ax0=0x5c;dm(img228_)=ax0my1=92;dm(img228_)=my1;注意前者可能会破坏程序结构,因为它使用了未经保护的寄存器AX0;而由 C 语言产生的汇编代码,则会自动选择合适的临时寄存器 MY1。3.2 使用汇
10、编子程序的方法使用汇编子程序是 C 语言程序与汇编语言接口的另一种方法。用户定义的子程序放在单独的汇编文件中,或是做成二进制的库文件,并将子程序的定义用 GLOBEL 输出,汇编后就可以供 C 语言程序调用。下面是一个不需要参数的子程序的例子:.MODULE/RAM_delay_;.external del_cycle; /声明 del_cycle 是外部变量.global delay; /声明 delay 为全局函数delay_:runction_entry; /子程序开始标志,必须要的ar=dm(del_cycle_);cntr=ar;do d_loop until ce;d_loop:n
11、op;exit; /子程序结束标志,必须要的.ENDMOD;如果汇编语言子程序中用到了参数,情况就复杂些。子程序中的入口参数前两个一定要保存在 AR、AY1 中。如果参数多于两个就要把其余的放在堆栈中。所有子程序的第一个返回值放在 AR 中。如果返回值不止一个,就要用到变量型参数或者指针来获得取所有的返回值了。下面是一个有 5 个输入参数、1 个返回值的子程序例子。add5_:function_entry;ar=ar+ay1; /前面的两个变量放在 AR、AY1 中readsfirst(ay1); /从程序堆栈中读取第三个变量ar=ar+ay1;ay1=readsnext; /从程序堆栈中读取
12、第四个变量ar=ar+ay1;ay1=readsnext; /从程序堆栈中读取第五个变量ar=ar+ay1; /返回值放在 AR 中exit;注意其中的 readsfirst 和 readsnext 都是汇编语言接口宏。其功能是从堆栈中读取所有的参数。4 C 运行库的汇编源代码如果只用 C 语言来开发 21XX 程序,只要有 C 运行库的二进制版就够了。幸运的是,AD 公司把所有 C 运行库的汇编源代码随VisualDSP 提供给了用户,所以对那些用汇编语言开发的工程师来说,这些源代码也提供了很大的帮助。因此这代表很多功能的子程序不需要自己去编码、调试,用到某功能时只要把相应的汇编代码链接进自
13、己的程序就可以。C 运行库的源代码是扩展名为 DSP 的文本文件。基本上一个库函数对应一个文件,文件名就是函数名。比如说 sin.dsp 是正弦、余弦查找、使用都很方便,但是对于其中的交叉调用要注意。反过来,用户也可以把自己已经调试、验证过的汇编子程序,做成二进制库文件,供 C 程序调用,这样可以大大提高软件的可重复利用率。要制作二进制库文件,只要用 lib21.exe 工具处理就行了。注意,生成的二制库文件的名字必须以.a 作为文件扩展名。笔者在实际的开发中,遇到这样的情况,自制的 2181 目标板上有一个自己开忍气吞声驻留程序,通过软件模拟的异步串口与 PC 通信,加载程序。但是这个驻留程
14、序占据了 00x500 的空间,用户开发的程序只能加载到从 0x500 开始的空间内,而用 C 语言开发的程序起始地址都是从 0 开始的。为了解决这个问题,只能自己修改2181_hdr.dsp 源文件。首先把第一行的.MODULE/ABS=0 改成.MODULE/ABS=0x500,然后汇编成 obj 文件,代替原来的文件。另外,在自己的程序中定义一个从 0 开始 0x500 大小的 PM 区域,并初始化成 0,就可以防止编译器在该区域内分配别的变量或程序代码,这样编译后的可执行文件的 00x500 空间都是 0,加载时把它剔除,而其它有用的指令代码都在 0x500 之后,解决了这一个问题。5 总结从实际开发的经验来看,VisualDSP 的 C 语言开发功能十分丰富。虽然提供的库函数只是 ANSI 的一个不完备子集,但是对于一般的工程开发来说已经足够用了,而且 VisualDSP 还提供了 C 运行库的源代码,这对于解决函数不完备的问题也好处。用 C 语言开发的好处还包括开发时间大大减少,程序的稳定性大大提高,这对于面对激烈的市场竞争,对于减轻设计工程师的工作量都很有好处。最后,用 C 语言开发是趋势,必将更加流行。