Saturday, December 16, 2017

Save and Restore HP 3478A Calibration Data with Matlab

The HP 3478A is a very nice 5½ digit auto-ranging digital multimeter, first marketed by Hewlett-Packard in the 1980's.

A few years ago I purchased one to log voltages to a computer for some experiments I was performing -- the 3478A has a GPIB interface that allows a computer to control the instrument (I use a National Instruments GPIB-USB-B dongle to connect the 3478A to my laptop's USB port).

I recently found a second one at a swapmeet for a very inexpensive price, and I discovered one reason why it was so cheap when I returned home -- when I powered it up, the first message it displayed was "UNCALIBRATED".  (I also discovered that the DC and AC amp functions were broken, too, which might have been the better reason for its low price).

The broken Amps functions I decided to leave for another time, and instead I decided to tackle the calibration problem.

The cal procedure is straightforward (read the manual before attempting), as long as you have appropriate equipment.  But first I needed to answer the question -- which functions and ranges were out of calibration?  I wanted to avoid recalibrating the entire instrument.

Discovering which ranges are out of cal is quite simple -- if the "CAL" annunciator on the LCD is visible and blinking, that range (for the function selected) is out of calibration.  If no "CAL" is seen, then that range is in calibration.

 (Click on image to enlarge)

Stepping through all ranges of all functions, I discovered that the CAL annunciator was present for the 30 mV and 300 mV DCV ranges and for the 3 Meg Ohm Resistance range.

Using an old Power Designs 5020 Precision DC Source and my HP 34401A as references, I performed the calibration procedure (per the manual) for the 30 mV and 300 mV DCV ranges.

I calibrated the 3 Mohm range with a GenRad Decade Resistor box set to 1.000000 Meg ohms.

After finishing these calibration steps I cycled power on the 3478A -- hurray! the "UNCALIBRATED" message had disappeared and in its place I saw the "SELF TEST OK" message.

This exercise in calibration got me wondering -- how might a 3478A lose its calibration?

The obvious way is if a user attempts a calibration without knowing what they are doing.  For this reason, most cal labs will place a sticker over the front panel's CAL ENABLE switch (see the sticker on the panel in first image of this blog post, above) to keep knob-twisters and button-pushers from inadvertently initiating a calibration cycle.

But there's another way for it to lose its calibration data...

The HP 3478A stores its calibration data in SRAM.  And if power to this memory is lost, its contents (and thus the calibration data) is lost.

To keep this SRAM powered when AC power has been turned off, the 3478A contains an internal 3.0 volt battery whose sole purpose is to keep power applied to this SRAM when the instrument is powered off.  (The SRAM is powered by the diode-or'd combination of this battery and the instrument's 5V DC supply (the latter only there when the instrument is on)).

So, if this internal battery goes dead (while the unit is OFF), a 3478A will lose its calibration data.  Both of my units were manufactured over 30 years ago.  Both of their batteries are original, and both still read 3.0 volts.  But how much longer will they last?  I have no idea.

If one would like to proactively replace this battery, remember that the SRAM must always be powered while the battery is being replaced.  If the SRAM loses power for any reason during this operation, you've lost your calibration data.

That's a sobering thought!

Wouldn't it be nice to somehow first back-up that calibration data to a computer and then, if for whatever reason the meter loses this data, restore it from that backed up file?

The manual does not mention any such GPIB commands, but they exist.  They are just undocumented.  The 'W' command reads the SRAM via the GPIB interface, and 'X' command writes to the SRAM via GPIB.  (A great investigation and discussion of these two commands is here).

I mentioned this to Dick Benson, W1QG, who is a Matlab guru and who had just written a Matlab logging program for the 3478A, and he took a cut at the Matlab code to read the SRAM.

Using his 'SRAM-read' code, I wrote Matlab code to write data back into the SRAM.

Both of these Matlab code-blocks are below...

Below is the Matlab code to save an HP 3478A's calibration data to a file on a computer.

(Note: to better view the code, copy and paste it into an app with a wider page size, e.g. Word, Notepad, or...Matlab).

% Authors: W1QG/K6JCA

% *** Read 3478a Cal Data ***
% This Matlab script downloads the calibration data from the
% HP 3478A's SRAM and writes it to a file.
% Note: this script also requires the "Instrument Control" toolbox.

% To run, first 'uncomment' the appropriate gpib() routine, below,
% based upon GPIB dongle that connects PC to the HP 3478A.

  %HP_3478a = gpib('AGILENT', 7, 23);  % Use if Agilent dongle
   HP_3478a = gpib('ni', 0, 23);       % Use if NI GPIB-USB-B dongle


   for k=1:256 
      cmd=uint8(['W',k-1,'\n']); % W, address, newline
      fwrite(HP_3478a,cmd);      % fwrite writes 8 bit unsigned integers.
      value(k)=fscanf(HP_3478a); % read the value addressed.

% Select the appropriate file into which to save the data by
% "uncommenting" the appropriate save command, below.
 % save('HP_3478a_Cal_Data_SN_2301A','value');
 % save('HP_3478a_Cal_Data_SN_2520A','value');

% reshape and transpose for easy reading

   val_table = reshape(value,[256/16,16])'   % transpose = '

And here is the Matlab code to write calibration data from a file back into an HP 3478A:

% Authors: W1QG/K6JCA

% *** Write 3478a Cal Data ***
% (Note, this script also requires the "Instrument Control" toolbox.)

%                  !!! DANGER  DANGER  DANGER !!! 
% This Matlab script overwrites the HP 3478A's calibration data stored
% in the meter's SRAM.  Be VERY CAREFUL when using it, or you might 
% forever lose your meter's calibration data!!!
% In fact, I would recommend: DO NOT USE IT unless the SRAM contents are
% already screwed up.

% NOTE:  Before running, turn the front panel's CAL ENABLED Switch so that
%        its slot is vertical.  This enables the SRAM write signal.
%        And don't forget, when finished, to turn the switch so that its
%        slot has been returned back to a horizontal orientation.

% To run, first 'uncomment' the appropriate gpib() routine, 
% based upon GPIB dongle that connects PC to the HP 3478A.
  %HP_3478a = gpib('AGILENT', 7, 23);  % Use if Agilent dongle
   HP_3478a = gpib('ni', 0, 23);       % Use if NI GPIB-USB-B dongle

% Now, select which file containing calibration data (created previously
% using the Read_Cal_Data script) will be loaded into the 3478A's SRAM by 
% *uncommenting* the appropriate statement, below.
%   load('HP_3478a_Cal_Data_SN_2520A','value');
%   load('HP_3478a_Cal_Data_SN_2301A','value');
% ********************************************

% Display the data from the just-loaded file...
   input_val_table = reshape(value,[256/16,16])' % no ending ';' will print
                                                 % the table in the Command
                                                 % Window

% Now, write this data into the instrument, one SRAM address at a time,
% by sequential writing the following triplet of bytes for each SRAM
% address:
%    0x58    -- 'X'  (The "write" command)
%    Address -- 0x00 to 0xFF
%    Data    -- any value between 0x40 and 0x4F.
   for k=1:256
      cmd=uint8(['X',k-1,value(k)]); % X, address, value (3 unsigned ints).
      fwrite(HP_3478a,cmd);        % fwrite writes 8 bit unsigned integers.

% And, to verify the write operation, read back the SRAM's contents.

   for k=1:256
      cmd=uint8(['W',k-1,'\n']); % W, address, newline
      fwrite(HP_3478a,cmd);      % fwrite writes 8 bit unsigned integers.
   % reshape for easy reading 
   val_table = reshape(value,[256/16,16])' % note that ' transposes the
                                           % matrix


Note:  be very careful using this code.  Before launching it, make sure you have backed up the calibration data from the 3478A to your computer so that, if you accidentally nuke the SRAM, you can recover!

And I will add -- I have only tested this code on one 3478A (and that was the meter that gave me the "uncalibrated" error message).  Given this code's potential to wreak havoc with the calibration SRAM, I would recommend running it only when your meter's SRAM calibration data has been lost or corrupted.  (Make sure you back up this data, though, before loss or corruption occurs!)

Note:  to write data into the 3478A's calibration SRAM, the CAL ENABLE switch must be rotated so that its slot is oriented vertically.  (It is shown in its horizontal, cal disabled, position, below).

This switch enables or disables writing to the calibration data SRAM.  But it is not read by the processor.  The processor indirectly verifies if calibration is enabled or disabled by alternating writes of 0x0 and 0xF to Address 0 of this SRAM.  If the data does not change, then the processor infers that the CAL ENABLE switch is disabled.  Otherwise, if the data changes, the processor infers that the calibration is enabled.

Note, when calibration is finished, be sure to rotate the CAL ENABLE switch back to its disabled position.

Here's the schematic.  Note that the CAL ENABLE switch only gates the write signal to the SRAM.  It is not read by the processor.


First, I had already read the data from my recently-calibrated 3478A and stored it in a file (using the Matlab "Read" routine, above).  This first test would be to write this file to the 3478A's SRAM (making sure first that the CAL ENABLE switch is in its "enabled" vertical orientation).

With the exception of the first data byte (which can toggle between 0x40 and 0x4F if CAL is ENABLED and the 3478A is alternatively writing 0x0 and 0xF to it (see explanation above)), the data is identical.  (Note, it would be identical, too, if I ran the same Write code but forgot to turn the CAL ENABLE switch to its enabled position).

Next, I read the data from my second 3478A and stored it in a file (using the Read code, above).  I then reconnected my GPIB dongle to my recently-calibrated 3478A, made sure its CAL ENABLE switch was in the disabled position, and attempted to write  my second 3478A's data file into the recently-calibrated 3478A using the Write routine.

Here are the results:

The SRAM data did not update!  Good -- because the meter's CAL ENABLE switch was disabled.

For my third test, I rotated the CAL ENABLE switch on this same 3478A to its enabled position and reran the test above.  This time, the SRAM's data changed to be that of my second 3478A:

After this write I checked a few of the DC voltage ranges and verified that the 3478A still worked (although its readings were, not surprisingly, off -- after all, it now was using a different unit's CAL data).

And finally, I rewrote the 3478's original CAL data into its SRAM and finished by turning the CAL ENABLE switch to its disabled (horizontal) position:

This was not an extensive verification test, but it did verify, for me, that I could both read and write the 3478A's calibration SRAM, and that the meter still operated properly after performing the write.


1.  The Matlab code (listed above) requires the "Instrument Control" toolbox to run (to access the  gpib() function).

2.  The 3478A's calibration SRAM is 4 bits wide, but the data readouts above imply that there are five bits (or more).  E.g. the ASCII character '@' is 0x40, and ASCII 'O' is 0x4F.  The SRAM actually contains, in these two cases, 0x0 and 0xF, and the DMM's software OR's this least-significant nybble with 0x40 to create an 8-bit data byte for transmission via the GPIB interface.

3.  HP 3468A/B DMM's also have internal "keep-alive" batteries for their calibration SRAM.  Unfortunately, their instrument-control interfaces are not GPIB (also known as HP-IB), but instead they are the much less common HP-IL interface.  It might be possible to interface them to GPIB controllers with an HP 82169A HP-IL/HP-IB Interface module, should someone like to attempt it.  (Otherwise, if you have an HP 3468A/B, you might want to leave it on!)

4.  PDFs of 3478 Operation and Service manuals can be found on the Keysight site:

Standard Caveat:

I might have made a mistake in my code, designs, equations, schematics, models, etc.  If anything looks confusing or wrong to you, please feel free to comment below or send me an email.

Also, I will note:

This 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.

Friday, December 1, 2017

Repair Log: Tektronix SC-504 Oscilloscope

[Note:  My "Repair Log" blog posts contain my notes on equipment I've recently repaired.  Posted here in case someone else might find them useful.]

After repairing my Tektronix SC 502 oscilloscope module (see this blog post: SC-502), I noticed I also had an SC 504 oscilloscope module squirreled away in a dark corner of a closet shelf.

I had just finished with the '502 and I was still familiar with the disassembly/assembly procedure.  Why not tackle the '504?

So I plugged it into my TM503 chassis and powered it up.  The Power LED came on, but nothing else.

OK, so it's broken.  I knew it was.

The first thing I noticed after removing the covers was that one (of three) fuses on the A3 Trigger board was missing.  This was fuse F3488, a 0.3A slow-blow fuse that is in-line with 33.5VDC to the High Voltage power supply.

I installed a new fuse and reapplied power:  F3488 blew.

OK -- something is making the fuse blow.  Per the SC 504 Manual, F3488 protects transistor Q1380, which is part of the High Voltage supply's voltage regulator.

Poking around Q1380, Q1381, and Q1378, it was clear that the base-emitter and base-collector junctions of Q1380 no longer exhibited a (roughly) 0.7 volt drop, but were instead shorted and that this transistor would need to be replaced.

Digikey had the required  D44H11 transistor,  I ordered a few, they arrived, and I installed one.

The fuse still blew!
If fuse F3488 is blown, I would recommend a much simpler test than I describe  below in this post (which details my steps to discover what the problem was).

First, check Q1380 and replace it if it is no good.  And install a good fuse in F3488.

Then, before powering up the scope, disconnect the wire from T1475 pin 8 (to the HV Multiplier module) and check if the power-supply now comes up when you turn on the AC power. If the HV Multiplier module (Tek p/n 152-0634-00) is the problem (as it was in my unit), the power supply should now start working (without F3488 blowing) and you should measure 70 volts DC on the 70 volt power line.

(Note that the problem might not be the HV Multiplier module, but a short (or low impedance) from its output to ground.  This can be checked by disconnecting the HV connector to the CRT (with the wire from T1475 pin 8 still connected to the HV Module) and checking if the problem goes away, as I describe below.)
As an experiment to see why the "regulator" (which is actually an oscillator) was not oscillating, I attached a current-limited 33.5V bench supply (set to about 20V) to the J3490 side of F3488's fuse clip, and then connected a second bench supply, set to 0V, to pin 6 of T1475 -- this second supply essentially breaks the feedback path: I wanted to see if I could "start" the oscillator by increasing the voltage of this supply.  (Note:  I also needed to parallel this supply's output with 20 ohms because, otherwise, U1270 was forcing this point to be about 1.0 VDC.  The 20 ohm resistor creates enough of a voltage drop through R1370 to allow me to start increasing the voltage from below the turn-on point of Q1378.

As I increased the voltage at T1475.6 to about 0.6V, the regulator circuit started oscillating, but with a very loud audible squeal.  This oscillation stopped when the voltage went beyond about 1.07V, at which point Q1380 seemed to go into saturation.

OK, the HV supply's oscillator can be forced to oscillate, but when this occurs the +70V supply derived from this circuit only goes to up to about +30V, and there is that annoyingly loud squealing.

The squealing probably meant that an abnormal amount of current was flowing through the transformer's windings, causing its windings to vibrate and create an audible squeal.

Was the transformer overloaded?  What would happen if I disconnected T1475.8 from the High Voltage (HV) Multiplier module's input.

The squealing stopped!

Hmmm...maybe the HV Multiplier's load is the issue.  What happens if I leave the HV Multiplier connected to T1475.8, but now disconnect the multiplier's output from the CRT's anode?

The squeal is back!

So, the problem would seem to be the HV Multiplier itself.

Tektronix HV Multiplier, P/N 152-0634-00

I found a replacement HV Multiplier on eBay and purchased it.  When it arrived, I installed it, re-assembled the module, and then powered up the scope...

Success!  A trace!

OK -- that problem was fixed -- what else was wrong?

Channel 2's Vertical Gain knob shaft was broken and the knob spun freely.  This is an integrated knob/shaft combo (Tek P/N 366-1733-01), which I've highlighted in yellow, below:

Unfortunately, this part is difficult to find.  So, until I can find a replacement, I will be using the scope as a single-channel instrument (which was my cunning plan, anyway).

(By the way -- omniscient Google informs me that this Tek knob has an NSN number:  5355-01-186-1111.)

Another problem I had was that the focus shaft had had its tip broken off (to which a now-missing Focus knob attached), thus making the shaft too short.

I had a long length of 1/8" diameter clear plastic rod (available from Tap Plastics) and a spare 1/8" coupler.  So I clipped off a short piece of rod and used my extra coupler to extend the shaft:

(I also dug through my junkbox and found "good enough" replacement knobs for the missing Focus and the broken Intensity knobs).

Finally -- the Time Base knob's skirt had detached from the knob.  Superglue fixed this.

That's it!  Here's the SC 504 on the bench for testing with my FPGA SDR and ATU...


Instruction Manual PDFs (which include schematics) can be downloaded here:

Standard Caveat:

I might have made a mistake in my designs, equations, schematics, models, etc.  If anything looks confusing or wrong to you, please feel free to comment below or send me an email.

Also, I will note:

This 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.

Monday, November 27, 2017

Replace an HP 16047A Test Fixture with a BK TL89F1

A year or two ago I picked up an inexpensive HP 4274A LCR meter at the De Anza swapmeet in Cupertino, California.

Unfortunately, it did not have a test fixture into which one could plug a component to test, so I needed to scrounge one up.

Hmmm...could I make my own?

Maybe, but the text fixture must have four male BNC connectors to mate with the four female BNC jacks on the LCR meter.

I could probably cobble something together, but why not first look for an HP adapter?

HP made a number of different 4-BNC adapters, and the one which shipped with an HP 4274A was the HP 16047A.  (For other adapters, please refer to:

HP 16047A Test Fixture:

I happened to find an HP 16047D on eBay -- it is similar to the HP16047A, except its frequency rating is to 40 MHz instead of 13 MHz.

But the HP 16047D only came with one set of component-lead clips.  There are actually 3 different types of clips (as seen in the photo for an HP 16047A, above), and it would be nice to not have to bend leads to fit my sole set of clips.

I could hunt for more clips, but they typically came with test fixtures, and these fixtures, with clips, usually cost in the hundreds of dollars on eBay.

Somehow I happened to stumble across a picture of a BK TL89F1 test fixture, and I was immediately struck by how similar it looked to the HP 16047A.  Given its sub-100 dollar price, it looked like it could be an inexpensive "connector-for-connector" compatible replacement for a 16047A, and it included all 3 styles of component clips.

BK TL89F1 Test Fixture:

How do specifications compare?


(Click on image to enlarge)

(From: Accessories Selection Guide For Impedance Measurements, Agilent Technologies, April, 2005.)


Model TL89F1
Test fixture for convenient testing of axial and radial leaded type components.
  • Frequency: DC to 10MHz
  • DC Bias:+/- 40V peak max (AC+DC)
  • Operating Temperature: 0 to 40 degrees C
  • Terminal Connection: BNC to 4 terminal insertion slots (radial or axial)

Specifications were close enough for me (especially given the fact that the HP 4274A is a 100 KHz instruments), so I ordered one.  Here is the test fixture and its various adapters, as received:

And its size, compared to an HP 16047D fixture:

Doing a quick test to compare HP and BK test fixtures...

1.  A 1000 pF dipped-mica capacitor, tested with my HP 16047D test fixture:

2.  And now, the same capacitor, but tested on my BK TL89F1 test fixture:

Not much difference!

There is one physical difference between the two fixtures:  the HP 16047A has a plastic piece to ensure that the bias switch is forced into its lowest positions -- the BK fixture has no such block.  Unless this feature is important to you, I believe the BK TL89F1 would be a satisfactory (and inexpensive) replacement for an HP 16047A.  (But, of course, do your own research to verify!)

Additional Notes:

For testing SMD components, the BK TL89S1 could probably be used in lieu of an HP 16034E:

Standard Caveat:

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 finally, 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.

Thursday, November 23, 2017

The Hilbert Transform and SSB Modulation

(Below are some brief notes to myself on the Hilbert Transform's use for the "phasing" version of SSB modulation.)

The "Phasing" method of SSB generation was a popular way of generating SSB in the early days of Amateur Radio SSB operation.

Some transmitters, such as the Heathkit TX-1, were designed to utilize outboard phasing accessories, such as the Heathkit SB-10, shown below.  (The TX-1 and SB-10 were my first SSB station while in high school).

Other early SSB transmitters had their phasing networks built in, such as the Hallicrafters HT-37 and the Central Electronics CE-100V.

The phasing method requires that the audio frequencies in the voice signal be shifted by 90 degrees.  In those early transmitters, this shift was accomplished with an analog phase-shift network.  Typically its setup would involve a nulling process using several knobs.

Now, with digital signal processing, the requisite 90 degree shift of the audio signal can be accomplished much more accurately and without tuning using a Hilbert Transform.

Below are two visual representations of the math underlying SSB generation via the Hilbert Transform in terms of sines and cosines.  For visualization I find it useful to express sines and cosines in their complex-exponential form.  E.g:

cos(2πfot) = (ej2πfot + e−j2πfot)/2


sin(2πfot) = j*(e-j2πfot - ej2πfot)/2

Note that j =  ejπ/2.   When multiplying (e-j2πfot - ej2πfot)/2 by j, the "π/2" term in j's complex-exponential representation results a +90 degree rotation of each of the two exponentials in (e-j2πfot - ej2πfot)/2.  The result is that the negative-frequency exponential (e-j2πfot) is rotated by +90 degrees, and the positive-frequency exponential (- ej2πfothas a total rotation of 270 degrees: 90 degrees due to the multiplication with j, and an additional 180 degrees due to the minus sign in front of it.

Or, in other words, the positive-frequency exponential is rotated by -90 degrees rather than +90 degrees.

Here's a visual representation of LSB generation:

(Click on image to enlarge)

And second, USB generation:

(Click on image to enlarge)

If the input audio were a sawtooth waveform, the image below shows the signals at various stages of the modulation process.

(Click on image to enlarge)
Note, in the image above, that the resulting SSB signal can have amplitudes larger than the peak values of its input audio (due to the Hilbert Transform's phase shifting).

This difference in input versus output signal magnitudes can be seen more easily in the image, below.  The sawtooth input has had its peak magnitude defined to be 1.0.  The peak value of the modulator's output, however, is 1.8.

A significant difference!

(Click on image to enlarge)

Therefore, because the level of the modulator's output IQ signal level can differ dramatically from the input audio's signal level, feed-forward transmitter gain control is ideally accomplished using the magnitude of the modulator's output IQ signal, rather than the magnitude of the input audio signal.

This conclusion is also true for the Weaver method of SSB generation.


Standard Caveat:

I might have made a mistake in my designs, equations, schematics, models, etc.  If anything looks confusing or wrong to you, please feel free to comment below or send me an email.

Also, I will note:

This 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.

Saturday, November 18, 2017

Repair Log: Tektronix SC-502 Oscilloscope

[Note:  My "Repair Log" blog posts contain my notes on equipment I've recently repaired.  Posted here in case someone else might find them useful.]

A couple of days ago I was thinking it would be nice to add a small oscilloscope to my FPGA SDR station for monitoring my transmit RF, and I remembered that, several years ago, I had picked up a broken Tek SC502 oscilloscope module at the De Anza swap-meet.

It had been languishing in my "projects for the future" pile (a very large pile!), and I thought that it, coupled with a TM503 chassis, could be a great addition to the station.

So I retrieved the SC502 from the pile, plugged it into the TM503, turned it on...and started to hear periodic snapping.

Oh oh -- something is arcing!

Also, although I could see a glow on the CRT (which was a sign that the CRT was probably good), there was no trace.

Well, I knew it was a project when I bought it.  Time to dig deeper...

After removing it from the TM503 chassis, I noticed that some of the pots were missing their wipers while blowing out the accumulated dust with a can of compressed air.

How could I tell?  Here is a picture of a "good" potentiometer (left) with its wiper "top" and a "bad" potentiometer (right), missing its top.

Below are the four bad boys (with one unattached wiper top) that I replaced, using various trimmer pots from my junk box (none of these replacement pots were of the original (and apparently flakey) style used by Tek in this module):

[After I had reassembled the SC502 I discovered that the wiper-top of R473 was turning freely -- in other words, it was also broken, but I had not noticed this earlier because the top had not fallen off of the pot.  I thought about replacing this one, too, but removing the CRT assembly to get at the PCB pads is a bit of a pain, and I decided that, for my application (monitoring my modulated waveform), R473 isn't that critical (it is used to set the frequency response of the cascode stage driving the vertical deflection plates).]

With the four potentiometers replaced and the SC502 reassemblied, I plugged this module back into the TM503 chassis and powered it up.

No snapping!  A good sign!

And now I could see a trace -- but it was very bright -- much too bright even with the INTENSITY knob turned to minimum intensity.

And another problem -- although there was a trace, I could not get it positioned above the lowest graticule marker on the CRT.  In other words, I could not move the trace up to the vertical center of the screen.

Attacking the latter problem first -- there was clearly a problem with the vertical deflection.

With no input signal, it seemed to me that the voltage on the CRT's vertical plates should be equal if the trace were to be centered vertically on the CRT screen, otherwise the electron beam would be deflected vertically in one direction or the other.

But measuring the collectors of the cascode plate drivers (Q470 and Q475), it was clear no amount of position-pot rotating would make these voltages equal.

So, with the SC502's MODE switch set to CH 1, I first adjusted the CH1 POSITION potentiometer so that the voltages at the collectors of Q320 and Q325 would be equal (in my case, roughly -2.3 volts) -- my thought being that, if these two voltages were equal here (assuming equal collector loads), this equality-of-voltages should apply to the differential signals along the entire vertical amplification chain.  And problems would be revealed if the two complementary voltages were ever unequal.

I've annotated Tek's schematic with my voltage measurements, below.  You can see that the complementary-voltages become unequal in the second schematic, at the bases of the Q460/Q465 pair (in fact, Q460 isn't even forward biased!).

(Click on image to enlarge)

(Click on image to enlarge)

With power off I made a quick in-circuit resistance measurement of R447 and R454 -- being in circuit, each should measure no more than their 698 ohm values (and possible much less, depending upon what is in parallel with them), but their values should be equal.

Instead, I discovered that both values measure significantly greater than 698 ohms (by at least 1K ohms),  and that the two measured values differed significantly, too.

So I removed R447 and R454 from the circuit and remeasured their values.  R447 was 1.78K, and R454 was open!

Per the manual, these are both 1/4 watt resistors, and, seeing how they and the board below them had darkened from heat, it seemed pretty clear that heat from power dissipation had probably affected their values.

Interestingly, using the voltage measurements above, the heat dissipation across each resistor should have been about 0.3 watts with the trace centered vertically on the CRT screen -- in other words, they were operating above their power-rating specification!

This too-high power dissipation raises the possibility -- perhaps the -5 volts I measured at the emitters is out-of-spec, and that this voltage should actually be lower -- if no base current were being drawn by Q450/Q455, then the voltage their bases would be about -8 volts (i.e. R449/R450 voltage divider), putting the emitters at about -7.3 volts.  In this ideal case, though, R447/R450 power dissipation would be about 0.23 watts -- too close to the 0.25 watt resistor specification for my tastes.  And with actual base current (rather than an ideal base current of 0 mA), the base voltage of Q450/Q455 will only become more positive, thus raising the emitter voltages and the power dissipated by the two resistors.

Concerned about their heat dissipation, I replaced R447 and R454 each with a series-connection of three 232 ohm, 1/8 watt resistors (to improve the overall power rating), and mounted them a bit away from the PCB so that they would get some air circulation around them and not discolor the board further.  (Note, these mods could be made without disassembling the SC502).

With this mod, the power rating of R447 and R454 becomes 0.375 watts.  But if more power-dissipation margin is desired, perhaps a better choice would be to replace R447 and R454 each with a series-connection of four 174 ohm, 1/8 watt resistors.

(Click on image to enlarge)

With the SC502 plugged back into the TM503 and powered up, success!  The trace(s) could now be centered vertically on the CRT!

The blindingly bright intensity was fixed by adjust the beam-current potentiometer (R873).  Although the manual says the current should be adjusted so that the test-point measures 0.4 volts, I found 0.2 volts to be a bit better, in my opinion).

Here's the TM503 and SC502 undergoing some bench checkout, just after I finished adjusting the beam current...

One final note -- the SC502 is a 15 MHz scope, and I had planned to used it for monitoring my transmit RF at frequencies up to 30 MHz.  Because I am more interested in seeing how the waveform looks rather than making accurate voltage measurements, it does not bother me if the response rolls off above 15 MHz, but I was curious how much this roll off would be.

Using my HP 3335 signal generator set to +10 dBm and feeding the scope directly via a length of coax (terminated in 50 ohms at the scope input), I measured the following frequency response.  Note, the amplitude measurement is in vertical division of the scope's CRT.

So, at 30 MHz the frequency response is only down about 3 dB from the response at 1 MHz.  Not too bad, and certainly acceptable for my application!

That's it for this post.


Instruction Manual PDFs (which include schematics) can be downloaded here:

Standard Caveat:

I might have made a mistake in my designs, equations, schematics, models, etc.  If anything looks confusing or wrong to you, please feel free to comment below or send me an email.

Also, I will note:

This 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.

Thursday, October 5, 2017

An FPGA SDR HF Transceiver, Part 11 -- Floobydust...

This eleventh and (I hope) final blog post in my FPGA SDR transceiver series is a collection of miscellaneous topics that do not warrant blog posts of their own.

In other words, Floobydust!

Floobydust?  From my copy of National Semiconductor's 1980 Audio Handbook:
"Floobydust" is a contemporary term derived from the archaic Latin miscellaneus, whose disputed history probably springs from Greek origins (influenced, of course, by Egyptian linguists) -- meaning here "a mixed bag." 

With that, let's dive into this posting's potpourri of miscellaneous topics!

The FPGA SDR's Simulink File Download:

If you'd like to get a copy of the the FPGA SDR's Simulink model (Xcvr_SSB_AM_2p5.mdl), it can be freely downloaded from the following site:

Please read the following notes!!!

  • The FPGA SDR design utilizes a Waveshare Xilinx 3s500e Development Board.  (For more information on the design, start here:
  • The Matlab version that I used:  R2009b, along with Simulink.  Note, I purchased the "Home" version of Matlab and Simulink.  Purchasing the current "Home" versions should also allow you to download previous versions, such as R2009b.  At least, I could download (for free) previous versions after I purchased my "Home" version several years ago.
  • The Simulink Model file (Xcvr_SSB_AM_2p5.mdl) is THE design file.  All other files are ancillary files.
  • You will also need the Xilinx ISE Design Suite for the Xilinx blockset required by the Simulink model as well as for the tools to create and load the .bit file onto the Xilinx 3s500e board.  I'm using the "Xilinx ISE Design Suite  12.2".
  • Regarding the Xilinx ISE Design Suite:  Use the Xilinx "Project Navigator" to convert the .xise file into the final .bit file (the .xise files is created by clicking on the Xilinx "System Generator" block that is on the top level of the Simulink model) .  And then use iMPACT (from the Xilinx ISE) to load the .bit file into either the eeprom on the Waveshare board or into the FPGA itself.  (And you might see quite a few "warnings" generated by the Xilinx Project Navigator as it goes through its process -- these were present in W1QG's original version of the design, and, being a neophyte using these tools, I've ignored them).
  • These files are free to all.
  • I am not available to provide help (which is the hidden price of having the files be free to all).  Therefore, if you want to use these files, I recommend that you be already familiar with Matlab, Simulink, and the Xilinx tool set, and that you are comfortable with using them to create FPGA designs and files that can be downloaded into actual FPGA devices.  If you do not have this familiarity, learning how to properly set up and use the tools can be a major major issue.  So, before you spend money on anything, I would recommend that you first know what you are getting into, or that you have colleagues who are familiar with the tools and design process and who are willing to help you.
  • Finally, I might have made a mistake in my designs, equations, schematics, models, etc. Do not assume that the design is bug free!

FPGA SDR Filter Downloads:

Files of Filter Data (including Information Filters of various bandwidths and filters used in the RX EQ stage) can be found here:

From the Readme file at the above URL:

This repository contains some of the Filter Files that I download into my FPGA SDR transceiver from an Arduino NANO used as the UI Control processor.
Note that, in the Arduino code, I store these filters in the Arduino's Program Memory, thus the "const PROGMEM int" in lieu of "static int" used by Dick, W1QG, in his original filter files (Dick used a PIC processor for UI control).
The file "AF_Filters_1.h" contains the filters I use in the audio RX Equalizer stage, while all other ".h" files are Base-Band Information Filters (centered at 0 Hz -- refer to blog post 3 in my FPGA SDR series).

(Again, these files are freely provided, and because of this I again caution that I am not available to provide help.)

Other Floobydust:

1.  FPGA Utilization:

I've highlighted the Xilinx XC3S500E attributes in the following table:

(Click on image to enlarge)

Note that the total number of slices available is 4,656 (four slices form one CLB, or Configurable Logic Block).  Version 2.5 of my FPGA design occupies 97% of the FPGA's slices.  Not much more room is left!

(Click on image to enlarge)

2.  FPGA Power Dissipation:

The FPGA SDR Transceiver, powered with 14V, consumes about 9 watts of power (0.65 Amps).  Originally there was no venting in the case, and its inside could get a bit toasty (imagine a small box completely enclosing a 10 watt light-bulb).

To provide a bit of heat relief, I added a very small fan to the FPGA SDR's back panel and 10 quarter-inch holes on the bottom of the case (I believe I used a 1 1/8 inch chassis punch to make the fan hole).  The fan runs at a low speed (the fan is a 12V fan, but I power it at about 7V using a series dropping resistor from the 14V line).

I haven't made any measurements of the temperature profile within the box.

3.  Fan Speed Control:

The switching power supply has a fan that is constantly on, and it is a bit noisier than I would prefer.  On the other hand, I've set the speed of the PA fan at a low value so that its noise is fairly unobtrusive, but it isn't very efficient for cooling the PA when transmitting at high power.

Wouldn't it be nice if these two fans would go to full speed if their components were getting hot, but otherwise luffed along at a low, quiet, speed (or were off altogether)?

So I decided to add fan speed controllers to both the PA's fan and the Switcher's fan, and I'd like to have the fans start speeding up and a temperature of 40 degrees C or a bit higher (40 degrees C = 104 degrees F).

Which temperature sensors to use?  I've plotted the characteristics of some temperature sensors, below:

(Click on image to enlarge)

To turn ON the fan, I am going to use an MJF122 NPN Darlington transistor (explained further below).  Here's a graph of its Ic versus Vin characteristics, given the test circuit included with the graph:

(Click on image to enlarge)

Note that the Darlington is ON and its transfer characteristics linear when Vtemp is between about 1.16 and 1.28 volts.

And why 100 ohms collector load?  That's approximately what the PA's fan looks like, when it is spinning.

Let's add this information to the Temperature Sensor graph:

(Click on image to enlarge)

Amplifying the MCP9700's output by a factor of about 1.3 results in, roughly, the same turn-on point as I would get with the MCP9701.  Both turn on at a temperature around 40 degrees C and are in saturation (i.e. the fan can spin no faster) by, worst-case (for the MCP9700, amplified by 1.3), about 50 degrees C.

In the case of the MCP9701 you might initially think, given its output voltage at 40 degrees C, that it could drive the Darlington directly, but the MCP9701 is only spec'd for 100 uA output current, which, given the range of the Darlington's Beta, might not be sufficient.  So an op-amp provides enough current to drive the Darlington's base, even when the Darlington is in saturation.

Now let's look at the Switcher's fan-controller, which, of the two designs I'm presenting here, is the simplest:

(Click on image to enlarge)

Notes on the Fan-Speed Controller:
  1. The temperature-sensor is an MCP9700 in a TO-92 package.  Its plastic case (meant for ambient air temperature measurements) will phyically contact the windings of the Switcher's L1 inductor (which I determined, by touch, is the component that becomes warmest) -- thus the need for a plastic case: to provide voltage isolation.
  2. I would have preferred to use the MCP9701 in a TO-92 package, but I didn't have one at hand -- I only have these devices in SOT-23 packages.
  3. The MCP9700 cannot source much current, so I use an op-amp to provide a current boost.  This op-amp also multiplies the sensor's output by a factor of 1.3 so that, at a temperature greater than about 40 degrees degrees C, the resultant voltage is about 1.18 volts, which is (roughly) the voltage at which the MJF122 Darlington turns on sufficiently to start the fan turning (Note that the voltage across the fan needs to be fairly significant to get it to start (e.g. 5 to 6 volts?), but, once started, this voltage can be decreased and the fan will still continue to turn).
  4. An MJF122 was used because of its high current gain and also because it has an insulated package (no insulated screws and/or washers are required when attaching it to the chassis (which acts as its heat-sink)).
  5. Some resistance in series with the base of the MJF122 is required to limit base current when the Darlington saturates.  I'm using 470 ohms, which, when the op-amp output is 2.0 volts (i.e. temperature at sensor > 80 degrees C), results in a (measured) base current of 1.5 mA.  This amount of current can be easily sourced by the TLV271.  
  6. The MJF122's Beta can vary tremendously with collector current and temperature.  At 100 mA and 25 degrees C, per the MJF122 datasheet (figure 8), DC current gain is about 500 (this will vary from device to device), which means base current would be 0.2 mA.  This would result in a voltage drop across the 470 ohm base resistor of about 0.1 volts -- equivalent to a temperature error of 5 degrees for the MCP9701 (19.5 mV/degree slope) or about 8 degrees for the MCP9700 when amplified by 1.3.  If important, this error can be reduced by decreasing the value of the base resistor, with its lower limit being a value that would still allow the TLV271 to adequately source the base current at, say, an input voltage equivalent to a temperature of 80 degrees C.  (Note: I measured a base current of about 0.07mA prior to device saturation in this application).
  7. A 78L05 powers both the sensor and the op-amp with 5VDC.  It's possible that this circuit could be replaced with a zener diode and a resistor, but the 78L05 is a simple solution whose output voltage is constant with temperature (when compared to a zener diode).

The temperature-sensor is mounted on a small board (with bypass cap), and this board sits IN the switcher's toroidal L1 "doughnut hole":

Note that the sensor's plastic case physically contacts the inductor's windings.  (The sensor is black, the capacitor is yellow-brown).  (The white goop was added by the manufacturer).

Here's the entire fan-controller circuit, mounted on the inside of the top of the switcher's chassis, next to the fan:

For the PA fan I wanted to do something similar, but I had two concerns:
  1. There could be a lot of RF within the PA compartment, so the circuit needed to be immune to RF.
  2. I didn't want to use a temperature sensor in a TO-92 package.  I wanted a device with a low-impedance thermal path between its pins and its die-based temperature sensor so that I could connect a pin (e.g. the device's ground pin) directly to the heatsink or some other "grounded" heat source.  So in this design I use an MCP9701 in a SOT-23 package, with the temperature-sensing path made via its ground pin.

Here's the circuit for the PA's fan controller.

(Click on image to enlarge)

Although it appears complex, the "bones" of this circuit are the same as the switcher fan-controller circuit.  But note:
  1. The gain of the op-amp is now 1, rather than 1.3.
  2. There is a 100 ohm resistor which keeps the fan always on, but at a low speed.
  3. There are a lot of additional R's and C's acting as filters to mitigate any possible ill-effects created by having high-power RF near this circuitry.

To create a low-impedance thermal path between the PA and the temperature sensor, I soldered the temperature sensor's "Ground" pin to a Ring Terminal.

Ring Terminal:

 The rest of the sensor circuitry (consisting of the sensor and RFI mitigation passive components) sits on a small PCB.  The Ring Terminal, itself, is screwed to the PA's Q1 mounting flange using the flange mounting screw, as shown below:

Here's a test of temperature in CW mode on 80 meters, operating at 90 watts out, with the key held down for 2 minutes, and then released and the PA allowed to cool for 3 more minutes:

(Temperature was determined using the measured sensor voltage and reworking the sensor's "voltage as a function of temperature" equation to instead represent "temperature as a function of voltage.")

You can see how the temperature rise is fairly steep when the PA is initially keyed, but as the fan turns on the temperature rate-of-change slows down to about 7 degrees per minute.  (Ideally, I'd like to see this slope flatter.  It hasn't been an issue with my usual SSB operation.  Were it to become a problem, I would look into improving the air flow through the heat-sink fins.  Some examples include better routing of air into the heatsink fins, or adding more exhaust holes.)

I tried a similar test in LSB mode of the PA's fan, but instead of transmitting for 2 minutes I transmitted for 6 minutes, continuously talking (reading out loud the text from a QST article).  The PA's temperature started at 29 degrees C and, over the course of the six minutes, never got above 39 degrees, and I had to really work at getting it that high -- lots of yelling into the mic!  (Note that at 39 degrees the fan still hasn't kicked on).

I haven't done any testing of the switcher's fan and under what operating conditions it turns on, but I have noted that, during normal sideband conversations on 80 meters (at about 90 watts out), the switcher's fan does come on after a few minutes of talking.

4.  Codec Output Low Pass Filter:

While using headphones to listen to some local LSB conversations on 80 meters, I thought I detected some out-of-band distortion components (i.e. above the audio Nyquist frequency of 4882.8125 Hz).  I didn't hear these with the built-in speaker (whose response rolls off nicely), but only with the wide-band stereo headphones I was using.

Assuming that these were generated by the codec (note: unverified), I decided to add a low-pass filter between the codec's output and the speaker amplifier to roll off out-of-band audio components.

I chose a four-pole Sallen-Key topology using two op-amps (i.e. a single 8-pin SOIC package), with the cutoff frequency set to about 4.9 KHz.

Here's the design:

(Click on image to enlarge)

You can find additional information on this filter in Part 6 of this series:

5.  External Speaker:

The FPGA SDR's speaker is mounted on radio's top cover, towards the rear, as shown below:

This location works fine -- I have plenty of speaker loudness while I'm sitting in front of the radio, but I have been considering placing my Automatic Antenna Tuner on top of the FPGA SDR.  If I do this, then this speaker's audio would be obstructed by the Tuner.

I had considered this eventuality when I built the FPGA SDR by including an "External Speaker" connector on its rear panel (if an external speaker were plugged into this connector, it would automatically disconnect the speaker in the FPGA SDR).

But where to mount the speaker?  Why not on the PA's front panel?  There is plenty of room, and the speaker would face forward, towards me, the operator.

I would use the same speaker I had used in the FPGA SDR -- an 8 ohm, 2 watt speaker that can be driven by the TPA0211 speaker amplifier.  And this speaker would be mounted within its own enclosure (sealed, non-ported, with a volume of roughly 27 cubic inches).

Here is the schematic:

(Click on image to enlarge)

The PA's front panel has some dimension constraints, so I would need to be creative in terms of how I mounted the speaker.  The enclosure would be held to the front panel with three screws (rather than four -- I wanted to create a "rectangular" pattern on the front panel, with one of the corners of the rectangle being the TX LED).

Two of the nuts for these three mounting screws would be within the sealed speaker enclosure.  But because I would be constructing the speaker enclosure from double-sided PCB stock material, then all of the seams would be soldered to create the sealed enclosure.  This would mean that I would not be able to get to the two internal nuts when screwing the speaker enclosure to the front panel.  So, I "captured" them by soldering the nuts to the PCB copper.

In the picture below, the two top nuts are the nuts internal to the enclosure, and the bottom nut is external.  All three are soldered to the PCB (note: choose nuts that will wick solder -- some won't!).

The image below shows how the front of the speaker enclosure mounts to the front panel (the PCB strip below the speaker has the two PA LEDs (Power-On and Transmit indicators -- note that I notched the speaker's front-panel material to prevent mechanical interference with this LED board).

After the speaker's front panel has been fitted correctly to the PA's front panel, it is time to build an enclosure around it:

Note that a back cover will be added and all seams are soldered to prevent air leaks behind the speaker.

After the speaker is installed in the enclosure but before the back is soldered on (which will complete the assembly of the enclosure), the enclosure is stuffed with polyester fiber (the same sort you can find at fabric stores, used for stuffing pillows) to help dampen out internal acoustic resonances within the enclosure.

And here is the final result:

For completeness, below is a comparison of the new speaker assembly's frequency response (green trace) relative to the speaker in the FPGA SDR (gray trace):

(Response measured with a Heil PR-20 mic placed 3 inches from the respective speaker grill.  Other than that, measurement system uncalibrated -- use these curves for relative response, only).

6. Receiver IMD Performance:

In the "RX and TX Signal Chains" post I measured the IMD performance of the receiver's preamp stages, which demonstrated excellent IMD performance.

But a real IMD test should include the RF ADC, too.

So, with the transceiver completed, I drove the antenna input with a two tone signal and measured the two-tone's distortion at the Audio DAC output (i.e. measured at the audio codec prior to the speaker amplifier).

This measurement measures the IMD of the signal chain starting with the receiver preamplifier stages, and then through the RF ADC, the receiver digital stages within the FPGA, and finally ending at the audio DAC output.

The signal levels of the two signal generators were set so that, when combined, they created a two-tone signal whose PEP level into the ADC was at the ADC's maximum allowed input, just prior to ADC clipping (+7 dBm).

(Thus, given receive preamplifier gain of 33 to 34 dB and a loss of 3 dB in the Mini-Circuits Splitter/Combiner, the signal generators were each set to -29 dBm, resulting in about +7 dBm PEP into the ADC)

Here is the test setup:

Note that the FPGA-SDR's receiver was setup to minimize distortion introduced by the receive AGC process (in this case, the receive AGC was set to Slow, peak detect, hang = 1.6 seconds).

And here are the results:

Note that the two-tone spacing is 200 Hz.  Thus, if there were distortion, we should see products at 200 Hz intervals from either tone (e.g. at 1200 and 1800 Hz, etc.).   But no products can be seen, even given a noise floor that is 90 dB below the level of either tone.

In other words, given that IMD3 products are not measurable at the maximum allowable two-tone signal levels of -32 dBm (each) into the radio (i.e. generators each set to -29 dB, plus 3 dB loss through the splitter/combiner), I would say that this is excellent IMD performance.

Note that the two -32 dBm generator signals (the level of each generator when measured at the receiver's antenna terminal) are equivalent to two signals that are each 41 dB over S9.  (Combined signal level is +47 dB over S9).

And a final note:  Siglab's setup was:

7.  An ATU-SDR Communications Interface:

After operating the FPGA SDR with my Automatic Antenna Tuner for a couple of months, it became clear to me that it would be nice to add a communications link between the two devices so that the tuner could be more easily set to the transmit frequency, rather than first having to measure frequency from the transmitted RF.

Why do this?  Although the ATU's relays are rated at 20 million mechanical cycles, their contacts are only rated at 30,000 cycles.  Admittedly, the 30,000 cycles is determined with a significant amount of current passing through the contacts (16A), but, assuming the transmit power while tuning is 10 watts and an SWR of 10:1, RF current passing through the relay contacts, while tuning, could be over an amp.

Much better for relay contact life, I thought, if I could tune at a much lower power.

But lower power meant that the ATU could not first measure the frequency of the transmitted RF signal -- it requires that this signal be more on the order of 7 watts (e.g. if operating into a low-impedance load with SWR = 10:1).  This meant that, every time I changed to a new transmit frequency, the tuner would have to go through its complete tuning sequence.  Lots of relay cycles, with contacts carrying current opening and closing!

So...rather than have the ATU measure the transmit frequency from the transmitted RF signal, why not instead have the FPGA SDR send the transmit frequency to the ATU first before it actually transmits any RF?

I had had the foresight to design into the FPGA SDR such an interface: one input from the external ATU to the FPGA and one output from the FPGA to the external ATU, but, unfortunately, because I had designed and built the ATU several years ago, and I had not thought to add a complementary interface at that time.

Instead, I had designed into the ATU two extra output signals (which I have never used), but no inputs.

Why not change one of these outputs into an input so that the ATU had both an input and an ouptut?  It would then be compatible with the FPGA-SDR's existing ATU interface.

It was a simple fix to make.  The physical interface now looks like this:

(Click on image to enlarge)

(Circuit details can be found here for the ATU and here for the FPGA SDR).

As you can see, the two-wire interface consist of two signals: data sent from the FPGA SDR to the ATU and a clock sent from the ATU to the FPGA SDR.

The FPGA SDR sends the transmit frequency to the ATU via a 24-bit packet.  The packet has the following structure (here defined assuming high-true data):
  1. 4 bit header.  Value 0xF.  (Strictly speaking, only two header bits are needed -- the first one always acts as a start bit by taking the Data line out of its IDLE state, and the second bit ensures that there are an even number of bits, and thus clock-edges, in the packet, so that, with the last clock transition, the clock is back in its IDLE state).
  2. 15 bits of binary frequency information, representing the tx frequency in KHz.  Sent LSB first.
  3. 4 bits of checksum, representing the number of zeroes in the 15-bit binary frequency word.  Sent LSB first.  Because the ATU generates its clock transitions irrespective of whether or not the SDR is sending correct data (or even sending data), this field helps the ATU verify that, yes, it correctly received the frequency data.
  4. 1 bit Stop Bit (value 0).  To place data line back into its idle state.
The tuning procedure is:
  1. First, the user depresses the TUNE switch on the FPGA SDR's front panel, which causes the data bit from the FPGA SDR to the ATU to go HIGH. (Here I am defining HIGH = True, or '1'.  Therefore, when idle (i.e. False), this bit sits low, or 0.  This bit is the first bit of the four-bit header whose value is 0xF.  Note that the signaling on the interconnect cable between the SDR and the ATU is LOW (low voltage) = True, due to the inverters).
  2. The ATU (which might be busy with other tasks) will eventually poll this input data bit.  If it sees it HIGH (i.e. the input is no longer "idle"), it knows that the FPGA SDR wants to send the tx frequency.
  3. The ATU then responds by first shoving this input data bit into a shift register and then transitioning its Clock Out bit (sent to the FPGA SDR) from its idle state of low to HIGH.
  4. The FPGA SDR (which has been sitting in a tight polling loop waiting for a clock transition from the ATU) detects this transition and immediately puts the next packet bit on its output line to the ATU.  (Note that if the FPGA sees no clock transition within, say, 100 ms of setting that first bit, the FPGA SDR assumes no ATU is attached and aborts the packet transmission, after which it will transmit the TUNE tx signal for as long as the TUNE switch is depressed).
  5. The ATU, having generated the first clock transition, waits 1 ms (to allow the FPGA SDR to output a new packet bit) and then clocks into its shift register this new bit, followed by a clock transition in the opposite direction.
  6. Step 6 is repeated 22 more times (for a total of 24 clock transitions).
  7. After having received the entire 24 bit packet, the ATU counts the number of zero bits in the received 15-bit "tx frequency" field and compares this count to the received 4-bit checksum.  If the two are equal, the ATU will use the received frequency to address its stored Tuner settings.  But if the two are not equal, the ATU discards the packet.
  8. On the the FPGA SDR side, after it has seen all 24 clock transitions from the ATU, it begins transmitting the TUNE rf  signal (at very low power -- about 0.05 watts) on the tx frequency.  (Note: the ATU can easily tune using this level of power).

(Click on image to enlarge)

  1. The signals in the image above were measured on the cable between the FPGA SDR and the ATU, and are LOW-TRUE (low voltage = logic 1, high voltage = logic 0).
  2. After each ATU Clock transition, the FPGA SDR's places the next packet bit on its output about 350 us later. .
  3. The interval between the first header bit being placed on the FPGA SDR's data-out line and the first clock transition from the ATU can be up to 100 ms, depending upon what house-keeping tasks the ATU is performing at the time.  (In the image above this interval is about 20 ms).
  4. In the image above, the frequency is 3865 KHz (binary 00111100011001), and its checksum is 0x8 (there are 8 zeroes in the 15 bit word).  Therefore, the complete packet is 1111,100110001111000,0001,0 (I've inserted commas to delineate the header, frequency, checksum, and stop-bit fields for the reader).  But because the signalling on the interface cable is low-true logic, the signals in the image above have an inverted sense:  i.e. a logic 1 = low-voltage and a logic 0 = high-voltage.
Here's a photo showing the SDR and the ATU being tuned...

I'm depressing the TUNE momentary-contact toggle switch on the FPGA SDR's front panel, and it is transmitting a CW signal whose voltage amplitude is 2% of the maximum possible amplitude (you can see the "2%" on the bottom line of the FPGA SDR's LCD).

In other words, the TUNE signal is 34 dB down from 100% amplitude, the latter being 50 dBm (100 watts).  The output is therefore about +16 dBm (40 milliwatts).

The ATU's frequency detector circuit cannot measure the frequency of an RF signal at such a low level (it needs roughly 3-7 watts of signal, depending upon termination impedance), and previously this would trigger the tuner to run through its tuning process (usually about 4 to 5 seconds of high-speed relay chatter), but with this interface there is only a single "click" heard (as the relays set once, simultaneously) and tuning is finished.

You can see the 3.663 on the bottom line of the ATU's LCD, which is the frequency sent to the ATU from the FPGA SDR via this interface.  (The numbers to the right of the "3.663" are Forward Power (in this case, less than 0.1 watts), and SWR (in this case, better than 1.1:1).

In this example, the ATU, upon receiving the 3.663 KHz frequency from the FPGA SDR, checked its EEPROM for a valid tuner setting.  Finding one, it set the relays to this setting (with a single "click" sound as the relays were set simultaneously) and voila, the resulting SWR was less than 1.1:1.

Tuning finished!

If a tuner setting has not been stored previously, the tuner would, after checking if there had been a valid setting already stored, initiate its tuning process and then, after much relay clatter, when it finds the setting with the best SWR, it would store this setting into its EEPROM, ready for recall if this frequency is called up again.

(For more information on the Tuning algorithm, go to:

8.  S-Meter Calibration:

I chose the meter for the S-Meter to match the same meter I used for Return Loss measurement on my Automatic Antenna Tuner.

The image below shows where the S-Unit divisions would be (were I to print a meter-face overlay with S-units on it).

Note.  S-units are assumed to be 6 dB apart, and S9 is -73 dBm.

9.  Notes to Self on using creating the FPGA files and programming the Core3S500E board's PROM using the Xilinx ISE Design Suite 12.2:

 (So that I do not forget!!!)

1.  To call up the Simulink model in Matlab 2009b:
  • Find the appropriate model file (.mdl) in the appropriate directory and click on it to launch.
2.  To create compile the Simulink model and create the .XISE file (that will be used by the Xilinx tools):

The System Generator will create a .XISE file (Xilinx ISE Project file), that will be used for the next step:

3.  Create the .BIT file from the .XISE file:
  • Launch the Xilinx (64-bit) Project Navigator program in the "ISE Design Tools" folder (which, in turn, is in the "Xilinx ISE Design Suite 12.2" folder").  
  • Open the appropriate Project (e.g. click on xcvr_ssb_am_2p5_cw.xise in the appropriate folder).
  • Then, to generate the .BIT file, follow the steps in the image, below:

4.  Finally, to program the EEPROM on the Core3S500E FPGA board from the .BIT file:

·         Programmer cable should be connected to the Core3S500E board.
·         Launch Xilinx’s iMPACT (ISE Design Suite > ISE Design Tools > 64-bit Tools)
·         (Close down the two pop-ups which will appear).
·         Double-Click (DC) Boundary Scan, then Right-Click (RC) in main window and select “Initialize Chain”.
·         (Close down the two pop-ups which will appear).
·         In the iMPACT Flows window, DC on “Create PROM File”.
Ø  Select Xilinx Flash/PROM (then Green Arrow).
Ø  Change device to xcf04s and click on “Add Storage Device”, then Green Arrow.
Ø  Enter Output File Name.
Ø  Enter Output File Location (use same location as .bit file).
Ø  Click OK.
·         At Add Device popup, click OK.
·         Select the .bit File.
·         Click NO when asked “would you like to add another device file to”.
·         Click OK to “You have completed the device file entry”.
·         In the iMPACT Processes window, DC on Generate File.  Should then say “Generate Succeeded”.
·         Go back and click on Boundary Scan.
·         In Main Window, select the xcf04s device (it will become Green), then RC on it.
·         Select “Assign new configuration file”.
·         DC on the .MCS file.
·         In Main Window, again select the EEPROM.
·         In the iMPACT Processes window, DC on Program.
·         Click OK in the Popup Window.  

PROM programming should now start.  At its end, “Program Succeeded” should be displayed.

Cycle power to program the FPGA with the new contents of the EEPROM.

10.  Notes to Self:  The User Interface:

Just some notes to myself regarding the User Interface programmed into the Arduino NANO processor:


There are 60 memory locations in the Arduino's EEPROM assigned for storing frequencies.  These can be in any band.

Each memory location consists of 8 bytes.  These bytes are:
  • 1 byte:  Data Valid (valid data is stored in this location)
  • 4 bytes: Frequency
  • 1 byte:  Mode
  • 2 bytes:  Power
To write a memory location:
  • Set the BAND/MODE toggle switch is set to its "center" position (MISC).
  • Rotate the left-hand rotary-encoder to select "m_Write"
  • Push (click) the right-hand rotary-encoder to perform the write.

Software then will scan through the memory locations, searching for the first "empty" location (the memory location's Data Valid byte will contain 0xFF, the EEPROM's default).

If an empty location is found, the eight bytes of data are written into this location and its Data Valid byte written with 0x00, signifying this location contains valid data.

The buzzer will beep once, signaling that the write was successful.

If all 60 memory locations are full (no Data Valid bytes are 0xFF), the buzzer will instead beep twice and the LCD will display the message, "Memory FULL".  It is then up to the user to make room in the memory by "deleting" one or more memory locations.

To "delete" a memory location:
  • Set the BAND/MODE toggle switch is set to its "center" position (MISC).
  • Rotate the left-hand rotary-encoder to select "m_Rd/D"
  • Rotate the right-hand rotary-encoder.  This will step through each memory location whose "Data Valid" byte is valid (i.e. equal to 0x00), starting with the first location.  As the valid memory locations are stepped-through, the radio will be set to the contents stored for each location (frequency, mode, and power).
  • To "delete" a memory location, press (click) the right-hand rotary encoder.  This will cause 0xFF to be written into the Data Valid byte of this memory location.  Note that the other 7 bytes in the memory location remain unchanged.
When the memory is deleted the buzzer will beep twice and the radio will return to the original state it was in before the memories were scrolled through.

To read memories:

There are two ways to read memories:

Read Method 1:
  • Set the BAND/MODE toggle switch is set to its "center" position (MISC).
  • Rotate the left-hand rotary-encoder to select "m_Rd/D"
  • Rotate the right-hand rotary-encoder.  This will step through each memory location whose "Data Valid" byte is valid (i.e. equal to 0x00), starting with the first location.  As the valid memory locations are stepped-through, the radio will be set to the contents stored for each location (frequency, mode, and power).
Note, though, that memories are written per the first one available, so, when scrolling through the sixty locations, the radio may jump from band to band and back again as the user steps through each memory location, which can be impractical if many of the memory locations contain valid data.  So, this brings us to the second Read method:

Read Method 2:

This method steps through the memory locations that have been stored for the current band, ignoring all other memory locations.
  • Set the BAND/MODE toggle switch is set to its "upper" position (BAND/MODE).
  • Press (click) the left-hand rotary-encoder.  This will step through each memory location that has a valid entry for the current band.  For example, if the band is 80 meters, clicking the left-hand encoder will step through each memory location that contains a valid 80 meter frequency.
As memory locations are stepped through, an "M" will briefly appear on the LCD to the left of the frequency readout with the radio being set to the contents of that memory.

After the last valid memory for the band is loaded, pressing (clicking) the left-hand rotary-encoder will return the radio to its original non-memory (i.e. VFO) state, at which time a "v" will briefly appear on the LCD to the left of the frequency readout.

Additional clicks of the encoder will again cycle through the band's memory locations.

Note that memories can be for frequencies outside of a ham band.  These can be stepped through when the frequency is not set to any ham band


There are quite a few sub-menus available through the user interface.  To access these sub-menus:
  • Set the BAND/MODE toggle switch is set to its "center" position (MISC).
Rotating the left-hand rotary-encoder will step through these sub-menus.

The sub-menus are:
  • dF:  This is the default sub-menu selection.  When it is selected: the right-hand encoder will set the frequency-tuning resolution (a cursor will appear under the digit that the frequency will increment by).  Note that if the "10 Hz" digit is underscored, it will increment in 20 Hz increments when in CW mode (because 10 Hz increments were too slow and 100 Hz increments were too fast).  Also note:  while this sub-menu is selected, clicking the left-hand encoder will toggle VFO Lock (when locked a blinking "L" will appear to the left of the frequency display), and clicking the right-hand encoder will zero-out all digits to the right of selected digit.  E.g. if the frequency display is 3.876543 and the underscore is under the "KHz" digit (which equals 6, in this example), then clicking the right-hand encoder will made the frequency 3.876000.
  • attn:  Rotating the right-hand encoder will step through 4 values of attenuation (0, 6, 12, and 18 dB) at the input of the receiver.
  • rfg:  This sub-menu controls the four levels digital gain of the CIC stage (refer to this post: an-fpga-sdr-hf-transceiver-part-3).  These gains are 0, 6, 12, and 18 dB.
  • Ragc:  This sub-menu selects the receiver's AGC characteristics (e.g. Slow, Fast, etc.) for the current mode.
  • Tagc:  This sub-menu selects the transmitter's AGC characteristic (in the Audio path) for the current mode.
  • % Pwr:  This sub-menu controls the TX output power setting.  For example, if you want to lower output power for testing or for local communications, use this sub-menu.  Clicking on the right-hand encoder will store this value in EEPROM for the current band.  Note that this setting will be relative to the maximum power setting that is set (per band), under the MaxP sub-menu (see below).  When this sub-menu is set to 100 (its max), the output power will be the value set in the MaxP sub-menu.  For all other values, output power will be less.
  • m_Rd/D:  This sub-menu lets the user scroll through all "valid" memory locations (rotating the right-hand encoder) and delete any one of them (clicking on the right-hand encoder).  See the Memory description elsewhere in this blog post.
  • m_Write:  This sub-menu lets the user write the current radio's setting into 1 of 60 EEPROM memory locations.  See the Memory description elsewhere in this blog post.
  • rMax:  This control effectively sets the maximum amount of gain available from the RX AGC, and is band dependent.
  • mMax:  This control selects four levels of digital mic gain (via AGC during transmit), in 6 dB steps.
  • hang:  This sub-menu controls AGC hang-time, in increments of 52 milliseconds, from 0 to 1.6 seconds.  The right-hand encoder selects the value, and clicking this controller will update hang to be this value.  This Hang-time value is common to both the RX and TX modes.
  • side:  This sub-menu uses the right-hand encoder to adjust side-tone level.  Note that this adjustment is immediate.  Clicking the right-hand encoder will store this value in EEPROM, making it the power-on default.
  • RxEQ:  This sub-menu allows the user to select a number of filters (or equalizers) in the RX audio chain (that is, they are downstream from the first set of filters).  These filters are used primarily to remove subtle audio hiss that is above the cut-off frequencies of the first set of filters.  The appropriate audio filter is selected when adjusting the Bandwidth (toggle switch set to BAND/SHIFT mode), but this sub-menu allows the user to change which audio filter is used for a particular receiver bandwidth (updated by clicking the right-hand encoder).
  • TxBW:  This sub-menu selects which TX bandwidth will be used each mode by rotating the right-and encoder.  Clicking this encoder will store the bandwidth as the default bandwidth for the mode currently displayed on the LCD.
  • TxEQ:  This sub-menu selects which filter (e.g. equalization) to use in the TX audio path.  Not Currently Used (and defaults to "OFF").
  • TxMN:  If not set to zero, this sub-menu enables monitoring of the TX audio, and its volume is controlled by the right-hand encoder.  At power-up it defaults to OFF (value = 0).
  • hold:  This sub-menu controls the TX hold time (how much additional time the transmitter remains in TX mode after the PTT (or key) is released.  Displayed value is in tenths of milliseconds, and it can be varied from 20.0 to 400.0 ms in steps of 20 ms.
  • TunP:  This sub-menu allows the user to set the power (relative to the TX output power setting) to be used when tuning.  Note that each band has its own setting.  And the number displayed is NOT in watts or percent.
  • MaxP:  This sub-menu allows the user to set the maximum output power for the current band.  Power adjustments in other power-related sub-menus will always adjust the output power to be less than this maximum output power.
  • PA_P:   This sub-menu allows the user to set the transmitter's power (relative to TX output power setting) when a PA is being used (PA Enable switch is in its UP position) to prevent the PA from being overdriven.  Each band has its own setting.
  • AM_c:  This sub-menu adjusts the carrier level for AM.  Too little carrier level and the output signal will be overmodulated.  (If beeps are heard while talking, then the level on AM waveform "troughs" is too close to 0, if I recall correctly).
  • AM_P:  This sub-menu adjusts AM power output (relative to the TX output power setting), and is used to compensate for differences in power output levels between modes.
  • sb_P:  This sub-menu adjusts sideband power output (relative to the TX output power setting), and is used to compensate for differences in power output levels between modes.
  • (Line-In/Mic-In):  This sub-menu selects the source of the TX Audio.  If the mic is currently selected, the LCD will display "Line In?", and if Line In is currently selected, the LCD will display "MIC In?".  Clicking on the right-hand encoder will select that input.
  • GPIO:  When in this sub-menu, the right-hand encoder will step through all of the FPGA's GPIO bits.  When doing this, it will also display a single hex value representing the following 4 input bits:  bit 3:  K6JCA_ATU_IN, bit 2: nJCA_PA_DET, bit 1: EXT_IN, bit 0: nSDR_PA_DET.  E.g. if this value is "4", that means that the nJCA_PA_DET bit is high (no K6JCA PA attached) and the other three bits are low).
  • Restr Dflts:  Clicking on the right-hand encoder will return the Arduino's EEPROM to a set of default values.
  • fpga_RST:  Clicking on the right-hand encoder when this sub-menu is selected will reset the FPGA.
  • DC Voltage:  When in this sub-menu, the LCD displays the value of the radio's DC voltage.
  • Fcor:  80 MHz oscillator frequency correction.  The number displayed (which ranges from -128 to +127) is the radio's frequency error, in Hz, if the frequency were extrapolated to 100 MHz.  To use: measure frequency on the 10 Meter band, either using an RF generator set to 28.1261 MHz and using WSJT-X (in WSPR mode) to check accuracy of signal at 1500 Hz on waterfall display, or connecting the FPGA-SDR's output to a 50 ohm attenuator, depressing its TUNE button on 10 meters, and checking frequency on Spectrum Analyzer (note the +800 Hz offset).  Adjust and "click" using the right-hand encoder.

Other User Interface notes:

The two submenu rotary encoders perform the following functions, depending upon the state of the "function select" toggle switch on the front panel, just to the left of the two encoders:
  • BAND/MODE (switch up):  Left encoder selects band; right encoder selects mode.
  • MISC. (switch centered):  Left encoder selects submenu; right encoder selects submenu value.
  • BW/SHIFT (switch down):  Left encoder selects RX filter bandwidth; right encoder selects the filter's frequency shift (i.e. its BFO value).

Each of these two rotary encoders has a pushbutton feature (in addition to being rotary encoders).  The function of these pushuttons depends upon the state of the "function select" toggle switch just to the left of the two encoders.

For the left encoder, its pushbutton functions are:
  • BAND/MODE (switch up):  Step through the memories that have been stored for the current band.
  • MISC. (switch centered):  If the submenu is not the dF menu, clicking the left encoder will reset to the submenu selection to dF. If the submenu is the dF submenu, then clicking the left encoder will toggle the VFO Lock state (the VFO is locked mode when a blinking "L" is displayed on the LCD).
  • BW/SHIFT (switch down):  Clicking the left rotary encoder will store the current bandwidth as the default RX bandwidth for the current mode.
For the right encoder, its pushbutton functions are:
  • BAND/MODE (switch up):  (No function assigned).
  • MISC. (switch centered):  The righthand encoder's pushbutton performs the function defined in the description of each submenu, as described earlier in this blog post.
  • BW/SHIFT (switch down):  Clicking the right rotary encoder will store the current filter frequency-shift (i.e. its BFO value) as the default frequency-shift for the current RX filter.


...Future topics to be added as they come to mind...

OK.  That's it for this blog post and this series.  I'll close it out with this photo of the station set up at my wife's QTH in Nevada City, CA.

(The scope is a Tek SC 504 that I use for monitoring my transmitted RF waveform.  See this post:

Background Notes:

SDR Notes:  Weaver Modulation and Demodulation
SDR Notes:  The Mixer Mathematics of Digital Down Conversion

Posts in this Series:

Part 1: Overview
Part 2: FPGA Modulation and Demodulation
Part 3: Interpolation and Decimation Filters
Part 5: Control Interface, Etc.
Part 9: 50 dB HF RF Power Amplifier

Standard Caveat:

I might have made a mistake in my designs, equations, schematics, models, etc.  If anything looks confusing or wrong to you, please feel free to comment below or send me an email.

Also, I will note:

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.