實驗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)
;=============================================================
.title "fir4.asm"
.mmregs
.def start
;分配數據存儲區
.bss y,1 ;y
xn .usect "xn",80 ;xn
h .usect "h",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 ;保存計算結果
PORTW @y,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 .usect "stack",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 0
filterdata: .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 *2^15
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
技巧提示:只有第一個中斷(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指令:
.copy 「IPTR0080H.asm」
或: .include 「IPTR0080H.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 000000B ;數碼管的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 #110000000B,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 #1100001B,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自動重新測量,或者用按鍵來觸發測量。