It is a truth universally acknowledged, that a person in possession of an oscilloscope must draw Lissajous curves.

As the fine Wikipedia article1 explains a Lissajous curve is a parametric plot of sinusoids:

\[ \begin{align} x &= \sin(a \, \omega t + \phi), \\\ y &= \sin(b \, \omega t). \end{align} \]

To draw nice curves we want \(a/b\) to be rational, and for the whole thing to be precise and stable.

In the past, one might have used use fancy analogue electronics to generate these sinusoids, but today there are good digital alternatives.

In particular, we will:

With all this we can set the sinusoids’ frequencies anywhere up to about 20MHz with a precision of about 0.03Hz.

Hardware

The key component is the AD9850 DDS synthesizer. Conceptually this generates a sine wave whose frequency is given by

\[ f = f_m × \frac{n}{2^{32}}. \]

where \(n\) is a 32-bit number we choose, and \(f_m\) is the frequency of the master clock supplied to the chip.

Rather than buying the chip directly it’s easier to buy a module containing the AD9850 from eBay. Most of the these modules5 consist of the AD9850 plus a 125MHz oscillator. I think most of the modules are clones of the same design, but caveat emptor. Mine looked like this:

Note: The AD9850 can also produce a square-wave output, and the trimmer adjusts its duty-cycle: we can ignore this.

In essence, we just apply power, send the relevant configuration data from the Arduino, and we’re done.

In practice, there is one issue which has us reaching for the soldering iron: we need to synchronize the master oscillators. That’s just a case of removing the oscillator from one module and bodging a connection to the other. It’s easy to do if you remember which pin to connect! I suspect doing this isn’t ideal: the wire’s carrying (and thus presumably radiating) 125MHz.

Before I did this, I found the master frequencies differed by about 6ppm. That’s a bit better than I expected.

I wasn’t able to find a data-sheet for the precise oscillators on my boards, but they’re a bit like the TXC 7C series.6 Certainly pin 3 (diagonally opposite the pin 1 spot) is the clock output.

Although sharing the master oscillator ensures that the synthesizers won’t drift with respect to each other, they can still be a constant phase apart. Assuming that the synthesizers lock to the phase of the master clock, they will potentially be an integral number of cycles apart. At 125MHz, one cycle takes 8ns. If we’re synthesizing a 100kHz sine wave, that’s a phase error of about 0.3°. Effectively then, the sinusoids have a random arbitrary offset from each other.

To some extent we could address the problem by better synchronizing the synthesizers’ reset signals and frequency adjustments, but I’ve not explored that.

Instead it’s easy to adjust the phase to the desired value. There are a couple of different approaches:

The latter can be improved by making the Arduino perturb the frequency for a fixed time. The software described below does this and gives a tuning resolution of roughly 1.5°. One could easily do better, though I’ve no idea about the accuracy of the method.

The original prototype was build on a breadboard,

but then transferred to matrix board having proved it worked:

Software

There are many AD9850 drivers on the Internet. It falls into that class of hardware which presents just enough complexity that it’s helpful to start from working code, but is easy enough that there’s nothing much to encapsulate.

Many examples use a static singleton AD9850 device, which makes it harder for our application. However, Poul-Henning Kamp wrote something more suitable7 which I proceeded to clone and butcher. You can see the result on GitHub.8

There are three key changes:

  1. I added support for a reset line;
  2. I extended the API to facilitate generating sinusoids with frequencies in a rational ratio;
  3. I added an example to drive a couple of synthesizers over a serial connection to the Arduino.

On top of this I changed the API’s style to suit my own preferences.

The key API change is to explicitly expose the integer which sets the AD9850’s frequency. Thus we can easily ensure that e.g the synthesized frequencies are in the ratio 3:2 without worrying about how they’ll be rounded.

For example, to set the oscillators to 200kHz and 300kHz we might do this:

AD9850 osc1(...);							
AD9850 osc2(...);							
									
double f = 100000.0;							
									
uint32_t base = osc_1.calc_phase_delta(f);				
									
osc1.set_phase_delta(2 * base);						
osc2.set_phase_delta(3 * base);						

If the 125MHz master clock were exactly correct we would see output frequencies about 0.0095Hz and 0.0142Hz too high. However regardless of the master clock their ratio will be exactly 2:3.

A full recipe

It’s easy to replicate the example at the top of the page. Begin by building the hardware.

If you want to make stable pictures, you’ll need to modify the AD9850 modules with a soldering iron to share a common clock, as described above. You could get away without doing this though.

Connect the Arduino to the PC and check that you can program it. The Arduino website has a good getting started page9 if you need help with that.

Now connect:

Arduino PinAD9850 1AD9850 2
+5VVccVcc
GNDGNDGND
D4W_CLK
D5FQ_UD
D6DATA
D7RESET
D8W_CLK
D9FQ_UD
D10DATA
D11RESET

Note that there are two Vcc and GND pins on each module so you’ll end up running four wires from both the Arduino’s 5V output and its GND pin.

Finally, connect an oscilloscope to the ZOUT2 outputs of the two modules. Set the scope to XY mode (often a setting in the horizontal timebase), and set the inputs to AC coupling with a scale of about 200mV per division.

If you just want to see the waveforms plotted against time, the signals are 20–30kHz, so a timebase of about 5µs per division is about right.

That’s the hardware done.

Next the software.

Download the AD9850 driver from GitHub10 as a ZIP file and add it to the Arduino IDE. The key option is in the Sketch > Include Library menu.

You should then be able to compile and upload the Dual example from the File > Examples menu. When you upload it to the Arduino and it runs you should see something on the scope.

To change the pattern, open a serial connection to the Arduino. You can use the Arduino IDE’s own Serial Monitor, but that will only send a command when you hit return which gets boring. On the Mac or Linux, gnu screen11 is a better alternative.

Once connected, h will display help:

$ screen /dev/tty....  115200    					
									
Dual AD9850 controller							
M J Oldfield, 17.iv.2015						
									
Controls:								
  tweak phase:                 <,>					
  change frequency multiplier: 1,..,9					
  select second oscillator:    :					
     so e.g. 2:3 does what you expect					
  tweak frequency of osc 1:    k,l					
  as above just for a trice:   i,o
  zero frequency tweaks:       z					
									
Current state:								
  base: 10.000kHz => 343597						
  osc1: base * 1 + 0							
  osc2: base * 1 + 0							
  phase: 0								

To recreate the movie at the top of the article type 2, :, 3, k which should generate signals of roughly 20kHz and 30kHz, then slightly increase the lower frequency. You can think of this as continuously adjusting the relative phases of the signals which causes the display to ‛rotate’.

Hit z to stop the rotation. Use i and o to step the rotation by changing the frequency of oscillator 1 for a fraction of a second. After about 250 such steps the display will return to the original pattern.

Addendum

The Si535112 is probably a better choice than two AD9850s. Development boards are available on eBay for under £10.