# 采用MAXQ2000进行音频滤波

### Abstract

MAXQ2000的MAC能够发挥多大的性能？本应用笔记以一个音频滤波器为例来解释此问题，并定量给出MAXQ2000支持的性能。

### 运行演示

MAXQ2000评估板上的按键用于选择滤波器，并播放经过滤波的音频采样。使用按键SW4选择滤波器，滤波器名称将显示在LCD上(HI为高通、LO为低通、BP为带通，ALL为全通)。使用按键SW5播放通过所选滤波器的音频。可在播放期间切换滤波器。

### 设计一个简单的FIR滤波器

y(n) + ΣbKy(k) = ΣaJx(j)

y(n) = 0.5y(n-1) + x(n) - 0.8x(n-1)

y(n) = ΣaJx(j)
y(n) = x(n) - 0.2x(n - 1) + 0.035x(n - 3)

### 使用乘-累加(MAC)单元实现一个滤波器

```Zeroes:
dc16
dc16 12, 11, 0x1000, 0x26d3, 0x1e42, 0xf9a3, 0xecde, 0xff31, 0xa94,
0x2ae, 0xfd0c, 0xff42, 0xde
Shift amount: 12
```

### 用MAXQ汇编语言实现滤波器

```    move  MCNT, #22h           ; signed, mult-accum, clear regs first

zeroes_filterloop:
move  A[0], DP[0]          ; let's see if we are out of data
cmp   #W:rawaudiodata      ; compare to the start of the audio data
lcall UROM_MOVEDP1INC      ; get next filter coefficient
move  MA, GR               ; multiply filter coefficient...
lcall UROM_MOVEDP0DEC      ; get next filter data
move  MB, GR               ; multiply audio sample...
jump  e, zeroes_outofdata  ; stop if at the start of the audio data
djnz  LC[0], zeroes_filterloop

zeroes_outofdata:
move  A[2], MC2            ; get MAC result HIGH
move  A[1], MC1            ; get MAC result MID
move  A[0], MC0            ; get MAC result LOW
```

### 性能

```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
```

```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
```

```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
```

```    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
```

```    ;
; 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]
;
```

 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

```    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
;
```

 Filter Length (Taps) Max Rate (Hz) 50 105263.1579 100 58823.52941 150 40816.32653 200 31250 250 25316.4557 300 31250 350 27027.02703

### 支持IIR滤波器

• 使用一段专用RAM来存储最后的输出采样(环形缓冲中使用该方法最有效，BP[Offs]寄存器的使用方式与前面描述的相似)
• 包括滤波器的反馈(‘y'部分)特征参数
• 加入另一个循环，该循环持续累加滤波器反馈部分的乘积结果

### 结论

MAXQ2000具有的性能和外设可使其成为优秀的通用微控制器，可以广泛应用在需要快速、通用微控制器(特别是需要用户交互)的场合。高效的MAC使MAXQ2000具有一定的数字滤波能力，可成为最通用的通用微控制器。