Tuesday, August 16, 2022

500 Watt Antenna Tuner Part 8 - Software and Microcontroller

Controller Hardware and Programming Language Selection

I have experience with Arduino and Raspberry Pi.  I used the Arduino for a telemetry board for our ham radio club EME head end.  I programmed it in C++ (a programming language from Hell).  I use the Raspberry Pi to run my Stationmaster software and it is programmed in Go (as programming languages should be).  Python is the natively supported programming language for Raspberry Pi, but for a lot of reasons which one of them was my naiveté, I decided to use Go (I had also switched from Python to Go as my go to programming language for the most part around 2015 or 2016).  It has worked out handsomely, but I have had to come up with some low level workarounds.

This experience has convinced me of two things.  One is that Arduino is a better solution for the tuner (though Raspberry Pi is a fine solution for more general purpose use cases).  The other is not to try to program it in anything other than its natively supported language and libraries, and that would be C/C++ (though as I have gotten more and more into it, my approach has become C where you can, C++ where you must).

But which model?  I only have an Arduino Due on hand that I am saving for the 500 watt power amp that I will build next.  Given that I have to buy something, I need to decide which one.  My starting selection will be I/O count.  I am not a fan of I/O expanders (more board area, more parts, more interconnections, more interference, more code, more things to go wrong).   So, let me start there:

  • 1 pins for the bypass relay
  • 1 pin for the capacitor relay (across load - Region 1 or across source Region 2 see below)
  • 8 pins for the capacitor network
  • 8 pins for the inductor network
  • 15 pins for the touch screen display
  • 2 analog pins for magnitude and phase of the reflection coefficient
  • 1 analog pin for power level input 
  • 1 pin for frequency input
  • 4 additional pins for other user interface functions that I have not thought of yet
  • 4 spare pins
So, I will need something around 45 I/O pins which puts my in the 54 pin and $40+ space in Arduino land.  So, might as well go with the Due that I have on hand.  I will also get the benefit of 12 bit A/D convertors in place of 10 bit ones as well as nine 32 bit timer channels.  Swinging 3.3 volt digital signals will also generate less noise than swinging 5 volt ones.  

This is a 32 bit ARM core micro controller running at 84 MHz.  That should make many things easier.  It has 3.3 volt IO pins, so the interfacing will need some extra care.  It takes in 6-12 volts input and generates +3.3 volts output at 800 mA (it also generates +5 volts at 800 mA but it is not likely that we will need it).  It has an Analog Reference input (AREF) which I might want to drive from the 1.8 volts stable output of the AD8302 for a more accurate A/D conversion.

User Interface 

For user interface, I have decided to use the Adafruit 3.5" TFT touch screen display.  When I first started thinking about the user interface, I was not sure what I wanted to do so a touch screen display seemed to be a natural choice because of its flexibility.  As I worked on ideas about how to use the touch screen display, I decided that it was the best option since it simplified the design and provided flexibility for any future improvements.

Software Design


The structure of the software is a state machine.  The state transition diagram is shown here:

StateEntry CriteriaActionNext State
POWERONPower onMonitor buttonsPRETUNE or PREBP
PRETUNEPress TUNEMeasure powerRFLOW, RFHIGH, MEASURE
RFLOWPower level lowIncrease powerPRETUNE
RFHIGHPower level highDecrease powerPRETUNE
MEASUREPower in rangeMeasure Freq, GammaTUNE
TUNEAutomaticCalc/Apply C and LMONITOR
MONITORSuccess tuningMonitor SWR, PWR, buttonsPRETUNE, PREBP
NOTUNEError detectedCorrect errorPRETUNE, PREBP
PREBPPress BYPASSMeasure powerRFHIGHBP or BYPASS
RFHIGHBPPower highDecrease powerPREBP
BYPASSPower in rangeActivate bypass relaysPRETUNE

The state machine enters the POWERON state upon the application of power and looks for a button push.  If the TUNE button is pushed (BYPASS button discussed below), it enters the PRETUNE state and in this state measures the RF power at the input.  If the power is less than the required threshold (to be determined experimentally) for successful tuning, it enters the RFLOW  state and instructs the user to increase the power and push the DONE button which will move the state machine back to the PRETUNE state.  If the power entering the tuner is too high for safe tuning (minding our on the air manners and following good practice), it enters RFHIGH state and instructs the user to decrease the power and push the DONE button which will move the state machine back to the PRETUNE state and restarts the cycle.  If the power level is in the correct range, the state machine transitions from the PRETUNE state to the MEASRE state where it measures the phase and magnitude of the reflection coefficient (Gamma) and the frequency of the incoming signal.  After the measurement is complete, it transitions to the TUNE state.

In the TUNE state, the controller calculates the required capacitor and inductor values using the equations discussed in the "Tuning Algorithm" page.  Because the Analog Devices phase output has a 180 degree phase ambiguity, and under some conditions it might not be possible to resolve this ambiguity as discussed earlier, two sets of capacitors and inductors may have to be calculated and tested to determine the right match.  After the relays for the desired capacitor and inductor combinations are activated, the reflection coefficient is measured.  If SWR is in the desired range (currently assumed to be 1.2), the controller enters the MONITOR state.  In this state, it measures and displays PWR and SWR data on the touch screen.  It also monitors the TUNE and BYPASS buttons and depending on which button is pushed, it moves to PRETUNE or PREBP state respectively.

Assuming that I can manipulate the Ten Tec ALC circuit, some of the power up and power down cases might be achievable automatically.  But that is a future project.  I just need to make allowance for it.

I should note that I do not plan to operate the relays with the power applied.  I have built and tested a serial link between the tuner and the Stationmaster software.  I plan to ask for key down when I need to make a measurement and then ask for key up before operating the relays.  The reason I have the RFLOW and RFHIGH states is that below a certain power level, it will not be possible to make good measurements and too high of a power level for tuning is in general bad on the air manner and under high SWR conditions, bad practice.

If the SWR measurement is above the desired limit, it enters the NOTUNE state.  This is an error state and I will experimentally determine what to do next.

If in the POWERON state (or any other state where the buttons are monitored) the BYPASS button is pushed, the state machine moves to the PREBP state and in this state measures the input power to the tuner.  If the power is too high for a given SWR, it moves to the RFHIGHBP state and instructs the user to lower the power and push the DONE button which moves the state machine back to the PREBP state and repeats the cycle.  If the power is at a safe limit, it will move to the BYPASS state and operate the bypass relays.  In this state, it monitors and displays the PWR and SWR levels and monitors the TUNE and BYPASS  buttons and depending on which button is pushed, it moves to PRETUNE or PREBP state respectively.

When the state machine is in the MONITOR state, the tune button changes its color from white to green.  When it is in the BYPASS state, the bypass button changes its color from white to green.

User Interface Screenshots

As of now, here are my ideas about the user screens.  I might modify them as I build and test the tuner.  Ignore the 10 and 30 watt limits, they will change.


Basic Tuner Screen


Tuner Instructing the Power to be Lowered


Tuner Instructing the Power to be Increased


Tuner in the Tuned State


Tuner in the Bypass State

Frequency Measurement

It took me a few days of investigation, testing and trial and error to figure out how to measure frequency, but it worked.  In the Arduino Due microcontroller, all signals are sampled by the master clock (84 MHz) before being processed, so the frequency has to be at least 2.5 times less than the master clock frequency.  If I limit myself to HF bands only, I don't need to do anything other than to attenuate the output, put it through a comparator (that I will disable when not measuring frequency, less digital noise that way), and input it to the Arduino Due.  The reason being that 84/30 = 2.8 > 2.5; so I am in good shape.  If I want to go up to the 6 meter band, I will have to put 2:1 divider in the path (54/2 = 27) and I will end up in about the same place (84/27 = 3.1 > 2.5).  I need to think about this (I decided to stick to the HF band - 6 meter will have many more challenges and I don't feel up to them at this time).

Here is how I went about building the proof of concept.
  • The lower numbered timer-counter (TC0) is used for the operating system functions. For example, if call the "delay" function, chances are that the operating system is going to use the timer for it.  If you are going to use any other library, it would be good to check if the library uses any of the timers-counters.
  • The timer-counters have a number of input and output signals.  The signals are multiplexed with most likely one other peripheral signal and then multiplexed with general purpose I/O pins.  Some of these pins do not make it out to the Arduino pins.  Some may be multiplexed with other needed pins.  So I had to make a study of it.  That rules out all three channels of the timer-counter one (TC1).
  • I ended up using timer-counter two (TC2) for my testing.  I used channel 0 to generate the test signal.  The highest frequency that it can generate is 21 MHz because the highest frequency clock available to the timer-counters is master clock divided by two so the highest frequency that the timer can generate is 1 tick low and 1 tick high, hence master clock divided by 4.
  • TC2 Channel 0 toggles the TIOA6 signal (see table 36-4 of the microcontroller data sheet) every time there is match with register A and register B (they are both loaded with 1).  TIOA6 signal is connected to the I/O line PC25 in group B peripherals.  On the Due schematic, it is labeled PWM5 and connected to pin 5 so labeled on the board and the connector.  This is the clock input to channel 2 of the same TC2 (more on this in a few lines).
  • I used channel 1 to generate 1 millisecond timebase by driving it by the highest frequency clock available to the timer (42 MHz) to minimize phase ambiguity as much as possible.
  • The millisecond timebase pulse is output on signal TIOA7 which is routed to controller pin PC28, also in peripheral B.  On the Due schematic, PC28 is labeled PWM3 which appears on pin 3 of the board (and it is so labeled).
  • I verified both the clock frequency of pin 5 and the 1 ms pulse on pin 3 on a scope.
  • I drove channel 2 with the test signal and stored the value of the counter in register A (RA) on the rising edge of the clock and the value of the counter in register B (RB) and generated an interrupt on the falling edge of clock
  • Clock input input to channel 2 of TC2 is signal TCLK8 which appears on the controller pin PD9 and on the Due schematic is labeled PIN30 and it appears on the board pin 30.
  • So, the wiring is a jumper from pin 5 of the Arduino (clock output of channel 0 - the test frequency) to pin 30 (clock input of channel 2 of TC0).  The other jumper is from pin 3 (1 ms timebase) to pin 11 of the Due (signal name PWM11) which is pin PD7 of the controller and from table 36-4, we see that it is signal TIOA8 which loads register A on its rising edge and register B on its falling edge.  The difference is the number of pulses that channel 2 has seen in a millisecond.
  • The interrupt service routine (which cannot have any arguments or return any value) calculates RB-RA which I use to calculate the frequency. 
Some of the resources that one might find useful are:

The SAM3X microcontroller data sheet (actually a book, it is 1,459 pages).  

A tutorial by KO7M that helped start me in the right direction.

The Arduino Due schematic on the Due webpage is needed to trace signals from the source (data sheet) to the useable end point (Due board connector and pin number).

I ended up digging through three software modules and reading code to figure out what it did.  The three were:
  • Power Management Controller (PMC) - it contains some of the clock action
  • Parallel Input/Output Controller (PIO) - that is where all the multiplexing happens
  • Timer Counter (TC) - That is where the 3 TC modules with their 3 channels are located

The old Arduino IDE did not add these libraries automatically, so I had to add them manually.  On my mac, they are stored in (the new one does):

$HOME/Library/Arduino15/packages/arduino/hardware/sam/1.6.12/system/libsam/include

The software is in a preliminary state with stubs and test scaffolding, but the core functionality as described can be found here.

No comments:

Post a Comment