AD9833 Problems with Arduino and SPI [Can't think of a good title]

Alright I'm about at my wits end, I'm playing around with a AD9833 to synthasize a sin wave. I have combed though all forms of forums regarding the AD9833 to no avail. This is the circuit I'm running.

EDIT: although the circuit says Fsync is controlled by PB0(pin 53) its actually connected to pin 36 as per the code

Another EDIT: Im doing this on a breadboard, which as I have read is a big no no, could this damage the part, or would it only introduce crazy interference. . I'm controlling the AD9833 with an Arduino Mega2560 and communicating with the SPI protocol, but instead of using the SS pin on the Arduino I'm manually controlling the Fsync pin, as I need to transfer 16bit.

// the sensor communicates using SPI, so include the library:
#include <SPI.h>

// pins used for the connection with the sensor
// the other you need are controlled by the SPI library):
const int fSync = 36;

void setup() {
Serial.begin(9600);

// start the SPI library:
SPI.begin();
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3));
// initalize the  data ready and chip select pins:
delay(10);
pinMode(fSync, OUTPUT);
digitalWrite(fSync, HIGH);
delay(10);

digitalWrite(fSync, LOW);
SPI.transfer(0x20);      //turns B28 - write 28bits to FREQ register
SPI.transfer(0x00);
digitalWrite(fSync, HIGH);
delayMicroseconds(1);

digitalWrite(fSync, LOW);
SPI.transfer(0x4C);     //write 0x0C0F to 14LSB
SPI.transfer(0x0F);
digitalWrite(fSync, HIGH);
delayMicroseconds(1);

digitalWrite(fSync, LOW);
SPI.transfer(0x70);     //write 0x30FF to 14MSB
SPI.transfer(0xFF);
digitalWrite(fSync, HIGH);
delayMicroseconds(1);

digitalWrite(fSync, LOW);
SPI.transfer(0x00);      //Output sinewave
SPI.transfer(0x00);
digitalWrite(fSync, HIGH);
delayMicroseconds(1);

SPI.end();
}

void loop() {

}


The data is being clock in on the falling edge, and the clock is idling high.

This is 1MHz signal I'm using as my master clock, and its coming from a function generator.

This monstrosity is what I'm getting for an output. By my calculations the FREQ register should have 0x30FFC0F = 51.379E6. This means the output frequency should be about 191 kHz - which is a fluke I think becasue this wave form has a frequency of about 200 kHz

I'm sure the data registers are being updated as can be seen here when I enter the following SPI data

0x2000
0x4C00
0x7F0F
0x0000


I have checked my voltages and everything seems to be withing range

• CAP/2.5V is ~2.49V
• AGND to DGND 0V
• VDD 4.95V from the arduino

My only thought is that I fried the chip when I soldered it to the breakout board, I have tried 2 already and am hesitant to put the 3rd on in as these bad boys are not cheap.

Are there any glaring issue that anyone can see? Ask for any other data if needed.

• I haven't read the datasheet but one immediate question, as you're using a function generator, does it matter that MCLK and SCK may not be synchronized? I'm assuming you've shared grounds with the funcgen too? – Roger Rowland Apr 6 '16 at 4:28
• The "SPI.transfer16(val16)" function might simplify the code, but it wouldn't change the output. – davidcary Apr 6 '16 at 15:48
• Make sure you use SPI Mode 2, data should be written on rising edge. – lucas92 Apr 6 '16 at 17:12
• @lucas92 as per the documentation page 20 it says it should be valid on the falling edge – Lpaulson Apr 6 '16 at 17:15
• I owe you an apology @lucas92, it should be on mode2. – Lpaulson May 18 '16 at 1:32

Summary

It appears to be working fine as-designed.

If you want us to further debug this problem, you need to explicitly say (1) what you expected to see, (2) what you actually saw, and (3) what appears to be the difference.

Some of the hardest problems for me to debug are when I'm convinced there is a problem with something, but it turns out that everything is actually working just fine -- I'm mis-interpreting what I see on my o'scope as a problem, when actually my o'scope is showing me that things are working fine.

Also: good job reducing your code to a relatively short SSCCE. That made it much easier to figure out what was going on. Thanks.

details

This image is exactly what I expect to see on the scope when the DAC in a DDS is programmed to generate a sine wave close to (but not exactly the same as) 1/5 the output sample rate.

It doesn't matter how many bits of resolution the DAC has, if you only have time to output 5 sample values per cycle of the sinewave, you're going to see 5 steps per cycle of the output waveform, as you see here.

This is perfectly normal and expected. All the so-called "sine-wave" DTMF generators I've used have very similar-looking outputs.

With some applications (such as the DTMF generators I've used), while such waveforms may look pretty ugly on the o'scope and not even recognizable as sine waves, they work perfectly fine in practice.

With many applications, a little bit of filtering rounds off the sharp stair-step edges so it looks like a sine wave on the o-scope. (A series RC filter circuit is often adequate).

A few applications are very sensitive to harmonic and non-harmonic distortion caused by this sort of stair-steps. With such applications, you must either (a) heavily filter the output to get rid of the sample-rate frequency and all its harmonics, or (b) increase the sample rate to get it out of the sensitive zone. In your case, you may be able to bump your master clock up to 12.5 MHz fairly easily, but above that requires more serious hardware modifications. (People who do RF often can't do (b) and so are forced to use option (a) and spend a lot of time carefully tuning complex RLC ladder filters and worrying about component value drift. People who do audio electronics often find option (b) a lot simpler. )

If I understand your code correctly, you're writing 0x30FF to the 14 MSB of the 28-bit FREQ0 register. While normally increasing the binary value in the FREQ register increases the output frequency, frequency aliasing / undersampling / Nyquist rate effects cause values over half the period (in this case, values over 0x2000 in the 14 MSB) to alias and appear to generate a lower frequency. (Such values are still useful when generating triangle waves ...) So I expect the same frequency as 0x4000 - 0x30FF = 0x0F01.

output_frequency = Phase * f_MCLK /( 2^28 )  # (from p. 12 of datasheet)


In this case, Phase is effectively (0x0F01<<14), giving an output frequency with only about (2^28 / (0x0F01<<14)) == 4.2 samples per output cycle. At f_MCLK == 1 MHz, I expect an output frequency of about 230 KHz, which is about what I see on your scope.

If you really need to generate a frequency of more than half of 1 MHz, you need to change your hardware.

EDIT:

By my calculations the FREQ register should have 0x30FFC0F = 51.379E6.

I wish this chip were designed such that that were true. But because this chip uses funky 14-bit register loads,

SPI.transfer(0x4C);     //write 0x0C0F to 14LSB
...
SPI.transfer(0x70);     //write 0x30FF to 14MSB


ends up putting (0x30FF)<<14 + 0x0C0F == (0x30FF)*2^14 + 0x0C0F == 0x0C3F_CC0F == 206e6 (decimal) into the FREQ0 register. Because this is more than half of 2^28, we see aliasing foldback, so the output frequency is the same as loading 0x1000_000 - 0x0C3F_CC0F = 0x03C033F1 into the FREQ0 register. Since 2^28 / 0x03C033F1 is about 4.3, you'll see 4 or 5 steps per complete "sine wave". And with 1 MHz step rate, that gives an output frequency of about 0x03C033F1 * 1 MHz / 2^28 which is about 230 kHz.

I think you want something more like

// FIXME: do this without float, only integers,
// without overflowing the 32-bit Arduino "long int" ?
void set_frequency( long int desired_frequency ){
const long int f_MCLK = 1e6; // change to 10e6 when we put the 10 MHz crystal in.
ASSERT( (desired_frequency * 2) < f_MCLK );
const int phase0command = 0x4000;
const float steps_per_Hz = (1.0 * ((long int)1)<<28) / f_MCLK;
// phase =  (desired_frequency * 2^28) / f_MCLK
unsigned long int steps_per_clk = desired_frequency * steps_per_Hz;
unsigned int high14 = steps_per_clk >> 14;
unsigned int low14 = steps_per_clk & (0x3FFF);
digitalWrite(fSync, LOW);
SPI.transfer16(phase0command | low14);
digitalWrite(fSync, HIGH);
delayMicroseconds(1);
digitalWrite(fSync, LOW);
SPI.transfer16(phase0command | high14);
digitalWrite(fSync, HIGH);
}

• Thanks for the explanation on the registers. There are definitely some issue that I need to figure out, I keep getting the stepped output even when I try to turn the device off. – Lpaulson Apr 7 '16 at 3:46