⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 specana.asm

📁 快速傅里叶变换在单片机中的实现,可用来显示生音波形
💻 ASM
📖 第 1 页 / 共 2 页
字号:

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