What I learnt today…

… is that on the AVR, the “Data Memory Usage” information given by AVRGCC  only refers to memory allocated at compile time, and does not take the stack into account.1 2 The stack is not to be underestimated: it holds not only the return addresses from function calls, but also all local variables3 of the function(s) called.

So you might feel safe and sound reading something like “Data Memory Usage : 66 bytes 51,6% Full”, thinking there’s plenty of space left for future features; and then the stack still swoops down and corrupts your precious data because of a couple of nested function calls.

Took me a while to figure out what happened here. Then again, I have never worked on a machine with just 128 Bytes of RAM before.

The good news is that this can be reproduced reliably in the AtmelStudio simulator: Find the memory locations of the data being corrupted, set data breakpoints, and when the simulator stops at the end of something like this

000000F5 PUSH R11 Push register on stack 
000000F6 PUSH R12 Push register on stack 
000000F7 PUSH R13 Push register on stack 
000000F8 PUSH R14 Push register on stack 
000000F9 PUSH R15 Push register on stack 
000000FA PUSH R16 Push register on stack 
000000FB PUSH R17 Push register on stack 
000000FC PUSH R18 Push register on stack 
000000FD PUSH R19 Push register on stack 
000000FE PUSH R20 Push register on stack 
000000FF PUSH R21 Push register on stack 
00000100 PUSH R22 Push register on stack 
00000101 PUSH R23 Push register on stack 
00000102 PUSH R24 Push register on stack 
00000103 PUSH R25 Push register on stack 
00000104 PUSH R26 Push register on stack 
00000105 PUSH R27 Push register on stack 
00000106 PUSH R28 Push register on stack 
00000107 PUSH R29 Push register on stack 
00000108 PUSH R30 Push register on stack 
00000109 PUSH R31 Push register on stack

you know Bob’s your proverbial male relative.

Repairing an AVR DDS Signal Generator

Background

As far as I can tell, the first use of an AVR to do direct digital synthesis of an analog signal was by Jesper Hansen in 2001.  Mindaugas Marozas picked up the idea to create a stand-alone function generator in 2006. In 2008, Mindaugas published an improved version, which has become the basis of many homebrew projects, as well as a number of Chinese clones. Georg Latzel, DL6GL, gives a very nice and detailed rundown of the theory of operation (in German).

What’s wrong?

In December 2017, I purchased one of these clones on eBay. Unlike the projects linked above, this one does not require an external three-voltage power supply (+5V for digital logic, -12V/+12V for the op-amp rails). Instead, it uses a single DC barrel connector for (what I thought) +12V, deriving +5V with a 78L05, and -12V with an ICL7660.

ICL7660 pinout
ICL7660 pinout (from the Intersil / Renesas datasheet)

Avid readers of the ICL7660 datasheet will already have spotted the problem: The ICL7660 is specified only up to +10V. 1 With a 12V supply, it worked fine for about half an hour, then gave up. Now, the 5V part of the circuit (AVR, display, buttons, high speed digital output) still works fine, but the analog output appears completely dead. On pin 5 of the ICL7660 (VOUT), I measured +0.2ish Volt instead of the expected – V+. At least, the ICL7660 is socketed.2

DDS board
The DDS board in question, with the display removed. Note that the ICL7660 is the only socketed chip. Also, note that it does say +12V above pin 8 of the ICL7660. If you bought the same board, and made the same mistake, this article is for you.

The Fix

Having replaced the ICL7760, I now get -9V at VOUT, for V+ = +9V, and the analog output works again.

And that’s all?

Fortunately, yes. I also bought a spare opamp, but I’m glad I didn’t need it. I still dread SMD desoldering.

Here are some nice pictures from the working signal generator:

The charge pump at work

ICL7660 charge pump capacitor voltages
ICL7660 charge pump capacitor voltages. For the first half of the cycle, CAP+ (yellow) is connected to V+, and CAP– (cyan) is connected to ground, charging the capacitor to V+. In the second half of the cycle, CAP+ is connected to ground instead, leaving CAP– at –(V+) to charge the charge reservoir capacitor at VOUT.

Some waveforms

AVR DDS: 1 kHz sine
AVR DDS: 1 kHz sine
AVR DDS: 1 kHz EGC waveform
AVR DDS: 1 kHz EGC waveform. This nicely shows of the ability to generate arbitrary waveforms through DDS, even though it is of very limited use.
AVR DDS: "noise"
AVR DDS: “noise”. Note that “noise” means a different, random 8-bit value output every 80us or so.
AVR DDS: 1 MHz high speed TTL
AVR DDS: 1 MHz high speed TTL. Note the 8 MHz and 16 MHz components visible in the high state.
AVR DDS: 8 MHz high speed TTL
AVR DDS: 8 MHz high speed TTL