Tuesday, April 21, 2015

AD9833 Signal Generator

In an earlier series of posts, I described building a prototype signal generator using a DAC driven by an Arduino. The Arduino sent sample values to it, allowing arbitrary wave forms to be generated. It was limited to a fairly low frequency by the rate at which the samples could be sent.

An alternative is to use a component that generates signals directly. Analog Devices have several such. They are known as DDS devices, for direct digital synthesis. The idea is that the DDS generates a digital value internally which it then converts to an analog output. The disadvantage of such devices is that they can't generate arbitrary waveforms. For example, the AD9833 generates sine, triangle and square waves, and the AD9850 generates only sine and square waves. They are not really intended for arbitrary signal generation, and instead are aimed more at things such as modulating and demodulating signals.

I put together a signal generator using an Arduino, a prebuilt AD9833 module and some components to provide a user interface: a LCD display, and a rotary encoder. You can pick up AD9833 modules quite cheaply on ebay. AD9850 modules are more widely available and a bit cheaper. Here is the wiring diagram for how I connected it up:
The rotary encoder incorporates a switch, which I have shown separately, and the trimmer is for adjusting the contrast on the LCD.

[Sep 2021: the code for this is no longer available. The following description might not make sense as a result.] Roughly, the idea is to show three fields in the display: the frequency (1Hz to 1MHz), the waveform and whether automatic or manual mode is in use. Automatic mode means changes take effect immediately. Pressing the switch (actually the shaft of the rotary encoder) has various effects. A long press moves between the three fields, indicated by an arrow next to the active field. While in the frequency field, turning the encoder increases or decreases the frequency, and a short press of the button select which digit you are altering. For example, if the current frequency is 10000Hz and the current digit, indicated by a cursor, is the middle one, the frequency changes in steps of 100Hz. On the waveform field, the encoder steps between sine, square and triangle. On the automatic/manual field, the encoder steps between these options, and a short press on the button while in manual mode applies the current settings.

Originally I had thought of making this a full project, packaging it up and adding more options to the software. For now, I am leaving it like this, as I have some ideas for a different signal generator project that I would like to explore.

19 comments:

Raspberry Pi Goodies said...

I am unable to compile this due to a missing include "ClickEncoder.h" - do you have a link for that?

wolf said...
This comment has been removed by the author.
wolf said...

Rotary encoder uses the library from:
https://github.com/0xPIT/encoder/tree/arduino.

Also needs:
http://playground.arduino.cc/Code/Timer1

to have square-wave output with the shown (full, otherwise only half) frequency, change Line 354ff to:
************************
case Square:
word |= 0x0028; //Control Bit3 should be 1
break;
#if 0
// We don't implement half frequency square wave in this version.
case SquareHalfFreq:
word |= 0x0020;
break;
#endif
************************


With my encoder, I had to comment lines 236 and 237 to be able to change the wave- and A/M-mode values
************************
void EnumeratedSetting::ChangeSetting(bool next) {
if (next) {
setting_ += 1;
// } else { //line 236
// setting_ -= 1; //line 237
************************

To change the frequency, I used the following code:
search for void loop() {
and change it to:
************************
int kk;
void loop() {
************************
search for switch (switch setting_mode.Current()) {
and change code til if (b == ClickEncoder::Clicked) {
in:
*************************
switch (setting_mode.Current()) {
case ModeHandler::Freq: {
bool changed = false;
if (encoder_value != 0) {
kk=kk+1;
if (kk==2) {
value_encoder.Add(encoder_value);
kk=0;
changed = true;
}
}
if (b == ClickEncoder::Clicked) {
*************************

Moosteron said...

@wolf, thanks for the comments. It seems like there is some variation between different click encoders.

wolf said...

I used this module (http://www.thebackshed.com/forum/uploads/matherp/2015-10-13_101115_P1070065.JPG)
It has a digital poti (MCP41010onboard and therefore i changed your code to adjust and display the amplitude on the LCD.
(Ok, I killed the A/M module...). now there's only the phase shifting which isn't implemented yet. Perhaps I'll change the supply voltage of the OPAmp to get a greater amplitude (only 4 Volt with Triangle and Sin).

Very nice project.

Gr33tZ
wolf

Unknown said...

Hi!
A very nice project.
Unfortunately I can not identify all components on the Fritzing image: What is the value for the trimmer, what is on the left sind (blueish component), and wehre can I find details about the rotary encoder?

Would be very happy if you could answer these questions.

Thanks a lot in advance
Jazzman

Moosteron said...

The trimmer was supplied with the LCD (https://www.adafruit.com/product/181). It's 10k. The rotary encoder was http://www.dxsoul.com/product/maitech-5-pin-short-handle-rotary-encoder-switches-silver-2-pcs-901302050#.VpQrKI0rLlM.

Unknown said...

Sad - but I can not find any retailer for the AD9833!

I do not know why, but they seems not to being sold in Germany (not at Amazon, Farnell, Mouser...). I found it as a SMD part - but then I would have to solder it. And I am afraid that not only a AD9833 is on the board. Since I can not see what kind of AD9833 is on your Fritzing image - I would be happy if you could send me a real image of it - or any alternatives?

So sad that I can not order a AD9833 :-(

Thanks
Jazzman

Moosteron said...

I bought it as a module rather than just the IC. It was this (though maybe not from this seller): http://www.ebay.com/itm/DDS-Signal-Generator-Module-AD9833-Sine-Square-Wave-/321768209062?hash=item4aeae13aa6:g:JDYAAOxyY3ZRwmWV.

Unknown said...

Hello again!
I have two questions more, and hope you can answer them:
1. In your Fritzing image I see that the two first pins of the LCD (from left) are not connected. I think that can not work. In my own project I have connected the first pin (1) to ground and the second (2) to 5V. Can you explain this?
2. Since I can not find a AD9833 component in the Fritzing component library I wanted to ask you for this component. Or would it be possible to explain how you created that? (I am new to Fritzing and not sure how I can create new components.)
Thanks a lot
Regards, Jazzman

Unknown said...

Any news?

Unknown said...

Hello.
I would be happy, if you could send me the AD9833 Fritzing component. Do you think it would be possible - it would be a great help.
Regards, jazzman

Moosteron said...

Jasmin, try this: https://drive.google.com/open?id=0B1Estn1NTU3TRjd2bF9DVm5SVE0. It's the only file I can find for the project.

Unknown said...

Cool!
I will give it a try.
Thanks a lot!

Warm Regards, jasmin

Unknown said...

how can we change phase angle of sine or some other waves. i tried to access Phase register but not use.

Moosteron said...

Sorry Siva, I don't remember. It's a long time since I did this work.

Jan said...

@Wolf
Is it possible to post your code for this version of the AD9833 module?

Unknown said...

@Wolf
May I ask sir if what is the used of pin OUT and REF in the module AD9833?
Thanks.

Muhammad Sufyan said...

https://github.com/tardate/LittleArduinoProjects/tree/master/FritzingParts/AD9833_Module

use this link to get AD9833