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
Diff: AD9851/AD9851.cpp
- Revision:
- 0:1ed24aaf786d
diff -r 000000000000 -r 1ed24aaf786d AD9851/AD9851.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AD9851/AD9851.cpp Wed Apr 04 18:14:54 2012 +0000 @@ -0,0 +1,217 @@ +#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(); +} +*/ \ No newline at end of file