Computing stuff tied to the physical world

Generating sine waves with DDS

In AVR, Hardware on Dec 4, 2011 at 00:01

This is a topic I’ve covered before, in a post of about a year ago, but given the recent post about a sine wave generator, and yet another opportunity to learn and show the new scope in action, here goes…

The first step towards Direct Digital Synthesis (DDS), is to generate a rapidly-adjusted analog signal through a Digital-to-Analog Converter (DAC). One way to do so is to use a resistor ladder network, tied to a number of digital output pins. The idea is that all these pins are either 0 or 1 using fixed voltage levels, so with the proper resistors, you get a signal where bit N has the proper weight in the final signal to represent the voltage 2^N.

With 8 output bits, you get an 8-bit DAC which can output voltages 0 .. 3.3V in 256 steps, i.e. ≈ 13 mV each.

The next step is to approximate a sine wave by rapidly adjusting the output bits to the values of a sine wave. This toneGen sketch from the 2010 weblog post does precisely that:

This lets us generate an decent sine wave by stepping voltages in the proper sequence, looping forever:


The trouble is the “glitching” and the step-wise behavior of the signal:


This last image shows a small portion of the signal near zero, greatly magnified – and it’s quite a mess!

Fortunately, this is usually very easy to fix with a low-pass filter (even just a single R-C filter), since these artifacts are at a much higher frequency than the generated sine wave itself. But let’s not go into such details for now.

The AD9851 chip used in the Sine Wave Generator works the same way, but it has one more clever trick up its sleeve, which lets it generate arbitrary frequencies using a single fixed crystal-based master clock.

Let’s start from a 1 MHz clock, and use a 1000-element lookup table for the sine wave. Then every microsecond, a new value is looked up, and after 1000 lookups we can start over. The result would be a 1000Hz sine wave.

Now suppose we want a 500 Hz sine wave, driven by the same 1 MHz clock source: we can simply re-use the same table entry twice, before moving on to the next. Likewise, for a 1 Hz sine wave, we’d re-use the same table entries 1000 times, before moving on to the next table entry.

How about 300 Hz? Ah, yes, that’s a bit tricky. We’d need to re-use the same table entry 3 1/3rd times, which is not really meaningful. But what we can do, is represent the step time as a fractional value, i.e. 0.3. The 1st “step” is 0.3, the 2nd 0.6, the 3rd 0.9, the 4th 1.2, etc. The fractional part is called the “phase”, BTW.

And now the big trick: ignore the fractional part while deciding which table entry to use!

This causes the table entries to be used in sequence, but possibly with a slight jitter as the stepping progresses in such a way that the full table will be cycled through exactly fast enough to produce the desired frequency.

So 1 Hz output is produced with a 0.001 step, and 500 Hz is a 0.500 step. I.e. frequency = 1000 x step.

The same mechanism can also be used to generate frequencies higher than the 1 KHz you get when stepping through each of the 1000 table entries with a 1 µs step rate. All you need to do is allow the fractional step rate to be larger than 1. Stepping through the table with rate 100.000 (i.e. skipping the next 99 entries each time) will generate a 100 KHz sine wave, albeit with only 10 data points per wave. So its amplitude changes will not be as fine-grained, but its frequency will be exact. Again, same formula: frequency = 1000 x step – easy!

This is the basis on which a DDS chip such as the AD9851 can adjust its frequency output. It’s based on very fast hardware with a very fast DAC: the input clock can be up to 30 MHz, and it even has a built-in 6x clock multiplier, so the “sine wave table stepping” can be based on a 180 MHz clock, which is equivalent to a 5.56 ns step time!

For completeness: an Arbitrary Waveform Generator (AWG) works similar to a DDS in that it also synthesizes a wave by running samples through an DAC from a table, but now the table may contain anything, not just a pure sine wave. The entries in the table describe one full wave. In this case, stepping is not possible (neither fractional nor skipping) because then you’d no longer be creating the proper waveform. Instead, an AWG really has to accurately control its step time from table entry to table entry to produce the desired frequency. This is more complicated – also because the wave table is RAM, not just a fixed ROM with sine wave coefficients.

So much for DDS and AWG … onwards!

  1. How is performance on very low frequencies, especially: how much does a 50 Hz sine wave drift? Compare differentially mains on one pin and a crystal-derived frequency on other JeeNode pin. Then you could perhaps do without having to swap the ceramic resonator for a crystal on the JeeNode.

    • It’ll drift as much as the clock driving the DDS. You can’t “win frequency accuracy” any other way than by improving the clock stability.

  2. hmm… and how would this be used with all the JeeNodes ?

  3. “You can’t “win frequency accuracy” any other way than by improving the clock stability.”

    So when do we see the article about the oven-controlled GPSDO orchestrated by a JeeNode? :D

Comments are closed.