Archive for the ‘ Radio ’ Category

Audio Adapter for the Si5351 Signal Generator

I had just finished building a three port RF signal generator when the January 2018 QST arrived in the mail. January is the annual Do It Yourself issue and there was an intriguing article by Keith Kunde, K8KK titled “A Low Distortion Digital Audio Oscillator”. The heart of Keith’s circuit is a MAX294 filter chip, a sophisticated 8th order switched capacitor filter capable of rounding off a square wave into a pretty good sine wave. The ‘294 is fed with a square wave at the desired frequency and also a clock signal 100 times the desired frequency. Keith generates his clock with a 555 timer and then feeds a divide by 128 chip to develop the base output frequency. My new Si5351 RF generator could be a crystal controlled clock source and all I would only need the divider and filter circuits to add audio capability. The MAX294 costs about six bucks each.

Goals for the Audio Adapter were:

  1. 20 to 20000 Hz capability
  2. Sine or Square wave output
  3. Line level output, one volt peak to peak into 600 ohms
  4. Be as portable as the signal generator, meaning battery operation in an Altoids tin
  5. Two channels
  6. Direct frequency readout from the signal generator display

That sixth requirement means decimal dividers throughout. If I add one additional decade to the ‘294 chip’s clock divide by 100 requirement, the total division would be 1000. When the signal generator display shows 25 megahertz, the output would be 25 kilohertz. No math necessary.

The MAX294 has an uncommitted on board op amp but it is intended as a pre or post processing filter and has weak output specs. To get line level output I decided to buffer the ‘294 output with an LM358 op amp connected as a voltage follower. Later on, this proved to be the most troublesome part of the project.

Internet searching did not turn up many choices for decade frequency dividers. I decided on the 74hct390 chip which I have used before. It’s a dual decade divider, each side has a divide by two, and a divide by five stage. Cascading these gives a divide by ten with BCD output of the counter state. For this two channel build I would need a total of ten divide by ten stages, achievable with five 74hct390s. This diagram shows the basic filter wiring.

Basic MAX294 Application

Basic MAX294 Application

The last divider stage is a divide by two so the ‘294 filter sees a symmetrical square wave. 100k and 39k resistors form a voltage divider network to get the TTL level square wave down to an amplitude the ‘294 can handle without clipping.


I decided the project was indeed viable and ordered parts from Digikey.

Software in the signal generator was tweaked to have a lower range limit of 100 Kilohertz. The Si5351 should go all the way down to 10 Khz with appropriate software support but rather than press my luck, I added two additional decade divider stages to the design. A three position switch selects a frequency tap from the chain so the frequency ranges are:

  • Divide by 10**3  100 to 25,000 Hz
  • Divide by 10**4  10 to 2,500 Hz
  • Divide by 10**5  1 to 250 Hz

With the additional ranges, I can still read the LCD display directly but have to mentally move the decimal point. The first requirement is met. Also added is an SPDT switch to connect the op amp input to either the filter input (square wave) or the filter output (sine wave). That meets the second requirement.

Digikey parts finally in hand, I bread boarded the circuit. The dividers are on the left, the op amp is on the right.

Audio Adapter Breadboard

Audio Adapter Breadboard

This is the final schematic of the filter circuits. Eagle made the drawing and I did go through the exercise of generating a PC board  just to see if there really was room for the parts.  Since the project is a one-off, I built everything on perf board, using 30 gauge wire wrapped around IC pins with my standard wire wrap tool – a ballpoint pen refill. It would have been a lot faster if I had a real PC board.

Analog Board Schematic

Analog Board Schematic

Analog Board

Analog Board

A 2000 mAh portable USB power pack was sacrificed to obtain an 18650 battery, it’s associated charger, and 5 volt up converter. That would satisfy the portability requirement. I stuffed the battery, charger board, four RCA jacks and three slide switches into an Altoids tin while waiting for Digikey.

I used Eagle to generate a schematic and proposed PC board for the higher level digital divider circuits. This board had to fit between the 18650 battery and the range switches, and I had to nip off the corners to work around the battery charger circuit. This board is mounted on #4 screws soldered to the bottom of the Altoids tin. I built the digital divider board first, it is much simpler than the analog boards.

Digital Board Schematic

Digital Board Schematic

Digital Divider Board

Digital Divider Board

I used the analog portion of the bread board to verify the digital dividers were working properly. I found the 74hct390 chips would accept a signal as high as 90 MHz. They will be loafing at 25 MHz. This photo shows the digital board seated in the bottom of the Altoids tin. Only six wires will connect to the analog board in the tin lid, 5 volt power, ground, two divided outputs from the range switches, and two audio output leads. Audio connects to 1000 ufd  capacitors nestled on either side of the battery.

Digital Divider Board and Charger Installed

Digital Divider Board and Charger Installed

Now came extensive testing on the breadboard. Keith Kunde’s QST article discusses the level and DC offset considerations of the MAX294 filter when used with a single ended supply. I used a pair of 10k resistors to create a half supply voltage virtual ground and bypassed that rail with 22 uF capacitors.  I’m using DC coupling between the dividers, the filter chip, and the op amp so had to do some fussing with the voltage divider parameters Keith talks about to get a filter output with no clipping. My final divider has 100k resistor in series with the TTL level divider output, and a 36k resistor to virtual ground. I also found that connecting a VOM in series with the 5 volt supply to measure current seriously upset the DC balance for some reason. It appears the final circuit will draw about 25-30 milliamps from the battery. At that rate, the adapter should run 60 hours on a charge.

But the output waveform from the LM358 buffer amp was horrible! To make a long story short, Google “LM358 Crossover Distortion”.  The ‘358 has a class B push pull output stage and when the signal crosses over from one side to the other it takes a short nap. After a good bit of troubleshooting and research, the fix is simple. Add a 1000 ohm resistor from amp output to ground. This forces the output stage into a class A region and I was able to get 2 volts peak to peak out with no glitches and it will drive a 100 ohm load with no clipping or distortion.  I believe 2200 ohms to ground will also work and draw less current through the amp.

Also the ‘358 has a slow slew rate which causes the sides of the square wave to lean noticeably.   If I knew then what I know now I would have ordered an MC34072 amp which has better specs and no crossover problem, still less than a dollar.

The following photos are the analog board top, bottom and trial fit into the lid. The board is supported in the Altoids tin by the pot mounting nuts at the front and a single L shaped bent paper clip soldered to the lid at the back. I’ve also added an LED in the lid to remind me to turn the power off.

Top of Analog Board

Top of Analog Board

Bottom of Analog Board

Bottom of Analog Board

Connecting Digital Divider Board to Analog Board

Connecting Digital Divider Board to Analog Board

I took a couple of weeks part time to wire and debug the analog circuits but I was finally satisfied and mounted the board in the Altoids tin lid. It JUST clears the battery and the inductor on the battery charger. This photo is as finally assembled. Note a small bit of blue clay on the charger inductor, that’s how I checked the clearance.

Interior of Finished Audio Adapter

Interior of Finished Audio Adapter

These are the money shots of the fully assembled Audio Adapter.

Dual Channel Audio Adaptor

Dual Channel Audio Adaptor

Dual Channel Audio Adaptor

Dual Channel Audio Adaptor

But does it work?

This shot has sine wave selected on one channel and square wave selected on the other.

MAX294 Filter Out and In

MAX294 Filter Out and In

A 10 KHz sine wave. As K8KK noted in QST, there is some clock noise on the wave form at 100x the output frequency.

10000 Hz Sine Wave

10000 Hz Sine Wave

This is a 1 (ONE!) Hz sine wave. Notice the sweep speed setting on the right. It took some creative manipulation of room lights and the camera shutter speed to get this to show properly. You can definitely see the clock noise on this trace.  It looks a lot like the synthesized sine waves I experimented with a couple of years ago.

One Hertz Sine Wave

One Hertz Sine Wave

The next two photos show the waveform when the two channels are combined in an external resistor network. 1500 ohms from either side to a junction, then 1500 ohms to ground to load the signal.

Combined Waveform: 10000 + 10500 Hz

Combined Waveform: 10000 + 10500 Hz

Combined Waveform: 1000 Hz + 1100 Hz

Combined Waveform: 1000 Hz + 1100 Hz

Finally, here is the family connected together to the resistive combining network.

Set Up for Combined Waveform Test

Set Up for Combined Waveform Test

This was an enjoyable but sometimes frustrating project. It’s definitely the densest thing I ever built and would be much simpler if I wasn’t too cheap to order a PC board. I learned that 0603 resistors are not a good choice for hand soldering. I learned that LM358 op amps suck. It is working great now though, and even though I have two other audio oscillators, this is a welcome addition to my test equipment stable.

de WB8NBS/9



April 27 2018:  I acquired a Brother P-touch labeler. Labels help my feeble memory. The P-touch came with a short reel of 12 mm black on white background – these labels were made in two line mode which fits well on the edge of the lid. I will probably replace them with black on clear sometime as that would better keep the Altoids theme.

PTouch Labels Added

PTouch Labels Added


Arduino – Si5351 Powered Signal Generator

Arduino-Si5351 Signal Generator

Arduino-Si5351 Signal Generator

Device Description

For a long time I wanted a general purpose signal generator. Now Direct Digital Synthesizer hardware is available on a single programmable chip. The Analog Devices AD9851 is used in many ham radio projects, also widely used is the Silicon Labs Si5351. Either of these can be obtained from many sources such as Adafruit, Sparkfun, or on EBay and there’s lots of information on the internet. Even Amazon has them. A few dollars gets a DDS chip that will tune continuously from audio to VHF mounted on a small breakout board. I purchased an Si5351 board from Etherkit because they offer a version with a TCXO.

Silicon Labs makes the Si5351 in several variations. It’s intended use is as a multiple output clock generator with up to eight individually programmed frequencies. Most commonly available breakout boards though, use the A version with three outputs. Digikey has the bare chips for less than $1. Connectors are optional, most boards are set up for SMA female jacks. The signal generator I built brings out all three outputs but I used good old RCA phono jacks. SMA connectors are wonderful but the cables to use them are pricey. My box will be used to check and align receivers so precision impedance control is less important.

AD9851 chips have a real Digital/Analog converter on board, it uses an amplitude lookup table to produce a fair sine wave. The data sheet says:

“The AD9851 uses an innovative and proprietary angle rotation algorithm that mathematically converts the 14-bit truncated value of the 32-bit phase accumulator to the 10-bit quantized amplitude that is passed to the DAC. This unique algorithm uses a much-reduced ROM look-up table and DSP to perform this function.”

which sounds suspiciously like the quarter wave sine synthesis I experimented with a few years ago. I’ll have to revise my WordPress pages about quarter wave DDS techniques to include the phrase “angle rotation algorithm”. The price for pure sine wave complexity is, the device has only a single output. In contrast, the Si5351 outputs a square wave on all it’s ports – it is intended to serve as a programmable frequency clock source but for my purposes I don’t care and the available multiple outputs are attractive.
I breadboarded the Etherkit breakout along with one of Paul Stoffregen’s Teensy-LCs I had on hand for the controller. A Teensy-LC has an ARM Cortex M0 heart clocked at 48 Mhz. An ordinary 16 Mhz Arduino would probably work in this circuit but would have trouble with sweep. I used basic software from N6QW to get started and my oscilloscope soon showed it was working. Then a series of enhancements to the N6QW sketch followed:
  • expand to controlling all three outputs
  • setting up frequencies using rotary encoder and LCD menus
  • save and restore setup in EEPROM
  • add output power change to the menus
  • add  output OFF to the power menu
  • add sweep capability with menu control

The Box

A thin metal gift card box was cut up to form an enclosure for the generator. It is about a quarter inch larger than the usual Altoids tin in all three dimensions. I needed the extra volume to fit in a battery and charger removed from a cheap phone power pack. These booster packs usually contain a single 18650 cell and it just fits.

Arduino-Si5351 Signal Generator Interior

Arduino-Si5351 Signal Generator Interior

The components are, top to bottom, blue 16×2 LCD board supporting the Teensy-LC. The entire unit can be 5 volt powered either from the Teensy USB jack or from the battery charger, I added a fat diode to isolate the two sources.  Both the Teensy and the Si5351 board are using their on board voltage regulators. The LCD is five volt, but the Teensy-LC does not have 5 volt tolerant inputs. There are 2.2k resistors between the LCD data pins and the Teensy to smooth over that discrepancy, these would not be necessary if the LCD was a 3.3 volt unit. The pot below the Teensy adjusts the LCD contrast.
At left below the LCD is the Adafruit (Bourns) rotary encoder. It just clears the battery. Right of the encoder is a strip of perf board with the three output select pushbuttons mounted. The LCD, encoder and buttons are Adafruit parts.
At the top of the open box bottom is the salvaged 18650 cell. The measured drain of the whole circuit is less than 100 milliamps so the battery should last half a day at least. The gooey glob at the center is a 2.5 amp fuse. To the right of the battery is the on/off switch and isolation diode. The salvaged Lithium charge/boost circuit is the green board at bottom right. It has it’s own separate USB jack because the USB data leads are not accessible. To program the unit you have to plug into the Teensy USB jack.
Finally the blue board in the bottom is the Etherkit breakout. The actual Si5351 chip is at the left end, next to the TCXO. There are three RCA output jacks mounted in the left side of the box, the fourth jack next to the handle is for syncing the scope when sweeping.


On power up the unit reads saved frequency settings from EEPROM. The display then shows frequency, current port selected, and the output power setting.

Click one of the three buttons to change the port selected to display on the LCD.

Rotating the encoder knob will change the frequency digit under the flashing cursor. Press click the encoder knob to change the digit under the cursor, you can set the cursor to change digits from 1 Hz to 10 MHz.

Hold one of the port select buttons down and turn the encoder knob to change output power for that port. The chip has choices of 8 milliamps, 6 mA, 4 mA, 2 mA, and OFF. Silicon Labs’ spec for driver impedance is 50-85 ohms.

If any of the above settings are changed, the software waits ten seconds, then copies the current settings into EEPROM. In the event the unit gets confused, it can be restored to last saved settings by cycling the power switch. Also it can be returned to default settings by holding down all three port select buttons, while powering up.

Arduino-Si5351 Signal Generator Frequency/Power

Arduino-Si5351 Signal Generator Frequency/Power Setting


Sweep Function

Sweep is accessed from a separate menu. Press down the encoder knob for more than two seconds (a long press) and release to enter sweep parameters for the currently selected port.  A short click of the encoder knob will advance the menu through the sweep choices, currently +/-  0, 1000, 5000, 15000, 50000, or 150000 Hz. The unit sweeps from frequency minus that amount to frequency plus that amount so the total width of sweep is twice the setting. Sweeping is done by reprogramming frequencies in 20 steps between the limits.

A second long press of the encoder knob will return to the frequency menu. The letters “sw” appear on the LCD to indicate that that port is set up to sweep. All three ports can be set up but only the port currently selected in the display will be sweeping at any given time.

A pulse is available at a phono jack on top of the box to trigger an oscilloscope at start of each sweep iteration.

Sweep parameters are not currently saved in EEPROM.

Arduino-Si5351 Signal Generator Sweep

Arduino-Si5351 Signal Generator Sweep Setup Screen


The Software

I am using the Si5351 library from Etherkit. I added a function to completely disable the output drivers to save battery when a port is set to “OFF” so I will include the library in the zip file.
Most of the sketch, implementing multiple port and the menus, was straight forward. The one thing that gave me fits was the quadrature nature of the rotary encoder. This is a mechanical switch and it glitches. Not a problem if you are say, setting an analog output from 0 to 1023, you probably wouldn’t notice but if you need to change a digit by exactly one, glitches are intolerable.  Conventional debouncing a switch usually just waits a certain amount of milliseconds after a transition is detected, read again and proceed. There are debounce libraries for doing this. I had no luck. I finally found an post by Oleg Mazurov about treating the quadrature pulses as a Gray code. It helped a lot and I posted about my findings in the Adafruit Feather forum.
The Adafruit rotary encoder outputs four state transitions on each of it’s 24 rotary detent positions. To get one increment per detent, I tried skipping four state reads with a software counter but it was still glitching if the knob was inadvertently touched. What finally worked was changing the Gray code decode table to disallow all but one positive change and one negative change. The allowed changes remaining are in the middle of the detent so glitches near the resting position are unlikely.
Sweep is accomplished by reprogramming a port frequency on the fly. Tests indicate this is slow and the 20 step sweep takes about 65 milliseconds which limits the sweep rate to about 15 per second. I found a very good way to time something is to write a 1 to some output pin at the beginning, then write a 0 at the end. It’s easy to see exactly how much time the intervening code took by measuring the pulse on an oscilloscope. The send_frequency function takes 3.5 milliseconds. Looking at the Si5351 library, the set_freq code is long and complex. It might be possible to speed this up by using the set_freq_manual call but I’m not smart enough to do that. Porting this code to a 16 Mhz Arduino might make the sweep unusably slow.

Addendum April 4, 2018: Amplitude Modulation Experiment

I thought I might try generating an AM modulated signal by summing three generator outputs.  A 1.1 MHz signal modulated  at 1 KHz would have a 1.100 MHz carrier, a 1.101 MHz upper sideband at half the carrier amplitude, and a 1.099 MHz sideband at half the carrier amplitude. I breadboarded a resistive combiner as follows:
Resistive Combiner

Resistive Combiner

The Si5351 was set to equal drive power on all three outputs.  I examined the output on the oscilloscope, channel 1 connected to AM Out, channel 2 to Audio Out with sync taken from Channel 2. The result is not encouraging. It does output an amplitude modulated signal but the waveforms are bizarre. I see a blocky square wave changing at a 1000 Hz rate but there is some phase problem I can’t control.  This is the best I could capture:

AM Modulated Signal

AM Modulated Signal

Connecting an audio amp and speaker does show a 1 KHz tone if the phases happen to line up just right. I found that setting any one of the generators to be one Hz off frequency results in a rolling pattern with about a one per second beat note in the speaker.

This method of faking Amplitude Modulation is certainly not precise or controllable. Setting one of the outputs off frequency by a few Hz does give a useful warbling tone in an AM receiver.


A zip archive is available including sketch source, the Si5351 library, and a schematic
Jan 4, 2018 V1.1 including the sweep function
 Jan 5, 2018 V1.11 Sweep bug would not change freq while in sweep mode. Cleaned up schematic.

Arduino Iambic Keyer – 2017

Last spring I started doing what I call “Morse Walking”. Going out with headphones on, beeping morse code. I’m doing this hoping I will get good enough at morse to actually use it on the air without making a fool of myself. I previously made two battery operated Arduino based keyers here and here that can generate random morse characters. But they are awkward, the 2015 version requires an external battery and the 2016 model won’t fit in my pocket. Obviously I needed another project.

Arduino Feather keyer

Arduino Feather keyer


I decided to use an Adafruit Feather, it has an Atmel 32u4 processer, built in USB interface, a charger/converter for a 3 volt lithium battery, and plenty of pins brought out. The idea was to cut down the previous keyer software to fit the 32u4 equipped with only the hardware I needed for battery powered practice. Like many of my projects, putting it all into a small box proved to be difficult. Not many parts in the schematic but that Altoids tin is only 2 1/4″ x 1 1/2″ and about 1/2″ deep.

Arduino Feather Iambic Keyer Schematic

Arduino Feather Iambic Keyer

Note the unusual wiring at the headphone jack. Ring is grounded while tip carries the signal. Sleeve is not connected. This puts the two headphone elements in series and presents a higher impedance to the output circuit. The ring normal contact can then signal power enable to the Feather when the phones are plugged in.

I sawed about a quarter inch off the breadboard end of the Feather to make it fit, along with two phone jacks, in an Altoids Small tin. I wired up the Feather along with a quadrature rotary encoder which I thought would be cool to use as a volume control. Porting the previous keyer sketch to the 32u4 proved more difficult than I expected. The encoder required major changes to the keyer code as volume control is now in software and requires manipulation of the sine wave synthesizer tables. I got that part mostly working but set the project aside in May.

So now it’s November and I’ve picked up the little keyer again. The software has been revamped and now has these features:

  1. Characters to be sent are buffered in an asynchronous circular queue so memory buttons or keyboard characters can be “typed ahead”.
  2. USB serial terminal is supported as a keyboard for sending or function programming.
  3. Paddle generated morse is interpreted and printed as ASCII letters on the serial terminal.
  4. Four programmable memories available with 251 character capacity each.
  5. Memories programmable from serial terminal or from the paddles.
  6. Random code practice modes, letters, letters and numbers, letters numbers and punctuation.
  7. Adjustable character spacing in code practice mode (Farnsworthiness).
  8. Morse character speed settable 10 to 45 WPM.
  9. Sidetone frequency settable 100 to 1200 Hz.
  10. Synthesized sine wave sidetone with leading and trailing edge envelope shaping.
  11. Memories and operating parameters stored in EEPROM and easily reset to defaults.
  12. Stand alone operation from LiPo battery.

I went for an hour walk today with the keyer in my shirt pocket and it performed flawlessly so I consider it done.

This is a photo of the unit with battery removed.

Arduino Feather keyer battery removed

Arduino Feather keyer battery removed


I had to move the JST connector to the side to get clearance, the battery would not fit under the rotary encoder. There are four memory buttons, plus the back switch on the encoder used for Function. I’m using my usual analog read routine to debounce the button switches. Metal cap switches from Adafruit, work much better than the 6mm plastic buttons I used in previous versions.

You can see here the battery just fits.

Arduino Feather keyer with battery

Arduino Feather keyer with battery


I spent quite a bit of time working on the waveform generation setup. The encoder routine generates a number 0-64 which is used to scale the synthesizer waveform. Four 16 byte amplitude tables must be regenerated in RAM each time the volume is changed. Initially the sine waves were horribly distorted so I made a spread sheet helped to see what was happening. I was able to work out code that produced a good stepped morse element.  There is very little audible clicking now at beginning or end of the morse elements.

This photo is a dit at about 25 WPM.

Arduino Feather keyer waveform

Arduino Feather keyer waveform

The software, detailed operating instructions, schematic, and spreadsheets can be downloaded from Dropbox.
Any future revisions will appear here

Version 1.0 12/3/2017

Version 1.2 12/6/2017 Was running out of memory, rearranged startup and moved stuff to PROGMEM

Jim Harvey –


More Fun With Direct Digital Synthesis: Adafruit Feather 32u4

Feather Port with Volume Control

Long walks are a good thing and I’ve taken along one of my morse code keyers running in practice mode to pass the time. Neither of the keyers I made fit pockets very well so I decided to build yet another one, battery operated, with headphone only output. The target container is an Altoids Small tin easily carried in a shirt pocket.

An Adafruit Feather 32u4 Basic has built in USB and an on board battery charger so it is a good start for this project. I ported my previous 32u4 code easily. Reference my previous page on the 32u4 experiments here. Driving headphones directly from a Pulse Width Modulated output is different from my previous projects where I used a small audio amplifier to drive a speaker. Headphones have a much lower impedance than an amp so RC filter components change radically. Implementing a volume control would be a challenge. I tried a 500 ohm trim pot and that worked fairly well with some but not all of the headphones I tried. But I couldn’t find a pot with a shaft that would fit in the Altoids tin.

With PWM Direct Digital Synthesizer generating a sine wave I might be able to throttle the PWM output with software. I have an Adafruit Rotary Encoder that fits the Altoids tin if I’m careful so I worked that into the demo program.  Rotary Encoders are basically mechanical, therefore subject to contact bounce like any other switch. I Googled up a half dozen different Encoder sketches and all of them would glitch badly. I finally found code by Oleg Mazurov that uses a Grey coding technique to ignore invalid inputs. It works well. I was able to get that code running on the Feather and contributed the sketch to the Adafruit Feather forum.

This photo shows the slightly truncated Feather in the Altoids Small tin. The encoder is the green object in the center of the lid. There are a couple of Oscilloscope umbilicals attached and the battery is not yet installed.

Changing the apparent volume of the DDS output is a process of multiplying the Sine table values by a volume parameter between zero and one. I copy the Sine table into RAM and apply this transform. But since I use only integer math in the sketch, the method is, read the value from flash then multiply by 0-63 volume, then divide the result by 63. Close enough.

One more improvement: in the original sketch, even when the volume is set to zero the PWM signals are 50% high and 50% low, averaging zero as far as the Sine wave coupled through the output capacitor is concerned. That means the output pin is still driving full voltage at the PWM frequency. With the low load impedance it’s a significant drain on the DC power and I’m using a very small battery. The remedy was to lower the zero crossing base line in step with lowering the amplitude of the Sine table.  A new volatile variable maxSine passes the necessary correction to the DDS Interrupt Service Routine. The ISR doesn’t like having it’s variables changed on the fly. Rotating the Encoder makes a scratchy sound like a dirty potentiometer but it’s fine when you stop adjusting.

I measured 18 milliamps constant draw from the USB supply before implementing the zero crossing shift. With the shift, current varies from 10 ma at zero volume to 17.6 ma at maximum volume. The 150 mah battery should last 6-10 hours, way more than my morse code attention span.

My example sketch with all the experimental options in the previous version is downloadable from Dropbox. A short video showing the waveforms produced is on YouTube.



Arduino Iambic Keyer 2016 – Part 1: Hardware

Third Generation:

Arduino Iambic Keyer - Top

Arduino Iambic Keyer – Top


Arduino Iambic Keyer - Left Side

Arduino Iambic Keyer – Left Side


Arduino Iambic Keyer - Right side

Arduino Iambic Keyer – Right side


In a Chicago winter it’s way too cold in the garage for woodworking, so I turn to coding to pass the time. In 2014 I built an ATTINY85 Morse Code keyer in an Altoids Small box and in 2015 I expanded that with an Arduino Pro Mini based keyer in a regular Altoids tin. It was a lot of fun and consumed pretty much the whole winter. I’ve written down a few ideas for enhancements and in this year’s model some of those are implemented. The hardware wish list (so far):

  1. Battery power, enabling stand alone operation > 24 hours
  2. LCD display 16×2 minimum
  3. Real Time Clock, Local and GMT
  4. More memories (7 or 8 buttons)

Batteries and LCD won’t fit in an Altoids tin. I found a metal Crayola box at Tuesday Morning. It was made by the Tin Box Company, who produce many designs that would make interesting project enclosures. It is 3″ x 5″ x 1.5″, about three times the volume of an Altoids box, the metal is slightly sturdier than Altoids but still flimsy enough to be difficult to work without distortion. I found the inside surface was coated with a thin layer of something which repelled solder unless sanded a bit first. I don’t see this particular box available any more but there is a slightly larger version. My experience indicates that the time to complete a project is inversely proportional to the size of the enclosure (maybe to the fourth power).

Unmodified Crayola Box

Unmodified Crayola Box


These days “Arduinos” come in many shapes and varieties. The latest official 1.6.7 IDE is almost 100 megabytes, expanded to accommodate different versions.  I wanted to try processors other than the standard ATMEGA328, so last summer bought a Teensy2.0 (32u4) and a TeensyLC (ARM Cortex M0) made by PJRC. Both promise built in USB client support. The PJ in PJRC is Paul Stoffregan, who has contributed a great deal to the Arduino community. There’s an IDE add-on “Teensyduino” that must be downloaded from the PJRC site to use Teensy boards. Teensyduino installation is dead simple and includes Teensy versions of most familiar Arduino libraries plus a few useful additions from Paul.

Last summer I worked with the Teensy2.0 a bit, wanted to see if the DDS sine wave generation function I used in the 2015 design would work. The port was successful, the 32u4 required only a few minor tweaks, and I even got Fast PWM working as described in Atmel’s documentation. PJRC has a forum where you can brag about your accomplishments so I wrote something on the 32u4 DDS sketch thinking it might be useful to others. Paul Stoffregan replied suggesting I consider a Teensy3.2 as it has an integrated Digital-Analog Converter which would produce a cleaner waveform. I fired up the similar TeensyLC and used Paul’s suggested method. DDS on the TeensyLC was also successful so I built a breadboard version of last years keyer using the LC.  Everything worked with PJRC’s libraries including DDS side tone, the PS2 keyboard, and lcd.prints added for the display.

The small module at the upper left of the breadboard is an Adafruit PAM8302 audio amplifier. Last year I struggled with a 1 transistor class A amp for the speaker, gave up on that and built an LM386 design. The PAM8302 amp at only four bucks is clearly a winning choice. The only problem I had was later on I discovered the Output side did not like being grounded and I had to insulate the external speaker jack.

First Breadboard - TeensyLC

First Breadboard – TeensyLC


TeensyLC has one serious limitation for my application. Because the ARM chip handles flash differently than the MEGA328, TeensyLC has only 128 bytes of emulated EEPROM. That meant limiting stored button memory to four messages only 30 characters each. At that time I was thinking about adding a Real Time Clock so looked at getting Adafruit’s FRAM breakout and their DS1307 RTC. But for less money than these two modules plus a TeensyLC I could get a Teensy3.2 module with a Cortex-M4, lots of memory, built in RTC, and 5 volt tolerant inputs. I sent off an order to Adafruit (10% off if you watch “Ask An Engineer”).

Teensys have lots of I/O pins, same spacing as the LCD modules, so I elected to mount the Teensy board directly on the LCD.  One 3 pin header and one four pin header is needed. In the next photo you can see the headers with two short gray spacers to separate the PC boards. I had to flatten one of the LCD bezel mounting tabs for clearance but the mount is very compact and rigid. Note to self: make sure you don’t need any more connections to the bottom of the board before soldering down the headers.

I had the idea to use a software driven flashing LCD back light to indicate a flat battery. ARM I/O pins are limited to 9 milliamps each, not enough for an LCD back light so a 2n2222 transistor was glued in to act as back light current switch. The trim pot on the right is for adjusting LCD contrast. It is across the back light LED pads, did not work out well, as later in development I am PWMing the 2n2222 to get adjustable back lighting. So the trim pot has been moved up on the LCD board, epoxied in place, and hard wired to ground and +3.3 volts.

Teensy3.2 Grafted on to LCD

Teensy3.2 Grafted on to LCD


The two wires leading off the right end of the Teensy go to a CR2032 backup battery for the Real Time Clock, and you can just see the Adafruit 32KHz crystal added on the bottom of the Teensy. With this minimal configuration I was able to test and experiment with the built in RTC using the example program furnished with the PJRC Time library, modified with LCD prints.  Initially setting the clock was a problem, you need to send a “T” followed by Unix time (seconds since 1970) into the serial port. I worked out this Linux incantation to get the proper format for Central Standard Time:
echo T$[`date +%s` – 6 * 3600]

Then copy “T1453151560” and paste into the Arduino serial window.  Once the clock has been set it takes care of itself though I’m not sure how. I believe it reads and sets time from code uploaded from the compiler. The Time library is more than a little obscure.

Clock Testing Processor/LCD Sandwich

Clock Testing Processor/LCD Sandwich


Of course many wires have to be added to interface Teensy with the rest of the keyer. It’s not so neat looking now, I’m using nearly every I/O pin plus power from the built in 3.3 volt regulator. I use mostly 24 gauge wire, solid if connecting to other points on the lid, stranded if routing to points below. I have an old Ungar fine tipped soldering iron plugged into a Variac set to about 70 percent.

Processor/LCD With Necessary Wiring

Processor/LCD With Necessary Wiring


There are three auxiliary perf boards in the design, One mounts seven memory switches, another holds volume control, transmit LED, and the Function button, the third has clock battery and an optoisolator for transmitter keying. These boards were carefully laid out on paper, then cut out and marked up so mounting holes could be located. Working with a hinged lid box you have to be careful to leave extra clearance for the lid to close. I did have to file a bit off the button board and the speaker.

The box needs a couple dozen holes to mount parts. Blue tape was applied to all surfaces, a layout drawn on the tape, then all holes center punched.  I start with my smallest drill bit in a drill press then enlarge 1/64 at a time to final size.  A few holes required fine tuning with a tapered reamer.  I made a rectangular cutout for the LCD bezel by using a wooden template screwed to the lid, then cutting with a 3/16 carbide router bit surrounded by a 1/4″ collar. Mounting hardware is mostly 2-56 with a few 4-40 spacers.

Crayola Lid Drilled

Crayola Lid Drilled


I had a pair of paralleled 18650 cells taken from a cell phone charging pack. These are fastened in the box by a strip of tin can metal soldered in, and restrained by an angle bracket soldered at one end. The small speaker was taken from a defunct IPod dock. In the next photo, most of the lid components are mounted. The small audio amp board goes on the two screws at right center of the lid, mounted mezzanine style.

Box Lid Components Mounted

Box Lid Components Mounted


Next is a close up of the batteries with 2 amp fuses soldered in both plus and ground leads. Also see three stereo jacks at the right side for Key/Audio Out, External Speaker, and Paddles In. You can see in the bottom three long #2 screws for mounting the third perf board and Adafruit boost/charger. Most board mounting screws have three nuts; one to secure the screw, one to support the bottom of the board at the proper height, and a third to secure the board against the second. Thank heaven I still have a Heathkit nut starter.

Mounted 18650 Cells with Fuses in Both Leads

Mounted 18650 Cells with Fuses in Both Leads


At the right side of the box there is a power switch, PS2 jack, and a micro USB jack breakout. The power switch does not actually switch power, it grounds the Enable pin on the charger board which turns off the boost converter.  That allows charging to continue while the rest of the unit is off.  Later in debugging the hardware, I added bypass capacitors to that switch and a separate wire to the Enable pin on the audio amplifier which suppresses a weird sequence of sounds from the speaker on powering off. The PS2 jack leads wouldn’t reach the processor board so they route to the third perf board and get jumpered there to stranded wire headed for the Teensy.  It’s getting hard to find a real PS2 keyboard but the software works fine with a USB keyboard plugged into a USB/PS2 adaptor.

Power Switch, PS2, and USB Connectors

Power Switch, PS2, and USB Connectors


This is a good place to register a complaint. I bought the Adafruit PowerBoost 500 board to manage the battery. It charges from 5 volt USB in and boosts from the 3 volt battery, seamlessly switching sources when you pull the USB connection. It does NOT however pass through or even break out the two USB data pins from the micro USB input jack. The only way to actually use USB while charging the battery is to wire out the D+ and D- leads outside the board. Adafruit support suggested doing this by cutting up a USB cable. I was able to route the micro USB breakout data leads (Green in the next photo) to the processor and the incoming positive and negative supply leads to the PowerBoost using a plug from an Adafruit micro USB connector (red and black in the photo). An extra $2.50 in parts that wouldn’t have been needed if Adafruit had only provided pads on the PowerBoost for D+ and D- or better, added two traces to route the data signals from the input connector to the output connector.

Detail of the Hacked USB Connection

Detail of the Hacked USB Connection


One more issue with the PowerBoost. It has a nice pair of status LEDs (where it says CHRG) yellow when charging and green when fully charged. These operate from a single pin on the charger chip but that pin is not broken out and you can’t of course, see the LEDs when the box is closed. I added a wire (gray, leading off to the right in the photo) to the common side of the LED dropping resistors so I could have the Teensy display charging status on the LCD.  Not difficult but would have been nice to have official access to that chip pin.

The keyer has four monitoring leads between the PowerBoost and the processor. Besides the status signal mentioned above, I wired up the LowBattery pin and USB (power).  USB activates the Status signal which is only valid when USB is plugged in and receiving power from the host.  LB goes low when the battery is REALLY flat (3.25 volts I think). I also wired the BAT pin to the Teensy A10 analog input through a 10k calibration pot so software can read and display the battery voltage. You can see the calibration pot at the bottom of the board in this photo.

TX board, PowerBoost with Voltage Cal Pot

TX board, PowerBoost with Voltage Cal Pot


The next photo shows how I insulated the External Speaker jack by opening up the mounting hole and screwing a small piece of Lexan to the box. The plastic had to be counterbored so the jack mounting nuts would fit.

Output Jack Insulation

Output Jack Insulation


Here is a close up of the box lid interior. You can see the LCD contrast pot which is glued to the LCD, perfboard for the LED, volume control, and Function button. Two screws and a couple of spacers mount the PAM8302 audio amp on top of the LED board.

LCD Contrast, Audio Amp

LCD Contrast, Audio Amp On Top of LED Board

Here is the completed keyer opened up. Clockwise from top left, I/O stereo jacks, 18650 batteries, memory button board, Teensy3.2 processor on top of 16×2 LCD display, LED board, speaker, on/off switch, PS2 keyboard jack, USB input jack, PowerBoost charger/boost converter, and the transmit interface board.

Keyer Internals

Keyer Internals


An Eagle schematic diagram of this project can be downloaded from:

Keyer 2016 Schematic Version 1

Keyer 2016 Schematic Version 1


Revision History

February 25, 2016       MemoryKeyerTeensy3.2_V1.0    Initial sketch
March 9, 2016             MemoryKeyerTeensy3.2_V1.1.0  Rework battery alarm logic, bug fixes.
March 16, 2016           MemoryKeyerTeensy3.2 V1.1.1   Workaround fix LCD does not have backslash in its font.

Arduino Iambic Keyer 2016 – Part 2: Software


The 2016 version keyer hardware has four additions that require software support; more memory buttons, stand alone battery operation, Real Time Clock, and the biggest change a 16 character 2 line Liquid Crystal Display.

Additional memory buttons need:

  • Expansion of button scanning while in operation
  • Expansion of button programming
  • Addition to default messages
  • Consideration of potential uses while not in operation

Battery and associated (PowerBoost 500c) charger/converter need:

  • Charge status monitoring
  • Discharge status monitoring and alarm
  • Work out how to turn the unit off while charging

The Teensy3.2 built in Real Time Clock will need:

  • Ability to read hardware clock and convert to display friendly form
  • Ability to set hardware clock when in stand alone mode
  • Display GMT and Local time and date
  • Desirable: sync hardware clock over serial from PC

Stand alone operation requires all information displayed on the LCD as well as the serial port.
This will require:

  • Battery charge/discharge status
  • Keyer parameters, speed and side tone frequency
  • Time and date
  • Desirable: manage the LCD backlight

A link to my sketch is at the end of this article.

Following is a description of some things I learned writing this code.

Event Loops

When I first looked at KC4IFB’s Iambic code I couldn’t see how it worked. But after a fair amount of study and experimentation (see my instrumented version) I now understand and use event loops often, avoiding delay() whenever possible.  In an Arduino sketch loop() is an event loop. It just spins forever waiting for something to do. Code entered within loop() is repeatedly executed, like scanning an input pin for a button press which sends in a ground.

Why avoid delay()? Because it stops all sketch processing until it times out. Better to use the timer to trigger an event asynchronously at the current time plus a delay interval. Let loop() continue to spin, watching over the rest of your code. An example might be:

unsigned long trigger1k;
unsigned long trigger5k;
unsigned long currentTime;
void setup() {}
void loop() {
currentTime = millis();
if (currentTime > trigger1k) {
   < do stuff every second >
   trigger1k =trigger1k + 1000;
if (currentTime > trigger5k ) {
   < do stuff every five seconds >
   trigger5k = trigger5k + 5000;

This would not work well with delay(1000) and delay(5000) in place of the time triggers.

You can roll your own event loops. I’m doing this often in the keyer sketch. Just set up your own infinite spinner:

while (true) {
  < code executed until a break; is seen >

The C statement break: exits the while loop. You can make event loops inside of event loops but more than two levels gets very difficult to debug.


Stupid Switch Tricks

I used the “C” switch statement a lot in this years update and thought I would document some of the ideas.

Leading Zeros

This is a function to print 2-4 digit numbers with leading zeros. It can also be used to right justify a number by changing “0” to ” “. Note there are no break statements in the switch, it is entered at a point determined by “digits” then falls through all succeeding statements.

 Just to get leading zeros on up to four digit integer
 arg k is variable to print
 arg digits is # places to use
 void lcdPz(int k, int digits) {
 switch (digits) {
   case 4:
     if (k < 1000 ) lcd.print("0");
   case 3:
     if (k < 100  ) lcd.print("0");
   case 2:
     if (k < 10   ) lcd.print("0");


Building a Menu with Switch

I gave a lot of thought and time to how I could do stand alone update menu system.  The menu loop is entered if the “FUNCTON” button is down when the processor boots up. Teensy3.2 does not provide easy access to the reset pin so my workaround is just switching power off and on.

In this bit of pseudocode, the switch statement just displays menu options. Pressing the “ENTER” button while a specific item is on the LCD selects that menu item for updating. I use a separate function to actually implement specific item updates but that could be done in line.

while (true) {             // Event loop
  Mtime = millis();
  if (MTime > nextMenuTime) {
  nextMenuTime = MTime + 1500; // New menu item trigger  whichMenu = (whichMenu + 1) % 8; // Counts 0 to 7
  switch (whichMenu) {
    case 0:
      < display first menu item >
    case 1:
      < display second menu item >
etc. etc.
    case 7:
      < display seventh menu >
  }        // End of switch statement
if ( < SELECT button is pressed > ) {
 < menu item# whichMenu is selected,
    do something about it  >
}           // End of while() loop


Selecting Columns to Update

One particular problem was how to update the clock time and date. Time is displayed on the LCD as HH:MM:SS so how to click through that and change individual digits? I decided to only increment or decrement the ones digits so the second “H”, the second “M”, and second “S” digits are the only targets. I can skip everything else. Two buttons were designated as “up” and “down” and I wrote a function that returns 1 if “up” is pressed, -1 if “down” is pressed, zero if neither.

Using switch() to select the appropriate digits on the LCD easily allows skipping over columns.

case 3:                            // Set GMT time

 Ltime = now();                    // System time snapshot
 // Convert snapshot into simpler variables for display
 Lhour = hour(Ltime);              // Need the date as well
 Lmin = minute(Ltime);
 Lsec = second(Ltime);
 cursorPos = 0;                    // Start at first position
 lcd.cursor();                     // So you can see where you are
 lcd.setCursor(0, 1);
// Walk the cursor down the displayed time
 while (true) {                    // Start event loop

   Action = upDown();              // Up or Down pressed?
   if (Action != 0) {
     delay(150);                   // limit speed of change
     Changed = true;               // Flag something was changed
switch (cursorPos) {
   case 0:                       // Hours tens digit
     cursorPos += 1;
   case 1:                       // Hours ones digit
     Lhour = (Lhour + Action) % 24;
   case 2:                       // Ignore the colon
     cursorPos += 1;
   case 3:                       // Skip Minutes tens digit
     cursorPos += 1;
   case 4:                       // Minutes ones digit
     Lmin = (Lmin + Action) % 60;
   case 5:                       // Ignore the colon
     cursorPos += 1;
   case 6:                       // Skip Seconds tens digit
     cursorPos += 1;
   case 7:                       // Seconds ones digit
     Lsec = (Lsec + Action) % 60;
 }                               // End of switch
if ( < ENTER button pressed > ) { 
   cursorPos = (cursorPos + 1) % 7;//  Move to next digit
if ( < EXIT button pressed> ) {
  < Write changed time to the system clock >
  break;                         // Jump out
  <  redisplay the time on LCD >
 break;                        // Exit the while()

Revision History

February 25, 2016      MemoryKeyerTeensy3.2_V1.0  Initial software
March 9, 2016            MemoryKeyerTeensy3.2_v1.1.0 Rework battery alarm logic, bug fixes
March 16, 2016           MemoryKeyerTeensy3.2 V1.1.1   Workaround fix LCD does not have backslash in its font.

Arduino Iambic Keyer 2016 – Part 3: Operation

Memory Keyer 2016

Arduino Iambic Keyer - Keyboard and Paddles

Arduino Iambic Keyer – Keyboard and Paddles


This describes the operation of an Arduino sketch and appropriate hardware that serves as an iambic morse code keyer. This version runs on a PJRC Teensy3.2 board and libraries. It will not compile to an Atmel (traditional Arduino) processor without major changes. I chose the Cortex M4 based Teensy because it has built in Real Time Clock, a real DAC, built in USB, and lots of memory. I added a 16×2 liquid crystal display and batteries for stand alone operation.


  1. Characters to be sent are buffered in an asynchronous circular queue so memory buttons or keyboard characters can be “typed ahead”.
  2. PS2 and serial terminal keyboards supported.
  3. Paddle generated morse is interpreted and printed as ASCII text.
  4. Seven 50 character memories. Each is programmable from keyboards or from paddles.
  5. Random code practice modes, letters only, letters and numbers, letters numbers and punctuation.
  6. Sending speed settable 10 to 45 WPM. Limits can be changed by recompiling.
  7. Sidetone frequency settable 100 to 1200 Hz. Limits can be changed by recompiling.
  8. Synthesized sine wave sidetone with leading and trailing edge envelope shaping.
  9. Memories and operating parameters stored in EEPROM, are easily reset to defaults.
  10. Stand alone operation from batteries. Based on tests, a 4400 MAH battery will last at least 36 hours.
  11. A Liquid Crystal Display.

Outside the Box

This keyer has five I/O connectors:

  1. A 3 conductor jack for the paddle or straight key.
  2. A 3 conductor jack for transmitter keying with an optocoupler open collector output on the tip. Line level sidetone audio is connected to the ring.
  3. An external speaker jack connected to a 2.5 watt audio amplifier.
  4. A mini DIN connector for PS2 keyboard. USB keyboards will work with an adapter.
  5. A micro USB port for programming and serial terminal connection. This also powers the unit and charges the battery.

There are eight push button switches, a volume control, and an LED:

  1. A Function button.
  2. Seven push buttons to activate individual memories.
  3. The volume control feeds a Class D amplifier for the speaker. It does not affect the level on the line output connection.
  4. The LED follows the transmit keying signal.

There is an on/off switch that also serves to reboot the processor into setup mode.

Liquid Crystal Displays have a limited space for messages so information has to be presented sequentially. Switching on power displays clock status then “Keyer Ready” is displayed on the LCD and on the serial port. The unit is then ready for normal operation.

Straight Key Operation

On power up, if the unit senses a two conductor plug in the paddle jack, it will go into Straight Key mode and just pass keying through to the transmit circuit, with side tone. Memories and other features are not available as the morse engine is never started.

Normal Iambic Operation

The dual paddle jack is wired dit paddle on tip, dah paddle on ring of the mini stereo connector. The external speaker jack will work with stereo headphones or a speaker. On the transmit jack, there is an open collector optocoupler connected to tip and line level side tone on the ring.

Software will attempt to translate paddle sent morse into ASCII which will display on the LCD and is also sent to the serial port. Decode success depends on how good your fist is. The keyer cannot decode morse received over the air.

Keyboard Operation

The keyer will accept and send characters entered from a PS2 keyboard or from a terminal emulator program such as PuTTY, or even the Arduino IDE serial window. It’s better to use an emulator that supports line at a time transmission as that gives you an opportunity to fix typing mistakes. Opening a terminal window on a USB connected PC also lets you view and log status messages sent from the keyer. PS2 support also works with a USB keyboard and appropriate USB to PS2 adapter.

All characters in the Wikipedia morse code table are supported except the underscore and the dollar sign. From either serial or PS2 keyboards, enter normal text in lower case. Entering text in upper case will suppress the next intercharacter gap, thus running two characters together. This can be used to send prosigns. For example, As (wait) or Sk (end of contact). Message text entered from the paddles will always be treated as all lower case.

Serial or PS2 keyboards use a one at a time command mode, activated by typing a back slash followed by a single character. Keyboard commands are:

  1. \+ or \= increase sending speed one Word Per Minute
  2. \- decrease sending speed one Word Per Minute
  3. \u increase sidetone frequency by 5%
  4. \d decrease sidetone frequency by 5%
  5. \w save current sidetone frequency and WPM to EEPROM memory
  6. \1, \2 … \7 send stored text as though a memory button was pressed.


Seven programmable 50 character memories are available by pressing buttons. The sketch uses a 64 byte circular buffer to queue sendable text from either keyboard or from EEPROM memory, the buffer is asynchronous so memory messages can be stacked with interspersed keyboard text. Memory messages are read as needed from EEPROM so each consumes only a single byte of circular buffer space. Memories can also be queued from the keyboards by entering commands \1 … \7.

Message memory can be programmed from compiled defaults, from either keyboard, or directly from the paddles if your sending is good which is useful in stand alone operation. To program a message into memory, press and hold the Function button, then press and release the desired memory button, then release Function. Enter your text from paddles or keyboard, then exit programing mode by clicking Function again.

Normal Operation Display

Operating parameters can be viewed on the LCD by holding the Function button. Parameters also print to the serial port. The rotating menu display will show:

  • Time and date both GMT and local
  • Sending speed and side tone frequency
  • Battery status
  • The first 16 characters of each programmable message.

Each item will be on the LCD for one second. Releasing Function stops menu rotation but does not erase the LCD which allows more time to read a particular display.

Changing Words Per Minute

Since speed may need to be adjusted according to conditions, there is a provision to change WPM on the fly. Just hold the Function button down and close a paddle. Dits increase speed, dahs decrease. On releasing Function, the changed speed writes to EEPROM.

You can also change speed from the keyboards by entering \+ to increase or \- to decrease. Entering \= will also increase WPM if you forgot to shift. If adjusting by keyboard, you must enter \w to write the new setting to EEPROM.

Changing Side Tone Frequency

This can be done from the keyboards by sending \u to raise frequency or \d to lower frequency. As with WPM, enter the command \w to save the change. Tone frequency can be set in stand alone operation from the Startup Menu described below.

Battery Status

Software constantly monitors battery voltage and the PowerBoost charger status signals. These can be seen in the operating display. Voltage is shown in hundredths with no decimal point. A fully charged battery will show about 4.20 volts, if the battery drops below 3.40 volts “LOW BATT” will show on the battery status and the LCD back light will flash. If voltage drops below the boost regulator LB threshold, about 3.25 volts the status display will show “DEAD BATT”.

Startup Mode

Arduino sketches have a separate startup() section for initializing things. It is executed once when the processor resets, just before entering the main event loop(). This keyer takes advantage of separate startup to recall and optionally change important system parameters. A normal power on sequence copies the following items from EEPROM to RAM:

  • Words Per Minute
  • Side Tone frequency
  • LCD Back light brightness
  • GMT – Local time offset

Memory messages are also stored in EEPROM but are not read into RAM. Startup then reads the Real Time Clock into the system clock.

Startup then checks to see if Code Practice mode (see below) is requested, if so, Code Practice begins as soon as the memory button is released.

Startup Menu

If Startup sees the Function button held down, it enters Startup Menu mode. Eight parameters rotate on the LCD, seven of these can be entered and changed.

  1. Sending speed Words Per Minute
  2. Side Tone frequency
  3. LCD Back light brightness
  4. System clock time (GMT)
  5. System date (also GMT)
  6. GMT – Local offset in hours
  7. Reset all stored parameters to defaults
  8. Display battery voltage and charge status

For Startup Menu purposes, three of the memory buttons are redefined. M5 is Enter, M6 is Up, M7 is Down. Click the Enter (M5) button while a menu item is on the display to activate change mode for that item. For the first three menu items and for GMT offset, Up (M6) and Down (M7) act directly on the displayed number.

Once entered, Time and Date can be set by repeatedly pressing the Enter button until the cursor is beneath the digit needing change. Once there Up and Down operate as expected. The RTC will be updated when the Time or Date menu is exited.

After a change, exit the menu item by pressing and holding Enter (M5) for longer than 2 seconds. Menu rotation will continue where it left off.

Entering menu 7 will reset all EEPROM stored parameters including the seven memory messages to defaults specified in the file “canned.h”. You can change these defaults by editing that file with the Arduino IDE and recompiling. Canned.h appears as one of the tabs at the top of the Arduino editor window.

The last Startup Menu display shows the current battery voltage and charge status. This information is also sent to the serial connection, at the menu rate of rotation, about five times per minute. A terminal emulator program like PuTTY or Minicom on the PC, can log these battery messages in a text file, you can later load the text into a spread sheet and with some amount of fussing create a charge or discharge curve for the battery. To get a discharge curve though you have to disable charging through the USB connection by cutting the red wire in the USB cable.

Startup Menu mode is exited by clicking the Function button again. Changed parameters will write to EEPROM and normal operation starts.

Synchronize the Real Time Clock

Internal system time is maintained by software in the PJRC libraries. System time is initialized at bootup from the crystal controlled, battery backed Real Time Clock inside the processor chip. You can hack set the RTC from the Startup Menu, but there is a way to synchronize the RTC with a PC clock over a USB serial connection. If the PC is itself synchronized with an Internet NTP server, the result will be within 1 or 2 seconds of WWV.

Accurate clock synchronization requires the Arduino sketch be ready to accept and process a time update at the exact moment the PC sends it. Connect the keyer to the PC with a USB cable, power up the keyer while holding the Function button down, then while the LCD displays “Enter Setup Mode”, paste the following Linux command into a shell;

date +T%s\n > /dev/ttyACM0

Release the Function button and the RTC synchronizes. There is a processing sketch included with the PJRC Time library that can be used to synchronize the clock from a Windows computer.

Code Practice Mode

Holding one of the first three memory buttons down on boot up puts the keyer in Code Practice Mode. Characters generated are based on tables in the Wikipedia article on Morse Code.

  • M1 Send letters only
  • M2 Send letters and numbers
  • M3 Send letters, numbers, and punctuation

Characters are sent in groups of five. If a serial terminal window is open it will display the sequential group number as well as the ASCII characters themselves.

Practice Mode Commands

In practice mode, the first four memory buttons adjust the delay between characters in increments of two element (dot width) times. M1 adjusts by zero, M2 by two, M3 by four, M4 by six elements giving a listener additional time to decode the sounds. Each step slows the average WPM by about 10 percent.

Pressing the M5 button pauses practice and the display back light will begin blinking. Pressing M5 again resumes but will likely have mutilated any character that was in progress. M6 increases sending speed and M7 lowers sending speed, one WPM per click. The changed speed is only effective until the keyer is reset, it is NOT written to EEPROM.

Display Mode

Normal Operating Displays are also available in Code Practice mode by pressing Function. The display will not start until the current five letter code group is completed.

Battery Status

If the battery voltage drops below 3.40 volts, the display back light will begin flashing.


Many thanks to Richard Chapman KC4IFB whose September 2009 QEX article provided the inspiration and base code for this sketch. His iambic keyer code feels exactly like my original WB4VVF Accukeyer. Also see Rarons Blog for a discussion of the tree method for decoding and encoding morse characters. It was very helpful in building efficient translation tables. The circular queue was implemented with help from examples at Paul Stoffregen encouraged me to try the Teensy3.2 on the PJRC forum.


Revision History

February 25, 2016       MemoryKeyerTeensy3.2_V1.0    Initial sketch
March 9, 2016             MemoryKeyerTeensy3.2_V1.1.0  Rework battery alarm logic, bug fixes.
March 16, 2016           MemoryKeyerTeensy3.2 V1.1.1   Workaround fix LCD does not have backslash in its font.