📄 specana.asm
字号:
;----------------------------------------------------------;
; Spectrum analyzer
;----------------------------------------------------------;
; 16bit fixed point FFT performance with megaAVR @16MHz
;
; Points: Input, FFT, Output, Total: Throughput
; 64pts: .17ms, 1.9ms, 1.4ms, 3.5ms: 18.3kpps (expected)
; 128pts: .34ms, 4.4ms, 2.6ms, 7.3ms: 17.5kpps (measured)
; 256pts: .68ms, 10.1ms, 5.2ms, 16.0ms: 16.0kpps (expected)
; 512pts: 1.4ms, 22.6ms, 10.4ms, 34.4ms: 14.8kpps (expected)
;
; Input: Input waveform into butterfly table with applying window
; FFT: Execute butterfly operations
; Output: Descramble and output the spectrum as scalar values
;----------------------------------------------------------------------
; Low Resolution FFT Functions - Spectrum from 0 to 11kHz
;----------------------------------------------------------------------
do_window: ; Fill butterfly table with applying window function
ldiw X, CaptBuf ;Select source
ldiw Y, BflyBuf ;Destination
ldiw Z, t_hamming*2 ;Window table
ldiw C, FFT_N
ms_l1: lpmw A, Z+ ;Get a window attenuation ratio
ldw B, X+ ;Get an input value
subiw B, 512 ;unsigned -> signed
FMULS16 A, B, T4, T2 ;Apply window
stw Y+, T4 ;Store real
st Y+, _0 ;Clear image
st Y+, _0 ;/
subiw C, 1
brne ms_l1
ret
do_fft: ; Execute butterfly operations (not optimized)
ldi XH, 1 ;u
ldi EL, FFT_N/2 ;l
df_l1: ldiw Z, BflyBuf ;Z = BflyBuf
ldiw Y, BflyBuf ;Y = BflyBuf + l * 4
muli EL, 4 ;
addw Y, T0 ;/
mul AL, XH ;T10L = u * 4
mov T10L, T0L ;/
mov XL, XH ;w = u
df_l2: clr T14L ;p=0
df_l3: lddw A, Z+0 ;A = [Z+0] - [Y+0], [Z+0] += [Y+0]
movw CL, AL ;B = [Z+2] - [Y+2], [Z+2] += [Y+2]
lddw D, Y+0 ;
subw A, D ;
addw C, D ;
stw Z+, C ;
lddw B, Z+0 ;
movw CL, BL ;
lddw D, Y+2 ;
subw B, D ;
addw C, D ;
stw Z+, C ;/
movw T0L, ZL
movw ZL, T14L ;C=cos(p), D=sin(p)
addiw Z, t_cos_sin*2 ;
lpmw C, Z+ ;
lpmw D, Z+ ;/
movw ZL, T0L
FMULS16 A, C, T4, T2 ;[Y+0] = A * C + B * D
FMULS16 B, D, T8, T6 ;[Y+2] = B * C - A * D
addw T2, T6 ;
adcw T4, T8 ;
stw Y+, T4 ;
FMULS16 B, C, T4, T2 ;
FMULS16 A, D, T8, T6 ;
subw T2, T6 ;
sbcw T4, T8 ;
stw Y+, T4 ;/
add T14L, T10L ;p += u
rjne df_l3
muli EL, 4 ;Y += l * 4, Z += l * 4; (skip split segment)
addw Y, T0 ;
addw Z, T0 ;/
dec XL ;--w
rjne df_l2
lsl XH ;u *= 2
lsr EL ;l /= 2
rjne df_l1
ret
make_bars: ;Get scalar spectrum and update spectrum bar length
ldiw Z, t_desc*2 ;Descramble table
ldi CH, FFT_N/2 ;Number of elements
ub_l1: lpmw A, Z+ ;Get a vector value (A = r, B = i)
ldiw X, BflyBuf ;
addw X, A ;
ldw A, X+ ;
ldw B, X+ ;/
FMULS16 A, A, T4, T2 ;A = sqrt(A * A + B * B); 0..32767 (scalar)
FMULS16 B, B, T8, T6 ;
addw T2, T6 ;
adcw T4, T8 ;
SQRT32 ;/
movw T2L, AL ; AL = sqrt(A); 0..181 (root compression)
SQRT16 ; / * remove this for linear scale
ldi AH, FFT_SCALE ;T0H = AL/3; (scaling)
mul AL, AH ;/
dec T0H ;decrement bar length to suppress noise
brpl PC+2 ;
clr T0H ;/
ld AH, Y ;Update bar length with peak holding
subi AH, FFT_BDEC ; <-peak decay rate
brcs PC+3 ;
cp AH, T0H ;
brcc PC+2 ;
mov AH, T0H ;
st Y+, AH ;/
dec CH
rjne ub_l1
ret
calc_mixed_spec: ;calculates the interpolated spectrum from LvlBuf1 and LvlBuf3
ldiw X, LvlBuf1 ;high resolution FFT buffer
ldiw Y, TmpLvlBuf3 ;interpolated FFT buffer
ldi AH, 22 ;copy first 22 bars from LvlBuf1 to LvlBuf3
cm_l1: ld BL, X+ ;
st Y+, BL ;
dec AH ;
rjne cm_l1 ;/
ldi AH, 21 ;copy next 42 bars from LvlBuf1 to LvlBuf3
cm_l2: ld BL, X+ ; load next 2 bars
ld BH, X+ ;
cp BL, BH ; copy the bigger one
brlo PC+3 ;
st Y+, BL ;
rjmp PC+2 ;
st Y+, BH ;
dec AH ;
rjne cm_l2 ;/
ldiw X, LvlBuf2 ;low resolution FFT buffer
addiw X, 16 ;omit first 16 bars (frequency range of LvlBuf1)
ldi AH, 22 ;copy next 22 bars from LvlBuf2 to LvlBuf3
cm_l3: ld BL, X+ ;
st Y+, BL ;
dec AH ;
rjne cm_l3 ;/
ldi AH, 13 ;copy next 26 bar length from LvlBuf1 to LvlBuf3
cm_l4: ld BL, X+ ; load next 2 bar length
ld BH, X+ ;
cp BL, BH ; copy the bigger one
brlo PC+3 ;
st Y+, BL ;
rjmp PC+2 ;
st Y+, BH ;
dec AH ;
rjne cm_l4 ;/
ret
calc_peaks1: ;calculate peaks of LvlBuf1
ldiw X, TmpLvlBuf1
ldiw Y, PeakBuf1
ldiw Z, PeakSpeedBuf1
ldi AH, 64
rcall calc_peaks
ldiw X, TmpLvlBuf1
ldiw Y, LvlBuf1
ldi AH, 64
rcall copy_bars
ret
calc_peaks2: ;calculate peaks of LvlBuf2
ldiw X, TmpLvlBuf2
ldiw Y, PeakBuf2
ldiw Z, PeakSpeedBuf2
ldi AH, 64
rcall calc_peaks
ldiw X, TmpLvlBuf2
ldiw Y, LvlBuf2
ldi AH, 64
rcall copy_bars
ret
calc_peaks3: ;calculate peaks of LvlBuf3
ldiw X, TmpLvlBuf3
ldiw Y, PeakBuf3
ldiw Z, PeakSpeedBuf3
ldi AH, 78
rcall calc_peaks
ldiw X, TmpLvlBuf3
ldiw Y, LvlBuf3
ldi AH, 78
rcall copy_bars
ret
;calculate peak values, for selected buffer
; X=TmpLvlBuf, Y=PeakBuf, Z=PeakSpeedBuf, AH=value count
calc_peaks:
cp_l1: ld BL, X+ ;load new bar length
ld BH, Y ;load old peak value
cp BL, BH ;if(barLength > peak) {
brlo PC+5
st Y+, BL ; save bar length as new peak value
ldi AL, (FFT_PS<<4)|0x0F ; reset peak speed
st Z+, AL ; /
rjmp cp_ie
;} else { //update peak value
ld AL, Z ; load peakSpeed
mov CL, AL ; if((peakSpeed & 0x0F) > 0) {
andi CL, 0x0F ; /
breq cp_l2
dec AL ; decrement peak speed
st Z+, AL ; save updated peak speed
addiw Y, 1 ; increment peak-pointer
rjmp cp_ie
cp_l2: mov CL, AL ; } else if((peakSpeed & 0xF0) > 0) {
andi CL, 0xF0 ; /
breq cp_l3 ;
cpi BH, 2 ; decrement peak value
brsh PC+2 ;
ldi BH, 2 ;
dec BH ; /
subi AL, 0x10 ; decrement upper 4 bits of peakSpeed
lsr CL ; AL |= (AL & 0xF0) >> 4
lsr CL ;
lsr CL ;
lsr CL ;
or AL, CL ; /
st Y+, BH ; save new peak value
st Z+, AL ; save new peak speed
rjmp cp_ie
cp_l3: cpi BH, 2 ; } else {
brsh PC+2 ; decrement peak value
ldi BH, 2 ;
dec BH ; /
addiw Z, 1 ; increment peak speed pointer
st Y+, BH ; save new peak value
; }
cp_ie: dec AH ;}
rjne cp_l1
ret
;copy bar length buffer from temp buffer
; X=TmpLvlBuf, Y=LvlBuf, AH=value count
copy_bars:
ld BL, X+ ;load new bar length from temp buffer
st Y+, BL ;store new bar length
dec AH
rjne copy_bars
ret
; These tables must be rebuilt when change FFT_N
t_cos_sin: ; {cos(x),sin(x)} table (0 <= x < pi, in 64 steps)
.dw 32767, 0, 32727, 1607, 32609, 3211, 32412, 4807
.dw 32137, 6392, 31785, 7961, 31356, 9511, 30851, 11038
.dw 30272, 12539, 29621, 14009, 28897, 15446, 28105, 16845
.dw 27244, 18204, 26318, 19519, 25329, 20787, 24278, 22004
.dw 23169, 23169, 22004, 24278, 20787, 25329, 19519, 26318
.dw 18204, 27244, 16845, 28105, 15446, 28897, 14009, 29621
.dw 12539, 30272, 11038, 30851, 9511, 31356, 7961, 31785
.dw 6392, 32137, 4807, 32412, 3211, 32609, 1607, 32727
.dw 0, 32767, -1607, 32727, -3211, 32609, -4807, 32412
.dw -6392, 32137, -7961, 31785, -9511, 31356, -11038, 30851
.dw -12539, 30272, -14009, 29621, -15446, 28897, -16845, 28105
.dw -18204, 27244, -19519, 26318, -20787, 25329, -22004, 24278
.dw -23169, 23169, -24278, 22005, -25329, 20787, -26318, 19519
.dw -27244, 18204, -28105, 16845, -28897, 15446, -29620, 14009
.dw -30272, 12539, -30851, 11038, -31356, 9511, -31784, 7961
.dw -32137, 6392, -32412, 4807, -32609, 3211, -32727, 1607
t_hamming: ; Hamming window (for 128 samples)
.dw 2621, 2639, 2693, 2784, 2910, 3073, 3270, 3502
.dw 3768, 4068, 4401, 4765, 5161, 5587, 6042, 6525
.dw 7036, 7571, 8132, 8715, 9320, 9945, 10588, 11249
.dw 11926, 12616, 13318, 14031, 14753, 15482, 16216, 16954
.dw 17694, 18433, 19171, 19905, 20634, 21356, 22069, 22772
.dw 23462, 24138, 24799, 25443, 26068, 26673, 27256, 27816
.dw 28352, 28862, 29345, 29800, 30226, 30622, 30987, 31319
.dw 31619, 31885, 32117, 32315, 32477, 32603, 32694, 32748
.dw 32767, 32748, 32694, 32603, 32477, 32315, 32117, 31885
.dw 31619, 31319, 30987, 30622, 30226, 29800, 29345, 28862
.dw 28352, 27816, 27256, 26673, 26068, 25443, 24799, 24138
.dw 23462, 22772, 22069, 21356, 20634, 19905, 19171, 18433
.dw 17694, 16954, 16216, 15482, 14753, 14031, 13318, 12616
.dw 11926, 11249, 10588, 9945, 9320, 8715, 8132, 7571
.dw 7036, 6526, 6042, 5587, 5161, 4765, 4401, 4068
.dw 3768, 3502, 3270, 3073, 2910, 2784, 2693, 2639
t_desc: ; Descramble table (for 128 point FFT)
.dw 0*4, 64*4, 32*4, 96*4, 16*4, 80*4, 48*4, 112*4
.dw 8*4, 72*4, 40*4, 104*4, 24*4, 88*4, 56*4, 120*4
.dw 4*4, 68*4, 36*4, 100*4, 20*4, 84*4, 52*4, 116*4
.dw 12*4, 76*4, 44*4, 108*4, 28*4, 92*4, 60*4, 124*4
.dw 2*4, 66*4, 34*4, 98*4, 18*4, 82*4, 50*4, 114*4
.dw 10*4, 74*4, 42*4, 106*4, 26*4, 90*4, 58*4, 122*4
.dw 6*4, 70*4, 38*4, 102*4, 22*4, 86*4, 54*4, 118*4
.dw 14*4, 78*4, 46*4, 110*4, 30*4, 94*4, 62*4, 126*4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -