/*
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);
}
}
///////////////////////////////////////////////////////////////////////////
Comments
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
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