MCU Memory Constraints and Morse Encoding

In my previous post about completing my initial code for my MCU based beacon keyer I made mention to the use of memory. Indeed, my code was of such size I had to use the largest AVR ATtiny chip I could (well, memory wise). The ATtiny85 gave me a whopping 512 bytes of SRAM – and 512 of EEPROM and 8KB of flash. Who could ever need more than that right!

Sending just my callsign (VK1IS) worked fine with my code running on this MCU, however last night I thought I'd try the longer string of:

Could be useful for common CW comms.

Unfortunately, that resulted in the chip running out of memory when it got the third iteration of my callsign. With compile time memory usage being up at 260 bytes with this string; then the need for memory for active instructions; and then finally the dynamically allocated memory to store the encoded version of that string; there simply wasn't enough space. Indeed, with my current encoding method, to encode that string required more than 150 bytes and that was more than was available (after the 260 bytes at compile time and active instructions). (Note here, my look-up tables – by manual calculations – require 223 bytes!!)

So, it seems I should do some memory optimisations after all.

Conveniently, I received an email from Owen this morning (VK1OD) informing me that it is possible to encode all Morse characters in 8 bits. So after a bit of pondering I realised this would be possible by just using (for example) 1 for dit and 0 for dah. But seeing it's variable length what do you use for a marker for the start. In trying to figure this out, eventually I decided to be lazy and search the web. That search revealed this:

Seems all I need is to just mark the start of a sequence with a 1:

The format of each Morse character is as follows: Zero or more 0 bits, followed by a single 1 bit, followed by the Morse Code representation of the character in binary, with a 0 indicating a dit and a 1 indicating a dah.

That first "single 1 bit" is what then marks the start.

With this method one can definitely encode all 41 characters in the Koch set plus a good number of prosigns (AR, KN, etc.). As time permits I think I'll look at writing another cw library to implement this. Big memory will be saved – about 75% – and maybe I'll look to see if I bother with an intermediary encoding of the string or not (I have some ideas on how to deal with that to save significant memory.) Maybe it'll fit on an ATtiny13 yet (64 bytes of SRAM, 64 bytes of EEPROM and 1KB of Flash).

While looking at this I also looked at the code for the Freakin Beacon. It seems rather than a look-up table they've gone down the path of a subroutine for every character. This would save on SRAM, but then the code size would be bigger. I may also consider looking at this as another option – should be able to generate the code for this from my current CW library. 😉

CW Beacon Keyer

You might be wondering why activity has been a bit minimal lately. Well, our first child was born almost one month ago now so I’ve been a tad busy. 😉 I’ve got a couple of more things coming up soon, but hopefully activity will resume in the next month or two. 🙂

That said, in the meantime I’m reading and where possibly playing with simpler things.

For example, some months ago I decided to start looking into microcontrollers. I pondered between AVR and PIC and in the end with with AVR. So I grabbed myself an AVRISP mkII and a few ATtiny chips and built up a basic development board following instructions on I Make Projects. Within a short time I had a flashing LED but then got busy.

Anyway, I had decided a great first MCU project would be a CW Keyer (mainly for QRSS on LF, but also wherever else). These can be implemented many ways (and indeed, there’s many bits of code one could download) and many simply hardcode the sequence for the callsign. However, I wanted to learn and build from scratch – plus it was a great opportunity to do some C programming.

To that end I decided to write up a library that would provide encoding of a string into a CW element sequence. I could then enumerate over this sequence generating the matching delays for the key-ups and key-downs. Further, I did calculations based on the PARIS methodology for the element durations for various common speeds covering 5WPM to 40WPM and QRSS1 to QRSS60. I initially wrote the library and unit tests on the PC with GCC, and then when it was ready just added it into an AVR Studio 5 solution.

With such a library, the resulting MCU specific code was minimal and I have two ‘configuration’ variables – one for speed and one for the string to send.

Yesterday I got this all working and successfully tested on my dev board with an LED. Doing so I learnt several things such as _delay_ms() requires a constant parameter and more significant how to use the AVR Studio simulator – very handy tool.

Oh, I also came to better appreciate the minimal memory contraints of the ATtiny chips. In the end my program had to be run on an ATtiny85 (although it may fit on a ATtiny45), this is due to the encoding library and it’s look-up tables being on the chip. This results in AVR studio stating SRAM usage of 240 bytes (ATtiny45 has 256 and ATtiny85 has 512). Strictly speaking there is no need for the encoding library on the chip so you could go smaller – you could run it on a PC, grab the encoded array and place it on the EEPROM and have it read from there. But hey, for now this is okay me thinks.

So the video shows the result with an LED flashing out my callsign at 5WPM. From here I just need to whip together a small number of components to have a nice standalone beacon/QRSS keyer – however, not entirely sure when I’ll have the time for this. When that’s done, I’ll be sure to share all. 🙂