SPI control of AD9833

A few months ago I ordered a MSOP to DIP conversion board including an AD9833 from proto advantage.  The AD9833 (LOW POWER, 12.65 MW, 2.3 V TO +5.5 V, PROGRAMMABLE WAVEFORM GENERATOR) looks like an interesting IC, doesn’t cost too much and is perhaps suited for a musical purpose.

Wiring up and controlling the AD9833 took some time and some research but I finally combined the right pieces of the puzzle.

124

At first I wired up the power section as proposed in the datasheet:

Screen Shot 2013-04-15 at 12.35.32 PM

Lots of attention to decoupling and separation of DGND and AGND, which both are a good thing ™ but also clutter my experimental setting on the breadboard. So, time to reduce the number of components with the setup from NXR:

AD9833Connsmall

Much better.

Annem did a great job interfacing the AD9837 with the Arduino. Fortunately, the AD9833 has the same interface. I did however make some adjustments. I removed the delay in re-activating the AD9833. I added the Timer1 library to generate the masterclock for the AD9833. This clock runs in the background at ~1Mhz and is made available through pin 9.

/*
AD9837 Pro Generator sample code
This was written in Arduino 1.0.1,
for an Arduino Pro Mini, 5V, 16MHz
Pete Dokter, 9/2/12
Remixed by Anne Mahaffey, 10/8/12
ReRemixed by sinneb, 15th of april 2013

The connections to the AD9837 board are:

FSYNC -> 2
SCLK -> 13 (SCK)
SDATA -> 11 (MOSI)
MCLK -> 9 (Timer1)
+Vin = VCC on Pro Micro
GND -> GND

This code bears the license of the beer. If you make money off of this,
you gotta beer me.
*/

long freq; //32-bit global frequency variable

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

// Define the FSYNC (used for SD funtion)
#define FSYNC 2

 

void setup()
{
 Timer1.initialize(1);
 Timer1.pwm(9, 512);

 pinMode(FSYNC, OUTPUT); //FSYNC

 Serial.begin(9600); // start serial communication at 9600bps

 digitalWrite(FSYNC, HIGH);

 SPI.setDataMode(SPI_MODE2); // requires SPI Mode for AD9837
 SPI.begin();

 delay(100); //A little set up time, just to make sure everything's stable

 //Initial frequency
 freq = 4000;
 WriteFrequencyAD9837(freq);

 Serial.print("Frequency is ");
 Serial.print(freq);
 Serial.println("");

}

void loop()
{

}
void WriteFrequencyAD9837(long frequency)
{
 //
 int MSB;
 int LSB;
 int phase = 0;

 //We can't just send the actual frequency, we have to calculate the "frequency word".
 //This amounts to ((desired frequency)/(reference frequency)) x 0x10000000.
 //calculated_freq_word will hold the calculated result.
 long calculated_freq_word;
 float AD9837Val = 0.00000000;

 AD9837Val = (((float)(frequency))/16000000);
 calculated_freq_word = AD9837Val*0x10000000;

 /*
 Serial.println("");
 Serial.print("Frequency word is ");
 Serial.print(calculated_freq_word);
 Serial.println("");
 */

 //Once we've got that, we split it up into separate bytes.
 MSB = (int)((calculated_freq_word & 0xFFFC000)>>14); //14 bits
 LSB = (int)(calculated_freq_word & 0x3FFF);

 //Set control bits DB15 ande DB14 to 0 and one, respectively, for frequency register 0
 LSB |= 0x4000;
 MSB |= 0x4000;

 phase &= 0xC000;

 WriteRegisterAD9837(0x2100);

 //delay(500);

 //Set the frequency==========================
 WriteRegisterAD9837(LSB); //lower 14 bits

WriteRegisterAD9837(MSB); //upper 14 bits

WriteRegisterAD9837(phase); //mid-low

 //Power it back up
 //AD9837Write(0x2020); //square
 WriteRegisterAD9837(0x2000); //sin
 //AD9837Write(0x2002); //triangle

}

//This is the guy that does the actual talking to the AD9837
void WriteRegisterAD9837(int dat)
{
 digitalWrite(FSYNC, LOW); //Set FSYNC low
 delay(10);

 SPI.transfer(highByte(dat)); Serial.println(highByte(dat));
 SPI.transfer(lowByte(dat)); Serial.println(lowByte(dat));

delay(10);
 digitalWrite(FSYNC, HIGH); //Set FSYNC high
}

I added a buffering opamp to listen to the generated sinewave. Sounds pretty OK to me. Now off to further investigate the audio possibilities of this IC.