Project

How to Build Your Own Function Generator Using Analog Devices’ AD9833

January 17, 2018 by Cezar Chirila

Tired of using your PC or mobile phone as a signal generator? It’s time to upgrade to a standalone one by making it yourself.

Learn how to make your own arbitrary waveform generator using an ATmega328p, a DDS function generator IC, an op-amp, a few passives, and some hard work.

Related Articles:

Having your own electronics laboratory at home is great—the only downside is that even basic equipment can be costly. Building your own devices is not only easier on your wallet, but it is also a great way to improve your knowledge. Therefore, in this article, I am going to explain how to build your own function generator.

 

Waveform Generator

What is a function generator?

First, a function generator (also called a tone generator) is an electronic device that can output a specific waveform at a set frequency. For example, one could generate a sinusoidal signal at 60Hz. You can use it to test the inner workings of audio amplifiers, find the characteristic of op-amps and diodes, make funky noises—the list of applications goes on. 

A DDS function generator is a digital arbitrary waveform generator, meaning it uses a digital-to-analog converter (DAC) to build a signal. It also has read only memory (ROM) where it stores amplitude values for specific waveforms at various time intervals based on a sampling frequency (Fs).

Let's say we have a DDS signal generator with an 8-bit DAC and it outputs a sinusoidal signal at 100Hz with a sampling frequency of 800Hz. Because the Fs is eight times the frequency of the sine wave, an engineer or, more likely, a computer needs to extract from a real sine wave eight amplitude values from t = 0 to t = 2π. This amplitude interval is [0, 255] (1111 1111 in binary = 255), which corresponds to the interval [-1, 1] with a real sine wave. As a picture is worth a thousand words, below is a comparison between the real sine wave and the one outputted by our imaginary (and low-performance) DDS function generator.

 

Building Your Own

The aim is to build a reliable function generator that can go up to 1MHz in frequency, up to 9V in amplitude, and that allows you to choose between sinusoidal, triangle, and clock (i.e., rectangular with 50% duty cycle) signals. To help you understand why I chose the components used, how they work together, and how the firmware was written, I am going to split this article into two big chunks, the hardware and the software. 

Hardware

There are two main parts regarding the hardware aspect of this build: the power supply and the main PCB containing the function generator IC and the microcontroller.

The Power Supply

The main PCB will need two voltage rails: +12V and -12V. The symmetrical supplies are needed for the final amplification of the signal. A smaller +5V rail will be created directly on the main PCB by regulating the +12V one; it is needed to power the microcontroller, the AD9833, the function generator IC, and finally the 24MHz crystal oscillator. Below you can find the schematic of the power supply board:

 

Power Supply Schematic

 

To obtain these voltages, a transformer will be used, from 230V or 110V (depending on your region) to two 12V AC lines (on the transformer it will usually be written something along the lines of 12V-0V-12V). An output current of 200mA is more than sufficient.

Remember that the output of a transformer is AC and we need DC. For this, we will be using a simple rectifier bridge. This will change the sinusoid into a positive signal. These usually come as standalone components but you can alternatively use four general purpose diodes such as 1N4001.

We will not be using it in the standard configuration as we want a symmetrical output, so we will connect them as in the schematic above: the ends of the transformer are connected to the rectifier, and the center tap is connected to ground. To smooth out the output we will first use two large capacitors, each 1000µF rated at 35V. Below you can find the output waveforms for the power supply rails at various stages:

 

 

In addition, to remove the ripple, two voltage regulators are used, the classic LM7812 and its sibling the LM7912, which is used for negative voltages. To top it off we add a 100µF capacitor and a 100nF one, both rated at 25V, to each regulator IC output. We want this supply to be as smooth as possible, as we will be using them to offset our final output voltage, and any AC components will propagate to the output. 

AD9833 Board

Let’s get to the main PCB.  The LM1117-5V linear regulator is used to create a +5V rail from the +12V supply. To keep everything smooth, we add capacitors to both voltage input lines (+12V and -12V) and the output of the voltage regulator.

 

 

On the left side of the schematic, you will find an ATMega328p-AU microcontroller, the same used on the Arduino Uno but in an SMD package. To program the MCU, a 6-pin connector called AVR-ISP is placed next to it. It has two pins for power (+5V and GND) and four other pins for communication: MISO, MOSI, CLK, and RESET.

We will be using only one user input component, a rotary encoder with an integrated switch. This will be our control element to set the frequency, signal type, and other settings. The signals from the rotary encoder are routed to two interrupt pins on the microcontroller, PD2 and PD3 (D2 and D3 on the Uno), and the switch goes to an available pin that can act as an input; I chose PD1 (D1 on the Uno). We won’t be adding any pull-up resistors as we will be using the ones integrated into the microcontroller. Because mechanical contacts are not perfect, when we rotate the encoder, instead of an ideal pulse, a jittery signal will appear, but this can be easily fixed either by software or hardware using a capacitor. For the integrated switch, we will use the software method, and for the rotating contacts, two 100nF capacitors will be used. 

A plain green LED is hooked up to pin PD7 (D7 on the Uno), for debugging purposes or to display status. The display used is a simple LCD with an HD44780 controller, which has 16 lines and two columns and includes a backlight. To reduce the number of connecting wires, an adapter board was used so that the only pins needed to control the LCD are 2 for data over I2C and another 2 for power (+5V and GND). The I2C lines on the microcontroller are on pins PC4 for SDA and PC5 for SCL. On the Arduino Uno, these are named A4 and A5, respectively.

Finally, the last connection for the microcontroller is made between it and the AD9833 integrated circuit. It uses a unidirectional SPI bus, meaning that data can only flow in one direction, from the MCU to the IC. The signals are MOSI (Master Out - Slave In), CLK (Clock), and CS (Chip Select, called FSYNC on the AD9833). To conclude the microcontroller portion, I should mention that decoupling capacitors with a value of 100nF are needed for each power supply pin. 

 

 

Before continuing to the last part of the schematic, the part with the function generator IC, let me point out a few key features of the AD9833. Although I am going to sound like a salesperson, let’s start. It is a DDS type programmable waveform generator, so it takes a clock signal with a maximum frequency of 25MHz (for this particular IC), which it then divides based on a value passed by the microcontroller (maximum 228) via the SPI bus, and using a 10-bit DAC it outputs a waveform chosen by the microcontroller. The output has a peak-to-peak value of 0.65V-0.038V (VOUT maximum – VOUT minimum), and it has an offset of (0.65V-0.038V)/2. This means that VOUT minimum is very close to 0V. One important note is that the clock output (rectangular signal) has an amplitude of 2.5V, which is the voltage generated by the device's internal voltage regulator.

Now that we have got that out of the way, let’s look at the last part of the schematic. A crystal oscillator is used to feed a 24MHz clock signal to the master clock input of the AD9833. FSYNC, SCLK, and SDATA are connected to the SPI bus of the microcontroller. Two decoupling capacitors are used near the VDD pin, one with a value of 0.1µF and another one with a value of 10µF. Another decoupling capacitor is needed for the 2.5V internal voltage regulator; this is near the pin CAP and has a value of 0.1µF. One more capacitor is needed between the COMP and VDD pins for decoupling the DAC bias voltage; it has a value of 10nF, as indicated by the datasheet.

 

AD9833 schematic

 

A few paragraphs above when I was talking about the microcontroller connections, I also wrote the Arduino Uno pin equivalents. I did this because the AD9833 circuit described in the previous paragraph is available at various Chinese manufacturers as a breakout board that you can connect to an Arduino Uno. Keep in mind that the output is straight from the IC, without the additional circuitry that I will continue to explain below.

The output of the IC is fed into the non-inverting input of the op-amp using a 1.3kΩ resistor. The trimmer POT1 (a variable resistor), which has its side pins connected to -12V and +12V, has the sweeper connected to a switch's input terminal to provide an offset voltage. The other input terminal of the SPDT switch is wired directly to ground, and the output terminal is connected to the non-inverting input of the op-amp with another 1.3kΩ resistor. This configuration combined with a 50kΩ potentiometer allows us to have a variable gain between 1 and approximately 20. This was computed using Millman’s theorem and the fact that the op-amp keeps its inputs, V+ and V-,  at the same voltage:

 

$$V^{^{+}} = \frac{\frac{V_{in}}{R3} + \frac{V_{offset}}{R4}}{\frac{1}{R3} + \frac{1}{R4}}$$

$$V^{^{-}} = \frac{\frac{V_{out}}{POT2}}{\frac{1}{POT2} + \frac{1}{R2}}$$

$$V^{^{+}} = V^{^{-}}$$

$$V_{out} \approx 20$$

 

Keep in mind that the gain is also applied to the offset voltage. I did this to have three configurations: 

  1. The offset voltage is set to -350mV using the trimmer POT1. When the switch is in position 3 (R4 connected to ground), the output voltage is the output of the IC, a signal with an amplitude of 350mV and an offset of 350mV, multiplied by the gain set by the potentiometer POT2. When the switch is in position 1 (R4 connected to the offset voltage obtained by the trimmer POT1), the output is just as before minus the offset voltage, essentially a signal with a 350mV amplitude and no offset, multiplied by the gain.  
    With this configuration, the output voltage can either swing from -7V to +7V or from 0V to what the op-amp is capable of (something near +12V). 
     
  2. The offset voltage is set to VOUT minimum of the AD9833. This is then multiplied by the gain, which can vary from 1 to 20.
     
  3. Instead of the trimmer POT1, you can use a potentiometer and mount it on the front panel so you can have a variable offset. Just remember that the offset is also affected by gain, so it is wise to first set the gain, to choose the peak-to-peak voltage that you need, and after that use the offset potentiometer to adjust the signal's vertical position. I do not recommend this setup; if you want variable offset, I suggest that you add a separate op-amp as a summing amplifier with a fixed gain of 2, as in the schematic below.
     

$$V_{out} = 40\cdot V_{in} + V_{offset}$$

 


Alternative AD9833 offset

 

In order to wrap up the amplifying part of the circuit, I have to mention that you will need 100nF decoupling capacitors for both the positive and the negative power supply and that you need to choose an op-amp that can withstand the power supply voltages (+12V and -12V) and that has a very good slew rate, so that it can keep up with high-amplification signals.

Ideally, this circuit should be built on a PCB designed specifically for this application and not on a prototype board. I will provide you with an already designed PCB in KiCad via the files below. However, if you want to make your own, keep these things in mind:

  • Place the decoupling capacitor for all of the integrated circuits as close as possible to the power supply pins.
  • Try to use a ground plane (if using only two layers, make the bottom layer to consist mostly of ground).
  • Separate the analog part of the circuit (the output of the AD9833, the amplifying circuit, and the output BNC connector) from the digital part (microcontroller and communication side of the AD9833). You can split the ground plane right below the AD9833. This can be done easily as the IC has two separate pins for analog and digital ground.
  • As the datasheet of the AD9833 suggests, avoid running digital traces under the AD9833.



     

All the necessary components to build this can be found in the BOM included in the zip file at the bottom of the article. 

Now that we are done with building the circuits let’s dive into programming. 

Software

To write the code that will be uploaded into the microcontroller’s memory, we will be using the Arduino IDE. In the following few paragraphs I will explain how to write a library for the AD9833 and then the main piece of software that allows us to interface the microcontroller with the AD9833, the LCD, and the rotary encoder. The AD9833 has these so-called registers, which are basically memory locations, into which we can put data, and based on these values the integrated circuit changes its mode of operation; it chooses what waveform to output, the phase, and the division factor. We will be working with five registers: the control register; two phase registers, PHASE0 and PHASE1; and two frequency registers, FREQ0 and FREQ1. 

AD9833 Library

We will create two files, AD9833.cpp, the file that will contain the source code, and AD9833.h, its header.

Inside the header, we specify the name of the class (AD9833) and, just like a Russian nesting doll, inside it, variables and functions that we will be calling to communicate with the waveform generator IC and to change its parameters, such as the frequency and the type of waveform. These can be one of two types: public, which we can call from outside the class methods (functions), or private, which we can call only when we are inside a class’s method. I have added comments so that you have an idea about the purpose of every function and variable; for example:

//Initialise the AD9833
//_FYNC is the pin on the uC where FYNC is connected
//_mclk is the frequency of the crystal generator 
AD9833(int _FSYNC, unsigned long _mclk);

Going on to the source file, when we initialize a new object of type AD9833 a few things are going to happen; this is inside the function “AD9833::AD9833(int _FSYNC, unsigned long _mclk)”. First, we take note of the FSYNC pin we have passed as an argument, and we set it as an output pin. When writing to the AD9833, this pin will go LOW. Inside this method, we also set some default values for the registers so that we output a sinusoidal signal at 1kHz using the FREQ0 register. The last lines set the SPI to mode2, which is the setting that the microcontroller and AD9833 use to communicate. 

All that is remaining now is to carefully read the datasheet and see what values we have to set in the AD9833’s registers to manipulate the output waveform and its operation. Thus, we will write functions for the following operations: write data, set frequency, set phase, sleep, reset, mode, and choose frequency/phase register.

We will be working directly at the bit level. Sometimes we may want to change the value of an entire register, for example for the frequency register, but sometimes we want to only change a few bits of the whole word. To achieve this, we will use the following operations:

  • “&=” To set some bits to 0 while leaving the rest undisturbed. (0 = set to 0, 1 = leave it how it is). Example:
controlRegister &= 0xF3FF; // Set D11 and D10 in control register to 0
  • “|=” To set some bits to 1 while leaving the rest undisturbed. (1 = set to 1, 0 = leave it how it is). Example:
controlRegister |= 0x0C00; // Set D11 and D10 in control register to 1

In the table below I have extracted from the datasheet which bits need to be set to execute the operations. 

 

Operation Register Value
Set Frequency FREQ0 FREEQ0: D15 = 0, D14 = 1
Set Frequency FREQ1 FREEQ1: D15 = 1, D14 = 0
Set Phase PHASE0 PHASE0: D15 = 1, D14 = 1, D13 = 0
Set Phase PHASE1 PHASE0: D15 = 1, D14 = 1, D13 = 1
Set Mode - Sine CNTRL D5 = 0, D1 = 0
Set Mode - Triangular CNTRL D5 = 0, D1 = 1
Set Mode - Clock CNTRL D5 = 1, D1 = 0
Set Frequency Register CNTRL D11 = 0 (choose FREQ0); D11 = 1 (choose FREQ1);
Reset CNTRL D8 = 0 or 1
Sleep - No power-down CNTRL D7 = 0, D6 = 0
Sleep - DAC powered down CNTRL D7 = 0, D6 = 1
Sleep - Internal clock disabled CNTRL D7 = 1, D6 = 0
Sleep - DAC powered down and internal clock disabled CNTRL D7 = 1, D6 = 1

 

The registers have different sizes. The control register is 16 bits long, the phase registers are 12 bits long, and the frequency registers have 28 bits. To output data via SPI, we send one byte at a time, as can be seen in the “writeData” function, starting with the low byte (first 8 bits from the data integer) and then the high byte.

Setting the frequency is a bit more tricky because we are not directly sending the frequency that we want. According to the datasheet, the analog output is fMCLK/228 × FREQREG. Thus, the frequency register must be set to:

$$FREQREG = \frac{frequency \cdot 2^{28}}{f_{mclk}}$$

 

Because the obtained number can be as long as 28 bits, we divide it into two words, each 16 bits long, and then we send the data starting with the lower one.

The rest of the methods should be straightforward if you follow the table above and my indications in the comments. 

Main Routine

For the main code that will connect our AD9833, LCD, rotary encoder, and microcontroller together we are going to cheat a bit and use some very well written libraries for the LCD, which uses the I2C bus, and for the rotary encoder.

Our arbitrary waveform generator does not make good use of the phase functionality; I have decided to keep this feature unavailable, but you can use it by uncommenting the directive “//#define usePhase”. However, doing that will disable the ability to choose between the FREQ0 and FREQ1 registers.

I tried to make the software as user-friendly as possible. From the start, on the LCD you can see the frequency in the upper left corner and change it digit by digit, in the upper right corner is the power state of the analog output, which can be either ON or OFF, meaning you can turn off the output without turning off the device. In the bottom left corner, you can choose the register used for storing the frequency, either FREQ0 or FREQ1. This is useful in case you want to easily switch between two different frequencies. Lastly, in the bottom right corner is the type of waveform that you want to output, either sine wave, triangular wave, or rectangular wave. Keep in mind that the clock output will always have a higher amplitude, as the AD9833 outputs it at 2.5V as opposed to 0.65V for sinusoidal and triangular signals.

 

 

This is how you make changes: Pressing the encoder makes the cursor active, and then you rotate the encoder to "scroll" (move) between the four settings (frequency, ON/OFF, FREQ0/1, and waveform type). After selecting the setting to be changed, pressing the encoder will either change the setting (if ON/OFF or FREQ0/1 has been selected), or you can change the setting's value by rotating the encoder (rotating increments/decrements the current digit or changes the waveform type, depending on the chosen setting). Pressing again applies the setting (for waveform type) or goes to the next digit (for frequency).

I have tried to make the code as concise as possible, and comments are available to help you understand my thought process. If you have any questions, do not hesitate to leave a comment or contact me.

I sincerely hope that everything goes smoothly and you will be able to enjoy your very own Arbitrary Waveform Generator. 

Below are some output waveforms for you to enjoy:

sine wave, 1V peak-to-peak, 1kHz, no offset

 

triangular wave, 1V peak-to-peak, 1kHz, no offset

 

clock signal, 11V peak-to-peak, 500Hz, with offset

 

GoodiesSignalGen.zip

84 Comments
  • Dillon Nichols January 26, 2018

    What’s the approximate BOM cost for this circuit?

    Like. Reply
    • Cezar Chirila February 02, 2018
      Hi there! Unfortunately, I cannot give a good BOM cost as I already had most of the SMD passive parts and the power supply. At a glance, I would say about 50$, but keep in mind as this is a one time project, the cost is significantly cheaper if you parts for more.
      Like. Reply
  • jlachance February 02, 2018

    Hi Cezar,

    Thank you for this useful, well-documented and easy-to-read project!  I’m looking forward to building one myself!

    I probably overlooked it, but how can we obtain one of your PCBs? 

    Thanks again!!

    Jennifer

    Like. Reply
    • Cezar Chirila February 02, 2018
      Hi Jennifer. I only made a few PCBs for myself, I do not intend to sell them, although the PCB files are available to download in case you want to make them yourself at a fab like OSHpark. However, if you are OK with waiting, I still have a few left and can send you one, just send me the address via private messaging. (free of charge of course)
      Like. Reply
  • A
    aries1470 February 10, 2018

    Hi, you mentioned OSHPark,, I wanted to know if you have made the PCB a shared design, and if yes, what is the link to it.

    Thank you in advance.

    Like. Reply
    • Cezar Chirila February 11, 2018
      No shared design but you can download the KiCAD project files and then export in Gerber format, which you can then use on OSHPark. If you only need one, send me a private message and I'll post it to you.
      Like. Reply
    • Cezar Chirila February 11, 2018
      No shared design but you can download the KiCAD project files and then export in Gerber format, which you can then use on OSHPark. If you only need one, send me a private message and I'll post it to you.
      Like. Reply
  • M
    Muziker February 16, 2018

    Hey Cezar, beautiful project. I happen to be busy building a function generator. Can I get a PCB to? Greetings John

    Like. Reply
  • A
    aquaman8_2001 February 18, 2018

    Hi Cezar,

    Well written article and very interesting project. Do you have any PCB left? Would love one!

    Thanks,

    Mitch

    Like. Reply
  • A
    aquaman8_2001 February 18, 2018

    Hi Cezar,

    Well written article and very interesting project. Do you have any PCB left? Would love one!

    Thanks,

    Mitch

    Like. Reply
  • C
    cyber February 27, 2018

    Hi Cezar
    Fantastic project, just what I have been looking for.
    Is it still possible to get a PCB?
    Regards
    Graham

    Like. Reply
    • Cezar Chirila March 01, 2018
      Hi, thank you! Send me a private message with your address. Cezar
      Like. Reply
      • C
        cyber March 02, 2018
        Sorry, For some reason it says I do not have permission to send you a private message
        Like. Reply
        • Cezar Chirila March 04, 2018
          That seems strange. Just use the contact form on my website (www.cezarchirila.com).
          Like.
        • Cezar Chirila March 04, 2018
          That seems strange. Just use the contact form on my website (www.cezarchirila.com).
          Like.
  • D
    dyn_o March 06, 2018

    Hy,

    I think you made a mistake in the table. To set the frequency of register FREQ0 you write D15 = 1 and D14 = 0. To set the frequency of register FREQ1 you write D15 = 0 and D14 = 1. But it is the opposite. If you look at page 18 of the datasheet ( http://www.analog.com/media/en/technical-documentation/data-sheets/AD9833.pdf ) it shows a “frequency register bits” at the bottom left of the page where the bits D15 and D14 are inverted compared what you wrote, and it shows the same in the example top right. Am I wrong ?

    Like. Reply
    • Cezar Chirila March 06, 2018
      You are right! I must apologize profoundly and thank you for your observation, I will edit with the correct values. Thankfully, the code is correct, the mistake is only available in the table above. (AD9833.cpp file, comment line 162 and 168 says exactly how it should be)
      Like. Reply
    • RK37 March 06, 2018
      Thanks for catching this mistake, dyn_o. I corrected the table.
      Like. Reply
  • Elijah4me March 16, 2018

    Thanks Cezar, for this wonderful piece. I have be given an assignment to design a signal generator and also characterize it to display the three usual waveforms sine, triangular and square. I believe you will guide me.
    I have only one week to design it, will appreciate all you can do for me

    Like. Reply
  • messu April 05, 2018

    Hi Cezar
    and thanks for this very interesting project.
    I was searching for something like this for a while and I’ve even bought an ebay AD9833 module, but the results, following an already written project (I don’t know C or other uC programing language), were rather dissapointing in terms of wave shapes on any frequency higher that 10 Khz.
    My goal would be an 5 Mhz FX generator, which I know it is too much for AD9833, but could you be kind enough and tell me how does the wave shapes look like at 2-2.5 Mhz, which, in theory would be much more achivable ?
    Thank you !

    Like. Reply
    • Cezar Chirila April 05, 2018
      Hi Messu! I am currently out of town, please contact me this same time next week (comment here or private message) and I will provide you with oscillograms at 2-2.5 Mhz. The results do not depend on the code written, as it either works or not. It is however influenced by the PCB layout and additional circuitry. Cezar
      Like. Reply
      • messu April 05, 2018
        Yes, you're right and I'm fully aware of the importance of the PCB layout, specially when we're dealing with high frequency signals. The problem is, I've got pretty bad wave forms using JUST the AD9830 module, the way I've bought it, no PCB what so ever. This could mean the module it is VERY CHINESE, or maybe, hopfuly, I've just bought a bad module. That's why I'm asking for the oscillograms. Thanks, again and I'll get back to you next week ! Happy Easter ! Marian
        Like. Reply
  • P
    pansls April 06, 2018

    Hi Cezar,
    Excellent project, just what I want at the moment
    Is it still possible to get a PCB?
    Regards
    pansls

    Like. Reply
  • D
    DocFlash April 17, 2018

    Can anybody share what rotary encoder you used as SW1? I’m at a loss for what part to use. A part number would be much appreciated.

    Jeff

    Like. Reply
    • Cezar Chirila April 17, 2018
      Most quadrature encoders will work. Just remember that it has to have a pushbutton. One could be PEC12R-4215F-S0024 I think. Cezar
      Like. Reply
      • A
        aalbala August 20, 2018
        Hi Cezar, PEC12R-4230F-S0024 or PEC11R-4220K-S0024 would work? Great article, thanks for the sharing Thank you!
        Like. Reply
  • ozdigennaro June 07, 2018

    Great project.  I’m diving in.  Any PCB left?

    Like. Reply
  • C
    Conjada August 02, 2018

    Excellent article with no stone left unturned. It’s great the way that you show how you designed it from start to finish.

    Like. Reply
  • H
    hssandesh September 21, 2018

    hay i Made one like this but without microcontroller….you can find out on this video
    https://youtu.be/mhd3CGJHpXk

    Like. Reply
  • Alireza Jamshidi November 23, 2018

    Hi thank you for sharing, Good Luck:)

    Like. Reply
  • M
    mikepukmel December 02, 2018

    Hi Cezar, thank you very much for this great project.  You’ve had many questions bout PCB boards, I got the KiCad files downloaed, but not much good at KiCad yet.  Any chance you have the export files generated for OshPark that you could post?  Thanks!
    Mike

    Like. Reply
  • A
    Anas Hanif January 16, 2019

    hi Cezar,
    can i get some help regarding this project.will appreciate if you help me out.
    Thanks
    Anas Hanif

    Like. Reply
  • A
    Ahmedfathy1 February 06, 2019

    What a Great project.
    Do still have any more PCB?
    I need one.

    Like. Reply
  • uwezi February 16, 2019

    Both of your amplifier circuits have some severe shortcomings - partly based on the chosen operational amplifiers.

    a) the single opamp circuit where you subtract the offset directly is frequency limited by the 15 MHz gain-bandwidth of the LM318. Only up to frequencies of 350 kHz you can get the closed-loop gain of 40. Also even at lower frequencies the phase drift of the LM318 will deteriorate many non-sinewave signals because different harmonics will experience different phase shifts.

    b) the second circuit with two LM318 is actually much worse. Because here you amplify the dc offset in the first operational amplifier by the 40x gain. 0.325 V x 40 is already 13 V and thus by far exceeds the maximum positive output voltage of the first amplifier. There will be no signal left from which you could subtract the offset in the output stage.

    Like. Reply
  • B
    beamsbox February 24, 2019

    Has anyone made these PCBs? I’d like to get my hands on one. No idea how to use the software, etc.

    Like. Reply
  • Toekhant Hlaing March 03, 2019

    Can I get PCB design plz

    Like. Reply
  • D
    drakkn March 11, 2019

    Hi are the pcb files still available

    Like. Reply
  • D
    David1128 July 10, 2019

    Hi Cezar,
    Excellent project, just what I want at the moment
    Is it still possible to get a PCB?
    Regards

    DAVID

    Like. Reply
  • luis daniel rivera ortiz September 04, 2019

    Good simple tutorial. One thing though, this is NOT an arbitrary waveform generator. Arbitrary means you can program any wave-shape based on spectral or time domain data points and reproduce it. Still a very useful tool to have in any lab since most people wont have need for more than sine and square.

    Like. Reply
  • G
    GeorgeCT September 25, 2019

    Very nicely done project.  I’m wondering if you have tried a sweep-frequency type function?  Is it practical with this DDS chip and MCU (processor speed, settling times, etc.)?

    Like. Reply
  • S
    sisco December 13, 2019

    hi , i make this , but show in my frequncymeter different frewuncy , for example i set in 1.000.000 hz but my frequncy meter show 520.800 hz ?
    can help me ?

    Like. Reply
  • S
    sisco December 13, 2019

    other freq :
    set 10000 show frequncymeter 5207.995
    set 1000 show frequncymeter 520.7623
    set 2000 show frequncymeter 1041.571
    set 5000 show frequncymeter 2603.998
    set 5500 show frequncymeter 2864.379
    set out CLK mode

    Like. Reply
    • Cezar Chirila December 14, 2019
      Hi. Make sure the DIV2 (D3) from the control register is set to 1. See page 14/21 from the datasheet. That should solve your problem.
      Like. Reply
    • Cezar Chirila December 14, 2019
      Or make sure you are using a 16MHz crystal oscillator. If you are using an 8MHz, that could be the problem and you need to change the code to account for this. Some ebay boards come with an 8MHz oscillator I think. Did you make the board yourself?
      Like. Reply
    • S
      shaggyDog18 July 01, 2020
      Firmware issue: There is an error in the AD9833 library code. It provides 0.5 x frequency for square wave signal. Also, there is an error in the setting of the initiation line for the AD89833 module: crystal oscillator should be 25MHz instead of 24MHz. That eventually caused inaccurate setting for the output frequency. I would recommend using my Firmware: fixed all the errors as well as use other library for the AD9833 module. Available at: https://github.com/ShaggyDog18/SignalGeneratorSD
      Like. Reply
  • S
    sisco December 15, 2019

    hi , i use this module :
    https://www.newbecca.com/product/559765841595
    you think my problem for this , because in this module used 25MHZ crystal ?

    Like. Reply
  • S
    sisco December 15, 2019

    and .. yes Cezar , i make board myself with this AD9833 module and ATmega328p DIP model ( not SMD) .

    Like. Reply
  • S
    sisco December 15, 2019

    in this line arduino file : AD9833 sigGen(10, 24000000) can replace 24000000 with 25000000 ?

    Like. Reply
    • S
      shaggyDog18 July 01, 2020
      sure, that's the place to tune up the crystal frequency. After that the out signal frequency will become more precise...
      Like. Reply
  • marcoscab1166 February 21, 2020

    Hi, thanks in advance for the circuit. I have a few questions.
    If I understood correctly, the output can make at least 20v peak to peak right?
    Because im thinking to use it as power source of an ultrasonic piezoelectric of 1mhz and another of 3mhz, obviously not the two at same time.
    So my first problem is the current that the output of the op-amp can drive.
    How can I adapt this circuit so I can use it to drive that type of load?

    Like. Reply
  • alias ahula February 28, 2020

    if friends have problem with i2c modele ( like me ) must be change addres 0x27 to 0x3F . for example if use old I2C module with NXP chip must use 0x27 but if use new I2C module with philips chip must use 0x3F address .

    Like. Reply
  • alias ahula February 28, 2020

    Chip PCF8574A     0x3F
    Chip PCF8574       0x27

    Like. Reply
  • S
    sdascl March 31, 2020

    Is it still possible to get a PCB?

    Like. Reply
  • Lawrence Link April 11, 2020

    Hi Cezar,
    I’m currently trying to make this interesting project, and in my final schematic I used an LCD1602 without I2C, but it doesn’t work when I try to initialize the AD9833 library, and I can’t find anything wrong with the hardware. So if it’s ok please contact me by a private massage? 😊

    Like. Reply
    • S
      shaggyDog18 July 01, 2020
      you might use the same SPI interface for both AD9833 and display. Try to connect display to other pins and use software SPI for it...
      Like. Reply
  • brackstanos April 20, 2020

    Have you ever simulate the schematic on any simulator, yet?

    Like. Reply
  • C
    Ckohn May 08, 2020

    Terrific project, I have spent a lot of time with Arduino projects.
    Where or how can I get the circuit board?
    Thanks
    Carl

    Like. Reply
  • R
    robthomp62 May 17, 2020

    Hello Cezar.  This is looks like a very interesting project, and your write-up is excellent.  I think I’m going to make it.  I have a question - do you think it would be advisable to use a SMPS instead of a linear PS, or would that have too much ripple for the signal generator?

    Like. Reply
  • lightingnerd June 19, 2020

    If anyone else in the US needs a PCB or two, I’m making an order soon.

    I’ve also compiled a parts list on Mouser that should be compatible(some changes due to availability), although I would love it if someone were to double-check it for errors—especially the power supply components.

    Here’s the Shopping Cart exported from Mouser:

    https://drive.google.com/file/d/1JrfFX-mE_Vmvj7YQxStPawyJCWwoR6lY/view?usp=sharing

    Like. Reply
  • S
    shaggyDog18 July 01, 2020

    Sharing an improved firmware:
    Change log:
    - Simplified, optimized, fixed bugs, used better/“standard” libraries for all components: display, rotary encoder, button and, most important, for AD9833 module.
    - Added graphic icons for signal representation on the display.
    - Renamed FREQuency register on the display to CHANnel: so, now it looks like CHAN0 and CHAN1.
    - Tied a signal mode to CHANnel; so, now you may change signal form along with the frequency.
    - Slightly changed navigation.
    - Use EEPROM to store and recover settings.
    - Added a new signal mode: square/meander signal wave at 1/2 frequency (for even more accuracy of the output signal frequency). This is a standard feature of AD9833 module.

    - I’ve never used a PHASE option… so, did not test it…

    Works much better and provides more features. Enjoy its new feel and look:
    https://github.com/ShaggyDog18/SignalGeneratorSD

    Like. Reply
  • S
    shaggyDog18 July 01, 2020

    Hi Cezar!
    Thank you for sharing your project. I am improved your firmware and sharing it with the community:
    Change log:
    - Simplified, optimized, fixed bugs, used better/“standard” libraries for all components: display, rotary encoder, button and, most important, for AD9833 module.
    - Added graphic icons for signal representation on the display.
    - Renamed FREQuency register on the display to CHANnel: so, now it looks like CHAN0 and CHAN1.
    - Tied a signal mode to CHANnel; so, now you may change signal form along with the frequency.
    - Slightly changed navigation.
    - Use EEPROM to store and recover settings.
    - Added a new signal mode: square/meander signal wave at 1/2 frequency (for even more accuracy of the output signal frequency). This is a standard feature of AD9833 module.

    - I’ve never used a PHASE option… so, did not test it…

    Works much better and provides more features. Enjoy its new feel and look:
    https://github.com/ShaggyDog18/SignalGeneratorSD

    Like. Reply
  • Jmur30 July 15, 2020

    Excuse me, someone has already done the simulation of the circuit in the proteus program could you help me.

    Like. Reply
  • N
    Nagy57 July 16, 2020

    Hi Cezar, Hello!
    The pcb is done, but I have a problem writing the interrupt.
    would you help me thank you very much!
    Ferenc

    Like. Reply
    • S
      shaggyDog18 July 21, 2020
      Please, clarify what is the issue? Interrupts are used for encoder pins. You may pick up my firmware, it works well.
      Like. Reply
  • N
    Nagy57 July 22, 2020

    Hi Cezar,

    394/5000
    I get this message when I upload
    “In file included from SignalGenerator.ino: 2:
    E: \ Arduino-1.0.5 \ libraries \ AD9833 / AD9833.h: 55: error: ‘boolean’ does not name a type
    SignalGenerator.ino: In function ‘void setup ()’:
    SignalGenerator: 81: error: ‘digitalPinToInterrupt’ was not declared in this scope “and I don’t know where I am.
    I ask for help in this.
    (GOOGLE TRANSLATOR)
    Please help.
    Nagy F.

    Like. Reply
    • S
      shaggyDog18 July 22, 2020
      Take my re-incarnation of the firmware! It has no bugs, more sexy :-) and provides more functionality: https://github.com/ShaggyDog18/SignalGeneratorSD
      Like. Reply
    • S
      shaggyDog18 July 22, 2020
      looks like you are using an old Arduino IDE. Upgrade to the latest one!
      Like. Reply
  • N
    Nagy57 July 23, 2020

    Hi Cezar,
    I use Arduino-1.0.5 and STK500
    Not good?
    Ferenc Nagy

    Like. Reply
    • S
      shaggyDog18 July 23, 2020
      Hi Nagy57. This is not Cezar... ShaggyDog is here :-) The current Arduino IDE version is 1.8.13!!! So, sure, you need to upgrade... My firmware is here: https://github.com/ShaggyDog18/SignalGeneratorSD Hope you will like it :-) Enjoy!
      Like. Reply
  • N
    Nagy57 July 24, 2020

    shaggyDog18
    I’m sorry I’m not going.
    I wish you good luck.
    Feri

    Like. Reply
  • S
    shaggyDog18 August 12, 2020

    I’ve just added a new cool feature to my SignalGeneratorSD firmware: Stepped Sweep Generator - the frequency is varied in a range defined by values set in Ch#0 (start of the range) and Ch#1 (end of the range) with signal settings of Ch#0 and discrete steps of 0,1 of a current running frequency (kind of logarithmic steps). Frequency value steps either up or down from the start of the range depends on what channels’ frequency is larger. Frequency is changed discretely every 250 mSec (can be changed at compilation).
    The running Stepped Sweep Generator cycle is indicated by a blinking cursor at the end of a frequency value. Can be activated for Ch#0 only and uses its signal settings. While running, can be cancelled by short press and hold of OK button. When the end of the range is reached, it pauses for 3 sec and switches back to Ch#0 settings.
    Sweep generators are commonly used to test the frequency response of electronic filter circuits. Read more about Sweep Generator in Wikipedia
    Enjoy: https://github.com/ShaggyDog18/SignalGeneratorSD

    Like. Reply
    • ttran207 September 15, 2020
      Hi shaggyDog18, can you provide links to buy all the parts required (USA). I don't want to shop multiple website for the parts. Thank You so much. I will use this for a project for class work.
      Like. Reply
  • foolrear August 14, 2020

    Hi Cezar, Great project! Managed to generate new gerbers, and ordered some boards, looked through your zip file, and the one thing i’m still confused about, as i didn’t see a way to connect the ide, through a usb port?

    Like. Reply
    • foolrear August 14, 2020
      Cezar, Thanks for the great project, as an old dog learning new tricks, this is great! Think i figured out the need for an in circuit programming adapter, orderd a kit from adafruit...will let you know how it went.
      Like. Reply
  • V
    victor5 September 14, 2020

    Hi Cezar,
    Nice project, thanks for sharing.
    I am a beginner , i want to make a same project but i like to use microcontroller atmega32a with ad9833. Please help me to make connections between microcontroller and ad9833.
    Thanks

    Like. Reply
  • M
    Miroslav Lojka October 16, 2020

    Hello Cesar, I am a totally newbie in Arduino technology. Could you (or someone in the audience) provide to me a link, how to load the codes to the PCB using a Windows PC? I think I am able to modify the PCB to a one sided, so I can make it in DIY conditions. I am interested on, how to successfully connect to a PC and ow to USE the IDE environment to load the code to PCB
    Thanks a lot
    Miroslav

    Like. Reply
  • andreapas79 October 21, 2020

    Hi everyone, and thanks Cezar for your wonderful project really detailed. I’ve a question, I bought a AD9833 mounted inside a breakout board from Chinese store (the board is CJMCU9833). I use for some period and now work every kind of waves (Sine and Triangle) but not Square wave… I tried to load a simple sketch to check but nothing… anyone know how i can test it? Thanks a lot

    Like. Reply