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.
At first I wired up the power section as proposed in the datasheet:
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:
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.


