Using the 908JL16 Input Capture Feature to Measure Low Frequency Tones (e.g. 67.0 to 250.3 Hz)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Using the 908JL16 Input Capture Feature to Measure Low Frequency Tones (e.g. 67.0 to 250.3 Hz)

1,534 Views
joeburch
Contributor III

Hello folks,

 

I would like to ask another question on using the timer capabilities of the JL16 to measure these low frequency tones.

 

In reading the literature, it would appear that one method would be using the input capture capability.  Would someone be so good as to provide some high level advice as to how this might be accomplished by measuring the period?  In the case of a 250.3 Hz tone, the period is around 4 ms.

 

I guess that I'm somewhat confused about the input capture timing mechanism.

 

I've tried several approaches.  One was using one of the timers (TIM 2) to generate an interrupt every 100 ms and another TIM1 input compare interrupt to count the 'compares' generated every 100 millisecond interval.  After 10 TIM 2 interrupts, I thought I would end up with something close to the measured frequency.  It didn't work that well.

 

Thanks, in advance, for your help.

 

Joe Burch

Labels (1)
0 Kudos
13 Replies

882 Views
rocco
Senior Contributor II

Hi Joe,

 

First, just to be sure, are you squaring-up the tone with a input buffer with hysteresis (like a 7414 or a comparator)? I found the input capture to be unreliable for any signal with a slow rise/fall time.

 

OK, assuming you have a nice square wave that represents your tone, I would initialize the timer as follows:

1) Set the counter to free-run with its maximum (default 65,536) modulus,

2) Set the prescaler of the timer such that it overflows no faster than half of 67 hertz,

3) Set the input capture to trigger on either the rising or falling edge (it will not matter which), and

4) create a 16-bit variable which will be the "previous-capture time".

 

I would then have an ISR that:

1) Reads the captured-time from the capture register,

2) subtract the "previous-capture time" from it, to get a 16-bit "delta time", and

3) save the captured-time as the new "previous-capture time".

 

I would then, outside of the ISR, lookup the delta-time in a table to find the frequency. If you wished to save code space rather than time, you could simply take the reciprocal of the delta-time to calculate the frequency.

 

A table could just be a table of reciprocals, but if I were to use a table, I would put minimum and maximum delta-time values, with gaps in between, to reject out-of-bound frequencies.

 

Also, you may want to wait for multiple time samples to be sure they are consistent. I would not average them, as that would make the system susceptible to noise. What I would do it make sure some number of them, like 4 out of 5, are within the same "range" to qualify as a valid frequency.

0 Kudos

882 Views
joeburch
Contributor III

Hi Rocco,

 

Thanks for the suggestions.

 

The frequencies to be measured comes from the limiter of an FM radio and is already nicely 'squared up according to my scope.

 

I'm not really all that familiar with the timer.  So, if you don't mind, I'd like to ask a few questions about this method.

 

Setting the mod counter to the max 65536 is easy enough to do with FFFF.

 

You mentioned setting the prescaler so that the counter overflows no faster than the lowest frequency (67 Hz / 2).  With FFFF and a prescaler of 1, the counter will overflow every 27 ms (approx), with a prescaler of 2, every 13ms, and so forth. I just need the 'linkage' between the prescaler overflow and 37.5 Hz which has a period of 30 ms.  What am I missing??

 

Is this requirement needed to ensure that the subtractions come out properly??

 

The first 'previous capture time' will be stored.  The next capture time will be subtracted from it to get the 'delta time', and so forth.  So, what you're essentially doing is recording the length (period) of the unknown frequency.  I assume that I always subtract the smaller from the larger number??

 

If I can get this phase to work, I'm sure that I can build the required tables to finish up.

 

Thanks for your time and your patience.

 

Joe Burch

0 Kudos

882 Views
rocco
Senior Contributor II

 

Hi Joe,
It sounds like you are most of the way there with your understanding of this. To confirm the answers that you seem to have already come up with:

joeburch wrote:

Setting the mod counter to the max 65536 is easy enough to do with FFFF.

Yes. The reset value is FFFF, so you don't need to touch it at all.

 

You mentioned setting the prescaler so that the counter overflows no faster than the lowest frequency (67 Hz / 2).  With FFFF and a prescaler of 1, the counter will overflow every 27 ms (approx), with a prescaler of 2, every 13ms, and so forth. I just need the 'linkage' between the prescaler overflow and 37.5 Hz which has a period of 30 ms.  What am I missing??

The point of the 1/2 number is to have the counter never count more than half of the FFFF (past a maximum of 7FFF) such that the subtraction always results in a positive integer. This requirement isn't even necessary if no math is done on the period, as would be the case is you were just doing a table lookup.

 

Is this requirement needed to ensure that the subtractions come out properly??

Exactly. To be more specific, to ensure that the subtraction results in a positive integer. If you were to take the reciprocal to get the frequency, this would be a requirement. Again, a table would not require it.

 

The first 'previous capture time' will be stored.  The next capture time will be subtracted from it to get the 'delta time', and so forth.  So, what you're essentially doing is recording the length (period) of the unknown frequency.  I assume that I always subtract the smaller from the larger number??

Yes, you are measuring the tone's period. But you would always subtract the previous time value from the new time value. Look at it as subtracting the 'start' time of one cycle from the 'end' time of that same cycle. When the timer rolls-over, the new time value will be less than the previous time value, and the subtraction will 'underflow' (the 'V' bit set in the condition codes), but the result will still be the correct delta-time. You can look at it as there being an implied 'borrow' from a non-existent 17th bit.

 

If I can get this phase to work, I'm sure that I can build the required tables to finish up.

I'm confident that you can.

 


 

 

0 Kudos

882 Views
joeburch
Contributor III

Hi Rocco, Kef and others.

 

Thank you very much for your encouragement and suggestions.

 

I coded the program last nite and used CodeWarrior to step thru it and found some mistakes which I fixed.  There may be other bugs.  I programmed it with a prescaler value of 1 and TMOD set to FFFF, and set it up to report the results when two exact, consecutive 16 bit matches occurred.  And this happens in a second or two.

 

When I apply a 250.3 Hz. tone thru an interface (a commercial FM transceiver (that generates a nice clean, sharp pulse), I get a 'match' of  1338h (for example).  I don't know if this is correct or not.

 

If TMOD is set to FFFF, with a prescaler of 1, what is the 'weighting' (if any) of the numbers in the match.  Are they some function of the TMOD value??

 

What happens if TMOD is shortened and / or a different prescaler value applied??

 

I plan to build a data table based upon this that takes into consideration tone variations as these tones can vary as much as .5Hz in either direction.

 

Thanks,

 

Joe

0 Kudos

882 Views
rocco
Senior Contributor II

Hi Kef,

Your post got me thinking, and I decided that I need to write the reciprocal routine before I can answer with any certainty. Stay tuned.


Hi Joe,


joeburch wrote:

If TMOD is set to FFFF, with a prescaler of 1, what is the 'weighting' (if any) of the numbers in the match.  Are they some function of the TMOD value??

No, they are a function of the rate of counting. Specifically, it is the number of timer 'ticks' in the period on the wave.

 

What happens if TMOD is shortened and / or a different prescaler value applied??

If you change TMOD, then the subtraction will come up with the wrong result each time the timer rolls over.

 

If you increase the prescaler value, the timer will slow down (in powers of two) and the resulting period will be less. As an example, if you change the prescaler from 1 to 2, the 1338h you were getting should become 99Ch (which is half of 1338h, though it doesn't look it).


As far as whether that number is correct, it depends on your bus clock. The timer appears to be counting near 1.23mHz, which would be a bus clock of 2.46mHz. Is that really your bus clock? It seems slow to me, but I haven't used the JL16 before.

 

0 Kudos

882 Views
kef
Specialist I

Rocco,

 

It would be nice to see something wallbreaking, but for f(x)=1/x arguments from 0x100 to 0xFFFF, I think you can't avoid some loops and/or slow iterativave algorithm. I would like to be wrong.

 

 

Joe,

 

I think you mentioned in the thread about generating tones using PWM, that your 908JL16 is clocked from 9,8304 MHz crystal? If so, then bus clock should be 2457600Hz and 0x1338 timer ticks at 1:1 prescaler are giving 0x1338/Fbus, bit more than 2ms. Having capture set up for both edges, provided square wave is perfectly square and both edges are the same, provided JL16 rising edge threshold is perfectly is as far from VSS as the falling edge threshold is far from VDD, yes, 0x1338 ticks mean period is 2ms*2=~4ms and you are getting 249.8Hz. It makes sense to capture only one kind of edges, either rising or falling. It will eliminate requirement for exactly 50% duty cycle and difference between rising and falling edges. You will still fit timer overflow period, which is Fbus/65536= 37.5Hz

 

I doun't think you should keep sampling untill some timer ticks difference appears two or more times. Try summing differences for a while and taking average.

0 Kudos

882 Views
joeburch
Contributor III

Hi Rocco and Kef,

 

First of all, please let me thank you both for your help.  I was able to get the input capture routine up and running.  I included the code to take the averages, and thoroughly debugged the thing on CodeWarrior time and time again.  However, it didn't always work reliably.

 

So, I took a closer look at the pulses coming from the radio whose CTCSS frequency I was trying to determine.   At first, the pulses looked very clean and sharp.  I could measure their frequency with an external frequency counter.  However, there were very short duration downward 'spikes' when the pulse was in its high state.  I was unable to measure them on the scope (they were very hard to see) but they were apparently just long enough to activate the input capture feature of the JL16, providing erratic erroneous information.

 

Since this M/P is part of an amateur radio project that 'revitalizes' old commercial radios, it's not really worth the effort digging back into the radio's innards to determine (and then correct, if at all possible) the origination of these spikes.  Chances are, they are coming from the radio's own internal processor.

 

So, I tried a much less elegant approach of using the software to count the pulses over a period of a second using the timer overflow feature to provide the 'time base'.  Even with this approach, there were still occasional overcount errors caused by the spikes.  To solve this problem, I used a simple software timer set to 1 ms to determine if the polarity transition was 'real' or not.  Since these are signals with a relatively long period, this was a possible workaround.

 

While it's not what you would call a 'high tech' solution, and while it takes 2 seconds to compute (I scan twice just to be sure), it does work rather well.

 

Thanks again for all of your help and encouragement.

 

Joe Burch

 

 

0 Kudos

882 Views
kef
Specialist I

If I understood you, one or both edges are bouncing and producing some noise (maybe lack of hysteresis in squarifying comparator)? I probably would do noise removal this way:

 

  • when capture even occurs, remember capture value tcapt
  • reconfigure timer channel for output compare, without pin setting/clearing on compare match. Set compare register for tcapt + 1ms.
  • On output compare reconfigure timer for input capture
  • On next input capture take difference new capture minus old tcapt

With this approach you wouldn't have to ignore wrong timer capture differencies. After capture occurs, you can skip 1ms or more and start looking for next capture after bouncing cancels.

 

You should keep in mind that input capture isn't waiting while you service timer interrupt. On some MCU's it can be blocked until serviced, but not on JL16, I guess. If new edge (could be wrong one) comes before your read capture register, capture register will be overwritten with new captured timer counter value. The best would be to remove noise in hardware. But if you can't, then try making reading capture register very first task in your interrupt routine. Other interrupts also should be as short as possible, reducing interrupt latency and improving your time readings.

 

0 Kudos

882 Views
joeburch
Contributor III

Hi Kef,

 

Thanks for your suggestion.

 

It looks like these 'spikes' are very quick  and random, and are occurring several times within the pulse I'm trying to measure.  There's really no way to easily remove the interference from the radio.

 

But I'll keep this idea in mind when I try to optimize the code.

 

Joe

0 Kudos

882 Views
bigmac
Specialist III

Hello Joe,

 

For the CTCSS decode application, I would assume that the usual requirement is to test whether a selected tone frequency is present, or not, rather than the need to determine which of the multiplicity of available tone frequencies is present.  One exception to this might be a "talk-through" repeater application that may need to respond to more than one of the frequencies.

 

You will need to take into account that the demodulator output from the receiver will also contain voice (speech) components, in addition to the CTCSS tone, and higher frequency noise will also be present, particularly as the received signal weakens.  The CTCSS FM deviation level will usually be significantly lower than the peak speech deviation.

 

This will therefore require that the demodulator output signal be subject to significant low-pass filtering prior to being applied to a comparator, the output of which provides the input capture signal.  The filtering will need to be sufficient to reduce the speech and noise levels below the hysteresis level of the comparator, otherwise spurious transitions will occur.  The degree of filtering required will primarily depend on the maximum CTCSS frequency to be used, and the lowest frequency at which significant speech components occur.

 

If there are significant speech components at 300Hz, and the maximum required tone frequency is 250Hz, this would indeed require a very sharp filter.  However, if the transmission equipment does limit significant speech components to 500Hz and above, and you can avoid the use of the higher CTCSS frequencies, the filter requirements would become more moderate.  I would consider the minimum requirement to be a two-pole or four-pole active filter, maybe using the Sallen and Key configuration.  This filter will also reduce the effect of high frequency noise.

 

Regards,

Mac

 

0 Kudos

882 Views
kef
Specialist I
  • The point of the 1/2 number is to have the counter never count more than half of the FFFF (past a maximum of 7FFF) such that the subtraction always results in a positive integer. This requirement isn't even necessary if no math is done on the period, as would be the case is you were just doing a table lookup.

IMO sign of the difference is not required in this case, no need for "1/2". Unsigned short int difference of timer capture data should work.

0 Kudos

882 Views
rocco
Senior Contributor II

Hi Kef,

 

Keep in mind that Joe is not using C, but assembly language. So he would be depending on the DIV instruction. Although DIV is an unsigned divide, to take the reciprocal would require loading a dividend greater than the calculated cycle duration to be divided by that cycle duration. For instance, I might load $8000, which would represent 1.0, with an implied decimal point between bits 15 and 14. The cycle duration is then guaranteed to be smaller.

 

There are other ways to do it, but that seems (to me) to be the simplest.

0 Kudos

882 Views
kef
Specialist I

Joe could avoid divisions creating table of timer count differences for each used channel frequency and scan the table. (Binary search could improve speed if necesssary.)

 

But do you mean reciprocal of 16-15bits value can be easily calculated using single or two S08/HC08 DIV instructions? I think that reciprocal of 3-32767 and reciprocal of 3-65535 are equally hard to calculate on S08. Or are you suggesting to drop lower order bits of time difference to fit 0x80-0xFF and divide 0x8000 (one) by 0x81-0xFF? But that would give poor ~2Hz frequency resolution.

0 Kudos