Building a Lissajous Pattern Display: ESP32 Dual-DAC Output Driving an Oscilloscope in XY Mode
A Lissajous figure is the looping, figure-eight-or-stranger curve traced on an oscilloscope screen when you feed one sine wave into the horizontal (X) input and a second sine wave into the vertical (Y) input instead of letting the scope sweep time on the X axis the normal way. The resulting shape encodes the frequency ratio and phase difference between the two signals directly in its geometry — a 1:1 ratio in phase draws a diagonal line, a 1:1 ratio 90 degrees out of phase draws a circle, and a 2:3 ratio draws a more elaborate woven pattern. This project builds a small ESP32-based signal source purpose-built to generate these patterns on demand, which is both a genuinely useful way to learn phase and frequency relationships hands-on and a strangely mesmerizing desk toy once it's running.
Why You Need Two Independent DACs
The ESP32 has two onboard 8-bit DACs (on GPIO25 and GPIO26 on the original ESP32; check your specific variant's pinout, since not every ESP32 family member has the same DAC peripheral), which is exactly what this project needs — one DAC drives the X channel, the other drives Y, and because they're on the same chip you can keep their phase relationship precisely synchronized in software, which is the whole point. An 8-bit DAC gives you 256 output levels, coarser than a proper signal generator but entirely sufficient for Lissajous work, where the shape being traced matters far more than amplitude precision.
Generating the Waveforms
Rather than using the AD9833 DDS approach covered elsewhere on this site for a single precise waveform, this project generates both X and Y waveforms directly in software using lookup tables, since the two channels need to stay phase-locked to each other in a way that's simplest to guarantee when a single loop is computing both outputs each cycle. Precompute a sine lookup table (256 or 512 entries is plenty for 8-bit DAC resolution) and step through it on a timer interrupt, writing to DAC1 for X and DAC2 for Y. For a classic Lissajous figure, step through the Y table at a different rate (or a different table entirely) than the X table — a 2:1 index-advance ratio between the two produces the classic figure-eight, a 3:2 ratio produces a more complex woven shape, and a 1:1 ratio with a fixed index offset between the two tables produces an ellipse whose aspect ratio depends on that offset.
X:Y Frequency RatioPhase OffsetResulting Pattern 1:10°Diagonal line 1:190°Circle 1:145°Diagonal ellipse 1:2variesFigure-eight / parabola-like curve 2:3variesWoven multi-loop pattern 3:4 and higher ratiosvariesIncreasingly complex star/weave patternsDriving the Scope
Connect DAC1 (X) to the oscilloscope's Channel 1 input and DAC2 (Y) to Channel 2, then switch the scope out of its normal time-sweep mode into XY mode (every scope with two channels has this; check your model's menu, often labeled explicitly "XY" or "X-Y"). In this mode, the scope ignores its internal timebase entirely and plots Channel 1's voltage against Channel 2's voltage as a literal X-Y point, tracing the Lissajous curve in real time rather than showing two separate waveforms over time. Because the ESP32's DAC output rides on a DC offset and swings only across a modest voltage range (roughly 0-3.3V), you may need to adjust the scope's vertical scale and position on each channel to center and size the pattern nicely on screen — there's no signal conditioning strictly required, though a simple DC-blocking capacitor on each line gives a more centered, symmetric figure if your scope doesn't have convenient offset controls.
Adding Interactive Control
A basic version just runs a fixed ratio on power-up, but the more engaging version adds a rotary encoder or a couple of buttons to let you step through different frequency ratios and phase offsets live while watching the pattern reshape on the scope — this is where the project earns its keep as a teaching tool, since watching a figure-eight smoothly morph into a woven triple-loop pattern as you nudge the ratio makes the underlying math viscerally obvious in a way that reading about Lissajous curves never quite does. Add a small OLED showing the current ratio and phase values so you know exactly what pattern you're looking at without having to count loops on the scope screen.
Safety Notes
This is a purely low-voltage build — ESP32 logic levels into a scope's high-impedance input — with no mains connection and no meaningful electrical hazard beyond standard low-voltage handling care. The only real risk is to the ESP32's DAC pins themselves: never connect them to anything beyond the chip's rated voltage range, and if you add external buffering or amplification for a brighter/larger pattern on an older analog scope, make sure that stage can't backfeed voltage higher than the ESP32 tolerates onto the DAC output pins.
Once dialed in, this little build turns an oscilloscope most people only ever use for debugging circuits into a genuinely captivating visual instrument, and it's one of the more direct, intuitive ways to actually feel frequency ratios and phase relationships rather than just calculating them on paper.