device pins28,pages4,banks8,turbo,oschs,optionx,carryx,stackx reset start ; A Cooley-Tukey Radix-2 DIF FFT ; ; Radix-2 implementation ; Decimation In Frequency ; Single Butterfly ; Table Lookup of Twiddle Factors ; Complex Input & Complex Output ; ; All data is assumed to be 16 bits and the intermediate ; results are stored in 32 bits ; ; Length Of FFT must be a Power Of 2 ; ; ; ; FftLen = 16 ; FFT Length Power = 4 ; (2**Power = FftLen) SCALE_BUTTERFLY = 1 ; intermediate scaling performed RamAddr = $90 Data = RamAddr ; ;************************************************************************* ; BB0 = 0 B0 = BB0 BB1 = 1 B1 = BB1 BB2 = 2 B2 = BB2 BB3 = 3 ; RAM offset constants B3 = BB3 ; for 16 bit x 16 bit multiplication org $50 arith = $ md16 ds 2 mr16 ds 2 upper_prdt ds 2 count ds 1 sign ds 1 AARG = mr16 AARG1 = mr16+1 ; 16 bit multiplier A BARG = md16 BARG1 = md16+1 ; 16 bit multiplicand B DPX = mr16 DPX1 = mr16+1 DPX2 = upper_prdt DPX3 = upper_prdt+1 ; 32 bit multiplier result = A*B ACC ds 1 ACC1 ds 1 ACC2 ds 1 ACC3 ds 1 ; 32 bit accumulator for computations org $8 ;=16 primary = $ Cos ds 1 write_ptr = Cos ; reuse Cos1 ds 1 read_ptr = Cos1 ; reuse ;=24 Sin ds 1 rw_cnt = Sin Sin1 ds 1 rw_temp = Sin1 testCount ds 1 temp1 = testCount ptr ds 1 pulseCount = ptr temp2 = ptr temp3 ds 1 temp4 ds 1 org $10 Xi ds 1 Xi1 ds 1 Yi ds 1 Yi1 ds 1 Xl ds 1 Xl1 ds 1 Yl ds 1 Yl1 ds 1 ;=41 Xt ds 1 Xt1 ds 1 Yt ds 1 Yt1 ds 1 org $30 ;=45 var = $ VarIloop ds 1 VarJloop ds 1 ;=30 VarKloop ds 1 VarL ds 1 temp ds 1 TF_Addr ds 1 TF_Addr1 ds 1 TF_Offset ds 1 ;twiddle factor offset count1 ds 1 ; N1 count2 ds 1 ; N2 top ds 1 bottom ds 1 ;=54 bytes ; ; MOVK16 MACRO 2 mov \2+BB0,#(\1) & $ff mov \2+BB1,#((\1) >> 8) ENDM MOV16 MACRO 2 ; 16 bit move mov \2+B0,\1+B0 mov \2+B1,\1+B1 ENDM MOV32 MACRO 2 mov \2+B0,\1+B0 ; move A(B0) to B(B0) mov \2+B1,\1+B1 ; move A(B1) to B(B1) mov \2+B2,\1+B2 ; move A(B2) to B(B2) mov \2+B3,\1+B3 ; move A(B3) to B(B3) ENDM ADD16 MACRO 2 clc add \2+B0,\1+B0 add \2+B1,\1+B1 ENDM ADD32 MACRO 2 clc add \2+B0,\1+B0 add \2+B1,\1+B1 add \2+B2,\1+B2 add \2+B3,\1+B3 ENDM SUB16 MACRO 2 ; 16 bit subtraction, result in second parameter stc sub \2+B0,\1+B0 sub \2+B1,\1+B1 ENDM SUB16ACC MACRO 3 ; 16 bit subtraction, result in the third parameter ; \3=\2-\1 stc mov w,\1+B0 ; get lowest byte of a into w mov w,\2+B0-w mov \3+B0,w mov w,\1+B1 ; get 2nd byte of a into w mov w,\2+B1-w mov \3+B1,w ENDM SUB32 MACRO 2 ; 32 bit subtraction stc sub \2+B0,\1+B0 sub \2+B1,\1+B1 sub \2+B2,\1+B2 sub \2+B3,\1+B3 ENDM CLR16 MACRO 1 ; Clear 2 consecutive bytes of data memory clr \1+B0 clr \1+B1 ENDM INC16 MACRO 1 inc \1+B0 snz inc \1+B1 ENDM DEC16 MACRO 1 ; decrement 16 bit register stc sub \1+B0,#1 clr w sub \1+B1,w ENDM RLC16 MACRO 1 ; 16 bit rotate left clc rl \1+B0 rl \1+B1 ENDM RLC16AB MACRO 2 ;a,b 16 bit rotate left A into B (=2*a) clc mov w,<<\1+BB0 mov \2+BB0,w mov w,<<\1+BB1 mov \2+BB1,w ENDM RRC16 MACRO 1 ; 16 bit signed rotate right (=/2) mov w,<<\1+B1 ; move sign into carry bit rr \1+B1 ; rotate MSByte first rr \1+B0 ; then LSByte to propagate carry ENDM TFSZ16 MACRO 1 ; 16 bit test, skip if zero mov w,\1+B0 or w,\1+B1 sz ENDM ; get test data gen_test MACRO ;******************************************************************* ; Test Routine For FFT ; read table of test data ;******************************************************************* testFft mov temp1,#testdata//256 ; low mov temp2,#testdata/256 ; high mov fsr,#RamAddr ; load start address mov rw_cnt,#Fftlen ; how many times to write loaddata mov m,temp2 mov w,temp1 iread ; read data mov ind,w ; store lower byte of real data inc temp1 ; next mov m,temp2 mov w,temp1 iread ; read data inc fsr mov ind,w ; store upper byte of real data clr w ; imaginary data is always 0 inc fsr mov ind,w inc fsr mov ind,w inc temp1 inc fsr setb fsr.4 decsz rw_cnt jmp loaddata ENDM ;****************************************************************** ; Test Program For FFT Subroutine ;****************************************************************** ORG 0 start clr fsr ; reset all ram banks :loop setb fsr.4 ; only second half is addressable clr ind ; clear ijnz fsr,:loop ; all ; fsr=0 on entry gen_test ; Generate Test Vector Data call R2FFT ; Compute Fourier Transform page Unscramble call Unscramble ; bit reverse the scrambled data ; Fourier Transform Completed ; page start self jmp self ;---------------------------------------------------- ; 16 bit x 16 bit signed multiplication ; entry: multiplicand in $09,08, multiplier at $0b,$0a ; exit : 32 bit product at $0d,$0c,$b,$a ; cycles=19+258+16=293 DblMult ; process the sign first mov w,md16+1 ; 1 test the sign xor w,mr16+1 ; 1 same sign? mov sign,w ; 1 save, so that we can bit test it at the end sb md16+1.7 ; 1/2 msb=1? jmp check_mr ; 3 no, check multiplier ; =7 ; msb of multiplicand=1, negate not md16 ; 1 1's complement inc md16 ; 1 2's complement=1's complement+1 snz ; 1/2 special case if =0 dec md16+1 ; 1 dec then complement = increment not md16+1 ; 1 this will take care of the carry from lsb to msb ;=5 check_mr sb mr16+1.7 ; 1/2 msb=1? jmp normal_mult ; 3 sign check done ; msb of multiplier=1, negate not mr16 ; 1 1's complement inc mr16 ; 1 2's complement=1's complement+1 snz ; 1/2 special case if =0 dec mr16+1 ; 1 dec then complement = increment not mr16+1 ; 1 this will take care of the carry from lsb to msb ;=7 ; worst case = 19 ; following routine has a worst case of 261-3 (no ret)= 258 cycles normal_mult mov count,#17 ; 2 set number of times to shift clr upper_prdt ; 1 clear upper product clr upper_prdt+1 ; 1 higher byte of the 16 bit upeper product clc ; 1 clear carry ; the following are executed [count] times m1616loop rr upper_prdt+1 ; 1 rotate right the whole product rr upper_prdt ; 1 lower byte of the 16 bit upper product rr mr16+1 ; 1 high byte of the multiplier rr mr16 ; 1 check lsb sc ; 1 skip addition if no carry jmp no_add ; 3 no addition since lsb=0 clc ; 1 clear carry add upper_prdt,md16 ; 1 add multiplicand to upper product add upper_prdt+1,md16+1 ; 1 add the next 16 bit of multiplicand no_add decsz count ; 1/2 loop [count] times to get proper product jmp m1616loop ; 3 jmp to rotate the next half of product ; following instructions have a total of 16 cycles sb sign.7 ; 1/2 check sign ret ; 3 positive, do nothing, just return ; lower product not mr16 ; 1 form 1's complement not mr16+1 ; 1 not upper_prdt ; 1 not upper_prdt+1 ; 1 mov w,#1 ; 1 add 1 clc ; 1 to form 2's complement add mr16,w ; 1 mov w,#0 ; 1 add with 0 to propagate add mr16+1,w ; 1 carry to higher bytes add upper_prdt,w ; 1 add upper_prdt+1,w ; 1 ret ; 3 ; RADIX-2 FFT ; ; Decimation In Frequency ; ; Input Data should be unscrambled ; Output Data at the end is in scrambled form ; R2FFT bank var mov TF_Offset,#1 ; Init TF_Offset = 1 mov count2,#FftLen ; count2 = N=16 mov VarKloop,#Power ; Kloop Kloop ; for K = 1 to Power-1 mov count1,count2 ; count1 = count2 clc rr count2 ; count2 = count2/2 clr VarJloop ; J = 0 clr TF_Addr clr TF_Addr1 Jloop ; ; Read Twiddle factors from Sine/Cosine Table from Prog Mem ; mov temp1,#SineTable//256 mov temp2,#SineTable/256 ; load sine table address to table pointers mov w,TF_Addr clc add temp1,w mov w,TF_Addr1 add temp2,w mov m,temp2 ; load m first, since w will be used in doing it mov w,temp1 iread mov Sin,w ; get the sine value (low byte) inc temp1 ; no need to propagate carry since sine table is aligned to ; X00 ; both m and w are altered by iread, thus the reload mov m,temp2 ; m should be loaded first mov w,temp1 iread mov Sin+BB1,w ; Read MSB of Sine Value from lookup table clc add temp1,#(Fftlen/4)*2-1 ; prepare to read cosine table, *2 because each ; entry occupies two bytes, -1 because we have ; incremented once to read the high byte of sine mov m,temp2 mov w,temp1 iread mov Cos,w inc temp1 ; both m and w are altered by iread, thus the reload mov m,temp2 mov w,temp1 iread mov Cos+BB1,w ; Read MSB of cosine Value from lookup table clc mov w,<<TF_Offset add TF_Addr,w add TF_Addr1,#0 ; propagate carry clc mov w,<<VarJloop mov VarIloop,w ; I = J*2 since Real followed by Imag Data Iloop ;compute for pointer address that can be used throughout the loop clc mov w,<<VarIloop mov temp1,w and w,#%11110000 ; mask off lsb ; no overflow can happen, else we will be out of range of memory add w,temp1 ; adjust for gap in register banks mov top,w add top,#RamAddr mov w,<<count2 mov VarL,w ; VarL = count2*2 add VarL,VarIloop ; VarL = I+count2*2 mov w,<<VarL mov temp1,w and w,#%11110000 ; mask off lsb add w,temp1 ; adjust for gap in register banks mov bottom,w add bottom,#RamAddr mov fsr,bottom ; read bottom data on the butterfly mov temp1,ind inc fsr mov temp2,ind inc fsr mov temp3,ind inc fsr mov temp4,ind bank primary mov Xl,temp1 mov Xl+1,temp2 mov Yl,temp3 mov Yl+1,temp4 ; read top data on the butterfly bank var mov fsr,top mov temp1,ind inc fsr mov temp2,ind inc fsr mov temp3,ind inc fsr mov temp4,ind bank primary mov Xi,temp1 mov Xi+1,temp2 mov Yi,temp3 mov Yi+1,temp4 ; Real & Imag Data is fetched ; Compute Butterfly SUB16ACC Xl,Xi,Xt ; Xt = Xi - Xl ADD16 Xl,Xi ; Xi = Xi + Xl SUB16ACC Yl,Yi,Yt ; Yt = Yi - Yl ADD16 Yl,Yi ; Yi = Yi + Yl IF SCALE_BUTTERFLY RRC16 Xi RRC16 Yi RRC16 Xt RRC16 Yt ENDIF bank arith mov mr16,Sin mov mr16+1,Sin1 ; multiplier=Cos value bank primary mov w,Xt bank arith mov md16,w bank primary mov w,Xt1 bank arith mov md16+1,w Call DblMult ; SIN*Xt MOV32 DPX,ACC mov md16,Cos mov md16+1,Cos1 ; put COS in multiplicand since we want to preserve it bank primary mov w,Yt bank arith mov mr16,w bank primary mov w,Yt1 bank arith mov mr16+1,w Call DblMult ; COS*Yt, Scale if necessary SUB32 ACC,DPX clc mov w,<<DPX+2 ; scale decimal point bank primary mov Yl,w bank arith mov w,<<DPX+3 bank primary mov Yl+1,w ; Yl = COS*Yt - SIN*Xt mov w,Xt bank arith mov mr16,w bank primary mov w,Xt+1 bank arith mov mr16+1,w mov md16,Cos mov md16+1,Cos1 ; put COS in multiplicand since we want to preserve it Call DblMult ; COS*Xt MOV32 DPX,ACC bank arith mov mr16,Sin mov mr16+1,Sin1 ; multiplier=Sin value bank primary mov w,Yt bank arith mov md16,w bank primary mov w,Yt1 bank arith mov md16+1,w Call DblMult ; Sin*Yt, Scale if necessary ADD32 ACC,DPX ; DPX = COS*Xt + SIN*Yt clc mov w,<<DPX+2 ;scale decimal point bank primary mov Xl,w bank arith mov w,<<DPX+3 bank primary mov Xl+1,w ; Xl = COS*Xt + SIN*Yt mov temp1,Xi mov temp2,Xi+1 mov temp3,Yi mov temp4,Yi+1 ; prepare to store ; ; ; Store results of butterfly ; store top result bank var mov fsr,top mov ind,temp1 inc fsr mov ind,temp2 inc fsr mov ind,temp3 inc fsr mov ind,temp4 bank primary ; prepare to store data (L) mov temp1,Xl mov temp2,Xl+1 mov temp3,Yl mov temp4,Yl+1 ; prepare to store ; store bottom result bank var mov fsr,bottom mov ind,temp1 inc fsr mov ind,temp2 inc fsr mov ind,temp3 inc fsr mov ind,temp4 ; X(L) & Y(L) stored ; ; Increment for next Iloop ; bank var clc mov w,<<count1 add VarIloop,w ; I=I+count1*2 mov temp,#FftLen*2 clc sub temp,VarIloop ; temp = 2*FftLen - I-1 sb temp.7 jmp Iloop ; while I < 2*FftLen ; ; I Loop end ; ; increment for next J Loop ; inc VarJloop ; J = J + 1 mov temp,count2 clc sub temp,VarJloop ; temp = count2 - J-1 sb temp.7 jmp Jloop ; while J < count2 ; ; J Loop end ; ; increment for next K Loop ; clc rl TF_Offset ; TF_Offset = 2 * TF_Offset decsz VarKloop jmp Kloop ; while K < Power ; ret ; FFT complete ; ; K Loop End ; FFT Computation Over with data scrambled ; Descramble the data using "Unscramble" Routine org $200 ; ;****************************************************************** ; Unscramble Data Order Sequence ; bit reversal ;****************************************************************** ;****************************************************************** ; ; Unscramble Data Order Sequence Of Radix-2 FFT ; Length (must be a power of 2) ; ;****************************************************************** Unscramble clr VarIloop ; i=0..15 reverse clr VarL snb VarIloop.3 setb VarL.0 snb VarIloop.2 setb VarL.1 snb VarIloop.1 setb VarL.2 snb VarIloop.0 setb VarL.3 ; L contains the bit reversed version of I stc cjb VarIloop,VarL,swapdata ; I-L ; swap only if I<L ; carry=1 if no borrow, meaning I is >=L rev_cont inc VarIloop stc cjb VarIloop,#12,reverse ; if I <=11, continue, else done ret swapdata clc mov temp,VarIloop rl temp rl temp mov w,temp and w,#%11110000 ; mask off lsb ; no overflow can happen, else we will be out of range of memory add w,temp ; adjust for gap in register banks mov top,w add top,#RamAddr clc mov temp,VarL rl temp rl temp mov w,temp and w,#%11110000 ; mask off lsb ; no overflow can happen, else we will be out of range of memory add w,temp ; adjust for gap in register banks mov bottom,w add bottom,#RamAddr ; ; swap data mov fsr,top mov temp1,ind inc fsr mov temp2,ind inc fsr mov temp3,ind inc fsr mov temp4,ind bank var mov fsr,bottom mov Cos,ind inc fsr mov Cos1,ind inc fsr mov Sin,ind inc fsr mov Sin1,ind bank var mov fsr,top mov ind,Cos inc fsr mov ind,Cos1 inc fsr mov ind,Sin inc fsr mov ind,Sin1 bank var mov fsr,bottom mov ind,temp1 inc fsr mov ind,temp2 inc fsr mov ind,temp3 inc fsr mov ind,temp4 bank var jmp rev_cont org $300 ; ;***************************************************************** ; Sine-Cosine Tables ;***************************************************************** ; ; ;***************************************************************** ; FFT Input/Output Data Stored with 2 bytes of ; Real Data followed by 2 bytes of Imaginary Data. ;***************************************************************** ; ; 16 Point FFT Sine Table ; coefficient table (size of table is 3n/4). SineTable ; radians 0.392699082 ; degrees sin 16 bit form pt. dw 0 //256 ; 0 0 0 0 0 dw 0 /256 ; 0 0 0 0 0 dw 12539 //256 ; 0.392699082 22.5 0.382683432 12539 1 dw 12539 /256 ; 0.392699082 22.5 0.382683432 12539 1 dw 23170 //256 ; 0.785398163 45 0.707106781 23170 2 dw 23170 /256 ; 0.785398163 45 0.707106781 23170 2 dw 30273 //256 ; 1.178097245 67.5 0.923879533 30273 3 dw 30273 /256 ; 1.178097245 67.5 0.923879533 30273 3 CosTable dw 32767 //256 ; 1.570796327 90 1 32767 4 dw 32767 /256 ; 1.570796327 90 1 32767 4 dw 30273 //256 ; 1.963495408 112.5 0.923879533 30273 5 dw 30273 /256 ; 1.963495408 112.5 0.923879533 30273 5 dw 23170 //256 ; 2.35619449 135 0.707106781 23170 6 dw 23170 /256 ; 2.35619449 135 0.707106781 23170 6 dw 12539 //256 ; 2.748893572 157.5 0.382683432 12539 7 dw 12539 /256 ; 2.748893572 157.5 0.382683432 12539 7 dw 0 //256 ; 3.141592654 180 1.22515E-16 0 8 dw 0 /256 ; 3.141592654 180 1.22515E-16 0 8 dw -12539 //256 ; 3.534291735 202.5 -0.382683432 -12539 9 dw -12539 /256 -1 ; 3.534291735 202.5 -0.382683432 -12539 9 dw -23170 //256 ; 3.926990817 225 -0.707106781 -23170 10 dw -23170 /256 -1 ; 3.926990817 225 -0.707106781 -23170 10 dw -30273 //256 ; 4.319689899 247.5 -0.923879533 -30273 11 dw -30273 /256 -1 ; 4.319689899 247.5 -0.923879533 -30273 11 dw -32767 //256 ; 4.71238898 270 -1 -32767 12 dw -32767 /256 -1 ; 4.71238898 270 -1 -32767 12 testdata dw 0 dw 0 dw $40 dw $2d dw $ff dw $3f dw $40 dw $2d dw 0 dw 0 dw $c0 dw $d2 dw 1 dw $c0 dw $c0 dw $d2 dw 0 dw 0 dw $40 dw $2d dw $ff dw $3f dw $40 dw $2d dw 0 dw 0 dw $c0 dw $d2 dw 1 dw $c0 dw $c0 dw $d2
file: /Techref/scenix/fft/fft2sine.SRC, 17KB, , updated: 1998/8/17 00:15, local time: 2024/11/9 15:14,
3.144.6.223:LOG IN ©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/techref/scenix/fft/fft2sine.SRC"> scenix fft fft2sine</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Ashley Roll has put together a really nice little unit here. Leave off the MAX232 and keep these handy for the few times you need true RS232! |
.