电子文章 | 电子资料下载 | 家电维修 | 维修资料下载 | 加入收藏 | 全站地图
您现在所在位置:电子爱好者电子文章音响功放采用MAXQ2000进行音频滤波

采用MAXQ2000进行音频滤波

08-17 11:51:32 | http://www.5idzw.com | 音响功放 | 人气:955
标签:汽车音响功放,音响功放电路,http://www.5idzw.com 采用MAXQ2000进行音频滤波,http://www.5idzw.com
性能该应用处理单声道16位音频数据并产生8kHz输出,还没有完全发挥微控制器的能力。由于使用汇编语言编写滤波器,可用一个表达式方便算出用于计算长度为N的FIR滤波器所需的周期数。然后还可使用该表达式计算出采用前面所列算法的最大滤波速率。

可将用于产生音频采样的功能分成3部分:初始化、滤波器计算循环以及结果修正。在该例中,初始化需要38个周期,滤波器计算中每个滤波器参数需要17个周期,结果修正需要9 + (6 x S)个周期,其中S是移位数。通常,移位数为12,则结果修正为81个周期。因此,需要119 + (17 x N)个周期产生一个滤波输出结果。20MHz时,MAXQ2000可以运行近11kHz的100抽头滤波器,这已经是相当好的语音质量。

现在回到前面重新分析应用程序以进一步进行简化。我们将主要针对滤波器循环,因为此处占用了多数周期,并且最烦琐。

还可以对循环代码进行几处关键改进以提高效率。注意,我们采用了预先录制并存储在代码区的音频采样。由于MAXQ采用哈佛体系结构,因此查找代码空间比查找数据空间需要更多的时间。称为UROM_MOVEDP1INC和UROM_MOVEDP0DEC的函数每个执行需要5个周期(LCALL为2周期,函数内部为3周期)。如果滤波器存储在RAM中并处理存储在RAM中的实时输入数据,则每个只需两周期(一个周期选择指针,一个周期读)。如果将RAM中的256个字用于滤波器,可用BP[Offs]实现一个环形缓冲区来存储输入数据。这些改动可将循环时间由17个周期缩短为11个。这样的滤波器循环为下所示(在注释中首先列出所需周期数):
zeroes_filterloop:
    move  A[0], DP[0]          ; 1, let's see if we are out of data
    cmp   #W:rawaudiodata      ; 2, compare to the start of the audio data
    move  DP[1], DP[1]         ; 1, select DP[1] as our active pointer
    move  GR, @DP[1]++         ; 1, get next filter coefficient
    move  MA, GR               ; 1, multiply filter coefficient...
    move  BP, BP               ; 1, select BP[Offs] as our active pointer
    move  GR, @BP[Offs--]      ; 1, get next filter data
    move  MB, GR               ; 1, multiply audio sample...
    jump  e, zeroes_outofdata  ; 1, stop if at the start of the audio data
    djnz  LC[0], zeroes_filterloop  ; 1
将滤波器及输入数据装入RAM后还可以利用MAXQ体系结构的另一特点。MAXQ指令集高度不相关,在任何操作中,对采用何种源几乎没有限制。因此,可不将滤波器数据和输入数据读入GR,而是直接写入MAC寄存器。这样可使循环降至9个周期。
zeroes_filterloop:
    move  A[0], DP[0]          ; 1, let's see if we are out of data
    cmp   #W:rawaudiodata      ; 2, compare to the start of the audio data
    move  DP[1], DP[1]         ; 1, select DP[1] as our active pointer
    move  MA, @DP[1]++         ; 1, multiply next filter coefficient
    move  BP, BP               ; 1, select BP[Offs] as our active pointer
    move  MB, @BP[Offs--]      ; 1, multiply next filter data
    jump  e, zeroes_outofdata  ; 1, stop if at the start of the audio data
    djnz  LC[0], zeroes_filterloop  ; 1
最后的修改可极大改进该代码。每次循环时,比较当前数据指针和音频输入数据起始位置,以查看是否越界(MOVE A[0], DP[0]语句,CMP比较语句以及JUMP E语句)。如果设置初始音频数据(现在正在读取的、BP[Offs]指向的环形缓冲)为全零,则可以省略这些检查。与后面的几千次采样每次节省4周期相比,RAM初始化为全零的时间可忽略,新的循环代码缩减至5个周期。
zeroes_filterloop:
    move  DP[1], DP[1]         ; 1, select DP[1] as our active pointer
    move  MA, @DP[1]++         ; 1, multiply next filter coefficient
    move  BP, BP               ; 1, select BP[Offs] as our active pointer
    move  MB, @BP[Offs--]      ; 1, multiply next filter data
    djnz  LC[0], zeroes_filterloop  ; 1
在回到性能方程之前,先查看一下结果计算。看起来当前并不需要移位48位结果。
    move  A[2], MC2            ; get MAC result HIGH
    move  A[1], MC1            ; get MAC result MID
    move  A[0], MC0            ; get MAC result LOW
    move  APC, #0C2h           ; clear AP, roll modulo 4, auto-dec AP

shift_loop:
    ;
    ; Because we use fixed point precision, we need to shift to get a real
    ; sample value.  This is not as efficient as it could be.  If we had a
    ; dedicated filter, we might make use of the shift-by-2 and shift-by-4
    ; instructions available on MAXQ.
    ;
    move  AP, #2               ; select HIGH MAC result
    move  c, #0                ; clear carry
    rrc                        ; shift HIGH MAC result
    rrc                        ; shift MID MAC result
    rrc                        ; shift LOW MAC result
    djnz  LC[1], shift_loop    ; shift to get result in A[0]
    move APC, #0               ; restore accumulator normalcy
    move AP, #0                ; use accumulator 0
一个可能的方法是再次采用MAC。不采取右移12位(或0和16间的任一数值),而是向左移16减去该值的位数(如左移4位)。这会使结果处于MAC寄存器16位字的中间。注意,左移的实际结果是乘以2的若干次幂(假如开始准备右移12位时,为16)。
    ;
    ; don't care about high word, since we shift left and take the
    ; middle word.
    ;
    move  A[1], MC1            ; 1, get MAC result MID
    move  A[0], MC0            ; 1, get MAC result LOW
    move  MCNT, #20h           ; 1, clear the MAC, multiply mode only
    move  AP, #0               ; 1, use accumulator 0
    and   #0F000h              ; 2, only want the top 4 bits
    move  MA, A[0]             ; 1, lower word first
    move  MB, #10h             ; 1, multiply by 2^4
    move  A[0], MC1R           ; 1, get the high word, only lowest 4 bits significant
    move  MA, A[1]             ; 1, now the upper word, we want lowest 12 bits
    move  MB, #10h             ; 1, multiply by 2^4
    or    MC1R                 ; 1, combine the previous result and this one
    ;
    ; result is in A[0]
    ;
这将花费12个周期进行结果计算,而不是9 + (6 x S)个周期。

现在回到前面的方程中。新方程保守估计开销占用40个周期,每个循环迭代占5周期。采用与前面相同的100抽头滤波器,MAXQ2000能够处理16位、37kHz单声道音频数据,如表1所示。

表1. FIR滤波器最大采样速率(20MHz MAXQ2000,循环) Filter Length (Taps) Max Rate (Hz) 50 68965.51724 100 37037.03704 150 25316.4557 200 19230.76923 250 15503.87597 300 12987.01299 350 11173.18436
对于需要更高采样率的应用、可牺牲代码空间进一步提高性能。可以“内嵌”滤波器参数,不再需要选择有效指针和循环(该技术也称为循环展开)。这种改变的代价是增加代码空间,以前需要100个字来存储一个100个点的滤波器;现在,则需要300个字来存储(每个参数移动为2个字,每个数据移动为1个字)。在16k字的器件中,相对于性能的提高,这种代价可忽略。新代码形式如下:
    move  BP, BP               ; select BP[Offs] as our active pointer
zeroes_filtertop:
    move  MA, #FILTERCOEFF_0   ; 2, multiply next filter coefficient
    move  MB, @BP[Offs--]      ; 1, multiply next filter data
    move  MA, #FILTERCOEFF_1   ; 2, multiply next filter coefficient
    move  MB, @BP[Offs--]      ; 1, multiply next filter data
    move  MA, #FILTERCOEFF_2   ; 2, multiply next filter coefficient
    move  MB, @BP[Offs--]      ; 1, multiply next filter data
    . . .
    move  MA, #FILTERCOEFF_N   ; 2, multiply next filter coefficient
    move  MB, @BP[Offs--]      ; 1, multiply next filter data
    ;
    ; filter calculation complete
    ;

上一页  [1] [2] [3]  下一页

,采用MAXQ2000进行音频滤波
关于《采用MAXQ2000进行音频滤波》的更多文章