cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 real time FIR filter from ADC samples

Ruggero Still
Associate II
Posted on March 10, 2018 at 21:40

Hello,

I have a Nucleo-L476RG board and I'm trying to make a lowpass filter with the FIR function (using cmsis libraries) to filter the samples I get from the ADC in realtime.

Then I'd like to get the processed signal out through the DAC.

Both ADC and DAC work at a sampling frequency of 20khz, triggered by two (tim6 and tim7) timers. They use DMA.

FIR function is called every time the ADC ends a conversion.

I'm using arrays of 1 element as buffers, so the number of blocks of the FIR function is 1.

I can get a signal on the output, but it does not match what the input signal processed through the filter would be.

Thank you very much for your help. I hope my explanation is good enough.

Here is my code:

#include <math.h>

#include 'arm_math.h'

uint32_t adcValue[1];

uint32_t adcValue1[1];

int i;

float32_t signal_in = 0;

float32_t signal_out = 0;

#define TEST_LENGTH_SAMPLES  1

#define BLOCK_SIZE            1

#define NUM_TAPS              29

arm_fir_instance_f32 S;

static float32_t firStateF32[BLOCK_SIZE + NUM_TAPS - 1];

static float32_t firCoeffs[NUM_TAPS] = {-0.0018225230f, -0.0015879294f, +0.0000000000f, +0.0036977508f, +0.0080754303f,

    +0.0085302217f, -0.0000000000f, -0.0173976984f, -0.0341458607f, -0.0333591565f,

    +0.0000000000f, +0.0676308395f, +0.1522061835f, +0.2229246956f, +0.2504960933f,

    +0.2229246956f, +0.1522061835f, +0.0676308395f, +0.0000000000f, -0.0333591565f,

    -0.0341458607f, -0.0173976984f, -0.0000000000f, +0.0085302217f, +0.0080754303f,

    +0.0036977508f, +0.0000000000f, -0.0015879294f, -0.0018225230f};

uint32_t blockSize = BLOCK_SIZE;

uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE;

void SystemClock_Config(void);

int main(void)

{

  HAL_Init();

  /* Configure the system clock */

  SystemClock_Config();

  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  MX_DMA_Init();

  MX_DAC1_Init();

  MX_TIM6_Init();

  MX_ADC1_Init();

  MX_TIM7_Init();

  MX_ADC2_Init();

  //Timers

  HAL_TIM_Base_Start(&htim6);

  HAL_TIM_Base_Start(&htim7);

  //ADC Start

  HAL_ADC_Start_DMA(&hadc1, adcValue, 1 );

 

  //DAC Start

  HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);    

  HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (uint32_t*)adcValue1, 1, DAC_ALIGN_12B_R);

  //FIR Init

  arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs[0], (float32_t *)&firStateF32[0], blockSize);

 

  /* Infinite loop */

 

   while (1)

   {

 

   }

 

}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

{

    if(hadc->Instance == ADC1)

    {

            signal_in = (float32_t)adcValue[0];

            arm_fir_f32(&S, &signal_in, &signal_out, blockSize);

            adcValue1[0] = (uint32_t)signal_out; //signal_out;

    }

}
4 REPLIES 4
Ruggero Still
Associate II
Posted on March 13, 2018 at 10:17

Problem solved! The code is 100% right. I figured out that I swapped some pins in STM32CubeMX and so I was not putting my probe on the DAC output!

AvaTar
Lead
Posted on March 13, 2018 at 10:32

static float32_t firCoeffs[NUM_TAPS] = {-0.0018225230f, -0.0015879294f, +0.0000000000f ...

Just for the books - I think your floating point number precision is a bit excessive.

Single precision does not carry that much digits.

Posted on March 13, 2018 at 15:43

Yes, you are totally right. In fact I got the filter computed by a website that outputs the coefficients as 'double' type. I just forgot that, many thanks!

David Pekin
Senior
Posted on April 17, 2018 at 22:42

Hello,  I just started looking at the CubeMX FIR filters.  I too need to filter an ADC reading but I need a notch type filter. 

I'm updating a PID loop at approximately 4Khz.  Some system resonances are present in the ADC reading that I need to filter out.  These resonances are around 80hz.   I figured I could use a LP and HP filter to achieve a 80 hz notch filter.  But I've got a number of questions.

I see you set the block size to 1 so you filter each sample as it's taken.  That's what I need to do as well  Apparently the filter state structure keeps track of the prior N samples and is able to filter using that past data, right?

For a notch filter can I just feed the output of the LP filter into the HP filter?  That doesn't sound right since the output from the LP would not have the high frequency component.  Or should I take the original ADC reading and feed that into both a LP and a HP filters and then add the 2 outputs?   I'm uncertain on the correct approach.  

The FIR example shows how to build a LP filter by getting MATLAB to generate the coefficients by calling the fir1() MATLAB function.  How do I configure a HP filter?   

Thanks for any pointers on this!