Posts Tagged ‘ PWM ’

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
http://www.dropbox.com/s/o8cgh485wcqzgj3/MemoryKeyerFeather_V1.0.zip

Version 1.2 12/6/2017 Was running out of memory, rearranged startup and moved stuff to PROGMEM
https://www.dropbox.com/s/hqx54u6ha8uu6xn/MemoryKeyerFeather_V1.2.zip

Jim Harvey – wb8nbs@gmail.com

 

Advertisements

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.

References:
https://www.circuitsathome.com/mcu/rotary-encoder-interrupt-service-routine-for-avr-micros/
https://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino/

Files:
https://www.dropbox.com/s/t1fud02jcfdhxjl/Feather32u4V2.zip?dl=0
https://www.youtube.com/watch?v=jbv-z4wvXI8&feature=youtu.be

Still More Fun With Direct Digital Synthesis: TeensyLC with DAC

I posted a link to my previous page on setting up PWM Direct Digital Synthesized sine waves on PJRC’s Teensy 2.0, a 32u4 Arduino. Paul Stoffregen (the PJ in PJRC) commented that I should try porting my DDS demo sketch to a TeensyLC. “You won’t need PWM” he said. “Use the Digital Analog Converter” he said. I was a bit hesitant because TeensyLC has an ARM processor running at 48 Mhz. Quite a bit more power than the Atmel 16 Mhz chips and more I/O capability, so worth a look.  PJRC supplies an Arduino IDE add on called Teensyduino which configures support for PJRC boards so simply doing an analogWrite to pin A12 (took me a while to actually find A12) starts the DAC instead of starting PWM. Teensyduino has an included library IntervalTimer which sets a repetitive timer running and attaches that to an Interrupt Service Routine which you supply.  So an LC port should be simple as the dirty work of configuring the timer is taken care of.

Arduino PWM based DDS uses a fixed sample rate of 31 or 62 Khz and the interrupt generated sine wave has to fit into that constraint. That means low frequency audio tones are relatively smooth as there are lots of sample periods to go around even with the 256 step tables. High audio frequencies on the other hand, suffer distortion as the shorter period audio wave can’t fit in enough sample periods.

In the TeensyLC, the DAC always gets a fixed number of bits so you change the interrupt frequency to change the frequency of the generated audio tone. For instance, using the 256 step table, to generate a 1000 Hz tone requires 1000 * 256 interrupts per second. That’s about one every four microseconds, which even with the 48 Mhz processor clock, is going to use a LOT of CPU time. The shortest period I could set with IntervalTimer was 5 microseconds, my experiments with the demo program showed a maximum audio frequency of 650 Hz with the 256 step table, the 128 table limited at 1300 Hz, and the 64 step table maxed out at 2600 Hz.

Another down side to the DAC method stems from the fact that the audio frequency granularity is determined by the 1 microsecond granularity of the IntervalTimer function multiplied by the number of steps in the sine table.  The demo program shows this while sweeping. Low audio frequencies sweep smoothly but the higher frequencies have very noticeable jumps. Higher sine table sizes show this effect much more.

But the output wave form is much better than PWM. The following photos were shot using the Quarter Wave symmetry version of the demo sketch. Full table version traces were identical. All these were taken at a set audio frequency of 440 Hz. The filter was a single 10K resistor in series with the output pin, and a 0.01 ufd capacitor to ground. You can see the wave period changing a bit with the different table sizes. That is due to the granularity issue.

TeensyLC DAC Bottom - Raw, Top - Filtered 256 Step Table, Quarter Wave

TeensyLC DAC Bottom – Raw, Top – Filtered
256 Step Table, Quarter Wave

 

TeensyLC DAC Bottom - Raw, Top - Filtered 128 Step Table, Quarter Wave

TeensyLC DAC Bottom – Raw, Top – Filtered
128 Step Table, Quarter Wave

 

TeensyLC DAC Bottom - Raw, Top - Filtered 64 Step Table, Quarter Wave

TeensyLC DAC Bottom – Raw, Top – Filtered
64 Step Table, Quarter Wave

 

TeensyLC DAC Bottom - Raw, Top - Filtered 32 Step Table, Quarter Wave

TeensyLC DAC Bottom – Raw, Top – Filtered
32 Step Table, Quarter Wave Symmetry

 

TeensyLC DAC Bottom - Raw, Top - Filtered 16 Step Table, Quarter Wave Symmetry

TeensyLC DAC Bottom – Raw, Top – Filtered
16 Step Table, Quarter Wave Symmetry

I will probably use the TeensyLC in my next version of morse keyer.  I have to find a 16×2 LCD that will work at 3.3 volts, figure out how to interface a 5 volt PS2 keyboard, and how to charge and connect a 5 volt battery pack. The LC (and the 32u4) have USB serial built in which will make interfacing a terminal window on a logging computer a lot easier.

I found a useful web page showing how you implement quarter wave sine symmetry DDS on an FPGA and I took this opportunity to streamline the quarter wave ISR. You have to be familiar with bit banging to understand it now.

The demo sketches, full table and quarter table versions, and the Libre spreadsheet I used to develop the quarter wave half step offset tables are included in the archive at:
https://dl.dropboxusercontent.com/u/40929640/ArduinoSineSynth/TeensyLC_DDS_Demos.zip

More Fun With Direct Digital Synthesis: 32u4 and Fast PWM

32u4 Port

My 2015 winter project will be an expanded version of the Morse Code keyer I built last year. I now have a PJRC Teensy 2.0 controller board (from Sparkfun) to use. The Atmel 32u4 based Teensy 2.0 is even smaller than the Pro Minis I have been using. It is attractive because it has USB built in for program loading and serial transmission. And there’s lots of I/O pins available which will make an LCD easy to connect. I note that everybody making a 32u4 “Arduino” is defining a different pinout from the chip. The Adafruit Feather is quite ambitious, has it’s own IDE addon and can be bought with Bluetooth or WiFi  included.

This breadboard photo shows the Teensy 2.0 at top left, Sparkfun Pro Mini at center, Sparkfun RedBoard top right, and a MicroCenter Pro Mini clone at bottom right.

Arduinos

 

PJRC has ported many of the standard Arduino libraries to their 32u4 Teensy form factor and these are included in your Arduino IDE when you download and install the Teensyduino addon. But my keyer sketch uses Direct Digital Synthesis to form a nice sine wave side tone which requires direct setup of a Pulse Width Modulation timer inside the AVR chip. My implementation is based on code from Jeff Whitlatch, KO7M.  I used timer 2 in last winters UNO based keyer as that’s the timer that does tone() in the Arduino UNO and I completely superseded that function. Reading the data sheet on 32u4 shows that it doesn’t even *have* a timer 2. It has timer 0 (8 bit), timers 1 and 3 (16 bit), and timer 4 (10 bit). Digging into the Teensy Arduino libraries shows that PJRC is using timer 3 for tone() so I needed a port that just changed the timer used. Comparing the 32u4 data sheet with the Mega328 data sheet showed that the only difference besides the timer number would be in the Waveform Generation Mode bits. 32u4 has four WGM bits, Mega328 has 3. I used a mode setting that turns the 16 bit 32u4 timer 3 into an 8 bit timer and Success! The port was working in my test program.

Fast PWM

Phase Correct PWM in an AVR processor uses the timer in a manner that has it count from 0 to 255 then count back down to zero for each interrupt cycle. The PWM signal goes high on the way up and low on the way down. For an 8 bit counter, that’s 510 counts per cycle (read the data sheet to find out why it skips two) so with no clock scaling the sample rate is 16 MHz/510 or 31.4 KHz. In Fast PWM mode the timer counts from 0 to 255 then rolls over back to zero. A PWM wave on the output pin goes high on the way up and low on overflow. This results in some jitter on the PWM pulses but the sample rate is twice as fast, 16 MHz/256 or 62.5 KHz. I decided to try Fast PWM in the test program. It required only a change in the math that calculates the sample rate, and a slightly different set of WGM bits.

The following images show comparisons of the 31.4 KHz (Phase Correct) and the 62.5 KHz (Fast) rate tone waveforms from the test program. The PWM signal is filtered by a single 10k resistor and a 0.01 ufd capacitor to ground at the scope connection.

Comparison of Phase Correct PWM with Fast PWM

Comparison of Phase Correct PWM with Fast PWM at 100 Hz

 

Comparison of Phase Correct PWM with Fast PWM at 1000 Hz

Comparison of Phase Correct PWM with Fast PWM at 1000 Hz

 

Comparison of Phase Correct PWM with Fast PWM at 5000 Hz

Comparison of Phase Correct PWM with Fast PWM at 5000 Hz

 

Comparison of Phase Correct PWM with Fast PWM at 10000 Hz

Comparison of Phase Correct PWM with Fast PWM at 10000 Hz

 

There is a clear improvement at the higher sample rate in the amount of “fuzz” on the waveform. The fuzz is at the sample rate and is the result of the 0.01 ufd capacitor integrating the PWM square wave. At twice the rate, the capacitor has half the time to charge or discharge. You can see at 5 KHz, the Fast PWM signal is much closer to a sine wave than Phase Correct. At 10 KHz, both are falling apart. A better output filter that cuts off the sample frequency would help but for morse keyer side tone from a tiny speaker, the average amateur radio operators ear won’t know the difference. I may try a switched capacitor filter some time in the future just to see. Watch this space.

Revision History

2015/12/08   The photos above are all from the 32u4 port. The program uses quarter wave symmetry to reduce the table size by a factor of 4. Two sketches, one running on UNO or other Mega328 controllers, the other for the PJRC 32u4 Teensy are at:
https://dl.dropboxusercontent.com/u/40929640/ArduinoSineSynth/Quarter_Wave_Demos.zip

I also back ported the changes to an earlier sketch that did not take advantage of symmetry. Scope traces were identical to the 32u4 port. Since the complete 360 degree cycle is specified, the code may be modified to generate arbitrary non-sinusoidal waveforms by manipulating the tables. Download at:
https://dl.dropboxusercontent.com/u/40929640/ArduinoSineSynth/Full_Table_Demos.zip

Each of these zip archives has a copy of the spreadsheet I used to construct the sine tables.

 

 

Fun With Direct Digital Synthesis

You know that good feeling you get when a project comes together? Thats what I felt when I saw this sine wave on my oscilloscope.  It’s a Pulse Width Modulation (PWM) signal generated by an Arduino using a Direct Digital Synthesis (DDS) technique and a lookup table of amplitude values. It was the result of searching for a way to improve the tone quality of a morse code keyer project and I had gotten half wave, then quarter sine wave symmetry working in a demonstration sketch.

Quarter Wave Symmetry

Quarter Wave Symmetry
1000 Hz 256 Step Table

Digital to Analog Conversion is best done with optimized precision circuits. The relatively simple processor in an Arduino does not have a DAC device but it can do Pulse Width Modulation which can, in most cases, do the job adequately.

Pulse Width Modulation is widely documented. Basically it is a technique for generating an analog voltage from a digital signal. The device generates a high speed pulse train with varying pulse widths.  This is fed through a filter circuit which averages the energy in the pulses.  Fat pulses average to a higher voltage, skinny pulses average to a low voltage. By changing the pulse width over time, digital software can create a good analog representation of an arbitrary periodic signal. Other interesting applications are possible.

An Arduino generates PWM by setting up a timer. This is a counter with a circuit to trigger an interrupt at a specified count. The counter is incremented by the processor clock or, through a prescaler, a submultiple of the processor clock.  PWM is achieved by the Interrupt Processing Routine (ISR) manipulating the specified count at which the timer fires. DDS applications synthesize an arbitrary waveform by using a lookup table of values that the ISR accesses sequentially to change the terminal count.

Common non-DDS applications might be dimming an LED , feeding an RC servo, or controlling the speed of a motor, and the Arduino environment has a convenient analogWrite() function that handles all the details for you. Hybrid cars use PWM to control the traction motors.

I found many articles on generating DDS sound using the Arduino platform. I picked one from KO7M as a base to learn more about the method. Read Jeff’s weblog entry with source code here. His sketch sets up timer 2 for PWM with a 32 KHz base frequency.  Timer 2 is normally used by the Arduino for the tone() function and since my aim is to supersede the tone() function with something better, his example was a perfect starting point. In this article, I will only describe the changes I made in Jeff’s Interrupt Service Routine (ISR) and in the tables. Details of setting up the timers are covered in the source code and in many Internet sources. Here is a drawing of the Arduino connections:

Schematic for DDS Demo

Schematic for DDS Demo

Only five external parts needed including a button switch that stops and starts the sweep.

My test bed started out simple but it grew some (gruesome?).

Test Bed

Test Bed

Part 0: Analyzing and Parting Out the KO7M Sketch

After confirming that the sketch actually worked, I added code to sweep the frequency range from 50 to 2000 HZ so I could hear what it would sound like, and observe fidelity on my oscilloscope. Later I also added lines to generate a pulse at the start of the sine wave on a different pin. Using this pulse as an external sync source allowed the scope to display a steady waveform. I removed the sync code in the examples in this post for clarity.

This is the ISR from the original sketch (with small changes by me). TuningWord is the only parameter passed from the main part of the program. It is adjusted to set the particular PWM output frequency desired:

ISR(TIMER2_OVF_vect) {
  byte sine_table_index;
  static uint32_t phase_accumulator;
  
  // Update phase accumulator and extract the sine table index from it
  phase_accumulator += tuning_word;
  sine_table_index = phase_accumulator >> 24;  // Use upper 8 bits as index

  // Set current amplitude value for the sine wave being constructed.
  OCR2A = pgm_read_byte_near(sine256 + sine_table_index); 
}

Note Jeff is storing his sine table in flash memory. If you’re not familiar with that technique, read this tutorial. It is a good method for reducing the RAM footprint of an Arduino sketch. You can find my version of Jeff’s sketch here.  This is the 1000 Hz output from the original sketch with floating point math:

Original Floating Point

Original Floating Point
1000 Hz 256 Table

Part 1: Integer Conversion and Multiple Sine Tables

At this time, all floating point math in the example was converted to integer. To my surprise, it still works. There is more jitter on the waveforms due to integer truncation, but for keyer sidetone it is acceptable and the sketch sized dropped by about half.

I wanted to experiment with multiple lookup tables to get an idea of the minimum memory footprint possible while still producing acceptable sound. Libre Office Calc easily produced data with a 0-255 range for tables of length 256, 128, 64, 32 and 16 samples. See my spreadsheet here. Calc could also graph the tables to show how rough the waveform might be.  It was a simple matter to paste a table column into VI and join the values into C style  statements. These lines of data were inserted into the sketch and wrapped with #ifdef and #endif statements. At the top of the sketch is this code:

// Table sizes. Uncomment one and only one
//#define Table256
//#define Table128
#define Table64
//#define Table32
//#define Table16

Which allows me to choose a table size to evaluate at compile time. The wrapped tables look like:

#ifdef Table16
// 16 samples per period
#define Bits 12               // # of bits to shift 
PROGMEM prog_uchar sineTable[16] = {
  128,177,218,245,255,245,218,177,
  127,79,38,11,1,11,38,79
};
#endif // Table16

Bits is a constant definition that controls how far the ISR has to right shift the phase accumulator variable so the number that remains does not exceed the sine table size.

The interrupt handler changed little and looks like this:

ISR(TIMER2_OVF_vect) {
byte sineTableindex;
static unsigned int phaseAccumulator;

  // Update phase accumulator and extract the sine table index from it
  phaseAccumulator += tuningWord;
se
  // Right shift because we're only using the most significant bits of the INT
  sineTableindex = phaseAccumulator >> Bits;

  // Look up current amplitude value for the sine wave being constructed.
  OCR2A = pgm_read_byte_near(sineTable + sineTableindex);
}

Code for this full table sketch is here. These are waveforms from the Integer version:

Integer Version

Integer Version
Three Table Sizes

Part 2: Using Half Wave Symmetry of Sine Waves to Reduce Table Size

During my Google research I found articles pointing out that the size of the sine table could be reduced by a factor of two or four if you exploited the symmetry of a sine wave. Several pages described how to do this in FPGA hardware but I could not find a good example of symmetry use in C code and nothing at all for an Arduino. I tackled symmetry in two stages.

For half wave symmetry it is only necessary to duplicate the first half of the wave for the second half, inverting the second half as it is generated. First you need to know which half is being processed during the interrupt. The Most Signifigant Bit (MSB) of the phase accumulator variable has that information. It will be zero in the first half of the sine wave, one in the second half. I added a variable to record this bit and use a mask of 0x8000 to extract the bit. Then a new constant MSBMask was created inside the table definitions to turn off the high order MSB during table lookup. The tables now look like this example:

#ifdef Table16
// 16 samples per period
#define Bits 12
#define MSBMask 0x07
PROGMEM prog_uchar sineTable[8] = {
 128,177,218,245,255,245,218,177
};
#endif // Table16

Note the table sizes are half the original. This 16 stepe per period table is now only 8 bytes long.  The modified ISR with half wave symmetry now looks like:

ISR(TIMER2_OVF_vect) {
byte sineTableindex;                     // calculated index into sine table     
static unsigned int phaseAccumulator;    // running total of phase offset
unsigned int whichHalf;                  // for sine symmetry switching

  // Update phase accumulator and extract the sine table index from it
  phaseAccumulator += tuningWord;
  whichHalf = phaseAccumulator & 0x8000; // record which half of wave

  // Right shift because we're only using the most significant bits
  // of the INT. Leave only enough bits for one half table range
  sineTableindex = (phaseAccumulator >> Bits) & MSBMask;

  // Set current amplitude value for the sine wave being constructed.
  OCR2A = pgm_read_byte_near(sineTable + sineTableindex);

  // invert the second half of sine wave
  if(whichHalf) OCR2A = 255 - OCR2A;
}

The only additions to the ISR were the whichHalf variable, MSBMask which is defined with the sine table to remove the MSB, and the if statement at the end which does the actual inversion.

Code for the half wave symmetry version is here. These photos are from the half wave version:

Half Wave Symmetry Version

Half Wave Symmetry Version
Three Table Sizes

Part 3: Using Quarter Wave Sine Symmetry to Reduce Table Size

Exploiting quarter wave symmetry is more complicated. It is a left/right symmetry while half wave symmetry is up/down. First you have to know which quarter of the wave is being generated. The second most significant bit in the phase accumulator variable has this information. It will be 0 if in the first or third quarter, 1 if second or fourth. A new state variable and a mask of 0x4000 records this bit.  Since we are using less of the lookup tables, the MSBMask is smaller, it now needs to discard two MSB bits. The tables now look like:

#ifdef Table16
// 16 samples per period
#define Bits 12
#define MSBMask 0x03
PROGMEM prog_uchar sineTable[5] = {
  128, 177, 218, 245, 255
};
#endif // Table16

Note that the sixteen sample table has been reduced to five (not four) bytes. The 256 level table is only 65 bytes long! The odd byte at the end was necessary to work around a glitch – the table read from flash would look up the same value twice at the beginning and end of the even quadrant. Adding one to the index and one extra table byte solves that issue. The ISR now looks like this:

ISR(TIMER2_OVF_vect) {
byte sineTableindex;                     // calculated index into sine table     
static unsigned int phaseAccumulator;    // running total of phase offset
unsigned int whichHalf;                  // for sine symmetry
unsigned int whichQtr;                   // for sine symmetry
static boolean pulsed;                   // for unique scope sync

  // Update phase accumulator and extract the sine table index from it
  phaseAccumulator += tuningWord;
  whichHalf = phaseAccumulator & 0x8000; // record which half of wave
  whichQtr =  phaseAccumulator & 0x4000; // record which quarter of wave

  // Right shift because we're only using the most significant bits
  // of the INT. Leave only enough bits for one quarter table range
  sineTableindex = (phaseAccumulator >> Bits) & MSBMask;

  // Look up current amplitude value for the sine wave being constructed.
  if(whichQtr) {                         // in second or fourth quarter
  // +1 works around a glitch where same data at the quarter 
  // transitions was looked up twice in a row
    OCR2A = pgm_read_byte_near(sineTable + (MSBMask - sineTableindex + 1));
  } 
  else {                                 // in first or third quarter
    OCR2A = pgm_read_byte_near(sineTable + sineTableindex);
  }
  // invert the second half of sine wave
  if(whichHalf) OCR2A = 255 - OCR2A;
}

This code does quarter wave symmetry first, then wraps half wave symmetry around that for the final output.  The changes to add quarter wave are the whichQtr variable and it’s masking line, and the if(whichQtr) statement which inverts the table lookup left to right. MSBMask in in the byte read statement because it is the number of steps that exactly form a quarter of the wave form.

Code for the quarter wave symmetry sketch is here. Here are scope traces of the quarter wave symmetry version:

Quarter Wave Symmetry Version

Quarter Wave Symmetry Version
Three Table Sizes

Conclusion:

These changes to the original Interrupt Service Routine allowed the table sizes to be reduced by a factor of four with hopefully, not too much additional overhead. Any ISR overhead added is executed 32000 every second so you have to be conservative.  CPU time in the ISR is traded for a smaller program.

All three of these sketches can be useful for arbitrary waveform synthesis by constructing an appropriate table.  The base sketch would work for any periodic waveform, including those that have no symmetry either up/down or left/right. A sawtooth wave for example.  Half wave symmetry would be good for representing an underdamped or overdamped square wave.  Quarter wave symmetry works for sine waves, as shown here, or a triangle wave.

The oscilloscope traces are interesting by themselves. These sketches and a scope could be used to demonstrate microcontroller techniques at your local science fair. My scope is an 80’s vintage Tektronix clone. On the screen you can see the generated sine waves and by zooming in, see the artifacts of PWM happening at a 32 KHz rate. Use the coarse 16 step table and the staircase model of DDS is clear. You can view the raw PWM by simply disconnecting the 0.1 Ufd integrating capacitor from the scope input. Interesting though, disconnecting the filter capacitor does not affect the audio much because your ears can’t respond to 32 Khz sound.

DDS quantization is most visible at low frequencies, using the smaller tables. Here you can clearly see the 16 steps and 32Khz fuzz on the trace.

50 Hz 16 Step Waveforms

50 Hz 16 Step Waveforms

Footnote:

The 64 step sine synthesizer with quarter wave symmetry was successfully added to my keyer project.  I see no degradation of the morse timing at 50 WPM.  A brief video is here.  Also I recorded MP3s of the tone before and after.  The tone produced by the stock Ardino tone() function is here.  The tone from the 64 step (16 values) DDS function is here.

Arduino Based Iambic Keyer(s)

Version 1.0 – ATTiny85 Port

Richard Chapman KC4IFB published an article in the Sep/Oct 2009 QEX magazine (subscription required) for constructing an Iambic Keyer on the Arduino platform. I downloaded his code from the QEX web site (ARRL membership required) and found it worked well.  I have not been active in Ham Radio for years and my morse code is seriously rusty, so I decided to build a keyer for practice purposes and maybe to use on a real radio some day when I figure out how to get an antenna up on this small lot.  I have a WB4VVF Accu-Keyer I used with my homemade paddles long ago.  I bought the PC board from WB4VVF himself at the Dayton Hamvention.  Chapman’s keyer implementation on the Arduino Uno felt exactly the same and I had no problem getting used to it.

I wanted to see if this code would run on an ATtiny85 chip. These are beautiful little microcontrollers in an 8 pin DIP package. They have 8K of internal flash memory and with a minor bit of library downloading, are programmable via the Arduino IDE.  There is a catch though, tiny85 does not normally have bootloader code like a formal Arduino does so you need additional circuitry to burn your sketch onto the little chip. In July 2013 Jim Williams from Workshop 88 in Glen Ellyn conducted a class in tiny85 programming which I attended. At the end of the class we all had our own Arduino ISP adapter board and could burn a tiny85 by using an Arduino UNO as an intermediary.

I amped up my ISP adapter by adding a ZIF socket. It also can program the ATMega328 chips by moving five jumpers.

ISP programmer for ATtiny85 and ATMEGA328 microcontrollers

ISP programmer for ATtiny85 and ATMEGA328 microcontrollers

With the ISP programmer working, I was ready to work on the tiny85 port.  I found Chapman’s code worked but there was no side tone generated.  After a few hours debugging I noticed Chapman’s code was turning the tone on in every iteration of loop(). The tiny85 did not like that. I just added a flag so tone was turned on once, then left on, and the tiny85 port was working 100%. In the end, a very minor change.

I wanted SMALL so I added code to eliminate the speed potentiometer. In my version, you hold both paddles closed for 5 seconds and it goes into speed set mode. Dots increase the speed and dashes decrease.  Another five second Iambic squeeze and it goes back to normal mode.  Also I added a Straight Key mode. If a two conductor instead of a three conductor plug is inserted in the paddle jack it will just beep out what it sees on the dot paddle.  Good for code practice with my J38 if I can remember where I put it.

Source code for the ATtiny85 port is here. This is the finished Keyer in the mandatory Altoids enclosure (but note SMALL Altoids):

Atmel ATtiny85 based Iambic Keyer

It was a challenge to get everything in there and still have the lid close.  The speaker is from a defunct greeting card but rest of the parts were purchased from Jameco. In the end, the most expensive single component was the Altoids mints from the drug store.  The ATtiny85 chips are less than a dollar if you buy ten.

There are these few parts required:

  • speaker and 22 ohm resistor
  • 2032 battery and holder
  • two 3.5 mm jacks, one output, one paddles
  • three bypass capacitors
  • Dropping resistor and LED
  • Power switch
  • ATtiny85 chip and 8 pin socket
Interior of ATtiny85 Iambic Keyer.

Interior of ATtiny85 Iambic Keyer.

There is a short video of the keyer in action here.  So now if I spend a few minutes every day practicing I might get back to the 13 WPM I had to do to get my current license.

Version 2.0 – ATMega328 with Memories

Richard’s QEX article suggested several possible enhancements. I thought adding memories would make the device much more useful so began another journey into Arduino programming. Yes, I know there are already Arduino keyers out there. The K3NG implementation has a ridiculous number of options, but I wanted to do my own based on Chapman’s sketch in the most efficient manner possible. A schematic drawing of my completed keyer is available, and I have written a description of the functions. Source code for the sketch is here.

The PS2 keyboard requires +5 volts so I designed around a five volt Sparkfun Pro Mini board. Only ten bucks! Available here or here. The Pro Mini has an on board 150 milliamp capacity 5 volt regulator if you use a 7-12 volt power supply.

Features in the keyer sketch now include:

  1. Memory or keyboard characters 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 letters on the serial terminal.
  4. Four programmable memories with 50 character capacity each.
  5. Memories programmable from the keyboards or from the paddles.
  6. Random code practice modes, letters, letters and numbers, letters, numbers, and punctuation.
  7. Sending speed settable 10 to 45 WPM. Limits can be changed by recompiling.
  8. Sidetone frequency settable 100 to 1500 hz. Limits easily changed by recompiling.
  9. Commonly changed default settings are in a separate header file (Canned.h).
  10. Message strings, sending speed, and sidetone frequency are stored in EEPROM and easily reset to defaults.

The sketch requires five I/O connectors:

  1. A 3 conductor jack for the paddle or straight key. Connect dot paddle to tip, dash paddle to ring. Use a 2 conductor plug for a straight key in the same jack.
  2. A 3 conductor jack for transmitter keying. A 2N2222 open collector output is on the tip. Line level sidetone is connected through a 5k resistor to the ring so you can connect an external amplifier if you need louder audio.
  3. A power jack for either a 5 volt or 7 -12 volt wall wart supply. Consult the Sparkfun documentation for which Pro Mini pin to use for power.
  4. A six conductor mini DIN connector for the PS2 keyboard. See Canned.h for information on the four leads needed.
  5. A connection for programming, and TTL serial terminal through an FTDI adapter. This can also power the unit instead of the wall wart.

There are six push button switches and a volume control needed:

  1. A reset button for the Arduino.
  2. A Function button.
  3. Four push buttons to activate individual memories.
  4. The volume control feeds a one transistor buffer for the internal speaker. It does not affect the level on the line output connection.

Operation:

Pressing reset momentarily has different effects depending on what other switches are closed. A processor reset normally takes a few seconds, when finished three mid tone beeps will be heard.

  • Press the reset button alone to restart the Arduino. This is also the only way to exit code practice mode.
  • Press the reset button while holding the function button down until three low tone beeps sound will restore the four message memories and code speed to defaults. Default messages, speed, and sidetone frequency are set at compile time from the file canned.h. You must do this action when loading the sketch for the first time into a new Arduino to initialize the EEPROM.
  • Press the reset button with a 2 conductor straight key plug inserted and the keyer enters straight key mode where the sketch generates tone and output simply follows the key closures.
  • Press the reset button while holding down one of the memory buttons starts random code practice. Characters will be generated in five character groups and echoed on the serial port.
  1. Memory 1: letters only
  2. Memory 2: letters and numbers
  3. Memory 3: letters and numbers
  • Pressing reset while holding Memory 4 enters sidetone frequency set mode. The dot paddle increases frequency, dash paddle decreases. Press M4 again to exit set mode.

The function button has three duties:

  • Reset to default messages as mentioned above. You must hold the function button down until you hear 3 low tone beeps.
  • Holding function alone down triggers speed change mode. While function is held, the dot paddle increases speed, dash paddle decreases speed.
  • Holding function down and then momentarily pressing a memory button allows programming that memory. After programming, press function again to return to normal.

New memory messages may be entered from the PS2 keyboard, the serial port keyboard, or from the paddles.

Pressing a memory button by itself transmits the programmed message.

Serial or PS2 keyboards have a command mode, entered by typing a back slash followed by a single character. Commands implemented are:

  1. \+ 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, \3, \4 send a message as though a memory button was pressed.

The keyboard translation table (AtoM.h) includes all the characters shown in the Wikipedia article on Morse Code except the underscore and the dollar sign. Typing an unsupported character echos “x” on the serial port and will be ignored by the morse interpreter.

Version 2.0 Hardware Implementation

Here is a photo of my 2.0 construction. There are three jacks on the left for power, paddles and transmitter keying. PS2 keyboard jack on the right, small volume control and send monitor LED on the front. Not visible is the six pin serial connector on the rear.

On the lid of the S.A.E. you can see a small speaker through the holes around the center. Round holes were made with a heavy duty paper punch. For buttons, I used 6 mm square through hole PCB mount switches with four pins, the kind everybody uses on their solderless breadboard. I bent the pins on one side back so they could be soldered directly to the Altoids lid. Quarter inch square holes for the buttons were punched with a hollow chisel mortiser bit which worked quite well.  I made labels by placing the lid in a scanner, adding text to the scan in GIMP, then printing a 1:1 image of the labeled lid on photo paper. I cut the letters out and glued them to the Altoids lid. This technique produces text labels with the original Altoids artwork underneath. I coated each label with clear nail polish for protection.

Arduino Memory Keyer Exterior

Arduino Memory Keyer Exterior

With the box opened you can see the small Sparkfun Pro Mini board. It is mounted by a pair of L shaped wires cut from a paper clip. These are soldered in the Mini’s two ground pins and then soldered to the Altoids tin. A rectangular hole in the back of the tin provides access to the six pin serial connector. All the in use Arduino inputs have 9.8 k pull up resistors added, and are bypassed at the switch with a small capacitor. The outer end of the pullup resistors are soldered to a narrow bit of PC material wired to Vcc.

Three jacks on the left are epoxyed in place. The PS2 jack on the right, which was salvaged from a defunct USB-PS2 adaptor, is held by a narrow copper strap soldered to the jack and to the Altoids tin. A small perf board at the front holds most of the ancillary components for keying and the audio control. I mounted the perf board using more stiff wire cut from the paper clip.

There is a strip of thin PC material laid across the button switches to add more physical support. The two switch pins not soldered to the Altoids lid are bent over the strip and soldered. Notches filed in strategic places across the copper isolate each switch, and I added the necessary 0.1 uFd capacitors at this point.  The speaker is tucked under one of the PC strips and epoxyed in a couple of places. A short piece of flexible solder wick bonds the box lid to the bottom.

Arduino Memory Keyer Interior

Arduino Memory Keyer Interior

Future Enhancements

Add a FTDI USB to Serial adapter inside the box. It would allow a more graceful connection to a host computer running a serial communication program. Or build another unit with a USB integrated chip.

Add a 16×2 LCD display. Code would be trivial, but will probably have to find a bigger box.

Expand to six or eight memories. My sketch is compiling in about 13 k of flash, and has over 1500 bytes of ram free plus the Pro Mini has eight analog inputs so easily done. But how many memory messages can the average ham keep track of? I think four is a good number and I love the Altoids tin paradigm.

Credits

Many thanks to Richard Chapman KC4IFB whose February 2009 QEX article provided the inspiration and base for this sketch. His iambic keyer sketch feels exactly like my original WB4VVF Accukeyer. A version of his sketch with instrumentation added so you can see the state changes is here. Also see Rarons Blog  for a discussion of the tree method for decoding and encoding morse characters. Would you believe 300 WPM full duplex?  I did not use his library but his work was very helpful in building efficient translation tables. The circular queue was implemented with help from examples from the Embedded Systems Journal.

Revision History

V2.0.0 Initial coding to implement fully asynchronous event loop.
All delay() and spin waits removed from the main loop path.
Remove numbers only practice. Change eeprom order. Add change sidetone.
https://dl.dropboxusercontent.com/u/40929640/ArduinoMorseCode/MemoryKeyerV2.0.zip

V2.0.1 Minor tuning space generation in doIambic.
https://dl.dropboxusercontent.com/u/40929640/ArduinoMorseCode/MemoryKeyerV2.0.1.zip

V2.0.2 Converted sidetone generation to DDS/PWM sine wave with help from
http://ko7m.blogspot.com/2014/08/direct-digital-synthesis-dds.html

https://dl.dropboxusercontent.com/u/40929640/ArduinoMorseCode/MemoryKeyerV2.0.2.zip

Quarter Wave Symmetry

Quarter Wave Symmetry
1000 Hz 256 Step Table

V2.0.3 Changed sine table to half step offset. Saves one byte.
https://dl.dropboxusercontent.com/u/40929640/ArduinoMorseCode/MemoryKeyerV2.0.3.zip

V2.0.4 Added sidetone envelope shaping. Required several other changes.
https://dl.dropboxusercontent.com/u/40929640/ArduinoMorseCode/MemoryKeyerV2.0.4.zip

Shaped Dits at 45 WPM

Shaped Dits at 45 WPM

V2.0.4.1 Bug fix was dropping dits on a long string of upper case “H”s. Disable interrupt while changing sine tables.
https://dl.dropboxusercontent.com/u/40929640/ArduinoMorseCode/MemoryKeyerV2.0.4.1.zip

V2.0.5  Changed AtoM table from prog_uint16_t to char to save memory, which created bug where setup does gratuitous write to A6 and A7. Fixed problems when compiling under Arduino IDE 1.6.1, did not accept typedefs in pgmspace.h. Fixed bug in initByte, 1.6.1 did not like  aaByte = aByte -= 0x20;  Compiled size is 2k smaller in 1.6.1 and no more bogus compiler warnings!
https://dl.dropboxusercontent.com/u/40929640/ArduinoMorseCode/MemoryKeyerV2.0.5.zip

April 30 – Have not changed the V2.0.5 sketch but did redo the audio section of the Altoids keyer. I found the single transistor audio buffer was not satisfactory, distorting badly when driven by a sine wave. Also it was drawing 50 milliamps at idle. I removed the transistor and connected an LM386 amplifier – much better sound and very little current draw when idle. A revised schematic is at:
https://dl.dropboxusercontent.com/u/40929640/ArduinoMorseCode/MemoryKeyerV2.0.5Schematics.zip

Notes

20 March 2015  —  The keyer sketch was developed with Arduino 1.0.6. Recently I downloaded the latest Arduino IDE 1.6.1 and discovered the keyer sketch will not compile. It appears the newer version of GCC will not accept the typedefs used in the pgmspace.h library. I will upload a 1.6.1 release as soon as I figure out what’s going on. FIXED see V2.0.5 above.

24 March 2015  — Was shopping in Frys and bought an inexpensive (< $3) adaptor, is USB A female to PS2 male, is about the same size as the two connectors placed end to end.  It was made by Shaxon Industries in guess where. To my complete surprise it works. Using the adaptor I can connect any USB keyboard to the keyer which is good news, as PS2 keyboards especially compact ones, are getting hard to find. I measured power supply current with the adaptor, it does not add significant drain over the 25 Ma the keyer itself draws. The small USB keyboard I tried added only about 3 milliamps when not typing. I did find the transistor I used to buffer the speaker draws 25 milliamps itself, will have to find a more efficient amplifier.