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@0:1ed24aaf786d, 2012-04-04 (annotated)
- Committer:
- loopsva
- Date:
- Wed Apr 04 18:14:54 2012 +0000
- Revision:
- 0:1ed24aaf786d
050511
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
loopsva | 0:1ed24aaf786d | 1 | #include "mbed.h" |
loopsva | 0:1ed24aaf786d | 2 | #include "AD9851.h" |
loopsva | 0:1ed24aaf786d | 3 | |
loopsva | 0:1ed24aaf786d | 4 | extern int gDebug; // defined in main.cpp, used for printing verbose-ness level (0-3) |
loopsva | 0:1ed24aaf786d | 5 | //extern double StepFreq; // step frequency (used for gDebug lines only) |
loopsva | 0:1ed24aaf786d | 6 | |
loopsva | 0:1ed24aaf786d | 7 | // power up default values |
loopsva | 0:1ed24aaf786d | 8 | double BaseFreq = 10000000.000; // base frequency - if frequency |
loopsva | 0:1ed24aaf786d | 9 | double IfFreq = 455000.0; // IF frequency |
loopsva | 0:1ed24aaf786d | 10 | double RealFreq = BaseFreq + IfFreq; // sum of the two frequencies |
loopsva | 0:1ed24aaf786d | 11 | double RefOsc = 30000000.000; // reference oscillator frequency |
loopsva | 0:1ed24aaf786d | 12 | char MultSix = 'A'; // x1 or x6 frequency oscillator - 0, 1 or A only |
loopsva | 0:1ed24aaf786d | 13 | bool ErrorFlag = false; // error flag |
loopsva | 0:1ed24aaf786d | 14 | bool FirstEnable = false; // used for DDS-60 bug fix |
loopsva | 0:1ed24aaf786d | 15 | |
loopsva | 0:1ed24aaf786d | 16 | double OldBaseFreq = BaseFreq; // old base frequency - if frequency |
loopsva | 0:1ed24aaf786d | 17 | double OldIfFreq = IfFreq; // old IF frequency |
loopsva | 0:1ed24aaf786d | 18 | char OldMultSix = MultSix; // old x1 or x6 frequency oscillator - 0, 1 or A only |
loopsva | 0:1ed24aaf786d | 19 | |
loopsva | 0:1ed24aaf786d | 20 | double SerCount = 1431655765.0; // calculated final value of data to AD9851 |
loopsva | 0:1ed24aaf786d | 21 | unsigned int FreqDiv = 0x55555555; // calculated value of SerCount to be divided into SerData[0-4] |
loopsva | 0:1ed24aaf786d | 22 | |
loopsva | 0:1ed24aaf786d | 23 | const char LsbPhase = 0x08; // LSB of phase setting, 0-31 (0-0x1f), 11.25 degrees per step |
loopsva | 0:1ed24aaf786d | 24 | const char PwrDnFlag = 0x04; // + power down flag |
loopsva | 0:1ed24aaf786d | 25 | const char Mult6Flag = 0x01; // + 180MHz - 30MHz multiplier x6 flag |
loopsva | 0:1ed24aaf786d | 26 | char FortyBitWd = PwrDnFlag + (LsbPhase * 1); // calculated 5th byte fo 40 bit word to be divided into SerData[0-4] |
loopsva | 0:1ed24aaf786d | 27 | |
loopsva | 0:1ed24aaf786d | 28 | // constructor takes paramters and initializes I2C bus |
loopsva | 0:1ed24aaf786d | 29 | AD9851::AD9851(PinName CLK, PinName SDO, PinName LEN) |
loopsva | 0:1ed24aaf786d | 30 | : _clk(CLK) |
loopsva | 0:1ed24aaf786d | 31 | , _sdo(SDO) |
loopsva | 0:1ed24aaf786d | 32 | , _len(LEN) |
loopsva | 0:1ed24aaf786d | 33 | { |
loopsva | 0:1ed24aaf786d | 34 | _clk = 0; |
loopsva | 0:1ed24aaf786d | 35 | _sdo = 0; |
loopsva | 0:1ed24aaf786d | 36 | _len = 0; |
loopsva | 0:1ed24aaf786d | 37 | OutNewValue(); // initialize the AD9851 |
loopsva | 0:1ed24aaf786d | 38 | } |
loopsva | 0:1ed24aaf786d | 39 | |
loopsva | 0:1ed24aaf786d | 40 | // destructor |
loopsva | 0:1ed24aaf786d | 41 | AD9851::~AD9851() { |
loopsva | 0:1ed24aaf786d | 42 | } |
loopsva | 0:1ed24aaf786d | 43 | |
loopsva | 0:1ed24aaf786d | 44 | // return base frequency value |
loopsva | 0:1ed24aaf786d | 45 | double AD9851::GetBaseValue() { |
loopsva | 0:1ed24aaf786d | 46 | return BaseFreq; |
loopsva | 0:1ed24aaf786d | 47 | } |
loopsva | 0:1ed24aaf786d | 48 | |
loopsva | 0:1ed24aaf786d | 49 | // return IF frequency value |
loopsva | 0:1ed24aaf786d | 50 | double AD9851::GetIfValue() { |
loopsva | 0:1ed24aaf786d | 51 | return IfFreq; |
loopsva | 0:1ed24aaf786d | 52 | } |
loopsva | 0:1ed24aaf786d | 53 | |
loopsva | 0:1ed24aaf786d | 54 | // return 32 serial word value |
loopsva | 0:1ed24aaf786d | 55 | unsigned int AD9851::GetFD32Value() { |
loopsva | 0:1ed24aaf786d | 56 | return FreqDiv; |
loopsva | 0:1ed24aaf786d | 57 | } |
loopsva | 0:1ed24aaf786d | 58 | |
loopsva | 0:1ed24aaf786d | 59 | // return 5th "control" byte for 40 bit serial word value |
loopsva | 0:1ed24aaf786d | 60 | char AD9851::GetFortyValue() { |
loopsva | 0:1ed24aaf786d | 61 | return FortyBitWd; |
loopsva | 0:1ed24aaf786d | 62 | } |
loopsva | 0:1ed24aaf786d | 63 | |
loopsva | 0:1ed24aaf786d | 64 | // return error flag |
loopsva | 0:1ed24aaf786d | 65 | bool AD9851::GetErrFlagValue() { |
loopsva | 0:1ed24aaf786d | 66 | return ErrorFlag; |
loopsva | 0:1ed24aaf786d | 67 | } |
loopsva | 0:1ed24aaf786d | 68 | |
loopsva | 0:1ed24aaf786d | 69 | //--------------------------------------------------------------- |
loopsva | 0:1ed24aaf786d | 70 | // set base frequency value |
loopsva | 0:1ed24aaf786d | 71 | double AD9851::SetBaseValue(double bv) { |
loopsva | 0:1ed24aaf786d | 72 | if(bv >= 0.0) { |
loopsva | 0:1ed24aaf786d | 73 | BaseFreq = bv; |
loopsva | 0:1ed24aaf786d | 74 | } else { |
loopsva | 0:1ed24aaf786d | 75 | printf("Base neg number!!!\n"); |
loopsva | 0:1ed24aaf786d | 76 | } |
loopsva | 0:1ed24aaf786d | 77 | return(bv); |
loopsva | 0:1ed24aaf786d | 78 | } |
loopsva | 0:1ed24aaf786d | 79 | |
loopsva | 0:1ed24aaf786d | 80 | // set IF frequency value |
loopsva | 0:1ed24aaf786d | 81 | double AD9851::SetIfValue(double bv) { |
loopsva | 0:1ed24aaf786d | 82 | if(bv >= 0.0) { |
loopsva | 0:1ed24aaf786d | 83 | IfFreq = bv; |
loopsva | 0:1ed24aaf786d | 84 | } else { |
loopsva | 0:1ed24aaf786d | 85 | printf("IF neg number!!!\n"); |
loopsva | 0:1ed24aaf786d | 86 | } |
loopsva | 0:1ed24aaf786d | 87 | return(bv); |
loopsva | 0:1ed24aaf786d | 88 | } |
loopsva | 0:1ed24aaf786d | 89 | |
loopsva | 0:1ed24aaf786d | 90 | // set base frequency value, ascii 0 1 or A |
loopsva | 0:1ed24aaf786d | 91 | char AD9851::SetM6Value(char bx) { |
loopsva | 0:1ed24aaf786d | 92 | MultSix = bx; |
loopsva | 0:1ed24aaf786d | 93 | return(bx); |
loopsva | 0:1ed24aaf786d | 94 | } |
loopsva | 0:1ed24aaf786d | 95 | |
loopsva | 0:1ed24aaf786d | 96 | //--------------------------------------------------------------- |
loopsva | 0:1ed24aaf786d | 97 | // turn on AD9851 |
loopsva | 0:1ed24aaf786d | 98 | void AD9851::AD9851Enable() { |
loopsva | 0:1ed24aaf786d | 99 | FortyBitWd = FortyBitWd & (-1-(PwrDnFlag)); |
loopsva | 0:1ed24aaf786d | 100 | FirstAccess(); |
loopsva | 0:1ed24aaf786d | 101 | // OutNewValue(); |
loopsva | 0:1ed24aaf786d | 102 | } |
loopsva | 0:1ed24aaf786d | 103 | |
loopsva | 0:1ed24aaf786d | 104 | // turn off AD9851 |
loopsva | 0:1ed24aaf786d | 105 | void AD9851::AD9851Disable() { |
loopsva | 0:1ed24aaf786d | 106 | FirstEnable = false; |
loopsva | 0:1ed24aaf786d | 107 | FortyBitWd = FortyBitWd | PwrDnFlag; |
loopsva | 0:1ed24aaf786d | 108 | OutNewValue(); |
loopsva | 0:1ed24aaf786d | 109 | } |
loopsva | 0:1ed24aaf786d | 110 | |
loopsva | 0:1ed24aaf786d | 111 | // calculate new value based on change. If an over frequency condition exists, then resort back to original values |
loopsva | 0:1ed24aaf786d | 112 | bool AD9851::CalcNewValue() { |
loopsva | 0:1ed24aaf786d | 113 | RealFreq = BaseFreq + IfFreq; |
loopsva | 0:1ed24aaf786d | 114 | ErrorFlag = false; |
loopsva | 0:1ed24aaf786d | 115 | if(RealFreq >= 0.0) { // error if RealFreq is negative number |
loopsva | 0:1ed24aaf786d | 116 | if(((RealFreq >= RefOsc) && (MultSix == '0')) || (((RealFreq >= (RefOsc * 6.0)) && ((MultSix == '1') || (MultSix == 'A') || (MultSix == 'a'))))) { |
loopsva | 0:1ed24aaf786d | 117 | //error if >30MHz and multiplier = 0 |
loopsva | 0:1ed24aaf786d | 118 | //error if >180MHz and multiplier = 1 or A |
loopsva | 0:1ed24aaf786d | 119 | ErrorFlag = true; |
loopsva | 0:1ed24aaf786d | 120 | BaseFreq = OldBaseFreq; |
loopsva | 0:1ed24aaf786d | 121 | IfFreq = OldIfFreq; |
loopsva | 0:1ed24aaf786d | 122 | RealFreq = BaseFreq + IfFreq; |
loopsva | 0:1ed24aaf786d | 123 | MultSix = OldMultSix; |
loopsva | 0:1ed24aaf786d | 124 | } else { |
loopsva | 0:1ed24aaf786d | 125 | OldBaseFreq = BaseFreq; |
loopsva | 0:1ed24aaf786d | 126 | OldIfFreq = IfFreq; |
loopsva | 0:1ed24aaf786d | 127 | RealFreq = BaseFreq + IfFreq; |
loopsva | 0:1ed24aaf786d | 128 | OldMultSix = MultSix; |
loopsva | 0:1ed24aaf786d | 129 | if((MultSix == '0') || ((MultSix == 'A') && (RealFreq < RefOsc))) { //less than 30MHz |
loopsva | 0:1ed24aaf786d | 130 | SerCount = 1.0 / (RefOsc / 4294967296.0 / RealFreq); // 4294967296 = 2^32 |
loopsva | 0:1ed24aaf786d | 131 | FortyBitWd = FortyBitWd & (-1-(Mult6Flag)); |
loopsva | 0:1ed24aaf786d | 132 | // 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); |
loopsva | 0:1ed24aaf786d | 133 | } else { //less than 180MHz |
loopsva | 0:1ed24aaf786d | 134 | SerCount = 1.0 / ((RefOsc * 6.0) / 4294967296.0 / RealFreq); |
loopsva | 0:1ed24aaf786d | 135 | FortyBitWd = FortyBitWd | Mult6Flag; |
loopsva | 0:1ed24aaf786d | 136 | // if(gDebug > 1) printf("2- m6: %c rF: %f sF: %f 40bw: 0x%02x sc: %f\n", MultSix, RealFreq, StepFreq, FortyBitWd, SerCount); |
loopsva | 0:1ed24aaf786d | 137 | } |
loopsva | 0:1ed24aaf786d | 138 | FreqDiv = (unsigned int)SerCount; |
loopsva | 0:1ed24aaf786d | 139 | if(gDebug > 1) printf("3- out: 0x%02x%08x\n", FortyBitWd, FreqDiv); |
loopsva | 0:1ed24aaf786d | 140 | OutNewValue(); |
loopsva | 0:1ed24aaf786d | 141 | } |
loopsva | 0:1ed24aaf786d | 142 | } else { |
loopsva | 0:1ed24aaf786d | 143 | printf("calc neg number!!!\n"); |
loopsva | 0:1ed24aaf786d | 144 | ErrorFlag = true; |
loopsva | 0:1ed24aaf786d | 145 | } |
loopsva | 0:1ed24aaf786d | 146 | if(gDebug) printf("\nBase: %.3f IF: %.3f Freq: %.3f Mult: %c Out: 0x%02x%08x\n", BaseFreq, IfFreq, RealFreq, MultSix, FortyBitWd, FreqDiv); |
loopsva | 0:1ed24aaf786d | 147 | return (ErrorFlag); |
loopsva | 0:1ed24aaf786d | 148 | } |
loopsva | 0:1ed24aaf786d | 149 | |
loopsva | 0:1ed24aaf786d | 150 | /* Private routines: */ |
loopsva | 0:1ed24aaf786d | 151 | // set new value to AD9851 |
loopsva | 0:1ed24aaf786d | 152 | void AD9851::OutNewValue() { |
loopsva | 0:1ed24aaf786d | 153 | unsigned int ShiftOut = FreqDiv; |
loopsva | 0:1ed24aaf786d | 154 | unsigned int TestOut = FreqDiv; |
loopsva | 0:1ed24aaf786d | 155 | char i = 0; |
loopsva | 0:1ed24aaf786d | 156 | for(i=0; i<32; i++) { |
loopsva | 0:1ed24aaf786d | 157 | TestOut = ShiftOut & 1; |
loopsva | 0:1ed24aaf786d | 158 | if(TestOut==1) { |
loopsva | 0:1ed24aaf786d | 159 | _sdo = 1; |
loopsva | 0:1ed24aaf786d | 160 | } else { |
loopsva | 0:1ed24aaf786d | 161 | _sdo = 0; |
loopsva | 0:1ed24aaf786d | 162 | } |
loopsva | 0:1ed24aaf786d | 163 | _clk = 1; |
loopsva | 0:1ed24aaf786d | 164 | ShiftOut = ShiftOut >> 1; |
loopsva | 0:1ed24aaf786d | 165 | _clk = 0; |
loopsva | 0:1ed24aaf786d | 166 | } |
loopsva | 0:1ed24aaf786d | 167 | ShiftOut = FortyBitWd; |
loopsva | 0:1ed24aaf786d | 168 | for(i=0; i<8; i++) { |
loopsva | 0:1ed24aaf786d | 169 | TestOut = ShiftOut & 1; |
loopsva | 0:1ed24aaf786d | 170 | if(TestOut==1) { |
loopsva | 0:1ed24aaf786d | 171 | _sdo = 1; |
loopsva | 0:1ed24aaf786d | 172 | } else { |
loopsva | 0:1ed24aaf786d | 173 | _sdo = 0; |
loopsva | 0:1ed24aaf786d | 174 | } |
loopsva | 0:1ed24aaf786d | 175 | _clk = 1; |
loopsva | 0:1ed24aaf786d | 176 | ShiftOut = ShiftOut >> 1; |
loopsva | 0:1ed24aaf786d | 177 | _clk = 0; |
loopsva | 0:1ed24aaf786d | 178 | } |
loopsva | 0:1ed24aaf786d | 179 | _len = 1; |
loopsva | 0:1ed24aaf786d | 180 | _len = 0; |
loopsva | 0:1ed24aaf786d | 181 | } |
loopsva | 0:1ed24aaf786d | 182 | |
loopsva | 0:1ed24aaf786d | 183 | // BUG FIX, on the very first access after an enable, first force 100KHz w/Mult6 = 0, set Mult6 = 1 forever |
loopsva | 0:1ed24aaf786d | 184 | void AD9851::FirstAccess() { |
loopsva | 0:1ed24aaf786d | 185 | if(FirstEnable == false) { |
loopsva | 0:1ed24aaf786d | 186 | FirstEnable = true; |
loopsva | 0:1ed24aaf786d | 187 | unsigned int TempDiv = FreqDiv; |
loopsva | 0:1ed24aaf786d | 188 | FreqDiv =0x00da740d; |
loopsva | 0:1ed24aaf786d | 189 | char Temp40 = FortyBitWd; |
loopsva | 0:1ed24aaf786d | 190 | FortyBitWd = 0x0c; |
loopsva | 0:1ed24aaf786d | 191 | OutNewValue(); |
loopsva | 0:1ed24aaf786d | 192 | wait_ms(5); |
loopsva | 0:1ed24aaf786d | 193 | FortyBitWd = Temp40; |
loopsva | 0:1ed24aaf786d | 194 | FreqDiv = TempDiv; |
loopsva | 0:1ed24aaf786d | 195 | SetM6Value(1); |
loopsva | 0:1ed24aaf786d | 196 | } |
loopsva | 0:1ed24aaf786d | 197 | CalcNewValue(); |
loopsva | 0:1ed24aaf786d | 198 | } |
loopsva | 0:1ed24aaf786d | 199 | /* |
loopsva | 0:1ed24aaf786d | 200 | void AD9851::FirstAccess() { |
loopsva | 0:1ed24aaf786d | 201 | if(FirstEnable == false) { |
loopsva | 0:1ed24aaf786d | 202 | FirstEnable = true; |
loopsva | 0:1ed24aaf786d | 203 | unsigned int TempDiv = FreqDiv; |
loopsva | 0:1ed24aaf786d | 204 | FreqDiv =0; |
loopsva | 0:1ed24aaf786d | 205 | char Temp40 = FortyBitWd; |
loopsva | 0:1ed24aaf786d | 206 | FortyBitWd = 0x01; |
loopsva | 0:1ed24aaf786d | 207 | OutNewValue(); |
loopsva | 0:1ed24aaf786d | 208 | wait_ms(5); |
loopsva | 0:1ed24aaf786d | 209 | OutNewValue(); |
loopsva | 0:1ed24aaf786d | 210 | wait_ms(5); |
loopsva | 0:1ed24aaf786d | 211 | FortyBitWd = Temp40; |
loopsva | 0:1ed24aaf786d | 212 | FreqDiv = TempDiv; |
loopsva | 0:1ed24aaf786d | 213 | SetM6Value(1); |
loopsva | 0:1ed24aaf786d | 214 | } |
loopsva | 0:1ed24aaf786d | 215 | CalcNewValue(); |
loopsva | 0:1ed24aaf786d | 216 | } |
loopsva | 0:1ed24aaf786d | 217 | */ |