Programming DDS AD9833 signal generator

Hello,
Im trying to program a DDS AD9833 signal generator module like this one :

The signal I want is 400Hz, sine.
Fortunately there is application note AN-1070 from Analog Devices, that explains the programming bytes. That is :

MORE ON PROGRAMMING THE AD9833/AD9834
A simple example is the best method to explain how to program the AD9833/ AD9834. Refer to the AD9833 or the AD9834 data sheet for more details.
Basic Example
The aim is to generate a 400 Hz output frequency using the AD9833 with a 25 MHz MCLK.
The dial-up code for this is defined by the equation MCLKOUTffFreqReg282×=
Thus, for this example, Freq 0 = 400 Hz.
= 4295 decimal = 0x10C7 = 0001 0000 1100 0111
The required initialization sequence is shown in Table 1.
Table 1.
Hexadecimal Binary
0x2100 0010 0001 0000 0000
0x50C7 0101 0000 1100 0111
0x4000 0100 0000 0000 0000
0xC000 1100 0000 0000 0000
0x2000 0010 0000 0000 0000

So, I made up the following code

#include <SPI.h>
const int csPin = 10;
void setup() {

 SPI.begin();
 SPI.setBitOrder(MSBFIRST); 
 pinMode(csPin, OUTPUT);
 digitalWrite(csPin, HIGH);
 delay(10);

 byte a11 = 0x21;
 byte a12 = 0x00;
 byte a21 = 0x50;
 byte a22 = 0xC7;
 byte a31 = 0x40;
 byte a32 = 0x00;
 byte a41 = 0xC0;
 byte a42 = 0x00;
 byte a51 = 0x20;
 byte a52 = 0x00;



 word a1 = 0x2100;
 word a2 = 0x50C7;
 word a3 = 0x4000;
 word a4 = 0xC000;
 word a5 = 0x2000;
 /*
   sendit(a11, a12);
   sendit(a21, a22);
   sendit(a31, a32);
   sendit(a41, a42);
   sendit(a51, a52);
 */
 senditword(a1);
 senditword(a2);
 senditword(a3);
 senditword(a4);
 senditword(a5);
}

void loop() {
 // put your main code here, to run repeatedly:


}
void senditword(word b1) {
 // remember mode and cpha and pol
 digitalWrite(csPin, LOW); //select slave
 SPI.transfer(b1);
 delay(1);
 digitalWrite(csPin, HIGH); //de-select slave
 delay(1);

}

/*
 void sendit(byte byte1, byte byte2) {
 digitalWrite(csPin, LOW); //select slave
 SPI.transfer(byte1);
 SPI.transfer(byte2);
 digitalWrite(csPin, HIGH); //de-select slave
 delay(1);

}
*/

As you see, I tried in 2 ways :
1, send 10 bytes
2, send 5 words

But no way was succwesfull. In all cases the module seems to go erratically to a “random” frequency.
Any ideas?
thank you

Put this after SPI.begin()

SPI.setDataMode( SPI_MODE2 )

I've used this chip before, and it uses a different SPI mode than usual.

Thank you ny friend. I will try first thing tomorrow morning.

Also, SPI.transfer() does not support a 16-bit argument. You need to change it to transfer16() or transfer the high and low bytes separately.

demkat1:
Hello,
Im trying to program a DDS AD9833 signal generator module like this one :

http://www.ebay.com/itm/Programmable-Microprocessors-Sine-Square-Wave-AD9833-DDS-Signal-Generator-Module-/291989995195?hash=item43fbf5bebb:g:fAAAAOSw-0xYa1Ba

The signal I want is 400Hz, sine.
Fortunately there is application note AN-1070 from Analog Devices, that explains the programming bytes. That is :

MORE ON PROGRAMMING THE AD9833/AD9834
A simple example is the best method to explain how to program the AD9833/ AD9834. Refer to the AD9833 or the AD9834 data sheet for more details.
Basic Example
The aim is to generate a 400 Hz output frequency using the AD9833 with a 25 MHz MCLK.
The dial-up code for this is defined by the equation MCLKOUTffFreqReg282×=
Thus, for this example, Freq 0 = 400 Hz.
= 4295 decimal = 0x10C7 = 0001 0000 1100 0111
The required initialization sequence is shown in Table 1.
Table 1.
Hexadecimal Binary
0x2100 0010 0001 0000 0000
0x50C7 0101 0000 1100 0111
0x4000 0100 0000 0000 0000
0xC000 1100 0000 0000 0000
0x2000 0010 0000 0000 0000

So, I made up the following code

#include <SPI.h>

const int csPin = 10;
void setup() {

SPI.begin();
SPI.setBitOrder(MSBFIRST);
pinMode(csPin, OUTPUT);
digitalWrite(csPin, HIGH);
delay(10);

byte a11 = 0x21;
byte a12 = 0x00;
byte a21 = 0x50;
byte a22 = 0xC7;
byte a31 = 0x40;
byte a32 = 0x00;
byte a41 = 0xC0;
byte a42 = 0x00;
byte a51 = 0x20;
byte a52 = 0x00;

word a1 = 0x2100;
word a2 = 0x50C7;
word a3 = 0x4000;
word a4 = 0xC000;
word a5 = 0x2000;
/*
  sendit(a11, a12);
  sendit(a21, a22);
  sendit(a31, a32);
  sendit(a41, a42);
  sendit(a51, a52);
*/
senditword(a1);
senditword(a2);
senditword(a3);
senditword(a4);
senditword(a5);
}

void loop() {
// put your main code here, to run repeatedly:

}
void senditword(word b1) {
// remember mode and cpha and pol
digitalWrite(csPin, LOW); //select slave
SPI.transfer(b1);
delay(1);
digitalWrite(csPin, HIGH); //de-select slave
delay(1);

}

/*
void sendit(byte byte1, byte byte2) {
digitalWrite(csPin, LOW); //select slave
SPI.transfer(byte1);
SPI.transfer(byte2);
digitalWrite(csPin, HIGH); //de-select slave
delay(1);

}
*/




As you see, I tried in 2 ways :
1, send 10 bytes
2, send 5 words

But no way was succwesfull. In all cases the module seems to go erratically to a "random" frequency.
Any ideas?
thank you

I came on the same problem weeks ago and i found a working routine from web, i test it with a Nano board and a scope. works like a charm

/*
AD9833 Waveform Module vwlowen.co.uk
*/

#include <SPI.h>

const int SINE = 0x2000;                    // Define AD9833's waveform register value.
const int SQUARE = 0x2028;                  // When we update the frequency, we need to
const int TRIANGLE = 0x2002;                // define the waveform when we end writing.    

int wave = 0;
int waveType = SINE;
int wavePin = 7;

const float refFreq = 25000000.0;           // On-board crystal reference frequency

const int FSYNC = 10;                       // Standard SPI pins for the AD9833 waveform generator.
const int CLK = 13;                         // CLK and DATA pins are shared with the TFT display.
const int DATA = 11;

unsigned long freq = 640;               // Set initial frequency.

void setup() { 

  
   // Can't set SPI MODE here because the display and the AD9833 use different MODES.
  SPI.begin();
  
  AD9833reset();                                   // Reset AD9833 module after power-up.
  delay(50);
  AD9833setFrequency(freq, SQUARE);                  // Set the frequency and Sine Wave output
 }



void loop() {
  
}

// AD9833 documentation advises a 'Reset' on first applying power.
void AD9833reset() {
  WriteRegister(0x100);   // Write '1' to AD9833 Control register bit D8.
  delay(10);
}

// Set the frequency and waveform registers in the AD9833.
void AD9833setFrequency(long frequency, int Waveform) {

  long FreqWord = (frequency * pow(2, 28)) / refFreq;

  int MSB = (int)((FreqWord & 0xFFFC000) >> 14);    //Only lower 14 bits are used for data
  int LSB = (int)(FreqWord & 0x3FFF);
  
  //Set control bits 15 ande 14 to 0 and 1, respectively, for frequency register 0
  LSB |= 0x4000;
  MSB |= 0x4000; 
  
  WriteRegister(0x2100);   
  WriteRegister(LSB);                  // Write lower 16 bits to AD9833 registers
  WriteRegister(MSB);                  // Write upper 16 bits to AD9833 registers.
  WriteRegister(0xC000);               // Phase register
  WriteRegister(Waveform);             // Exit & Reset to SINE, SQUARE or TRIANGLE

}

void WriteRegister(int dat) { 
  
  // Display and AD9833 use different SPI MODES so it has to be set for the AD9833 here.
  SPI.setDataMode(SPI_MODE2);       
  
  digitalWrite(FSYNC, LOW);           // Set FSYNC low before writing to AD9833 registers
  delayMicroseconds(10);              // Give AD9833 time to get ready to receive data.
  
  SPI.transfer(highByte(dat));        // Each AD9833 register is 32 bits wide and each 16
  SPI.transfer(lowByte(dat));         // bits has to be transferred as 2 x 8-bit bytes.

  digitalWrite(FSYNC, HIGH);          //Write done. Set FSYNC high
}

ok,
It did work, so there is no problem (conserning programming) any more .
But, unfortunately I had in mind that chip's registers will keep programmed data and the module could be a "standalone" generator. I cant say how this "stick" into my mind, I dont see any eeprom or something similar.
So, a microcontroller (a nano or mini pro is fine) must be included in the project....

Thank you all.

In the next week i have in program to try controlling the DSS with an attiny45 using bit bang technique… hope to have success to have a small programmabile dss board

:slight_smile:

demkat1:
ok,
It did work, so there is no problem (conserning programming) any more .
But, unfortunately I had in mind that chip's registers will keep programmed data and the module could be a "standalone" generator. I cant say how this "stick" into my mind, I dont see any eeprom or something similar.
So, a microcontroller (a nano or mini pro is fine) must be included in the project....

Thank you all.

Chips with that feature are very likely to have it called out in the description on the first page of the datasheet. DACs and digipots are common types of ICs that might have nonvolatile EEPROM-backed registers.

Hi Everyone,

i am able to generate frequency in sine,square and triangle waveforms and also able to sweep frequency .But problem arised during sweeping frequency with step of 0.001 Hz.i am using freqreg0.

For Example:
Formula i used :
freq reg=(fout freq * 2^28)/25Mhz.

fout freq freq reg hex val
10.001 107.384919 6B
10.002 107.395657 6B
etc…

wave.MSB =(int)( 0x4000 | (int)((freq_reg & 0xFFFC000) >> 14)); //Only lower 14 bits are used for data
wave.LSB =(int)( 0x4000 | (int)(freq_reg & 0x3FFF));

GPIOB_OFF_BIT(12); //chip select bit is OFF
delay(5000);
AD9833_write((wave.LSB )); // Write lower 16 bits to AD9833 registers
AD9833_write((wave.MSB )); // Write upper 16 bits to AD9833 registers.
AD9833_write(0xC000); // Phase register
AD9833_write(wave.waveform); // Exit & Reset to SINE, SQUARE or TRIANGLE
delay(5000);
GPIOB_ON_BIT(12);

By seeing example hope it understand .Problem is while freq reg value is converting to hex its considering only integer part but fraction part is ignoring.
so in this case 0.001 hz step frequency is difficult.how do i send frequency with 0.001hz step fre

so, i need solution to overcome with issue.please help me its urgent.

Thank you.

MatrixGTI:
I came on the same problem weeks ago and i found a working routine from web, i test it with a Nano board and a scope. works like a charm

/*

AD9833 Waveform Module vwlowen.co.uk
*/

#include <SPI.h>

const int SINE = 0x2000;                    // Define AD9833’s waveform register value.
const int SQUARE = 0x2028;                  // When we update the frequency, we need to
const int TRIANGLE = 0x2002;                // define the waveform when we end writing.

int wave = 0;
int waveType = SINE;
int wavePin = 7;

const float refFreq = 25000000.0;          // On-board crystal reference frequency

const int FSYNC = 10;                      // Standard SPI pins for the AD9833 waveform generator.
const int CLK = 13;                        // CLK and DATA pins are shared with the TFT display.
const int DATA = 11;

unsigned long freq = 640;              // Set initial frequency.

void setup() {

// Can’t set SPI MODE here because the display and the AD9833 use different MODES.
  SPI.begin();
 
  AD9833reset();                                  // Reset AD9833 module after power-up.
  delay(50);
  AD9833setFrequency(freq, SQUARE);                  // Set the frequency and Sine Wave output
}

void loop() {
 
}

// AD9833 documentation advises a ‘Reset’ on first applying power.
void AD9833reset() {
  WriteRegister(0x100);  // Write ‘1’ to AD9833 Control register bit D8.
  delay(10);
}

// Set the frequency and waveform registers in the AD9833.
void AD9833setFrequency(long frequency, int Waveform) {

long FreqWord = (frequency * pow(2, 28)) / refFreq;

int MSB = (int)((FreqWord & 0xFFFC000) >> 14);    //Only lower 14 bits are used for data
  int LSB = (int)(FreqWord & 0x3FFF);
 
  //Set control bits 15 ande 14 to 0 and 1, respectively, for frequency register 0
  LSB |= 0x4000;
  MSB |= 0x4000;
 
  WriteRegister(0x2100); 
  WriteRegister(LSB);                  // Write lower 16 bits to AD9833 registers
  WriteRegister(MSB);                  // Write upper 16 bits to AD9833 registers.
  WriteRegister(0xC000);              // Phase register
  WriteRegister(Waveform);            // Exit & Reset to SINE, SQUARE or TRIANGLE

}

void WriteRegister(int dat) {
 
  // Display and AD9833 use different SPI MODES so it has to be set for the AD9833 here.
  SPI.setDataMode(SPI_MODE2);     
 
  digitalWrite(FSYNC, LOW);          // Set FSYNC low before writing to AD9833 registers
  delayMicroseconds(10);              // Give AD9833 time to get ready to receive data.
 
  SPI.transfer(highByte(dat));        // Each AD9833 register is 32 bits wide and each 16
  SPI.transfer(lowByte(dat));        // bits has to be transferred as 2 x 8-bit bytes.

digitalWrite(FSYNC, HIGH);          //Write done. Set FSYNC high
}

THANKS, I too found the code usefull. Am building a retro style waveform/signal genny and didn’t know where to start on coding for the dds module.
I manually edited and uploaded with various initial frequency values and wave type to test the module to ensure the module works.
Thank you very much.

demkat1:
Hello,
Im trying to program a DDS AD9833 signal generator module like this one :

Any ideas?
thank you

Try the attached library (see the README file). It’s a quick and dirty driver for the AD9833 that I made up. I didn’t do much with it because I switched to the AD9851 DDS which works better and is easier to program.

This library is quick and dirty… no guarantees other than “it works for me” and it’s not in n00b “click install in your IDE” format… you have to stick it into your libraries directory by hand.

It also doesn’t need SPI… it’s does SPI via bit-bang so you can use any Arduino pin for any DDS pin.

Hope this helps.

ad9833.zip (3.82 KB)

I am trying to control phase shift using AD9833 DDS , it seems phase is getting modified, but it is not working as expected.
please find the code snippet

#define BITS_PER_DEG 11.3777777777778 //-> 4096 / 360
#define PHASE_WRITE_CMD 0xC000
void AD9833_Phase(unsigned char fsync, uint32_t phaseInDeg)
{
phaseInDeg = fmod(phaseInDeg,360);
if ( phaseInDeg < 0 )
phaseInDeg += 360;

uint16_t phaseVal = (uint16_t)phaseInDeg & 0x0FFF;
phaseVal |= PHASE_WRITE_CMD;
digitalWrite(FSYNC, LOW); // Set FSYNC low
AD9833_Write(0xC000 | (0x1FFF & (uint16_t)(phaseVal)));
AD9833_Write(0xE000 | (0x1FFF & (uint16_t)(phaseVal>>12)));
digitalWrite(FSYNC, HIGH); // Set FSYNC high

}

So, a snippet, badly posted in a hijacked thread, without any details.
Neat.

from datasheet we know ad9833 and ad9834 have same register. (some bit is reserved in ad9833 but in ad9833/ad9834 same set to 0)
i run ad9833 with aruino library very well.
i know diffrent ossilator and maximum freq for any of them is differnt and in code has diffrent code

but when I use ad9833 library for program ad9834 by considering oscilltor freq , there is no wave or signal in output of ad9834.
i dont know what is the problem because of very similarity in two ic.
i need help