Control of a AD9851 DDS or Midnight Design DDS60 from serial terminal

Dependencies:   mbed

Fork of Serial_HelloWorld_Mbed by mbed official

Simple AD9851 demonstration

I wrote this to replace the previous controller program I had downloaded from somewhere as the other one was written in basic and had been transferred between at least two PIC Basic variants.


So the DDS60 has an AD9851 hardwired for serial operation, a passive low pass filter, and a buffer amplifier that currently uses an AD8008 dual op-amp though I understand that earlier versions used a "MMIC" RF amplifier. It also has its own 5v regulator and requires a supply of 8-12v though I would recommend at least 9v. The design makes some compromises. The AD9851 produces two complimentary outputs and it is generally assumed that these will be combined using a transformer or differential amplifier but in the DDS60 only one output is used. The square-wave output facility is not implemented.

Three control lines are used to communicate with the AD9851. On the DDS60 these all have strong (10k) pull-up resistors.

  • DATA is the device D7 pin, which serves as data-in in serial mode. NOTE that the data is loaded LSB first unlike most SPI devices. SPI might still be usable in conjunction with a bit-order-reversal function.
  • CLOCK is the device W_CLK line, and data is clocked in on rising edges.
  • LOAD is the device FQ_UD line, and a complete update is stored on the rising edge.

Note that as the DDS60 has pull-up resistors it is probably best to use an "idle high" serial configuration so that a microcontroller reset will not generate a clock or load transition when the outputs go tristate. This is particularly true of the load pin. Also given the choice I would prefer a pull-down on the DATA pin to reduce the risk of false commands being loaded by noise when the lines aren't being actively driven.

The serial input is described as a 40 bit shift register and it appears that the number of serial clocks is not checked, the behavior with more than 40 clocks is not documented but it seems likely that excess bits at the beginning will simply "fall off" so updating using three 16 bit SPI transfers may be possible.

Switching to serial mode

The AD9851 resets into parallel mode. It must then be switched into serial mode. The usual method is to hardwire the data lines to a value with bit 1 set to 1. Then the first attempt to clock serial data into the device will cause the "switch to serial mode" command to be loaded. I would add that there is some evidence that with the data lines hardwired a power-on reset may switch it to serial mode anyway.


In designs like the DDS60 where the microcontroller does not have direct control of the AD9851 reset line it is possible that the device may already be in serial mode when the program starts, either through a false clock edge during power up or because the microcontroller was reset and the DDS wasn't.

If the device is already in serial mode and the minimum serial mode command is sent with only one clock pulse then an unexpected "test mode" command could occur. This could happen in designs that use the power down or phase shift bits. If there is a 1 in bit (W34) of the shift register and we attempt a single parallel write then the bit will "walk" down to W33 and will be loaded into the "TEST" bit.

Extra precautions are needed in addition to the datasheet recommendations to ensure the DDS cannot accidentally enter "test" mode as the only way to get it out of test mode would be power cycling. As a minimum if we send at least 7 zeroes before loading then the test bit is certain to be set to zero not one. If the device is in parallel mode then a nonsense frequency will be loaded, which can be overwritten immediately,

I recommend always sending a "safe" serial control word at program start. I'm sending 8 zeroes followed by 40 zeroes at startup. This ensures that bit W33 is zero even during a restart. In a normal startup this will be ignored and the device will switch to serial. After the switch the shift register will be in an unknown state so the 40 zeroes clears the control register and sets the frequency to zero. Alternatively instead of 40 zeroes I could just send the first full 40 bit command.

Another popular solution is to simply send the full 40 bit command including frequency twice. This works.

If you do have access to the reset pin then please ignore the above and the sequence is simply:

  • Set the Reset line, clear Clock (WCLK) and Load (FQ_UD), Pull D1 high
  • Clear the Reset line (Device is definitely in Parallel mode now)
  • Set Clock
  • Set Load (Device enters serial mode)
  • Device is now in serial mode ready to receive a 40 bit command. Since the device was forced into rest its status is known and there is no uncertainty,

Oscillator multiplier bit

The multiplier bit is mandatory with the DDS60 board in its stock configuration.

If you do not use it the device will operate with a 30MHz clock which is well below the cutoff point of the recovery filter and you will get a very poor output waveform.

Alternatively you may wish to replace the 30MHz oscillator with a 180MHz source to avoid the need for the on-chip PLL. This may improve signal quality.

Calculating the frequency programming word

  • program_word=(frequency<<32)/clock_frequency

One common approach is to cast the frequency into a "float" and calculate the value in floating point math before converting back to integer. Alternatively the calculation might be performed successfully in integer math by promoting the frequency to a double long integer.

My preferred method is a modified division operation that assumes the result is less than 1 and returns the "fractional" part as a 32 bit number.

    for(count=0;count< 32;count++)
      result = result << 1;
      freq=freq << 1;
      if (freq >= ref)
        freq = freq - ref;
Download repository: zip gz

Files at revision 5:7eaf5a5f1b23

Name Size Actions
main.cpp 2532 Revisions Annotate
mbed.bld 65 Revisions Annotate