第7章 CCS开发工具及应用 7.1 CCS概述 7.2 CCS的安装及窗口 7.3 开发一个简单的应用程序 7.4 算法和数据测试的例子 7.3 开发一个简单的应用程序 7.4 算法和数据测试的例子 7.5 使用DSP/BIOS的语音实例
7.1 CCS 概 述 7.1.1 CCS的发展 CCS提供了基本代码生成工具,它具有一系列的调试、分析能力。CCS支持如图7-1所示的开发周期中的所有阶段。
图7-1 CCS开发周期
在学习本章之前,读者需要完成下述工作: ● 安装好目标板和相应的驱动程序。安装时请参考硬件厂商提供的安装说明书。 ● 安装CCS软件。安装时也根据安装说明书安装。如果你已经有了CCS仿真器和TMS320C54x代码生成工具,但是没有完整的CCS,可按照7.2节的步骤进行安装。 ● 运行CCS安装程序。安装程序为目标板提供驱动程序,安装完成后就可以使用目标板上所提供的设备。
Code Composer Studio(CCS)是TI公司推出的一个集成性DSP软件开发工具。在一个开放式的插件(Plug-In)结构下,CCS内部集成了以下软件工具: ● TMS320C54x代码生成工具(参见7.1.2节); ● CCS集成开发环境(IDE)(参见7.1.3节); ● DSP/BIOS插件程序和API(参见7.1.4节); ● RTDX插件、主机接口和API(参见7.1.5节)。 CCS的构成及其在主机和目标系统中的接口如图7-2所示。
图7-2 CCS构成及其接口
7.1.2 代码生成工具 代码生成工具是CCS开发环境的基础部分。图7-3示出了一个典型的软件开发流程图。大多数DSP软件开发流程都和C程序的开发流程相似,只是DSP开发的一些外围器件的功能得到了一定的增强和提高。
图7-3 软件开发流程
图7-3中的部分工具描述如下: ● C编译器(C Compiler)将C语言源代码编译成为汇编语言代码。 ● 汇编器(Assembler)将汇编语言源文件翻译成机器语言目标文件,机器语言使用的是通用目标文件格式(COFF)。 ● 连接器(Linker)把多个目标文件连接成一个可执行的目标文件。连接器的输入是可重定位的目标文件和目标库文件。
● 归档器(Archiver)允许将一组文件保存到一个存档文件里,称为库。存档器也允许开发人员通过删除、替换、提取和添加文件来修改一个库。 ● 助记符到代数汇编语言转换程序(Memoric-to-algebraic Translator Utility)将含有助记符的汇编语言文件转换成含有代数指令的汇编语言源文件。 ● 建库程序(Library-build Utility)创建满足开发者需要的运行支持库。 ● 运行支持库(Run-time-support Library)包括C编译器所支持的ANSI标准运行支持函数、编译器公用程序函数、浮点运算函数和C编译器支持的I/O函数。
● 十六进制转换程序(Hex Conversion Utility)能够将一个COFF目标文件转化成TI-Tagged、十六进制ASCII码、Intel、Motorola-S或者Tektronix等目标格式,也可以把转换好的文件下载到EPROM编程器中。 ● 交叉引用列表器(Cross-Reference Lister)用目标文件参考列表文件,可显示符号及其定义,以及符号所在的源文件。 ● 绝对列表器(Absolute Lister)输入为目标文件,输出为.abs文件。通过汇编.abs文件,产生含有绝对地址的列表文件。
7.1.3 CCS集成开发环境 CCS集成开发环境允许创建、编辑、编译和调试DSP目标程序。 1.编辑源程序 CCS允许编辑C语言源程序和汇编语言源程序,开发人员还可以通过在C语句后面显示汇编命令的方式来查看C语言源程序,如图7-4所示。
图7-4 “hello.c”源程序
集成编辑环境支持下述功能: ● 用彩色加亮关键字、注释和字符串。 ● 以圆括号和花括号标记C语言块,并可以查找匹配块或下一个圆括号和花括号;可以在一个或者多个文件中进行查找和替换;可以向前或者向后查找和快速查找C语言块。 ● 可以对多个操作进行撤销操作或者重新操作。 ● 获得上下文相关的帮助。 ● 定制个性化的键盘命令。
图7-5 “hello.pjt”工程文件目录
2.创建应用程序 在CCS中,应用程序通过向一个工程中添加文件来创建。工程文件中包括C语言源程序、汇编语言源程序、目标文件、库文件、连接命令文件和包含文件,如图7-5所示。编译、汇编和连接文件时,可以分别指定它们要使用的选项。在CCS中,可以通过一个窗口来详细为一个工程指定相应的编译、汇编和连接选项。CCS可以选择完全编译或增量编译,可以编译单个文件,也可以扫描出工程文件的全部包含文件从属树,还可以利用传统的makefiles文件进行编译。
3.调试应用程序 CCS提供下列调试功能: ● 设置可选择步数的断点; ● 在断点处自动更新窗口; ● 查看变量; ● 观察和编辑存储器和寄存器的值; ● 观察和调用堆栈;
● 对流入目标系统或从目标系统流出的数据采用探针工具观察,并收集存储器映像; ● 绘制选定对象的信号曲线图; ● 估算执行程序性能的统计数据; ● 观察目标程序的反汇编指令和C指令。 CCS还提供GEL语言,这种语言允许开发者向CCS通常的运行菜单中添加功能。
7.1.4 DSP/BIOS插件 在软件开发周期的分析阶段,当调试依赖于时间的程序时,传统的调试方法效率低下。 DSP/BIOS插件支持用于可视化的探测、跟踪和监视一个DSP应用程序的实时分析,而这种探测对程序的实时性能影响很小。例如,图7-6显示了一个执行了多个线程的应用程序的时序。
图7-6 应用程序的时序
DSP/BIOS应用编程接口(API,Application Programming Interface)具有下列实时分析功能: ● 程序跟踪(Program Tracing)在程序执行期间显示写入目标系统日志(Target Log)的事件并反映程序执行过程中的动态控制流。 ● 性能监视(Performance Monitoring)跟踪反映目标资源利用情况的统计表,诸如处理器负荷和线程时序等。 ● 文件流(File Streaming)把常驻目标系统的I/O对象捆绑成主机文档。
1.DSP/BIOS配置 在CCS环境中,可以利用DSP/BIOS API定义的对象创建配置文件,这类文件简化了存储器映像和硬件中断服务程序矢量映像,因此,即使没有使用DSP/BIOS应用编程接口,也可以使用配置文件。
配置文件有两个作用: ● 设置全局运行参数; ● 可视化创建和设置运行对象的属性。这些运行对象由目标系统应用程序的DSP/BIOS API函数调用,它们包括软中断、I/O通道和事件日志。 在CCS中打开一个配置文件时,会出现如图7-7所示的窗口。
图7-7 “hello.cdb”窗口
2.DSP/BIOS应用编程接口模块 传统的调试(Debugging)手段相对于正在执行的程序而言是外部的,而DSP/BIOS API要求将目标系统程序与特定的DSP/BIOS应用编程接口模块连接在一起。通过在配置文件中定义DSP/BIOS对象,一个应用程序可以使用一个或者多个DSP/BIOS模块。在源程序代码中,这些对象被声明为外部的,并调用DSP/BIOS应用编程接口。
DSP/BIOS API被分成下列模块,模块内的任何API的调用均以下面列出来的代码开头。 ● ATM:提供用来处理共享数据的函数。 ● C54:提供特殊函数来处理DSP中断。 ● CLK:片内定时器模块,控制片内定时器并且提供一个高精度的32 bit的实时逻辑时钟信号。
● DEV:用于创建和使用用户定义的设备驱动程序。 ● HST:主机输入/输出模块,管理主机通道对象,允许应用程序在主机和目标系统之间传送数据。主机通道通过静态配置为输入或输出。 ● HWI:硬件中断模块,提供对硬件中断服务程序的支持,可以在配置文件中指定当硬件中断发生时需要运行的函数。 ● IDL:空闲函数模块,管理空闲函数。空闲函数在目标系统程序中没有更高优先权的函数运行时启动。
● LCK:锁定模块,管理全局共享资源。当不同的任务请求使用同一资源时,对资源的分配做出裁决。 ● LOG:日志模块,管理LOG对象。LOG对象在目标系统程序执行的时候实时捕捉所发生的事件,并加以记录。开发者可以使用系统日志或者定义自己的日志,并可以在CCS中利用它实时查看这些日志文件。 ● MBX:邮箱模块,管理任务之间传递的消息。 ● MEM:存储器模块,允许指定存放一个目标程序的不同的代码和数据段所使用的存储器段。 ● PIP:数据通道模块,管理数据通道。
● PRD:周期函数模块,管理周期函数对象,它可以控制一个应用程序的周期性执行。 ● QUE:队列模块,管理数据的队列结构。 ● RTDX:实时数据交换模块,允许主机和目标系统之间进行实时的数据交换,在主机上使用自动OLE的客户都可以对数据进行实时显示和分析。 ● SEM:信号量模块,管理用来使任务同步或者互斥的信号量。 ● SIO:流模块,管理那些能够提供有效、实时的独立设备I/O对象。
● STS:统计模块,管理统计累加器。 ● SWI:软件中断模块,管理软件中断。 ● SYS:系统服务模块,提供执行基本系统服务的多种用途函数,这些系统服务包括执行挂起程序和打印格式化文本等。 ● TRC:跟踪模块,管理一套跟踪控制位,这些控制位通过事件日志和统计累加器来控制程序信息的实时捕获。 ● TSK:任务管理模块,管理任务线程,用来对优先级低于软件中断的线程进行调度。
7.1.5 硬件仿真和实时数据交换 美国德州仪器公司(TI)的DSP设备提供在片仿真支持,它使得CCS能够控制程序的执行和实时监视程序的运行。增强型的JTAG连接提供了对在片仿真的支持,这种连接是一种可与任意DSP系统相连的低干扰式的连接方法。仿真接口提供主机一侧的JTAG连接,如TI XDS510。为方便起见,评估板上提供了一个在板的JTAG仿真器接口。
在片仿真硬件提供了如下功能: ● DSP的启动、停止或复位功能; ● 向DSP中下载代码或者数据; ● 检测DSP的寄存器或者存储器; ● 设置数据断点; ● 包括周期的精确计算在内的多种计数能力; ● 主机和DSP之间的实时数据交换(RTDX)。
CCS提供在片能力的嵌入式支持,另外,RTDX通过主机和DSP的APIs提供主机和DSP之间的双向实时数据交换,它能够使开发者实时连续地观察到DSP应用的实际工作方式。在目标系统应用程序运行的情况下,RTDX也允许系统开发者在主机和DSP设备之间传送数据,而且这些数据可以在使用自动OLE的客户机上实时分析和显示,从而可以缩短开发时间。
如图7-8所示,RTDX由目标系统和主机两部分共同组成,一个小的RTDX软件库需要依靠目标DSP才能运行。开发者通过调用RTDX软件库里面的应用程序接口将数据输入或者输出目标系统的DSP,库函数通过在片仿真硬件和一个增强型的JTAG接口将数据输入或者输出主操作平台,在DSP应用程序运行时数据可实时传送给主机。
图7-8 RTDX系统组成
图7-9 RTDX实例
7.1.6 CCS小结 CCS是继“一体化的DSP解决方案”后,TI公司为巩固自己在DSP业界的地位而在开发工具方面的一次重拳出击。CCS的集成开发环境使得代码开发过程从编辑、编译到调试及代码性能测试都集成在一个环境下进行,而且各项功能都有了一定程度的提升,简化了开发过程,并降低了代码开发的难度。
7.2 CCS的安装及窗口 7.2.1 CCS的安装 1.系统配置要求 (1) 机器类型:IBM PC及兼容机。 (2) 操作系统:Microsoft Windows 95/98/2000或Windows NT 4.0。 (3) 当使用硬件开发时需要主机空余一条ELSA插槽,以便插入驱动板。
2.安装CCS 安装过程包括两个阶段。 (1) 安装CCS到系统中。将CCS安装光盘放入光盘驱动器,运行CCS安装程序setup.exe。如果在Windows NT下安装,则用户必须要具有系统管理员的权限。安装完成后在桌面上会有“CCS 2 ('C5000)”和“Setup CCS 2 ('C5000)”两个快捷方式图标(如图7-10所示),分别对应CCS应用程序和CCS配置程序。
图7-10 CCS快捷方式图标
(2) 运行CCS配置程序,设置驱动程序。如果CCS在硬件目标板上运行,则先要安装目标板驱动卡,然后运行CCS配置驱动程序,最后才能执行CCS。除非用户改变CCS应用平台类型,否则只需运行一次CCS配置程序。
3.CCS配置程序 CCS配置程序用来定义DSP芯片和目标板类型。单击桌面上的Setup CCS2快捷方式图标,弹出如图7-11所示的对话框。
图7-11 CCS配置对话框
7.2.2 CCS的文件和变量 1.安装目录 在安装CCS的过程中将会在CCS的安装目录(默认的安装目录是:c:\ti)里创建如下的子目录,如图7-12所示。在Windows系统目录(c:\windows或者c:\winnt)里也会创建一些子目录。
图7-12 CCS安装目录下的子目录
c:\ti目录包含下面这些目录: ● bin:各种不同用途的程序文件。 ● c5400\bios:DSP/BIOS应用程序接口在创建应用程序时需要用到的文件。 ● c5400\cgtools:德州仪器公司的源代码生成工具。 ● c5400\examples:源程序实例。 ● c5400\rtdx:对RTDX有用的一些文件。
● c5400\tutorial:TI CCS教程所用到的示例。 ● cc\bin:关于CCS环境的程序文件。 ● cc\gel:CCS所用到的GEL文件。 ● docs:一些pdf格式的文件和手册。如果安装时没有选择安装全部文件,则需要在CD-ROM里查看pdf格式的用户手册。
图7-13 Windows系统目录下的子目录
● myprojects:用户自己的文件或者工程文件的存放地点。 图7-13所示的目录结构是被添加到Windows系统目录里面的子目录: ● ti\drivers:各种DSP板的驱动程序文件。 ● ti\plugins:和CCS一起使用的一些插件程序。 ● ti\uninstall:CCS卸载时要用到的文件。
2.文件扩展名 当使用CCS的时候,所使用的文件都具有以下的文件命名规则: ● project.prj:CCS在定义一个工程或者创建应用程序时用的工程文件。 ● program.c:C语言源程序。 ● program.asm:汇编语言源程序。 ● filename.h:C程序的头文件,DSP/BIOS应用程序接口的包含文件。
● filename.lib:库文件。 ● program.cmd:连接命令文件。 ● program.obj:从源文件里组合或者编译成的目标文件。 ● program.out:经过组合、编译、连接后生成的可执行文件,可以在CCS里加载和执行这个文件。 ● project.wks:是CCS用来保存环境设置的文件。 ● program.cdb:CCS所创建的配置数据库文件。这个文件是要用到DSP/BIOS应用程序接口的用户程序所需要的,也是其他一些应用程序可选择的。
保存配置文件时还将产生下列文件: * programcfg.cmd:连接命令文件。 * programcfg.h54:头文件。 * programcfg.s54:汇编语言源程序文件。
3.环境变量 安装程序将会在autoexec.bat(对Windows 95或者Windows 98而言)文件中定义如表7-1所示的变量,或者将其作为环境变量(对Windows NT而言)。
表7-1 环 境 变 量 变 量 描 述 C54x_A_DIR 汇编程序用来寻找所需要的库和DSP/BIOS、RTDX以及代码生成工具所包含文件的一个搜寻列表。具体内容可参见TMS320C54x汇编语言工具用户手册 C54x_C_DIR 由编译程序和连接程序使用的用来寻找所需要的库和DSP/BIOS、RTDX以及代码生成工具所包含文件的一个搜寻列表。具体内容可参见TMS320C54x最优化C编译器用户手册 PATH 加到你的路径定义里的文件夹列表。默认路径是C:\TI\C5400\CGTOOLS和C:\TI\BIN
7.2.3 CCS的窗口、主菜单和工具条 1.CCS应用窗口 图7-14为一个典型CCS集成开发环境窗口的示例。整个窗口由主菜单、工具条、工程窗口、编辑/调试窗口、图形显示窗口、内存单元显示窗口和寄存器显示窗口等构成。
图7-14 CCS应用窗口示例
图7-15 工程窗口关联菜单
2.关联菜单 在任一CCS活动窗口中单击鼠标右键都可以弹出与此窗口内容相关的菜单,我们称其为关联菜单(Context Menu)。利用此菜单,用户可以对本窗口内容进行特定操作。例如,在图形显示窗口中单击鼠标右键,弹出如图7-15所示的菜单。选择不同的条目,可以完成添加程序、扫描相关性、关闭当前工程等功能。
3.主菜单 主菜单中各选项的使用在后面的小节中会结合具体使用详细介绍,在此仅对菜单项功能做简要说明。用户如果需要了解更详细的信息,请参阅CCS在线帮助“Commands”。CCS主菜单如图7-16所示,各项功能介绍如表7-2所述。
图7-16 CCS主菜单
表7-2 主菜单简要介绍 菜 单 项 功 能 File(文件) 文件管理,载入执行程序、符号及数据,文件输入/输出等 Edit(编辑) 表7-2 主菜单简要介绍 菜 单 项 功 能 File(文件) 文件管理,载入执行程序、符号及数据,文件输入/输出等 Edit(编辑) 字符串查找替换,内存变量、寄存器变量的编辑等 View(查看) 工具条显示设置,内存、寄存器对话框的显示等 Project(工程) 工程的管理、创建、打开和关闭,以及编译、构建工程等 Debug(调试) 断点、探针设置,程序的运行和复位 Profiler 性能菜单,包括时钟设置等 GEL(扩展功能) 利用通用扩展语言产生的扩展功能菜单 Option(选项) 选项设置,设置字体、颜色、键盘属性等 Tools(工具) 包括管脚连接、命令窗口、链接配置等 DSP/BIOS DSP/BIOS设置,包括实时分析、可视化探测等 Window(窗口) 窗口管理,包括窗口列表等 Help(帮助) CCS在线帮助菜单
4.常用工具条 CCS将主菜单中常用的命令筛选出来,形成4类工具条:标准工具条、编辑工具条、工程工具条和调试工具条,依次如图7-17~图7-20所示。用户可以单击工具条上的按钮执行相应的操作。
图7-17 标准工具条
图7-18 编辑工具条
图7-19 工程工具条
图7-20 调试工具条
7.2.4 TMS320C5402DSK的配置和使用 TMS320C5402DSK是TI公司提供的一款廉价、独立的开发平台,用于C54x系列DSP的开发。系统开发者可以用DSK来进行C54x DSP应用系统的开发,同时,TMS320C5402DSK 提供了DSP硬件设计的一个范例。利用TI公司提供的TMS320C5402DSK的电路图纸和DSK应用手册,DSP开发者能够大大缩短系统的设计时间。
TI的TMS320C5402DSK工具包包括:CCS安装光盘、TMS320C5402DSK、TMS320C5402DSK使用说明、并行口线、配套电源等(如图7-21所示)。
图7-21 TMS320C5402DSK工具包
TMS320C5402DSK的结构如图7-22所示,它包括以下硬件资源: ● 一片100 MHz TMS320VC5402 DSP。 ● 一片外部64 K字SRAM。 ● 一片256 K字Flash Memory。 ● 与CCS调试器兼容的JTAG(IEEE Std. 1149.1)测试接口和主机接口,可以用于和主机并行口相连。
● 电话接口。DSP通过模拟网络接口(DAA,Analog Network Interface)和AD50 AIC与电话接口相连,电话接口接在DSP的第一个McBSP(McBSP0)上。 ● 一片AD50 AIC,用作耳机和麦克风音频接口(3.5 mm的耳机插孔),与DSP的第二个McBSP(McBSP1)相连。 ● RS-232异步数据传输接口。 ● 扩展子板(Daughter Board)接口。
● 8键双列直插开关,用于用户设置、手动复位DSP的复位开关。 ● 板上有电压转换芯片,用于提供1.8 V的DSP内核电压、3.3 V数字电压和5 V模拟电压。
图7-22 TMS320C5402DSK的结构框图
TMS320C5402DSK上面有8键双列直插开关和4个跳线,用于用户配置DSK。表7-3描述了8键双列直插开关每一键的功能。表7-4给出了C5402 DSP的时钟模式(CLKMD)选择。
表7-3 8键双列直插开关功能 开关号码 名 称 关 开 1 JTAG选择 外部,比如XDS510PP 内部测试控制总线 2 MP/MC 表7-3 8键双列直插开关功能 开关号码 名 称 关 开 1 JTAG选择 外部,比如XDS510PP 内部测试控制总线 2 MP/MC 微处理器模式 微控制器模式 3,4,5 时钟模式 见表7-4 6 外部存储器选择 板上外部存储器 板外外部存储器 7 用户0 用户软件定义(1) 用户软件定义(0) 8 用户1
表7-4 时钟模式选择 开关5 (CLKMD1) 开关4 (CLKMD2) 开关3 (CLKMD3) CLKMD 复位默认值 DSP CPU 表7-4 时钟模式选择 开关5 (CLKMD1) 开关4 (CLKMD2) 开关3 (CLKMD3) CLKMD 复位默认值 DSP CPU 时钟频率 E007H ×15(无效) 1 9007H ×10(无效) 4007H ×5(100 MHz) 1007H ×2(40 MHz) F007H ×1(20 MHz) 0000H ×0.5(10 MHz) F000H ×0.25(5 MHz) — 保留
表7-5 跳线功能及默认设置 名称 描 述 1和2脚相连的功能 2和3脚相连的功能 默认值 JP1 CPLD编程选择 表7-5 跳线功能及默认设置 名称 描 述 1和2脚相连的功能 2和3脚相连的功能 默认值 JP1 CPLD编程选择 CPLD通过J1和JTAG编程 CPLD通过并行口编程 1和2脚相连 JP2 Boot模式控制 从HPI自举加载 从内部或外部存储器自举加载 2和3脚相连 JP3 麦克风输出控制 无缓冲输出 低阻抗驱动输出 JP4 DAA回路电流选择 125 mA(插入跳线) 45 mA(拔出跳线) 插入跳线
TMS320C5402DSK的配置和使用步骤如下: (1) 关闭计算机并且关闭计算机的电源。 (2) 将TI TMS320C5402 DSK工具包提供的并口(打印机接口)线与DSK板相连,如图7-23所示。 (3) 将并口线的另外一端与计算机的并行口相连,如图7-24所示。如果要接入耳机、麦克风或者子板卡,则一定要保证在DSK板上电前完成这些接入工作。
图7-23 并口线与DSK板相连示意图
图7-24 并行线与计算机的并行口相连示意图
图7-25 DSK双列直插开关定义
(4) 将DSK上的8键双列直插开关设置为1、2、3、4、7、8键开启,5、6键关闭。其中,1、2、3、4、5、6、7、8键的定义如图7-25所示。 (6) 将模拟电源线与TI工具包提供的变压器相连,并将插销插入插座。 (7) 启动计算机,在使用CCS和DSK之前,确保计算机的并行口被配置为ECP或者EPP模式。
图7-26 DSK配置对话框
(8) 如果此时没有安装CCS软件,可按照7.2.1节介绍的安装步骤安装CCS;如果已经安装了CCS软件,则按照以下步骤对CCS进行配置: ① 双击桌面上的“Setup CCS 2 ('C5000)”图标,出现如图7-11所示的对话框。 ② 在“Family”中选择“c54x”,在“Platform”中选择“dsk”,得到如图7-26所示的对话框。 ③ 选择“C54x Parallel Port Emulator(DSK5402)”,单击“Import”按钮,得到的结果如图7-27所示。
图7-27 配置结果
④ 在“C54x Parallel Port”上单击鼠标右键,选择“Properties”,得到的“Board Properties”对话框如图7-28所示。 ⑤ 在该对话框中的“I/O Port”后填入前面得到的并行口地址0x378,如图7-29所示。 ⑥ 关闭Setup CCS,选择保存系统设置(System Configuration),选择启动CCS。
图7-28 “Board Properties”对话框
图7-29 I/O端口设置
7.2.5 XDS510PP的配置和使用 仿真器,即扩展开发系统(XDS),可用来进行系统级的集成调试,是进行DSP芯片软硬件开发的最佳工具。目前主要有两种类型的仿真器:一种是传统的电路仿真器,主要用于早期的TMS320C1x和TMS320C2x两代DSP芯片的仿真,这两代DSP芯片没有仿真信号线;另一种是先进的扫描仿真器,主要用于TMS320C3x、TMS320C4x、TMS320C5x、TMS320C54x、TMS320C2xx和TMS320C8x等DSP芯片的仿真,在这些DSP芯片上提供了用于仿真的信号线。
采用传统的电路仿真器对用户设计的系统进行硬件仿真时,仿真器的电缆插头必须插入到用户硬件电路中DSP芯片的相应位置,也就是说,仿真电缆的插头引脚必须与DSP芯片的引脚一一对应。TI的XDS/22仿真器就属于这一类,主要用于TMS320C1x和TMS320C2x等芯片的仿真。
SEED-XDSpp仿真器的配置和使用步骤如下: (1) 关闭计算机并且关闭计算机的电源。 (2) 使用SEED-XDSpp仿真器工具包提供的25芯仿真器连接电缆,将PC机并口与仿真盒连接(如图7-30所示)。 (3) 将5 V直流电源插接到220 V交流电源上,并将直流5 V输出插头插入仿真盒的插孔。 (4) 使用仿真器的JTAG电缆,将仿真器插到目标系统的JTAG接口上,这里使用TMS320C5402DSK作为目标系统。
图7-30 PC机并口与仿真盒
(5) 将DSK上的8键双列直插开关设置为2、3、4、7、8键开启,1、5、6键关闭。这种设置将DSK设置为:JTAG与外部仿真器相连;DSP工作于微控制器模式;DSP CPU时钟频率为40 MHz;外部存储器使用DSK板上的外部存储器。跳线按照表7-5中的默认值设置。连接好的系统如图7-31所示。
图7-31 仿真器与目标系统JTAG接口连接示意图
(6) 启动计算机,插入SEED-XDSpp仿真器工具包提供的驱动光盘,双击SEED-XDSPP的驱动程序SetupCC54x (6) 启动计算机,插入SEED-XDSpp仿真器工具包提供的驱动光盘,双击SEED-XDSPP的驱动程序SetupCC54x.exe,安装Spectrum Digital TMS320C5000 Drivers及CCS 2.x Debug Tools,得到如图7-32所示的安装画面。
图7-32 “Spectrum Digital TMS320C5000 Drivers,CCS 2.x Debug Tools”的安装画面
图7-33 “SDConfig”图标
(7) 单击“Next”按钮,安装Spectrum Digital TMS320C5000 CCS Debug Tools,接受所有的默认选项。安装完成后,桌面上出现“SDConfig”图标(如图7-33所示)。 (8) 双击“SDConfig”图标,对计算机的并行口进行配置,如图7-34所示。
图7-34 “Spectrum Digital TMS320C5000 CCS Debug Tools”的进入画面
(9) 双击需要配置的端口名称,如“378”,单击“Emu”,在“Name of hardware”中选择“XDS510PP”,在“Emulator port”中选择“SPP8”,如图7-35所示。 (10) 单击图标可以测试XDS510PP与DSK板上的JTAG是否连接正常。
图7-35 XDS510PP的端口配置示意图
(11) 如果此时没有安装CCS软件,可按照7.2.1节介绍的安装步骤安装CCS;如果已经安装了CCS软件,则按照以下步骤对CCS进行配置: ① 双击桌面上的“Setup CCS 2('C5000)”图标,在出现的如图7-36所示的对话框的“Family”中选择“c54x”,在“Platform”中选择“emu”,在“Available Configurations”中选择“C54x PP Emulator-0x378”,单击“Import”按钮。
图7-36 XDS510PP配置对话框
② 在sdgo5xx (Spectrum Digital)上单击鼠标右键,选择“Properties”,在弹出的“Board Properties”对话框中选择“Startup GEL File(s)”选项卡,然后在Startup GEL中选择“c5402_dsk.gel”,如图7-37所示。
图7-37 XDS510PP属性配置
③ 关闭Setup CCS,保存系统设置(System Configuration),启动CCS。这样用户就完成了对CCS的配置,从而可以使用SEED-XDSpp仿真器,并且与TI TMS320C5402DSK配合来完成本章后面几个CCS的实例了。
7.3 开发一个简单的应用程序 7.3.1 创建一个新的工程 在本章中,将使用CCS来创建一个工程,并向这个工程里添加源程序文件和库文件,它采用标准的C语言库函数来显示一条“hello world”消息。创建一个新的工程的操作步骤如下:
(1) 如果用户的CCS是安装在c:\ti目录下,在c:\ti\myprojects目录里新建立一个名字为“hello1”的文件夹。(如果将CCS安装在其他的目录下,那么就在相应的安装目录中的“myprojects”文件夹里新建一个文件夹“hello1”即可。) (2) 将c:\ti\c5400\tutorial\hello1文件夹里的所有的文件复制到这个新的文件夹里。 (3) 从Windows的开始菜单里选择“Programs”→“Code Composer Studio TMS320C5400” →“CCStudio”(或者直接在桌面上双击Code Composer Studio图标),进入如图7-38所示的画面。
图7-38 CCS的进入画面
(4) 选择“Project”→“New”,弹出如图7-39所示的对话框。 (5) 在“Project Name”中输入“myhello”作为工程名,在“Location”(位置)中选择你所建的工作文件夹,然后在“Project Type”中选择“Executable(.out)”。输入完成后单击“Finish”按钮,CCS将会建立一个叫做“myhello.prj”的工程文件,这个文件保存了你的工程的设置和涉及到的变量文件。
图7-39 新建工程对话框
7.3.2 向一个工程里添加文件 向一个工程里添加文件的操作步骤如下: (1) 选择“Project”→“Add Files to Project”,然后选择“hello.c”文件,再双击打开(Open)。 (2) 选择“Project”→“Add Files to Project”,然后在文件类型中选择“Asm Source Files (*.a*, *.s*)”。
(3) 选择“Project”→“Add Files to Project”,在文件类型框中选择连接命令文件( (3) 选择“Project”→“Add Files to Project”,在文件类型框中选择连接命令文件(*.cmd),然后选择“hello.cmd”并打开。这个文件包含程序段到存储器的映射。 (4) 选择“Project”→“Add Files to Project”,进入编译库文件夹(c:\ti\c5400\cgtools\lib),再在文件类型框中选择目标文件和库文件(*.o*, *.lib),然后选择“rts.lib”并打开。这个库对目标系统DSP提供了运行实时支持。
(5) 单击紧挨着Projects、hello (5) 单击紧挨着Projects、hello.pjt、Libraries和Source旁边的“+”标记来扩充工程(Projects)列表,这个列表叫做工程窗口(Project View)。 (6) 此时,包含文件还没有出现在工程窗口里。 (7) 如果需要从工程中删除某一个文件,则只需要在工程窗口中的相应文件上单击鼠标右键,并从弹出的菜单里选择“Remove from project”(删除)即可。
在创建程序的时候,CCS通过下面的路径顺序搜寻,就会找到文件: ● 包含源文件的目录。 ● 编译器和汇编器选项的Include Search Path(搜寻路径)中列出的目录(从左到右)。 ● 列在C54X_C_DIR(编译器)和C54X_A_DIR(汇编器)环境变量中定义的目录列表(从左到右)。
7.3.3 查看源代码 在工程窗口里双击hello.c文件,可在窗口的右半部看到源代码。如果想使窗口更大一些,以便能够看到更多的源代码,则可以在“Option”→“Font”中选择较小一点的字体。 源代码如下: /* ======== hello.c ======== */ #include <stdio.h> #include "hello.h"
#define BUFSIZE 30 struct PARMS str = { 2934, 9432, 213, &str };
/* * ======== main ======== */ void main() { #ifdef FILEIO int i; char scanStr[BUFSIZE]; char fileStr[BUFSIZE]; size_t readSize; FILE *fptr; #endif
/* write a string to stdout */ puts("hello world!\n"); #ifdef FILEIO /* clear char arrays */ for (i = 0; i < BUFSIZE; i++) { scanStr[i] = 0 /* deliberate syntax error */ fileStr[i] = 0; }
/* read a string from stdin */ scanf("%s", scanStr); /* open a file on the host and write char array */ fptr = fopen("file.txt", "w"); fprintf(fptr, "%s", scanStr); fclose(fptr);
/* open a file on the host and read char array */ fptr = fopen("file.txt", "r"); fseek(fptr, 0L, SEEK_SET); readSize = fread(fileStr, sizeof(char), BUFSIZE, fptr); printf("Read a %d byte char array: %s \n", readSize, fileStr); fclose(fptr); #endif }
7.3.4 编译和运行程序 CCS自动将用户所做的改变保存到工程设置中。在查看完源代码之后,如果退出了CCS,则通过重新启动CCS,并单击“Project”→“Open”,即可从用户停止工作的地方开始继续以前的工作。
编译和运行程序的操作步骤如下: (1) 选择“Project”→“Rebuild All”,或者单击工具栏中的 按钮,可以重新编译、汇编、连接工程中的所有文件,有关这个工程的信息将显示在窗口底部的信息框中。 (2) 选择“File”→“Load Program”,再选择刚才重新编译过的程序“hello.out”(该程序在C:\ti\myprojects\hello\folder),并单击“Open”按钮,CCS就会把程序加载到目标系统DSP上。
(3) 选择“View”→“Mixed Source/ASM”,将同时显示该工程的C源代码和相应的反汇编指令。 (4) 单击混合模式窗口中任意一条汇编指令(单击指令,而不是单击指令的地址或者空白的区域),按F1键,CCS将会搜寻有关那条命令的帮助信息。 (5) 选择“Debug”→“Go Main”,使程序从main函数开始执行,程序将会在main停止,由指出。 (6) 选择“Debug”→“Run”,或者单击工具栏中的 (运行)按钮。 (7) 选择“Debug”→“Halt”放弃运行程序。
图7-40 hello程序运行结果
7.3.5 修改程序设置和纠正语法错误 在前一节中,由于没有定义FILEIO,因此预处理命令(#ifdef和#endif)之间的程序没有运行。在这一节中,使用CCS设置一个预处理器选项,并找出和纠正语法错误。具体操作步骤如下: (1) 选择“Project”→“Options”。 (2) 从Build Option窗口的“Compiler”栏的“Category”列表中选择“Preprocessor”。在“Define Symbols”框中键入“FILEIO”并按“Tab”键,如图7-41所示。
图7-41 编译选项设置
(3) 单击“OK”按钮,保存新的选项设置。 (4) 选择“Project”→“Rebuild All”,或者单击工具栏中的(Rebuild All)按钮。无论什么时候,只要工程选项改变,就必须重新编译所有文件。 (5) 如果出现一条说明程序含有编译错误的消息,单击“Cancel”按钮,在Build窗口向上移动滚动条,就可以看到一条语法错误信息,如图7-42所示。
图7-42 语法错误信息
(6) 双击描述语法错误位置的红色文字。注意到hello.c的源文件被打开,同时用户的光标会出现在下面这一行上: fileStr[i] = 0; (7) 修改语法错误(缺少分号)。注意,紧挨着编辑窗口题目栏的文件名旁边出现一个星号(*),表明源文件被修改过了。当文件被保存后,星号随之消失。
(8) 选择“File”→“Save”,或者按“Ctrl+S”键可将所做的修改保存至hello.c。 (9) 选择“Project”→“Rebuild All”,或者单击工具栏中的(Rebuild All)按钮,CCS会重新编译已被更新的文件。
7.3.6 使用断点和观察窗口 当开发或测试程序时,经常需要在程序执行过程中检查变量的值。在这一节里面,将使用断点和观察窗口(如图7-43所示)观察这些变量的值。程序执行到断点后,还可以使用单步执行命令。 具体操作步骤如下: (1) 选择“File”→“Reload Program”。 (2) 双击“Project View”中的“hello.c”文件,可以加大窗口,以便看到更多的源代码。
图7-43 局部变量的观察窗口
(3) 把光标放到这一行上: fprintf (fptr, "%s", scanStr); (4) 单击工具栏按钮 或者按“F9”键,这一行将显示为高亮的深红色。 (5) 选择“View”→“Watch Window”,在CCS窗口的右下角会出现一个独立的区域(在程序运行时,这个区域将会显示被观察变量的值)。 (6) 选择“Watch1”标签,单击“Name”列的表达式图标 ,再输入“*scanStr”作为跟踪变量,然后单击窗口白色区域中的任意位置。
图7-44 新的观察变量
(7) 选择“Debug”→“Run”,或者按“F5”键。 (8) 在相应的提示框中,输入“goodbye”,并单击“OK”按钮。注意,在“Stdout”框中以蓝色显示输入的文字,同时还应注意,“Watch Window”窗口中显示出“*scanStr”的值。在输入一个字符串之后,程序开始运行并在断点处停止,程序中将要执行的下一行以黄色高亮显示出来。 (9) 单击工具栏中的 (Step Over)按钮或者按“F10”键,以便执行到所调用的函数fprintf( )之后。
7.3.7 使用观察窗口观察structure变量 观察窗口除了可以观察简单变量的值以外,还可以观察一个结构体中的不同成员的值。具体操作步骤如下: (1) 在“Watch Window”窗口中选择“Watch1”标签,单击“Name”列的表达式图标 。
(2) 输入“str”作为表达式并单击窗口白色区域中的任意位置,则显示着“+str = { (2) 输入“str”作为表达式并单击窗口白色区域中的任意位置,则显示着“+str = { . . . }”的一行会出现在“Watch Window”窗口中。符号“+”说明这是一个结构体。由7.3.3节“hello world”的源代码可知,类型为PARMS的结构体被声明为全局变量,并在hello.中初始化,而这种结构体类型在hello.h中进行了定义。 (3) 单击符号“+”,CCS将展开这一行,并列出该结构的所有元素以及它们的值,如图7-45所示。
图7-45 观察一个结构体
(4) 双击结构体中的任何一个成员,可以打开该成员的变量编辑(Edit Variable)窗口。 (5) 改变变量的值并单击“OK”按钮,可以看到“Watch Window”窗口中的值改变了,而且值的颜色也发生了相应的变化,说明该值已经进行了改动。 (6) 在“Watch Window”窗口中选择“str”的变量并单击右键,从弹出的菜单中选择“Remove Current Expression”,并在Watch Window中对所有表达式重复上述操作。
(7) 在“Watch Window”窗口中单击鼠标右键,从弹出的菜单中选择“Hide”可以隐藏观察窗口。 (8) 选择“Debug”→“Breakpoints”,在“Breakpoints tab”中单击“Delete All”,然后单击“OK”按钮,全部断点都被清除。
7.3.8 测算源代码执行时间 在本节中,将使用CCS的profiling功能来统计标准输出函数puts( )的执行情况。具体操作步骤如下: (1) 选择“File”→“Reload Program”。 (2) 选择“Profiler”→“Enable Clock”,标记“ ”将出现在“Profiler”菜单的“Enable Clock”项的旁边,该选项使能计算指令周期。 (3) 在“Project View”窗口中双击“hello.c”文件。
(4) 在“Profiler”菜单中选择“Start New Session”,然后在“Profiler Session”名称对话框中输入“hello_profile”。 (5) 选择“View”→“Mixed Source/ASM”,汇编指令将显示成灰色并列在每一行C代码的下面。 (6) 在Profiler窗口中选择“Setup”标签,把光标置于下面所述语句的一行: puts ("hello world ! \ n" ) ; 将这一行拖进Profiler窗口中的“Start Points”,如图7-46所示。
图7-46 Profiler的起始点
(7) 向下移动滚动条,并把光标置于下面所述语句: for ( i = 0 ; i < BUFSIZE ; i ++ ) { 将这一行拖进Profiler窗口的“End Points”中,如图7-47所示。 (8) 从“Debug”菜单中选择“Restart”,然后选择“Run”,运行到程序结束。 (9) 选择Profiler窗口中的“Ranges”标签,可以看到有关统计数据的结果,如图7-48所示。
图7-47 Profiler的结束点
图7-48 Profiler的统计数据报告
7.4 算法和数据测试的例子 7.4.1 打开和查看工程 在CCS中打开一个工程文件(*.pjt),并且查看此工程中的源代码文件和库文件。具体操作步骤如下: (1) 如果CCS安装在c:\ti目录下,那么就在c:\ti\myprojects文件夹中创建文件夹“volume1”(如果CCS安装在其他位置,那么就在相应的myprojects文件夹里面创建文件夹“volume1”)。
(2) 将文件夹c:\ti\c5400\tutorial\volume1中所有的文件都复制到新建的文件夹中。 (3) 如果CCS还没有运行,则在Windows开始菜单中选择“Programs”→“Texas Instruments”→“Code Composer Studio”,单击“Code Composer Studio”(或者双击桌面上的Code Composer Studio图标)。
(4) 在Project菜单中选择“New”,在Project Name中输入“volume1”,在Location中将文件夹定位到第(1)步中创建的“volume1”,在Project Type中选择“Executable (.out)”,在Target中选择Setup CCS时的配置。单击“Finish”,这时,CCS将会在“volume1”文件夹中创建名为“volume1.pjt”的工程文件。 (5) 选择“Project”→“Add Files to Project”,选择“volume.c”,单击“Open”,也可以通过在工程窗口中的“volume1.pjt”上单击鼠标右键,从弹出的菜单中选择“Add Files to Project”。
(6) 选择“Project”→“Add Files to Project”,在文件类型框中选择“Asm Source Files (. a (6) 选择“Project”→“Add Files to Project”,在文件类型框中选择“Asm Source Files (*.a*, *.s*)”,然后选择“vectors.asm”和“load.asm”文件,单击打开。这些文件包含了RESET中断跳转到程序入口c_int00的汇编跳转指令。对于比较复杂的程序,可以在vectors.asm中定义其他的中断向量,或者通过DSP/BIOS自动生成。 (7) 选择“Project”→“Add Files to Project”,在文件类型框中选择“Linker Command File (*.cmd)”,然后选择“volume.cmd”文件,单击打开。这个文件是连接命令文件,它将各段映射到存储器中。
图7-49 展开后的工程窗口
(8) 选择“Project”→“Add Files to Project”,浏览至编译库文件夹c:\ti\c5400\cgtools\lib。在文件类型框中选择“Object and Library Files (*.o*, *.lib)”,然后选择与目标系统类型相匹配的“rts.lib”库文件,单击打开。这个库文件提供了对目标DSP的实时支持。对于某些DSP而言,它们的实时支持库文件可能会有比较特殊的名称,如rts_ext.lib。
(9) 在工程窗口中,在“volume1.pjt”上单击鼠标右键,从弹出的菜单中选择“Scan All Dependencies”,volume.h文件将会在工程窗口中的“Libraries”文件夹下出现。 (10) 在工程窗口中分别单击“Projects”、“volume1.pjt”、“Libraries”、“Source”旁边的“+”将工程列表展开,同样,打开库、资源、内容等文件夹。展开后的工程窗口如图7-49所示。
(11) 如果未出现工程窗口“View”→“Project”,则选择工程窗口底部的文件图标,然后在工程窗口中单击“File”。 (12) 如果想从工程中删除文件,则在要删除的文件上单击鼠标右键,从弹出的菜单中选择“Remove from project”。
7.4.2 回顾源代码 在Project View窗口中双击“volume.c”文件,源程序就会显示在CCS窗口的右边。 注意“volume.c”文件中的以下几个部分: ● 主函数输出一条消息后,应用程序处于无限循环状态。在这个循环中,主函数调用dataIO和进程函数。 ● 进程函数将增益与输入缓冲中的各数据相乘,并且将结果数据存入输出缓冲区中,同时也调用汇编Load子程序,该子程序占用的指令周期取决于给传它的processingLoad值。
● dataIO函数是一个空函数,它的作用除了返回以外不执行任何操作。这里使用CCS中的探针功能把主机文件中的数据读取到inp_buffer缓冲区中,而不是利用C程序直接执行输入/输出操作。
#include <stdio.h> #include "volume.h" /* Global declarations */ int inp_buffer[BUFSIZE]; /* processing data buffers */ int out_buffer[BUFSIZE]; int gain = MINGAIN; /* volume control variable */ unsigned int processingLoad = BASELOAD; /* processing load */ struct PARMS str =
{ 2934, 9432, 213, &str }; /* Functions */ extern void load(unsigned int loadValue); static int processing(int *input, int *output); static void dataIO(void);
/* ======== main ======== */ void main( ) { int *input = &inp_buffer[0]; int *output = &out_buffer[0]; puts("volume example started\n"); /* loop forever */ while(TRUE) /* Read using a Probe Point connected to a host file. */
/* Write output to a graph connected through a probe-point. */ dataIO( ); #ifdef FILEIO puts("begin processing"); #endif /* apply gain */ processing(input, output); } /* ======== processing ======== *
* FUNCTION: apply signal processing transform to input signal. * PARAMETERS: address of input and output buffers. * RETURN VALUE: TRUE. */ static int processing(int *input, int *output) { int size = BUFSIZE; while(size--){ *output++ = *input++ * gain; }
/* additional processing load */ load(processingLoad); return(TRUE); } /* ======== dataIO ======== * * FUNCTION: read input signal and write output signal. * PARAMETERS: none. * RETURN VALUE: none. */
static void dataIO() { /* do data I/O */ return; }
7.4.3 为I/O文件增加探针 探针(Probe Point)可以从PC机的文件中读取数据,是开发算法的一个有效工具。其使用方法如下: ● 将来自PC主机文件中的输入数据传送到目标系统的缓存器中供算法使用。 ● 将来自目标系统缓存器中的输出数据传送到PC主机的文件中供分析使用。 ● 用数据更新窗口,如图形窗口。
探针和断点很相似,它们都通过挂起目标系统来完成自己的动作,然而探针和断点又存在以下几个方面的差别: ● 探针立即中止目标系统的运行,在完成操作之后,再恢复目标系统的运行。 ● 断点暂停CPU直到人工恢复其运行为止,同时还要更新所有打开的窗口。 ● 探针允许自动执行文件的输入或者输出,而断点则不允许。
下面介绍如何利用探针来将PC机中文件的内容传送到目标系统中作为测试数据使用。当到达探测点时,同时使用断点更新所有打开的窗口,这些窗口包括输入和输出数据的图形窗口。 (1) 选择“Project”→“Rebuild All”,或者单击工具栏按钮。 (2) 选择“File”→“Load Program”,并选择新建的程序“volume.out”,然后单击打开。 (3) 在“Project View”窗口中双击“volume.c”文件。
(4) 将光标放在主程序中显示“dataIO( );”的这一行上,dataIO函数起到类似占位符的作用。 (5) 在工具条按钮中单击(Toggle Probe Point)按钮,则在这一行旁边会出现一个蓝色的图标表示一个探针已经设定。 (6) 在“File”菜单中选择“FileI/O”。在“FileI/O”对话框中可以选择输入和输出文件,如图7-50所示。
图7-50 “File I/O”对话框
图7-51 “sine.dat”运行图
(7) 在“File Input”栏中单击“Add File”,选择“sine.dat”文件。 (8) 单击“打开”按钮,将该文件添加到“File I/O”对话框的列表中,接着出现sine.dat文件控制窗口(可能被CCS窗口覆盖),如图7-51所示。在运行程序时,可以用这个窗口的开始、停止、重复执行或者快进按钮来控制数据文件。
(9) 在“File I/O”对话框中,将“Address”修改为“inp_buffer”,“Length”修改为“100”,同时选中“WrapAround”,如图7-52所示。
图7-52 “File I/O”对话框
● “Address”栏中的值指定来自文件中的数据将要存放的位置,“inp_buffer”是由“volume ● “Address”栏中的值指定来自文件中的数据将要存放的位置,“inp_buffer”是由“volume.c”文件中声明为BUFSIZE的整数数组。 ● “Length”栏中的值指定每次探针到达时读入数据样点的个数。使用“100”是因为BUFSIZE常数已由“volume.h”设置为100。 ● 当探针到达文件结尾时,“Wrap Around”选项将使CCS从文件的开始读数据。即使数据样点只含有1000个值且每次探针到达时读取100个值,也可将数据看作是连续的数据流。
图7-53 “Break/Probe Points”对话框
(10) 单击“Add Probe Point”,“Break/Probe Points”对话框中的“Probe Points”栏将会出现,如图7-53所示。 (11) 在“Probe Point”列表中,加亮显示“VOLUME.C line 61→No Connection”这一行。 (12) 在“Connect To”栏中,单击下箭头,在其下拉菜单中选择“sine.dat”文件。
(13) 单击“Replace”,“Probe Point”列表将显示探针已经连接到“sine.dat”文件。 (14) 单击“OK”按钮,“File I/O”对话框将显示文件已被连接到探测点。 (15) 在“File I/O”对话框中单击“OK”按钮。
7.4.4 显示图形 如果现在就运行这个程序,那么将不会看到更多的关于程序如何运行的消息。可以在inp_buffer和out_buffer数组的地址范围内设置观察变量,但需要设置很多变量,而且是按照数字形式显示而非图形形式。 CCS提供了多种用图形处理数据的方法。通过下面的操作将会看到一个基于时间绘制的信号波形。本小节介绍图形的打开,下小节介绍程序的运行。
(1) 选择“View”→“Graph”→“Time/Frequency”。 (2) 在弹出的“Graph Property Dialog”对话框(如图7-54所示)中的“Graph Title”、“Start Address”、“Acquisition Buffer Size”、“Display Data Size”、“DSP Data Type”、“Autoscale”、“Maximum Y-value”等的属性设置如图7-54所示。向下滚动或调整Dialog框的大小可以看到所有的属性。
图7-54 图形属性框
(3) 单击“OK”按钮就会出现一个输入缓冲的图形窗口。 (4) 用右键单击输入缓冲窗口,从弹出的菜单中选择“Clear Display”。 (5) 再次选择“View”→“Graph”→“Time/Frequency”。 (6) 将“Graph Title”的属性改为“Output”,将“Start Address”(起始地址)设为“out_buffer”,其他的设置都不变。
(7) 单击“OK”按钮,又出现一个图形窗口,在该图形窗口内单击鼠标右键,从弹出的菜单中选择“Clear Display”。
7.4.5 执行程序和绘制图形 (1) 在C源程序的“volume.c”窗口中,将光标放置到“dataIO”这一行。 (2) 单击Toggle Breakpoint图标工具栏按钮 或者按“F9”键,这一行旁边将会出现红色图标表示断点的设置。 (3) 调整窗口以便能够同时看到这两个图形。 (4) 单击工具栏按钮 (Animate)或者按“F12”键运行程序。
(5) 图7-55和图7-56中包含2.5个周期的正弦波形,且在程序运行过程中两个波形反向。
图7-55 波形输入图
图7-56 波形输出图
7.4.6 调节增益 回顾7.4.2节,processing函数将增益与输入缓冲区中的各值相乘并将结果存放到输出缓冲区中。在一个While循环中用如下语句完成此功能: *output++ = *input++ * gain; 该语句将增益与输入缓存区中的各值相乘并将结果存放到out_buffer 中相应的位置上。
调节增益的操作步骤如下: (1) 选择“View”→“Watch Window”,在弹出的窗口中选择Watch1选项卡。 (2) 在“Name”列中单击 按钮,输入“gain”作为观察变量。 (3) 单击“Watch Window”窗口中任意白色区域来保存修改,参量的数值将立即出现在窗口中,如图7-57所示。
图7-57 “Watch Window”窗口
(4) 如果程序已经暂停,则单击工具栏按钮(Animate),重新开始运行程序。 (5) 在“Watch Window”窗口中单击“gain”的“value”(值为1),将它改为10。
图7-58 输出窗
7.4.7 GEL文件的使用 CCS提供了修改变量的另外一种方法,这种方法需要使用通用扩展语言GEL来创建可修改变量的小窗口。具体操作步骤如下: (1) 选择“File”→“Load GEL”,在弹出的“Load GEL File”对话框中选择“volume.gel”文件,单击打开。 (2) 选择“GEL”→“Application Control”→“Gain”,弹出如图7-59所示的小窗口。这个选项是在上步加载GEL文件时自动增加的。
图7-59 增益调节窗
(3) 如果程序已经暂停,单击工具栏按钮 (Animate),重新开始运行程序。 (4) 在增益窗口中用滑动条来改变增益的大小,则“Output”窗口中正弦波波形的幅度也将随之改变。 (5) 单击工具栏按钮 (Halt)或者按“Shift+F5”键暂停程序运行。 (6) 为了了解Gain GEL函数是如何运行的,单击“Project View”窗口中“GEL files”旁边的“+”,然后在“volume.gel”文件上双击鼠标便可以查看其内容。如下所示:
/* * ======== volume.gel ======== */ menuitem "Application Control" dialog Load(loadParm "Load") { processingLoad = loadParm; }
slider Gain(0, 10 ,1, 1, gainParm) { gain = gainParm; }
7.4.8 进一步的探索 为了进一步了解CCS,可以完成以下工作: ● 把“ProcessingLoad”加入到Watch窗口中,当使用Load Gel控制的时候,Watch窗口的“ProcessingLoad”的值将会被更新。 ● 在Watch窗口中的“Watch1”选项卡中输入需要观察的表达式,比如键入“*input,x”来观察sine函数输入数据的十六进制格式。 ● 在volume.h中将BUFSIZE的大小改成0x78(或120)并重新编译,然后重新加载程序。
● 使用探针重复7.4.3节至7.4.5节的操作,这次仅用探针和“执行”命令。 ● 进一步学习关于探针、图表和GEL文件的知识,可以参照CCS中的在线帮助,或者参看CCS用户指南。
7.5 使用DSP/BIOS的语音实例[21] 7.5.1 DSP/BIOS SWI和PIP模块概述 1.软件中断和SWI模块 SWI模块管理与硬件中断服务程序相似的软件中断服务程序,这些软件中断响应是由诸如SWI_post的DSP/BIOS API调用产生的。一旦触发,SWI程序的运行将会抢占任何后台程序的运行和低优先级的SWI。
硬件中断服务程序比软件中断服务程序的优先级高,在任何程序的运行过程中都是使能的,这样就能够使目标系统及时的响应外围设备的响应。硬件中断能够提供介于硬件中断服务程序和后台空闲循环优先级之间的线程。DSP/BIOS线程的优先级如图7-60所示。
图7-60 DSP/BIOS线程的优先级
2.通道和PIP模块 DSP/BIOS缓冲通道管理器用于缓冲DSP应用系统的输入/输出数据。每一个通道对象都维持着一个以numframes 和 framesize为标志的定长缓冲区。所有的I/O操作一次处理缓冲区中的一帧数据。尽管每一帧的长度是一定的,但是应用程序可以在每一帧中放入长度可变的数据。一个数据通道有两端,程序在写入端写入数据,在输出端读出数据。DSP/BIOS数据通道如图7-61所示。
图7-61 DSP/BIOS数据通道(PIP模块)
数据写入和读出通知函数(NotifyReader和NotifyWriter)用于同步数据的传送。当一帧的数据被写入或读出完毕后就将触发这些函数。这些函数一般与PIP_free、PIP_put、PIP_get和PIP_alloc函数一起使用。当PIP_get函数被调用后,DSP/BIOS检查在通道中是否还有未读出的帧。如果有,将会调用NotifyReader。当PIP_alloc函数被调用后,DSP/BIOS检查在通道中是否还有空白帧。如果有,将会调用NotifyWriter。
7.5.2 语音实例 这个语音实例介绍了如何利用DSP/BIOS APIs来完成外围I/O器件和DSP之间的数据传送。提供这个例子是为了帮助用户开发自己的DSP应用程序。以下步骤将会介绍如何创建这个语音实例,如何使用DSP/BIOS配置工具,以及如何使用DSP/BIOS实时分析工具来调试和测试程序。这个例子能够在ti\c5400\examples\bios\ audio的目录下找到。在运行这个语音实例前先按照图7-62所示将计算机和DSK连接起来。
图7-62 语音实例中计算机和DSK的连接
1.关于这个例子 audio函数用C语言编写,能够在ti\c5400\examples\bios\audio中的audio.c文件中找到。两个通道被用于在软件中断服务程序和串行口之间进行数据交换。这两个通道用DSS_rxPipe和DSS_txPipe表示。输入数据从串行口中断服务子程序接收,通过DSS_rxPipe传给软件中断,输出数据从软件中断程序复制到DSS_txPipe,然后又被送回串行口中断服务子程序,通过Codec输出(如图7-63所示)。
图7-63 语音实例框图
DSS_init函数(在dss.c)中完成串行口和Codec的初始化。DSS_init函数主要完成对Codec采样速率的编程,设置IMR和IFR寄存器允许串行口接收中断等工作。注意以下几点: (1) 因为DSS_init并没有使能中断,所以应该在DSP/BIOS使能中断之前调用。 (2) DSS_init没有设置中断向量表来完成串口接收中断时的中断服务子程序调用。
2.设置配置文件 所有的DSP/BIOS对象都是预先设置的,并且被限制在一个可执行的程序中。这是通过DSP/BIOS配置工具来实现的。当保存一个配置文件时,DSP/BIOS配置工具将会根据配置设置创建汇编、头文件以及连接命令文件。当构建用户的应用程序时,这些文件就与用户的代码连接。更多的信息参见“DSP/BIOS User's Guide”中的“Using the Configuration Tool”和“Code Composer Studio Tutorial”中的“Creating a Configuration File”。
以下部分的DSP/BIOS对象将会被创建: (1) 用来运行audio函数的软件中断audioSWI。 (2) 两个数据通道DSS_rxPipe和DSS_txPipe,用来在audioSWI和串行口接收中断服务子程序之间交换数据。 (3) 利用硬件服务子程序管理模块中的HWI管理中断服务子程序的中断。
创建DSP/BIOS的操作步骤如下: (1) 打开Code Composer Studio并且查看在工程中的源代码和库文件,如果将Code Composer Studio安装在c:\ti,则在c:\ti\myprojects中新建一个名为“audio”的文件夹;如果装在别处,就在安装目录下的myprojects文件夹下建立。 (2) 将ti\c5400\examples\bios\audio文件夹下的所有文件复制到新建文件夹下。
(3) 在Windows的开始菜单中选择“程序”→“Code Composer Studio'5000”→“Code Composer Studio”。 (4) 选择“工程”→“新建”,在建立的文件夹下创建audio.pjt的文件,单击保存。 (5) 选择“文件”→“新建”→“DSP/BIOS配置”。 (6) 选择你的DSP板的名称,单击“确定”按钮。 (7) 右键单击“LOG-Event Log Manager”,从快捷菜单中选择“插入LOG”,将会创建一个LOG0的LOG对象。 (8) 右键单击LOG0的名字,从快捷菜单中选择改名。
(9) 右键单击LOG_system的名字,从快捷菜单中将缓冲区的长度改为256。 (10) 右键单击软件中断管理,选择“插入SWI”,将新建的SWI0改为audioSWI。 (11) 右键单击“audioSWI”,从菜单中选择属性。在audioSWI的属性窗口中,在“function”中填入“_audio”;在“mailbox”中填入“3”;在“arg0”中填入“DSS_rxPipe”,“arg1”中填入“DSS_txPipe”。选择“确定”按钮,保存设置。
(12) 右键单击“PIP-选择插入PIP两次”,将它们改名为DSS_rxPipe和DSS_txPipe。
(a) (b) 图7-64 “DSS_rxPipe属性”对话框 (a) “General”选项卡;(b) “Notify Functions”选项卡
(14) 用右键单击“DSS_txPipe”,在弹出的菜单中选择“Properties”(属性),并按图7-65所示输入属性值。
(a) (b) 图7-65 “DSS_txPipe属性”对话框 (a) “General”选项卡;(b) “Notify Functions”选项卡
图7-66 DSS_rxPrime和DSS_txPrime
(15) 单击紧挨着HWI(硬件中断服务程序)的符号“+”,将会显示出它包含的对象。每一个对象都对应着TMX320C54x中断向量表中的一个中断。正确单击并选择HWI_SINT10中的选项。选择相应于多波段缓冲0串行端口接收中断的中断源(MCSP_0_Receive),同时将函数设为“_DSS_isr”,如图7-67所示。
图7-67 “HWI_SINT10属性”对话框
(16) 右键单击“SWI-Software Interrupt Manager”,并从弹出的菜单中选择“Properties”。在统计单元栏中选择微秒,将会使DSP/BIOS的实时分析工具每微秒通过软件中断显示一次统计数据。 (17) 将配置文件保存为“audio.cdb”,如果被询问是否替代原来存在的文件,单击“YES”按钮。 (18) 选择“Project”→“Add Files to Project”,在文件列表中选择配置文件为(*.cdb)。选择文件“audio.cdb”并打开。
(19) 输出文件名必须与. cdb文件名相匹配(audio. out和audio (19) 输出文件名必须与.cdb文件名相匹配(audio.out和audio.cdb)。转到“Project”→“Options”并选择连接器标号,核对输出文件名为“audio.out”。 (20) 选择“Project”→“Add Files to Project”,在文件类型中选择连接命令文件,选择“audiocfg.cmd”文件并单击打开。 (21) 选择“Project”→“Add Files to Project”,在文件类型中选择源文件,选择“dss.c”、“audio.c”、“dss_evm54.c”、“dss_aisr.s54”、“audio_ld.s54”文件并单击打开。 (22) 选择“Project”→“Rebuild All”。
3.代码预览 在文件audio.c中预览audio代码(ISR将在本节最后予以详述)。注意到audio函数将从DSS_rxPipe中获得一个满帧的数据,而从DSS_txPipe中获得一个空帧,并且将输入帧的内容复制到输出帧。而只有当在DSS_rxPipe中有一个空帧且在DSS_txPipe中也有一个空帧时,audio函数才会运行。
audio代码如下: /* * ======== audio ======== */ Void audio(PIP_Obj *in, PIP_Obj *out) { Uns *src, *dst; Uns size; if (PIP_getReaderNumFrames(in) == 0 || PIP_getWriterNumFrames(out) == 0) { error( ); }
/* get input data and allocate output buffer */ PIP_get(in); PIP_alloc(out); /* copy input data to output buffer */ src = PIP_getReaderAddr(in); dst = PIP_getWriterAddr(out); size = PIP_getReaderSize(in); PIP_setWriterSize(out,size); for (; size > 0; size?) { *dst++ = *src++; }
/* output copied data and free input buffer */ PIP_put(out); PIP_free(in); }
4.用DSP/BIOS实时分析工具调试和测试语音信号 一旦电路板已经连接了一个输入/输出设备,可以发送输入信号(也就是可以播放CD)。 (1) 选定“File”→“Load Program”,选择刚刚编译的程序“audio.out”并打开。 (2) 选定“Debug”→“Go Main”,程序将运行主函数main停止。
图7-68 RTA控制面板
(3) 选定“DSP/BIOS”→“RTA Control Panel”,将在代码生成窗的底部看到几个复选框。 (4) 右键单击包含检查框的区域,并取消“Allow Docking”选项,或者选择“Float in Main Window”,以在一个单独的窗口显示实时分析器控制面板(RTA Control Panel)。调整窗口大小,可以看到所有的检查框,如图7-68所示。
(5) 选中“Enable SWI logging”和“Enable CLK logging”复选框,并选中“Enable SWI accumulators”和“Global host enable”复选框。 (6) 选定“DSP/BIOS”→“CPU Load Graph”(加载图表)。 (7) 选定“DSP/BIOS”→“Execution Graph”(运行图表),而“Execution Graph”窗口将出现在CCS窗口的底部。
(8) 右键单击“RTA Control Panel”(实时分析系统器控制面板),在弹出的菜单中选择“Property Page”(页面属性)。 (9) 确认“Message Log/Execution Graph”中“Refresh Rate”为1 s,然后单击“OK”按钮。 (10) 选定“Debug”→“Run”,或者单击工具栏上的“Run”快捷键,用户将会听到音响中的输出信号,程序的执行图将类似于图7-69所示。
图7-69 执行图
(11) 在audioSWI对象运行时,会在图中显示用于标记间隔的图形符号(图中方块)。audioSWI对象应该每隔2 ms运行一次,可以在两次运行的间隔时间中看到2个时钟Tick(每个时钟Tick相应于1 Ms)。
5.添加周期对象 我们将在应用程序中添加一个以8 ms为周期的新函数,函数的名称为load,在audio.c文件中定义。具体程序如下: /* * ======== load ======== */ Void load(Int prd_ms) {
{ static int oldLoad = 0; /* display confirmation of load changes */ if (oldLoad != loadVal ) { oldLoad = loadVal; LOG_printf(&trace, "load: new load = %d000 instructions every %d ms", loadVal, prd_ms); } if (loadVal) { AUDIO_load(loadVal);
图7-70 “loadPrd属性”对话框
通过DSP/BIOS Real-time Analysis Tools(实时分析工具),可以通过改变全局变量loadVal的值来调整CPU的加载负荷。具体操作步骤如下: (1) 在CCS窗口中打开文件“audio.cdb”,右键单击“Periodic Function Manager”(周期函数管理器),并在弹出的菜单中选择插入PRD。
(2) 将新建的PRD命名为“loadPrd”,右键单击“PRD”,并在弹出的菜单中选择“Properties”(属性),按图7-70所示输入属性值。 单击“确定”按钮,保存设置。 (3) 选定“Project”→“Rebuild All”,并重建audio.out。
6.运行周期函数 运行周期函数的操作步骤如下: (1) 在CCS窗口中选择“File”→“Reload Program”,重新加载audio.out。 (2) 选定“Debug”→“Run”。 (3) 选定“View”→“Watch Window”,在“Watch Window”中插入loadVal。 (4) 在“Trace State”(图表状态)窗口中关闭CLK记录,单击PRD记录。
(5) 观察“Execution Graph”窗口,将看到loadPRD函数每8个时钟周期运行一次。在audioSWI的“STS”窗口会看到,信号的最大值刚好低于2 ms的极限值。 (6) 在“Data Memory”(数据存储器)窗口中,双击变量“loadVal”,并设置变量值为100,随后会发现CPU负荷增加。AUDIO_load函数模拟CPU负荷,为1000×loadVal。 (7) 如果对loadVal输入一个太大的值,则会发现,CPU Load曲线和Execution曲线停止更新,程序相当于在执行一个空闲任务。
(8) 观察audioSWI中的STS数据,发现周期函数的值已增加到最大值,但仍低于audioSWI的2 ms的实时临界值。 (9) 在“Data Memory”(数据存储器)窗口中,继续增加loadVal变量的值,例如150、200等。 (10) 在“System Log”(系统纪录)窗口中,观察随着loadVal值的增加,使得loadPRD的执行时间得以延长的过程(通过计算loadPRD运行时的系统时钟Tick数量来得出这些结论)。
7.增加帧的数量 loadPRD负荷的增加使得实例非实时运行。当loadPRD用太长时间完成时,将使得audioSWI开始执行的时间较晚。因为只有2帧,audioSWI被loadPRD延误,在它有机会复制另一帧并释放它回pipe之前,中断服务程序也许就完成了填充(或传送)其中一帧。因此,由于中断服务程序,在一个新的帧到达之前会发生中断,导致数据的丢失。要解决这个问题,你可以增加每个pipe的帧数,从而当audioSWI被延误时,中断服务程序有另外一个帧来填充。
(1) 在CCS中打开audio.cdb文件。 (2) 打开“Buffered Pipe Manager”,并选中“DSS_rxPipe”,并在其上单击右键,调出“Properties”(属性)窗口,然后在“numframes”区,将“number of frames”(帧数量)设置为3。单击“OK”按钮,保存设置。 (3) 对DSS_txPipe进行同样的设置。
(4) 选定“Project”→“Rebuild All”,并保存设置。 (5) 重新加载audio.out,并选定“Debug”→“Run”。 (6) 选定“View”→“Memory”,键入你先前记录的loadVal值。 (7) 观察audioSig中的STS窗,最大值是否低于2 Ms,audioSWI是否与它的极限值匹配。 (8) 保持loadVal值的增加,最终应用程序将陷入同以前一样的问题,即audioSWI将再次非实时运行。
8.获得直接优先权 添加一个新的缓冲器似乎可以解决目前的问题,直到loadVal变得过大,并且应用程序又开始非实时运行。为什么会这样呢? 当audioSWI被激活时,它并不立刻运行而是必须等到loadPRD完成后才运行。当loadPRD开始需要大于2 ms执行时,它使得audioSWI处于等待状态并晚于它的2 ms的底线。
(1) 在CCS中打开audio.cdb文件。通过单击软件中断管理对象来选中它。 (2) 在右边的方格中,将“audioSWI”拖到“PRD_swi”的上面,从而使“audioSWI”成为最高优先权的软件中断。 (3) 选择“工程”→“全部重建”,并保存设置。
9.中断服务程序的汇编代码 串行端口接收服务,其串行中断的代码能够在DSS_AISR.S54中找到。大多数中断服务子程序是用汇编语言写的。我们将用中断服务程序的汇编语言源代码来举例说明DSP/BIOS系统的汇编接口。 具体源代码如下:
; ======== dss_aisr.s54 ======== .include c54.h54 .include gbl.h54 .include hwi.h54 ; sets .mmregs .include pip.h54 .include dss.h54
set BSP to 1 to use 549 BSP 1 and Spectrum Digital 549 card ; set BSP to 2 to use 5402 McBSP0 and Spectrum Digital eZdsp 5402 card ; set BSP to 2 to use 5410 McBSP0 and Spectrum Digital sd5410 card ; set BSP to 3 to use 5402 McBSP1 and DSK5402 card .if ($isdefed("_SD54_")) BSP .set 1 .endif .if ($isdefed("_DSK5402_"))
BSP .set 3 .endif .if ($isdefed("_SD5410_")) BSP .set 2 .if BSP = 1 RDRR .set BDRR ; 0x20 RDXR .set BDXR ; 0x21 .endif .if BSP = 0
RDRR .set TRCV ; 0x30 RDXR .set TDXR ; 0x30 .endif .if BSP = 2 RDRR .set 0x21 ; 数据接收寄存器McBSP0 RDXR .set 0x23 ; 数据传送寄存器McBSP0 .if BSP = 3
RDRR .set 0x41 ; 数据接收寄存器McBSP1 RDXR .set 0x43 ; 数据传送寄存器McBSP1 .endif .if ($isdefed("RDRR") = 0) ; RDRR is not defined above .emsg "unknown board specification"
.bss rtxDone,1,0,0 ; bit 0 for rxDone, bit 1 for txDone .bss _DSS_phaseDiff,1, 0, 0 .global _DSS_phaseDiff .text .global _DSS_isr ; ; ====== _DSS_aisr ======
; _DSS_isr: stw a0,*b15--[2] ; 压入临时寄存器 stw a1,*b15--[2] stw a2,*b15--[2] stw b1,*b15--[2] stw b2,*b15--[2] ; rxDone = 0, txDone = 0
zero a2 ; if (DSS_rxCnt) { ldw *+b14(_DSS_rxCnt),b1 nop 4 [!b1] b rxErr ; 处理rx错误 ; *DSS_rxPtr++ = *DRR; [b1] mvkl DRR,a1 ; 加载DRR串行端口的地址 [b1] mvkh DRR,a1 [b1] ldw *a1,a1 ; 从DRR读取字
||[b1] ldw *+b14(_DSS_rxPtr),b1 ; 加载DSS_rxPtr [b1] ldw *+b14(_DSS_rxCnt),b2 ; 加载DSS_rxCnt nop 3 stw a1,*b1++ ; 在*DSS_rxPtr储存DRR,自动增量DSS_rxPtr stw b1,*+b14(_DSS_rxPtr) ; 存储更新的DSS_rxPtr增量DSS_rxCnt sub b2,1,b2 ; decrement DSS_rxCnt
stw b2,*+b14(_DSS_rxCnt) ; 存储更新的DSS_rxCnt ; if (DSS_rxCnt == 0) { ; rxDone = 1; ; } [!b2] mvk 1,a2 checkTx: ; if (DSS_txCnt) { ldw *+b14(_DSS_txCnt),b1
nop 4 [!b1] b txErr ; 处理tx错误 ; *DXR = *DSS_txPtr++; [b1] ldw *+b14(_DSS_txPtr),b1 ; 加载DSS_txPtr [b1] ldw *+b14(_DSS_txCnt),b2 ; 加载DSS_txCnt nop 3 ldw *b1++,a0 ; 加载DSS_txPtr指向的数据DSS_txptr自动增加 stw b1,*+b14(_DSS_txPtr) ; 存储更新的DSS_txPtr
mvkl DXR,a1 ; 加载串行端口DXR的地址 mvkh DXR,a1 ; DSS_txCnt?; sub b2,1,b2 ; DSS_txCnt减1 stw a0,*a1 ; 写DXR stw b2,*+b14(_DSS_txCnt) ; 存储更新的DSS_txCnt ; if (DSS_txCnt == 0) { ; txDone = 1; ; }
[!b2] or 2,a2,a2 checkDn: ;if ((rxDone | txDone) == 0) { [a2] b Done ; if rxDone or txDone do Done processing stw a2,*+b14(rtxDone) ; store done flags into memory ; return; /* return from interrupt */ ; }
[!a2] ldw *++b15[2],b2 ; 恢复临时寄存器 [!a2] ldw *++b15[2],a2 [!a2] ldw *++b15[2],a1 b irp ; return from interrupt ldw *++b15[2],a0 nop 4 Done:
ldw *++b15[2],b2 ; 恢复临时寄存器 ldw *++b15[2],b1 ldw *++b15[2],a2 ldw *++b15[2],a1 ldw *++b15[2],a0 nop 4
HWI_enter C54_ABTEMPS, 0, 0xffff, 0 ; if (rxDone) { ldw *+b14(rtxDone),b0 ; 从存储器中加载完成标志 nop 4 and b0,1,b0 ; 检查rxDone是否设置 [!b0] b txDone nop 3 ; PIP_put(&DSS_rxPipe); [b0] mvkl _DSS_rxPipe,a4 ; 加载Pipe地址
[b0] mvkh _DSS_rxPipe,a4 PIP_put ; DSS_rxPrime( ); ; } b _DSS_rxPrime mvkl txDone,b3 ; 设置返回指针 mvkh txDone,b3 nop 3 txDone:
; if (txDone) { ldw *+b14(rtxDone),b0 ; 从存储器中加载完成标志 nop 4 and b0,2,b0 ; 检查txDone是否设置 [!b0] b allDone nop 3 ; PIP_free(&DSS_txPipe); [b0] mvkl _DSS_txPipe,a4 ; 加载Pipe地址 [b0] mvkh _DSS_txPipe,a4
PIP_free ; DSS_txPrime( ); ; } b _DSS_txPrime mvkl allDone,b3 ; 设置返回指针 mvkh allDone,b3 nop 3 allDone: HWI_exit C54_ABTEMPS, 0, 0xffff, 0
rxErr: ; dummy = *DRR; mvkl DRR,a1 ; 加载串行端口DRR地址 mvkh DRR,a1 ldw *a1,a1 ; 从DRR读取一个字 || ldw *+b14(_DSS_error),b1 ; 加载DSS_error值 b checkTx ; 返回原来的中断服务程序代码 nop 3 ; DSS_error |= 1;
or b1,1,b1 ; DSS_error出现 stw b1,*+b14(_DSS_error) ; 保存DSS_error的新值 txErr: ; *DXR = 0; mvkl DXR,a1 ; 加载串行端口DXR的地址 mvkh DXR,a1 || zero b1 stw b1,*a1 ; 写DXR
ldw *+b14(_DSS_error),b1 ; 加载DSS_error值 b checkDn ; 返回原来的中断服务程序代码 nop 3 ; DSS_error |= 2; or b1,2,b1 ; DSS_error出现 stw b1,*+b14(_DSS_error) ; 保存DSS_error的新值 .end
程序说明: (1) 既然中断服务程序调用HWI和PIP宏汇编,则hwi.h54、pip.h54和c54.h54也需要包括在内。HWI_Obj和PIP_Obj结构和HWI和PIP宏模块是在这些头文件中定义的。这些头文件包括能够在ti\c5000\bios\include中找到的。这些文件的顺序并不重要。 (2) 设置多通道缓冲串行口0的地址。 (3) 一个中断服务程序必须保存它用过的全部寄存器。在_DSS_isr一开始,我们仅保存了中断服务程序用过的全部寄存器的一部分,这样做是为了优化性能和节省CPU的消耗。
(4) 每次中断服务程序的触发,CheckRead都要从串行端口数据复制32位的值。 (5) 每次中断服务程序触发时,CheckWrite就从DSS_txPipe复制一个字到32位串行端口数据发送寄存器。 (6) 核对最后接收到的数据采样是否填满了一个_DSS_rxPipe帧,或最后传送的数据是否清空了一个_DSS_txPipe帧。如果两者都不满足,我们就恢复寄存器并从中断服务程序返回。 (7) 如果_DSS_rcPipe帧已满,则中断服务程序需要调用PIP_put宏汇编来使帧回到pipe中。
(8) 我们在调用PIP_put之前,需要满足它的前提,即a4应该包含Pipe目标的地址。PIP_put并没有什么附加条件。 (9) 就像PIP_put一样,我们要通过加载通道目标地址到a4来满足PIP_free的前提。PIP_free并没有任何附加条件。 (10) 在中断服务程序的最后,HWI_exit被调用,用来恢复寄存器,重新启动调度程序和退出中断服务程序。
10.调用C语言的中断服务程序 在ti\c5000\example\bios\audio路径下的dss_cisr.c的文件中,用户会发现一个C版本的中断服务程序。要用C版本的中断服务程序,就需在工程中添加dss_cisr.c文件,然后保存设置并恢复audio.out,加载audio.out,运行应用程序。注意用C中断服务程序来增加CPU对中断服务程序汇编版本加载的方法。
* ======== dss_cisr.c ======== */ #include <std.h> #include <pip.h> #include "dss.h" #include "dss_priv.h" #include <csl_mcbsphal.h> /* * ======== DSS_cisr ========
*/ void DSS_cisr(void) { volatile int dummy; int rxDone = 0; int txDone = 0; if (DSS_rxCnt) { *DSS_rxPtr++ = DRR1(DSS_hMcbsp0); DSS_rxCnt--; if (DSS_rxCnt == 0) { rxDone = 1;
} else { dummy = DRR1(DSS_hMcbsp0); DSS_error |= 0x1; if (DSS_txCnt) { DXR1(DSS_hMcbsp0) = *DSS_txPtr++ & 0xfffe; DSS_txCnt--;
if (DSS_txCnt == 0) { txDone = 1; } else { DXR1(DSS_hMcbsp0) = 0; DSS_error |= 0x2; if ((rxDone | txDone) == 0) { return; /* rete */
if (rxDone) { /* * don't have to set writerSize or writerAddr * since we only provide "full" frames and these * fields are already set. */ PIP_put(&DSS_rxPipe); DSS_rxPrime(TRUE); }
if (txDone) { /* * don't have to set readerSize or readerAddr * since they're already set. */ PIP_free(&DSS_txPipe); DSS_txPrime(TRUE); }
要用DSS_cisr作为中断服务程序,需要用汇编写一个短的函数调用这个DSS_cisr(详见第8 要用DSS_cisr作为中断服务程序,需要用汇编写一个短的函数调用这个DSS_cisr(详见第8.2节)。这个汇编函数名为_DSS_isr,因为这是输入到HWI_cisr目标的函数名(因此,该函数被插入到TMS320C54x中断向量表中)。该函数的代码能在DSS_aisr.s54中找到。
.global _DSS_isr ; ====== _DSS_isr ====== ; _DSS_isr: ssbx sxm ; sign extend mode ; int rxDone = 0; ; int txDone = 0; ld #0,b
11.进一步的学习 ● 增大在通道中的帧的大小,观察系统日志并注意信号运行所在频率的任何变化。将帧的长度增大一倍时,看看会发生什么。 ● 在通道中,将帧的尺寸变为512字。观察CPU加载的变化,观察系统日志。
● 在通道的信号一侧启动监视器,观察在什么样的频率下帧进出通道,并且它是怎样随着帧的大小而变化的。注意监视器对CPU的影响。 ● 为HWI_SINT10设一个监视器并观察它对CPU的影响。总之,能观察到在应用程序中怎样使仪器(记录,累加器,监视器)影响CPU的加载。
7.5.3 结论 语音实例演示了怎样设置和使用DSP/BIOS APIs在输入/输出外围设备和数字信号处理目标系统之间进行数据传输的时序安排。提供这个例子是为了帮助开发者开发自己的DSP应用系统,理解DSP/BIOS功能和使用方法。