📄 simd_fir_demo.asm
字号:
/* ///////////////////////////////////////////////////////////////////////////////////
/ 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 FILTER_TAPS 130
#define ONEHALF_FILTER_TAPS 65
.segment /dm dm_data;
.VAR dummy_variable=0;
.ALIGN 2;
.VAR dline [FILTER_TAPS]; /* delay line of input samples */
.VAR dummy_variable2 = 0;
.VAR filter_counter = 2; /* default is low-pass filter */
.endseg;
/*---------------------------------------------------------------------------*/
.segment /pm pm_data;
.ALIGN 2;
.VAR coef_lo_300Hz[FILTER_TAPS] = "coeffs129_300Hz.dat"; /* declare and initialize the higpass filter coefficients*/
.ALIGN 2;
.VAR coef_lo_600Hz[FILTER_TAPS] = "coeffs129_600Hz.dat"; /* declare and initialize the lowpass filter coefficients*/
.ALIGN 2;
.VAR coef_hi_4kHz[FILTER_TAPS] = "coeffs129_4kHz.dat"; /* declare and initialize the higpass filter coefficients*/
.ALIGN 2;
.VAR coef_hi_8kHz[FILTER_TAPS] = "coeffs129_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;
.segment /pm pm_code;
.GLOBAL init_fir_filter;
.GLOBAL fir;
.GLOBAL change_filter_coeffs;
.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;
nop;
/* initialize the DAGS */
b0 = dline; l0 = @dline; /* pointer to the samples (delay line) */
m1 = 1; m2 = -1; m3 = 2;
b9 = coef_hi_4kHz; l9 = @coef_hi_4kHz; /* pointer to the highpass filter coefficients */
m9 = 2;
B3=dline; l3=@dline; r12=0; /* clear the delay line */
lcntr=FILTER_TAPS, do clear until lce;
clear: dm(i3,2)=r12;
rts;
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); /* get left input sample */
r1 = DM(Right_Channel_In1); /* get right input sample */
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 */
f0 = f0 + f1; /* add both left and right channels together */
f2 = 0.7;
f0 = f0 * f2; /* turn down the volume slightly */
if flag2_in jump exit_filter;
do_filtering:
// Circular Buffering Issue:
// Because SIMD or Long word access transfer two 32-bit words, programs
// must be careful when using these accesses in circular buffering.
// It is important that SIMD or Long word accesses do not cross a circular
// buffer boundary. If a SIMD mode access occurs using a circular buffer
// index register that points to the last location in the circular buffer
// (end of buffer), the resulting access transfers the last location in
// the circular buffer and the first location outside the buffer (end of buffer + 1).
bit clr mode1 BDCST9; /* disable broadcast mode, we have 2 sets of coeffs */
// process filter on left and right channels
s0 = dm(i0, m1); /* move pointer to delay[1] */
// Enable the Y processing element for SIMD mode
bit set mode1 PEYEN;
s0 = dm(i0, m2); /* load s0 with the value of delay[1] for SIMD store, move pointer to delay[0] */
dm(i0,m3)=f0, f4 = pm(i9,m9); /* transfer sample to delayline, done in SIMD to load end of buffer + 1 */
/* to compensate for circular buffer issue described above, read 2 coeffs */
f8=f0*f4, f0=dm(i0,m3), f4=pm(i9,m9); /* samples * coeffs, read 2 samples, read 2 coeffs */
f12=f0*f4, f0=dm(i0,m3), f4=pm(i9,m9); /* samples * coeffs, read 2 samples, read 2 coeffs */
lcntr= ONEHALF_FILTER_TAPS - 3, do macloop until lce; /* FIR loop */
macloop: f12=f0*f4, f8=f8+f12, f0=dm(i0,m3), f4=pm(i9,m9); /* samples * coeffs, accum, read 2 samples, read 2 coeffs */
f12=f0*f4, f8=f8+f12, s0=dm(i0,m2); /* samples * coeffs, accum, dummy read to move pointer to oldest sample */
f8=f8+f12; /* perform the last SIMD accumulate */
bit clr mode1 PEYEN;
f12 = s8; /* move PEy total into PEx register file */
f8 = f8 + f12; /* last accum... add PEx and PEy partial results */
exit_filter:
r1 = 31; /* scale the result back up to MSBs */
r8 = fix f8 by r1; /* Convert back to fixed point */
DM(Left_Channel_Out0) = r8; /* send result to AD1836 DACs */
DM(Right_Channel_Out0) = r8;
DM(Left_Channel_Out1) = r8;
DM(Right_Channel_Out1) = r8;
rts;
fir.end:
/* ------------------------------------------------------------------------------------ */
/* */
/* IRQ2 Pushbutton Interrupt Service Routine */
/* */
/* This routine determines which FIR filter routine to execute. */
/* Pressing the IRQ1 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:
.endseg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -