Shop OBEX P1 Docs P2 Docs Learn Events
Demo: IIR filter with o-scope output — Parallax Forums

Demo: IIR filter with o-scope output

ReinhardReinhard Posts: 489
edited 2011-12-16 00:47 in Propeller 1
/*
    Demonstrate an IIR Filter (Highpass) with fixed point arithmetic in pure C
    
    Signal out on P0 via RC Lowpass ; R = 470 Ohm  C = 1µF
    Can observed with osci ( 0.5 V/Div  10ms/Div )
    
    shows alternate the input test signal and the filtered output
    on 1 osci channel
    
    Testinput Signal is generated per programm (Square puls)
    
    IIR Highpass 1. Order
    
    y[0]   = A[0] * x[0] + A[1] * x[1]  - B[1] * y[1];
    out    = B[0] * y[0];
    
    compile : propeller-elf-gcc -mlmm -Os -o IIR.elf  main.c 
    --------------------------------------------------------------------------
*/

#include <stdio.h>
#include <stdlib.h>
#include <propeller.h>
#include "fixed.h"

#define N 100
#define q 14
#define STACKSIZE 20


static int samples[N];     // the test input signal
int PWM;
static int cog_stack[STACKSIZE];

void Task_PWM_Pin0 ();
void start_lmm(void *func, int *stack_top);
void msleep(int t);
void input();
void filter ();

///////////////////////////////////////////////////////////////////////////
int main()
{
  int n;                         // common used index  
  
  for(n=0;n<N;n++)                // Setup the test signal
   samples[n] = TOFIX(0.0,q);
  for(n=N/4;n<=N/2;n++)  
   samples[n] = TOFIX(1.0,q);

  start_lmm(Task_PWM_Pin0, cog_stack + STACKSIZE);
   
  while(1)
  {

    input();        // show the input signal on osci
    msleep(10);
    filter();        // show the filtered signal on osci
    msleep(10);
  }   


  return 0;    
}
///////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////
void Task_PWM_Pin0 ()
{
    int t;
    int tInc = CLKFREQ/1000000;
    int tC = 100 * tInc;

    CTRA = (1<<28) + 0;
    FRQA = 1;
    DIRA |= (1 << 0);
    
    t = CNT;
    
    while(1)
    {
        PHSA = - PWM * tInc;
        t += tC;
        waitcnt(t);
    }
    
    

}

///////////////////////////////////////////////////////////////////////////
void start_lmm(void *func, int *stack_top)
{
    extern unsigned int _load_start_kernel[];

    /* push the code address onto the stack */
    --stack_top;
    *stack_top = (int)func;

    /* now start the kernel */
    cognew(_load_start_kernel, stack_top);
}

///////////////////////////////////////////////////////////////////////////
void msleep(int t)
{
    waitcnt((CLKFREQ/1000)*t+CNT);
}
///////////////////////////////////////////////////////////////////////////
void input()
{
    int n;
    for(n=0;n<N;n++)
    {
      PWM = 50 + (samples[n]/320);
      msleep(1);    
    }
}

///////////////////////////////////////////////////////////////////////////
void filter ()
{
  int n;               // common used index  
  int T1,T2,T3,T4;     // Help Terms     
  int out;             // the filter output  
  int A[2];            // Forward Coefficients
  int B[2];            // Reverse Coefficients
  int x[2];            // Forward stage
  int y[2];            // Reverse stage  

  A[0] = TOFIX(0.9695,q);        // Setup Filter
  A[1] = TOFIX(-0.9695,q);        // Set Coefficients
  B[0] = TOFIX(1.0,q);
  B[1] = TOFIX(-0.9391,q);
 
  x[0] = 0;
  x[1] = 0;
  
  y[0] = 0;
  y[1] = 0;  

  for(n=0;n<N;n++)     // Filter Loop
  {
    x[0]   = samples[n];
    T1 = FMUL(B[1],y[1],q);
    T2 = FMUL(A[1],x[1],q);
    T3 = FMUL(A[0],x[0],q);
    T4 = FADD(T3,T2);
    y[0] = FSUB(T4,T1);
    out = FMUL(B[0],y[0],q);
    x[1]   = x[0];
    y[1]   = y[0]; 

    PWM = 50 + (out/320);
    msleep(1);
    //printf("%d   %f   %f  %d\n",n,TOFLT(samples[n],q),TOFLT(out,q),out);
           
   }
       
}
///////////////////////////////////////////////////////////////////////////

h
h
1K
c
c
4K

Comments

  • ersmithersmith Posts: 6,099
    edited 2011-12-15 17:15
    Another cool demo. Thanks, Reinhard!

    A tip: you can replace your start_lmm function with _start_cog_thread, as documented in the Library.html file in the doc/ directory. It does pretty much the same thing as start_lmm, but also adds a parameter to the function you are starting, and a library state so that the new thread can use "errno", "gmtime", and other C library features that require internal storage. Or you can use pthreads, which are even higher level and also work in XMM mode (though there they have to run on the same cog).

    Eric
  • ReinhardReinhard Posts: 489
    edited 2011-12-16 00:47
    Thanks for the tip about the thread functions, Eric !

    I'll do it.
    The things to do with the combination propeller and propgcc with small effort are simple infinit.
    (If I had an infinit amount of time :-)

    Reinhard
Sign In or Register to comment.