Introduction
This post is about building a frequency synthesiser for various uses such as for a home lab or as a module for a larger project. The implementation can be useful from a few tens of kHz up to 160MHz; not anywhere near the capabilities of a commercial signal generator, but still very usable. It primarily generates sine waves and square waves but can also handle some forms of modulation and controlled sweeps. This should cover many use-cases, particularly radio related. So far, single tone, adjustable amplitude and frequency modulation (FM) has been implemented in the code.
Even if you already have a signal generator, one is never enough. There are many scenarios where more than a single device is needed so an additional one can be a useful thing to have.
A video of it in action (using a radio to test it) is further below. The photo here shows what it looks like, connected up to a BeagleBone Black (BBB) in this case. The white connector at the bottom is used to connect to the BBB for power and control purposes (just a few pins are used from the connector, not all have to be wired up). The coax connector on the right is the output.
The whole thing is controlled from a web browser.
It is quite small and can fit inside a screened can:
How does it work?
When it comes to a stable, adjustable frequency source a phase locked loop (PLL) is extremely common. The circuit in this post however uses a different method known as Direct Digital Synthesis (DDS) to create the signals. It is described in more detail further below but for now the diagram here shows an overview of the entire system. Node.js is used to create a web server and to handle requests from the user. These are then used to call a program written in C called (imaginatively) ‘dds’. Parameters include the desired frequency and the mode of operation. The C program toggles pins using a simple library described here. The DDS board consists of a DDS chip from Analog Devices (AD9954) that is used to construct up the desired frequency. It is quite closely based on AD’s reference design. The output is filtered and available at an output connector. How Direct Digital Synthesis works is described next (the section can be skipped if you are only interested in the results).
Direct Digital Synthesis (DDS)
The DDS method in summary constructs a sine wave digitally by sending a table of numbers to a digital to analog converter (DAC). The block diagram from the AD9954 datasheet shows how it works. The areas relevant to the following discussion are highlighted in green.
The DDS chip is fed by a high frequency clock (in this case a 100MHz oscillator is multiplied up to 400MHz by the DDS chip).
DDS devices allow a desired frequency to be programmed using an internal register (e.g. programmed via an SPI or other I/O bus). The programmed value is fed into a summing device or counter, known as a phase accumulator. This is just responsible for repeatedly adding the programmed value to the existing sum, on each clock cycle. So, if the desired frequency is a low value then the phase accumulator will increment in low values too (e.g. the accumulator may count 0,1,2,3,4… if the programmed register value was 1). If the desired frequency is higher, then the phase accumulator will increment in larger chunks (e.g. the count may be 0, 5, 10, 15… if the programmed register value is 5).
The phase accumulator loops back to zero once it reaches its maximum. As can be imagined, each possible value that the output of the accumulator can take represents a different point on a sinewave. The block marked COS(X) in the diagram above can be a look-up table to convert from the phase accumulator output to an amplitude on the curve of a sine wave. This then drives a DAC.
With a low programmed value in the ‘desired frequency’ register, each clock cycle gradually steps through the entire sine wave and eventually repeats. With a high programmed value, each clock cycle still steps through the sine wave but by missing out chunks of it so that the wave is completed in fewer clock cycles; this means that the output frequency is higher. The output from the DAC must be externally filtered to remove image components beyond the Nyquist frequency (half the clock rate).
The Direct Digital Synthesis method results in extremely low noise close to the oscillation frequency This noise close to the oscillation frequency is known as phase noise. However, the frequency spectrum view may also reveal frequency components in seemingly random (but actually some is deterministic) locations, known as spurious output; these are due in part because the resolution of the DAC can be low and therefore the constructed sine wave has errors that in the frequency domain show up as spikes of signal at different frequencies than the desired one. These artifacts can be filtered and removed, but filters are expensive and usually non-adjustable so there is a practical limit to what can easily be done to remove the artifacts.
Sometimes a DDS can be used standalone, or it can be used as part of a PLL in a more advanced frequency synthesiser. The DDS can replace the crystal oscillator in a PLL as an example (other topologies are possible too). The combined approaches provide the best of both worlds; it provides the extremely low close-in noise that a DDS exhibits, and greatly reduced spurious content. Today, if there is a need to create a variable frequency oscillator to span a large range, it is likely to be impossible to beat a DDS based system for all-round performance and value. A more high-end design would combine it with a PLL (but a DDS alone can have incredible performance).
Just to continue with the benefits; a typical feature of Direct Digital Synthesis is the capability to control frequency to a very high granularity; with the AD9954, the 32-bit resolution allows granularity to under a Hertz - perfect for fine-tuning radio receivers.
More notes on Direct Digital Synthesis can be found here.
There are a few additional features of the AD9954 i.c. that are of great interest beyond the basic DDS functionality described. Additional registers allow for functions such as automatic frequency ramping (using a ‘frequency accumulator’) and for adjustment of the output amplitude (by multiplying the output from the look-up table by a factor). One of the best features is that there is a large amount of RAM available that can store 1024 different frequencies. It is possible to instruct the AD9954 to step through the RAM in certain programs of operation. This opens up possibilities to rapidly change frequency (far quicker than any analog oscillator) and to implement some interesting frequency-hop types of use-cases. Yet another use for this feature is to implement modulation; this will be the way frequency modulation (FM) is implemented in this project (it is described later). There are also pins on the i.c. to allow automatic switching of frequencies (or programs) based on the digital state of the pins. It allows for the device to be used for frequency shift keying (FSK); it was not tried in this project. Finally, the serial interface to the AD9954 can run to very high speeds; it allow for features like linear sweeps to be implemented under control of the BBB. This was not tried but would be feasible too.
Signal output and amplification/attenuation
The signal output is available via a connector; there are different types of RF coaxial connectors, it doesn’t really matter which one you use for this project. Some popular ones are BNC, TNC, SMA, SMB and MCX. Since RF connectors are not usually cheap, it is nice to standardise on one or two for multiple projects, and purchase adapters to convert to any other type.
As mentioned earlier the AD9954 has the capability to reduce the amplitude of the signal, to a degree. It would be good to have selectable external amplification or attenuation too, however it complicates the circuit. It was decided to construct a separate amplifier that could be connected to the board whenever a higher output is needed, and to plug in a separate attenuator whenever a lower signal output is required.
The maximum amplitude of the existing circuit is just under 0.2Vp-p if the destination load has a 50ohm resistance. Often a decibel (dB) value is used to express power levels rather than referring to a peak-to-peak voltage across a certain impedance. Since decibels express a ratio from some reference point, often the reference point is 1mW, and then the special unit dBm is used. 0dBm means 1mW. It is logarithmic, and sequential increments or decrements of 3 correspond to a doubling or halving of power. So, 3dBm means 2mW. A value of -3dBm means 0.5mW. There are plenty of websites with calculators for conversions. Here are the formulas for reference since not all the websites contain these.
Converting from Vrms to dBm:
Converting from Vpp to Vrms:
Converting from dBm to Vrms:
Circuit Details
Power Supply
The input to the board can be 5V; it can be directly powered from the BBB header, so no additional external supply is needed (it will consume several hundred mA during operation however). The circuit here shows the power supply circuitry.
Clock and DDS circuit
The diagram here shows the main schematic. A few unusual value resistances are required, in places. Most parts were 0603 sized, but the 100pF capacitors were 0402 sized. The DDS circuit is controlled by the digital lines shown at the top of the schematic (SDIO, SCLK, *CS and SDO). Optionally, the OSK, PS0 and PS1 pins are needed if high speed switching of frequencies is needed (e.g. to use as a FSK modem).
The output of the DDS (current, not voltage) is at the IOUT and *IOUT pins at the bottom of the schematic. There is also a built-in comparator (pins shown at the right of the schematic) which is used to convert the sine wave output into a square wave if desired.
An On Semi oscillator was used. There is a alternative part Farnell code indicated in the circuit above but the price looks incorrect for it - another replacement would be Farnell code 2095912). The AD9954 does get warm during operation, but not too hot to worry (if anything the oscillator runs warmer than the AD9954). The board had space to install a PowerPeg (part code TCAP-4325) from TEM Products:
It was hand-soldered in place (there is a procedure), but for this board it was found that the AD9954 does not get hot enough to require it. However it was good to get practice with the PowerPeg because some projects will need the thermal interface capability that it provides. The pegs really are an excellent design. Here is the underside:
Sine Wave Output
The DAC output is converted from a balanced signal to an unbalanced one using a transformer. The signal is then filtered by a low-pass filter. The inductors need to be RF types, and Coilcraft 1008HQ parts were used in this instance. This part of the board was spread out and kept far away from the clock circuit.
Note that if you’re placing this in a screened can, you will want to use a bulkhead connector for J2, rather than the one in the photographs earlier.
Square Wave Output
This part of the circuit is optional and was not constructed. If square wave output is desired over sine wave output, then resistors R20 and R21 in the circuit above are not fitted, and the circuit here is constructed:
Connections to the BBB
The diagram here shows the connections from the circuit that go to a connector J1. This connector is used to interface to the BBB.
The pins that were connected are shown here:
// DDS board WireColor BBB // ------------ ----------- ----------------- // 5 - VIN RED P9_5 VDD_5V // 6 - IO_UPD PURPLE P8_39 // 7 - GND BLACK P9_1 DGND // 8 - SCLK ORANGE P8_40 // 10 - SDIO YELLOW P8_41 // 14 - *CS BLUE P8_42 // 16 - RESET WHITE P8_43
Software
The software is in two halves - C code, and JavaScript code. It is described below, after some preparatory steps.
Preparation
The software is attached to the end of this post. It is straigntforward to use; the file can be unzipped and placed in a folder off the home folder (/home/root in my case). I created a folder called development/dds using this syntax (from the /home/root folder):
mkdir –p development/dds
So, the full path is /home/root/development/dds
In that folder, unzip and place the software. It can be compiled using:
make all
You will also need a socket.io library. It will take a few minutes to install. To do this, in the same folder type:
npm install socket.io
C code
This is in a file called dds.c and it implements a command line capability to control the DDS board. The actual I/O capability is enabled using a software library called iolib described here (it is part of the attached zip file, in files BBBiolib.c and BBBiolib.h).
The compiled dds program accepts a few parameters. To generate a 50kHz sine wave:
./dds --mode single-freq --freq 50000
The amplitude can be specified in several ways. One way is to reference it from the maximum power that the board can deliver, call it 0dB; this command will output at half power:
./dds --mode single-freq --freq 50000 --rel-level -3.0
Another way is to do it referenced to the usual 1mW (i.e. 0dBm). It assumes that the max power that the board can deliver is -8dBm, so as an example the command line for specifying half the output is:
./dds --mode single-freq --freq 50000 --dbm-level -11.0
To turn on FM (this example generates a 10MHz carrier and modulates with 1.2kHz):
./dds --mode fmtone --freq 10000000 --tone 1200
The FM tone capability is implemented by instructing the DDS to play a range of frequencies at the right speed to create the desired tone. It can be tested by listening on a radio tuned to the same frequency. The level of modulation is currently a bit low for a normal FM radio, so it will sound quieter (but still very audible) than a normal radio station. It would be possible to modify the code to have adjustable modulation capability (something to implement in a later version of the code).
To create FM tones, a look-up table of a sine wave was created so that on-the-fly the carrier frequency could be added to the table values and then stored in the AD9954 RAM.
Look-up Table for FM Modulation
(Note – the information here is just to document it and is not needed unless you wish to implement some refinements to the frequency modulation, or to implement a new feature.)
To create a table, GNU Octave was used. In this example, the sinewave was split into 100 values (the last value was not used). The modulation can be adjusted by changing the 2500 value below. This is the GNU Octave code that was used:
x=linspace(0, 2*pi, 101); s=sin(x); s=s*2500; csvwrite("c:/c_root/mytable.csv", s);
The generated CSV file is converted into a C array by using the program csv2freq.c which is attached.
./csv2freq mytable.csv out.txt
The first 100 values in the generated out.txt file were just pasted into the dds.c file.
JavaScript Code
The other half of the software runs on the Node.js platform. The software is contained in a file called index.js and can be run by typing:
node index.js
When run, it will sit and wait for any web browser to connect. When it does, it will serve up the index.html file and allow control of the DDS. User interaction via the browser will result in the index.js file automatically executing the dds command line program.
With any browser, type the following:
http://xx.xx.xx.xx:8081/index.html
and you will see this appear:
Synthesiser in Action
To test out the synthesiser, no special hardware is needed; a radio can be used. The short video here has some audio from a radio, about 15 seconds in. It shows some navigation of the user interface on the right side. The top left shows an oscilloscope trace, and the bottom left shows the debug output of the software (expand the video to full screen to see this). The video shows first just a 60MHz signal generated, and then an FM tone followed by some playing with the signal level.
Some Measurements
The nice thing about using a DDS based circuit is that there are no adjustments to be made anywhere; therefore a repeatable result should occur for others who wish to construct such a circuit even if test equipment is unavailable to confirm the values. The measurements here were to verify the board layout and can be a guideline (and hopefully others can obtain additional or more accurate measurements).
The output was measured to be -8dBm (about 90mV RMS) into a 50 ohm load across most of the frequency range, with a drop of 2-3dB toward 160MHz due to the low pass filter, dropping dramatically after that. If you want to experiment with radio projects, this output level is perfect for the active mixer portion of radio circuits.
The output level was measured using an oscilloscope. Here is an example of a 145MHz signal created by the board:
The screenshot here shows the output of the circuit, programmed to generate a fixed 60MHz signal, observed on a spectrum analyser. The x-axis is 5kHz per division, and the resolution bandwidth is 1kHz. The y-axis is 10dB per division.
Nowadays spectrum analysers have built-in tools to calculate phase noise, however that capability does not exist in a such an early spectrum analyser. A procedure to calculate it is detailed in an app note but I’m hitting the noise floor; all that is observable is the response of the filter inside the spectrum analyser. The expected result is -110dBc at 10kHz for a 159.5MHz signal according to the AD9954 datasheet. As expected, the DDS provides extremely good results here.
The oscilloscope has a very good FFT capability, and so it was decided to observe the FM spectrum on it. Here is a 25kHz carrier with 1kHz modulation frequency. The vertical axis is 20dB/div, and the x-axis is 5kHz/div:
This corresponds very well to a simulation using the same frequencies:
Here is another FM signal, this time observed on the spectrum analyser. This is a 60MHz carrier with a 5kHz modulation frequency. The vertical axis is 10dB/div and the x-axis is 5kHz/div and the resolution bandwidth is 1kHz:
Sometimes it is good to really verify all is well! And ensure that the tone was modulated correctly with the right frequency and no anomalies. So, here is the recovered audio (i.e. I plugged into the audio output) from a radio for a 300Hz modulation frequency:
Here is the same thing but for 1kHz:
It was possible to see the radio receiver’s bandwidth by experimenting with a few more frequencies; this was 5kHz modulation frequency:
Summary
The DDS board described here works well from perhaps 20kHz to 160MHz and it provides a home lab capability to conduct a lot more future experiments. The AD9954 i.c. provides excellent results and has a lot of in-built capabilities that are worth investigating in future.
An amplifier would be a good improvement to implement, although for fun I’d like to build an experimental radio receiver with the board first.
On the software side, it would be very good to implement a linear sweep capability for being able to check the frequency response of circuits (e.g. filters) easily. Another thing worth doing would be to adjust the HTML file to suit a BBB touch-screen display cape (Both the 4.3 and 7 inch variants of the BB-View displays contain touch capability) for a fully stand-alone system.
All parts were purchased from Farnell (parts list is attached), with the exception of the transformer which can be bought from Minicircuits directly (it could be replaced with a hand-wound variant but I still need to test that) and the TCAP-4325 PowerPeg which was obtained from TEM Products.
All scope traces and FFT traces were taken with an MSO2024B oscilloscope. The remaining analog spectrum displays were taken with a very old 8558B spectrum analyser.
The version 1 source code is available here. Edit - now stored on github to make it easier for adding new features to the code in later releases.
Top Comments