AD9850 DDS VFO

I was browsing eBay one day and I ran across a posting for the Analog Devices AD9850. The AD9850 is a chip that can produce a sinusoidal wave from about 1hz to 40mhz. Somehow the electronics dealers in Hong Kong have been able to mate the chip to a small board that provides TTL level control and then sell it for an unbelievable $8 (or less!). I know a few people have paid as little as $4 (USD) for them.

AD9850 Module

To control the AD9850 you’ll need some sort of micro-controller.  Without going into too much detail you are required to send a set of serial or parallel data to the chip to set the frequency.  There are numerous postings on the web detailing exactly how to do this so I won’t go into too much detail. However it has been hard to find a good AD9850 Pinout so here you go.

D0 – D7 = Parallel programming bits
GND = Ground (obvious); Vss
CLK = Serial programming clock
Latch = Serial programming latch (FQ_UD pin on 9850)
DATA = Serial programming DATA (internally tied to D7)
RST = Reset. Keep tied to GND
SQW = Square wave outputs (complementary) Duty cycle adjustable with blue pot.
SINA = Raw unfiltered AD9850 sine output
SINB = 70 MHz LPF filtered AD9850 output.

For me, the easiest way to manage the AD9850 is with an Arduino Uno.  If you don’t know about the Arduino platform you should check out the official site at www.arduino.cc.  I have been playing with the Arduino for only a couple of months and I already have found it to be a fantastic development platform.  If you are a hobbyist tinkerer… you really can’t go wrong with one.

I have paired may AD9850 with an Arduino Uno, LCD display, Rotary encoder, and a few other small parts and have put together a very descent DDS VFO capable of any frequency between 1mhz and 30mhz (It will go to 40 if you wish).  A little quick work with a protoboard and I have a nice working VFO.  You can watch my video on YouTube showing how it works. I also have another video of the VFO attached to my oscilloscope.

AD7C DDS VFO

This project is ongoing.  You should be able to deduce the pin outs on all items from the Arduino Sketch but if you have questions just contact me. My schematic is a little rough as I do not tend to create them that often so let me know if you catch anything out-of-place!

Because of a lot of requests I have also created a version for IF (superhet) type receivers. The VFO now supports an Intermediate Frequency and can switch upon the HI/LOW level of one analog input on the Arduino. The IF can be anything you wish and can be additive or subtractive.

** UPDATE November, 2013 **
I have updated the sketch to write the last tuned frequency to memory and recall it upon boot-up. This is a 100% direct drop-in replacement and requires you to only upload the new sketch. The code is well documented and for those of you who modified my original sketch it should be easy enough to adapt as you see fit.

Both Arduino sketchs (IF and NON-IF), schematic, libraries, and notes are available for download here.  Also, Jiri (OK1DXK) create a great drawing (aka schematic) if you wish to use an Arduino Nano. If you build something from my design please send me a picture or a video of your creation.  I love to see what others do!





Or you can also send a donation via paypal to rvisokey@yahoo.com (My registered PayPal address.)

444 thoughts on “AD9850 DDS VFO

  1. Hi, I’m wanting to build a VFO to run an old Drake 2 NT xtal controlled transmitter. I’m interested in what you have built here. I will need some kind of amp to bump up the output to 4v ptp, manual calls for 12v on 15 meter band for some reason.
    Anyhow I like what you have here and let me know what you think.
    Thanks, Gary KF7WNS

    • Gary,

      You can easilly build a buffer amp to drive the signal to 4v PTP or even 12v PTP, however, I find that level somewhat huge! Typically 1v or .5v is more than ample for most circuits but if that’s what the manual for your Drake states… that’s what you’ll need.

      Please remember that the output voltage of the DDS VFO varies with frequency so if you need it to output a constant level across a wide-range VFO you’ll need to design an AGC (or sorts) into your buffer to provide a constant level output. I’ve seen some great designs with simple op-amps that accomplish this with a tap into the feedback circuit. I’m not the expert here so I would recommend you get on the eham.net forums or arrl.org TIS group for more assistance.

      God luck on your project.

      73,

      Rich
      AD7C

    • I am not familiar with the Arduino Mega so I can’t be of assistance. You’ll probably need to adjust the pinouts from the UNO to the MEGA as they are different. The main difference is going to be the Interrupt pins.

      Sincerely,

      Rich
      AD7C

    • This was asked a number of years ago but is still valid.
      The reason the rotary does not work on the Mega2560 is due to the differences in interrupts between the Uno and the Mega2560 or or specifically the Uno’s lack of them. It turns out the fix is rather simple.

      In the setup(){} function comment out the following lines and then add the two lines immediately after the commented out code like this::
      /*
      PCICR |= (1 << PCIE2);
      PCMSK2 |= (1 << PCINT18) | (1 <=30000000){rx=rx2;}; // UPPER VFO LIMIT
      if (rx =30000000){rx=rx2;}; // UPPER VFO LIMIT
      if (rx <=1000000){rx=rx2;}; // LOWER VFO LIMIT
      }
      }

      No change in pinouts necessary though I did adjust the lcd wiring with pin 4 of the lCD to D13 and pin 6 of the LCD to D12 (just swapped them) and changed:
      LiquidCrystal lcd(12, 13, 7, 6, 5, 4);
      TO:
      LiquidCrystal lcd(13, 12, 7, 6, 5, 4);

      One last thing that is not Mega2560 specific was a labeling errata in the wiring diagram. D10 of the Arduino goes to the DATA pin of the AD9850 and NOT D7. So it should read DATA and not D7 on the DDS AD9850 in the diagram. Hope this helps someone.
      It works for me :-)
      Nikki

      • What a shame, the web code filtered out some of the code I posted. This makes the above incomplete. So I will try to describe what needs to be done instead.

        On the Mega2560 use the attachInterrupt() function in the setup() part of the program. The lines that reference PCICR , PCIE2, PCMSK2, PCINT18 and PCINT19 as well as the sei(() function in setup() can be commented out or deleted. This amounts to 3 lines towards the top of the setup() function. The new code uses attachInterrupt() for INT_0 & INT_1 like this:
        attachInterrupt(0,MyIsr,CHANGE)
        attachInterrupt(1,MyIsr,CHANGE)
        of course don’t forget the semicolons at the end of each line.

        Next you simply want to change the name of the ISR service routine (called ISR) from ISR(PCINT2_vect) to void MyIsr(void). Then your’re done. I hope the web server doesn’t filter out this, If it does, then I tried.
        Good luck,
        Nikki

        • in this way?
          void setup() {
          lcd.begin(20,4);
          lcd.backlight();
          Serial.begin(9600);
          lcd.setCursor(0,0); // Se pone el cursor en la primera posición de la pantalla
          pinMode(A0,INPUT); // Connect to a button that goes to GND on push
          digitalWrite(A0,HIGH);
          //PCICR |= (1 << PCIE2);
          //PCMSK2 |= (1 << PCINT18) | (1 <=30000000){rx=rx2;}; // UPPER VFO LIMIT
          if (rx <=1000000){rx=rx2;}; // LOWER VFO LIMIT
          }
          }
          well i have a problem :

          dds9850.ino: In function 'void setup()':
          dds9850.ino:33:20: error: 'MyIsr' was not declared in this scope
          dds9850.ino: At global scope:
          dds9850.ino:46:6: error: expected constructor, destructor, or type conversion before '(' token
          Error de compilación

          • //PCICR |= (1 << PCIE2);
            //PCMSK2 |= (1 << PCINT18) | (1 <=30000000){rx=rx2;}; // UPPER VFO LIMIT
            if (rx <=1000000){rx=rx2;}; // LOWER VFO LIMIT
            }
            }

      • good morning i’m trying to load the code into an atmega1284p and i have a problem with the rotary encorder can you help me?
        in terms of the changes I need to make

        • Post your problem. However, most times you can fix the rotary encoded by making sure you use the proper case: Rotary not rotary.

          • good morning I am loading the file on arduino nano, uno, mega it works perfectly !!!! I also uploaded it to atmega 1284 and I see that it wants a different library for the rotary encoder, this is the only problem, can someone help me? I am new to programming !!! Thanks in advance.

  2. Hi, I too am planning on building this circuit. I was wondering if you’ve messed around with the AD9850 Library for the Arduino? I appears to have simplified things quite a bit. I’m also looking for other examples using the AD9850. I bought 2 for pocket change. Here’s the library:

    http://code.google.com/p/ad9850-arduino/

    • Never used the library as I had no issue controlling it for what I needed it to do but thanks for the tip! 73, AD7C – Rich.

    • Analog Devices AD9850. Get on ebay.
      The rotary encoder I used was from a junk drawer, however, you can find a similar one for $3-$4USD at sparkfun.com or mouser.com.

  3. Might this be a cheap replacement for a bad PTO on a TenTec Century 21 I have? Thoughts? Thanks for your work!

    Ronny
    K4RJJ

    • I don’t know much about Permeability Tuned Oscillator circuits, however, I see no reason why you can’t use it. Realize that it would replace the entire PTO