Reputation: 39
I am designing an IIR 2nd order Lowpass filter with sampling frequency = 100Hz and cutoff frequency = 10 Hz. The filter coefficients are of Chebyshev Type I using fdatool in Matlab. But the code is not able to filter the signal (i.e. for all frequencies it gives the output with same amplitudes as the input signal) . Only minor decrease in amplitude is observed for an input signal of 10 KHz and above. I assure you that the ADC and DAC are working fine as i have tested the for FFT filter.
Here is the code:
/* Include core modules */
#include "stm32f4xx.h"
#include "stdint.h"
#include "stdlib.h"
#include "arm_math.h"
#include "my_files.h"
#define URS 2
#define numStages 1
#define NUM_TAPS 5*numStages
#define samples 3
////////ADC FUNCTION//////////////////
void ADC_configure(void)
{
RCC->APB2ENR|=1Ul<<8; // ADC1 clock enabled
ADC1->CR2|=0x00000001; // enable ADC
ADC1->CR1|=0; // single conversion ADC1 pin 0 has been selected
}
int32_t readADC(void)
{
ADC1->CR2|=(1UL<<30);
return(ADC1->DR);
}
////////DAC FUNCTION/////////////////
int32_t dv1,dv2,ds;
//---function declaration--//
// initilising DAC---------//
void DAC_init(void)
{
RCC->APB1ENR|=1UL<<29;
DAC->CR|=((1UL<<16)|(1UL<<0));
RCC->AHB1ENR|=0x00000001; // clock to gpio A
GPIOA->MODER|=0x00000F03; // pt0,4,5 in Analog mode
}
// Sending to DAC...........//
void Send_DAC(int32_t data_in1, int32_t data_in2)
{ dv1=data_in1;
dv2=data_in2<<16;
ds=dv2+dv1;
DAC->DHR12RD=ds;
}
/* IIR settings */
float32_t pState[2*numStages];
const float pCoeffs[NUM_TAPS] = {1,2,1,-1.1997,0.5157};//{b0,b1,b2,a1,a2}
/* Global variables */
float32_t Input[samples]; /* Data to be read from ADC */
float32_t InputData[samples]; /* Data to be processed */
float32_t Output[samples]; /* Output filtered Data */
arm_biquad_cascade_df2T_instance_f32 S; /* ARM IIR module */
uint16_t i;
void TIM3_Init (void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; /* enable clock for TIM1 */
TIM3->PSC = 8600; /* set prescaler = 10KHz */
TIM3->ARR = 100; /* set auto-reload = 10ms */
TIM3->RCR = 0; /* set repetition counter */
TIM3->CR1 |= (1UL << URS);
TIM3->DIER = TIM_DIER_UIE; /* Update Interrupt enable */
NVIC_EnableIRQ(TIM3_IRQn); /* TIM1 Interrupt enable */
NVIC_SetPriority (TIM3_IRQn, 0);
TIM3->CR1 |= TIM_CR1_CEN; /* timer enable */
}
void TIM3_IRQHandler() {
/*Shift Operation*/
for(i=samples-1;i>0;i--){
Input[i]= Input[i-1];
InputData[i]= Input[i];
}
/* Input part from the ADC */
Input[0] = (float32_t)readADC();
InputData[0] = Input[0];
//////////IIR//////////////////////
/* Initialize the IIR module */
arm_biquad_cascade_df2T_init_f32(&S, numStages, pCoeffs, pState);
/* Process the data through the IIR module */
arm_biquad_cascade_df2T_f32(&S, InputData, Output, samples);
////////DAC Output/////////////////
Send_DAC(Input[0], Output[0]);
}
/////////main function///////////////
int main(void) {
/* Initialize system */
SystemInit();
DAC_init();
ADC_configure();
TIM3_Init();
while (1) {
}
}
Any suggestion or solution would be of great help.
Upvotes: 3
Views: 2938
Reputation: 16
You do not need to init IIR filter every time. Do it only once in init code. Init procedure clears previous values in pState, but they are required for IIR to perform correctly. That's the reason why your filter doesn't work. Presence of FPU only influences the speed of computation.
Upvotes: 0
Reputation: 12263
Some possible problems:
Good you do not use the stdlib for much more tha init, btw. But you really should use symbolic constants for the register initialization! This does not cost extra.
Not directly related, but will(!) give wrong results: If I get it right, you trigger each conversion in readADC. This leads to jitter (resulting in noise on the digitized signal); trigger the conversations by a timer (that's what the trigger system is for actually) and use the ADC-interrupt to read the data or use a DMA (the STM DMA provides a double-buffer mode which is perfect for this). In this simple example, if using DMA, you can even get along completely without interrupt and do the calculations in the main program.
For the DAC you should the same.
Not sure why use a timer anyway; the ADC can self-trigger. Is that not sufficient?
Upvotes: 1