lpc17xx frequency detection of square wave using polling

952 views Asked by At

I have to read 5 different frequencies(square wave) up to 20KHz by polling 5 different pins. Im using a single timer interrupt only,for every 1 millisecond. Polling of the pins would be done in the ISR.

The algorithm i have thought of so far is: 1.Count number of HIGH 2.Count number of LOW 3.Check if sum of HIGH+LOW=Time period. This algorithm seems slow and is not practical.

Is there any Filter functions that i could use to check the frequency at pin so that all i have to do would be to call that function? Any other algorithms, for frequency detection would be good.

I am restricted to only 1 interrupt in my code(timer interrupt)

1

There are 1 answers

5
Spektre On

you need to take in mind what are the input signal properties

  • as you are limited to just single interrupt (which is pretty odd)
  • and the timer has only 1 KHz
  • the input signal must not be above 0.5 KHz
  • if the signal is with noise the frequency can easily rise above that limit many times

speed

  • you wrote that the simple counting period approach is slow
  • what CPU and IO power have you?
  • I am used to Atmel AVR32 AT32UC3 chips which are 2 generation before ARM cortex chips
  • and I have around 96MIPS and 2-5 MHz pin R/W frequency there without DMA or interrupts
  • so what exactly is slow on that approach?

I would code it with your constrains like this (it is just C++ pseudo code not using your platform):

const int n=5;
volatile int T[n],t[n],s[n],r[n]; // T last measured period,t counter,s what edge is waitng for?
int T0[n]={?,?,?,...?}; // periods to compare with

void main() // main process
 {
 int i;
 for (i=0;i<n;i++) { T[i]=0; t[i]=0; s[i]=0; r[i]=0; }
 // config pins
 // config and start timer
 for (;;) // inf loop
  {
  for (i=0;i<n;i++)            // test all pins
   if (r[i]>=2)                 // ignore not fully measured pins
    {
    r[i]=2;
    if (abs(T[i]-T[0])>1)     // compare +/- 1T of timer can use even bigger number then 1
     // frequency of pin(i) is not as it should be
    }
  }
 }

void ISR_timer() // timer interrupt
 {
 // test_out_pin=H
 int i;
 bool p;
 for (i=0;i<n;i++)
  {
  p=get_pin_state(i);                                // just read pin as true/false H/L
  t[i]++;                                             // inc period counter
  if (s[i]==0){ if ( p) s[i]=1; }                   // edge L->H
  else         { if (!p) s[i]=0; T[i]=t[i]; t=0; r[i]++; } // edge H->L
  } 
 // test_out_pin=L
 }
  • you can also scan as comparation between last pin state and actual
  • that would eliminate the need of s[]
  • something like p0=p1; p1=get_pin_state(i); if ((p1)&&(p0!=p1)) { T[i]=t[i]; t[i]=0; }
  • this way you can also more easily implement SW glitch filters
  • but I think he MCU should have HW filters too (like most MCU does)

How would I do this without your odd constraints?

  • I would use external interrupt
  • usually they can be configured to be trigger on specific edge of signal
  • also including the HW filtering of noise
  • on each interrupt take the internal CPU clock counter value
  • and if it is not at disposal then timer/counter state
  • substract with the last measured one
  • restore from overflow if occured
  • change to s or Hz if needed
  • this way I can scan pins on MCU with 30MHz clock reliably with frequency up to 15MHz (use this for IRC decoder)
  • and yes IRC can give you above 1 MHz frequencies on occasions (on edge between states)
  • if you want the ratio also the you can:
  • have 2 interrupts one for positive and second for negative edge
  • or use just one and reconfigure the edge after each hit (Atmel UC3L chips I used some time ago had problem with this one due to internal bugs)

[notes]

  • it is essential that the pins you accessing are at the same IO port
  • so you can read them all at once and then just decode the pins after
  • also the GPIO module is usually configurable so check what clock is it powered with
  • there are usually 2 clocks one for interfacing the GPIO module with CPU core
  • and the second for the GPIO itself so check both
  • you can also use DMA instead of external interrupt
  • if you can configure to read the IO port by DMA ... to memory somewhere
  • then you can inspect on the background process independent to IO