I met a wide variety of engineers during my working days and some of them were actually normal people. Of course some of them lived up to the usual clichés about engineers including the one about never being quite done with a project. A desire for product improvement is a good thing but there is a fine line between that and obsessive tinkering. That tinkering can cause issues when you need to meet deadlines so, as the old saying goes, “There comes a point in every project where you have to shoot the engineer and go into production”.
I admit that I have some of that obsession and it kind of came out in my latest PIC project. At first I just wanted to create my own version of a PIC-based frequency counter even though there are a million of them out on the web. Then I wanted to create a PIC controller for the popular AD9850 DDS frequency generator. Then I got the idea to combine both into a single project. I was ready to call it finished when I noticed that there was still one PIC input pin left unused. That’s when I got the idea to add a capability to calibrate the frequency counter. I’m just hoping that I can get this written up and published before I think of something else to add.
At first I had planned to use a 40-pin PIC 18F4520 but that’s kind of overkill for this project. In fact, if I had used that I might still be tinkering. Instead, I decided that it could be done with one of the PICs we have used in previous posts: the 16F1847. The 16F1847 is pin compatible and backward function compatible with the older 16F628 but it adds more memory and a number of new functions.
Most of the simple PIC frequency counter designs on the web route the frequency input to 8-bit Timer 0 and use the 16-bit Timer 1 for the gate timer. The PIC counters cannot increment any faster than the instruction cycle rate which is one quarter the oscillator frequency. So, in our design here, that means a maximum direct input of 6-MHz. In order to get higher frequency counting capability the Timer prescaler is used. The prescaler hardware is able to run faster than the instruction rate so these counters are typically advertised as working up to 50-MHz. The downside is that the prescaler reduces the resolution of the counter. For instance, if the full 256 prescaler of Timer 0 is used, then the least significant 8-bits of counts are not available.
Another consideration in counter designs is the gate time. The gate is the thing that controls how long counter pulses are tabulated for each measurement. Ideally the gate would be at least one second long in order to produce 1-Hz resolution. Shorter gate times mean faster updates but reduced resolution. So if you do the math, a 100 ms gate time would have a maximum resolution of 10-Hz. Most of the popular kits on ebay actually only have a resolution of 1000-Hz at higher frequencies.
One of the upgrades in the 16F1847 that is used in this design is part of Timer 2 where the prescaler now includes a divide-by-64 option. That makes it a bit easier to get a full one second gate time for improved resolution. That also allowed me to use the 16-bit Timer 1 for the counter input instead of the 8-bit Timer 0. The bonus there is that the counter rolls over much less often. The downside of using Timer 1 is that it only has a divide by 8 prescaler so the theoretical upper end of the frequency counter range is 48-MHz with the 24-MHz oscillator shown in the diagram. But if you factor in the smaller prescaler with a full one second gate, and an LCD display then you get a resolution of 8-Hz at higher frequencies. The resolution improves at lower frequencies to 4-Hz, 2-Hz, or 1-Hz.
I used the 4-bit LCD interface I detailed in a previous post but with different pins for this PIC version. The frequency input connects directly to the PIC pin that is used as the clock input for Timer 1. The logic levels need to be standard TTL logic levels if no preamplifier or signal conditioner is added. Given that there are a million microcontroller based frequency counter circuits out on the web it is also easy to find variations for buffer or preamplifier circuits if you need one.
The AD9850 DDS module also has a lot of information available on the web. It can use either a parallel or serial interface for the frequency set commands and it has four signal outputs – two sine waves and two square waves. One of the sine wave outputs passes through an onboard low pass filter and the other (an inverted version) does not. The two square wave outputs are also complementary in phase. The square wave outputs are derived from a feedback of the filtered sine wave to the input of a high speed comparator. A potentiometer on the module allows for the setting of the duty cycle of the square wave. I’ve found that it is best to set the duty cycle to 50% for a consistent output across the frequency range. At other settings I sometimes noticed missed counts when connected to the frequency counter input. The sine wave outputs are a bit noisy and low in amplitude. Again, there are some designs on the web for output amplifiers if you need one. For my digital projects I use just the square wave output and, as you can see in the pictures below, the frequency counter section likes it just fine even at 45-MHz. It actually clocked the counter ok up to 47.3-MHz but I limited it in the software to 45.4-MHz so it wasn’t too close to the edge.
There are three switches included in the design and these control the step sizes and direction (increment/decrement) of change for both the DDS frequency set mode and for the frequency counter calibration mode. These are normally open, momentary contact switches. To enter the calibration mode, short the two contacts between PIC pins 4 and 5 as shown in the diagram. They can either be a pin header or a non-momentary switch. I use a switch so that I can recalibrate at any time without taking the cover off of the project box. Removing the short between the two contacts triggers an exit from the calibration mode.
To enter the DDS frequency set mode press the Step Switch. Once the mode is entered, each successive press will change the step size. The Increment/Decrement Switches will add or subtract from the displayed frequency with each press. The Step Switch can be pressed at any time during the setup to move to a different step size. The step size will wrap back around from 10,000,000 to 1. The set mode will automatically exit after 4 seconds with no switch presses. The PIC Watch Dog Timer is used to make this automatic exit possible. The reset causes the software to start over but it skips the section where the default DDS frequency gets set.
As indicated previously, the calibration mode is entered by shorting pins 4 and 5 of the PIC. During the calibration mode, the Step Switch will toggle between Fine, Medium, and Coarse frequency adjust steps. The Increment/Decrement Switches will add or subtract increments of counter gate time by adjusting the T2 count (coarse tuning) or by adjusting the delay loop count (medium and fine tuning). One thing to keep in mind is that only one key press will be recognized per second because the software is busy measuring the frequency with the new values. Also keep in mind that the resolution of the counter decreases at higher frequencies. For instance, if you are trying to calibrate to a 40-MHz input, the closest you can get is 8-Hz. I use the software initialized DDS frequency of 1-MHz for calibration.
The software link is listed below. Originally I started by getting the frequency counter function working on the 18F4520. That chip is pin compatible with the popular 16F877 but it has some upgraded hardware functions and some really nice additional software instructions. One of those instructions that came in very handy is DAW which stands for “Decimal Adjust W”. That allows the user to add packed BCD numbers together and then the processor automatically corrects the resulting binary number back to BCD. That’s handy when dealing with variables that get converted to ASCII for display. The 16F family doesn’t have this capability so I wrote a little macro to do the same function. If you aren’t familiar with them, macros act sort of like a subroutine call but without the CALL/RETURN overhead. What actually happens is that the compiler inserts the instructions for the macro (during assembly time) wherever the macro is referenced. It results in more overall lines of code in the listing file but eliminates the extra execution time of a subroutine call. When I added the DDS function I also found a need for a DAW function that worked after subtracting two BCD numbers. So in the final version I ended up with a DAA (Decimal Adjust Addition) macro and a DAS (Decimal Adjust Subtraction) macro.
As mentioned in the hardware section, the frequency input acts as the clock for Timer 1. The interrupt flag for Timer 1 will get set if the frequency is above 65,535 Hz. Each time a Timer 1 interrupt gets set a counter gets incremented. If that counter overflows then a second counter gets incremented. That allows the maximum count to be 2^32 so that easily handles our hardware upper limit of 48-MHz. TMR1L and TMR1H are copied at the end of one second into variables Hex1 and Hex2. Hex3 and Hex4 are the overflow bytes for Timer 1. Those variables are then converted from hex to packed binary coded decimal (i.e.: two digits per byte). The conversion routine is a brute force progressive subtraction.
The 16F1847 adds Timers 4 and 6 which have the same functionality as Timer 2. I stuck with Timer 2 because all of its registers are in Bank 0 so no bank switching was required. At the given instruction frequency of 6-MHz and maximum pre- and postscaling, Timer 2 can go up to about 43 milliseconds before it overflows. To get an even number of iterations for our one second gate time we would need about 40 milliseconds (25 overflows = 1 second). The actual gate time also has to account for software overhead so I allowed for tuning via the first timeout of Timer 2. I set the comparator (PR2) load values for the last 24 iterations at a little more than 40 milliseconds and then reduced the scaling for the first iteration to a divide by 4 prescaler and a divide by 15 postscaler. The postscaler can actually range anywhere from 1 to 16 in 1 step increments. I found a scaling combination and a PR2 load value that got me close to the desired gate time and then added a delay routine call to fine tune it. The coarse (PR2) and fine (delay count) tuning values are defined at the end of the software in a section that writes them directly into the EEPROM when the chip is programmed. You may want to tweak these values in the software for your own hardware or just use the frequency counter calibration mode to tweak them. The values are updated in EEPROM at the end of the frequency calibration mode so that they can be used again at the next power on.
As mentioned earlier, the maximum frequency that the PIC timers can handle is the instruction cycle time. For our circuit here that means 6-MHz. The software is set up to automatically determine the prescale setting for Timer 1. It is done by sampling the frequency for about 20 ms, starting with the maximum divide by 8 prescaler. If the resulting count is too low, then the count is checked against the maximum values that would be expected for prescale values of 4 and 2 and the prescale setting is adjusted accordingly. Once the proper setting is determined, a full one second count is taken. At the end of the gate time the resulting frequency count is scaled back up for display purposes.
The DDS function is pretty straightforward because it doesn’t require any software updating once a frequency is set. The command format consists of five bytes, four of which define the frequency, and one control byte that defines things like phase, etc. The control byte is set to zero for most applications so that is what the software always does. Some versions of software do 32-bit multiplication to calculate the DDS values from a desired frequency but that isn’t done here. There is a nice online calculator from Analog Devices (the chip maker) that lets you put in the desired frequency and it gives the four values for the AD9850. It also shows the expected waveforms, etc. By using the calculator I was able to determine which fixed values to add or subtract for the different step sizes. At the same time I updated the display values by adding or subtracting the equivalent BCD representation of the step size. The 16F1847 has some newer instructions that made the 32-bit adds and subtracts trivial because it takes care of the carries and borrows between bytes automatically.
Here’s the link to the calculator: http://www.analog.com/designtools/en/simdds/#/?part=AD9850&fin=125M&mult=1&ftw=158&rso=111111&harmonicDB=-50&useFilters=0
The calibration mode was mostly described in the hardware section. The software arbitrarily initializes the DDS frequency to 1-MHz and I manually feed that output into the frequency counter when I want to do a calibration. At that frequency, each Coarse step will change it about 160-Hz, each Medium step will change it about 13-Hz, and each Fine step will change it about 1-Hz. It’s not an exact science and the change values for each step will be different if you use a higher or lower calibration frequency. Keep in mind that we aren’t talking about a high end counter with an ovenized oscillator so we can’t expect too much precision.
Here are pictures of the normal, DDS Set, and Frequency Calibration modes. That’s it for this post. Check out my other electronics projects.