{_________________________________________________________________________ R2FIR.ASM ADSP-21020 Radix-2 FIR Filter This routine performs N-tap FIR filtering using a radix-2 implementation, where N must be even. The FIR filter is broken down into three subfilters resulting in about a 25% speed improvement at the cost of a 50% greater memory requirement. For a more complete discussion see: [1] Meyer, Reng, Schwarz : Convolution Algorithms on DSP Processors Proc. ICASSP 1991 Toronto [2] Mou, Duhamel : Fast FIR Filtering: Algorithms and Implementations Signal Processing 13 (1987) pp. 377-384 This routine should be called each time a new sample is available to be fed into the filter. Filter coefficients reside in program memory and can be generated from direct FIR filter coeff using the program D2R2FIR. This program creates the coeff tables H0, H1 and H0+H1 and stores them consecutively in a file where H0 = h(0), h(2), h(4), ... and H1 = h(1), h(3), h(5), ... . Author: Karl Schwarz, Universitaet Erlangen Nuernberg Revision: 29-MAR-91, Ronnin Yee, Analog Devices, DSP div., (617) 461-3672 Calling Information: f2 = x(n-1) in floating point f11 = x(n) in floating point where x is the incoming sample stream and n is the current sample Results: f9 = y(n-1) in floating point f10 = y(n) in floating point where y is the outgoing filtered sample stream and n is the current sample Altered Registers: f0,f1,f2,f3,f4,f8,f11,f12,f13,f14, i0,i1,i2,i3,i8,i9,i10,l0,l1,l2,l8,l9,l10, m0,m1,m2,m8 Benchmarks: radix-2 FIR, 3/4*N + 7 cycles/sample 3/4*N + 15.5 cycles/sample with pointer initialization/restoration Memory Usage: pm code = 32 words, pm data = 1.5N words, dm data = 1.5N + 1 words Assembler Preprocessor Variables: N = number of taps = degree + 1 = even _________________________________________________________________________} #include "def21020.h" #define N 32 .SEGMENT/PM pm_data; .VAR coeff[3*N/2] = "coeff.dat"; .ENDSEG; .SEGMENT/DM dm_data; .VAR a_smpl[N/2]; {a= x(n-1), x(n-3), ... ; b= x(n-2), x(n-4),...} .VAR bma_smpl[N/2]; { c= x(n), x(n-2), ... } .VAR amc_smpl[N/2]; { bma_smpl= b - a; amc_smpl= a - c } .VAR x_old; { x(n-2) sample} .ENDSEG; .SEGMENT/DM ports; .PORT adc; {adc port} .PORT dac; {dac port} .ENDSEG; .SEGMENT/PM rst_svc; pmwait=0x0021; {pgsz=0,pmwtstates=0,softw.wtstates only} dmwait=0x008421;{pgsz=0,dmwtstates=0,softw.wtstates only} jump main; nop; nop; .ENDSEG; .SEGMENT/PM tmzh_svc; jump timer_rnt; nop; nop; .ENDSEG; .SEGMENT/PM pm_code; main: imask=TMZHI; {irq3 enable, timer enable high priority} mode1=IRPTEN; {enable global interrupt} tperiod=16000; {8 KHz sampling} tcount=16000; mode2=TIMEN; r15=0x0; {*****Initialization for r2fir****} b0= a_smpl; { a } b1= bma_smpl; { b-a } b2= amc_smpl; { a-c } b3= x_old; { x(n-2) sample} b8= coeff+N; { h0+h1 } b9= coeff+N/2; { h1 } b10=coeff; { h0 } m0=1; m1=-1; m2=0; m8=1; l0=N/2; l1=N/2; l2=N/2; l8=N/2; l9=N/2; l10=N/2; {****************} idle; jump (pc,-1); nop; nop; r2fir: {The body of the radix-2 fir filter} { f2 = input; = x(n-1) } { f11 = input; = x(n) } { f8 = x(n-2) = old value from f11 } r14=r14-r14, f8=dm(i3,m2); {zeros out f14} f13=pass f2, dm(i0,m0)=f2, f4=pm(i8,m8); f12=f2*f4, f3=f8-f13, f0=dm(i0,m0), f4=pm(i9,m8); f13=f3*f4, f1=f11-f13, dm(i1,m0)=f3, f4=pm(i10,m8); f8=f1*f4, dm(i2,m0)=f1, f4=pm(i8,m8); LCNTR=N/2-2, do fir_l until LCE; f8=f0*f4, f14=f8+f14, f0=dm(i1,m0), f4=pm(i9,m8); f8=f0*f4, f12=f8+f12, f0=dm(i2,m0), f4=pm(i10,m8); fir_l: f8=f0*f4, f13=f8+f13, f0=dm(i0,m0), f4=pm(i8,m8); f8=f0*f4, f14=f8+f14, f0=dm(i1,m2), f4=pm(i9,m8); f8=f0*f4, f12=f8+f12, f0=dm(i2,m2), f4=pm(i10,m8); f8=f0*f4, f13=f8+f13, f0=dm(i0,m1); rts (db), f14=f8+f14; f9=f12+f13, dm(i3,m2)=f11; {x(n-2) = x(n)} f10=f12+f14; { output = f9 = y(n-1) } { output = f10 = y(n) } {end of routine} {An example timer routine} timer_rnt: i6=adc; i7=dac; m7=0; r15= pass r15, r5=dm(i6,m7); {read data} dm(i6,m7)=r15; {dummy write to start new conversion} if ne jump dofilter; r15=r15+1; rti (db); r9=fix f9; f2=float r5, dm(i7,m7)=f9; {write y(n-1) to DAC} dofilter: call r2fir (db); r10=fix f10; f11=float r5, dm(i7,m7)=f10; {write y(n) to DAC} rti (db); r15=0x0; nop; .ENDSEG;