📄 8th_order_fir.s90
字号:
;*****************************************************
;* File: 8th_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:
;* 8th order FIR filter.
;* 10-bit signed data.
;* 16-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-0), x(n-1), ..., x(n-8)
;* int filterCoefficients[(FILTER_ORDER)+1]; //filter coefficients B0, B1, B2, ..., B8
;* } myFilter = {0,0,0,0,0,0,0,0,
B0,B1,B2,B3,B4,B5,B6,B7,B8};
;*
;* 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 16-bit resolution (max)
;*
;* Registers usage:
;* r0-4, r16-23, Z (all scratch/volatile registers)
;* r14-r15 (stored and restored as required)
;*
;* Memory usage for variables and constants:
;* 16 bytes SRAM for filter nodes (filter memory)
;* 18 bytes SRAM for filter coefficients
;*
;* Stats:
;* INIT: Depending on compiler settings (399 cycles)
;* FILTER: 220 instructions; 317 cycles (excl. ret)
;*****************************************************
NAME assembly(16)
PUBLIC FIR8
RSEG CODE
;ZERO register (used to add carry flag)
#define ZERO r2
#define ZL R30
#define SW_STACK Y
;Accumulator - 32bit
#define AC3 r14
#define AC2 r15
#define AC1 r16
#define AC0 r17
;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
#define X3 2*2
#define X4 3*2
#define X5 4*2
#define X6 5*2
#define X7 6*2
#define X8 7*2
;Filter coefficient offset relative to filter struct address
#define B0 8*2
#define B1 9*2
#define B2 10*2
#define B3 11*2
#define B4 12*2
#define B5 13*2
#define B6 14*2
#define B7 15*2
#define B8 16*2
;**************************************************
;* MACROS
;**************************************************
STORE_REGISTER MACRO
st -Y, AC3
st -Y, AC2
ENDM
RESTORE_REGISTER MACRO
ld AC2, Y+
ld AC3, Y+
ENDM
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_32 MACRO
muls COEFH, DATAH ; Signed multiply, coefficient high byte and data high byte
movw AC3, r0 ; Copy result word into accumulator byte 2:3
mul COEFL, DATAL ; Unsigned multiply, coefficient low byte and data low byte
movw AC1, r0 ; Copy result word into accumulator byte 2:3
mulsu COEFH, DATAL ; Signed-unsigned multiply, coefficient high byte and data low byte
sbc AC3, ZERO ; Sign extention
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
adc AC3, ZERO ; Add carry to accumulator byte 3
mulsu DATAH, COEFL ; Signed-unsigned multiply, data high byte and coefficient low byte
sbc AC3, ZERO ; Sign extention
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
adc AC3, ZERO ; Add carry to accumulator byte 3
ENDM
;SMAC32:
SMAC32 MACRO
muls COEFH, DATAH ; Signed multiply, coefficient high byte and data high byte
add AC2, r0 ; Add low byte of result to accumulator byte 2
adc AC3, r1 ; Add with carry high byte of result to accumulator byte 3
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
adc AC3, ZERO ; Add carry to accumulator byte 3
mulsu COEFH, DATAL ; Signed-unsigned multiply, coefficient high byte and data low byte
sbc AC3, ZERO ; Sign extention
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
adc AC3, ZERO ; Add carry to accumulator byte 3
mulsu DATAH, COEFL ; Signed-unsigned multiply, data high byte and coefficient low byte
sbc AC3, ZERO ; Sign extention
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
adc AC3, ZERO ; Add carry to accumulator byte 3
; ret
ENDM
;*****************************************************
; FIR filter function
;*****************************************************
FIR8:
clr ZERO ; Clear ZERO register
movw ZL, FILTER_POINTER ; Move Struct pointer to the Z-pointer (r30:r31)
STORE_REGISTER
;B8*x[n-8]
LOAD_COEF B8
LOAD_NODE X8
MUL_MOV_32
;B7*x[n-7]
LOAD_COEF B7
LOAD_NODE X7
UPDATE_NODE X8
SMAC32
; rcall SMAC32
;B6*x[n-6]
LOAD_COEF B6
LOAD_NODE X6
UPDATE_NODE X7
SMAC32
; rcall SMAC32
;B5*x[n-5]
LOAD_COEF B5
LOAD_NODE X5
UPDATE_NODE X6
SMAC32
; rcall SMAC32
;B4*x[n-4]
LOAD_COEF B4
LOAD_NODE X4
UPDATE_NODE X5
SMAC32
; rcall SMAC32
;B3*x[n-3]
LOAD_COEF B3
LOAD_NODE X3
UPDATE_NODE X4
SMAC32
; rcall SMAC32
;B2*x[n-2]
LOAD_COEF B2
LOAD_NODE X2
UPDATE_NODE X3
SMAC32
; rcall SMAC32
;B1*x[n-1]
LOAD_COEF B1
LOAD_NODE X1
UPDATE_NODE X2
SMAC32
; rcall SMAC32
;B0*x[n]
LOAD_COEF B0
movw DATAL, NDATAL ; Load new sample into data multiply register
UPDATE_NODE X1
SMAC32
; rcall SMAC32
;Due to coefficient scaling (gain factor 2^15) the output requires "unscaling"
lsl AC1 ; Scaling to gain factor 2^16
rol AC2 ; --
rol AC3 ; --
mov AC1,AC2 ; Scaling to gain factor 2^0
mov AC2,AC3 ; --
;Return the value stored in accumulator AC2 and AC1 (which are the return registers)
RESTORE_REGISTER
ret
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -