(Solved) AD9833 Programmable DDS Waveform Generator

Anyone ever used this chip before? I’m having trouble getting it to work. I don’t have an oscilloscope yet (it comes tomorrow!), so I’ve hooked the output to my audio amp to try and listen to the frequencies it plays. So far, all attempts to generate a 440 Hz sine wave (or any other frequency) have failed. Searching only turned up this post (http://www.sinneb.net/?p=562), but the example sketch he gave doesn’t work. All I hear is weird noises coming from my speaker. My sketch does the same thing.

I managed to solder the thing onto a breakout board I got from OSH Park, and inspection under magnification does not show any solder bridges that I can see. I also tested adjacent pins with a continuity tester; no bridges found.

Here is a rundown of the connections:

VDD is connected to 5V
AGND and DGND are connected to the GND lines on my breadboard
COMP is decoupled through a 4.7 nF capacitor to 5V (odd, but that’s what the example schematic shows)
CAP/2.5V is decoupled through a 0.1 uF capacitor to ground.
MCLK is connected to Arduino pin 9 (OC1A), which is using Timer1 to generate a 1 MHz square wave
SDATA is connected to Arduino Pin 11 (MOSI)
SCKL is connected to Arduino Pin 13 (SCLK)
FSYNC is connected to Arduino Pin 10
Vout is attached through a 30 kHz low pass filter to the input of my audio amp.

I am using Timer1 in CTC mode with x1 prescaler and OCR1A value of 7 to get a 1 MHz square wave. I am reasonably certain that this clock is being generated, because when I change OCR1A to 18181 and hook Pin 9 to my audio amp, I get a 440 Hz tone. I’ll be able to check for certain when my scope gets here.

Measuring voltages, I get 2.45 V on the CAP/2.5V pin, as expected, and 3.63 V on COMP. I do not know if this is normal for COMP or not, the datasheet doesn’t say.

As I’ve written this post, I’ve gotten it to partially work. Through some odd combination of alternating between my sketch and the example sketch in the post I linked above, I’ve gotten it to play 1 kHz and 440 Hz sine tones (double-checked the frequencies with PA Tone on my phone), but it’s weird. I load the example sketch, and get weird noises. Then, when I load my sketch after that, I get a tone, but its frequency is set by the example sketch, not my sketch. After a power cycle, it goes back to weird noises.It’s very weird.

Here is my sketch. What am I doing wrong? (Note: Arduino IDE version 1.5.7)
DDS_Test.ino

#include "DDS.h"
#include <SPI.h>

void setup()
{
  pinMode( DDS_FSYNC, OUTPUT );
  digitalWrite( DDS_FSYNC, HIGH );
  Serial.begin(19200);
  SPI.setDataMode( SPI_MODE2 );
  SPI.setClockDivider( SPI_CLOCK_DIV2 );
  SPI.setDataMode( MSBFIRST );
  SPI.begin();
  set_timer1_clock();
  delay( 100 );
  Serial.println( "Set timer1" );
  dds_init();
  Serial.println( "DDS Init" );
  dds_set_frequency(1000);
  Serial.println( "DDS Set frequency" );
}

void loop()
{
  
}

void set_timer1_clock()
{
  // Disable timer1
  TCCR1B = 0;
  
  TCCR1A = _BV(COM1A0);
  OCR1A = 7;
  // Start Timer in CTC mode
  TCCR1B = _BV(WGM12) | 1;
}

DDS.h

#ifndef DDS_H
#define DDS_H

#include <stdint.h>

#define DDS_F_SETTING_MAX 0xFFFFFFFL
#define DDS_MCLK 1000000L

#define DDS_B28 13
#define DDS_HLB 12
#define DDS_FSELECT 11
#define DDS_PSELECT 10
#define DDS_RESET 8
#define DDS_SLEEP1 7
#define DDS_SLEEP12 6
#define DDS_OPBITEN 5
#define DDS_DIV2 3
#define DDS_MODE 1

#define DDS_FSYNC 9

#define DDS_SINE (0)
#define DDS_TRIANGLE (_BV(DDS_MODE))
#define DDS_SQUARE (_BV(DDS_OPBITEN))

void dds_write_control_reg(uint16_t);

void dds_init();
void dds_set_frequency(uint32_t);
void dds_set_reset();
void dds_disable_reset();

void dds_set_waveform_mode(uint16_t);

uint64_t map_frequency( uint64_t );

#endif

DDS.cpp

#include <Arduino.h>
#include <SPI.h>
#include "DDS.h"

uint16_t control_reg_value = 0;
uint16_t waveform_mode = DDS_SINE;

void dds_write(uint16_t con)
{
  //SPI.setDataMode( SPI_MODE3 );
  digitalWrite( DDS_FSYNC, LOW );
  delay( 10 );
  SPI.transfer( highByte(con) );
  SPI.transfer( lowByte(con) );
  digitalWrite( DDS_FSYNC, HIGH );
  
  //SPI.setDataMode( SPI_MODE0 );
}

void dds_init()
{
  // Set DDS chip into reset.
  dds_write( _BV(DDS_RESET) );
  
  dds_disable_reset();
}

// Frequency is in 100 mHz increments.
void dds_set_frequency(uint32_t freq)
{
  Serial.println( freq );
  int32_t freq_setting = map_frequency(freq );
  Serial.println( freq_setting );
  dds_write( _BV(DDS_B28) | _BV(DDS_RESET) | waveform_mode );
  // Write frequecy LSBs
  dds_write( (int16_t)(0x4000 | (freq_setting&0x3FFF)) );
  // Write frequency MSBs
  dds_write( (int16_t)(0x4000 | ((freq_setting>>14)&0x3FFF)) );
  
  // Write phase register.
  dds_write( 0b1100000000000000 );

  dds_disable_reset();
}

void dds_set_reset()
{
  dds_write( _BV(DDS_B28) | _BV(DDS_RESET) | waveform_mode );
}

void dds_disable_reset()
{
  dds_write( _BV(DDS_B28) | waveform_mode );
}

void dds_set_waveform_mode(uint16_t mode)
{
  waveform_mode = mode;
  dds_write( _BV(DDS_B28) | waveform_mode );
}

uint64_t map_frequency( uint64_t frequency)
{
  return frequency * DDS_F_SETTING_MAX / DDS_MCLK;
}

I seem to have solved my problem. Looks like it was a combination of two stupid things.

  1. In my sketch, in DDS.h, DDS_FSYNC was defined as 9, not 10. I would have sworn it was 10, but I guess not.

  2. In the example sketch, I wasn't setting pin 9 to OUTPUT, so the clock wasn't showing up.

So my observation works out like this: When I loaded the example sketch, it would correctly load the frequency data, but there would be no clock. When I loaded my sketch, it set PIn 9 to OUTPUT (because that was FSYNC's define), but didn't load its frequency data correctly because the FSYNC pin was wrong. However, now there was a clock, so the old frequency data would be played.

Changing the DDS_FSYNC define and adding pinMode( 9, OUTPUT ); fixed my problem.