这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » FPGA » 54×DSP编程基本格式

共2条 1/1 1 跳转至

54×DSP编程基本格式

专家
2010-08-13 11:33:50     打赏

54×DSP编程基本格式
——54×DSP边练边学
初学者编写的第一个程序通常是控制XF引脚的变化,然后用示波器测量XF脚波形或观察与相接的LED。这个程序也常常用来测度一下DSP能否正常工作。
 

实验1.1 :最简单的程序:控制XF引脚周期性变化
实验目的:通过简单的程序了解DSP程序的结构,熟悉CCS开发环境。
*************************************************************
*最简单的程序:TestXF1.asm
*循环对XF位置1和清0,用示波器可以在XF脚检测到电平高低周期性变化
*常用于检测DSP是否工作。
*************************************************************
.mmregs              ;预定义的寄存器
.def CodeStart       ;定义程序入口标记
.text                ;程序区
CodeStart:                     ;程序入口
SSBX XF            ;XF置1
RPT #999           ;重复执行1000次空指令产生延时
NOP
RSBX XF            ;XF清0
RPT #999           ;重复执行1000次空指令产生延时
NOP
B CodeStart ;跳转到程序开头循环执行,B指令表示无条件跳转
.end
 

NOP指令执行时间为一个时钟周期,设DSP工作频率是50MHz,可以估算出XF引脚电平的变化频率约为:50M/2000=25kHz
在没有示波器的情况下,就要将程序1.1稍作改进,增加延时,用一个延时子程序将XF脚电平变化频率降到肉眼可分辨的程度,就可以用LED来显示电平的变化,程序如实验1.2。
 

实验1.2:子程序调用
实验目的:学习子程序的调用
*************************************************************
*TestXF2.asm
*对TestXF1.asm稍作改进,用延时子程序设置较长的延时,
*可以用试验板上的LED看到XF引脚电平的变化
*************************************************************
.mmregs              ;预定义的寄存器
.def CodeStart       ;定义程序入口标记
.text             ;程序区
CodeStart:                     ;程序入口
SSBX XF            ;XF置1
CALL Delay         ;调用延时程序
RSBX XF            ;XF清0
CALL Delay         ;调用延时程序
B CodeStart        ;跳转到程序开头循环执行
**************************************************************
*延时子程序:Delay
*用两级减一计数器来延时。调整AR1和AR2的大小LED闪烁的频率不同
**************************************************************
Delay:
STM #999,AR1       ;循环次数1000,AR1=999
LOOP1:       STM #4999, AR2     ;循环次数5000,AR2=4999
LOOP2:       BANZ LOOP2,*AR2-   ;如果AR2!=0,AR2减1,同时跳转到LOOP2
BANZ LOOP1,*AR1-   ;如果AR1!=0,AR1减1,同时跳转到LOOP1
RET
.end
**************************************************************
*注意这种延时方法并不精确,需要精确定时必须用定时器。
*按此法延时的近似公式为:4*(AR2+1)*(AR1+1)*时钟周期
*BANZ指令需要4个周期(当条件为真),2个周期(当条件为假)
*当DSP工作在50MHz(时钟周期20ns),AR1=999, AR2=4999时
*延时约为400ms,则LED闪烁的周期为800ms,频率1.25Hz
**************************************************************
 

 

设计指导:
1.源代码书写格式
源代码的书写有一定的格式,初学者往往容易忽视。简单归纳如下:
1.每一行代码分为三个区:标号区、指令区和注释区。标号区必须顶格写,主要是定义变量、常量、程序标签时的名称。指令区位于标号区之后,以空格或TAB格开。如果没有标号,也必须在指令前面加上空格或TAB,不能顶格。注释区在标号区、程序区之后,以分号开始。注释区前面可以没有标号区或程序区。另外还有专门的注释行,以*打头,必须顶格开始。
2.一般区分大小写,除非加编译参数忽略大小写。
3.标点符号有时不注意会打成中文全角字符导致错误。
书写格式的要求在很多DSP书里都没有提,初学者往往只把书上的代码输入进去,编译时得到错误的提示,而不知所措。其中最容易犯的错误是把指令顶格写,不过一般经提示后不会犯第二次。
有些格式CCS并没有做要求,但注意养成良好的代码书写风格,增加代码的可读性。以上两个例子的书写风格可作参考,但不是硬性规定:
1.标号区占3个TAB的间隔,即12个字符
2.指令中的指令码占两个TAB间隔,然后是操作数。
3.每一行的尾注能对齐的尽量对齐
4.标明一段程序功能的注释以*号打头顶格写,如果功能说明的注释较多,用分格线框起来。例如 /*框法如两边*/
此外其它编程语言的编程风格也可以借用过来,比如标示符命名规则、程序说明的要求等。如果项目组有规定,则按规定执行。
2.链接配置文件
一个完整的DSP程序至少包含三个部分:程序代码、中断向量表、链接配置文件(*.cmd)。下面介绍一下链接配置文件,对本次实验影响不大的中断向量表将在暂不介绍。
链接配置文件确定了程序链接成最终可执行代码时的选项,其中有很多条目,实现不同方面的选项,其中最常用的也是必须的有两条:1.存贮器的分配;2.标明程序入口。以本次实验为例,下面的简单的链接配置文件就够用了:
/* TestXF.cmd */
-e CodeStart /*程序入口,必须在程序中定义相应的标号*/
MEMORY {
page 0:    PRAM: org="0100h" len="0F00h"
/*定义程序存贮区,起始0100H,长度0F00H*/
}
SECTIONS{
.text:>PRAM page 0
/*将.text段映射到page0的param区*/
}
 

由于每个程序都需要一个链接配置文件,可以编写一个满足通常需要的链接配置文件。作为本教程通用的链接配置文件如下,可以满足本教程大部分程序的需要。在未特别指明的情况下使用这个通用的链接配置文件:
/* 5402.cmd */
-e CodeStart /*程序入口,必须在程序中定义相应的标号*/
-m map.map    /*生成存储器映射报告文件 */
MEMORY {
PAGE 0:    VECT: org=0080h len="0080h" /*中断向量表*/
PARAM: org="100h" len="0F00h" /*代码区*/
PAGE 1:    DARAM: org="1000h" len="1000h" /*数据区*/
}
SECTIONS {
.text :> PARAM PAGE 0 /*代码段*/
.vectors :> VECT PAGE 0 /*中断向量表*/
stack :> DARAM PAGE 1 /*堆栈*/
.bss :> DARAM PAGE 1 /*未命名段*/
.data :> DARAM PAGE 1 /*数据段*/
}
 

下面一段是引自《TMS320LF240X DSP应用程序教程》一书关于链接器文件的介绍:(特权同学稍作了整理,呵呵)
(由于基本的概念上面已经有详细的叙述,这里就不重复。只是整理一些对上文的补充内容)。
MEMORY伪指令在命令文件中的书写方式为:以大写MEMORY开始,后面跟着由大括号括起来的一系列存储器范围说明。每一个存储器区间具有一个名称、起始地址以及存储器的长度。下面的实例为实用MEMORY伪指令的简单例子。在该例中,起始地址为数据存储器中的60H;B1块为256字节的RAM,起始地址为数据存储器中的200H;B0块为256字节的RAM,起始地址为数据存储器中的300H。
MEMORY
{
    PAGE0:     ROM:   origin=0h,length=1000h
    PAGE1:     B2:    origin=60h,length=20h
              B1:    origin=200h,length=100h
              B0:    origin=300h,length=100h
}
 

MEMORY伪指令的一般语法为:
MEMORY
{
    PAGE0:name 1[(attr)]:origin=constant,length=constant
    PAGE1:name n[(attr)]: origin="constant",length=constant
}
其中,PAGE:对一个存储空间加以标记,每一个PAGE代表一个完全独立的地址空间。页号n最大可以为255(因为DSP最大寻址可以到64K),取决于目标存储器的配置。通常PAGE0为程序存储器,PAGE1为数据存储器。如果没有规定的PAGE,则链接器就当作PAGE0。
Name:对一个存储器区间名。可以包含8个字符。只是起到标记的作用。同一个PAGE内不能重名,不同PAGE可以。
Attr:这是一个任选项。为命名区规定1-4个属性。如果有选项,应写在括号内。当输出段定位到存储器时,可以利用属性加以限制。属性选项有如下四项:
R:规定可以对存储器执行读操作。
W:规定可以对存储器执行写操作。
X:规定存储器可以装入可执行的程序代码。
I:规定可以对存储器进行初始化。
如果一项属性都没有选,则可以将输出段不受限制定位到任何一个存储器位置。就是任何一个没有规定的存储器都有四项属性。
Origin:规定一个存储区的起始地址。
Length:规定一个存储区的长度。
 

SECTION指令:
1、SECTIONS指令任务:
1、说明如何将输入段组合成输出段;
2、在可执行程序中定义输出段;
3、指定输出段在存储器中的存放位置;
4、允许重新命名输出段。
2、SECTIONS指令的一般语法如下:
SECTIONS
{
  name:[property,property,property,……]
  name:[property,property,property,……]
  name:[property,property,property,……]
  ……
}
    在链接器命令文件中,SECTIONS命令用大写字母,紧随其后并用大括号括起来的是关于输出段的说明语句。每一个输出段的说明都从段名开始,段名后是一行说明段的内容和如何给段分配存储单元的属性参数。一个段的属性参数包括:
(1)  Load allocation,由它定义将输出段加载到存储器中的什么位置。语法为:
Load=allocation(这里的allocation指的是地址)
或者> allocation
其中allocation是关于输出段地址的说明,即给输出段分配存储单元。具体写法有多种,例如:
.text:load=0x1000    ;将输出段.text定位到一个特定的地址
.text:load>ROM    ;将输出段.text定位到命名为ROM的存储区
.text:   PAGE 0   ;将输出段定位到PAGE 0
(2)  Run allocation,由它定义输出段在存储器的什么开始运行。其语法为:
run=allocation 或者
run>allocation
链接器为每个输出段在目标存储器中分配两个地址:一个是加载的地址,另一个是执行程序的地址。通常,这两个地址是相同的,可以认为每个输出段只有一个地址。有事要想吧程序的加载区和运行区分开,只要用SECTIONS命令让链接器对这个段定位两次就行了。一次是设置加载地址,另一次是设置运行地址。例如:
.fir:load=ROM,run=RAM
.data:load=ROM,align=32,run=RAM
3、为输出段指定地址
(1)  binding,将段定位到指定的地址。例如:
.text:load=0x1000
(2)  memory,将段定位到由MEMORY伪指令定义的具有指定的名称(例如ROM)或属性的地址范围。例如:
.text:load>ROM
(3)  alignment,使用对准关键字,指定段的其实地址边界。例如:
.text:align=0x80
(4)  blocking,使用块关键字指定段必须放置在2个地址边界之间,若段太大,将从一个地址边界开始。例如:
.text:block(0x80)
(5)  page,指定要使用的存储器页面。例如:
.text:PAGE 0
4、MEMORY和SECTIONS指令的默认算法
如果没有利用MEMORY和SECTIONS命令,链接器就按缺省算法来定位输出段。




关键词: 编程     基本     格式     程序     定义     .text     指令         

助工
2010-08-25 12:52:14     打赏
2楼
kakan

共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]