📄 dtmf_dec.asm
字号:
sub *AR2-,15,A ; (A) = -(1/2)vk(n-2) + (1/2)x(n)
ltd *AR2 ; vk(n-1) --> vk(n-2)
mac *AR2,*AR3+,A ; (A) = coef*vk(n-1) - (1/2)vk(n-2) + (1/2)x(n)
sfta A,1 ; (A) = 2*coef*vk(n-1) - vk(n-2) + x(n)
bc novf2,anov ; <--- check on OVERFLOW
st #-1,COUNT ; if(OV set) { COUNT = -1
b goer3 ; branch unconditionally to goer3 }
novf2 sth A,*AR2- ; (A) --> vk(n-1)
goer21 ; }
;do 1.Harm. for 205 samples
goer1 stm #END1st,AR2 ; AR2 points to end of tap block
stm #COEF1st,AR3 ; AR3 points to Coefficients
stm #(8-1),BRC ;
rptb goer11-1 ; for(k=0;k<8;k++) do 8 filters as follows
ld rcv,15,A ; { (A) = (1/2)x(n)
sub *AR2-,15,A ; (A) = -(1/2)vk(n-2) + (1/2)x(n)
ltd *AR2 ; vk(n-1) --> vk(n-2)
mac *AR2,*AR3+,A ; (A) = coef*vk(n-1) - (1/2)vk(n-2) + (1/2)x(n)
sfta A,1 ; (A) = 2*coef*vk(n-1) - vk(n-2) + x(n)
bc novf1,anov ; <--- check on OVERFLOW
st #-1,COUNT ; if(OV set) { COUNT = -1
b goer3 ; branch unconditionally to goer3 }
novf1 sth A,*AR2- ; (A) --> vk(n-1)
goer11 ; }
goer3 ret
**************************************************************************
* SUBROUTINE: dtmf_checks
*
* Input: none
* Output: A (status if valid digit)
* Uses:
*
* Description:
* (Subroutine is done if COUNT < 0
* It is only done once every 205 samples since COUNT is restored to 205)
*
* - energy computation
* - initialize filter taps to zero
* - maximum search
* - DTMF status check
* - signal strength check
* - twist check
* - relative peak check
* - 2nd harmonic check
* - digit check (same as second to last, same as last?)
*
**************************************************************************
dtmf_checks:
nop
;-------------------------------------------------------------------------
; Energy computation
;
; y(N)y*(N) = vk(N)*vk(N) - 2*coef*vk(N)*vk(N-1) + vk(N-1)*vk(N-1)
;
; Coefficients are in pmem in order starting with location COEF1st
; COEF1st .word xxxx ;coef0 <--AR3
; .word yyyy ;coef1
; ....
;
; Data vk(n-1), vk(n-2) is ordered as follows in dmem
; v15(n-1)
; v15(n-2)
; v14(n-1)
; v14(n-2)
; ....
; v0(n-1)
; v0(n-2) <--AR2
;
; FRCT = 1 , OVLY = 1
; AR2: points to v1(N-1)
; AR3: points to COEF1st
;
;-------------------------------------------------------------------------
energy stm #END1st,AR2 ;AR2 points to end of filter taps block
stm #COEF1st,AR3 ;AR3 points to beg of coefficient table
stm #ENERGY,AR4 ;AR4 points to block of energies
stm #(16-1),BRC
rptb ener1-1 ;for(k=0;k<16;k++) {
ld *AR2,16,A ; (A) = vk(N-1), A(32:16) loaded
mpya *AR2- ; (B) = vk(N-1)*vk(N-1), (T) = vk(N-1)
mpy *AR2,A ; (A) = vk(N)*vk(N-1)
ld *AR3+,T ; (T) = coef
mpya A ; (A) = coef*vk(N)*vk(N-1)
sub A,1,B ; (B) = -2*coef*vk(N)*vk(N-1) + vk(N-1)*vk(N-1)
ld *AR2,T ; (T) = vk(N)
mac *AR2-,B ; (B) = vk(N)*vk(N) - 2*coef*vk(N)*vk(N-1) + vk(N-1)*vk(N-1)
sth B,*AR4+ ; store result E[k] into energy data block
ener1 ;}
;------------------------------------------------------------------------
; Initialize Filter Taps to zero for next round
;
;------------------------------------------------------------------------
stm #TAPS2nd,AR2 ;AR2 points to beginning of filter taps
rpt #(32-1) ;for(i=0;i<32;i++)
st #0,*AR2+ ; initialize filter taps for next round
nop
;------------------------------------------------------------------------
; Maximum search
; Searches row-energies and column-energies for their maxima
; Distinguishes between 1.Harm and 2.Harm
;
; MAX_ROW_1st: Maximum spectral energy in row tone band (1.Harmonics)
; MAX_COL_1st: Maximum spectral energy in column tone band (1.Harmonics)
; MAX_ROW_2nd: Maximum spectral energy in row tone band (2.Harmonics)
; MAX_COL_2nd: Maximum spectral energy in column tone band (2.Harmonics)
;
;------------------------------------------------------------------------
max_search:
stm #ENERGY,AR2 ;AR2 points to energy table (row energies)
stm #(4-1),BRC
ld #0,B ;clear B
rptb max1-1 ;for(k=0;k<4;k++) {
ld *AR2+,A ; load A with next energy value E[k]
max B ; max(A,B) --> B
max1 ;}
stl B,MAX_ROW_1st ;save result
stm #(4-1),BRC
ld #0,B ;clear B
rptb max2-1 ;for(k=4;k<8;k++) {
ld *AR2+,A ; load A with next energy value E[k]
max B ; max(A,B) --> B
max2 ;}
stl B,MAX_COL_1st ;save result
stm #(4-1),BRC
ld #0,B ;clear B
rptb max3-1 ;for(k=8;k<12;k++) {
ld *AR2+,A ; load A with next energy value E[k]
max B ; max(A,B) --> B
max3 ;}
stl B,MAX_ROW_2nd ;save result
stm #(4-1),BRC
ld #0,B ;clear B
rptb max4-1 ;for(k=12;k<16;k++) {
ld *AR2+,A ; load A with next energy value E[k]
max B ; max(A,B) --> B
max4 ;}
stl B,MAX_COL_2nd ;save result
;----------------------------------------------------------------------
; DTMF Status Check:
; if(DTMF_STAT == 0)
; if( max(MAX_ROW_1st,MAX_COL_1st) < THR_PAU )
; DTMF_STAT = 1, detector enabled
; terminate all checks
; else
; continue
;
;----------------------------------------------------------------------
stat_check
bitf DTMF_STAT,#0001h ;
bc sig_check,tc ;if(DTMF_STAT == 1) continue with sig_check
ld MAX_ROW_1st,A ;
ld MAX_COL_1st,B ;else
max A ; (A)=max(MAX_ROW_1st,MAX_COL_1st)
sub #THR_PAU,A ; (A)=max(MAX_ROW_1st,MAX_COL_1st) - THR_PAU
bc stat1,ageq ; if((A)<0)
st #0001h,DTMF_STAT ; DTMF_STAT = 1
stat1 b ende ; terminate all checks
;----------------------------------------------------------------------
; Signal strength check:
; if(MAX_ROW_1st > THR_SIG)
; else terminate all checks
; if(MAX_COL_1st > THR_SIG)
; else terminate all checks
;
;----------------------------------------------------------------------
sig_check:
ld MAX_ROW_1st,A
sub #THR_SIG,A
bc ende,alt ;if(MAX_ROW_1st < THR_SIG) branch to ende
ld MAX_COL_1st,A
sub #THR_SIG,A
bc ende,alt ;if(MAX_COL_1st < THR_SIG) branch to ende
;----------------------------------------------------------------------
; Twist check:
; if( abs(MAX_ROW_1st-MAX_COL_1st) < THR_TWI )
; else terminate all check
;
;----------------------------------------------------------------------
twist_check:
ld MAX_ROW_1st,A
sub MAX_COL_1st,A
abs A
sub #THR_TWI,A
bc ende,agt ;if(abs(MAX_ROW_1st-MAX_COL1st) > THR_TWI) branch to ende
;----------------------------------------------------------------------
; Relative peak check:
; if( min(MAX_ROW_1st-E[0,1,2,3]) > THR_REL )
; else terminate all checks
; if( min(MAX_COL_1st-E[4,5,6,7]) > THR_REL )
; else terminate all checks
;
;----------------------------------------------------------------------
rel_check:
stm #ENERGY,AR2
ld #07fffh,B
stm #(4-1),BRC
rptb rel1-1 ;for(k=0;k<4;k++)
ld MAX_ROW_1st,A ; (A)=MAX_ROW_1st
sub *AR2+,A ; (A)=MAX_ROW_1st-E[k]
bc rel11,aeq ; if(identical) don't use value for min
min B ; (B)=min((B),MAX_ROW_1st-E[k])
rel11 nop
rel1 sub #THR_REL,B
bc ende,blt ;if(min(MAX_ROW_1st-E[k]) < THR_REL) branch to ende
ld #07fffh,B
stm #(4-1),BRC
rptb rel2-1 ;for(k=4;k<8;k++)
ld MAX_COL_1st,A ; (A)=MAX_COL_1st
sub *AR2+,A ; (A)=MAX_COL_1st-E[k]
bc rel21,aeq ; if(identical) don't use value for min
min B ; (B)=min((B),MAX_COL_1st-E[k])
rel21 nop
rel2 sub #THR_REL,B
bc ende,blt ;if(min(MAX_ROW_1st-E[k]) < THR_REL) branch to ende
;----------------------------------------------------------------------
; Second Harmonics check
; if( (MAX_ROW_1st-MAX_ROW_2nd) > THR_2nd )
; else terminate all checks
; if( (MAX_COL_1st-MAX_COL_2nd) > THR_2nd )
; else terminate all checks
;
;----------------------------------------------------------------------
sec_check:
ld MAX_ROW_1st,A
sub MAX_ROW_2nd,A
bc ende,alt ;if( (MAX_ROW_1st-MAX_ROW_2nd) < THR_2nd ) branch to ende
ld MAX_COL_1st,A
sub MAX_COL_2nd,A
bc ende,alt ;if( (MAX_COL_1st-MAX_COL_2nd) < THR_2nd ) branch to ende
;----------------------------------------------------------------------
; Map detected tone pair to digit
;
;----------------------------------------------------------------------
digit_map:
;---------- find row number corresponding to peak ------------
stm #ENERGY,AR2 ;AR2 points to energy table
ld MAX_ROW_1st,A ;load A with max row energy value
stm #0,AR3 ;AR3 is used as counter
stm #(4-1),BRC
rptb digit1-1 ;for(k=0;k<4;k++) {
sub *AR2+,A,B ; ---- do for row energies ----
bc digit11,bneq
mvmd AR3,DIGIT_ROW ; if(MAX_ROW_1st == E[k]) save row nbr
digit11 mar *AR3+ ; increment counter
digit1 ;}
;---------- find column number corresponding to peak ------------
ld MAX_COL_1st,A ;load A with max column energy value
stm #0,AR3 ;AR3 is used as counter
stm #(4-1),BRC
rptb digit2-1 ;for(k=4;k<8;k++) {
sub *AR2+,A,B ; ---- do for column energies ----
bc digit21,bneq
mvmd AR3,DIGIT_COL ; if(MAX_COL_1st == E[k]) save column nbr
digit21 mar *AR3+ ; increment counter
digit2 ;}
;---------- map row and column numbers to actual digit -------------
stm #KEYS,AR2 ;AR2 points to key mapping table
stm #0,AR3 ;AR3 is used as counter
stm #BUFFER+1,AR4 ;AR4 points to digit buffer +1
ld DIGIT_ROW,8,A ;load row nbr in upper byte of AL
add DIGIT_COL,A ;load column nbr in lower byte of AL
stm #(16-1),BRC
rptb digit3-1 ;for(k=0;k<16;k++) {
sub *AR2+,A,B
bc digit31,bneq
ltd *AR4- ; if(A == KEYS[k]) insert delay
ltd *AR4 ; insert delay
mvmd AR3,BUFFER ; save decoded digit into buffer
b digit4 ; branch to ende
digit31 mar *AR3+ ; increment counter
digit3 ;}
;------------------------------------------------------------------------
; Validate digits from previous digits
;
;------------------------------------------------------------------------
digit4
stm #BUFFER,AR2
mvdm DIGIT_PTR,AR3
ld *AR2+,A ;load current digit
sub *AR2,A,B ;compare with last digit
bc ende,bneq ;if current digit and last digit are the same
stl A,*AR3+ ; store VALID DIGIT into DIGITS
mvmd AR3,DIGIT_PTR ; update pointer
st #0,DTMF_STAT ; disable detector and wait for pause
ende ret
******************************************
* Interrupt Service Routines
******************************************
RINT1_ISR:
ld #rcv,DP
mvmd DRR1,rcv
andm #0fffch,tra
mvdm tra,DXR1
popm ST1
popm ST0
rete
*****************************************************************
* SUBROUTINE: hwinit *
* Description: Initializes Processor *
* Serial Port 1 *
* AIC *
* Input: none *
* Output: none *
*****************************************************************
hwinit:
;----------- Initialize Processor ---------------------------
stm #0ffe0h,PMST ;configure on-chip RAM in OVLY mode
stm #02000h,SWWSR ;I/O: 2 wait states
;memory: 0 wait states
stm #0000h,BSCR ;no bank switching
;----------- Initialize Serial Port 1 -----------------------
stm #10h, TCR ; turn off timer
stm #0c008h, SPC1 ; reset serial port 1
; =0 (b0) : reserved, always zero
; DBL =0 (b1) : loopback mode disabled
; FO =0 (b2) : 16-bit word operation
; FSM =1 (b3) : frame sync control
; MCM =0 (b4) : external CLKX
; TXM =0 (b5) : external FSK
; XRST=0 (b6) : Xmit reset
; RRST=0 (b7) : Recv reset
stm #0c0c8h, SPC1 ; take serial port 1 out of reset
; XRST=0 (b6) : Xmit reset
; RRST=0 (b7) : Recv reset
;----------- Initialize AIC ----------------------------------
ld #aic_conf,DP ; reset AIC
portr 0014h, aic_conf ; (EVM: Port 14h used as target control register
andm #7fffh, aic_conf; B15 of port 14h is AICRST/ )
portw aic_conf,0014h
rpt #40 ; keep low for 2usec
nop
ld #aic_conf,DP ; take AIC out of reset
portr 0014h,aic_conf
orm #8000h,aic_conf
portw aic_conf,0014h
stm #80h, IMR ; allow TINT1 interrupt
stm #0c8h, IFR ; clear pending serial port 1 and timer interrupts
rsbx INTM ; global interrupt enable
stm #0h, DXR1 ; dummy Xmit for synchronization
stm #3h, DXR1 ; request secondary Xmit mode to send control word
idle 1 ; wait for TINT1 interrupt
stm #0124h, DXR1 ; CONVERSION RATE: sample rate DXR1 value
idle 1 ; (Reg1) 16 kHz 0112h
; 8 kHz 0124h
; 4 kHz 0148h
stm #3h,DXR1
idle 1
stm #0212h,DXR1 ; PRESCALER: FCLK = 288 kHz
idle 1 ; (Reg2)
stm #3h,DXR1
idle 1
stm #0300h,DXR1 ; PHASE ADJUSTMENTS: none
idle 1 ; (Reg3)
stm #3h, DXR1
idle 1
stm #0426h, DXR1 ; OUTPUT GAINS: -8dB (monitor)
idle 1 ; (Reg4) -6dB (analog input)
; -6dB (analog output)
ssbx INTM ; global interrupt disable
stm #0h, DXR1
ret
;------------ END OF H/W INITIALIZATION SUBROUTINE---------------------
.end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -