The most essential instruments of an electronics lab: a power supply, an oscilloscope, and a signal generator. Equipped with the first two, I decided to try my hand at building the third. In this article I present you with an original design of a very low cost, versatile and precise baseband signal generator based on a DDS (direct digital synthesis) architecture.


The finished instrument. Click for hi-res [775 kB JPG]

Features

  • Excellent frequency and amplitude stability.
  • Generated waveforms: Sine, Square, Triangle and Sawtooth.
  • Output frequency: between 0.1 Hz and 1 MHz; settable with 0.1 Hz resolution.
  • Output impedance: 50Ω.
  • Output amplitude: between 10 mVpp and 20 Vpp unloaded; half of that into 50Ω (that is, up to 10 Vpp or 24 dBm). Settable with 10 mV resolution.
  • Duty cycle for square and triangle waves: 0 to 100% settable with 0.1% resolution.
  • For generating asymmetrical waveforms, it is possible to limit the positive and/or negative half to any level between 0 and 100% (full scale output), settable with 0.1% resolution. One of three limit modes governs how the waveform is limited/scaled: Saturate, Half-Scale, Full-Scale (explained later).
  • 3.5mm audio jack (input impedance 1MΩ) with level pot for AM modulation input.
  • Digital ASK modulation for generating DCF77 time code transmission.
  • Intuitive user interface with a large LCD, four push-buttons and a rotary encoder knob.
  • UART interface for remote control, development & debugging.

Design overview

DDS, or direct digital synthesis, is a method for generating waveforms (in principle, arbitrary ones) with high frequency resolution and stability, from a single stable clock. What we do, basically, is:

  1. store samples of a single period of the desired waveform in memory;
  2. periodically output a sample from this array (according to the momentary phase) to a DAC to obtain an analog signal;
  3. after each sample, increment the phase proportional to the current frequency.

Because we want to do so much more than just generate a sinewave of fixed amplitude at a user-specified frequency, we want a flexible, programmable solution that only an embedded system can provide. Otherwise we could just use a chip such as the AD9850. First of all, we want direct control over the samples (since we want to support multiple waveforms plus half-wave limiting to generate asymmetrical signals). Once that, plus the usual interfacing duties, are covered by an MCU platform, there is not that much a dedicated DDS chip would buy us. Yes, we could generate signals into the tens (or even hundreds) of MHz, but for our first (baby) signal generator, a “baseband” or “extended audio range” capability is plenty to experiment with. On the other hand, we want hefty drive capability at substantial output levels: 10Vpp into 50Ω (24 dBm) requires a dedicated output stage regardless.

Thus our design challenge: only cheap, common parts, no fancy IC that does everything… Let’s see how far that takes us?

The complete circuit

The complete schematic is available as a PDF. I recommend that you open it in a separate window, move it over to the side and refer to it as we proceed with the discussion.

Below I will present the analog signal paths in detail, but first a run-down of the main functional blocks and their central components:

  • For all the computational tasks (the DDS itself up to the DAC; maintaining state; operating the user interface) we use a Raspberry Pi Pico board, with its RP2040 processor running our program. The DDS runs at a clock frequency of 8 MHz; the code outputting samples to the DAC runs, all by itself, in a tight loop on the second core.
  • The 128x64-pixel monochrome graphical LCD is driven by a 16-bit register (two 74HC595 chips) fed via SPI, plus a separate strobe for triggering loads.
  • Input switches have low-pass RC filters on them for hardware debouncing.
  • We use the DAC0800, a common 8-bit fast (parallel) multiplying DAC, to convert the eight data bits output from the Pico into an analog signal (a current, in this case). In its capacity as a multiplying DAC, it facilitates amplitude modulation via the reference voltage (modulated according to the analog input or the ASK digital modulation pin).
  • The analog signal is treated by an attenuator built around a DG408 analog switch, providing attenuation in 6dB steps, from 0 to (nominally) -42dB.
  • The DAC amplitude is precisely set by an analog level created by low-pass filtering a PWM output of the Pico; this 12-bit value is used to fine-tune the amplitude within the current step of the attenuator. Using the attenuator and the level adjustment in tandem makes it possible to operate the DAC at an ideal reference current level, while allowing a wide range of output amplitudes. It also makes it easy to apply calibration data to offset frequency-dependent behaviour.
  • A complementary transistor stage drives the output with low impedance.
  • The circuit is supplied by an on-board PSU accepting the mains transformer’s secondary wiring, supplying ±15V for the analog circuits as well as +5V for feeding the Pico board.

Let’s take a closer look at the analog parts of this circuit.

The main analog path: from DAC to output


From DAC to output: overview (click to enlarge)

The above circuit is the meat of our DDS: the signal path from DAC to instrument output. From left to right: DAC, attenuator and power amplifier. The first two stages are buffered by JFET followers to avoid loading high-impedance signals. Let’s take it step by step.

The analog signal originates at the DAC0800, receiving eight data bits DAC[7..0] from the Pico. Note that this is a current-output DAC. The resistors R13 to R16 set the reference current based on the VREF voltage, and convert the output current to a bipolar DAC_OUT voltage. For example, if VREF is 10V above ground, the 8-bit range of values will be converted to ±10V on DAC_OUT.

Since DAC_OUT is at a high impedance (additional current to/from that node will change its voltage, thereby introducing an error), we need a buffer to convey this voltage on to ATT_IN, the input of the attenuator. We could just use an op-amp here, but what kind of op-amp? Well, we want to be able to generate 20Vpp signals, at a frequency of up to 1 MHz. That translates to a slew rate of ~63V/µs, so a pretty high-end op-amp! And remember: no fancy parts in this design!

Hence the humble JFET follower. Since we need very high input impedance but no voltage gain, it serves us nicely here. It has absolutely no problem with that kind of slew rate. Ideally, the two JFETs would be part of the same integrated dual JFET, to minimize manufacturing spread and ensure thermal coupling. But again, no fancy parts! We will show our “poor man’s dual JFET” solution later on, when discussing the construction.

The trimpot ensures that we can set the exact operating drain current at which Q1 does not introduce any DC offset. It is a set-and-forget thing, and chiefly necessary due to the above compromise regarding part selection. We don’t want DC offsets to accumulate, because the whole signal path is DC coupled (or else we’d have to put a bound on the lowest frequency).

There is no gain at all in this whole signal path, because the DAC is itself capable of producing the 20Vpp maximum amplitude signal. However, to generate smaller signals, we cannot arbitrarily reduce VREF – the DAC output would become rather poor if we reduced its reference current too much.

The solution is to keep the DAC happy with a reference current within the healthy range, and use a switchable attenuator to reach lower output amplitudes. Our solution is a classic R-2R ladder built with 0.1% (precision) resistors, with taps feeding into the DG408 analog switch. Each tap, from top to bottom, halves the signal (-6 dB), at least in theory. (In reality, it’s frequency-dependent, as the divider is capacitive as well as resistive, not to mention switch capacitance. More on that later.) Pico outputs the 3-bit selector signal ATT_A[2..0] to set the input tap to use.

Since the chosen tap is at a high impedance, the same kind of JFET follower circuit is hung on the switch output to buffer the voltage into ATT_OUT, the output of the attenuator.

This signal drives the power amplifier stage, built with cheap and common bipolar transistors. It is a basic push-pull emitter follower, but with the output transistors in the somewhat exotic (and advantageous) Sziklai pair configuration.

The output impedance is very close to 50Ω and is the sum of R48/R49 and R50 (49Ω in total) plus the output impedance of Q7/Q8 looking into the collector (a fraction of an ohm).

Level control & modulation circuit

Remember VREF, setting the reference current of the DAC (and by extension, the generated signal amplitude)? Well, that is the output of another analog signal path:


Level control & modulation circuit (click to enlarge)

A PWM output of the Pico is driven by a 12-bit value (0..4095) to set the signal level. This output is connected to the AMP_PWM signal, low-pass filtered by R12 and C4 to produce a DC voltage between 0 and 3.3V on the noninverting input of U2A, which amplifies it 5x to cover the whole range from 0 to VCC.

Parallel to this, U2B buffers the analog input coming off the 1 MΩ leveling pot, which controls the analog input signal or, if the analog input is unplugged, the MOD_ASK digital input coming from the Pico. (There is a jumper so the MOD_ASK input can be disabled, tying it to ground instead.) Worth noting that this signal path is DC coupled as well, so the input jack could also receive a digital signal (or DC voltage) to control the amplitude.

The level control & modulation sources are accurately summed by U3 to arrive at VREF. Due to the modest bandwidth requirement, we employ the vintage TL072 (but manufactured on the latest process, as promised by the TL072HIDR) with precision resistors.

PCB design, manufacturing and assembly

The circuit design presented above emerged as a result of much experimentation on the solderless breadboard. At the point where I had a working prototype with all the features verified to work (photo [1.3 MB JPG]), it was time to move on to the next phase: PCB design.

First I had to decide on the instrument housing, because I wanted the PCB to fit nicely into whatever case I ended up with. This became an iterative process, considering and discarding some alternatives. Finally I settled on a transparent blue box which looked like it could take in the mains transformer, the main PCB and everything else (the voluminous LCD panel was of chief concern), if only I did the PCB right…

It took a couple iterations to fit the design into a space of 127 x 72 mm, measured to fit snugly into the case interior left available beside the mains transformer. To spare board area and improve performance, I designed with 0805 SMD passives and SOIC variants of the chips where practical. As is now usual with my PCB designs, I kept using 8 mils as my go-to trace width for signals, stepping up to 15 and 40 mils for low impedance traces and supply rails.


The PCB layout, designed in KiCAD 9. Click for hi-res [652 kB PNG]

The fast digital signals coming out of the Pico (the 8-bit DAC bus and the 3-bit attenuator signal) are back terminated by 140Ω resistors inserted right at the driving end of the traces to minimize interference into the analog circuits. (This is also called series termination.) The resistance value comes from this impedance calculator after plugging in 8 mils trace width, 35 µm copper thickness, 1.6 mm board thickness and a best-guess εr of 4.4.

Back termination works by letting the high impedance (open circuit) receiving end reflect the incoming signal, then absorbing that reflection as it reaches the source end. The receiving end sees the full signal with no reflections. The driver sees a load that equals twice the line impedance, but only for the round-trip duration, after which the load becomes an open circuit.


Poor man's dual JFET

As a final design quirk, let me direct your attention at the JFET pairs Q1-Q2 and Q3-Q4, standing back to back on the PCB with the flat side of their TO-92 packages facing each other. These are what we call the “poor man’s dual JFET”, manufactured by shrink-tubing the two devices together into one thermally coupled unit. (We could have used SMD variants of these devices as well, except we could not have made this kind of dual JFET with them.)

The PCB got manufactured by PCBWay, a leading Chinese factory. They strongly encourage customers to upload conventional Gerber (as well as drill) files zipped into a package when ordering, instead of directly processing EDA tool project files. Fortunately, they do supply detailed and clear instructions for obtaining this output, e.g., on this howto page for KiCAD 9 (my current EDA tool), so it’s not much of a hassle. Each upload is checked by PCBWay engineers to make sure that the data is complete and makes sense from a fabrication perspective. This review only takes a couple minutes, after which the customer can complete the order.

After the order was placed, it was fun to watch fabrication go through the 15 or so steps, each defined and explained in a nice short video showcasing the factory facilities. And… they were done with my boards! PCBWay’s normal lead time is below 48 hours (that is, without paying extra for an expedited order). No need to wait a week or so, as with some other manufacturers, just so your design fits into their next batch.

I also received the boards in record time via DHL Express. This was my fastest PCB factory turn-around ever: order placed on the morning of the 23rd of April (already afternoon hours in China), manufacturing done by the 25th (a Saturday), and I had my hands on the boards on the afternoon of the 27th (Monday).

The stack of boards and the SMD stencil were all professionally packed in the box, the former in a vacuumed protective blipper bag with desiccant, the latter secured between two pieces of pressed hardboard. For the curious, here is a photo [1.2 MB JPG] of the (already unboxed) PCBWay delivery.

Final notes on the PCB service:

  • I ticked the option of specifying a location for the PCBWay production number assigned to the PCB, having put the placeholder text “WayWayWay” on the silkscreen layer (along the right edge, on the back side). It got rendered exactly at the specified location; it is small and non-intrusive. You can order a board without this number printed if you pay an extra $1.5, but I saw no need to do that.

  • I especially like that on the edges of the finished board, there are no remains of milling bridges (mouse bites) seen with certain other PCB manufacturers. The edges are just smooth and clean. Well done!

All in all, I am very happy with the boards (I got 5 pieces, the minimal order quantity), the SMD stencil and the service from PCBWay. Recommended!

[Full disclosure: The blog has accepted PCBWay’s offer of sponsoring us with their manufacturing services in return for an unbiased review.]

Even though I now have the necessary confidence to solder the less challenging types of SMD components by hand, I still went with the stencil method for this project, as it is much faster compared to soldering all the itty-bitty components one by one. And of course, watching the paste melt and phase-change from wet sand to shiny metal is somehow deeply satisfying. Regular solder paste (Sn 96.5%, Ag 3%, Cu 0.5%) was used with a reflow profile peak of 245°C; the hot air was set to 320°C coupled with a rather low airspeed.

For the curious, here’s a high resolution photo [3.0 MB JPG] of the board fresh after SMD assembly but before mounting any through-hole components. Below is the fully assembled board, complete with the Pico daughterboard:


The assembled board. Click for hi-res [2.6 MB JPG]; another take [2.6 MB JPG]

As I already had some preliminary working software from the breadboarding stage, it was easy to verify that the circuit works perfectly as expected. No surprises!

Construction

The instrument is built into a rectangular plastic box with a translucent blue upper half. I don’t recall where I found this box or what its original purpose was, but I kept it around as it was practically begging to be made into some gadget. The bottom half is black, with a grid of perforations conveniently providing some ventilation. The box measures 14 cm in both directions; its height is a bit less than 7 cm.


Innards of the finished instrument (click to enlarge)

The mains transformer is the result of some dumpster-diving – it is of a type commonly used in VCRs, set-top boxes, receivers/decoders and the like, now being gradually phased out and frequently turning up in electronics trash. These transformers are great, and their cost is literally just unscrewing and ripping them out of their original habitat. The secondary wiring ends in a 6-pin molex plug which we decided to keep (see the schematic for wiring notes).

The controls and connectors are wired to custom hand-made wiring harnesses built of flat cable, terminated with IDC plugs mating the sockets on the main board. After so many years of soldering wires to pin and socket headers, I really learned to love the IDC connector. I can easily press it on a flat cable without the (expensive) crimping tool. Alas, that is not the case with JST XH & co. – maybe I need to burn some cash on a PAD-11 or similar…

Software

Software running on the RP2040 is an integral part of this project. It consists of several modules for input event handling, calibration data, LCD display handling, main loop, and of course the DDS itself. It has the following main areas of responsibility:

  • On boot, setup peripherals and initialize each module.
  • React to pushbutton & rotary encoder state changes and push corresponding events into the input queue.
  • Read and buffer the UART input, and hand off finished lines for processing.
  • Maintain the state of the on-screen menu system and refresh the LCD as needed.
  • Recompute the wavetable (1024 samples of a single period to be output on the DAC) in response to changes in waveform and parameters.
  • If activated, generate periodic events for digital modulation (ASK) according to the DCF77 time code, based on the current RTC time.
  • Main loop on core 0: process input events and UART lines, update the on-screen menu system, and control the DDS parameters.
  • Main loop on core 1: feed the TX FIFO of the PIO state machine outputting samples on DAC[7..0] at a steady rate of 8 Msps.

The menu system is arranged as a hierarchy of vertically laid out menu items, each one being either a choice (such as a waveform), a parameter (such as the frequency) or an entry into another menu (for submenus such as waveform parameters). The code handling all this is fully generic; the actual menu structure is defined as static data, making it easy to modify.


Menu system overview (click to enlarge)

The bottommost screen indicates support for toggling the load impedance between HIGH Z and 50 OHM. The indicated amplitude (and its settable range) will be adjusted to reflect what you see on the scope; if terminated in 50Ω the amplitude will be halved.

Even though we use a 128x64-pixel graphical LCD, this project only employs it as a simple alphanumeric display. The font is gratefully snatched from here. We use an 8 pixel high font, because it fits nicely with the way this LCD is written to, and makes refreshing single rows very simple and economical both in terms of software and time.

The full software is published under the very permissive BSD license and is fully available in the project’s git repository under the pico subdirectory.

Demonstration & evaluation

So how well does it all work? In this section I will present you with a hopefully satisfactory coverage and discuss how the design performs.

Basic waveforms

The available waveforms are: sine, square, triangle and sawtooth. The instrument was set to generate a 10.00 Vpp signal at 5000.0 Hz; only the waveform was changed.


Basic waveforms (click to enlarge)

Waveforms with asymmetrical duty cycle

Square and triangle waves react to the duty cycle parameter. This can be set from 0% to 100% in 0.1% steps; the default value is 50%. For the triangle, duty cycle is the percentage of the period spent in the rising slope. Ramping up the duty cycle in 10% steps of square and triangle waves:


Duty cycle sweeps (click to enlarge)

Note that the sawtooth is exactly equivalent to a triangle with a duty cycle of 100%.

Limited waveforms

To create asymmetrical output, the interface offers to limit the positive and/or the negative half-cycle of the generated waveform. This is done by recomputing the samples stored in the wavetable, being continuously output to the DAC. Each half-cycle can be limited from 100% (full-scale, no limit) to 0% in 0.1% steps.

One of three limit modes specifies how exactly the samples of the waveform are recomputed:

  • Saturate acts as a hard limiter. Samples within the limit are not altered; samples above the limit will assume the limit value. Turning the knob on the positive limit, down from 100% to 0% in 10% steps (click to enlarge):

  • Half-scale proportionally scales the halfwave (positive and/or negative) with a limit below 100%. The two halves are scaled independently, each to its individual limit. Scaling down the positive limit in 10% steps (click to enlarge):

  • Full-scale proportionally scales the complete wave to fall within the set limits. This avoids distorting the waveform. Scaling down the positive limit in 10% steps (click to enlarge):

Setting a limit on the negative half-wave (or even both) works the same, as you would expect. And, since it is an independent post-processing step on the wavetable, it works uniformly for all supported waveforms.

Estimated analog bandwidth & DAC artifacts

By outputting a square wave and measuring the positive edge rise time tr, we can roughly estimate the analog bandwidth as BW = 1 / 3·tr. We do this for each attenuator level, as the effective analog circuit will be different in each case. Results:

Att. tr [µs] BW [MHz]
0 0.33 1.01
1 0.75 0.44
2 0.85 0.39
3 0.93 0.36
4 1.00 0.33
5 1.00 0.33
6 0.90 0.37
7 0.26 1.28

These numbers are suspiciously low! Even for attenuator channels 0 and 7, which seem to be the most transparent (channel 0 obviously, as the low impedance JFET follower output directly drives the analog switch input). The further diminished bandwidth of channels 1 to 6 is just adding insult to injury, and proves that our attenuator ladder is more capacitive than we thought. Never underestimate a couple tens of pF of stray switch capacitance is the lesson, I guess.

But even apart from that lesson, why does the direct signal on channel 0 (that does not even enter the attenuator ladder) have such a low bandwidth of just 1 MHz?

Let’s verify the bandwidth of the analog circuit post-DAC. We set up a constant positive voltage output (100% duty cycle square wave); set the attenuator to channel 1 (in software), turn on DCF77 modulation, and temporarily connect the MOD_ASK signal (available on a J4 jumper pin) to pin 5 of U5, the analog switch (that pin is the input of attenuator 1). The instrument output shows sharp digital transitions with ~10 ns rise time and some ringing, but fully settled within 50 ns. So our analog circuit should have a bandwidth around 35 MHz; north of 10 MHz seems like a very safe bet.

So it must be the DAC0800. Even though its settle time is specified as 100 ns (typ), which would mean that we should expect to be able to give it new input with a frequency of 10 MHz. We are very far from doing that, and still… something is off.

It might be the way we use the DAC; perhaps we’d need to do something more complicated than the resistor-based current-to-voltage conversion? It is easy enough to confirm if there is backwards leakage of the generated signal into VREF (which could mean that the slowness of the TL072 op-amp driving it is the culprit). But nope, VREF is just beautifully constant while DAC_OUT exhibits these leisurely approximations of a square wave edge. (The reason: both complementary current outputs are tied to VREF through identical resistors R13 and R14, so the total current sourced by the op-amp does not change.)

Or maybe the C1 compensation capacitor is too large? Unlikely: the datasheet has an example of using this DAC as part of a SAR ADC with 2 µs cycle time (so max 250 ns of DAC settling time), where this cap is 0.1 µF, ten times greater than ours.


MSB transient (click to enlarge)

I am a bit inconclusive here, but it does seem to be the DAC, exacerbated (at lower amplitudes) by the R-2R ladder coupled with the stray capacitance of the DG408.

Incidentally, zooming in on the MSB switchover transient of the DAC (see exhibited capture on the right), the timing of spike recovery is consistent with what seems like the inherent (rather poor) analog bandwidth of the DAC.

At any rate, we are good to generate sine waves up to 1 MHz (with slightly decreasing amplitude which we can and do compensate for in software). Obviously, other waveforms with harmonic content will gradually suffer as the frequency is increased above ~300 kHz. Not great, but not a show-stopper.

Distortion & spectral (im)purity

How clean is our output? Let’s generate some sine waves and take a look at the spectrum up to 5 MHz. Amplitude was held constant at 4.00 Vpp while the frequency was stepped by 50 kHz. On the scope FFT, the Blackman window was chosen for its low spectral leakage.


Frequency sweep in 50 kHz steps (click to enlarge)

Apparently, there is quite a lot of spurious output. The highest peaks are around -40 dBc (that is, 1/100 of the carrier amplitude) with most under -60 dBc. I don’t think it would be reasonable to expect more from an 8 bit DAC with its theoretical maximum dynamic range (quantization noise floor) of ~48 dB. In terms of THD, this is firmly in the very low single percent range (1-2%). That is on par with, or better than relaxation oscillators (but those are much less stable and cannot be numerically controlled to 6 significant digits of precision). Still, not as good as bespoke sine oscillators (also not amenable to so precise control). Basically, if stability and controllability is of value (as in this instrument), this could only be reasonably upgraded to a bigger and better DDS: same principles but improved parameters.

If you looked at the sweep close enough, you might have noticed another interesting phenomenon: certain frequencies look “better” than others, in that they have relatively very few spurious emissions – and those are all clean harmonics! This is most visible at 400 kHz, 500 kHz, 800 kHz and 1 MHz. These frequencies all have an integer number of DAC samples in their periods (the DAC is clocked at 8 MHz). As a result, the DDS accumulated phase does not drift around between output cycles; each cycle is forever sampled at exactly the same phase angles. This is an example of coherent sampling. On the other hand, frequencies that have a more complicated relationship to the sample clock will have samples that “move around” in circles according to the numerical relationship (some kind of rational number) between the frequencies. The result is spectral leakage of varying distribution and intensity.

AM modulation

Even though our instrument barely scratches the realm of RF, we can still apply amplitude modulation to the generated waveform via plugging in an analog cable (3.5mm phone plug) and supplying a signal from e.g., the computer soundcard output.

That is exactly what we did here, and used a tone generator program to modulate the carrier frequency of 1 MHz. The baseband signal was stepped by 1 kHz to cover the 1 to 20 kHz range. The first frame shows the carrier without modulation.


Spectrum of AM modulated carrier (click to enlarge)

No surprises here. Our multiplier DAC does multiply; the spectrum exhibits the sidebands as it should. Nice and clean!

ASK modulation with DCF77 time code

As a final demo of the instrument’s capabilities, below is a rolling capture of the 77.5 kHz sinewave carrier ASK-modulated with the DCF77 time code. This consists of one bit per second, where each bit is encoded as reduced carrier amplitude starting on the second, lasting 100 ms for a 0-mark and 200 ms for a 1-mark.


Rolling capture of DCF77 time code (click to enlarge)

Generating something like this is very difficult with conventional electronics, but becomes borderline trivial with a programmable platform such as this instrument.

It is useful to have such capability in a household with multiple radio-controlled clocks; I already had to use this to set them on multiple occasions.

Miscellaneous: disconnected DAC input pins!

As a final prank: how about disconnecting some of the 8 pins feeding the DAC? (I did this on the breadboard while it was still easy to do.) First let’s disconnect the least significant bit(s):


Disconnected LSBs (click to enlarge)

It is clear that all 8 bits are being put to good use! Even losing the single least significant bit results in a slightly rugged waveform; losing two bits, we get a clearly visible staircase.

Just for fun, let’s now disconnect some of the most significant bits, one by one:


Disconnected MSBs (click to enlarge)

And that is exactly what we expected to see!

Conclusion

As always, I had lots of fun designing, building and playing with this project. Sufficiently wide and deep in scope that circuit design, construction issues and software development all played a critical role, calling for the kind of R&D and generalist problem-solving activity I personally enjoy the most.

I also hope this might serve as a source of inspiration to those who wish to construct a similar signal generator for themselves. If so, I would love to hear about it!

I think this build more or less maxes out on what can be achieved with a single 8 bit DAC chip. For my next DDS generator, I will move on to something bigger and better, using one (or more) of those “magic DDS chips” that can generate signals at multiple tens or hundreds of MHz. Until then, this simple and low cost “baby DDS” is capable of some neat tricks and is certainly more than adequate for experimenting in the sub-megahertz range.

I also have the necessary hardware to force discipline on any of my radio-controlled clocks, should they fail to acquire the real DCF77 signal for too long.

KiCAD design files, PCB manufacturing data, source code of the Pico program & component datasheets are all available as part of the project’s git repository.