Programming of the DDS-60 (AD9851) frequency synthesizer from AmQRP http://midnightdesignsolutions.com/dds60/index.html I had to use long, floating math in order to get accurate frequency output.

Dependencies:   TextLCD mbed ChaNFS

AD9851/AD9851.cpp

Committer:
loopsva
Date:
2012-04-04
Revision:
0:1ed24aaf786d

File content as of revision 0:1ed24aaf786d:

#include "mbed.h"
#include "AD9851.h"

extern int gDebug;                      // defined in main.cpp, used for printing verbose-ness level (0-3)
//extern double StepFreq;                 // step frequency (used for gDebug lines only)

// power up default values
double BaseFreq = 10000000.000;         // base frequency - if frequency
double IfFreq = 455000.0;               // IF frequency
double RealFreq = BaseFreq + IfFreq;    // sum of the two frequencies
double RefOsc = 30000000.000;           // reference oscillator frequency
char MultSix = 'A';                     // x1 or x6 frequency oscillator - 0, 1 or A only
bool ErrorFlag = false;                 // error flag
bool FirstEnable = false;               // used for DDS-60 bug fix

double OldBaseFreq = BaseFreq;          // old base frequency - if frequency
double OldIfFreq = IfFreq;              // old IF frequency
char OldMultSix = MultSix;              // old x1 or x6 frequency oscillator - 0, 1 or A only

double SerCount = 1431655765.0;         // calculated final value of data to AD9851
unsigned int FreqDiv = 0x55555555;      // calculated value of SerCount to be divided into SerData[0-4]

const char LsbPhase = 0x08;             // LSB of phase setting, 0-31 (0-0x1f), 11.25 degrees per step
const char PwrDnFlag = 0x04;            // + power down flag
const char Mult6Flag = 0x01;            // + 180MHz - 30MHz multiplier x6 flag
char FortyBitWd = PwrDnFlag + (LsbPhase * 1); // calculated 5th byte fo 40 bit word to be divided into SerData[0-4]
    
// constructor takes paramters and initializes I2C bus
AD9851::AD9851(PinName CLK, PinName SDO, PinName LEN)
      : _clk(CLK)
      , _sdo(SDO)
      , _len(LEN) 
    {
    _clk = 0;
    _sdo = 0;
    _len = 0;
    OutNewValue();                      // initialize the AD9851
}

// destructor
AD9851::~AD9851() {
}

// return base frequency value
double AD9851::GetBaseValue() {
    return BaseFreq;
}

// return IF frequency value
double AD9851::GetIfValue() {
    return IfFreq;
}

// return 32 serial word value
unsigned int AD9851::GetFD32Value() {
    return FreqDiv;
}

// return 5th "control" byte for 40 bit serial word value
char AD9851::GetFortyValue() {
    return FortyBitWd;
}

// return error flag
bool AD9851::GetErrFlagValue() {
    return ErrorFlag;
}

//---------------------------------------------------------------
// set base frequency value
double AD9851::SetBaseValue(double bv) {
    if(bv >= 0.0) {
        BaseFreq = bv;
    } else {
        printf("Base neg number!!!\n");
    }
    return(bv);
}

// set IF frequency value
double AD9851::SetIfValue(double bv) {
    if(bv >= 0.0) {
        IfFreq = bv;
    } else {
        printf("IF neg number!!!\n");
    }
    return(bv);
}
    
// set base frequency value, ascii 0 1 or A
char AD9851::SetM6Value(char bx) {
    MultSix = bx;
    return(bx);
}
    
//---------------------------------------------------------------
// turn on AD9851
void AD9851::AD9851Enable() {
    FortyBitWd = FortyBitWd & (-1-(PwrDnFlag));
    FirstAccess();
//    OutNewValue();
}

// turn off AD9851
void AD9851::AD9851Disable() {
    FirstEnable = false;
    FortyBitWd = FortyBitWd | PwrDnFlag;
    OutNewValue();
}

// calculate new value based on change.  If an over frequency condition exists, then resort back to original values
bool AD9851::CalcNewValue() {
    RealFreq = BaseFreq + IfFreq;
    ErrorFlag = false;
    if(RealFreq >= 0.0) {    // error if RealFreq is negative number
        if(((RealFreq >= RefOsc) && (MultSix == '0')) || (((RealFreq >= (RefOsc * 6.0)) && ((MultSix == '1') || (MultSix == 'A') || (MultSix == 'a'))))) { 
            //error if >30MHz and multiplier = 0     
            //error if >180MHz and multiplier = 1 or A
            ErrorFlag = true;
            BaseFreq = OldBaseFreq;
            IfFreq = OldIfFreq;
            RealFreq = BaseFreq + IfFreq;
            MultSix = OldMultSix;
        } else {
            OldBaseFreq = BaseFreq;
            OldIfFreq = IfFreq;
            RealFreq = BaseFreq + IfFreq;
            OldMultSix = MultSix;
            if((MultSix == '0') || ((MultSix == 'A') && (RealFreq < RefOsc))) { //less than 30MHz
                SerCount = 1.0 / (RefOsc / 4294967296.0 / RealFreq);            // 4294967296 = 2^32
                FortyBitWd = FortyBitWd & (-1-(Mult6Flag));
//                if(gDebug > 1) printf("1- m6: %c  rF: %f  sF: %f  40bw: 0x%02x  sc: %f\n  ref: %f", MultSix, RealFreq, StepFreq, FortyBitWd, SerCount, RefOsc);
            } else {                                                            //less than 180MHz
                SerCount = 1.0 / ((RefOsc * 6.0) / 4294967296.0 / RealFreq);
                FortyBitWd = FortyBitWd | Mult6Flag;
//                if(gDebug > 1) printf("2- m6: %c  rF: %f  sF: %f  40bw: 0x%02x  sc: %f\n", MultSix, RealFreq, StepFreq, FortyBitWd, SerCount);
            }
            FreqDiv = (unsigned int)SerCount; 
            if(gDebug > 1) printf("3- out: 0x%02x%08x\n", FortyBitWd, FreqDiv);
            OutNewValue(); 
        }
    } else {
        printf("calc neg number!!!\n");
        ErrorFlag = true;
    }
    if(gDebug) printf("\nBase: %.3f  IF: %.3f  Freq: %.3f  Mult: %c  Out: 0x%02x%08x\n", BaseFreq, IfFreq, RealFreq, MultSix, FortyBitWd, FreqDiv); 
    return (ErrorFlag);
}

/* Private routines: */
// set new value to AD9851
void AD9851::OutNewValue() {
    unsigned int ShiftOut = FreqDiv;
    unsigned int TestOut = FreqDiv;
    char i = 0;
    for(i=0; i<32; i++) {
        TestOut = ShiftOut & 1;
        if(TestOut==1) {
            _sdo = 1;
        } else {
            _sdo = 0;
        }
        _clk = 1;
        ShiftOut = ShiftOut >> 1;
        _clk = 0;
    }
    ShiftOut = FortyBitWd;
    for(i=0; i<8; i++) {
        TestOut = ShiftOut & 1;
        if(TestOut==1) {
            _sdo = 1;
        } else {
            _sdo = 0;
        }
        _clk = 1;
        ShiftOut = ShiftOut >> 1;
        _clk = 0;
    }
    _len = 1;
    _len = 0;
}

// BUG FIX, on the very first access after an enable, first force 100KHz w/Mult6 = 0, set Mult6 = 1 forever
void AD9851::FirstAccess() {
    if(FirstEnable == false) {
        FirstEnable = true;
        unsigned int TempDiv = FreqDiv;
        FreqDiv =0x00da740d;
        char Temp40 = FortyBitWd;
        FortyBitWd = 0x0c;
        OutNewValue();
        wait_ms(5);
        FortyBitWd = Temp40;
        FreqDiv = TempDiv;
        SetM6Value(1);
    }
    CalcNewValue();
}
/*
void AD9851::FirstAccess() {
    if(FirstEnable == false) {
        FirstEnable = true;
        unsigned int TempDiv = FreqDiv;
        FreqDiv =0;
        char Temp40 = FortyBitWd;
        FortyBitWd = 0x01;
        OutNewValue();
        wait_ms(5);
        OutNewValue();
        wait_ms(5);
        FortyBitWd = Temp40;
        FreqDiv = TempDiv;
        SetM6Value(1);
    }
    CalcNewValue();
}
*/