Go Down

Topic: Programming DDS AD9833 signal generator (Read 2068 times) previous topic - next topic

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



Code: [Select]
#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

Jiggy-Ninja

Put this after SPI.begin()
Code: [Select]
SPI.setDataMode( SPI_MODE2 )
I've used this chip before, and it uses a different SPI mode than usual.
Hackaday: https://hackaday.io/MarkRD
Advanced C++ Techniques: https://forum.arduino.cc/index.php?topic=493075.0

demkat1

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

Jiggy-Ninja

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.
Hackaday: https://hackaday.io/MarkRD
Advanced C++ Techniques: https://forum.arduino.cc/index.php?topic=493075.0

MatrixGTI

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



Code: [Select]
#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

Code: [Select]
/*
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
}

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.

MatrixGTI

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


Jiggy-Ninja

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.
Hackaday: https://hackaday.io/MarkRD
Advanced C++ Techniques: https://forum.arduino.cc/index.php?topic=493075.0

sulochana

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.

krazydarcy

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

Code: [Select]
/*
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.

krupski

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.


Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Go Up