




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
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 BCodeStart;跳转到程序开头循环执行.end NOP指令执行时间为一个时钟周期,设DSP工作频率是50MHz,可以估算出XF引脚电平的变化频率约为:50M/2000=25kHz在没有示波器的情况下,就要将程序1.1稍作改进,增加延时,用一个延时子程序将XF脚电平变化频率降到肉眼可分辨的程度,就可以用LED来显示电平的变化,程序如下:实验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 LOOP1:STM#4999,AR2;循环次数5000 LOOP2:BANZ LOOP2,*AR2-;如果AR2不等于0,AR2减1,再判断BANZ LOOP1,*AR1-;如果AR1不等于0,AR1减1,跳转到LOOP1 RET.end*注意这种延时方法并不精确,需要精确定时必须用定时器。*按此法延时的近似公式为:4*(AR2+1)*(AR1+1)*时钟周期*当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.标明一段程序功能的注释以*号打头顶格写,如果功能说明的注释较多,用分格线框起来。此外其它编程语言的编程风格也可以借用过来,比如标示符命名规则、程序说明的要求等。如果项目组有规定,则按规定执行。本书的代码尽量保持一定的风格,不过读者可以发现前面的代码注释较多,后面随着学习的深入,一般不会对每一条指令加注释,只注明程序段的功能。另外代码贴到word里后,格式有些错位,无法一一纠正。2.链接配置文件一个完整的DSP程序至少包含三个部分:程序代码、中断向量表、链接配置文件(*.cmd)。这里介绍一下链接配置文件文件,对本次试验影响不大的中断向量表将在后文介绍。连接配置文件的确定了程序链接成最终可执行代码时的选项,其中有很多条目,实现不同方面的选项,其中最常用的也是必须的有两条:1.存贮器的分配2.标明程序入口。以本次实验为例,下面的简单的链接配置文件就够用了:/*TestXF.cmd*/-e CodeStart/*程序入口,必须在程序中定义相应的标号*/MEMORYpage 0:PRAM:org=0100h len=0F00h/*定义程序存贮区,起始0100H,长度0F00H*/SECTIONS.text:PRAM page 0/*将.text段映射到page0的param区*/由于每个程序都需要一个链接配置文件,可以编写一个满足通常需要的链接配置文件。作为本手册通用的链接配置文件如下,可以满足本书大部分程序的需要。在未特别指明的情况下使用这个通用的链接配置文件:/*5402.cmd*/-e CodeStart/*程序入口,必须在程序中定义相应的标号*/-m map.map/*生成存储器映射报告文件*/MEMORYPAGE 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/*数据段*/更多参考:1.关于代码书写格式:SPRU102:TMS320C54x Assembly Language Tools Users Guide,3.5 Source Statement Format 2.关于链接配置文件:SPRU102:TMS320C54x Assembly Language Tools Users Guide,7.5 Linker Command Files,7.7 The MEMORY Directive,7.8 The SECTIONS Directive练习:1、试一下不按规定格式书写代码会产生什么样的编译错误。2、试一下将链接配置文件中的MEMORY,SECTIONS改成小写会出现什么样的编译错误。3.修改程序1.2中AR1,AR2的值,观察LED闪烁频率实验二基本运算DSP指令数量最多的是:算术指令、逻辑指令和数据加载与传送指令。数据加载与传送指令由于处处要用,所以不单独列为实验。算术与逻辑指令也是数量繁多,无法一一举例,这里简单举一个加法和除法的例子,乘法和乘加指令在FIR用得比较多,稍后一并介绍。其它指令有兴趣可以对照指令表的说明,试验一下各指令运行的结果。实验2.1加减法计算*计算z=x+y-w。*.mmregs.def CodeStart Data_DP:;数据段指针x:.word 10;初始化变量y:.word 26 w:.word 23 z:.word 0.text CodeStart:LD#Data_DP,DP;装载数据指针DP STM#STACK+10H,SP SUMB:LD x,A;A=x ADD y,A;A=A+y SUB w,A;A=A-w STL A,z;z=A END:B END计算结果数据存储器地址存储内容十进制x1010H000aH10 y1011H001aH26 w1012H0017H23 z1013H000dH13技巧提示:试验算术指令由于不需要外部资源,可以不需要仿真器和实验箱。同学们可以平时自己用软件仿真,多多实验。但是复杂的算法最好还是在线仿真,因为程序是流水线执行,软件仿真有时与实际硬件执行结果有所不同。实验2.2除法计算DSP并没有除法指令,回想一下我们用在稿纸上演算除法列的竖式,实际是一种移位减法,DSP中也是通过做多次减法的办法来做除法。下面例子是把用除以10的办法二进制数转成BCD码例子:*16进制转BCD码*.mmregs.global CodeStart.data x:.word 1234;待转换的数字y:.word 10;除数z:.word 0Fh,0Fh,0Fh,0Fh,0Fh;结果区,每位BCD存一个字,;初始化为F因为实验板的数码管不显示F.text CodeStart:LD#x,DP;设置DP LD x,A;被除数STM#z,AR1;结果区指针loop:RPT#15;执行完16次减法后,A的高16位是余数SUBC y,A;低16位是商STH A,*AR1+;余数保存到Z AND#0FFFFH,A;掩盖掉高16位,保留商值BC loop,ANEQ;继续做除法直到商为0 end:B end练习:练习其他算术指令其它参考:spru172c:TMS320C54x DSP Reference Set Volume 2:Mnemonic Instruction Set,2.1 Arithmetic Operations这个资料对每个指令都有详细说明。也可以在Help中的TMS320C54x DSP Mnemonic Instruction Set中查询或搜索相关指令。实验三中断中断的概念应该不陌生,指的是当某个事件发生时,暂停当前的操作,转向中断服务程序,执行完后再返回继续原来的操作。这使得DSP能够处理多个任务。DSP有许多中断源,可以设置中断控制寄存器来确定响应哪些中断而不理会哪些中断。本实验介绍最常用的定时器中断和外部中断的使用方法,并介绍中断向量表和中断向量指针。实验3.1定时器中断:方波发生器实验目的:学习定时器中断的设计方法回顾一下实验一控制LED的闪烁实际就是一个简单的方波发生器。但不足的是延时的方法定时不精确,另外还有一个缺点是在执行延时的过程中DSP就无法执行其它指令,这时就可以用定时器来改进。使用定时器首先要对它初始化,基本步骤如下:1.关掉中断2.停止定时器运行。3.设定时器的定时长度4.允许定时器中断5.运行定时器6.打开中断现以简单的方波程序为例:;=;fangbo1.asm;利用定时器Timer0在XF脚产生周期2ms的的方波;=.titlefangbo1.asm.mmregs.def codestart;程序入口.def TINT0_ISR;Timer0中断服务程序STACK.usectSTACK,10H;分配堆栈空间;设定定时器0控制寄存器的内容K_TCR_SOFT.set 0B 11;TCR第11位soft=0 K_TCR_FREE.set 0B 10;TCR第10位free=0 K_TCR_PSC.set 0B 6;TCR第9-6位,可设TDDR一样,也可不设自动加载K_TCR_TRB.set 1B 5;TCR第5位TRB=1此位置1,PSC会自动加载的K_TCR_TSS.set 0B 4;TCR第4位TSS=0 K_TCR_TDDR.set 1001B 0;TCR第3-0位TDDR=1001B K_TCR.set K_TCR_SOFT|K_TCR_FREE|K_TCR_PSC|K_TCR_TRB|K_TCR_TSS|K_TCR_TDDR K_TCR_STOP.set 1B 4;TSS=1时计数器停止.data DATA_DP:;数据区指针XF_Flag:.word 1;当前XF的电平标志,如果XF_Flag=1,则XF=1;=;主程序:;=.text CodeStart:STM#STACK+10H,SP;设堆栈指针SP LD#DATA_DP,DP;设数据地址DP STM _Flag,AR2;AR指向XF标志;改变中断向量表位置K_IPTR.set 0080h;指向0080H,默认是FF80 LDM PMST,A AND#7FH,A;保留低7位,清掉高位OR#K_IPTR,A;STLM A,PMST*初始化定时器0*f=50MHz,定时2ms时:*根据定时器长度计算公式:Tt=T*(1+TDDR)*(1+PRD)*给定TDDR=9,PRD=9999,CLKOUT主频f=40MHz,T=25ns*Tt=20ns*(1+9)*(1+9999)=2000us=2ms*f=100Mhz,定时最大是:10ns*24*216=10ms,PERIOD.set 9999;定义计数周期STM K_TCR_STOP,TCR;停止计数器0;STM#PERIOD,TIM;可设成跟PRD一样,也可不设自动加载STM#PERIOD,PRD;设定计数周期STM#K_TCR,TCR;开始Timer0 stm#0008h,IMR;允许Timer0中断STM#0008h,IFR;清除挂起的中断rsbx intm;开中断end:nop Bend;=;Timer0中断服务程序:TIN0_ISR;=TINT0_ISR:PSHM ST0;本中断程序影响TC,位于ST0中;判断当前XF状态并作电平变化BITF*AR2,#1;IF XF_Flag=1 then TC=1 else TC=0 BC ResetXF,TC;IF TC=1 then XF=0 else XF=1 setXF:SSBX XF;置XF为高电平ST#1,*AR2;相应修改标志B Next ResetXF:RSBX XF;置XF为高电平ST#0,*AR2;相应修改标志Next:POPM ST0 RETE.end有时定时的长度不能满足需要,比如DSP工作频率50Mhz时,定时最大值是:20ns*24*216=20ms。如果需要更长的定时,就要在定时器中断子程序中再加一个计数器,直到产生一定次数的定时中断后再执行相应的操作。程序只需要稍作修改,见附盘的fangbo2.asm技巧提示:寄存器的不同位通常有不同的含义,初始化时单独设定寄存器的每一位可以增加程序可读性,容易让其它人看懂具体每一位设置的含义,并且易于修改。如果代码太长可以自己写一个初始化的子程序,需要时修改一下调定时再调用。当然如果对寄存器各个位的含义相当熟悉,直接整个初始化也行。可以自行选择这些不同的编程风格。设计指导:1.中断向量表中断向量表是DSP程序的重要组成部分,当有中断发生并且处于允许状态时,程序指针跳转到中断向量表中对应的中断地址。由于中断服务程序一般较长,通常中断向量表存放的是一个跳转指令,指向实际的中断服务程序。下面是5402中断向量表的一个范例,可以作为模板,使用时稍作修改就行:*5402Vectors.asm*完整的5402中断向量表示例*5402共有30个中断向量,每个向量占4个字的空间。*使用向量一般用一条跳转指令转到相应中断服务子程序,其余空位用NOP填充*未使用的向量直接用RETE返回,是为了防止意外进入未用中断。*.sect.vectors;开始命名段.vecotrs.global CodeStart;引用程序入口的全局符号定义;。引用其它中断程序入口的全局符号定义.align 0x80;中断向量表必须对齐128字的页边界RESET:B CodeStart;Reset中断向量,跳转到程序入口NOP;用NOP填充表中其余空字NOP;B指令占了两个字,所以要填两个NOP NMI:RETE;不可屏蔽中断NOP NOP NOP;软件中断SINT17.space 4*16;软件中断使用较少,简单起见用0填充SINT18.space 4*16 SINT19.space 4*16 SINT20.space 4*16 SINT21.space 4*16 SINT22.space 4*16 SINT23.space 4*16 SINT24.space 4*16 SINT25.space 4*16 SINT26.space 4*16 SINT27.space 4*16 SINT28.space 4*16 SINT29.space 4*16 SINT30.space 4*16 INT0:RETE;外部中断INT0 NOP NOP NOP INT1:RETE;外部中断INT1 NOP NOP NOP INT2:RETE;外部中断INT2 NOP NOP NOP TINT:RETE;Timer0中断NOP NOP NOP BRINT0:RETE;McBSP#0接收中断NOP NOP NOP BXINT0:RETE;McBSP#0发送中断NOP NOP NOP DMAC0:RETE;无定义(默认)DMA0中断NOP NOP NOP TINT1:RETE;Timer1中断(默认)或DMA1中断.NOP NOP NOP INT3:RETE;外部中断3 NOP NOP NOP HPINT:RETE;HPI中断NOP NOP NOP BRINT1:RETE;McBSP#1接收中断(默认)或DMA2中断NOP NOP NOP BXINT1:RETE;McBSP#1发送中断(默认)或DMA3中断NOP NOP NOP DMAC4:RETE;DMA4中断NOP NOP NOP DMAC5:RETE;DMA5中断.end在本实验中只要把在开头加上中断子程序标号的引用,并在中断表的TINT部分换成跳转指令就行了:*vectors.asm for方波发生器*.sect.vectors;开始命名段.vecotrs.global CodeStart;引用程序入口的全局符号定义.global TINT0_ISR;引用Timer0中断子程序TINT:B TINT0_ISR;Timer0中断NOP NOP BRINT0:RETE;McBSP#0 receive interrupt节省篇幅,下略技巧提示:只有第一个中断(Reset中断)是每个程序都应该有的,在不需要其它中断的情况下,可以只用这一部分,后面可以省略。如果只需要部分中断也可以按需设置,但必须保证所用中断在中断向量表的位置不变。不熟悉中断向量表的情况下最好还是用这个完整中断向量表样例。另外C5400系列中不同型号DSP的中断向量数量和在中断向量表中的位置有所不同,程序移植时需要查相应datasheet确认。2.中断向量指针中断向量表的位置并没有强制的位置,可以在内部存贮器,也可以在外部存贮器。但有一个要求:中断量表必须放在80H字长存贮块的起始处,即中断向量表的首地址的低7位必须全为0。DSP的寄存器PMST的高9位是中断向量表的指针IPTR。其上电时默认是在FF80H处,这是为了运行固化在内部ROM的上电加载程序(见实验八的程序加载部分)。由于FF80H是只读的,加载用户自定义的中断向量表时会报错。这样需要重新设置IPTR的值,本书一般把它重定义到0080H(也可以用自定义的地址),并在程序开头重新设置一下IPTR的值:;改变中断向量表位置K_IPTR.set 0080h;指向0080H,默认是FF80 LDM PMST,A AND#7FH,A;保留低7位,清掉高位OR#K_IPTR,A;将新值传到高9位STLM A,PMST;修改PMST寄存器技巧指示:由于这段代码几乎每个程序都需要,可以单独存成一个文件:IPTR0080H.asm,然后在程序需要的地方用.copy或.include指令:.copyIPTR0080H.asm或:.includeIPTR0080H.asm编译时就会自动把这段代码嵌到相应位置。稍微要注意的是由于这一小段代码要用到累加器A,所以最好保证执行这段代码之前不要使用累加器A。其它还有一些经常重复的代码,如初始化SP、DP、IPTR的代码都可以写在一个文件里include/copy进来。注1:.copy和.inlucde指令效果是一样的,只是在生成程序列表时,.copy会把代码复制过来,而.include不会。注2:文件名可以用路径,如果不用,则编译器会按下面的循序搜索:当前目录、编译选项指定的目录、环境变量指定的目录。更多参考:1.关于中断:SPRU131 TMS320C54x DSP Reference Set,Volume 1:CPU and Peripherals,6.10 Interrupts 2.关于定时器:SPRU131 TMS320C54x DSP Reference Set,Volume 1:CPU and Peripherals,8.4 Timer实验3.2外部中断:频率计DSP有4个外部中断INT0-INT3,下降沿触发,实验箱的频率计使用的是INT3。频率计的设计原理是:在设定时间下计外部中断INT3的次数,除以定时器的定时周期(也就是乘以定时器中断的触发频率),就得到外部脉冲频率。实验箱上配有1.024k-262.144k共8档频率源,也可以外接频率源。用跳线冒选择频率源,并接到INT3上。下面的例程是定时器定时1s,在INT3中断服务子程序中计脉冲个数,到时则关闭中断。脉冲计数结果显示到数码管上,即为以单位为Hz的频率值*频率计*.mmregs.global CodeStart.global TINT1_ISR.global INT3_ISR.include./DefineIO.asm.data DATA_DP:PulseCounter:.word 0;脉冲计数器Display:.word 0FH,0FH,0FH,0FH,0FH,0FH;存放数据管显示值,值F在数码管上不显示DotData:.word 000000 B;数码管的dot point Number10:.word 10;十六进制转BCD所除的10.text CodeStart:.copy./SP_DP_IPTR.asm;初始化SP、DP和IPTR的代码段STM#99,AR1;10ms计数后再100分频STM#Display,AR3;定义数据管显示存贮区指针LD#0,A;A用来计脉冲数SSBX INTM;关中断CALL Timer1Init;初始化Timer1 STM#110000000 B,IMR;允许Timer1和INT3中断STM#0FFH,IFR;清除挂起的中断RSBX INTM;开中断wait:B wait;*外部中断子程序*INT3_ISR:ADD#1,A;计中断次数RETE*定时器中断子程序*TINT1_ISR:BANZ GoOnCount,*AR1-;测量次数计数器减1,次数为0就中止计数数,;结束计数STM#0,IMR;取消所有中断HEX2BCD:;把计数结果转成BCD码RPT#15 SUBC Number10,A STH A,*AR3+AND#0FFFFH,A BC HEX2BCD,ANEQ;在数码管上显示结果STM#Display,AR3 PORTW*AR3+,Digital0 PORTW*AR3+,Digital1 PORTW*AR3+,Digital2 PORTW*AR3+,Digital3 PORTW*AR3+,Digital4 PORTW*AR3+,Digital5 PORTW DotData,DotPoint RETE GoOnCount:;继续计数STM#1100001 B,IFR;清除挂起的中断RETE*定时器初始化*Timer1Init:;定时器1的寄存器地址TIM1.set 0030h;减1计数器PRD1.set 0031h;存放定时时间常数TCR1.set 0032h;定时器状态及控制寄存器;F=50MHz,T=20ns*(1+15)*(1+3124)=20ns*16*31250=10ms STM#010,TCR1;TSS置位停止Timer STM#31249,PRD1 STM#2FH,TCR1 RET.end简单起见本例只能测一次,可以做一些改进,比如每隔1-2S自动重新测量,或者用按键来触发测量。实验4.1数码管及LED显示接口实验实验箱说明部分已经介绍了数码管的控制原理,下面的程序DigitalLED.asm简单的演示了对数码管和LED控制的指令,可以在显示预设的数字和LED状态。复杂的程序可以见附盘的流水灯程序,DigitalLED2.asm;=;DigitalLED.asm;实验用DSP控制实验板数码管;DSP用I/O指令对CPLD地址1000-10005写数据,分别对应Digtal0-5;=.mmregs.def main;主程序入口.ref Timer0Init;Timer0初始化子程序;数据管地址Digital0.set 1000H;数据管1 Digital1.set 1001H;数据管2 Digital2.set 1002H;数据管3 Digital3.set 1003H;数据管4 Digital4.set 1004H;数据管5 Digital5.set 1005H;数据管6 DotPoint.set 1006H;小数点LED.set 1007H;LED STACK.usectSTACK,10H;分配堆栈空间.data DATA:.word 1,2,3,4,5,6;测试数据Dot_DATA:.word 010101 b;LED_DATA:.word 0101010 b.text main:STM#STACK+10H,SP;设堆栈指针SP STM#K_SWWSR,SWWSR SSBX INTM;关中断LD#DATA,DP;设数据地址DP STM#DATA,AR1*写数据PORTW*AR1+,Digital0 PORTW*AR1+,Digital1 PORTW*AR1+,Digital2 PORTW*AR1+,Digital3 PORTW*AR1+,Digital4 PORTW*AR1+,Digital5 PORTW Dot_DATA,DotPoint PORTW LED_DATA,LED END:B END.end技巧提示:数码管、LED的IO地址的定义也可以单独存到一个文件中,在需要它的程序中用.include/.copy指令。练习:修改预设值重新运行观察结果。实验4.2键盘接口实验实验板上有四个按键,当有键按下时,会触发DSP的INT1中断,在INT1的中断服务程序中读入键码,判断哪一个键被按下,然后执行相应的操作。各键对应的二进制和十六进制键码分别为:按键1:0001B 1H按键2:0010B 2H按键3:0100B 4H按键4:1000B 8H下面有一个小例子:*keyboardTest.asm*测试按键的功能,响应按键中断,读取键值,*并对不同键按键次数计数*.mmregs.global CodeStart.global INT1_ISR.include./DefineIO.asm.data DATA_DP:Counter1:.word 0;按键1计数器Counter2:.word 0;按键2计数器Counter3:.word 0;按键3计数器Counter4:.word 0;按键4计数器Keyvalue:.space 30H*16;按键历史缓冲区.text CodeStart:.copy./SP_DP_IPTR.asm;初始化SP、DP和IPTR代码段;初始化变量STM#Keyvalue,AR2 ST#0,Counter1 ST#0,Counter2 ST#0,Counter3 ST#0,Counter4 SSBX INTM;关中断STM#00000010 B,IMR;允许INT1中断STM#0FFH,IFR;清除挂起的中断RSBX INTM;开中断wait:B wait;*键盘中断子程序*INT1_ISR:PORTR#Keyboard,*AR2;读取键码ANDM#0FH,*AR2;Keyvalue只有低四位有效BITF*AR2,#01H;如果键码为1,跳转到FuncKey1 BC FuncKey1,TC BITF*AR2,#02H;如果键码为2,跳转到FuncKey2 BC FuncKey2,TC BITF*AR2,#04H;如果键码为3,跳转到FuncKey3 BC FuncKey3,TC BITF*AR2,#08H;如果键码为4,跳转到FuncKey4 BC FuncKey4,TC BFuncKeyEnd;FuncKey1:ADDM#1,Counter1;按键1计数器+1 BFuncKeyEnd FuncKey2:ADDM#1,Counter2;按键2计数器+1 BFuncKeyEnd FuncKey3:ADDM#1,Counter3;按键3计数器+1 BFuncKeyEnd FuncKey4:ADDM#1,Counter4;按键4计数器+1 BFuncKeyEnd FuncKeyEnd:PORTW*AR2+,Digital0;当前键码显示到数码管上STM#0FFH,IFR;清除挂起的中断RETE实验六DMA实验实验目的:学习DMA的原理的使用方法实验内容:用DMA方法接收McBSP接口语音芯片的数据DMA是直接存储器存取,是一种传送不占用CPU处理时间的大批量数据传送的有效方式。我们用以下实例来说明它的应用:如果我们要做一个音频处理系统,需要连续用McBSP接口的语音芯片采集若干个样本进行处理,比如频谱分析、音频压缩等。本例假设要每采集256个样本进行一次处理。上例用的是查询方式,占用了所有CPU资源。可以用中断方式,结合前面的实验不难做到,请同学们自行完成。在这个实验中我们将介绍一个更有效的DMA传送方式。我们比较一下用中断方式和DMA方式的效率有何不同:一、中断方式:每当中缓冲串口接收一个16bit样本的数据,触发一次串口接收中断,将数据转移到一个256 word的数据接收缓冲区并计数。当计数达到256个,即缓冲区满时,将256个数据转移到数据处理存储区,并通知主程序进行处理。二、DMA方式:我们使用一个通道自动接收McBSP传来的数据并存入接收缓冲区,当缓冲区满时触发DMA中断,将256个数据传送到数据处理存储区,传送完毕触发通知主程序进行处理。由上比较可见,每接收一批样本,用中断方式将触发256次中断,也就是主程被打断256次去接收数据。而用DMA方式,只在全部256个样本全部接收完毕时发生一次中断,这时主程序应该已经处理完上一批的数据。进一步考虑,当数据处理完毕后还需要将数据送走,这时又可以采用另一个DMA通道完成这个任务,将CPU释放出来等待进行下一批样本的处理。事实上DMA传送并非比用CPU直接处理快,例如在内部存贮器之间传送时,用CPU需要2cycle/word,而用DMA要4cycle/word。DMA的优势在是把CPU解放出来做其它的事。以下是两个DMA通道与CPU协调工作的情况(阴影部分表示空闲)。DMA0CPUDMA1从McBSP接收数据DMA中断,将数据从接收缓冲区转移到数据处理存储区对对数据进行处理将处理完的数据送走估计一下各步的时间,设采样频率是8kHz,CPU时钟频率100MHz。因此一个处理周期为1/8kHz*256=32ms。传送256个点至少需要256word*2cycle/word=512cycle=5.12us。假设处理完后数据量不变,需要256word*4cycle/word=1024 cycle=10.24us。所需要的时钟周期取决于算法的复杂度了。计算好各步所需要的时钟周期,就可以根据情况灵活选择如何使用DMA,例如如果CPU有足够的空闲时间送走数据就不必要;如果CPU仍然不足,就需要再增加个一个DMA来做的任务。如果数据的输出也是从McBSP输出,还要用一个DMA通道进行McBSP的发送。总之要合适地使用DMA通道,使用不当也会使程序变得更加复杂,例如多个DMA通道优先级的问题等等。C54x系列有6个DMA通道,但不同型号C54x系列DSP DMA通道的使用不全相同,如C5402只能将DMA通道用于内部数据存贮器之间传送、McBSP和HPI接口,而C5410可用于内部、外部数据、程序存贮器之间传送。详细介绍请参阅SPRU302 TMS320C54x DSP Reference Set,Volume 5:Enhanced Peripherals和各DSP的数据手册。实验7.1 FIR;=;fir4.asm;用用循环缓冲区和双操作数寻址方法实现FIR滤波器;先用matlab,选择80点汉明窗设计一个截止频率为0.2的低通滤波器;本例与前不同的是系数直接引用程序存储器的系数表;N=5 y(n)=h0*x(n)+h1*x(n-1)+h2*x(n-2)+h3*x(n-3)+h4*x(n-4);=.titlefir4.asm.mmregs.def start;分配数据存储区.bss y,1;y xn.usectxn,80;xn h.usecth,80;h PA0.set 0000H;数据输出端口PA1.set 0001H;数据输入端口;参数表.data table:.word-7,-18,-24,-22,-9,11,33,48;已在Matlab中转成十六进制的小数.word 46,20,-24,-73,-104,-97,-43,49.word 146,204,187,81,-91,-268,-371,-337.word-144,162,476,661,603,261,-297,-894.word-1283,-1222,-562,697,2373,4142,5618,6456.word 6456,5618,4142,2373,697,-562,-1222,-1283.word-894,-297,261,603,661,476,162,-144.word-337,-371,-268,-91,81,187,204,146.word 49,-43,-97,-104,-73,-24,20,46.word 48,33,11,-9,-22,-24,-18,-7 start:SSBX FRCT;小数乘法;把参数表复制到数据存储区STM#h,AR1 RPT#79 MVPD#table,*AR1+;把x(n)-x(n-79)赋始值0 STM#xn,AR1 RPT#79 ST#0,*AR1+STM#xn+79,AR3;x(n-79)-AR3 STM#h+79,AR4;h(n-79)-AR4 STM#80,BK;循环缓冲区大小80 STM#-1,AR0;指针调整值-1 LD#xn,DP;DP指向xn所在页PORTR PA1,xn;输入数据LD#y,DP;DP指向y所在页FIR:RPTZ A,#79;进行一次FIR运算MAC*AR3+0%,*AR4+0%,A;A=(AR3)*(AR4)+A,AR3=AR3+AR0,AR4=AR4+AR0 STH A,y;保存计算结果PORTWy,PA0;输出结果BD FIR;读入下一个数据并进行下一次计算PORTR PA1,*AR3+0%;新数据覆盖了最旧的数据.end实验7.2 IIR.mmregs.global codestart K_DATA_SIZE.set 256;输入数据个数K_BUFFER_SIZE.set 8;缓冲大小,需是2的整数次幂,并大于a、b的个数K_STACK_SIZE.set 256;堆栈大小K_A.set 3;a向量个数K_B.set 4;b向量的个数K_CIR.set 4;=a、b的长度,也可以设为K_BUFFER_SIZE-1 STACK.usectstack,K_STACK_SIZE SYSTEM_STACK.set K_STACK_SIZE+STACK.data DATA_DP:.align K_BUFFER_SIZE bufferdatax:.space K_BUFFER_SIZE*16;size in bits bufferdatay:.space K_BUFFER_SIZE*16;size in bits inputdata:.word 0filterdata:.word 0.text.asg AR2,ORIGIN.asg AR3,INPUT.asg AR4,FILTER.asg AR5,OUTPUT codestart:SSBX FRCT SSBX INTM LD#DATA_DP,DP STM#SYSTEM_STACK,SP CALL filter_start NOP NOP NOP LOOP:B LOOP.def b0,b1,b2,b3,a1,a2,a3;.def filter_start b0.set 1456H;b1=0.1589*215 b1.set 3D07H;b2=0.4768 b2.set 3D07H;b3=0.4768 b3.set 1456H;b4=0.1589 a1.set-103AH;a1=-0.1268 a2.set 430FH;a2=0.5239 a3.set-1016H;a3=-0.1257;=;滤波子程序:filter_start;=.text filter_start:STM#K_CIR,BK;设置环形buffer的大小STM#1,AR0;和步长STM#inputdata,ORIGIN;AR2 STM#bufferdatax,INPUT;AR3 STM#bufferdatay,FILTER;AR4 STM#filterdata,OUTPUT;AR5;初始化RPT#K_B-1-1;ST#0,*INPUT+0%;x(-1)、x(-2)、x(-3)设为0 RPT#K_A-1 ST 0,*FILTER+%;y(-1)、y(-2)、y(-3)设为0 STM#bufferdatay,FILTER STM#K_DATA_SIZE-1,BRC;块循环次数,头三个值已经直接通过了RPTB filter_end-1;块循环结束位置;可以把块循环改成中断调用,有新数据就中断一次。nop;数据从件导入点,加nop保证数据在使用前导入nop MVDD*ORIGIN,*INPUT;新数据MAR*+INPUT(-K_B+1)%MPY*INPUT+0%,#b3,B;B=x(n-3)*b3,i=i+1 LD B,A MPY*INPUT+0%,#b2,B;B=x(n-2)*b2,i=i+1 ADD B,A MPY*INPUT+0%,#b1,B;B=x(n-1)*b1,i=i+1 ADD B,A MPY*INPUT+0%,#b0,B;B=x(n)*b0,i=i+1 ADD B,A MPY*FILTER+0%,#a3,B;B=y(n-3)*a3,j=j+1 j=n-3为y的指针ADD B,A MPY*FILTER+0%,#a2,B;B=y(n-2)*a2,j=j+1 ADD B,A MPY*FILTER+0%,#a1,B;B=y(n-1)*a1,j=j+1 ADD B,A STH A,*FILTER;传送y(n)至y区,;16位小数相乘得到的是32位小数STH A,*OUTPUT;传送y(n)至结果区;取前16位就行了MAR*+FILTER(-K_A+1)%nop nop;数据文件导出点,加nop保证数据在导出前已更新filter_end:NOP;循环结束RET.end实验八程序加载C5000 DSP没有内部提供掉电保存程序的ROM/EPROM/Flash,上电时需要从外部加载应用程序。C5000 DSP提供了多种程序加载方式,满足不同应用的需要:串行加载、并行加载、HPI加载等,实际应用最多的是并行加载,本实验主要介绍8位并行存贮器加载。加载过程:DSP上电时,如果MP/MC引脚为低电平,则跳转到内部ROM的FF80中断向量表的Reset中断,该处有一个跳转指令转到称为Bootloader的加载程序执行,该程序的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 幼儿教师招聘:济南幼师面试常见题目详解
- 产权过户及继承知识
- 行业新:九江文员岗位招聘面试题目及技巧分析
- 小小讲解员讲解长城课件
- 商务汇报简约大气
- 职场晋升必 备:大众经理面试实战题库深度解析
- 生殖细胞的变化
- 血脂代谢机制与调控药物研究
- 细胞呼吸的过程
- 危机干预常见技术
- GB/T 45089-20240~3岁婴幼儿居家照护服务规范
- 康复治疗颈椎病
- DB36T+2031-2024高弹沥青超薄罩面施工技术规范
- 2024桥式门式起重机大修项目及其技术标准
- 【部编】人教版六年级上册道德与法治全册知识点总结梳理
- 电动汽车V2G技术
- 2023风光互补路灯设计方案
- jgj592023安全检查标准完整版
- 2022年临沧市市级单位遴选(选调)考试试题及答案
- 中专宿舍管理制度和方法
- 屁屁辅助脚本
评论
0/150
提交评论