Signal Generator AD9833

Introduction: Signal Generator AD9833

A signal generator is a very useful piece of test gear. This one uses an AD9833 module and an Arduino Nano - that's all, not even a PCB. You can optionally add an OLED display. The AD9833 can gererate sine, triangle and square waves from 0.1 Hz to 12.5 MHz - the software in this project is limited to 1Hz to 100kHz.

There have been other Instructables using an Arduino and an AD9833, here and here. This is simpler and can be used as a sweep generator. Sweep generators help test the frequency response of filters, amplifiers and so on. Unlike the other Instructables designs, this does not include an amplifier or amplitude control but you could add them if you wanted.

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Simplest Signal Generator

For the simplest Signal Generator, you just solder the AD9833 module onto the back of the Arduino Nano. No PCB is needed.

The AD9833 module I chose is similar to this one. I'm not saying that's the best or cheapest supplier but you should buy one that looks like that photo (or the photo above).

The connections between the modules are:

  • grounds connected together
  • D2 = FSync
  • D3 = Clk
  • D4 = Data
  • D6 = Vcc of AD9833

The AD9833 is powered from data pin D6 of the Arduino - the Arduino can supply sufficient current. I've added a 100n decoupling capacitor because I thought I "ought" to but I couldn't see any difference - there is already a decoupling capacitor on the AD9833 module board.

If you were being fancy, you might worry about "analogue ground" vs "digital ground" but if you were being fancy, you'd be spending more than £4.

The simplest Signal Generator is controlled and powered over a USB lead from a PC. The USB emulates a serial port running at 115200bps (8-bits, no parity). The commands are:

  • '0'..'9': shift digit into "min" frequency array
  • 'S': set AD9833 frequency and produce sine wave
  • 'T': set frequency and produce triangle wave
  • 'Q': set frequency and produce square wave
  • 'R': reset the AD9833
  • 'M': copy "min" frequency array into "max" array
  • 'G': sweep from "min" to "max" over 1 second
  • 'H': sweep from "min" to "max" over 5 seconds
  • 'I': sweep from "min" to "max" over 20 seconds

The Arduino program contains two 6-character arrays "min" and "max. If you transmit a digit then it is shifted into the "min" array. If you send an 'S' then the "min" array characters are converted into a longint frequency and sent to the AD9833. So sending the string

002500S

will set the AD9833 output to a 2500Hz sine wave. You must always send all 6 digits. The minimum frequency is 000001 and the maximum frequency is 999999.

If you send an 'M' then the "min" array is copied into the "max" array. If you send an 'H' then the AD9833 repeatedly outputs a gradually increasing frequency over 5 seconds. It starts at "min" frequency and 5 seconds later is at "max" frequency. So

020000M000100SH

sweeps from 100Hz to 20kHz. The frequency change is logarithmic so after 1 second the frequency will be 288Hz, after 2 seconds 833Hz then 2402, 6931 and 20000. The frequency is changed every milliSecond.

The loop stops when the Arduino receives another character so be careful not to send the command followed by carriage-return or line-feed. That extra character would terminate the loop. If you're using the Serial Monitor, there's a box at the bottom right that might say for instance "Both NL & CR" which (I think) sends characters after your command. Set it to "No line ending".

You can download the Windows EXE program below which will send the required commands or you could write your own. The Arduino INO file is also here.

Step 2: Add an OLED

If you add an OLED and two buttons, the signal generator can work alone without a PC.

Those of you who have read my oscilloscope Instructable will recognise the similarity. The AD9833 module can be added to my oscilloscope to produce an "Oscilloscope and Signal Generator in a Matchbox".

The display is a 1.3" OLED running at 3.3V which is controlled by an SH1106 chip via an I2C bus.

Search eBay for 1.3" OLED. I don't want to recommend a particular seller as links quickly go out of date. Choose one that looks like that photo, says "I2C" or "IIC" and has four pins labelled VDD GND SCL SDA. (Some displays seem to have the pins in a different order. Check them. The proper name for the clock of I2C is "SCL" but on eBay the boards can be labelled "SCK" like my one in the photo.)

A fuller description of the OLED library is in my oscilloscope Instructable in Step 8. You should download and install the driver library SimpleSH1106.zip which is in Step 8. (I don't want to upload another copy here and have to maintain two copies.)

The INO file can be downloaded below. The pin numbers used for the OLED are declared around line 70. If you have built my "Oscilloscope and Signal Generator in a Matchbox" and want to test this INO file with it, alternative pin numbers are enabled via a #define.

I've shown a stripboard layout for the circuit. There are two stripboards - one for the Nano and the AD9833 and one for the display. They should form a sandwich. The boards are shown from the component side. Fine flexible wires join the two boards. Attach the boards together with soldered stand-offs. In my diagram, the copper of the stripboard is shown in cyan. Red lines are wire links on the stripboard or flexible wires joining the boards together. I haven't shown the power and "signal" leads.

The AD9833 module is soldered on the copper side of the stripboard - on the opposite side from the Nano. Solder pins onto the copper strips then fit the AD9833 onto them and solder it on.

The display shows either a single frequency or the "min" and "max" frequencies.

There are two pushbuttons: a "Horizontal" button to select a digit of the frequencies and a "Vertical" button to change that digit.

I power the signal generator from the circuit I'm developing - I always have 5V available at my workstation.

Step 3: Future Developments

Could it be battery powered? Yes, just add a 9V PP3 connected to the RAW pin of the Nano. It typically uses 20mA.

Could it be powered by a single lithium cell? I don't see why not. You should connect the OLED Vdd and its pull-up resistor to the 3.7V battery (I doubt if the 3.3V output of the Arduino would work properly).

A sweep generator is more useful when testing the frequency response of a filter if you can graph amplitude vs frequency. Measuring the amplitude of a signal is tricky - you have to trade off the decay of your envelope detector vs ripple for low frequencies and response time for high frequencies. Having built your amplitude detector, you could feed its output into the ADC of the Arduino of the "Simplest Signal Generator" then send the result, along with the current frequency to the PC.

This page is a useful starting point or search Google for "envelope detector" or "peak detector". In the suggested circuit above, you would set the signal frequency, wait for it to stabilise, set the Arduino A0 pin to output digital low, wait to discharge C, set A0 to input, wait, then measure with the ADC. Let me know how you get on.

2 People Made This Project!

Recommendations

  • Backyard Contest

    Backyard Contest
  • Silly Hats Speed Challenge

    Silly Hats Speed Challenge
  • Arduino Contest 2020

    Arduino Contest 2020

20 Discussions

0
emil.cristofor
emil.cristofor

4 weeks ago

Hi Peter,
I find your " Step1: Simplest Signal Generator" a very nice project to understand the functioning of AD9833! Everything OK but, I have a problem with SWEEP function, it doesn´t works on my hardware.
My hardware configuration is almost identical with the one in your exemple: Arduino UNO R3 together with one module AD9833 identical with the one in your picture and the same connections.
Have you an idea way the comand 002000M000100SH ( and also other similar combinations) didn´t works ?
Thanks for your answer!
Sincerely yours, Emil

0
Peter Balch
Peter Balch

Reply 4 weeks ago

So it looks like the loop inside the Sweep function only executes once.

The loop is
do {
...
} while (!Serial.available());

The loop stops when the Arduino receives a character. Could you be sending

002000M000200SI

followed by carriage-return or line-feed? And that extra character is terminating the loop?

The Serial Monitor has a box at the bottom right tha might say for instance "Both NL & CR" which I think might send characters after your command. Try setting it to "No line ending".

0
Peter Balch
Peter Balch

Reply 4 weeks ago

Good. I'll update the Instructable to warn about the problem.

Thanks.

0
emil.cristofor
emil.cristofor

Reply 4 weeks ago

Thank you Peter! You´ve found the solution!
That was the problem: the editing of a new line.
I have blocked the NL in Seriall Monitor and now SWEEP works wonderfull.
Thanks a lot again! Sincerelly yours, Emil

0
emil.cristofor
emil.cristofor

Reply 4 weeks ago

Thanks for your answer.
After your addendum I received the following messages on Serial monitor:
Command:
002000M000200SI
Monitor replay:
fmin200
fmax2000
f200
Sorry, but no sweep !
Emil

0
Peter Balch
Peter Balch

Reply 4 weeks ago

I don't know why it's going wrong just with that command.

You could put some debugging statements into the sweep function. See below. Then use the Arduino Tools SerialMonitor to see what Sweep thinks it's doing.


void Sweep(int n) {
int fmin,fmax;
fmin = calcFreq(freqSGLo);
fmax = calcFreq(freqSGHi);
Serial.print("fmin ");Serial.println(calcFreq(freqSGLo));
Serial.print("fmax ");Serial.println(calcFreq(freqSGHi));
int i=0;
do {
long f = exp((log(fmax) - log(fmin))*i/(n-1) + log(fmin)) +0.5;
Serial.print("f ");Serial.println(f);
SG_freqSet(f, waveType);
delay(1);
i++;
if (i >= n) i = 0;
} while (!Serial.available());

SG_freqSet(calcFreq(freqSGLo), waveType);
}

0
Peter Balch
Peter Balch

Reply 4 weeks ago

Hi Emil

I'm sorry you're having trouble. You say that "other similar combinations" don't work. What does work? Do simple commands like 002500S work?

What commands do or don't work?

Peter

0
emil.cristofor
emil.cristofor

Reply 4 weeks ago

Hi Peter,
Here some more info:
I said already that all simple functions, like 002000S, or 000100Q, or 004000T all of them are functioning perfect.
When I give a command for SWEEP, like 003000M000300SH, or similar with other frequency or an other wave is following hapend ( I am watching what hapend on my osciloscope):
1. PC W10 with Arduino 1.8.12;
2. Command 002000M000200SH writen in Serieller Monitor is taken without error by your Skatch;
3. On my scope is suddenly dislayed only the lowest frecvency of 200 Hz.
4. I supose that the higher freqvency of 2000 Hz was already changed in AD9833 register with the lower frequency of 200 Hz,
but no FREQUENCY SWEEP of 5 sec. long is on osciloscope to be observed.
Thanks, Emil


0
emil.cristofor
emil.cristofor

Reply 4 weeks ago

Hi Peter,
I already said that everythig works perfect, include the simple command like 002000S, or 000100T, and so one. Only SWEEP functon like 002000M000200SG or, similar x...xMy...yTG or similar x...xMy...yQI, these are not working.
Emil

0
tannenba
tannenba

2 months ago

Made this on a breadboard for now. Your library works great with an .96" OLED with a SSD1306. Even it, is very legible. Love it. Moved it to a circuit card the size of a 1/2 breadboard. It will fit in a box with a 9v Battery.
Joe

0
tannenba
tannenba

2 months ago

While waiting on the AD9833, I got the OLED. Your library example works with an Uno. Also tried it with a Digispark, but it doesn't work for that. Didn't figure out why not..

0
freddie43
freddie43

5 months ago

I loved your Oscilloscope in a Matchbox (at https://www.instructables.com/id/Oscilloscope-in-a-Matchbox-Arduino/) - as mentioned in my previous comments on that project.

But I wanted to use this Sig Gen project of yours to drive that 'scope. When my AD9833 arrived I eventually got round to trying it.

What I wanted was to set my frequency by rotary encoder and/or a potentiometer, but I am afraid I just couldn't get my head round the AD9833 interface and the way you had coded it. The project sat on the shelf for a while until I stumbled on Bill William's AD9833-Library-Arduino which took all the hassle out of the interface.

This was just what I wanted and it allows the user to independently program frequency, phase, and waveform type for the AD9833. It is at https://github.com/Billwilliams1952/AD9833-Library-Arduino and I commend it to you

0
Peter Balch
Peter Balch

Reply 5 months ago

That sounds good. Did you use my code for the OLED?

My code is more complicated then it needs to be probably because all I did was delete lines from the "Oscilloscope in a Matchbox".

0
freddie43
freddie43

Reply 5 months ago

Sorry to take so long to get back to you but had a number of problems.
I decided to use a Rotary encoder for 0-30kHz in 1K steps and add on to that a pot to give 0-1000 (approx) fine tuning.

First problem was my old simple Rotary encoder code wouldn't work, so I
experimented with a number of libraries which gave a precise reading,
but of course when I included an OLED for the KHz reading that threw
them out, so I adopted a simple update of the OLED every now and again. I
settled for an OLED update once every 500 cycles of the Rotary code.

RotaryEncoder.h by Matthias Hertel worked well, but I get the odd hiccup with it so I
plan to explore some of the others (of which there are many) - some
working on interrupts.

Anyway, that is where I got to. The important thing is the grandson is impressed - especially when connected up to your "Oscilloscope in a Matchbox" now I have connected up BtnHorz to expand the X axis of the display and connected it all up to an amplifier. He happily doodles all day proving that his hearing is far superior to our 9.5kHz!

0
freddie43
freddie43

Reply 5 months ago

Sorry Peter. Only low priority project using serial monitor at the moment. Having a bit of a problem using two (noisy) pots to set the frequency. Must work out how to best use my rotary encoders. Haven't yet get out of my hearing range to show grandson that I only hear a fraction of what he does! But your scope Nano + OLED on a small breadboard is SO useful as an educational aid.

0
piconano4u
piconano4u

5 months ago

You ROCK.
Just got my AD9833. My module has different pin outs but will do.
I'll be stealing your code as a starting step for my own tweaks.
I love all your projects. Both thumbs up :)

0
Peter Balch
Peter Balch

Reply 5 months ago

Excellent. I look forward to your instructable when you finish!

0
AdeZ4
AdeZ4

8 months ago

Sorry for bothering you, SCK is for SPI and you said yours is 12C. Maybe I miss something but better to ask you before buying an Oled.
Thanks!
You have the best and simplest tutorial on the internet for a signal generator with AD9833.

0
Peter Balch
Peter Balch

Reply 8 months ago

Yes it's an I2C Oled.

And you're right, the clock for I2C is called "SCL" not "SCK". Thank you, I'll correct the text.

But on the actual OLED board it's labelled "SCK". Confusing.

0
Peter Balch
Peter Balch

Tip 1 year ago

TungL20 has pointed out that the button assignment in the schematic is to pins 6 and 7 but the code refers to pins 4 and 7.

Lines 35-36 of SigGen2.ino should be:

const int BtnHorz = 6; // pushbutton
const int BtnVert = 7; // pushbutton

Sorry for my mistake.