📄 2nd_order_fir.s90
字号:
;*****************************************************
;* File: 2nd_order_FIR.s90
;*
;* Version: 1.0
;* Date: 01.06.15 [yy.mm.dd]
;* Author: jllassen
;*
;* Last modified 02.02.20, by jllassen
;* Changes: ported the code from the AVR assembler to IAR assembler/compiler
;*
;* Target device: AVRs with HW multiplier
;*
;* Compiler:
;* IAR EWAVR 2.26C
;*
;* Describtion:
;* 2nd order FIR filter.
;* 10-bit signed data.
;* 13-bit signed filter coefficients.
;*
;* Usage:
;* Implemented so that the filter can be called from IAR EWAVR C compiler.
;* Address to the filter nodes and filter coefficients should be provided
;* as first calling argument (will thus be placed in R16:R17) and the new
;* input sample to the filter should be provided as the second calling
;* argument (placed in R18:R19).
;*
;* int FIR_filter(*myFilter, newDataSample);
;*
;* The structure for the filter nodes and filter coefficients should be
;* as follows:
;*
;* struct FIR_filter{
;* int filterNodes[FILTER_ORDER]; //memory nodes required to store x(n-1), x(n-2)
;* int filterCoefficients[(FILTER_ORDER)+1]; //filter coefficients B0, B1, B2
;* }, myFilter = {0, 0, B0, B1, B2}
;*
;* The filter nodes should be initialized prior to the first call of the
;* filter function and the filter coefficients should be scaled to use
;* signed 13-bit resolution (max)
;*
;* Registers usage:
;* r0-4, r16-23, Z (all scratch/volatile registers)
;*
;* Memory usage for variables and constants:
;* 4 bytes SRAM for filter nodes (filter memory)
;* 6 bytes SRAM for filter coefficients
;*
;* Stats:
;* INIT: Depending on compiler settings (135 cycles)
;* FILTER: 60 instructions; 80 cycles (excl. ret)
;*****************************************************
NAME assembly(16)
PUBLIC FIR2
RSEG CODE
;ZERO register (used to add carry flag)
#define ZERO R2
#define ZL R30
;Accumulator - 24bit
#define AC2 R16
#define AC1 R17
#define AC0 R3
;First argument passed in the function call: the address to the filter struct (16 bit address pointer)
#define FILTER_POINTER r16
;Second argument passed in the function call: the new data sample
#define NDATAL R18
#define NDATAH R19
;Data samples mul register (used in multiplication)
#define DATAL R20
#define DATAH R21
;Filter coefficient mul register (used in multiplication)
#define COEFL R22
#define COEFH R23
;Filter nodes offset relative to filter struct address
#define X1 0*2
#define X2 1*2
;Filter coefficient offset relative to filter struct address
#define B0 2*2
#define B1 3*2
#define B2 4*2
;**************************************************
;* MACROS
;**************************************************
LOAD_NODE MACRO
ldd DATAL,Z+\1 ; Load low byte of node
ldd DATAH,Z+\1+1 ; Load high byte of node
ENDM
UPDATE_NODE MACRO
std Z+\1, DATAL ; Update low byte of node to prepare next filter run
std Z+\1+1, DATAH ; Update high byte of node to prepare next filter run
ENDM
LOAD_COEF MACRO
ldd COEFL,Z+\1 ; Load low byte of node
ldd COEFH,Z+\1+1 ; Load high byte of node
ENDM
MUL_MOV_24 MACRO
muls COEFH, DATAH ; Signed multiply, coefficient high byte and data high byte
mov AC2, r0 ; Copy low byte into accumulator byte 2 (sign bit automatically correct)
mul COEFL, DATAL ; Unsigned multiply, coefficient low byte and data low byte
mov AC0, r0 ; Mover result into accumulator byte 0:1
mov AC1, r1
mulsu COEFH, DATAL ; Signed-unsigned multiply, coefficient high byte and data low byte
add AC1, r0 ; Add low byte of result to accumulator byte 1
adc AC2, r1 ; Add with carry high byte of result to accumulator byte 2
mulsu DATAH, COEFL ; Signed-unsigned multiply, data high byte and coefficient low byte
add AC1, r0 ; Add low byte of result to accumulator byte 1
adc AC2, r1 ; Add with carry high byte of result to accumulator byte 2
ENDM
SMAC24 MACRO
muls COEFH, DATAH ; Signed multiply, coefficient high byte and data high byte
add AC2, r0 ; Copy low byte into accumulator byte 2
mul COEFL, DATAL ; Unsigned multiply, coefficient low byte and data low byte
add AC0, r0 ; Add low byte of result to accumulator byte 0
adc AC1, r1 ; Add with carry high byte of result to accumulator byte 1
adc AC2, ZERO ; Add carry to accumulator byte 2
mulsu COEFH, DATAL ; Signed-unsigned multiply, coefficient high byte and data low byte
add AC1, r0 ; Add low byte of result to accumulator byte 1
adc AC2, r1 ; Add with carry high byte of result to accumulator byte 2
mulsu DATAH, COEFL ; Signed-unsigned multiply, data high byte and coefficient low byte
add AC1, r0 ; Add low byte of result to accumulator byte 1
adc AC2, r1 ; Add with carry high byte of result to accumulator byte 2
ENDM
;*****************************************************
; FIR filter function
;*****************************************************
FIR2:
clr ZERO ; Clear ZERO register
movw ZL, FILTER_POINTER ; Move Struct pointer to the Z-pointer (r30:r31)
;B2*x[n-2]
LOAD_COEF B2
LOAD_NODE X2
MUL_MOV_24
;B1*x[n-1]
LOAD_COEF B1
LOAD_NODE X1
UPDATE_NODE X2
SMAC24
;B0*x[n]
LOAD_COEF B0
movw DATAL, NDATAL ; Load new sample into data multiply register
UPDATE_NODE X1
SMAC24
;Due to coefficient scaling (gain factor 2^12) the output requires "unscaling"
asr AC2 ; Scaling to gain factor 2^11
ror AC1 ; --
asr AC2 ; Scaling to gain factor 2^10
ror AC1 ; --
asr AC2 ; Scaling to gain factor 2^9
ror AC1 ; --
asr AC2 ; Scaling to gain factor 2^8
ror AC1 ; --
;Return the value stored in accumulator AC2 and AC1 (which are the return registers)
ret
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -