├── .gitignore ├── ADF4350.cpp ├── ADF4350.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | desktop.ini 3 | *.swp 4 | -------------------------------------------------------------------------------- /ADF4350.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ADF4350.cpp - ADF4350 PLL Communication Library 3 | Created by Neal Pisenti, 2013. 4 | JQI - Strontium - UMD 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | aunsigned long with this program. If not, see . 18 | 19 | 20 | */ 21 | 22 | #include "Arduino.h" 23 | #include "SPI.h" 24 | #include 25 | 26 | 27 | 28 | // NOTE: Currently, set up for channel spacing of 10Mhz; might ammend later if needed, 29 | // but this was easy and takes care of forseeable applications... 30 | // This means we'll be operating in int-N mode. 31 | // 32 | // Currently, keep frequency between 140Mhz and 3Ghz. 33 | 34 | /* CONSTRUCTOR */ 35 | 36 | // Constructor function; initializes communication pinouts 37 | 38 | ADF4350::ADF4350(byte ssPin) { 39 | _ssPin = ssPin; 40 | pinMode(_ssPin, OUTPUT); 41 | digitalWrite(_ssPin, HIGH); 42 | } 43 | 44 | 45 | 46 | 47 | 48 | // Initializes a new ADF4350 object, with refClk (in Mhz), and initial frequency. 49 | void ADF4350::initialize(int freq, int refClk = 10){ 50 | _refClk = refClk; 51 | _phase = 1; 52 | 53 | _feedbackType = 0; 54 | _powerdown = 0; 55 | _auxEnabled = 0; 56 | _rfEnabled = 1; 57 | 58 | // default power = 5dbm 59 | _auxPower = 3; 60 | _rfPower = 3; 61 | 62 | // sets register values which don't have dynamic values... 63 | ADF4350::setR1(); 64 | ADF4350::setR3(); 65 | ADF4350::setR5(); 66 | 67 | 68 | ADF4350::setFreq(freq); 69 | // ADF4350::update(); 70 | } 71 | 72 | // gets current frequency setting 73 | int ADF4350::getFreq(){ 74 | return _freq; 75 | } 76 | 77 | void ADF4350::setFreq(int freq){ 78 | _freq = freq; 79 | int multiplier; 80 | 81 | // selects the right divider range (ie, output divider is 2^(_divider)) 82 | // the multiplier is required if you're using fundamental feedback to N-counter 83 | if (_freq <= 270 && _freq >= 140){ 84 | _divider = 4; 85 | multiplier = 16; 86 | } else if (_freq >= 280 && _freq <= 540){ 87 | _divider = 3; 88 | multiplier = 8; 89 | } else if (_freq >= 550 && _freq <= 1090){ 90 | _divider = 2; 91 | multiplier = 4; 92 | } else if (_freq >= 1100 && _freq <= 2190){ 93 | _divider = 1; 94 | multiplier = 2; 95 | } else{ 96 | _divider = 0; 97 | multiplier = 1; 98 | } 99 | 100 | if (_feedbackType == 0){ 101 | _int = _freq/_refClk; 102 | } else{ 103 | _int = _freq*multiplier/_refClk; 104 | } 105 | ADF4350::update(); 106 | } 107 | 108 | 109 | 110 | // updates dynamic registers, and writes values to PLL board 111 | void ADF4350::update(){ 112 | // updates registers with dynamic values... 113 | ADF4350::setR0(); 114 | ADF4350::setR2(); 115 | ADF4350::setR4(); 116 | 117 | // writes registers to device 118 | ADF4350::writeRegister(_r5); 119 | ADF4350::writeRegister(_r4); 120 | ADF4350::writeRegister(_r3); 121 | ADF4350::writeRegister(_r2); 122 | ADF4350::writeRegister(_r1); 123 | ADF4350::writeRegister(_r0); 124 | } 125 | 126 | void ADF4350::setFeedbackType(bool feedback){ 127 | _feedbackType = feedback; 128 | } 129 | 130 | void ADF4350::powerDown(bool pd){ 131 | _powerdown = pd; 132 | ADF4350::setR2(); 133 | ADF4350::update(); 134 | 135 | } 136 | 137 | void ADF4350::rfEnable(bool rf){ 138 | _rfEnabled = rf; 139 | ADF4350::setR4(); 140 | ADF4350::update(); 141 | } 142 | 143 | // CAREFUL!!!! pow must be 0, 1, 2, or 3... corresponding to -4, -1, 3, 5 dbm. 144 | void ADF4350::setRfPower(int pow){ 145 | _rfPower = pow; 146 | ADF4350::setR4(); 147 | ADF4350::update(); 148 | } 149 | 150 | void ADF4350::auxEnable(bool aux){ 151 | _auxEnabled = aux; 152 | ADF4350::setR4(); 153 | ADF4350::update(); 154 | } 155 | 156 | // CAREFUL!!!! pow must be 0, 1, 2, or 3... corresponding to -4, -1, 3, 5 dbm. 157 | void ADF4350::setAuxPower(int pow){ 158 | _auxPower = pow; 159 | ADF4350::setR4(); 160 | ADF4350::update(); 161 | } 162 | 163 | // REGISTER UPDATE FUNCTIONS 164 | 165 | void ADF4350::setR0(){ 166 | unsigned long r0 = (_int << 15); // sets int value... 167 | byte r0Ary[] = { lowByte(r0 >> 24), lowByte(r0 >> 16), lowByte(r0 >> 8), lowByte(r0) }; 168 | memcpy(&_r0, &r0Ary, sizeof(r0Ary)); 169 | } 170 | 171 | void ADF4350::setR1(){ 172 | unsigned long r1 = (_phase << 15) + // phase value = 1 173 | (2 << 3) + // modulus value = 1 174 | 1; // register value 175 | byte r1Ary[] = { lowByte(r1 >> 24), lowByte(r1 >> 16), lowByte(r1 >> 8), lowByte(r1) }; 176 | memcpy(&_r1, &r1Ary, sizeof(r1Ary)); 177 | } 178 | 179 | void ADF4350::setR2(){ 180 | unsigned long r2 = (6 << 26) + // muxout 181 | (1 << 14) + // r-counter = 1 182 | (7 << 9) + // charge pump = 2.5 183 | (5 << 6) + // digital lock detect + polarity 184 | (_powerdown << 5) + // powerdown 0 = false; 1 = true 185 | 2; // register value 186 | 187 | byte r2Ary[] = { lowByte(r2 >> 24), lowByte(r2 >> 16), lowByte(r2 >> 8), lowByte(r2) }; 188 | memcpy(&_r2, &r2Ary, sizeof(r2Ary)); 189 | } 190 | 191 | void ADF4350::setR3(){ 192 | unsigned long r3 = 3; // (all zero, except register control value = 3); 193 | byte r3Ary[] = { lowByte(r3 >> 24), lowByte(r3 >> 16), lowByte(r3 >> 8), lowByte(r3) }; 194 | memcpy(&_r3, &r3Ary, sizeof(r3Ary)); 195 | } 196 | 197 | void ADF4350::setR4(){ 198 | 199 | unsigned long r4 = (_feedbackType << 23) + // divided/fundamental feedback 200 | (_divider << 20) + 201 | (80 << 12) + // band select clock divider 202 | (0 << 9) + // vco powerdown = false; MTLD = 1; aux output = divided; 203 | (_auxEnabled << 8) + // AUX OUTPUT enable/disable 204 | (_auxPower << 6) + // aux output power = {-4, -1, 2, 5dbm} 205 | (_rfEnabled << 5) + // RF OUTPUT ENABLED 206 | (_rfPower << 3) + // RF output power = 5dbm 207 | 4; // register select 208 | 209 | byte r4Ary[] = { lowByte(r4 >> 24), lowByte(r4 >> 16), lowByte(r4 >> 8), lowByte(r4) }; 210 | memcpy(&_r4, &r4Ary, sizeof(r4Ary)); 211 | 212 | 213 | } 214 | 215 | void ADF4350::setR5(){ 216 | 217 | unsigned long r5 = (1 << 22) + (3<<19) + 5; // lock detect pin mode = digital lock detect 218 | byte r5Ary[] = { lowByte(r5 >> 24), lowByte(r5 >> 16), lowByte(r5 >> 8), lowByte(r5) }; 219 | memcpy(&_r5, &r5Ary, sizeof(r5Ary)); 220 | 221 | } 222 | // Writes SPI to particular register. 223 | // registerInfo is a 2-element array which contains [register, number of bytes] 224 | void ADF4350::writeRegister(byte data[]){ 225 | 226 | 227 | digitalWrite(_ssPin, LOW); 228 | 229 | // Writes the data 230 | for(int i = 0; i < 4 ; i++){ 231 | SPI.transfer(data[i]); 232 | } 233 | 234 | digitalWrite(_ssPin, HIGH); 235 | 236 | } 237 | 238 | -------------------------------------------------------------------------------- /ADF4350.h: -------------------------------------------------------------------------------- 1 | /* 2 | ADF4350.h - ADF4350 PLL Communication Library 3 | Created by Neal Pisenti, 2013. 4 | JQI - Strontium - UMD 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | aunsigned long with this program. If not, see . 18 | 19 | 20 | */ 21 | 22 | #ifndef ADF4350_h 23 | #define ADF4350_h 24 | 25 | #include "Arduino.h" 26 | 27 | class ADF4350 28 | { 29 | public: 30 | // Constructor function. 31 | // Creates PLL object, with given SS pin 32 | ADF4350(byte); 33 | 34 | // Initialize with initial frequency, refClk (defaults to 10Mhz); 35 | void initialize(int, int); 36 | 37 | 38 | // powers down the PLL/VCO 39 | void powerDown(bool); 40 | void setRfPower(int); 41 | void setAuxPower(int); 42 | void auxEnable(bool); 43 | void rfEnable(bool); 44 | 45 | // Gets current frequency 46 | int getFreq(); 47 | 48 | // Sets frequency 49 | void setFreq(int); 50 | 51 | void setInt(int); 52 | 53 | void setFeedbackType(bool); 54 | 55 | void update(); 56 | 57 | unsigned long _phase; 58 | unsigned long _freq, _int, _divider, _refClk, _auxPower, _rfPower; 59 | private: 60 | // Instance variables that hold pinout mapping 61 | byte _ssPin; 62 | 63 | // Instance variables for ... 64 | bool _powerdown, _auxEnabled, _rfEnabled, _feedbackType; 65 | 66 | // register values 67 | byte _r0[4], _r1[4], _r2[4], _r3[4], _r4[4], _r5[4]; 68 | 69 | 70 | 71 | // function to write data to register. 72 | void setR0(); 73 | void setR1(); 74 | void setR2(); 75 | void setR3(); 76 | void setR4(); 77 | void setR5(); 78 | void writeRegister(byte[4]); 79 | 80 | 81 | 82 | }; 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ADF4350 2 | 3 | Communication library to interface with Analog Devices ADF4350 PLL IC. Designed 4 | with the ADF4350 evaluation board in mind. 5 | 6 | ## Getting started 7 | 8 | In your Arduino sketch, you'll want to include the SPI library in addition to this code: 9 | 10 | #include 11 | #include 12 | 13 | #define COM_PIN 32 // sets pin 32 to be the slave-select pin for PLL 14 | ADF4350 PLL(COM_PIN); // declares object PLL of type ADF4350. Will initialize it below. 15 | 16 | void setup(){ 17 | SPI.begin(); // for communicating with DDS/PLLs 18 | SPI.setClockDivider(4); 19 | SPI.setDataMode(SPI_MODE0); 20 | delay(500); // give it a sec to warm up 21 | 22 | 23 | PLL.initialize(400, 10); // initialize the PLL to output 400 Mhz, using an 24 | // onboard reference of 10Mhz 25 | 26 | } 27 | 28 | 29 | ### Important note 30 | 31 | The ADF4350 works with 3.3V logic levels, not 5V. Be careful if you're using an Arduino Uno or similar! 32 | 33 | ## Implemented features 34 | 35 | Self-explanatory functions... 36 | 37 | * `ADF4350::initialize(int frequency, int refClk)` -- initializes PLL with given frequency (Mhz) and reference clock frequency (also in Mhz). 38 | * `ADF4350::getFreq()` -- returns current frequency 39 | * `ADF4350::setFreq(int freq)` -- sets PLL to output new frequency `freq` (in MHz). 40 | 41 | Functions you should use after consulting datasheet: 42 | 43 | * `ADF4350::setFeedbackType(bool feedback)` -- fundamental vs. divided feedback 44 | * `ADF4350::powerDown(bool pd)` -- power down the VCO (or not). 45 | * `ADF4350::rfEnable(bool rf)` -- enable/disable output on the main RF output. 46 | * `ADF4350::setRfPower(int pow)` -- `pow` should be 0, 1, 2, or 3, corresponding to -4, -1, 3, or 5 dBm. 47 | * `ADF4350::auxEnable(bool aux)` -- enable/disable output on the auxilary output. 48 | * `ADF4350::setAuxPower(int pow)` -- set auxiliary power output. Again, `pow` should be 0, 1, 2, or 3, corresponding to -4, -1, 3, or 5 dBm. 49 | --------------------------------------------------------------------------------