« March 2017 »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
You are not logged in. Log in
Entries by Topic
All topics  «
Block Diagram
Blog Tools
Edit your Blog
Build a Blog
RSS Feed
View Profile
openQRP Transceiver
Wednesday, 14 September 2011
Final Documentation Update

I posted the final updates to the transceiver documentation package. The Schematics, Parts List, and Assembly Guide have all been finalized and posted. As always, even though I have reviewed the docs many times, there is a possibility that there may still be a typo.

Steve K1EL

Posted by k1el at 12:01 AM EDT
Tuesday, 14 June 2011
Documentation Updates

I have posted new revisions of the Assembly Guide and Parts List. Those who are familiar with previous versions will see a substantial improvement. Included in this revision are details on the new firmware additions. I have made changes to the assembly order to improve the flow. There were a couple of rough spots before that I needed to change.

So for all practical purposes the documentation package is complete and I can start sending out some kits. I will start with kit requests I have received by email and then open it up to everyone. I will be sending out upgrade kits to the beta builders to allow them to bring their radios up to the current version.

As a side not I completed a 30 meter version of the radio which works great. The spectrum plot is as good as the 40 meter version. I don’t get quite as much power out, about 5 watts instead of 6 watts but I still have some adjustments to make. I don’t have any immediate plans to release a 30 meter kit, I mostly wanted to see how well the design scales to other bands. I also have plans to build a 20 meter version.


Posted by k1el at 12:01 AM EDT
Tuesday, 31 May 2011
Firmware Work

I have been finalizing the radio firmware for initial release. I had hoped to get some help but ended up doing it myself and it has taken a while.

I added a setup function that makes Rx and Tx alignment very easy, no extra test equipment is required. Also included a frequency display calibration utility.  It used to take about 45 minutes to calibrate the frequency display, set Tx offset, and dial in the Rx BFO, now it takes about 10 minutes, no o-scope required.

New menu driven options makes operation of the radio, in general, much easier. For example the user can now scroll through a list of options and select using the front panel push buttons. Tune, RIT, and keyer speed can still be set directly andquickly by pressing two button combinations. All options are stored in EEPROM so that they are reloaded every time the radio is turned on.

The keyer now works fine (there was an interrupt timing bug)  but I am still fine tuning the Rx/Tx/muting delays, I’ll have to sit down with a scope and dial them in for minimal thump.

The assembly manual is looking very good, I did one final step reordering.  The assembly just didn’t flow smoothly and there were a couple of steps that were very difficult to do after most of the parts were on the board.

I still continue to have fun making contacts and collecting good signal reports.


Steve K1EL

Posted by k1el at 12:01 AM EDT
Sunday, 8 May 2011
Radio Fun

Well, I took the weekend off and instead of working on the radio I decided to make some contacts with it. I lurked around the New England QSO Party and worked some stations there. Tonight I just did some general calling and answering CQs and did quite well. Actually just finished up a QSO with an SM6 ! Very nice opening to Sweden on 40 meters.  Just using a vertical with 6 watts of OQ power. I like the CW reader, it’s certainly a novelty and after a hour or so I went back to head copy, but it’s still fun to challenge it to see what it will or won’t copy.

I am not at all happy with the keyer though, it kept locking up on me, so I am going to rip it out and put my K1EL keyer back in for now. I will revisit the situation later, hopefully it’s some minor implementation bug on my part.  There’s a few other operational things that need tweaking as well, the kind of stuff you discover while making contacts. All and all I am very happy and can’t wait to get more of these rigs out there.

GN de K1EL

Posted by k1el at 12:01 AM EDT
Friday, 6 May 2011
Rerun of Spectrum Plot

Something bothered me about the plot I posted the other day.  The fact that the third harmonic was almost twice the amplitude of the second harmonic didn’t make a lot of sense to me but I didn’t have time to think about it then.

While looking over the radio this weekend and taking pictures for the assembly manual, I noticed that the gate termination resistor on the IRF510 final was not populated. I took a look at the output wave form, pre-low pass filter, and it was ringing like crazy, right around 21 MHz. The low pass filter knocked this down considerably but it was not the way it should be.

So I put in the 12 ohm gate termination resistor and the output wave form cleaned up nicely. This was because the impedance match between the driver and gate circuit was much better.  I got some time on the Spectrum Analyzer at work today and reran the sweep and now it makes sense, as you will agree:

On the Subject of Spectral Purity Requirements,  FCC Regulations State:

97.73 …the mean power of any spurious emission or radiation from an amateur transmitter, transceiver, or external radio frequency power amplifier being operated with a carrier frequency below 30 MHz shall be at least 40 dB below the mean power of the fundamental without exceeding the power of 50 mW.  For equipment of mean power less than five watts, the attenuation shall be at least 30 dB.

From the plot above:

Fundamental level is at -2.6 dbm, 2nd harmonic is at -49.88 dbm, and 3rd harmonic is at -62 dbm.

Closest spur is 47.28 dbm below fundamental, lots of margin there.

<Edit 5-9-2011>

I did a bit more experimenting with the final’s gate termination with the idea of moving the cut off frequency well above 7 MHz.  A 10 ohm in series with .1 uF really knocks the 7 MHz drive down too much. I settled on a 4.7 ohm resistor in series with .001 uF.  This performs very well bringing the power output up a watt or two while still meeting spectral purity requirements. (Plot above was taken with new network in place) Driving the gate a little harder results in the IRF510 being in saturation longer which reduces the MOSFET’s power disipation. I can actually run without a heatsink now.  I won’t eliminate it but I may make it smaller and easier to assemble.

Posted by k1el at 12:01 AM EDT
Updated: Friday, 4 January 2013 9:26 AM EST
Wednesday, 27 April 2011
Kit Discussion

I am at the point where the cost of the kit has been determined.  It was based on actual parts cost with an allowance to cover the labor I will need to pay someone to do the actual production kitting.

The cost for a kit, including all components, backlit display, and enclosure, is $149. USPS Priority Mail shipping cost is an additional $11. International shipping charge will be an additional amount that I have not determined yet, whatever the post office charges that will be the cost.

So I call this the day of reckoning because I have to see if the interest justifies continuing. I have 18 kits that I will be distributing over the next month. I hope to send these primarily to those who are interested in working on the firmware. I will be upgrading the firmware functionality myself for these 18 kits, but I was hoping to get some help to enhance it even further.

If interest justifies it, we will have another 75 kits available in about two months which will have the benefit of more improved firmware.

If you have a genuine interest in buying a kit please email me and let me know so I can formulate a plan. In addition if you are genuinely interested in being a firmware developer on the radio please let me know as soon as you can so I can begin to allocate the 18 kits in queue.

For general interest, here is a shot of the RF spectrum that I took today.  Comparing back to February 2010, you can see the improvements that the transmitter clean up and bias control provide.

73  Steve K1EL

Posted by k1el at 12:01 AM EDT
Updated: Friday, 4 January 2013 9:30 AM EST
Monday, 5 October 2009

October 29th, 2009

The transmitter is installed and works reliably. I’ll cover some of the highlights of the design in this installment. I’m open to criticism on my calculations, I am sticking my digital neck out pretty far on some of this analog world design.


TX Mixer and First Driver Stage


A small amount of VFO feed is taken from the VFO buffer and fed into one port of a NE602A mixer. It is mixed with the local crystal oscillator (4.9152 MHz) to produce sum and difference products. The sum product (4.9152 + 2.084=7.0) is filtered by a 42IF123 IF transformer. This transformer is normally used for 10.7 MHz IF applications but in this case we pad the resonant frequency down with a parallel capacitor of 56 pf. We get a nice peak at 7 MHz by adjusting the slug in the top of the transformer.  The primary side is a high impedance which allows a fairly hi Q filter with a low impedance secondary. The secondary feeds into the base circuit of Q1 which has an impedance of (10K in parallel with 5.6K)  about 3.6K.  The output impedance of the NE602A is about 1.5K which is connected to the center tap of the primary. The turns ratio of primary to secondary is 5T to 2T so the reflected impedance of 3.6K back to the NE602A is (2/5)² times 3.6K = 576 ohms. Not a perfect match but close enough to work ok.  Q1 is the first driver amplifier that has adjustable gain via adjustable trimmer RX1. The outout of this stage has a low impedance of about 100 ohms.


Second Driver Stage and Final


The input impedance of the second driver stage, Q2, is (1K in parallel with 4.7K) 824 ohms. The output of the first stage (100 ohms) plus the reactance of the coupling cap C12 (220 pf=100 ohms at 7MHz) is 200 ohms, a bit of a mismatch there as well. This driver stage uses a second IF transformer to drive the gate of the IRF510 MOSFET final amplifier. Orignally this was set up to be tuned at 7MHz but seems to work better as  an untuned broadband transformer. More investigation is due here. In any case it trnsforms the relatively high impedance of the collector circuit to the low impedance of the gate drive.  The MOSFET gate input capacitance is quite high (around 150 pF) so a low impedance drive is required to overcome this. The MOSFET gate is biased to 5.1V by a zener diode in the gate circuit. This gives us a bias current around 40 ma. When not in transmit mode the bias is removed which drops the idle current to near zero.


Tx Test setup



Waveform at Drain of IRF510 Final


Output Waveform: 60V Peak to Peak  or (60/2) times .7071 = 21.21 RMS Volts

Calculated Power = E²/R       Using measured values: (21.21V)² / 50Ω = 9 watts


Power Meter: 8+ watts !  (meter accuracy spec’ed at +/- 10%)


The prototype base chassis plate is on order, it’ll be a couple more days until it arrives. Since the LCD display is mounted to the main PCB and is also aligned to the chassis front panel I will hold off on the LCD interface for now.  Instead I decided move to the VFO section. I also want to jump ahead and get the transmitter working since I am a little uncertain about how the new IRF510 final is going to work in this PCB revision.


VFO stands for variable frequency oscillator and it determines the frequency the radio operates. I designed the VFO to run in the range from 2.0848 MHz to about 2.1648 MHz. You ask, I thought this transceiver is supposed to cover the 40 meter CW band 7.0 to 7.080 MHz ? The VFO signal is mixed with a crystal frequency of 4.9152 MHz in the first transmit mixer. The mixing process combines the two frequencies in a nonlinear way to produces two new frequencies: (crystal+VFO) and (crystal-VFO).  (4.9152+2.0848=7MHz and 4.9152-2.0848=2.8304MHz).  Side-note, if the two frequencies were combined linearly (.ie non-distorted) the two frequencies would not be mixed but preserved as two separate frequencies. It’s the non-linear transform that fosters the production of the sum and difference products, plus a whole bunch of other undesired frequencies. In our case we are only interested in the difference frequency. This gives us our coverage limits as 4.9152+2.0848=7MHz and 4.9152+2.1648=7.080MHz.

The receive chain also uses a mixer to combine incoming RF and a local oscillator in a slightly different way which we we cover when we get to the receiver.

The VFO uses a Colpitts topology with a split capacitance providing positive feedback to maintain oscillation. A varactor diode is used to vary the oscillation frequency. A varactor diode is a useful device in that it’s capacitance can be made to vary widely by applying a variable DC voltage.  This VFO design is based on a standard implementation, used in many low cost CW transceivers, most notably Dave Benson’s SW series. Varactor tuned VFOs have fallen out of favor in the past couple of years due to the availability of DDS Digital Synthesis ICs from Analog Devices and other companies.  I chose a varactor for two reasons, the first being that DDS ICs are only available in fine pitch surface mount packages, and two it adds a level of hardware and firmware complexity I want to avoid for this radio.  But since I have the CPU to control it, I’ll leave that for a future upgrade.

There are two significant disadvantages of varactor tuning, the first is the limited frequency coverage. Typical capacitance swings of 80 to 250pF are easily obtained but it’s not a linear change with voltage. The second disadvantage is poor temperature stability. I designed the VFO to be as stable as possible so that I only have one contribution to drift from the varactor.

There are several things I did to improve stability. Polystyrene caps, small multi-layer ceramic caps, and a separate 8 volt regulator for the VFO help alot. Also voiding the ground fill out of the VFO area reduces changes in capacitance due to physical dimension changes with temperature. With the varactor control grounded I see about 40 Hz drift from a cold start over a 4 hour period. With the varactor active, the frequency is less stable of course, it seems to be around 100-130 Hz from cold start but I have to wait until I get the tuning pots installed and wired nicely.

One thing I did a little differently in this design is to provide a stage of buffering between the VFO and the feeds to the Tx and Rx Mixers. There is an additional stage of buffering provided to drive the frequency counter input on the CPU.

One final note on the VFO, one thing I really like in a VFO design is a variable cap trimmer to allow for easy calibration. It cost about 45 cents and reduces temperature stability slightly but well worth it.

I will cover the transmitter build next, I’ll take a couple of pictures to post tomorrow,

73 Steve K1EL



I haven’t had a great deal of time to work on the board this week. What little time I did have I spent on Arduino aspects of the project.  I started with a small sketch that simply flashes and LED.

Today I present a basic iambic mode keyer that has adjustable speed and can be configured to operate in iambic mode a or b. At this point all it does is flash an LED in Morse, but it’s a good foundation to build upon.  There really isn’t anything novel about it, it’s the same basic algorithm used by many different keyers. Over the weeks I will add autospace, Ultimatic, and straight keying modes.  I’ll also include the ability to swap paddles. But this will hold us for quite a while.  You can cut and paste this into an empty Arduino sketch, it’s completely self contained. It’ll run on any Arduino board, just wire up a paddle and it will flash the LED. Add a pushbutton switch and you can select between iambic mode a and b. It would be very simple to add a keying output in place of the LED drive, probably a good idea to include a 2N2222 or 2N7000 buffer stage.

#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdio.h>
/////////////////////////////////////////////////////////////////////////////////////////  //  //  Iambic Morse Code Keyer Sketch  //  Copyright (c) 2009 Steven T. Elliott  //  //  This library is free software; you can redistribute it and/or  //  modify it under the terms of the GNU Lesser General Public  //  License as published by the Free Software Foundation; either  //  version 2.1 of the License, or (at your option) any later version.  //  //  This library 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.  See the GNU  //  Lesser General Public License for more details:  //  //  Free Software Foundation, Inc., 59 Temple Place, Suite 330,  //  Boston, MA  02111-1307  USA  //  /////////////////////////////////////////////////////////////////////////////////////////  //  //                         openQRP CPU Pin Definitions  //  /////////////////////////////////////////////////////////////////////////////////////////  //  //  Arduino  OQ PCB                                        OQ PCB    Arduino  //  -------  ------               ___________              ------    ----------  //           RESET-----------PC6 |1        28| PC5---------KEY_TX    Dig19 Ana5  //  Dig0     SER_REPLY-------PD0 |2  o   i 27| PC4---------LCD_E     Dig18 Ana4  //  Dig1     SER_CMD---------PD1 |3  o   i 26| PC3---------CMD_PB    Dig17 Ana3  //  Dig2     WIDE_SEL--------PD2 |4  o   i 25| PC2---------PB_NET    Dig16 Ana2  //  Dig3     SIDETONE--------PD3 |5  o   i 24| PC1---------ANT_XO    Dig15 Ana1  //  Dig4     LCD_D4----------PD4 |6  o   i 23| PC0---------MON_12V   Dig14 Ana0  //           VCC-------------VCC |7  o   o 22| GND---------AGND  //           GND-------------GND |8  o   o 21| AREF--------AREF  //           XTAL1-----------PB6 |9  i   o 20| AVCC--------AVCC  //           XTAL2-----------PB7 |10 i   o 19| PB5---------RIT_ON    Dig13  //  Dig5     FREQ_CNT--------PD5 |11 o   o 18| PB4---------NAR_SEL   Dig12  //  Dig6     LCD_D5----------PD6 |12 o   o 17| PB3---------LCD_RS    Dig11  //  Dig7     LCD_D6----------PD7 |13 o   o 16| PB2---------LPDL      Dig10  //  Dig8     LCD_D7----------PB0 |14 o   o 15| PB1---------RPDL      Dig9  //                                -----------  //                                 ATmega168  //  // Digital Pins  //  int         widePin  = 2;       // Wide filter select  int         STPin    = 3;       // Sidetone output pin  int         LPin     = 9;       // Left paddle input  int         RPin     = 10;      // Right paddle input  int         narPin   = 12;      // Narrow filter select  int         ritPin   = 13;      // RIT & LED share digital pin 13  int         ledPin   = 13;      //  int         antXOPin = 15;      // Antenna changeover control  int         cmdPin   = 17;      // Command pushbutton input  int         keyPin   = 19;      // Transmitter key output  int         lcdEPin  = 18;      // LCD E control output  //  // Analog Pins  //  int         PBnetPin = 2;       // Pushbutton network input  int         pwrPin   = 0;       // Voltage monitor input  //  /////////////////////////////////////////////////////////////////////////////////////////  //  //  keyerControl bit definitions  //  #define     DIT_L      0x01      // Dit latch  #define     DAH_L      0x02      // Dah latch  #define     DIT_PROC   0x04     // Dit is being processed  #define     PDLSWAP    0x08     // 0 for normal, 1 for swap  #define     IAMBICB    0x10     // 0 for Iambic A, 1 for Iambic B  #define     ULTIMATIC  0x20     // 1 for ultimatic  #define     AUTOSPACE  0x40     // 1 for autospace mode  #define     STRAIGHT   0x80     // 1 for straight key mode   //  /////////////////////////////////////////////////////////////////////////////////////////  //  //  Library Instantiations  //  /////////////////////////////////////////////////////////////////////////////////////////  // //  Global Variables  //
ULONG       ditTime;            // No. milliseconds per dit  UCHAR       keyerControl;  UCHAR       keyerState;
////////////////////////////////////////////////////////////////////////////////////////  //  //  State Machine Defines
///////////////////////////////////////////////////////////////////////////////  //  //  System Initialization  //  ///////////////////////////////////////////////////////////////////////////////
void setup()  {
    // Setup outputs           pinMode(ledPin, OUTPUT);     // sets the digital pin as output 
    // Setup control input pins           pinMode(LPin, INPUT);        // sets Left Paddle digital pin as input          pinMode(RPin, INPUT);        // sets Right Paddle digital pin as input          pinMode(cmdPin, INPUT);      // sets PB analog pin 3 as input      
    digitalWrite(ledPin, LOW);   // turn the LED off      keyerState = IDLE;     keyerControl = 0;     loadWPM(15);                 // Fix speed at 15 WPM     }
///////////////////////////////////////////////////////////////////////////////  //  //  Main Work Loop  //  ///////////////////////////////////////////////////////////////////////////////
void loop()  {        static long ktimer;        int debounce;          // Basic Iambic Keyer        // keyerControl contains processing flags and keyer mode bits        // Supports Iambic A and B        // State machine based, uses calls to millis() for timing.      
    switch (keyerState) {          case IDLE:         // Wait for direct or latched paddle press 	if ((digitalRead(LPin) == LOW) || (digitalRead(RPin) == LOW) ||             (keyerControl & 0x03))          {             update_PaddleLatch();             keyerState = CHK_DIT;         }         break;
    case CHK_DIT:         // See if the dit paddle was pressed         if (keyerControl & DIT_L) {             keyerControl |= DIT_PROC;             ktimer = ditTime;             keyerState = KEYED_PREP;         }         else {             keyerState = CHK_DAH;         }         break;
    case CHK_DAH:         // See if dah paddle was pressed         if (keyerControl & DAH_L) {             ktimer = ditTime*3;             keyerState = KEYED_PREP;         }         else {             keyerState = IDLE;         }         break;
    case KEYED_PREP:      // Assert key down, start timing, state shared for dit or dah         digitalWrite(ledPin, HIGH);        // turn the LED on         ktimer += millis();                // set ktimer to interval end time         keyerControl &= ~(DIT_L + DAH_L);  // clear both paddle latch bits         keyerState = KEYED;                // next state         break;
    case KEYED:         // Wait for timer to expire         if (millis() > ktimer) {           // are we at end of key down ?             digitalWrite(ledPin, LOW);     // turn the LED off             ktimer = millis() + ditTime;   // inter-element time             keyerState = INTER_ELEMENT;    // next state         }         else if (keyerControl & IAMBICB) {              update_PaddleLatch();         // early paddle latch in Iambic B mode         }         break;
    case INTER_ELEMENT:                    // Insert time between dits/dahs         update_PaddleLatch();              // latch paddle state         if (millis() > ktimer) {           // are we at end of inter-space ?             if (keyerControl & DIT_PROC) { // was it a dit or dah ?                 keyerControl &= ~(DIT_L + DIT_PROC);   // clear two bits                 keyerState = CHK_DAH;                  // dit done, check for dah             }             else {                 keyerControl &= ~(DAH_L);   // clear dah latch                 keyerState = IDLE;          // go idle             }         }         break;     }
    // Simple Iambic mode select          // The mode is toggled between A & B every time switch is pressed     // Flash LED to indicate new mode.          
    if (digitalRead(cmdPin) == LOW) {         // Give switch time to settle         debounce = 100;         do {                                      // wait here until switch is released, we debounce to be sure             if (digitalRead(cmdPin) == LOW) {                  debounce = 100;             }             delay(2);      
	} while (debounce--); 
        keyerControl ^= IAMBICB;        // Toggle Iambic B bit         if (keyerControl & IAMBICB) {   // Flash once for A, twice for B             flashLED(2);                  }         else {             flashLED(1);         }     }  }
///////////////////////////////////////////////////////////////////////////////  //  //    Flash LED as a signal  //  //    count specifies the number of flashes  //  ///////////////////////////////////////////////////////////////////////////////
void flashLED (int count) {     int i;     for (i=0; i<count; i++) {         digitalWrite(ledPin, HIGH);        // turn the LED on         delay (250);         digitalWrite(ledPin, LOW);         // turn the LED off         delay (250);          }  }
///////////////////////////////////////////////////////////////////////////////  //  //    Latch dit and/or dah press  //  //    Called by keyer routine  //  ///////////////////////////////////////////////////////////////////////////////
void update_PaddleLatch() {     if (digitalRead(RPin) == LOW) {          keyerControl |= DIT_L;          }     if (digitalRead(LPin) == LOW) {          keyerControl |= DAH_L;          } }
///////////////////////////////////////////////////////////////////////////////  //  //    Calculate new time constants based on wpm value  //  ///////////////////////////////////////////////////////////////////////////////
void loadWPM (int wpm) {      ditTime = 1200/wpm;  }

I posted three archive files in the Design Files/Tools area. I will discuss each one and show how to install and build a sketch under the Arduino IDE.

openQRP core: The openQRP implementation is different than a standard Arduino board in several ways. Rather than hack the existing board files I created a custom core file that contains the changes required to support the openQRP board.  It’s easy to install the core, simply click on the file, let WinZip open it up, select all files, and extract to the Arduino/hardware/cores directory:


You should now see the openQRP core folder as shown:


boards.txt: Now that we have installed the core we need to add an entry to the boards.txt file that describes the openQRP board.  You can download the entire boards.txt file from Design Files/Tools and copy over the one in your installation.  The preferred way to do this is to add the openQRP entry to the end of your existing boards.txt file because you may already have some customizations in the file that you want to preserve.

The boards.txt file is located here:


Here is the entry which you can cut and paste into your boards.txt file.


openQRP.name=openQRP via USBtinyISP




sketch_gnu_qrp: Finally we will install a test sketch which can be used to test our environment and make sure everything is in the correct place. First create a folder called sketch_gnu_qrp. This can be placed anywhere you like, it is not a good idea to not put it in your arduino tools folder. I just put it in the root directory of drive C:   Now open up Arduino and click File->Open and navigate to the folder you just made and select the test sketch:


Click Open. You will then see the sketch:


Now select Tools->Board and you will see openQRP via USBtinyISP   select that. If you don’t see an entry for openQRP,  check your boards.txt file to make sure it has an entry for openQRP.

Now select Sketch->Verify/Compile  which will build the sketch and if all is well you will see:


If you do get a bunch of errors and warnings that means the openQRP core wasn’t installed in the right place .

At this point you could upload the sketch to the openQRP board and see the LED flash on and off once a second.

Let’s take a look at the sketch source file. All arduino sketches have at least three basic sections.

The first section is board specific declarations. Here names are given to all of the inputs and outputs pins on the CPU. Descriptive names are much easier to keep track of than numeric values. If you compare these names and pin numbers to the schematic you will find there is no direct corespondence. The definitions relate to Arduino port assignments. There are two types of port pins Digital and Analog.  Analog pins can be used as digital pins but not vice versa.  

/////////////////////////////////////////////////////////////////////////////////////////  //  //                         openQRP CPU Pin Definitions  //  /////////////////////////////////////////////////////////////////////////////////////////  //  //  Arduino  OQ PCB                                        OQ PCB    Arduino  //  -------  ------               ___________              ------    ----------  //           RESET-----------PC6 |1        28| PC5---------KEY_TX    Dig19 Ana5  //  Dig0     SER_REPLY-------PD0 |2  o   i 27| PC4---------LCD_E     Dig18 Ana4  //  Dig1     SER_CMD---------PD1 |3  o   i 26| PC3---------CMD_PB    Dig17 Ana3  //  Dig2     WIDE_SEL--------PD2 |4  o   i 25| PC2---------PB_NET    Dig16 Ana2  //  Dig3     SIDETONE--------PD3 |5  o   i 24| PC1---------ANT_XO    Dig15 Ana1  //  Dig4     LCD_D4----------PD4 |6  o   i 23| PC0---------MON_12V   Dig14 Ana0  //           VCC-------------VCC |7  o   o 22| GND---------AGND  //           GND-------------GND |8  o   o 21| AREF--------AREF  //           XTAL1-----------PB6 |9  i   o 20| AVCC--------AVCC  //           XTAL2-----------PB7 |10 i   o 19| PB5---------RIT_ON    Dig13  //  Dig5     FREQ_CNT--------PD5 |11 o   o 18| PB4---------NAR_SEL   Dig12  //  Dig6     LCD_D5----------PD6 |12 o   o 17| PB3---------LCD_RS    Dig11  //  Dig7     LCD_D6----------PD7 |13 o   o 16| PB2---------LPDL      Dig10  //  Dig8     LCD_D7----------PB0 |14 o   o 15| PB1---------RPDL      Dig9  //                                -----------  //                                 ATmega168  //  // Digital Pins  //  int         widePin  = 2;       // Wide filter select  int         STPin    = 3;       // Sidetone output pin  int         LPin     = 9;       // Left paddle input  int         RPin     = 10;      // Right paddle input  int         narPin   = 12;      // Narrow filter select  int         ritPin   = 13;      // RIT & LED share digital pin 13  int         ledPin   = 13;      //  int         antXOPin = 15;      // Antenna changeover control  int         cmdPin   = 17;      // Command pushbutton input  int         keyPin   = 19;      // Transmitter key output  int         lcdEPin  = 18;      // LCD E control output  //  // Analog Pins  //  int         PBnetPin = 2;       // Pushbutton network input  int         pwrPin   = 0;       // Voltage monitor input  //  /////////////////////////////////////////////////////////////////////////////////////////


The next section is the setup function. This is where we put all of the initializations that are necessary before actually starting the main program loop. This is only called once at power up. All we need to do is specify that the LED pin is an output.


Now we are at the main loop of the sketch:


This function is called continuously after setup() completes. This is where all the action is. In our test sketch the loop continually turns the LED on, waits one second,  turns the LED off, and waits another second. This is repeated forever. The functions digitalWrite() and delay() are built into the Arduino library, all we have to do is call them and they work. A list of Arduino functions can be found here.  Arduino has a great tutorial that I highly recommend.

So what exactly is the difference between the openQRP core file and a standard arduino core ? Well not too much at this point, it’s a good idea to stay as close to standard as possible. This makes life easier when we upgrade to new arduino releases.  In our core, wiring.c has been modified to adjust the timing routines for a 16.384 MHz oscillator and to add a frequency counter capability to the Timer Zero interrupt handler. Two new functions are added: getFrequency() and getTick(). Whenever functions are added to wiring.c they also must be added to wiring.h. While I was in wiring.h I also added typedefs for UCHAR, UWORD, and ULONG.  We’ll talk abut those later. 

Next time I will introduce a very simple Iambic keyer that supports both A and B modes.  Then we will give firmware a rest and move on to install the LCD display and VFO sections.

I’m going to devote an installment to the USBtinyISP programmer I use to upload sketches into the openQRP board. This is a great little programmer kit that you can buy from adafruit for $22 plus shipping. It takes about one half hour to build and about half that time to install. There are great assembly instructions here. I was unable to get the programmer to reliably program boards until I removed zener diode D1 or D2. That could have just been faulty zeners but I’ll just throw it out as a suggestion.

Installation Tips

First of all you need to download the USB driver for USBtinyISP. You can get it from here, make sure you get version v1.12. The download is a zip file which will automatically extract into a directory called usbtinyisp.  You can tell WinZip to put the directory whereever you like, just remember where since you will need to know the path when it’s time to install the driver.

Once you have built the programmer it’s time to test it out. First of all plug it into your PC’s USB port and you should get this dialog box:


Click No, not this time and Continue. The following dialog box will then display:



Click Install from a specific location and Next:


Browse to the directory that you placed the install files then click OK:


Click as shown then Next:


The driver will install and then show the following dialog box, Click Finish


Now unplug the programmer and then start up Arduino. Select Tools->Burn Bootloader->w/USBtinyISP and you should get the following message:


Now plug in the programmer and after 3 or 4 seconds Select Tools->Burn Bootloader you should then get this dialog box:


This means that the programmer was detected but the upload failed because the programmer was not connected to a target board. This is exactly what we want to see, the programmer is ready for the next step.

Next time we will install the openQRP customization itno Arduino and then we can upload sketches.

There was a more of a learning curve with the CPU than I expected. I have been using Arduino microcontrollers for some time now and have quite a bit of experience with them. I started with their Duemilanove board and used that platform for basic software development. When my target board was ready I simply pulled the CPU out of the Duemilanove board, plugged it into my prototype board and continued. This was a leap from using the USB download capability of the Duemilanove board to using USBtinyISP and the ICSP connector to upload sketches to the CPU.

If you look at how most Arduino designs work, the CPU contains a  preloaded bootloader that accepts an uploaded sketch from the serial port and transfers it into the ATmega168′s flash memory program space. The advantage of this process is that it is very simple and easy to use. The disadvantage is that you need to include a USB to serial interface IC in your design and give up about 2K of flash code space for the bootloader.  I did not want either of these things on the openQRP board, instead I opt’ed to use an ICSP connector over which I can upload a sketch directly to flash memory without a bootloader. USBtinyISP takes care of the USB interface link and Arduino supports USBtinyISP so I’m all set. And it worked great on my initial prototypes since I always started with a preprogrammed CPU.

I now proceed with my new openQRP PCB, USBtinyISP, and an empty ATmega168 CPU fresh from Mouser.  I start from scratch on a new PC,  install Arduino, USBtinyISP driver, and build up the openQRP environment. I begin testing with a simple sketch that flashes the openQRP LED off and on every second. I upload that to the board and lo and behold the LED comes on and stays on….. then goes out and back on every 16 seconds. Why so slow ? Recheck the my test code, all looks good. Pop out the new ATmegaCPU and plug in the CPU from the Duemilanove board, upload the test sketch into that…. guess what ? The LED flashes off and on every second ! So what is different between the two CPUs ? The Duemilanove CPU had been preloaded with a bootloader, but  since an upload through ICSP is started directly after loading, the bootloader is not used. After some reading I remembered that there are configuration fuses in the ATmega CPU that need to be programmed. A stock CPU is set up to run on an internal 8MHz clock using an internal divide by eight for a net clock rate of 1 MHz. I had expected a clock rate of 16.384 MHz, roughly 16 times greater. So that’s why the LED flash rate was 16 times slower than I expected. So, how do we program the fuses ? One way is to figure out the fuse settings , use avrdude manually with USBtiny, and program them directly. A much easier way is to use Arduino to download a bootloader because when you do that, fuse programming is included as part of the process.  I don’t care if the bootloader gets programmed, I’m not going to use it, but it is nice to have Arduino set the fuses exactly the way they should be, that gives me one less thing to worry about. And the fuses only need to be programmed once. So that’s what I do. After a minute wait, the process completes, the fuses get programmed and now when I upload my test sketch the LED flashes off and on once a second !

The reason I covered all of this is that it is handy to know how to do this sort of thing if you ever want to build your own Arduino controller.  All of this information can be found in bits and pieces out on the web but it takes quite a bit of work to put it all together.

In the next installments I’ll cover how to install and test the USBtinyISP programmer, how to install the openQRP environment in Arduino, and how to program a target board.

I installed the Arduino CPU complex and it’s operational.  I have been able to upload test sketches* into the CPU through the ICSP connector and test basic functions. I’ll cover the pieces of the CPU complex that were installed:

The CPU is clocked by a 16.384 MHz crystal that is directly attached to the CPU. An internal clock oscillator resides inside the CPU. The CPU has many inputs from different sources on the board. The command pushbutton and paddle inputs have pull-ups to assert these inputs high when the switches are not closed to ground. Five additional pushbuttons are connected to resistors making up a multi-tap voltage divider, when one of these pushbuttons are closed the voltage applied to a CPU input changes which is read by an analog to digital converter inside the CPU. This arrangement allows us to read five pushbuttons with one CPU input pin. By assigning the command pushbutton it’s own separate input, we can detect when two pushbuttons are pressed (command plus one of the five) to double the number of pushbutton states.

The ICSP connector has six pins, two go to power and ground, one goes to CPU reset and the remaining three are used to serially upload sketches to the CPU’s flash memory. These three programming pins are shared with CPU control functions, namely RIT ON, Narrow Select, and LCD Register Select. These are all high impedance lines and are virtually invisible to the programmer during ICSP programming. The RIT ON line also drives an on board LED, this mimics Arduino designs, providing something simple to turn on and off for our initial CPU tests. Not shown in the picture is the paddle input connector, I installed that so I could plug in a set of paddles and write a simple CW keyer that will light the LED.


I had a bit of trouble getting the CPU operating at the correct frequency, this is the first unused ATmega168 CPU I have used and I learned that there are configuration fuses that have to be programmed first. I’ll cover this in the next installment tomorrow.

*sketch is an arduino term for a project file that is edited and compiled in the arduino IDE and then uploaded to the board. It is a much more friendly term than object files, code, source files, etc.

A beautiful weekend here in NH, hiking and family took priority over the OQ board. I did manage to install and check out the system power supplies. After doing a short and open test I always like to verify all power supply sections first.  It’s much easier to debug power problems at the beginning. Luckily all rails checked out fine. There are four main system voltages:

Five volt digital power: CPU, PSoC, VFO sampler, LCD Display

Eight volt analog: VFO, Tune, RIT

Six volt analog: 1st and 2nd Rx Mixer, Diff amp, Active Filter, Audio amp, Analog Switch

Three volt analog reference: Diff Amp, Active Filter, Audio Amp

The transmit mixer and driver stages run off Keyed 12 Volts while the Tx final runs directly off the 12 volt rail. We will test keyed 12V later.

I really like three terminal regulators, a bit more expensive than zener diodes but worth the extra quarter. In addition to being fairly load insensitive, they have built-in over current protection.  (That said, I did use a zener diode regulator for the transmit mixer since it is the only thing on that circuit)  I used three regulators in all, a 7805 (TO-220 package) for 5V, a 78L08 (TO-92) for 8 volts, and a 78L06 (TO-92) for 6 volts. As long as you follow the rules for capacitor placement these regulators provide very clean and stable voltage rails.


An on board power connector is well worth the real estate it takes up, off board connectors float around and eventually short against something while you are debugging and are a big pain in general. (I guess that can be said for all connectors now that I think of it) So once I had everything installed I simply plugged in my power cable and quickly checked all the test points.  The picture shows two pushbuttons on the board, not soldered in, just there to make sure the PCB footprint is correct. The most stressful thing about a new PCB is the whether all the footprints are correct and oriented properly. On the previous OQ board spin I placed the pushbutton switches backwards !  No clean way to recover from that sort of error, instant scrap. Good news is that all footprints in this version are right so it’s clear sailing.

You might wonder what D2 (1N4001) is for,  it’s a polarity protection diode. If you accidentally connect power the wrong way (plus and minus reversed) D2 is forward biased, draws a lot of current and pops the fuse in your power lead instead of electronics on the OQ PCB. It requires that your power lead has an inline fuse holder (which is always a good idea anyway). Some designs put the diode in series with the power lead so that it will only conduct current when the power leads are hooked up right, but this incurs a .7V drop in supply voltage (.7 watts at a current draw of 1A), a consideration if you’re running on battery power. Either scheme is equally good just as long as there IS some sort of protection, it is very easy to hook power up wrong if you are in a hurry or it’s late at night during Field Day….don’t forget extra fuses :)

I am working on a bill of materials that I will post soon. I am breaking the parts up into groups per debug session. It will be a big help as we move along.

Next on the trail is the CPU, I’ll start that tonight. That is where the fun really starts.

The board arrived today, here’s what it looks like. I will start working on it this weekend.


Installing Arduino is very easy to do but it is not a completely automatic process. As mentioned before, we are using Arduino-0017 which you download from here: http://arduino.cc/en/Main/Software

I am using the Windows version, other operating systems are supported but I’m sticking with Windows for now. The file you download is a zip file, 80+MB in size. When the file has been downloaded WinZip will automatically open displaying all of the files in the archive. Next Click Edit->Select All  Then select the hard drive you want to install to, I pick drive C:, then click on Extract and the toolset will be installed into a directory called c:\arduino-0017  (Make sure that “Use Folder Names” is selected)


To make the application easy to find, I add a shortcut and place it on my Desktop:

Right click on your desktop, select New->Shortcut and Browse to C:\arduino-0017\ and select arduino.exe


Click OK and now you will find the aduino icon on your desktop which you can click to bring up the IDE.


Take a look at the file structure of the arduino installation:


The hardware directory contains a file called boards.txt. We will be adding an entry to this file that describes the openQRP board:


openQRP.name=openQRP via USBtinyISP





Several things to notice, we specify the programmer we will be using, namely USBtinyISP. Next we specify the CPU as an ATmega168 with 16384 bytes of code space available. Since we will not be using a bootloader, the entire code space can be used for our application. Even though we aren’t specifically using a bootloader we still maintain the bootloader entries. Finally we specify that our board will use the openQRP core. This is a set of definitions and low level functions that have been customized for openQRP.  This will be contained in a directory called openQRP in the hardware/cores directory, we will install this ourselves.

Posted by k1el at 12:01 AM EDT
Updated: Thursday, 5 December 2013 10:50 AM EST
Monday, 28 September 2009

I finished the final tweaks to the oQ PCB and sent it out for fabrication on 9/25. I have updated the schematic, PCB data files, and schematic data files. These now match the board that is being made. I also updated the Specification as well as a making a couple of website tweaks. This site is built upon WordPress which is a very nice package but it does take lots of work to customize. Even the simplest changes or additions require reading and reading…. In any case it’s pretty close to what I want now.

As soon as the board arrives, sometime around 10/6, I will start documenting the board bring up and make regular posts.

In the final version I changed the final to an IRF510 MOSFET,  these are easy to find and work much better than a standard bipolar design. With the IRF510 I get a nice solid clean 8 watts out.

Posted by k1el at 12:01 AM EDT
Tuesday, 18 August 2009
Schematics Uploaded

One car accident and one new K1EL kit release later, I am finally getting back to the openQRP project.  The ‘proof of concept’ board is up and running but it really did not come up as cleanly as I hoped it would.  So today I posted, what I hope to be, the final oQ transceiver schematics along with a block digram and specifications. You can access them through the Reference link on the right hand sidebar, these are all in pdf format. I’m still working on some things and there might be a tweak or two before I send the release board out for fabrication. The previous board design (REVA shown on the February post) was a good learning exercise and was well worth the effort, one more clean up cycle should do it.  If anyone has any comments or suggestions please post them in Design Discussion are of the forum.

I have also posted the schematics and PCB layout source files in the Design Files/Tools section as well. You will need to download and install the appropriate design tools to view these files.

Thanks, Steve K1EL

Posted by k1el at 12:01 AM EDT
Thursday, 5 February 2009
First Entry, Boards are In !

I will start this off with the arrival of the ‘oQ’ prototype PCB.  This is a ‘proof of concept’ board, used mainly to debug the Ardunio implementation and transceiver interface.  Over the next few months I will cover the bring up of the board and in doing so introduce the design. 


Posted by k1el at 12:01 AM EST

Newer | Latest | Older