Browse over 10,000 Electronics Projects

Build Your Own Function Generator Using Analog Devices’ AD9833

Build Your Own Function Generator Using Analog Devices’ AD9833

Software

To write the code that will be uploaded into the microcontroller’s memory, we will be using the Arduino IDE. In the following few paragraphs I will explain how to write a library for the AD9833 and then the main piece of software that allows us to interface the microcontroller with the AD9833, the LCD, and the rotary encoder. The AD9833 has these so-called registers, which are basically memory locations, into which we can put data, and based on these values the integrated circuit changes its mode of operation; it chooses what waveform to output, the phase, and the division factor. We will be working with five registers: the control register; two phase registers, PHASE0 and PHASE1; and two frequency registers, FREQ0 and FREQ1.

 

AD9833 Library

We will create two files, AD9833.cpp, the file that will contain the source code, and AD9833.h, its header.

Inside the header, we specify the name of the class (AD9833) and, just like a Russian nesting doll, inside it, variables and functions that we will be calling to communicate with the waveform generator IC and to change its parameters, such as the frequency and the type of waveform. These can be one of two types: public, which we can call from outside the class methods (functions), or private, which we can call only when we are inside a class’s method. I have added comments so that you have an idea about the purpose of every function and variable; for example:

 

//Initialise the AD9833
//_FYNC is the pin on the uC where FYNC is connected
//_mclk is the frequency of the crystal generator 
AD9833(int _FSYNC, unsigned long _mclk);

 

Going on to the source file, when we initialize a new object of type AD9833 a few things are going to happen; this is inside the function “AD9833::AD9833(int _FSYNC, unsigned long _mclk)”. First, we take note of the FSYNC pin we have passed as an argument, and we set it as an output pin. When writing to the AD9833, this pin will go LOW. Inside this method, we also set some default values for the registers so that we output a sinusoidal signal at 1kHz using the FREQ0 register. The last lines set the SPI to mode2, which is the setting that the microcontroller and AD9833 use to communicate.

All that is remaining now is to carefully read the datasheet and see what values we have to set in the AD9833’s registers to manipulate the output waveform and its operation. Thus, we will write functions for the following operations: write data, set frequency, set phase, sleep, reset, mode, and choose frequency/phase register.

We will be working directly at the bit level. Sometimes we may want to change the value of an entire register, for example for the frequency register, but sometimes we want to only change a few bits of the whole word. To achieve this, we will use the following operations:

  • “&=” To set some bits to 0 while leaving the rest undisturbed. (0 = set to 0, 1 = leave it how it is). Example:

 

controlRegister &= 0xF3FF; // Set D11 and D10 in control register to 0

 

  • “|=” To set some bits to 1 while leaving the rest undisturbed. (1 = set to 1, 0 = leave it how it is). Example:

 

controlRegister |= 0x0C00; // Set D11 and D10 in control register to 1

 

In the table below I have extracted from the datasheet which bits need to be set to execute the operations.



Advertisement1


 

Operation Register Value
Set Frequency FREQ0 FREEQ0: D15 = 0, D14 = 1
Set Frequency FREQ1 FREEQ1: D15 = 1, D14 = 0
Set Phase PHASE0 PHASE0: D15 = 1, D14 = 1, D13 = 0
Set Phase PHASE1 PHASE0: D15 = 1, D14 = 1, D13 = 1
Set Mode – Sine CNTRL D5 = 0, D1 = 0
Set Mode – Triangular CNTRL D5 = 0, D1 = 1
Set Mode – Clock CNTRL D5 = 1, D1 = 0
Set Frequency Register CNTRL D11 = 0 (choose FREQ0); D11 = 1 (choose FREQ1);
Reset CNTRL D8 = 0 or 1
Sleep – No power-down CNTRL D7 = 0, D6 = 0
Sleep – DAC powered down CNTRL D7 = 0, D6 = 1
Sleep – Internal clock disabled CNTRL D7 = 1, D6 = 0
Sleep – DAC powered down and internal clock disabled CNTRL D7 = 1, D6 = 1

 

The registers have different sizes. The control register is 16 bits long, the phase registers are 12 bits long, and the frequency registers have 28 bits. To output data via SPI, we send one byte at a time, as can be seen in the “writeData” function, starting with the low byte (first 8 bits from the data integer) and then the high byte.

Setting the frequency is a bit more tricky because we are not directly sending the frequency that we want. According to the datasheet, the analog output is fMCLK/228 × FREQREG. Thus, the frequency register must be set to:

FREQREG=frequency228fmclkFREQREG=frequency⋅228fmclk

 

Because the obtained number can be as long as 28 bits, we divide it into two words, each 16 bits long, and then we send the data starting with the lower one.

The rest of the methods should be straightforward if you follow the table above and my indications in the comments.

Pages: 1 2 3 4 5 6 7 8

 


Top