3
votes

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.

2
Lots of short forms are used. And the question is not clear!Anand Gupta
Did you enable the FPU? 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. Also, check alignment for ADC (and DAC?). 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 and use the ADC-interrupt to read the data, that's what the STM has its variable trigger options for. Also: did you check the timing for interrupt overflows?too honest for this site
You can do easy profiling using the DWT module (need the ARM architecture reference manual - for free but with registration).too honest for this site
Thanks @Olaf, it was only the problem of alignment. Everything was right. It was just that i had taken the output from the wrong side of the Output array. Once I took it from the other end, the problem was solved. Thanks a lot. Also i introduced the timer triggered conversations. That was a lot of help from you. Again, thanks a lot.user11622
I made that an answer and hope you will honor this accordingly. Oh, and I added some more hints.too honest for this site

2 Answers

1
votes

Some possible problems:

  • Did you enable the FPU?
  • Check alignment for ADC (and DAC?).
  • Ensure the interrupt-handler does not run too long (overflow).

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?

0
votes

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.