Finally! I've integrated a microcontroller into the design and the tuner can now tune automatically. In other words, the Tuner is essentially finished! (Software development, though, will probably continue without end).
This blog post describes design and implementation of this final block: the microcontroller and its interface circuitry.
The previous blog post, in which match-detection is incorporated into the design, can be found here: http://k6jca.blogspot.com/2015/12/antenna-auto-tuner-design-part-8-build.html
Which Microcontroller to Use?
During this entire build I'd been planning to use a PIC processor as the system's microcontroller. In the past I'd designed it into hardware for a few commercial products, but I had not programmed them, so I was approaching the anticipated (and unknown) software task with a bit of trepidation.
To get started with the effort, about a month and a half ago I ordered a "demo" board (PICkit 44-pin Demo Board with PIC18F45K20) to use as a development platform. And it was right around this time that I serendipitously received an email from Graeme Jury, ZL2APV that changed my direction. He had been working on an automatic tuner of his own and was in the process of writing the software, but he was using an Arduino processor.
Well, I'd heard of the Arduino. In fact, much earlier in the year I'd purchased the ARRL's book, "Arduino for Ham Radio". I had glanced through it after it arrived, but then it went onto the bookshelf and over the following months I forgot about it.
I learned from Graeme that one advantage of the Arduino platform was the variety of different pre-assembled boards (often quite inexpensive) that one could purchase. This could simplify implementation.
Also, Arduino programming is in C, with quite a bit of open-source code available, and there is a large group of users who actively post (and answer) questions on the Arduino forum.
One specific concern I'd had going into this design was writing the code to measure frequency. I knew that a PIC could measure frequency, but I was hoping that I wouldn't have to write the frequency-capture code in assembly (which would be a learning curve of its own), and I didn't know if there were any pre-existing frequency measurement code for the PIC that I might be able to use instead of "rolling my own."
When Graeme mentioned the Arduino, I did a quick internet search and discovered that there were several open-source frequency-measuring routines for the Arduino.
So I pulled the ARRL book from my bookshelf, blew off the dust, and read it more closely. Looked pretty straightforward, and so I thought, why not give an Arduino a try?
The Arduino Nano
Arduino can be purchased in a number of hardware configurations. Due to space-constraints, I chose the Nano platform and placed an order. It arrived just after Christmas, about a month ago:
I also ordered a 16x2 LCD with integrated I2C interface. When it arrived I connected the two together and wrote my first bit of code:
(From little acorns...)
I had a few minor stumbles bringing up the Nano, but all resolved fairly quickly. Specifically, they included selecting the proper COM port on the computer, discovering the I2C address of the LCD (this one's is 0x3F -- I had to download an I2C bus scanner "sketch" (Arduino's name for a program)), discovering that I needed to adjust the LCD's contrast pot before I could see anything, and finally, tracing down a problem in which only the first character of a string was shown on the LCD (I needed to update the IDE's LCD routines with the latest versions). But, with the help of google and the Arduino forum, these start-up issues were quickly overcome.
Before I got too far into the programming, though, I wanted to verify that the Arduino could actually measure frequency (a prime requirement which would determine my processor choice), so I tested a couple of Frequency Counter routines. The one that, to me, seemed to work the best was FreqCounter, available here and at GitHub here.
Note, the Arduino cannot directly measure frequency over my application's entire frequency range. Clock resynchronization within the ATmega328 limits the counter's upper frequency to Fosc / 2.5 (per Atmel's datasheet). Assuming the processor is running at 16 MHz (Fosc), then the upper frequency applied to the counter's input should be no more than about 6.4 MHz.
But not a problem. If I divide the RF by 8, then the highest frequency the counter's clock should see is 3.75 MHz (i.e. 30 MHz / 8).
It looked like the Arduino could do the job. Now it was time to design some hardware...
Again, schematics were drawn with the free version of Orcad. Because of parts-count limitations imposed on designs when using this free version, the overall Microcontroller design is broken up into multiple projects, rather than integrated together into one design. So, unfortunately, Orcad's design-rules checker cannot verify the entire design, and thus there could be errors in my drawings. Also, portions of the design might be located on other pages from those where they should most logically have been placed, to comply with this parts-count-per-design limitation.
Schematic, Arduino Main:
(Click on image to enlarge)
Notes on the Arduino Main schematic:
- I do not use Arduino's on-board 5V regulator -- I was concerned about its heat-sinking, given the loads I would be attaching to it. So instead, 5V is generated elsewhere and fed into the Nano's 5V pin (it is OK to back-feed the NANO's on-board regulator this way). The Arduino's 12V In pin is left floating (but it is RF bypassed to ground).
- The FreqCounter routine uses pin D5 of the Arduino, so that's the pin into which I apply the frequency-sample signal.
- The frequency sample (which is the RF frequency divided by 8) arrives on the Microcontroller board from an off-board RF Frequency Sampler circuit. It is buffered on this board by U4, a Schmidtt-trigger inverter, that serves several purposes: first, being a Schmitt-trigger, it (in theory) should be less sensitive to noise that might be coupled onto the RF_FREQ/N signal as it travels from the Tuner's RF compartment to the Microcontroller board. It also provides a bit of protection between the outside world and Arduino, for although the RF_FREQ/N signal could directly drive the Arduino Nano input, if something went wrong with this signal I'd rather have it blow up this single inverter rather than take out the Nano board.
- Strictly speaking, R7 and C73 aren't needed, but I'm so used to adding a small bit of high-frequency roll-off to clock signals (for emissions compliance in other products I've designed) that I feel weird not including it. So not needed, but there they are!
- I have a fear of high-power RF in such close quarters coupling into the wiring connected to the microcontroller circuitry and causing flakey processor operation, so there is much capacitor bypassing used in this design. One (inexpensive) technique I like to use to mitigate such "susceptibility" issues is to filter digital I/O signals with simple one-pole filters created with a small series resistor and a cap to ground. So you will see 100 ohm resistors with either 100 nF or 10 nF caps to ground sprinkled throughout this design. I try to place these filters where the I/O signals exit or entire a shielded area.
- The Nano has an on-board Reset button, but with the Microcontroller board installed in the tuner chassis I would not be able to reach it, so I brought the Reset signal to a 2-pin header that would be easily accessible when the Tuner's cover was off.
- But RF-bypassing Arduino's Reset line can create a problem. As I unintentionally discovered, simply adding capacitance across Reset to ground can screw up Arduino. Arduino uses a series 100 nF cap from an IO pin on their comm IC to drive the Arduino's Atmel processor into reset, and if capacitance-to-ground is added to the Arduino's Reset pin, the reset-voltage driving this pin will be reduced by the ratio of these two capacitors. So, I've limited C36 to 10 nF, which is a factor of 10 times smaller than the 100 nF series cap on the Arduino board, and there shouldn't be a problem with its inclusion for RF bypassing.
- Q13 provides a bit of isolation between the +5V on the microcontroller board and the +5V going to the RF divider in the RF compartment, just in case there's a "back-current" from the RF Frequency Sampler due to action of its protection diodes (see further discussion, below).
- The SW_5VDC is used to disable the Microcontroller's drive to the relays when the Tuner is in Bypass or Manual mode. This technique is discussed in more detail with the next schematic, below.
- And strictly speaking, Q11 isn't needed -- Q8's base could be driven directly (through a series-R) with a low-true signal from the Arduino, but I'd added Q11 with the thought of driving Q8.base with a second signal, and although I decided that the second signal wasn't needed, I didn't remove this transistor.
- A VTEST port was added so that I could calibrate the A/D conversion process by connecting an external DC voltage to this port and checking the A/D's measurement accuracy.
- The buzzer is a TDK piezoelectric buzzer, p/n PS1240P02CT3 (available from Digikey). Per the TDK datasheet, they recommend a resistor be placed across the buzzer (e.g. 1K). I used a 2.4K value, deeming it close enough and wanting to reduce the current-draw a bit. (By the way, the buzzer is very useful to alerting me to error conditions, etc.)
Schematic, IO Expander 1:
(Click on image to enlarge)
Notes on the IO Expander 1 schematic:
- U1 is a PCF8575C I2C IO expander IC. It has 16 bidirectional IO bits.
- The PCF8575C outputs cannot drive high -- they must rely upon pullups to bring the output voltage up (although an internal current-source on each of the output pins will briefly source current to help charge capacitance on the output lines).
- Thus, the 2.4K ohm pullups on the relay-driver lines. These relay-driver signals are elsewhere diode-or'd with the signals from the rotary switches to turn ON, when high, the 2N3904 transistors which drive the relays. The value of 2.4K assures that there will be enough base drive into these transistors to drive the transistors into saturation, even if the relay voltage is at 17VDC and the transistors are at their minimum Beta (assuming a minimum Beta of 60 and Relay Coil resistance of 360 ohms).
- The 2.4K pullups are connected to a switched-5VDC line rather than the 5V bus. Because of the diode-or'ing of relay control signals, when in Manual (rotary-switch control) mode, this voltage is switched OFF so that these signals all drop to 0 volts and thus won't drive the relays in parallel with the rotary switches. Much less power is used when the drive to the relays is turned off in this fashion than if I'd instead, via software, written zeroes to all 16 bits and kept the pullups connected to +5V (which would mean an extra 33 mA from the +5V supply, sinked by the '8575C outputs, whenever I was in Manual mode).
- Note: PCA9535 IO expanders can be used in lieu of the PCF8575 expanders -- their outputs don't require pullups. But their software interface is a bit more complicated (there's an additional command word), and so for the sake of software simplicity I used the PCF8575 devices.
- The nybbles of the inductor and capacitor relay-control bytes are arranged to make circuitry wiring convenient, rather than for the convenience of software.
- There's an I2C EEPROM on board. This was included in case I needed additional non-volatile memory above the 1024 bytes available on the Nano board (1024 bytes if the Nano uses the Atmega328 processor). At this moment, I'm not using this external EEPROM.
- Relay drive signal rise and fall times, measured at the relays themselves, are quite fast and well under 1 msec.
Schematic, IO Expander 2:
(Click on image to enlarge)
Notes on the IO Expander 2 schematic:
- The I2C bus needs some sort of pullups, and they are included in this schematic. Although the LCD module has pullups on it, if this module isn't connected to the microcontroller, the Arduino's I2C interface won't work. So the microcontroller board has its own pullups.
- Again, RF bypassing using series 100 ohms and caps to ground to attenuate RF that might be conducted to the board via external wiring.
- Note that the PCF8575C on this page has a different I2C address from the previous PCF8575C.
- The two signals, /TUNE_RLY and /DIS_AMP_RLY, are currently not used and, although implemented on the board, are only there in case, in the future, I decide to add additional features to the tuner.
Schematic, RF Frequency Sampler:
(Click on image to enlarge)
Notes on the RF Frequency Sampler schematic:
- The RF sampler directly samples the RF being applied to the Tuner's input to provide frequency information for the Arduino. It is not part of the Microcontroller board, but is instead a separate sub-assembly.
- An inexpensive inverter (74LVC1G14) does this sampling, converting the RF to a digital signal whose frequency is then divided by 8 by U1, a 4-bit counter. This divided-down signal is then sent (via a short length of RG-174 50-ohm coax) to the Microcontroller board for frequency measurement. For example, if the RF is at 30 MHz, Arduino should see a 3.75 MHz signal.
- Strictly speaking, R6 and C6 aren't needed (but I have a habit of rolling off clock edges, see explanation earlier in this post). However, I recommend some high-frequency roll-off of the divide-by-8's output signal (as provided here by R4 and C4) if driving it a "long" distance to an unterminated input, to minimize reflections that might cause ringing and possible false-clocking.
- Because the peak RF voltage at the input of the Tuner could be very high (for design purposes I'm assuming 1000Vpeak), this voltage must be attenuated before it's applied to the input of inverter.
- Attenuation is accomplished via the voltage divider formed by the combination of R1 and R2 with R5. Two 24K 1/4 watt resistors are used, rather than a single 48K half-watt resistor, because I had the former, but not the latter, on hand. (A half watt of dissipation assumes an applied power of 200 watts with a 3:1 SWR (i.e. Vrms = 150V)). The value of 48K limits the max current through the clamp diodes.
- The 1 pF cap, C1, flattens the divider's response over frequency. Without it, attenuation is much higher at higher frequencies.
- The diodes provide voltage clamping to ensure that whatever voltage applied to the input of the inverter does not exceed its input-voltage specifications.
- D2 limits the negative peak, and although D1 can provide positive-peak limiting, I prefer to use the diode-string of D3-D8. This is because, if D1 provides the positive-peak limiting, it is shunting RF current onto the +5VDC bus, which could raise the voltage on this bus (if its impedance is too large with respect to this current) and thus possibly create unwanted and unintended consequences (it is for this reason that I've also added extra 100 nF caps to this assembly's +5V power). So consider D1 backup to the operation of D3-D8.
- The resistor divider consisting of R1, R2, and R5, also provides a direct DC path from the Antenna port to Ground, and thus they provide a discharge path for any charge that might accumulate on the antenna (e.g. static charge accumulation from wind blowing across an antenna, etc).
- Somewhere between 5 and 10 watts of applied power is required to get an accurate frequency reading.
Here's an image showing the clamping provided by D3-D8. The bottom trace is the input to the inverter, clamped by the diode clamps, and the top trace is the inverter's output. Note that with the string of 6 diodes, the input is limited to 4V, peak:
Schematic, Other Controls:
(Click on image to enlarge)
Notes on the Other Controls schematic:
- This is a revised schematic (revision now X2) of the schematic originally posted here.
- I added an extra control line to the Arduino (AUTO), and removed some unnecessary components, having placed them instead on the Microcontroller board (e.g. the pull-down resistors).
- I have also added the five new push-buttons.
- And rather than have Arduiono control the /RLY_NORM/BYPASS signal, I simply diode-or the AUTO and the MANUAL signals to turn ON the 2N3904 transistor.
Schematic, Directional Coupler:
(Click on image to enlarge)
Notes on the Directional Coupler schematic:
- The two 100 nF caps that had been connected across each AD8307 output to ground (for RF bypassing) have been removed. Coupled with the internal 12.5K ohm output resistance of the AD8307 devices, they each had formed a pole whose cut-off frequency was roughly 130 Hz, which is much too low if one of my goals is to also measure peak power. With them removed, the corner-frequency is now determined by the 1 nF feedthru caps, which shift the poles of the two outputs from about 130 Hz to about 13 KHz.
Schematic, Return Loss:
(Click on image to enlarge)
This schematic has changed due to a design error on my part. At high input powers, U2A's "Input Common-Mode Voltage Range" specification can be violated. As it turns out, for the specific LMC662 part that I've used on this board (I measured its "Input Common-Mode Voltage Range" and it is 3.6V), this would occur when input power is above 1 KW.
But, per the LMC662 datasheet, the typical value for this parameter is (V+ - 1.9V), or 3.1 V for 5V power, and over temperature this value decreases to about 2.5 VDC.
So with the original design and an applied RF-power of 100 watts, the voltage at U2 pin 3 would 3 volts (U1.1 is 4.0 volts) -- significantly above the worst-case spec of 2.5 V and uncomfortably close to the "typical" spec of 3.1 V. Not a good design.
Better that the spec not be violated under any conditions, for when this spec is violated, an op-amp will no longer behave like an op-amp.
But the fix is simple -- if I change the voltage-gain of the differencing amp, U2A, from 3 to 1, then, if one KW of RF power were applied to the tuner, the voltage at U2 pin 3 would be 2.25 VDC (given that the voltage at U1.1, by design, is 4.5VDC for 1KW of applied power). And 2.25V is under the LMC662's worst-case spec for "Input Common Mode Voltage Range."
In other words, I can meet the specification if I just change R15 and R17 from 10K to 30K ohms.
And to get back the gain of 3 that I need for the Return Loss voltage, I've made use of the previously-unused op-amp in U2's package and given it the task of amplifying the differencing-amp's output by 3.
Again, a very simple change to make. Just add two resistors and a cap to the unused op-amp and wire it into the circuit. Done!
OK -- on to the build!
The first question I had to answer -- how large should the Microcontroller board be?
I planned to mount it on the grounded chassis bulkhead, in the open area to the left of the power transformer.
Because there so many wires passing between the RF compartment (where the relays are) and the front-panel compartment (where the Microcontroller mounts), I added header strips to allow me to easily attach and remove the front-panel. Each pin of the header strip is bypassed to ground with a 100 nF cap an 0805 package (to bypass RF that might be conducted on the wiring from the RF compartment). The one exception to this bypass-cap rule is the divide-by-8 frequency pin from the RF Frequency Sampler.
NOTE: neither these header-strips, nor their bypass caps, are shown in the schematics.
Here are front and back images of the Microcontroller board. Note that the PCF8575C devices in SOIC packages, and so I used 28-pin SOIC proto-boards (although the devices are 24-pin -- these were the boards I had on hand) so that I could mount them to my vector-board.
Almost all components are surface-mount. One exception is the 2N2907 used to switch on and off the 5V_SW voltage..
For purposes of documentation (and my memory), here's a diagram showing the locations of the connectors:
Here's how the board mounts:
As I've mentioned earlier, one huge concern I've had is the effect of nearby high-power RF energy on the operation of the microcontroller electronics. Usually I solve susceptibility issues with ground-floods on PCB top and bottom layers and simple (and inexpensive) stamped-metal shields over the sensitive electronics while simultaneously low-pass filtering signals that pass under the shields from the outside world. But this tuner is a "one-off" project, not something designed to ship in quantity, so no PCB with its convenient ground floods and no stamped-shields (and their associated tooling charges).
Instead, I shielded the board with copper tape from my bin of, well, copper tape.
Kapton tape (and on the underside of the board, where the sharp connector-pin points are, an additional layer of cardboard), keep these shields from shorting-out the electronics.
Here's the process for the top-side of the board. First, apply the Kapton tape:
Then add the copper tape, soldering it to the board's ground at as many points as possible (e.g. the four corners and points between).
You might be able to make out the slit I cut in the copper to reveal the Nano's LEDs. Also, the open area at the right is left empty because the back of the front-panel meter fits into this area.
Here are two shots of front and back shielding:
Here's the build of the RF Frequency sampler (shot while I was bench-testing it). That "large" chip is the 4-bit counter used to divide the RF frequency by 8..
And here's an image showing the RF Frequency Sampler mounted in the chassis:
(Click on image to enlarge)
Finally, I needed to replace the two panel meters (that I'd intended to use to show tuning Resistance and Conductance) with the new LCD, requiring that I construct a new front panel and make a new panel overlay for it.
Again, the panel was cut from a piece of scrap PCB stock, and I made the overlay per the method described here: http://k6jca.blogspot.com/2009/12/how-to-make-your-equipment-look-like.html
Here's the result (with no RF applied):
And here's how the display looks, with RF, after it's been tuned:
Decoding the display:
Top Line, starting from the left:
- "Am" means Automatic Tune mode, Manual Arm (must first be armed by pushing the Auto/Arm toggle switch down momentarily before it will trigger). If the Auto/Arm switch is in its UP position, the display will instead show "Aa", meaning Automatic Tune mode, Automatic Arm (automatically arms itself and triggers if the SWR is above a pre-defined limit (currently set to 1.5:1)).
- "LC" means LsCp configuration (versus "CL" for CpLs).
- "L04": Ls setting is 0x04. This value is also displayed in the LEDs to the left.
- "C08": Cp setting is 0x08. This value is also displayed in the LEDs to the left.
- "B80": 80 meter band. Sets Cs, the Series-capacitance. This can be manually set, using the up/down push-buttons, or it can be set automatically, if there is enough applied power to provide Arduino with an accurate frequency reading.
- "3.865": Frequency, in MHz.
- "p 49": Power, measures 49 watts.
- "<1.1": SWR, reading better than 1.1:1.
- Select Peak power display versus Instantaneous power.
- Select a display of Power in dBm and Return Loss in dB, versus Power in watts and SWR.
- Store the current L-network setting in Arduino's EEPROM.
- Recall the L-network setting from Arduino's EEPROM and apply to the L-network (these are automatically recalled and applied at power-up).
- Scroll through and display the contents of Arduino's EEPROM (1024 addresses).
- Erase the contents of Arduino's EEPROM
- Display the actual "raw" RF frequency being measured by Arduino and the value it is "corrected" to.
- Display the raw ADC values for Vrl, Vf, Vr, and Vtest.
- Calculate a compensation value for the ADC. (Attach 4.800 VDC to the Vtest pin and measure. In a perfect world (ADC reference equal to 5.000 VDC, etc.), the ADC should measure 0x3D6. If not, use the measured value to calculate a compensation factor.)
- Turn on the relays, one at a time. (Allows me to find faulty relays and/or connections by listening for their click when they turn on. Note that this method doesn't work if you turn off a relay at the same time you are turning another one on.)
A Few Software Notes:
Burning the midnight oil...
The Top-loop and Peak Power Measurement:
There is no hardware "peak-hold" in this design. So, if a display of peak-power is desired, Arduino must sample Vf very frequently if it hopes to capture a voice-peak. This task defines the fastest loop in my code and it runs at a loop-speed of about 120 microseconds, thus sampling Vf at an 8 KHz rate.
This fast-sampling loop is shown in red on the left-hand side of the flowchart below, and it is part of the overall top-loop.
(Click on image to enlarge)
But I cannot spend all of my time in this sampling loop, looking for peak power. Periodically I need to check the Return Loss, run the tuning algorithm and update the relays, read and debounce the front-panel switches, get the RF frequency, and update the LCD. So after a fixed number of passes through the fast-sampling loop, I pop out and check if I should be taking care of other house-keeping tasks. (Currently I pop out after 8 passes through the top-loop -- i.e. about once a millisecond).
These other tasks are shown at the right-hand side of the flowchart.
(Strictly speaking, I don't need to set a flag at one point in the code and then check for it later to see if I should call the necessary routines -- I could just call the necessary routines in lieu of setting a flag. But setting a flag and checking for it allows me to interleave tasks and use the same flag at different points in the code, as is illustrated by the "22ms_flag" use in the flowchart above.)
As described above, the RF frequency is divided by 8 before it arrives at the Arduino, so the highest frequency that Arduino will see at its D5 pin is 3.75 MHz, assuming a 30 MHz RF signal.
I've programmed the frequency counter's gate-time to be 20 msec. Because this gate time is 20 msec, I can convert the "divide-by-8" reading back to a count reflecting frequency with a simple shift-left by 2 operation (multiply by 4). Measurement resolution is 400 Hz.
The FreqCounter routines contain a compensation function to correct frequency-counting errors, but when I first start using them, I discovered that if the displayed frequency is measuring too high, this compensation cannot lower it -- it can only raise a frequency that is too low. So I instead just multiplied the measured reading by a "compensation value" that I had calculated would bring it in line with the actual frequency displayed on my HP 8640B. (I later discovered that the counter on my HP 8640B was off, and that the FreqCounter's compensation routine probably would have worked, but I decided not to change my method, I just changed by compensation factor from a value slightly less than one to a value slightly greater than one).
By the way, here's my Frequency sub-menu, showing my three stages of frequency measurement:
The top left-hand number is the "raw" frequency reading, after the result from FreqCounter has been multiplied by 4 (shift-left by 2) but before compensation has been applied. This value changes in increments of 400 Hz as frequency is increased or decreased (i.e. last digit bumps up or down in increments of 4).
The number just to its right, again on the top line, is the frequency after it has been compensated. I only use one compensation value across the entire frequency range, but this value really wants to change slightly between low-frequencies (80 meters) and high-frequencies (10 meters). However, the one-size-fits-all approach that I've taken gets me close enough to where I want to be (final display accuracy +/- 1 KHz).
And the third number, on the bottom line, is the final frequency!
An important note: when making a measurement using FreqCounter the Arduino's "millis()" counter (and I also assume its micros() counter) will be stopped. So if you are using these routines for loop timing, you'll inadvertently lengthen the loops by the counter's gate time whenever millis() is invoked. In other words, if you call millis() just before and just after the counter is invoked, the delta between the two readings will be 0 msec (or close to it), even though 20 msec of real time have actually passed (assuming a gate-time of 20 msec).
LCD Display Update:
The LCD display itself, because of the nature of the LCD material, is a bit slow to visually update. So it doesn't make sense to frequently update the LCD -- you wont' see it. For this reason, and also because updating the LCD can slow down my other loop times, I limit LCD updates to a screen update rate of once every 250 msec.
Per the Relay datasheet, the worst case relay set/reset time is 15 msec, max. My measurements of Vrl show a settling time (for a large transition) of about 7 msec. So I've defined the basic "Stepping Speed" of this Tuner to be the sum of these two values: 22 msec. In other words, after any change of the Ls or Cp relays, the voltages Vrl and Vf should not be sampled by the A/D for at least 22 msec.
With this constraint, actual tuning seems fairly fast. It usually takes about 4.5 msec to tune from a "cold start" (Ls and Cp both at 0x00) and a load of 500 ohms (10:1 SWR). Other loads can be tuned more quickly, and tuning can also be faster still if not starting from the L and C = 0x00 point, but instead starting from the currently in-use value (assuming that the new frequency isn't too far away).
(An interesting side benefit of the 22 msec tuning speed -- I've always used 20 msec as being a good "switch debounce" time, so the tuning-loop speed of 22 msec allows me to also include switch/pushbutton debouncing within the same loop).
Searching for Best Return Loss (lowest SWR):
The search algorithm is the heart of the Tuner, and after some trial and error, I came up with a search pattern based on rectangles. I cannot say that this method is the best, but it works, it is fast (relatively), and seems, so far, to always find the optimum match.
Here is a (very) brief description:
The algorithm starts its search from L = 0x0, C = 0x0 (this point I consider to be a "cold start") and with a step size set to 3 times the minimum step size specified for the frequency band being tuned.
The algorithm starts in the LsCp configuration and then moves incrementally along the L "line", keeping C at 0x0 while L is incremented, until it finds a maximum value of Return Loss (i.e. lowest SWR) on that line. If a maximum isn't found, the algorithm bumps C by one increments and repeats. If none are found and both Ls and Cp are at their max, the algorithm will then switch to the CpLs configuration and begin again).
Once a maximum is found, the algorithm starts searching around this point in a "square" pattern in which the maximum is placed at the center of the square and the 8 nearest points around this maximum (at a distance defined by the current step-size) are searched for a new maximum. If a new maximum is found in one of these 8 points, the search-square is moved to center on this new maximum and a new 8-point search commences.
If no new maximum is found, the step-size is reduced (by dividing it by 2) and 8 new points around the same maximum (and closer to it), are then searched.
If the minimum step size is reached without finding a new maximum, the search (with a caveat, to be discussed just below) is considered to be finished.
Note that if the search-square is moved to an adjacent new maximum, we don't need to search all 8 points again. We've already measured some of the points in our previous search, and so we can speed up the process by skipping these:
But, as I discovered during testing, sometimes the "square" search doesn't land on the optimal match. I had this happen to me on 20 meters. To demonstrate the problem, here's a spreadsheet showing Return Loss for a small area in the Tuner's match-space at 14.125 MHz. Note that larger values of Return Loss are good, as they equal lower SWR (values shown are in Hex).
I discovered that the tuner would tune to the L and C setting for the "amber" square, but that this was not the optimal setting. The optimal setting was actually for the "green" square, but there was no way for a "square" search pattern, once it was down to its minimum step size, to get to the green square from the amber square.
So as a "final check" I added a further search that takes place after I've reached the point of minimum step-size and no further square searches. I do four 8-point rectangular searches (by rectangle I mean that one axis is twice the length of the other axis). Two searches uses a horizontal rectangle (one rectangle twice the dimensions of the other rectangle), and the other two searches use two different sizes of vertical rectangles.
It was a quick fix, but so far it seems to do the trick.
A side note: You might be looking at the above Return Loss grid for 14.125 MHz and wondering how this could be -- there are two maxima shown, yet a property of L-networks is that there should only be one maximum in the match space.
Well, there really is only one maximum. The problem here is that the minimum component step-size used for the search is too large, so we miss the underlying Return Loss pattern as we step through the component values.
In other words, the actual Return Loss, if displayed as a grid similar to the one shown above but with much smaller component step sizes, probably looks like a "ridge" rising from the "North-Northeast" direction and descending to "South-Southwest," and with a single peak in the vicinity of the Ls = 0x03, Cp = 0x2B area.
I utilize the Arduino's internal 1024-byte EEPROM to store Tuner settings, thus allowing the tuner to quickly set itself to an optimal tuning setting for a frequency, as long as there is enough RF power for the Tuner to read frequency and as long as that optimal setting has already been stored into the EEPROM.
Tuner settings in the EEPROM are divided into 3 banks of 333 bytes, each. So a total of 999 bytes out of the EEPROM's 1024 bytes are assigned to tuner-setting storage.
Each of the three banks is independent, and each can contain tuner settings for all nine ham bands (80 - 10 meters).
Each band within a bank is broken up into a number of frequency "bins," per the table below.
Each bin entry consists of 3 bytes:
- First Byte: Configuration-bit (1 = LsCp, 0 = CpLs) and 4-bit Cs setting. Bypass isn't stored, as it is not under software control in this design.
- Second Byte: Ls setting
- Third Byte: Cp setting
If the software, when tuning, does not first find a match in any of the EEPROM's 3 banks, it will invoke a "normal" tune cycle. At the end of this cycle, if it has found a "great" match (at the moment defined to be SWR 1.2:1 or better), it will write this setting into the EEPROM in a FIFO fashion (First-In, First-Out). That is:
- First, the Bank 2 setting for that frequency-bin is moved to Bank 3.
- Then, the setting for Bank 1 is moved to Bank 2.
- And finally, the new setting is written into Bank 1.
If another new setting is found, it will be written into the FIFO and the FIFO's contents shifted, and the last entry (the oldest, in Bank 3) will be dropped off.
In this way, settings that might no longer be useful (e.g. an antenna has changed, etc.) will eventually be automatically dropped, should new settings later be stored.
Three banks allows me to have settings for, say, three different antennas. In other words, if I switch antennas and give the tuner some RF, the best setting appears (essentially) immediately. But note that a bank isn't specifically assigned to an antenna. Settings for an antenna can be in different banks, depending upon how many settings have already been stored for that specific frequency "bin.".
Or, in the case of my 80 meter loop (fed with twin-lead), multiple banks could allow me to store different settings to compensate for feedline/antenna detuning due to rain or snow.
Or, if an antenna has a really high Q (i.e. SWR changes appreciably within a bin), the three banks could store the optimum settings for three different frequencies within a bin (e.g. at the start of the bin, at the center of the bin, and at the end of the bin).
One final note on memory operation: the EEPROM is not written-to if the contents to be overwritten are the same as the data to-be-written. The EEPROM is only written-to if its contents will change.
And I should add: I've also included an external I2C EEPROM in the hardware design just in case I needed it, but I haven't yet had a need to use it.
Other Software Notes:
To keep the relay contacts from degrading if switching high voltages or currents (i.e. if transmitting at maximum power and at high SWR), the tuner will only tune if Forward Power is below a "Maximum Tune Power" threshold.
I have (arbitrarily) chosen the Maximum Tune Power threshold to be 50 watts.
If, while tuning, Forward Power exceeds this threshold, the tuning process will stop, an Error message is displayed on the LCD (i.e. "Reduce Power!"), and the operator will hear beeps until either power is reduced and tuning continues, or the operator "clears" the tuning process by (briefly) transitioning to Manual or Bypass mode with the front-panel toggle switch.
(This excellent idea came from Jukka Siitari, SV9RMU, who is building an auto-tuner of his own design and mentioned this concept during an email conversation with me).
OK! That ends my description of my software.
Observations on EMI and Susceptibility to RF:
I have had two over-arching concerns regarding the integration of a Microcontroller into this design. The first concern has been: will the processor and/or its associated circuitry (e.g. LCD) generate noise that I can hear on my receiver?
And the second concern was: would high-power RF cause the processor and/or its associated circuitry to act weirdly?
Because of these two concerns, I took care to create two compartments in the chassis -- one for the RF components such as the L-Network, and the other for the control circuitry.
I routed wiring in the RF compartment (e.g. the wires to the relays) as twisted-pairs, to minimize their loop area and thus B-field pickup, as well as bypassing them to ground with 100 nF caps at the shielded bulkhead wall between the two compartments.
Also, within the control compartment, the Microcontroller board was "locally" shielded with copper tape, and I filtered signals that pass between the outside world and the circuitry under this shield with R-C lowpass filters (except for the I2C lines to the LCD -- filtering these could adversely affect rise/fall times). (Note, though, that the LCD assembly and its 4-wire interconnect cable are not shielded -- shields can be added, though, if an interference/susceptibility issue crops up).
So, to the first concern of Tuner-generated EMI: I've tested this tuner with it connected to a 50 ohm load (so there is no atmospheric noise that might mask any tuner-generated noise), and I haven't heard any difference in receiver noise between the tuner being powered ON and the tuner being turned OFF.
However, if the USB cable for Arduino downloading/monitoring is connected between the Tuner's Arduino Nano and my PC, there is a noticeable increase in receiver noise. This noise occurs even if I simply touch the USB connector's shield to my tuner's ground, so it seems to be ground-loop noise, probably originating at the switching-supply used by my laptop.
It isn't a big deal, because this cable is rarely attached (it's connected only if I'm working on the Arduino code).
Regarding susceptibility to RF -- so far, there's been no problem, but I haven't extensively tested it.
I did notice, though, that if the chassis top cover (which is grounded) is pulled back to the point of revealing the Return Loss board and part of the Directional Coupler assembly, the Tuner's "Power" reading becomes inaccurate at 100 watts and more -- it reads too low. I traced this problem to RF getting into the very short run of wire (for Vrl and Vf) between the Return Loss board and the chassis bulkhead. Sliding the chassis cover over the Return Loss board fixed this problem.
I also ran my 813 AM rig through the Tuner to my 80-meter G5RV. There was no flakey microcontroller or LCD operation while I was transmitting at a carrier power of about 230 watts (and therefore peak power of around 900 watts when I was saying "Ahhh"). So this is a positive sign. But I need to do testing on other bands, too.
However, while I was transmitting with this AM transmitter and saying "ahhh", my shack lights turned off. These are remote-control lights using an "X10" module. This hasn't happened to me before -- normally I use a Johnson Matchbox (dedicated to this transmitter) for antenna tuning. But it's been quite some time since I've used this rig and this antenna, and there have been some wind storms, so my current suspects are:
- The G5RV has become unbalanced (e.g. one of the radiating elements broke at the antenna's center-insulator in a windstorm -- it's happened before), and so there's RF in the shack from feedline radiation.
- RF is getting into the shack's AC wiring via the Tuner's AC power line. Perhaps it needs better filtering? Or power the tuner from an external 12 VDC supply?
Some Notes on this Tuner's Performance:
- Tuning range is from 3.5 MHz to 30 MHz.
- It should tune loads with 10:1 SWRs to an SWR of at least 1.2:1 (although some loads on 10 meters might be problematic) -- I've tested with 500-ohm and 5-ohm resistive loads, and, when tested on 75, 40, 20, 15, and 10 meters (I skipped the WARC bands out of laziness), this Tuner almost always tuned to an SWR better than 1.1:1. Twice it tuned to 1.1:1 (5 ohm load on 10 and 20 meters), and once to an SWR of 1.2:1 (5 ohm load on 15 meters).
- It will tune at low power (currently the tuning-power threshold is set to 10 milliwatts).
- To measure frequency, it requires (roughly) 5 to 10 watts of forward power (assuming a 50 ohm load, other loads can require higher power to achieve an adequate transmission-line voltage).
- Its tuning speed, into a 10:1 SWR, starting from L = 0 and C = 0, is about 4.5 seconds, max.
Notes to Myself:
- With 121 VAC applied to the Tuner's AC input, the +12VDC power supply measures 16.8 VDC (with 0.15 Vrms ripple) with all relays OFF, and 13.1 VDC (with 0.76 Vrms ripple) with all relays ON.
Still to Do (at a future date...):
- Hardware: Add "Tuning" and "Amplifier Disable" relays. The Arduino outputs to drive these relays have been implemented, I just need to fabricate a small board and attach it to the Tuner's back panel (with holes cut for RCA jacks). And of course, it will require a bit of software. But, at this moment, there isn't a need to do it. Maybe down the road...
OK, that's it for this blog post. The next, and final, blog post in this series will wrap it up with an update of all of the schematics (their revisions will be bumped from their current Rev. X levels to "Rev. A").
And here it is: http://k6jca.blogspot.com/2016/01/antenna-auto-tuner-design-part-10-final.html
And please note: The "final" schematics could have changed from the versions included above, in this post. The final "release" schematics can be found in Part 10 of this series: http://k6jca.blogspot.com/2016/01/antenna-auto-tuner-design-part-10-final.html
A Thank You to...
A big thanks to Graeme Jury, ZL2APV for pointing me in the direction of the Arduino. I'm amazed and very happy at how easy, with the Arduino platform, the code and hardware development turned out to be.
Also, a big thanks to Dick Benson, W1QG, for being a sounding board and source of good ideas, and for fabricating that special right-angle mounting bracket to get around mechanical interference issues with the LCD assembly.
Links to my blog posts in this Auto-tuner series:
Part 1: Preliminary Specification
Part 2: Network Capacitor Selection
Part 3: Network Inductor Selection
Part 4: Relays and L-Network Schematic (Preliminary)
Part 5: Directional Coupler Design
Part 6: Notes on Match Detection
Part 7: The Build, Phase 1
Part 8: The Build, Phase 2 (Integration of Match Detection)
Part 9: The Build, Phase 3 (Incorporating a Microcontroller)
Part 10: The Final Schematics
Links to my Directional-Coupler Posts:
Notes on HF Directional Couplers
Notes on the Bruene Coupler, Part 1
Notes on the Bruene Coupler, Part 2
Notes on the Monimatch
Notes on the Bird Wattmeter
Building an HF Directional Coupler
As always, I might have made a mistake in my equations, assumptions, drawings, or interpretations. If you see anything you believe to be in error or if anything is confusing, please feel free to contact me or comment below.
And so I should add -- this design and any associated information is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.