📄 2nd_order_iir.s90
字号:
;*****************************************************
;* File: 2nd_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:
;* 2nd order IIR filter.
;* 10-bit signed data.
;* 12-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 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, B0, B1, B2, A1, A2};
;*
;* 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 12-bit resolution (max)
;*
;* Registers usage:
;* r0-4, r16-23, Z (all scratch/volatile registers)
;*
;* Memory usage for variables and constants:
;* 8 bytes SRAM for filter nodes (filter memory)
;* 10 bytes SRAM for filter coefficients
;*
;* Stats:
;* INIT: Depending on compiler settings (223 cycles)
;* FILTER: 92 instructions; 116 cycles (excl. ret)
;*****************************************************
NAME assembly(16)
PUBLIC IIR2
RSEG CODE
;ZERO register (used to add carry flag)
#define ZERO r2
;Accumulator - 24bit
#define AC0 r3
#define AC1 r16
#define AC2 r17
;New data sample
#define NDATAL r18
#define NDATAH r19
;Data sample multiply registers (used in multiplication)
#define DATAL r20
#define DATAH r21
;Filter coefficient (used in multiplication)
#define COEFL r22
#define COEFH r23
; Filter nodes offset (relatively to the filter struct)
#define X1 0*2
#define X2 1*2
#define Y1 2*2
#define Y2 3*2
;Filter coefficients offset (relatively to the filter struct)
#define B0 4*2
#define B1 5*2
#define B2 6*2
#define A1 7*2
#define A2 8*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
;*****************************************************
; IIR FILTER function
;*****************************************************
IIR2:
clr ZERO ; Clear ZERO register
movw ZL, r16 ; 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
;A2*y[n-2]
LOAD_COEF A2
LOAD_NODE Y2
SMAC24
;A1*y[n-1]
LOAD_COEF A1
LOAD_NODE Y1
UPDATE_NODE Y2
SMAC24
;Due to coefficient scaling (gain factor 2^11) the output requires "unscaling"
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 ; --
;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, AC1 ; Update low byte of y[n-1] node to prepare next filter run
std Z+Y1+1, AC2 ; Update high byte of y[n-1] node to prepare next filter run
;Return value stored in accumulator AC2 and AC1
ret
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -