/* /////////////////////////////////////////////////////////////////////////////////// / FIR_Demo.asm 21161 EZ-KIT LITE SIMDFIR digital filter / / / / Receives input from the AD1836 A/D's via the 21161 serial port (SPORT1), / / Filters the data using a Finite Impuse Response Filter, and then stores the / / output for the SPORT1 ISR to transmit the data back to the AD1836 D/A's. / / / / The digital filter coefficients are in the files "high1.dat" and "low1.dat" / / / / The samples from the AD1836 are 24-bits and are are converted to / / floating point numbers. The values are also scaled to the range +/-1.0 / / with the integer to float conversion (f0 = float r0 by r1). / / / / The digital filtering takes place in the SPORT1 transmit interrupt service / / routine. / / / / See the "ADSP-21000 Family Applications Handbook Vol. 1" for more information / / regarding the implementation of digital filters (chapter 4) / / / / / /////////////////////////////////////////////////////////////////////////////////// */ /* ADSP-21161 System Register bit definitions */ #include "def21161.h" /* *** C preprocessor declarations (defines, includes, etc.) *** */ #define DOUBLE_FILTER_TAPS 132 #define FILTER_TAPS 66 #define HALF_FILTER_TAPS 33 .section /dm dm_data; .VAR filter_counter = 1; /* default is low-pass filter */ .ALIGN 2; /* wymuszenie odpowiedniego ułożenia zmiennych w pamięci (address alignment)*/ .VAR dline [DOUBLE_FILTER_TAPS]; /* delay line of input samples */ .endseg; /*---------------------------------------------------------------------------*/ .section /pm pm_data; .ALIGN 2; .VAR coef_lo_300Hz[FILTER_TAPS] = "coeffs65_300Hz.dat"; /* declare and initialize the higpass filter coefficients*/ .ALIGN 2; .VAR coef_lo_600Hz[FILTER_TAPS] = "coeffs65_600Hz.dat"; /* declare and initialize the lowpass filter coefficients*/ .ALIGN 2; .VAR coef_hi_4kHz[FILTER_TAPS] = "coeffs65_4kHz.dat"; /* declare and initialize the higpass filter coefficients*/ .ALIGN 2; .VAR coef_hi_8kHz[FILTER_TAPS] = "coeffs65_8kHz.dat"; /* declare and initialize the lowpass filter coefficients*/ /* "coeffs129_300Hz.dat" & "coeffs129_600Hz.dat" contains the coefficients for a low pass filter and "coeffs129_4kHz.dat" & "coeffs129_4kHz.dat" contains the coefficients for a high pass filter */ .endseg; .section /pm pm_code; /* deklaracje etykiet */ .GLOBAL init_fir_filter; .GLOBAL fir; .GLOBAL change_filter_coeffs; /* deklaracje zmiennych dostępnych w innych plikach */ .EXTERN RX_left_flag; .EXTERN Left_Channel_In1; .EXTERN Right_Channel_In1; .EXTERN Left_Channel_Out0; .EXTERN Right_Channel_Out0; .EXTERN Left_Channel_Out1; .EXTERN Right_Channel_Out1; init_fir_filter: bit set mode1 CBUFEN ; /* tryb bufora kolowego DAGs */ nop ; /* initialize the DAGS (dual Data Address Generators) */ b0 = dline; l0 = @dline; /* pointer to the samples (delay line) */ m1 = 2; b9 = coef_lo_300Hz; l9 = @coef_lo_300Hz; /* pointer to the filter coefficients */ m9 = 1 ; i3=dline; l3=@dline; r12=r12 xor r12; /* clear the delay line */ bit set mode1 PEYEN ; /* przejscie do trybu pracy SIMD (PEY ENable) */ lcntr=FILTER_TAPS, do clear until lce; /* lcntr: dlugosc petli, clear: etykieta ostatniej linii kodu, lce: warunek zakonczenia */ clear: dm(i3,2)=f12; /* wyzerowanie lokacji pamięci */ bit clr mode1 PEYEN ; /* opuszczenie trybu SIMD */ rts; /* zakonczenie podprogramu (return) */ init_fir_filter.end: /* //////////////////////////////////////////////////////////////////////////////// * * FIR filter subroutine * * //////////////////////////////////////////////////////////////////////////////// */ fir: /* process Left Channel Input */ r2 = -31; /* scale the sample to the range of +/-1.0 */ r0 = DM(Left_Channel_In1); /* pobranie probki */ r1 = DM(Right_Channel_In1); /* pobranie probki */ f0 = float r0 by r2 ; /* and convert to floating point */ f1 = float r1 by r2 ; /* and convert to floating point */ f8 = f0; /* in case we are in bypass mode, copy to output */ f9 = f1; /* in case we are in bypass mode, copy to output */ if FLAG2_IN jump exit_filter; do_filtering: dm(i0,m1)=f0 (LW); /* long word addressing */ // Enable broadcast mode and also set the PEYEN. bit set mode1 PEYEN | BDCST9; bit clr mode1 IRPTEN; r12=r12 xor r12; /* clear f12,put sample in delay line; niejawne zerowanie f12 */ /* odniesienie sie do rejestrow przez f0-f15: operacje zmiennoprzecinkowe */ /* odniesienie sie do rejestrow przez r0-r12: operacje staloprzecinkowe */ f8=pass f12, f0=dm(i0,m1), f4=pm(i9,m9);/* clear f8 (f12->f8),get data & coef */ lcntr=FILTER_TAPS-1, do macloop until lce; macloop: f12=f0*f4, f8=f8+f12, f0=dm(i0,m1), f4=pm(i9,m9); f12=f0*f4, f8=f8+f12; /* perform the last multiply */ f8=f8+f12; /* perform the last accumulate */ bit clr mode1 PEYEN | BDCST9; /* BDCST9 umożliwia broadcastowe (podwojne) ladowanie rejestrow komplementarnych z przesuniec wykorzystujacych rejestr I9 */ bit set mode1 IRPTEN; /* globalne wlaczenie przerwana */ r9 = s8; /* skopiowanie wartosci prawego kanalu */ exit_filter: r1 = 31; /* scale the result back up to MSBs */ r8 = fix f8 by r1; /* convert back to fixed point */ r9 = fix f9 by r1; /* Convert back to fixed point */ DM(Left_Channel_Out0) = r8; /* send result to AD1836 DACs */ DM(Right_Channel_Out0) = r9; DM(Left_Channel_Out1) = r8; /* send result to AD1836 DACs */ DM(Right_Channel_Out1) = r9; rts; fir.end: /* ------------------------------------------------------------------------------------ */ /* */ /* IRQ2 Pushbutton Interrupt Service Routine */ /* */ /* This routine determines which FIR filter routine to execute. */ /* Pressing the IRQ2 pushbutton will toggle between each filter. The default */ /* is a lowpass filter */ /* */ /* To listen to unfiltered signal, hit the FLAG 3 pushbutton */ /* ------------------------------------------------------------------------------------ */ change_filter_coeffs: bit set mode1 SRRFH; /* enable background register file */ NOP; /* 1 CYCLE LATENCY FOR WRITING TO MODE1 REGISER!! */ r11 = 4; r10 = DM(filter_counter); /* get last count from memory */ r10 = r10 + 1; /* increment preset */ comp (r10, r11); /* compare current count to max count */ if ge r10 = r10 - r10; /* if count equals max, reset to zero and start over */ DM(filter_counter) = r10; /* save updated count */ r15 = pass r10; /* get FIR filter preset mode ID */ if eq jump filter_select_2; /* check for count == 0 */ r10 = r10 - 1; r10 = pass r10; if eq jump filter_select_3; /* check for count == 1 */ r10 = r10 - 1; r10 = pass r10; if eq jump filter_select_4; /* check for count == 2 */ filter_select_1: /* count therefore, is == 3 if you are here */ b9 = coef_lo_300Hz; l9 = @coef_lo_300Hz; /* load 300 Hz lowpass filter coefficients */ ustat1=dm(IOFLAG); bit clr ustat1 0x3E; /* turn on Flag4 LED */ bit set ustat1 0x01; dm(IOFLAG)=ustat1; jump exit_IRQ_routine; filter_select_2: b9 = coef_lo_600Hz; l9 = @coef_lo_600Hz; /* load 600 Hz lowpass filter coefficients */ ustat1=dm(IOFLAG); bit clr ustat1 0x3D; /* turn on Flag5 LED */ bit set ustat1 0x02; dm(IOFLAG)=ustat1; jump exit_IRQ_routine; filter_select_3: b9 = coef_hi_4kHz; l9 = @coef_hi_4kHz; /* load 4000 Hz highpass filter coefficients */ ustat1=dm(IOFLAG); bit clr ustat1 0x3B; /* turn on Flag6 LED */ bit set ustat1 0x04; dm(IOFLAG)=ustat1; jump exit_IRQ_routine; filter_select_4: b9 = coef_hi_8kHz; l9 = @coef_hi_8kHz; /* load 8000 Hz highpass filter coefficients */ ustat1=dm(IOFLAG); bit clr ustat1 0x37; /* turn on Flag7 LED */ bit set ustat1 0x08; dm(IOFLAG)=ustat1; exit_IRQ_routine: rti(db); bit clr mode1 SRRFH; /* switch back to primary register set */ nop; change_filter_coeffs.end: