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

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