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(); } */