1 TMS320LF240X DSP硬件结构特点
TMS320LF240x DSP有以下一些特点:采用高性能静态CMOS技术,使得供电电压降为3.3V,减少了功耗;基于TMS320C2xxDSP的CPU核,保证与TMS320系列DSP代码兼容;片内有高达32K字的Flash程序存储器,544字的双口RAM(DARAM)和2K字的单口RAM(SARAM);两个事件管理器模块EVA和EVB,适用于控制各类电机;看门狗定时器模块(WDT);控制器局域网络(CAN)2.0B模块;串行通信接口(SCI)模块;16位的串行外设接口(SPI)模块;JTAG接口,使得在系统编程(ISP,)很容易实现;10位A/D转换器最小的转换时间为500ns,可选择由两个事件管理器来触发2个8通道输入A/D转换器或1个16通道输入A/D转换器,而每次要转换的通道都可通过编程来选择。需要说明的是,TMS320LF240x DSF是定点l6位芯片,存储数据的最小单位是16位的字,每个地址(包括程序地址、数据地址及I/O地址)所存的数据都是16位。
1.1 改进的哈佛结构和流水线操作
DSP采用程序空间和数据空间完全分开的哈佛(Havard)结构,允许同时取指令和操作数,而且允许在程序空间和数据空间之间相互传递数据,即改进的哈佛结构。TMS320LF240x DSP的cPu核心具有独立的内部数据和程序总线结构。数据和程序总线分为6条l6位的总线,分别为:PAB,程序地址总线,为读写程序空间提供地址;DRAB,数据读地址总线,为读数据空间提地址;DWAB,数据写地址总线,为写数据空间提供地址;PRDB,从程序空间向c.PU传送代码、立即操作数和表信息的程序读总线;DRDB,从数据空间向中央算术逻辑单元(CALU)和辅助寄存器算术单元(ARAU)传送数据的数据读总线;DWEB,可以传送数据到程序空间和数据空间的数据写总线。数据读地址总线(DRAB)和数据写地址总线(DWAB)是相互独立的地址总线,CPU 在相同的机器周期内可以同时进行数据读写操作。
TMS320LF240x DSP流水线具有四个独立的阶段:取指令、指令译码、取操作数以及指令执行。一般情况下,取指令占用PAB和PRDB;指令译码不占用任何程序和数据总线;取操作数占用DRAB和DRDB;指令执行包括将执行结果写回数据存储器,将占用DWAB和DWEB。可见,TMS320LF240x DSP独特的总线结构大大减少了流水线冲突,极大提高了指令的运行速度。
1. 2事件管理器模块
事件管理器模块提供了许多适用于运动控制和电机控制的功能。每个240x器件都包括两个事件管理器模块:EVA和EVB。每个事件管理器模块包括两个16位69通用定时器、比较单元、捕获单元、8个16位的脉宽调制(PWM)通道以及正交编码脉冲输入电路。它们能够实现:三相反相器控制;PWM的对称和非对称波形;编程的PWM死区控制以防止上下桥臂同时导通而引起短路。事件管理器模块适用于控制交流感应电机、无刷直流电机、开关磁阻电机、步进电机、多级电机以及逆变器。
2 C0FF目标文件
TI公司汇编器所创建的目标文件采用的是一种称为COFF(Common Object File Format)的文件格式,即共同目标文件格式。目的是提高编程和程序执行的效率,同时也有利于使用TI公司的BIOS(Basic Input Output System)。
COFF文件格式的核心概念就是使用代码段、数据段编程,而不是指令或数据简单的顺序编写。代码段和数据段的概念不仅是现代软件编制的重要技术概念,同时也是嵌入式系统的重要编程技术。使用这种技术的优点是:程序具有良好的可读性;程序具有良好的可移植性;能与系统存储单元充分配合。
在COFF目标文件中,段(section)是其最小的单位。所谓“段”就是最终在TMS320 DSP的存储器映像中占据连续空间的一块代码或数据。这些段在目标文件中是相互独立的。由于大多数系统都包含有不同类型的存储器(ROM、RAM、EEPROM),所以使用段可使用户更有效地利用目标存储器;所有段都能够独立进行重定位,因此可以将不同的段分配至不同类型的存储器中去。
通常,一个COFF目标文件中都包含三个缺省段:text段(通常包含可执行代码)、.data段(通常包含已初始化数据)和.bss段(通常为未初始化的数据保留所需的空间)。除了这三个缺省的段之外,编程人员可使用汇编器指示符(.sect和usect)自定义段。
TMS320LF240x DSP C编译器产生可重定位的数据段和代码段。这些段以不同方式分配到内存中,以满足不同的系统配置。编译器创建两种基本的段:初始化段和未初始化段。
初始化段包括数据表和可执行代码。C编译器创建下初始化段:
◆.text段一包含所有的可执行代码和浮点常数;
◆.cinlt段一包含用于初始化全局变量和静态变量的表:
◆.const段一包含字符常量以及用关键字const声明的全局和静态变量:
◆.switch段一包含switch语句的跳转表。
未初始化段在内存(通常是RAM)中保留空间。程序在运行时用这些空间创建和保存变量。编译器创建以下未初始化段:
◆.bss段一为全局变量和静态变量保存空间,在程序开始运行时,C初始化boot程序将数据从.Clnlt拷贝到bss段中;
◆.stack段——为系统堆栈分配存储空间,用于将变量传递至函数以及为局部变量分配空间;
◆.system段一为动态内存分配保留空间,为动态存储函数malloc、callo和realloc分配存储空间。当然,若C程序没有用到这些函数,那么编译器就不用创建system段了。
3 C程序运行环境
TMS320LF240x DSP提供两种编程语言:汇编语言和C语言。如果源程序为C语言,需调用TMS320LF240x DSP的C编译器将其编译成汇编语言,然后送汇编器进行汇编。汇编后产生COFF格式的目标文件,再用链接器进行链接(链接过程包括将编译器的运行支持库相关代码链接进来以及代码段和数据段的重定位),生成在TMS320LF240x DSP上可执行的COFF格式的目标代码(如有必要,可使用目标代码格式转换工具),并调用下载程序将目标代码下载到目标芯片上。
TMS32OC2xx DSP(当然包括TMS320LF240x DSP)C语言编译器包含两个库:rts2xx.1ib和rts.src。
(1)rts2xx.Ii b
rts2xx.1ib运行支持目标库。具有COFF文件格式。运行支持目标库(即rts2xx1ib)是由rts.src中的C和汇编源程序通过编译和汇编而得到的。rts2xx lib包含三部分内容:ANSI C标准库、系统启动程序c int00、允许C访问特殊指令的函数和宏。
链接程序时,必须指明具体的目标库并把该库作为链接输入文件之一,这样对目标库所包含的运行支持函数的引用就得到了解决。链接运行目标库时,链接器只是将目标库中被引用部分加进目标文件。这里所说的目标库指的就是rts2xx.lib。由于运行支持函数符合函数调用规约,可以直接被C访问。
(2)rts.src
rts.src运行支持源文件库,由c和汇编源程序组成,可在集成开发环境(CCS)下打开,任何一个运行支持函数的源代码都可以在rts.src找到。
rts.src中包含有用汇编语言编写的算术程序。由于这些函数的特殊调用规约,它们不能从C中被访问:但可以对它们作扩展或修改以作为自己的程序。只要修改后的程序遵循函数特定的调用规约和保护规约,它们就可以被C直接访问。
算术程序中包含浮点运算函数。浮点数采用IEEE754单精度浮点数格式为
浮点数由3部分组成,即符号位(“S”)、指数和尾数。指数是有+127偏置的无符号整数。一个浮点数占有32位,占用TMS320LF240x DSP两个字的空间。32位规格化数的值由值(规格化)=(-1)3×l.尾数×2(指数-127)给出。这样,浮点数O.5的单精度浮点数为3F000000h,格式为
例如,源库rts.src中的汇编函数F$$ITOF是将16位有符号整形数转换为浮点数,只要在汇编程序中加入“ref F$$ITOF”指令,即可直接调用该函数。查看F$$ITOF函数的说明文档可知,该函数不遵循C子程序调用规约,所以它不能直接被C调用。
下面介绍C程序的系统初始化。
在运行C程序之前,必须创建C运行环境。这个程序由C引导程序使用名为c_intO的函数来执行。运行支持源库(rts.src)在名为boot.asm的模块中包含这个程序的源程序。c_intO执行如下初始化C环境的任务:
①为系统堆栈定义一个名为stack的段,并设置初始化指针;
②初始化全局变量,将.Clnlt段中的初始化表中的数据复制到bss段中;
③调用函数main来运行C程序。
运行堆栈(即.stack段)被分配在存储器的一个连续块中,并且从低地址向高地址增加。寄存器ARl通常指向堆栈中下一个可获得的字(堆栈顶加一个字)。代码不会检查运行时堆栈是否会溢出,因此要确保分配给堆栈足够的空间。
有些全局变量在C程序开始运行前必须赋初值,检索这些变量的数值并用数值将它们初始化的过程成为自动初始化。编译器在名为.clnlt(该段位于程序空间)的特殊段中建立表。该段包含了用于初始化全局变量和静态变量的数据。每个被编译模块都包含这些初始化表,链接器将它们组成单个表(单个的clnlt段)。引导程序使用这个表初始化所有的系统变量。
.clnlt段中的表是由多项初始化记录组成的。每个必须自动初始化的变量在.cinit段中都有记录,.clnlt段中初始化记录的格式如图l所示。
初始化记录包括三部分:字节长度,即需要初始化的变量个数;.bss中变量的指针,为该记录第一个变量在.bss段中的地址;初始化数据,指的是用于初始化变量的数据。初始化数据的个数必须和字节长度相等。在变量的自动初始化过程中,为了能让初始化程序识别初始化记录的结尾,最后一项初始化记录的第一个字用0填充,即该初始化记录的字节长度为0。至此初始化程
序完成了全局变量的初始化。
全局变量的初始化包括运行时变量的自动初始化和加载时变量的初始化。笔者认为,加载时变量的初始化没有实用价值。因为当DSP断电后,这些变量的值就丢失了。当DSP重新上电后,由于初始化程序不给这些全局变量赋初值,使得系统的初始化失败。
4 C语言和汇编语言的混合编程
开发DSP芯片可以用汇编语言或C语言。两种语言各有所长:用C语言开发DSP芯片,开发速度快,可读性好,可移植性强;而用汇编语言开发DSP芯片,则能充分利用DSP芯片的软硬件资源,程序代码的执行效率高。在DSP运算能力比较宽裕,实时性要求不是很强的场合,用C语言非常合适。在对运算速度以及实时性要求极高或者是在不能扩展外部存储器而且片内存储器又非常有限的条件下,使用汇编语言几乎是必须的。在程序的开发过程中,几乎不可避免地要使用C语言和汇编语言的混合编程。
用C语言和汇编语言进行混合编程主要有以下三种方法:
①独立编写C程序和汇编程序,分开编译或汇编形成各自的目标代码模块,然后用链接器将C语言模块和汇编模块链接起来。这其实就是一个C模块和汇编模块的接口问题。
②直接在C程序中的相应位置嵌入汇编语句。
③对C程序进行汇编生成相应代码,然后对这些汇编代码进行手工优化与修改。
在用c语言和汇编语言进行混合编程时,必须遵循寄存器规约和函数调用规约。
(1)寄存器规约
在C环境中,对什么寄存器用于完成什么样的操作有严格规定。所有这些规定统称为寄存器规约(registcr conventions)。如果想编写出正确的C语言DSP程序,将C程序和汇编程序接口,则必须理解和遵循这些规约寄存器规约规定编译器如何使用寄存器以及在函数的调用过程中如何保护寄存器。在函数的调用过程中有两种保护寄存器的方法:一种是在调用时保护寄存器(由调用函数来完成),另一种是在被调用函数程序的入口处保护寄存器(由被调用函数来完成)。限于篇幅,不再详细介绍。在编程的过程中,一定要严格遵循这些规约,否则,会出现错误。
(2)函数调用规约
C编译器对函数调用有一系列严格的规约。任何函数不管是调用C函数,还是被C函数调用,都必须遵循这些规约。不遵循这些规约将破坏C环境,导致程序运行失败。函数调用规约(function calling conyentions)l确规定在函数调用的全过程中,调用函数和被调用函数所必须执行的操作,以保证调用前后C环境的一致性。
当父函数调用子函数时,必须保证当前的辅助寄存器为ARl。父函数执行以下操作:①将被调用函数所需参数的值压入堆栈(按从右到左的顺序),使最左边的参数位于堆栈的顶部;②调用子函数,即开始执行子函数程序代码;③父函数认为,当函数调用返回时,ARl是当前的辅助寄存器;④当被调用函数完成时,父函数将堆栈指针移回到函数调用前的位置。直接把压入堆栈中参数的值丢弃。
由上可看出,函数调用过程中参数的传递是值传递,并没有改变参数的值,只是把被调用函数所需参数的值拷贝进堆栈中。子函数使用的是堆栈中的拷贝。子函数对拷贝部分的修改并不改变参数的值。当函数调用完成时,父函数直接将堆栈中的拷贝丢弃。
子函数所执行的操作相对复杂一些,这里不再叙述。读者可参阅TI公司技术手册:TMS320C2x/C2xx/C5xOptlmizing CCompiler Users’s Guide。
结语
从普及、推广的角度来看,TI公司的TMS320C2xx系列具有较好的应用基础和较高的性能价格比,在我国有着广泛的应用前景。TMS320LF240x DSP是TMS320C2xx系列中的新成员,其性能远远超过传统的l6位微控制器和微处理器,非常适用于电机的数字化控制,是电机数字化控制的升级产品。用高级语言进行DSP的开发是DSP开发的重要方向。C语言在满足控制应用程序运行速度的基础上可以更好地维护程序和移植程序,是开发控制应用程序的必然趋势。因此,我们有必要深入了解C程序的运行环境和编译器的工作原理。DSP软硬件开发过程中综合了多方面的知识,只有在充分了解硬件资源的基础上,才能开发出好的程序。