frequency measurement with interrupts

Hi all,

i think the topic of frequency measurement should have come up on quite a few projects so instead of bumping to the same errors i thought to ask your ideas on the subject.

The setup is that i've got the mega board for measurement purposes, it is supposed to measure multiple channels of voltages and some frequency data also.

my initial idea was to setup the freq measurement so that the signal would following:

The frequency measurement is done by assigning interrupt to a IO and then increasing a counter every time the IRQ triggers. then with a timer interrupt on even intervals the counter is translated to frequency and reset to zero.

So the following algorithm might be used for freq calculation

counter is increased by an interupt set on a digital pin. so counter++ basicly.

the timer2 dividers are set to the max of 1024 on the AVR. this would mean that the timer overflow interupt hits on 15.625kHz frequency. This would make one timer interrupt every 0.064ms. This will effectively limit the low level resolution of the system to a certain level.

If we count 100 timer interrupts we get 64ms intervals, to get the frequency we would then need to do following

// f = 1 / s

freq = counter / 0.064;

now floating calculations are notoriously slow on the embedded devices however dividing by 0.064 we are actually multiplying the counter by a factor of 15.625 which is relatively close to 16. multiplying with 16 is a very low cost operation indeed so we might be able to safely state that

freq = counter << 4;

This would result on 2.4% error on the value that might be in the limits of acceptable.

note that this implementation would be very specific to the freq ranges i'm looking at.

any comments?

oh, put this in the wrong subforum, admins can you move this to the sw side?

Maybe i misread but it would be better to time some whole number of waves rather than count waves in a specific interval.

yep that might be feasible too, the whole reason behind this complexity is that i don't want to spend much time in the interrupt handler since with high frequencies that is called quite often.

My aim was to generate a system that has fairly standard cost for measuring highish frequency which would not be (much) affected by the actual frequency.

for low freqs i was planing to use time between pulses but your idea of calculating a number of pulses is nice improvement, thanks for that. :slight_smile:

have you seen this thread: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231326297/0

i briefly glanced that way, it had some while( something is done ) looping on it but i must confess that didn't dig that much deeper in it.

i've got a case where i want to constantly monitor 5-8 channels of data and would not like to stall to wait for any channel. if the freq lib does that then all the better, won't have to do everything from the scratch :slight_smile:

what are the highest and lowest frequencies that you want to measure and how much deviation will there be on any channel?

the two channels that i currently know are 400-5000hz and 1khz-16khz.

is there a good way to profile how much cpu time is spend on certain stuff? I could try multiple different methods and run each for a period and just have a counter on the main loop and see which one counts the farthest.

For this kind of thing, a logic analyzer or oscilloscope would be handy. But as long as your application has enough time to do whatever it needs to do while taking the frequency measurements then you may not need to optimize.

How fast will the frequencies change (i.e. what is the minimum acceptable time between measurements) ?

i think i would be happy with a <100ms resolution on the higher freq band.

Might be that i'm optimizing the hell out of everything for no reason what so ever. Should do some calculations.

Might be that i'm optimizing the hell out of everything for no reason what so ever. Should do some calculations.

well worth doing - it may be feasible to use pulseIn if you only need to sample each channel 10 times per second.

i'd like to be able to read all channels atleast 10/sec, is pulseIn async? i think it might just wait until timeout.

on voltage side
also trying to think ways to make linear interpolation from the ad value via translation table to real value as fast as possible.

for example if i have a sensor that lets say at 0v = 10 C and 1V = 20C , 2V = 40C , 4V = 60C and 5V = 80C

the traditional way i guess is to just to see between which reference values you'd land with the ad value and then interpolate the output from there by calculating the slope and multiplying by the distance.

i was thinking about pre calculating the slopes to a array and using binary search to find the correct index which would make the interpolation algorithm worst case somewhere around 1/2N

if there was bit more sdram i'd rather just run the interpolation first and then use the ad value as a pointer for that table but 4k aint much.

another idea is to just cache part of that table in ram and extend it once it gets hit ..

Yes its async but does that really matter. If all 8 channels where pulsing at the slowest rate (400Hz) it should only take 20 milliseconds to measure them all. So worst case, for your ten measurements per channel per second you would have 80% CPU time available to do other things. In my view, no point in complicating your code if you don't need to.

As to linear interpolation, I also suggest initially using the simplest approach (probably a floating point multiply if its linear) and worry about optimizing only if you need to.

ok.

At this point it looks like i'll have 3 freq channels with not too tight resolution limits and 4-5 analog channels with much tighter limits eg. 18ms for all so lets see :slight_smile: