circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

June 2005, Issue 179

Precision Frequency Meter
Cypress PSoC High Integration Challenge 2004 Contest Winner


SOFTWARE ESSENTIALS

I wrote most of the code in C language. I used some in-line assembler code to improve the overall execution speed and software size. Data memory conservation was a major problem. Because of the depth of function calls and ISRs, I had to leave a reasonable amount of RAM for the stack.

The software operates a number of threads implemented as switch statements. The main routine loops through these threads in an appropriate manner for the operation mode.

The timing subsystem contains routines to maintain the synchronization data and calculate the current time from it. A reference count register holds the clock counts value at a known hour. The current time can be calculated by subtracting this reference from the current clock count. There’s also a clock rate register, which holds the number of reference clocks that have occurred over a number of hours and is used for frequency calculations. It’s calculated by subtracting the last reference count from a new reference count. The reference clocks count and the number of hours are then added to the clock rate count and hour registers. This continues for up to 232 h, at which point 32 h are removed from the clock rate registers and the hours count (to keep it to a single byte variable).

Earlier in the development process, the clock rate was based on only the last two clock references. But I found that the system would occasionally reference onto the wrong pulse of the time pips and therefore would be off by a few milliseconds. Accumulating the reference clock counts and hours averages out these abnormalities.

Before full synchronization has completed (which takes two time pip signals), the calibration registers are preset to default values based on the nominal clock frequency. The display shows smiley and sad faces next to readings to indicate whether or not they’re calibrated.

The radio’s audio signal is monitored to detect of time pips. The time pips consist of six 1-kHz pips on each second. The first five are 150 ms long. The final pip is 300 ms long. The exact hour is marked by the start of the long pip.[1]

The hardware captures the reference clock count at positive and negative audio edges. An ISR records these times (along with the SW high-order bytes). The time sync processing then goes to work. A time pip is validated by a silence period (at least 0.6 s) followed by a number of alternate positive and negative pulses in 500-µs intervals (for the 1-kHz pip signal), followed by more silence. The number of 1-kHz pulses is validated to detect a short or long pip. The reference clock count at the start of a pip is recorded. After the final pip is validated, this count synchronizes the system. The system must receive a short pip followed by a long pip to generate a valid synchronization. After synchronization, additional tests check that the time pip occurred when expected (i.e., close to the top of the hour).

Frequency measurement counts the number of reference clocks for a number of input signal cycles over a sample period of approximately 200 ms. The CountClock is set to capture on the terminal count of the InputDivider. An input sample therefore captures the reference clock count at the start and the end of a sequence of input signal cycles. It can calculate the number of reference clocks for the number of input signal cycles counted.

An initial sample is first performed to get an approximate indication of the frequency. The InputDivider counter is then set up appropriately and an accurate sample is taken. You must obtain the reference clock count at the start and end of a series of counted input signal cycles. The input frequency can then be calculated from this and the calibrated clock rate registers.

Frequency calculation requires precise mathematics. I used a set of 64-bit math routines (called UINT64, 64-bit unsigned), so precision wasn’t lost.

The data is multiplied by 10, as far as precision allows, creating decimal places of precision. The error of the frequency is also calculated by calculating the frequency for ClockCounts+1. (The difference from the real frequency calculation is the error.) Decimal precision is then reduced (divide by 10) so that the final error is reported as the precision of the last digit. The display then only shows significant decimal places along with the error in the last digit. The error calculation doesn’t take any account of the reference clock accuracy.

The oven case’s temperature is measured approximately every second. The heater turns on and off when appropriate. A simple on/off algorithm turns on the heater if the temperature drops below 45°C. A full PID control would generate better oven control, but this simple algorithm is adequate. The temperature of the crystal oscillator is also captured, but it’s only for display purposes.

Processing speed is extremely critical during time synchronization. The buffer to store audio edge capture data is extremely small, so the time synchronization routine must not be significantly delayed. Displaying of the temperature and time on the LCD is processed step by step in a switch statement. Each call to the display routine performs a small step in the process. Full processing and display in a single hit would take too long.

I used the debug port extensively during software development. Debug messages are still in the source code even though they’re disabled. Log messages are still output through the debug port. All of these are consistently formatted so that the data can be easily processed and graphed (using Excel).