DSP

FIR加速器

2019-07-13 15:55发布

FIR滤波器的作用:它可以对音响进行纠正,使用任何的测量工具测得房间的脉冲响应,我们知道FIR系数的傅里叶变换即为频率响应,那么就可以得到房间最适合音响的一种音质,这对于音响的保护和产生最佳音质是有及其重要的作用,越来越多的数字音频设备中将FIR加入它们的设备中,是一个极大的卖点。 我们来看看Sysmtrix(思美)的FIR滤波器是怎么样的,如下图。这是一个1024 TapsFIR滤波器,它直接点击Load Table选择,选择滤波器系数文件(*.csv)文件就可实现系数的导入,滤波器图形显示这是一个2k的低通滤波器。
好,接下来我们看看如何实现这个功能呢,大部分的DSP内部函数都带有了FIR函数,直接调用即可。但是FIR滤波器是很占资源的,使用CPU去做,很难达到理想的一种应用,要在时间和处理之间进行平衡。ADISHARC DSP呢,它自带有FIR硬件加速器,使用加速器不占用CPU时间,是非常棒的。 那么FIR加速器如何使用呢,用过VDSP的朋友应该知道,VDSP5.0有一个Accelerators插件,使用它我们可以通过参数配置的方式轻松得到一份代码例子(没有的朋友请到官网进行下载,按照文档安装)。
我们看左边的FIR Accelerator,它有很多参数,下面逐一解释: GlobalSettings for all channels -No ofChannels : 需要做FIR滤波器的通道数,FIR采用TDM方式将外部数据搬移到加速器。 -DataFormat: 数据格式指定定点还是浮点,既然是SHARC DSP,它肯定是浮点了。 -AutoIterate?: 自动迭代,一帧数据处理完后是否自动从TCB加载数据处理。设置为否,需要CPU启动。 -RoundingMode: 舍入模式,此处默认即可,既然是浮点,影响不大。 -DMAInterrupt: 指定DMA中断发生在CPU哪个中断脚。 -Statusinterrupt: 状态中断,正常状态下无需设置。 -InterruptWhen: 何时中断,是所有通道都处理完了中断还是单个通道处理完了就中断CPU ChannelSpecific Setting: 这里的设置我们先不管吧,主要对BUFFER进行设置,使用这个软件进行设置还不如直接进行代码修改来得快。注意到里面有一个Sample Rate Convertion,也就是说它还有采样率转换,比如输入48KFIR滤波之后得到8k的数据,降采样,这个时候我们将Ratio设置为6。本文将采用单速率的方式,此处不需要进行设置。 好,我们来看看产生的代码例子,#defineTAPS 512#define WINDOWSIZE 512,具体根据应用情况进行修改。 /*  This file includes the initialization codes for FIR, IIR and FFT Accelerators  */   #include  "def21489.h" #include  "Cdef21489.h"   void  Init_FIR();   /*  Declaring the external buffers needed for FIR Accelerator*/ extern  int FIR_IP_buff1[];  //输入数据BUFFER,大小为TAPS+WINDOWSIZE-1 extern  int FIR_OP_buff1[]; //输出BUFFER,大小为WINDOWSIZE extern  int FIR_CF_buff1[]; //系数BUFFER,大小为TAPS   extern  int FIR_IP_buff2[]; extern  int FIR_OP_buff2[]; extern  int FIR_CF_buff2[];   //这个很重要,DMA TCB配置 /*Adding  the TCB for FIR channels*/ int  FIR_TCB_CH2[13]={                                      0,//链式指针寄存器                                      512 TAPS,//系数buffer长度寄存器,我们修改为宏定义TAPS                                      1  -1, //系数修改寄存器,根据加速器                                      FIR_CF_buff2,                                      FIR_OP_buff2,                                      512  WINDOWSIZE, //输出BUFFER长度寄存器                                      1,                                      FIR_OP_buff2+0,                                      FIR_IP_buff2,                                      512  TAPS+ WINDOWSIZE-1,//输入BUFFER长度寄存器                                      1,                                      FIR_IP_buff2+0,                                      511|(511<<14)  TAPS -1|((WINDOW_SIZE-1)<<14)                             };     //TCB1亦如是配置 int  FIR_TCB_CH1[13]={                                      FIR_TCB_CH2+12,                                      512,                                      1,                                      FIR_CF_buff1,                                      FIR_OP_buff1,                                      512,                                      1,                                      FIR_OP_buff1+0,                                      FIR_IP_buff1,                                      512,                                      1,                                      FIR_IP_buff1+0,                                      511|(511<<14)                             };     /*  Adding the Initialization Code for FIR Accelerator Now */   void  Init_FIR() {            int temp; //链式指针寄存器          FIR_TCB_CH2[0]=FIR_TCB_CH1+12;   //这里映射DMA中断到PI0          //Mapping the FIR DMA interrupt          temp=*pPICR0;          temp&=~(P0I0|P0I1|P0I2|P0I3|P0I4);          temp|=P0I0|P0I1|P0I3|P0I4;          *pPICR0=temp; //选择FIR加速器,FIR,IIR,FFT只能使用一个,能不能同时使用三个,这是不行的          //Selecting the FIR Accelerator          temp=*pPMCTL1;          temp&=~(BIT_17|BIT_18);          temp|=FIRACCSEL;          *pPMCTL1=temp;            //PMCTL1 effect latency                    asm("nop;nop;nop;nop;");                      //Initializing the chain  pointer register          *pCPFIR=FIR_TCB_CH1+12-0x80000; //使能加速器,一旦配置好,加速器就会运行,这里将它注释掉          //Now Enabling the FIR Accelerator          *pFIRCTL1=FIR_EN|FIR_DMAEN|FIR_CH2|FIR_RND0;   }     上面呢,将加速器的使能语句注释掉了,是什么原因呢。在音频系统里面,DSP是按音频的采样率取帧进行处理,也就是采集到了一个WINDOWSIZE即产生中断,开始音频处理任务。如果你FIR加速器马上使能或者让它自动迭代处理,无法配合我们的应用程序完成数据同步的问题。最好的办法是音频处理完一帧,使能FIR加速器,在音频的下一帧处理中,我们就可以引用加速器处理之后的数据了,再将需要处理的数据扔回给加速器。 最后,还有一个问题,细心的朋友可能会发现,输入BUFFER长度是TAPS+WINDOWSIZE -1,那么输入数据该如何填充呢?OK,这是一个循环buffer,初始化的时候定义一个指针指向TAPS-1位置。在填充数据时,使用circptr内联函数将指针重定义位置,直接看代码吧。 float*  inptr = fir_ip_bufffer(0)+handle->taps-1;        //初始化为taps-1位置 ......... //填充数据代码段 for(i=0;ioptFIR输出buffer          *handle->inptr = in_ptr[i]; //音频采样过来的数据,填给FIR输入buffer          handle->inptr =  circptr(handle->inptr,1,iptr, handle->taps + WINDOW_SIZE - 1);//移动指针 } 这样明了吗,有什么不明白的地方请在公众号ddongcloud发信息给我!
作为一名技术工程师,我希望将我的知识分享给大家,帮助到大家一点点。如有写得有误的地方请指教,欢迎探讨!原创不易,尤其一个一个文字敲打出来,这都是实践中总结出来的步骤和方法。大家喜欢,请关注我的公众号:ddongcloud ,更多的原创文章和您分享。