📄 6th_order_iir.s90
字号:
;*****************************************************
;* File: 6th_order_IIR.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:
;* 6th order IIR filter.
;* 10-bit signed data.
;* 15-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 IIR_filter(*myFilter, newDataSample);
;*
;* The structure for the filter nodes and filter coefficients should be
;* as follows:
;*
;* struct IIR_filter{
;* int filterNodesX[FILTER_ORDER]; //memory nodes required to store x(n-1), x(n-2), ...
;* int filterNodesY[FILTER_ORDER]; //memory nodes required to store y(n-1), y(n-2), ...
;* int filterCoefficientsB[(FILTER_ORDER)+1]; //filter coefficients B0, B1, B2, ...
;* int filterCoefficientsA[FILTER_ORDER]; //filter coefficients A1, A2, ...
;* } myFilter = {0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
B0, B1, B2, B3, B4, B5, B6,
A1, A2, A3, A4, A5, A6};
;*
;* 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 15-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:
;* 24 bytes SRAM for filter nodes (filter memory)
;* 26 bytes SRAM for filter coefficients
;*
;* Stats:
;* INIT: Depending on compiler settings (575 cycles)
;* FILTER: 317 instructions; 449 cycles (excl. ret)
;*****************************************************
NAME assembly(16)
PUBLIC IIR6
RSEG CODE
;ZERO register (used to add carry flag)
#define ZERO r2
#define ZL R30
#define SW_STACK Y
;Accumulator - 32bit
#define AC3 r15
#define AC2 r16
#define AC1 r14
#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 Y1 6*2
#define Y2 7*2
#define Y3 8*2
#define Y4 9*2
#define Y5 10*2
#define Y6 11*2
;Filter coefficient offset relative to filter struct address
#define B0 12*2
#define B1 13*2
#define B2 14*2
#define B3 15*2
#define B4 16*2
#define B5 17*2
#define B6 18*2
#define A1 19*2
#define A2 20*2
#define A3 21*2
#define A4 22*2
#define A5 23*2
#define A6 24*2
;**************************************************
;* MACROS
;**************************************************
STORE_REGISTERS MACRO
st -Y, AC3
st -Y, AC1
ENDM
RESTORE_REGISTERS MACRO
ld AC1, 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
mov AC2, r0 ; Copy result word into accumulator byte 2:3
mov AC3, r1 ; Copy result word into accumulator byte 2:3
mul COEFL, DATAL ; Unsigned multiply, coefficient low byte and data low byte
mov AC0, r0 ; Copy result word into accumulator byte 2:3
mov AC1, r1 ; 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
;*****************************************************
; IIR FILTER function
;*****************************************************
IIR6:
STORE_REGISTERS ; Save registers that must be preserved accross function call
clr ZERO ; Clear ZERO register
movw ZL, r16 ; Move Struct pointer to the Z-pointer (r30:r31)
;B6*x[n-6]
LOAD_COEF B6
LOAD_NODE X6
MUL_MOV_32
;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 X2
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
;A6*y[n-6]
LOAD_COEF A6
LOAD_NODE Y6
SMAC32
; rcall SMAC32
;A5*y[n-5]
LOAD_COEF A5
LOAD_NODE Y5
UPDATE_NODE X6
SMAC32
; rcall SMAC32
;A4*y[n-4]
LOAD_COEF A4
LOAD_NODE Y4
UPDATE_NODE X5
SMAC32
; rcall SMAC32
;A3*y[n-3]
LOAD_COEF A3
LOAD_NODE Y3
UPDATE_NODE X4
SMAC32
; rcall SMAC32
;A2*y[n-2]
LOAD_COEF A2
LOAD_NODE Y2
UPDATE_NODE X3
SMAC32
; rcall SMAC32
;A1*y[n-1]
LOAD_COEF A1
LOAD_NODE Y1
UPDATE_NODE Y2
SMAC32
; rcall SMAC32
;Due to coefficient scaling (gain factor 2^14) the output requires "unscaling"
lsl AC1 ; Scaling to gain factor 2^15
rol AC2 ; --
rol AC3 ; --
lsl AC1 ; Scaling to gain factor 2^16
rol AC2 ; --
rol AC3 ; --
;Updating y[n-1] node
;(By copying result from AC1:2 instead of AC0:1 the gain factor becomes 1 (2^0))
std Z+Y1, AC2 ; Update low byte of y[n-1] node to prepare next filter run
std Z+Y1+1, AC3 ; Update high byte of y[n-1] node to prepare next filter run
;Restore registers and return (return value stored in accumulator AC2 and AC1, which are the return registers)
RESTORE_REGISTERS ; Save registers that must be preserved accross function call
ret
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -