Introduction
Signal generator with ESP32 and AD9833 DDS module. In our previous project described by article Guide to creating a simple signal generator with ESP32, we built a simple signal generator using an ESP32, capable of generating sine, square and triangle waves. This project demonstrated how the ESP32 can be used to create variable signals useful for testing and developing electronic circuits. However, the generator based only on ESP32 has some limitations, especially in terms of precision and maximum achievable frequency. The need therefore arises to find an alternative to create a more performing and useful signal generator in the hobbyist’s laboratory.
To overcome these limitations and create a more versatile and precise signal generator, we will use the AD9833 DDS (Direct Digital Synthesis) module. The AD9833 module is capable of generating signals with much higher frequencies and with greater precision than the ESP32 alone. This will allow us to significantly expand the capabilities of our signal generator, making it suitable for a wider range of applications, from prototyping electronic circuits to their testing.
In this article, we will explore how to integrate the AD9833 DDS module with the ESP32, walking through the setup, connection and programming process step by step. At the end of the project, we will have an advanced signal generator capable of producing sine, square and triangular waves with variable frequencies, overcoming the limitations of the previous project. Follow us on this journey to discover how to build a powerful and versatile signal generator with ESP32 and DDS AD9833.
As usual we will use the PlatformIO IDE to write the code.
Introduction to Direct Digital Synthesis (DDS)
Direct Digital Synthesis (DDS) is a technology used to generate analog waveforms through digital methods. It is widely used in radio frequency applications, measurement instruments, and in devices requiring high precision and stability signals. DDS allows the creation of signals with very precise frequencies, which can be easily varied via digital controls.
Operating principles of the DDS
Main components
- Phase accumulator: it is the heart of the DDS system. A register accumulates phase increments with each clock cycle, creating a phase ramp that determines the frequency of the output signal.
- Phase-to-Amplitude Converter (Look-Up Table): uses phase ramp to access a lookup table (LUT) that converts the phase to an amplitude value corresponding to the desired waveform (for example, sine).
- Digital-to-Analog Converter (DAC): converts digital amplitude values ​​into analog signals.
- Low-Pass Filter: used to remove unwanted high frequency components from the DAC signal, producing a clean analog signal.
Synthesis process
- Phase generation: the phase accumulator constantly adds a phase increment value with each clock cycle. This increment value determines the frequency of the output signal.
- Phase to amplitude conversion: the accumulated phase is used to access a LUT that converts the phase to a corresponding amplitude value. The LUT is pre-programmed with the values ​​of the desired waveform (for example, the values ​​of a sine wave).
- Digital-Analog Conversion: digital amplitude values ​​are converted to analog signals via the DAC.
- Filtering: a low-pass filter removes any high-frequency components, leaving a clean and stable analog signal.
Advantages of DDS
- Precision and stability: DDS offers precise control of the signal frequency with exceptional stability, as the frequency is determined digitally.
- Flexibility: can generate a variety of waveforms simply by changing the LUT or phase increment value.
- Settling speed: frequency changes are nearly instantaneous, making DDS ideal for applications requiring variable frequencies.
- Low cost and small size: DDS systems can be implemented in relatively cheap and compact hardware compared to other frequency generation techniques.
Applications of DDS
- RF Communications: used for the modulation and demodulation of signals.
- Measurement tools: generation of precise test signals.
- Audio systems: synthesis of sounds in music and audio applications.
- Radar and navigation: generation of signals for radar and navigation systems.
DDS represents a powerful and versatile technology for the generation of high-quality signals, finding use in a wide range of advanced technological applications.
The AD9833 Module: characteristics and operation
The AD9833 module is a DDS (Direct Digital Synthesis) programmable signal generator manufactured by Analog Devices. It is designed to generate sinusoidal, triangular and square signals, and is widely used in radio frequency applications, measuring instruments and communication systems.
Main features
- Clock frequency: the AD9833 can operate with an input clock of up to 25 MHz, allowing the generation of signals with frequencies up to approximately 12.5 MHz.
- Waveforms: it is capable of generating sine, triangular and square waves, with a simple selection via digital commands.
- Frequency resolution: it has 28-bit resolution for frequency synthesis, allowing for very high frequency precision.
- SPI interface: uses a simple three-wire SPI interface for configuration and control, making it easy to integrate with microcontrollers like the ESP32.
- Low energy consumption: it consumes little power, making it ideal for portable, low-power applications.
Operation of the AD9833 module
The AD9833 works using a phase accumulator that constantly adds an increment value determined by the desired frequency. This phase accumulator provides an address for a look-up table that converts the accumulated phase into an amplitude value corresponding to the desired waveform. This amplitude value is then converted into an analog signal via a digital-to-analog converter (DAC) integrated into the module.
Advantages of the AD9833
- High precision: thanks to its 28-bit resolution, the AD9833 offers very high frequency precision.
- Flexibility: it can generate different waveforms, making it versatile for multiple applications.
- Ease of use: the three-wire SPI interface simplifies connection and configuration with microcontrollers.
- Compactness: the small size of the module makes it suitable for projects where space is limited.
Typical applications
The AD9833 finds application in various fields, including:
- RF Communications: for the modulation and demodulation of signals.
- Measurement tools: to generate precise test signals.
- Audio systems: in the synthesis of sounds.
- Radar and navigation: for the generation of signals used in radar and navigation systems.
The AD9833 is a versatile and powerful component that allows you to create advanced signal generators with high precision and flexibility, making it an ideal choice for a wide range of advanced electronic applications.
The sweep signal generator
Since our project is capable of generating both fixed and variable frequency waves (swept oscillator), let’s spend a few words on the usefulness of this operating mode. A swept signal generator, or sweep generator, is a device that produces a signal whose frequency parameter varies continuously or discretely within a predefined range. This frequency variation, called a sweep, can occur linearly or logarithmically and is used to analyze the frequency response of circuits, devices or systems.
How does it work
A sweep generator systematically changes the frequency of the output signal. This can be achieved manually or automatically through electronic controls. The main parameters of a sweep are the starting frequency, the ending frequency, the sweep speed (how quickly the frequency changes), and the sweep type (linear or logarithmic).
Utilities and applications
- Resonance analysis: used to find the resonant frequency of components and circuits, such as filters and antennas.
- Filter characterization: allows you to trace the frequency response of a filter and determine passbands and cutoff.
- Testing amplifiers: tests frequency response and amplification at different frequencies.
- Circuit diagnostics: helps identify problems such as unwanted oscillations or attenuations in specific frequency bands.
- Communication systems: used to test the response of communications systems at different operating frequencies.
Advantages
- Versatility: it can be used in a wide range of applications.
- Precision: provides an accurate characterization of the frequency response.
- Efficienza: automates the testing process, saving time and reducing manual errors.
In summary, a swept signal generator is an essential tool for analyzing and testing electronic devices, offering a complete overview of their frequency response and helping to optimize system performance.
The AD9833 DDS Module used in this project
The following photo shows the AD9833 DDS module used in this project:

The AD9833 DDS module is a digital signal generator manufactured by Analog Devices, designed to create sine, square and triangle waveforms. This specific module uses the AD9833 chip, which allows you to generate signals with frequencies up to approximately 12.5 MHz.
Main features
- Reference clock: the module integrates a 25 MHz oscillator, visible as a silver rectangle on the board.
- Outputs: two SMA connectors (in the image they are protected by their red caps), one for the signal output (VOUT) and one for the external clock input (MCLK).
- Connections: includes header pins for VCC, GND, DAT (MOSI), CLK (SCK), and FSY (CS), making it easy to connect with microcontrollers like the ESP32.
Usage
- Signal generation: ideal for testing and developing electronic circuits, generating fixed or variable frequency signals.
- RF applications: used in radio frequency applications for modulation and demodulation of signals.
The AD9833 DDS module is a versatile solution for anyone wanting to explore high-precision signal generation using a microcontroller such as the ESP32.
Rob Tillaart’s AD9833 Library used in this project
Rob Tillaart’s AD9833 library, available on GitHub at this url https://github.com/RobTillaart/AD9833, is designed to facilitate interfacing of the AD9833 DDS module with microcontrollers such as the ESP32. This library offers a number of features that simplify the generation and configuration of signals.
Main features
- SPI interface: uses the three-wire SPI interface to communicate with the AD9833 module, making it easy to integrate with various microcontrollers.
- Signal generation: supports generating sine, square and triangle waveforms.
- Frequency configuration: allows you to easily set the frequency of the generated signal with a resolution of 28 bits, ensuring high precision.
- Phase configuration: supports signal phase setting for advanced applications.
API and main methods
- begin(): initializes SPI communication and configures the AD9833 module.
- setFrequency(frequency, channel): sets the signal frequency on the specified channel.
- setWave(waveType): configures the type of waveform to generate (sinusoidal, square, triangular).
- getFrequency(): returns the current frequency of the generated signal.
- getWave(): returns the current waveform type.
Rob Tillaart’s AD9833 library is a powerful and flexible tool for anyone who wants to use the AD9833 DDS module. It facilitates setup and signal generation, making the process simple and accessible even for those with little experience with digital signal generation.
What components do we need for our signal generator with ESP32 and AD9833 DDS module?
The list of components is not particularly long:
- a breadboard to connect the ESP32 NodeMCU to the other components
- someDuPont wires (male – male, male – female, female – female)
- an AD9833 DDS module like the one described in the paragraph “The AD9833 DDS Module used in this project”
- (optional) a digital frequency meter to precisely measure the frequency of the generated signal. This tool can help you verify that your generator is working properly.
- (optional) an oscilloscope, essential for viewing the generated wave.
- and, of course, an ESP32 NodeMCU!
The ESP32 model chosen for this project is that of the AZ-Delivery company.
Project implementation
The electrical diagram
Before creating the actual circuit let’s take a look at the pinout of the board:


As you can see from the following image, the electrical diagram (made with Fritzing) is very simple:

To make the connections clearer, here is the connection table between the power supply and GPIOs of the ESP32 and the AD9833 DDS module:
Modulo DDS | ESP32 Pin |
---|---|
VCC | 3V3 |
GND | GND |
DAT (MOSI) | GPIO 23 |
CLK (SCK) | GPIO 18 |
FSY (CS) | GPIO 5 |
VOUT | Oscilloscope |
Connection diagram
- VCC to 3V3: powers the DDS module with 3.3V from the ESP32.
- GND to GND: connects the ground pin of the DDS module to the ground of the ESP32.
- DAT to GPIO 23: connects the DAT (MOSI) pin of the DDS module to GPIO pin 23 of the ESP32.
- CLK to GPIO 18: connects the CLK (SCK) pin of the DDS module to the GPIO pin 18 of the ESP32.
- FSY to GPIO 5: connects the FSY (CS) pin of the DDS module to the GPIO pin 5 of the ESP32.
- VOUT to the Oscilloscope: connects the VOUT output to your oscilloscope to monitor the generated signal.
These connections will allow you to configure and use the AD9833 DDS module with your ESP32 to generate various types of signals.
Let’s create the PlatformIO project
We have already seen the procedure for creating a PlatformIO project in the article How to create a project for NodeMCU ESP8266 with PlatformIO.
Although it refers to the ESP8266 board, the procedure is similar.
Simply, when choosing the platform, you will have to choose the AZ-Delivery ESP-32 Dev Kit C V4.
Do not install any of the libraries mentioned in the article.
Now edit the platformio.ini file to add these two lines:
monitor_speed = 115200
upload_speed = 921600
so that the file looks like this:
[env:az-delivery-devkit-v4]
platform = espressif32
board = az-delivery-devkit-v4
framework = arduino
monitor_speed = 115200
upload_speed = 921600
and add Rob Tillaart’s AD9833 library so the file looks like this:
[env:az-delivery-devkit-v4]
platform = espressif32
board = az-delivery-devkit-v4
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps =
https://github.com/RobTillaart/AD9833
You can download the project from the following link:
unzip it, take the main.cpp file and replace it with the one you have in the previously created project.
Now let’s see how the sketch works.
The sketch begins with the inclusion of the necessary libraries and a check that the microcontroller used is indeed an ESP32:
#include <Arduino.h>
#include "AD9833.h"
#ifndef ESP32
#error ESP32 only example, please select appropriate board
#endif
The variables fixed_freq are then defined which is used to set the frequency of the signal generated when not in sweep mode, the Boolean variable up which, in sweep mode, determines whether the generated frequency should rise or fall, the variables freq_sweep_max and freq_sweep_min which determine the arrival frequency and the departure frequency in the case of sweep mode, the sweep_freq variable which contains the frequency value currently generated in the case of sweep mode and the sweep boolean variable which activates/deactivates the sweep mode:
int fixed_freq = 1000;
bool up = true;
int freq_sweep_max = 1000;
int freq_sweep_min = 100;
int sweep_freq = 100;
bool sweep = false;
Following is the instantiation of the SPI bus for controlling the DDS module and the AD9833 type AD object that manages the DDS module:
// HSPI uses default SCLK=14, MISO=12, MOSI=13, SELECT=15
// VSPI uses default SCLK=18, MISO=19, MOSI=23, SELECT=5
SPIClass * myspi = new SPIClass(VSPI);
AD9833 AD(5, myspi);
// AD9833 AD(15, 13, 14); // SW SPI
We then meet the setup function. In it the serial port is activated:
Serial.begin(115200);
delay(2000);
while(!Serial);
then information about the library version is printed on the Serial Monitor:
Serial.println(__FILE__);
Serial.print("AD9833_LIB_VERSION: ");
Serial.println(AD9833_LIB_VERSION);
Serial.println();
the SPI bus and the AD object that manages the DDS module are initialized:
myspi->begin();
AD.begin();
the frequency of the quartz oscillator inside the module and the frequency of the signal generated are set if the mode is fixed frequency (i.e. non-sweep):
AD.setCrystalFrequency(25000000);
AD.setFrequency(fixed_freq, 0);
the type of wave generated is then set:
AD.setWave(AD9833_TRIANGLE); // AD9833_SINE AD9833_SQUARE1 AD9833_SQUARE2 AD9833_TRIANGLE
In the case of AD9833_SQUARE1 and AD9833_SQUARE2, one of the two square waves has a frequency equal to half the other.
Finally, information on the type of wave generated and its frequency is printed on the Serial Monitor.
Serial.println(AD.getWave());
Serial.print("Current frequency: ");
Serial.println(AD.getFrequency());
The part that manages the sweep is implemented in the loop function.
if(sweep) {
if (up) sweep_freq++;
else sweep_freq--;
// reverse direction if needed
if (sweep_freq >= freq_sweep_max) up = false;
if (sweep_freq <= freq_sweep_min) up = true;
AD.setFrequency(sweep_freq);
Serial.print("Current frequency: ");
Serial.println(AD.getFrequency());
delay(10);
}
If the sweep is activated, the first if block is active and the code inside it calculates which frequency to generate and whether this should increase or decrease (via the up variable). The current frequency is set via the AD.setFrequency(sweep_freq) command. The current generated frequency is also printed on the Serial Monitor. The last command, delay(10), determines how quickly the frequency is incremented/decremented. So to slow down the sweep it is sufficient to increase the number inside it (for example 20 or 50 instead of 10).
In this implementation, the change in sweep frequency is linear.
Final considerations and limitations
These modules have good build quality and generally work well, but don’t expect to be able to get up to the AD9833’s maximum frequency of 12.5 MHz. The AD9833 is a DDS (Direct Digital Synthesis) chip and as the output frequency approaches the clock frequency, which in this case is 25 MHz, the ability to reproduce the required waveform begins to decrease.
Stability is good up to about 1 MHz for square and triangle waveforms, then the waveform starts to get worse as the frequency increases. In the case of a sine wave, the generated signal appears without appreciable distortions up to approximately 4 MHz.
In the case of a sinusoidal and triangular signal, the output has a voltage value of approximately 0.6 Vpp which oscillates between 0 V and approximately +0.6 V. At frequencies above 1 MHz, the amplitude of the signal begins to decrease. Unlike the other two waveforms, the square wave output will vary between 0 V and Vcc for most frequency values ​​generated.
Testing with the oscilloscope
Below are the tests done with the oscilloscope on the three types of waves:



Video of the generator in sweep mode
In the following video you can see how the sweep works. The waveform is a sinusoid whose frequency varies from a minimum of 100 Hz (because we have that freq_sweep_min = 100) to a maximum of 1000 Hz (because we have that freq_sweep_max = 1000) and then decreases to 100 Hz and starts to grow up to 1000 Hz in an infinite loop.
Newsletter
If you want to be informed about the release of new articles, subscribe to the newsletter. Before subscribing to the newsletter read the page Privacy Policy (UE)
If you want to unsubscribe from the newsletter, click on the link that you will find in the newsletter email.