LTC6950 - 1.4GHz Low Phase Noise, Low Jitter PLL with Clock Distribution

Features

  • Low Phase Noise and Jitter
  • Additive Jitter: 18fsRMS (12kHz to 20MHz)
  • Additive Jitter: 85fsRMS (10Hz to Nyquist)
  • EZSync™ Multichip Clock Edge Synchronization
  • Full PLL Core with Lock Indicator
  • –226dBc/Hz Normalized In-Band Phase Noise Floor
  • –274dBc/Hz Normalized 1/f Phase Noise
  • 1.4GHz Maximum VCO Input Frequency
  • Four Independent, Low Noise 1.4GHz LVPECL Outputs
  • One LVDS/CMOS Configurable Output
  • Five Independently Programmable Dividers Covering All Integers from 1 to 63
  • Five Independently Programmable VCO Clock Cycle Delays Covering All Integers from 0 to 63
  • –40°C to 105°C Junction Temperature Range
  • ClockWizard Software Design Tool Support

Typical Application

LTC6950 Typical Application
LTC6950 Typical Application

Description

The LTC®6950 is a low phase noise integer-N frequency synthesizer core with clock distribution. The LTC6950 delivers the low phase noise clock signals demanded in high frequency, high resolution data acquisition systems.

The frequency synthesizer contains a full low noise PLL core with a programmable reference divider (R), a programmable feedback divider (N), a phase/frequency detector (PFD) and a low noise charge pump (CP). The clock distribution section of the LTC6950 delivers up to five outputs based on the VCO input. Each output is individually programmed to divide the VCO input frequency by any integer from 1 to 63 and to delay the output by 0 to 63 VCO clock cycles. Four of the outputs feature very low noise, low skew LVPECL logic signals capable of operation up to 1.4GHz. The fifth output is selectable as either an LVDS (800MHz) or CMOS (250MHz) logic type. This output is also programmed to produce an output signal based on either the VCO input or the reference divider output.

Packaging

For complete and up to date package information and drawings, please refer to our packaging page

Part Number Package Code Temp Package
Drawing
RoHS
LTC6950IUHH#PBF 5x9 QFN-48 UHH I 05-08-1845 Yes
LTC6950IUHH#TRPBF 5x9 QFN-48 UHH I 05-08-1845 Yes


LTC6950 Package Drawing

Order Info

  • Part numbers ending in PBF are lead free. Solder plated terminal finish (SnPb) versions are non-standard and special terms and conditions and pricing applies if available. Please contact LTC marketing for information.
  • Part numbers containing TR or TRM are shipped in tape and reel or 500 unit mini tape and reel, respectively
  • Please refer to our general ordering information or the product datasheet for more details

Package Variations and Pricing

Part Number Package Temp Price
(1-99)
Price
(1k)*
RoHS
LTC6950IUHH#PBF 5x9 QFN-48 I $14.21 $9.95 Yes
LTC6950IUHH#TRPBF 5x9 QFN-48 I $14.27 $10.01 Yes
Buy NowRequest Samples
* The USA list pricing shown is for BUDGETARY USE ONLY, shown in United States dollars (FOB USA per unit for the stated volume), and is subject to change. International prices may differ due to local duties, taxes, fees and exchange rates. For volume-specific price or delivery quotes, please contact your local Linear Technology sales office or authorized distributor.

Demo Boards

Linear Technology offers many demo boards free of charge to qualified customers. Contact your local sales office or distributor to inquire about a demo board. Certain demo boards are also available for sale via credit card on this website. Demo boards are for evaluation purposes only. It remains the customer’s responsibility to verify proper and reliable operation in the actual end application.

Part Number Description Price Documentation
DC1795A LTC6950 Demo Board| Integer-N PLL with 5 outputs (requires DC590 or DC2026) $300.00
Buy Now

Companion Boards

Part Number Description Price Documentation
DC2026C Linduino One Isolated USB Demo Board: An Arduino- and QuikEval-Compatible Code Development Platform $75.00
DC590B Isolated USB Serial Controller for Linear Technology QuikEval-Compatible Demo Boards $50.00
Buy Now
Click here to view our complete list of demo boards

Applications

  • Clocking High Speed, High Resolution ADCs, DACs and Data Acquisition Systems
  • Low Jitter Clock Generation and Distribution

Product Notifications

Please login to your MyLinear account for notifications of datasheet updates, new document releases and LTspice model announcements for your favorite products. If you do not have a MyLinear account you may Sign Up Now.

Forgot your password? Click here.
Need help? Email mylinear@linear.com with questions and comments.

Design Tools

Linduino

Linduino is an Arduino compatible platform for developing and distributing firmware libraries and code for SPI and I²C-compatible integrated circuits. The Linduino One board interfaces to more than 300 QuikEval demonstration cards, supporting a variety of product types including analog-to-digital converters (ADCs)digital-to-analog converters (DACs)power monitors, and more. Firmware libraries for individual devices are written in C and designed to be portable to a wide variety of processors and microcontrollers. Each library has a demonstration program that can be uploaded to the Linduino One platform to allow the circuit and software to be quickly and easily verified.

Click here for more information on Linduino

ClockWizard

ClockWizard builds on PLLWizard and simplifies the evaluation process of the LTC6950. Besides the ability to design the loop filter components and predict the resulting phase noise and jitter performance, ClockWizard introduces a scope plot which shows the LTC6950 outputs in the time domain and illustrates the phase relationships between the outputs based on their respective EZSync settings.  It also controls the LTC6950 demoboard via the DC590 or DC2026.  Furthermore, you may it use to:

  • Show PLL frequency response and stability
  • Simulate output phase noise and jitter
  • Simulate output clock phase relationships based on EZSync settings
  • Read and write all device registers
  • Import and export VCO, reference and output noise data

Click Here to Download ClockWizard 

Code

Linduino is Linear Technology's Arduino compatible system for developing and distributing firmware libraries and example code for Linear Technology’s integrated circuits. The code below can be downloaded or copied and pasted into your project. Please visit the Linduino Home Page for demo board, manual and setup information.

This part is Code Supported: There is example code available for this part. The code below may rely on other drivers available in the full library.

Download LTC6950 - DC1795A Linduino .INO File

/*!
DC1795A
LTC6950: 1.4GHz Low Phase Noise, Low Jitter PLL with Clock Distribution 

@verbatim

  Setup:
    Set the terminal baud rate to 115200 and select the newline terminator.
    Refer to Demo Manual DC1795A.
    Ensure all jumpers are installed in the factory default positions.
    Two power supplies are needed for this demo board: a 5v and a 3.3v supply.
    The 5V powers the 5V supply and V+VCO turret.
    
    
Command Description:

                             *****Main Menu*****
    1-  Load Default Settings- Loads the SPI map that is identical to file 
        LTC6950_ALL_CHAN_250MHz.clkset that is supplied with the ClockWizard and mentioned
        in the DC1795A user's manual.  It assumes a 100MHz reference input, a 1GHz VCO input
        and the default DC1795A BOM.  It should output a 250MHz signal on all outputs.
        
        ** If you want to use a different loop filter, reference frequency or different
        register settings.  Please use ClockWizard for the loop filter design and initial
        device setup.  The register settings from ClockWizard can be entered into menu option 2.
        
    2-  READ/WRITE to Registers Addresses- Selecting this option will cause all the registers to
        be read, stored to variables, and displayed.  The user will then have the option
        to write to one register address at a time.

    3-  READ/WRITE to Registers Fields- Selecting this option will allow the user
        to read or write to one register field name at a time. 
        
    4-  This function calculates and programs OD, ND, NUM based on the desired Frf,
        the reference frequency, and the current RD value.  Linduino One (Arduino Uno) are 
        limited to 32 bit floats, int and doubles.  Significant rounding errors are created 
        with this 32 bit limitation.  Therefore, this function uses 64bit math functions 
        specifically created to overcome this limitation.  After OD, ND, and NUM are programmed, 
        the program calibrates the LTC6950.  If other register need change see menu 2 or menu 3.
                 
    5-  This function stores the current SPI settings in the demo boards EEPROM
        
    6-  This function loads SPI settings from the demo boards EEPROM to the device  

USER INPUT DATA FORMAT:
 decimal : 1024
 hex     : 0x400
 octal   : 02000  (leading 0 "zero")
 binary  : B10000000000
 float   : 1024.0

@endverbatim

http://www.linear.com/product/LTC6950

http://www.linear.com/product/LTC6950#demoboards

REVISION HISTORY
$Revision: 3018 $
$Date: 2014-12-01 15:53:20 -0800 (Mon, 01 Dec 2014) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

/*! @file
    @ingroup LTC6950
*/

#include <Arduino.h>
#include <stdint.h>
#include "Linduino.h"
#include "LT_SPI.h"
#include "UserInterface.h"
#include "LT_I2C.h"
#include "QuikEval_EEPROM.h"
#include "LTC6950.h"
#include <SPI.h>
#include <Wire.h>

// Function Declaration
void print_title();             // Print the title block
void print_prompt();            // Print the main menu
void menu_1_load_default_settings();  // Sub-menus
void menu_2_RW_to_reg_addresss();         
void menu_3_RW_to_reg_field();
void menu_4_set_frf();
void menu_5_store_settings();
void menu_6_restore_settings();

// Global Variables
static uint8_t ref_out = 0;            //!< Used to keep track of reference out status
static int8_t demo_board_connected;    //!< Demo Board Name stored in QuikEval EEPROM
uint8_t First_Run=0;                   //!< if first time through loop = 0, otherwise=1


/* ------------------------------------------------------------------------- */
//! Initialize Linduino
//! @return void
void setup() {
char demo_name[] = "DC1795";    // Demo Board Name stored in QuikEval EEPROM
uint8_t data;

quikeval_SPI_init();      //! Configure the spi port for 4MHz SCK
quikeval_SPI_connect();   //! Connect SPI to main data port
quikeval_I2C_init();      //! Configure the EEPROM I2C port for 100kHz
Serial.begin(115200);     //! Initialize the serial port to the PC
LTC6950_init();
print_title();

demo_board_connected = discover_demo_board(demo_name);  //! Checks if correct demo board is connected.

if (!demo_board_connected)
   while (1);                  //! Does nothing if the demo board is not connected

Serial.print(demo_board.name);
Serial.println(F(" was found"));

print_prompt();
} // end of setup()


/* ------------------------------------------------------------------------- */
//! Repeats Linduino loop
//! @return void
void loop(){
uint16_t user_command;          // User input command
  
if (Serial.available()) {        // Check for user input
   if(First_Run==0){
      First_Run=1;
      } 
 
    user_command = read_int();  //! Reads the user command
    if (user_command != 'm')
      Serial.println(user_command);
    
    switch (user_command) {     //! Prints the appropriate submenu
       case 1:
        menu_1_load_default_settings();
       break;
        
       case 2:
        menu_2_RW_to_reg_addresss(); 
       break;
        
       case 3:
        menu_3_RW_to_reg_field();
       break;
        
       case 4:
        menu_4_set_frf();
       break; 
       
       case 5:
        menu_5_store_settings(); 
       break; 
       
       case 6:
         menu_6_restore_settings(); 
       break; 
        
       default:
        Serial.println(F("Incorrect Option"));
       break;
    } // end of switch statement
  Serial.println(F("\n*****************************************************************"));
  print_prompt();
  } // end of if statement
} // end of loop()

// Function Definitions
/* ------------------------------------------------------------------------- */
//! Menu 1: Load Default SPI Register Settings
//!  This function loads the register settings referenced
//!  in the DC1795A demo manual's quick start section.
//!  The register settings loaded are the same as CLOCK WIZARDS 
//!  clkset files LTC6950_PECL0_250MHz.clkset 
//!  The setting loaded with this function assume the LTC6950's 
//!  reference is set to 100MHz, the VCO input is set to 1GHz and
//!  the DC1795A's BOM has not been modified.
//! @return void
void menu_1_load_default_settings(){

set_LTC6950_ALLREGS(LTC6950_CS, 0x04,0x3b,0x08,0x00,0x3b,0x00,0x00,0x01,0x00,0x0a,0x44,0x80,0x84,0x80,0x84,0x80,0x84,0x80,0x84,0x80,0x04); 
Serial.println(F("Registers Have Been Written"));
} // end menu_1_load_default_settings function


/* ------------------------------------------------------------------------- */
//! Menu 2: Reads and/or Writes the SPI register address
//!  This function reads and displays all SPI register address settings in HEX format.
//!  It then provides an option to modify(write to) individual registers one at time
//!
//!  EXAMPLE:
//!  - 0- ADDR00 = 0x04 (read only) 
//!  - 1- ADDR01 = 0x04
//!  - ....
//!  - 21- ADDR15 = 0x04
//!  - 22- ADDR16 = 0x65 (read only)  
//!  - 0 - Return to Main Menu
//!  - Enter a command (1-21 to modify register, or '0' to return to Main Menu): 
//! @return void
void menu_2_RW_to_reg_addresss(){
uint8_t i, regval, user_regval, num_reg;
uint16_t user_address;          // User input command

num_reg = get_LTC6950_REGSIZE();
user_address=1;
// Read/Write loop, can exit loop by choosing '0'
while  (user_address != 0) {
   Serial.println(F("\n*****************************************************************"));
   // Read All Registers and display results
   for(i=0; i<num_reg; i++) {
      regval = LTC6950_read(LTC6950_CS,i);
      Serial.print(i);
      if(i<16)
        Serial.print(F("- ADDR0"));
      else
        Serial.print(F("- ADDR"));
      Serial.print(i, HEX);
      Serial.print(F(" = 0x"));
      if(regval<16) Serial.print(F("0"));
      Serial.print(regval, HEX);
      if(i==3) Serial.print(F(" (warning: if D2=1 it resets all registers. RES6950 Bit)"));
      if((i==0)||(i==(num_reg-1))) Serial.print(F(" (read only) "));
      Serial.println("");
      }  // end for loop
   Serial.print("0 - Return to Main Menu\n\n");
   // User input: Select which register to modify, or return to main menu
   Serial.print("Enter a command (1-21 to modify register, or '0' to return to Main Menu): ");
   user_address = read_int();  //! Reads the user command
   Serial.println(user_address);

   // User input: enter new setting for selected register
   if (user_address >0 && user_address<(num_reg-1)) {
      Serial.print("What value should ADDR");
      Serial.print(user_address);
      Serial.print(" be set to (ex: HEX format 0xff): ");
      user_regval = read_int();  //! Reads the user command
      Serial.println(user_regval);

      // writes new setting to part
      LTC6950_write(LTC6950_CS, (uint8_t)user_address, user_regval);
      } // end if statement
   } // end while loop
}  // end menu_2_RW_to_reg_addresss


/* ------------------------------------------------------------------------- */
//! Support function for function menu_3_RW_to_reg_field  
//!  displays current state of select field 
//!  provides user the option to write to that field or return to menu
//!  @return field value (user input) that will be written to part
long field_menu_RW(long field_val,       //!< current state of the selected field
                   char field_name[],    //!< SPI Field name selected
                   uint8_t f            //!< SPI field identifier identifies selected fields information in SPI MAP arrays
                   ){ 
long usr_field_val;
uint8_t field_size, i;
long max_num=1, pow2=1;
  
Serial.print("CURRENT STATE (HEX): ");
Serial.print(field_name);
Serial.print("= 0x");
Serial.println(field_val, HEX);

if(get_LTC6950_SPI_FIELD_RW(f)==0){     
   field_size=get_LTC6950_SPI_FIELD_NUMBITS(f);
   for(i=1; i<field_size; i++) { 
      pow2=pow2*2; 
      max_num=max_num + pow2;}

   Serial.print("What value should ");
   Serial.print(field_name);
   Serial.print(" be set to or type '-1' to exit: (ex: HEX format 0x00 to 0x");
   Serial.print(max_num, HEX);
   Serial.print(")");
   usr_field_val = read_int();  //! Reads the user command

   if (usr_field_val>=0 && usr_field_val<=max_num){
      Serial.println(usr_field_val);
      return usr_field_val;
      }
   else {
      return field_val;
      } // end of if statement
   } // end of if statement
} // end of field_menu_RW


/* ------------------------------------------------------------------------- */
//! Menu 3: Reads and/or Writes individual SPI fields
//!  This function provides the user with a list of all SPI fields.
//!  The user can select a SPI field to read its current value.
//!  Then the user will be provided with an option to write to that field
//!  or return to the selection menu.
//!
//!  EXAMPLE:
//!  - 1-CMSINV      26-IBIAS3       51-PD_OUT2 
//!  - 2-CP          27-INV_ST1      52-PD_OUT3
//!  - ....
//!  - 23-IBIAS0     48-PD_DIV4      73-UNLOCK *
//!  - 24-IBIAS1     49-PD_OUT0       
//!  - 25-IBIAS2     50-PD_OUT1
//!  - 0 - Return to Main Menu
//!  - * = READ ONLY FIELD
//!  - Enter a command (1-73 to modify register, or '0' to return to Main Menu): 
//! @return void
void menu_3_RW_to_reg_field(){
uint8_t  field_num;
long field_val;

field_val=999L;
field_num=1;
// Read/Write loop, can exit loop by choosing 'm'
while  (field_num != 0) {
   Serial.println(F("\n*****************************************************************"));
   // Select Fields to read and write to
   Serial.print(F("1-CMSINV      26-IBIAS3       51-PD_OUT2\n"));
   Serial.print(F("2-CP          27-INV_ST1      52-PD_OUT3\n"));
   Serial.print(F("3-CPCHI       28-INV_ST2      53-PD_OUT4\n"));
   Serial.print(F("4-CPCLO       29-LKCT         54-PDPLL\n"));
   Serial.print(F("5-CPDN        30-LKEN         55-PDREFAC\n"));
   Serial.print(F("6-CPINV       31-LKWIN        56-PDVCOAC\n"));
   Serial.print(F("7-CPMID       32-LOCK *       57-R\n"));
   Serial.print(F("8-CPRST       33-LVCMS        58-RDIVOUT\n"));
   Serial.print(F("9-CPUP        34-M0           59-RES6950\n"));
   Serial.print(F("10-CPWIDE     35-M1           60-RESET_R\n"));
   Serial.print(F("11-DEL0       36-M2           61-RESET_N\n"));
   Serial.print(F("12-DEL1       37-M3           62-REV *\n"));
   Serial.print(F("13-DEL2       38-M4           63-SM1\n"));
   Serial.print(F("14-DEL3       39-N            64-SM2\n"));
   Serial.print(F("15-DEL4       40-NO_REF *     65-SYNCMD\n"));
   Serial.print(F("16-FILTR      41-NO_VCO *     66-SYNC_EN0\n"));
   Serial.print(F("17-FILTV      42-PART *       67-SYNC_EN1\n"));
   Serial.print(F("18-FLDRV0     43-PDALL        68-SYNC_EN2\n"));
   Serial.print(F("19-FLDRV1     44-PD_DIV0      69-SYNC_EN3\n"));
   Serial.print(F("20-FLDRV2     45-PD_DIV1      70-SYNC_EN4\n"));
   Serial.print(F("21-FLDRV3     46-PD_DIV2      71-THI *\n"));
   Serial.print(F("22-FLDRV4     47-PD_DIV3      72-TLO *\n"));
   Serial.print(F("23-IBIAS0     48-PD_DIV4      73-UNLOCK *\n"));
   Serial.print(F("24-IBIAS1     49-PD_OUT0        \n"));
   Serial.print(F("25-IBIAS2     50-PD_OUT1        \n"));
   Serial.print("0 - Return to Main Menu\n");
   Serial.print("* = READ ONLY FIELD\n\n");

   Serial.print("Enter a command (1-73 to modify register, or '0' to return to Main Menu): ");
   field_num = read_int();  //! Reads the user command
   Serial.println(field_num);
  
   // User input: enter new setting for selected register
   if (field_num != 0) {
      switch (field_num) {      //! Prints the appropriate submenu
         case LTC6950_CMSINV:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CMSINV);    // reads selected field   
           field_val=field_menu_RW(field_val,"CMSINV",LTC6950_CMSINV);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CMSINV, field_val);}   // updates selected field
         break;

         case LTC6950_CP:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CP);    // reads selected field   
           field_val=field_menu_RW(field_val,"CP",LTC6950_CP);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CP, field_val);}   // updates selected field
         break;

         case LTC6950_CPCHI:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CPCHI);    // reads selected field   
           field_val=field_menu_RW(field_val,"CPCHI",LTC6950_CPCHI);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CPCHI, field_val);}   // updates selected field
         break;

         case LTC6950_CPCLO:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CPCLO);    // reads selected field   
           field_val=field_menu_RW(field_val,"CPCLO",LTC6950_CPCLO);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CPCLO, field_val);}   // updates selected field
         break;

         case LTC6950_CPDN:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CPDN);    // reads selected field   
           field_val=field_menu_RW(field_val,"CPDN",LTC6950_CPDN);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CPDN, field_val);}   // updates selected field
         break;

         case LTC6950_CPINV:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CPINV);    // reads selected field   
           field_val=field_menu_RW(field_val,"CPINV",LTC6950_CPINV);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CPINV, field_val);}   // updates selected field
         break;

         case LTC6950_CPMID:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CPMID);    // reads selected field   
           field_val=field_menu_RW(field_val,"CPMID",LTC6950_CPMID);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CPMID, field_val);}   // updates selected field
         break;

         case LTC6950_CPRST:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CPRST);    // reads selected field   
           field_val=field_menu_RW(field_val,"CPRST",LTC6950_CPRST);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CPRST, field_val);}   // updates selected field
         break;

         case LTC6950_CPUP:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CPUP);    // reads selected field   
           field_val=field_menu_RW(field_val,"CPUP",LTC6950_CPUP);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CPUP, field_val);}   // updates selected field
         break;

         case LTC6950_CPWIDE:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_CPWIDE);    // reads selected field   
           field_val=field_menu_RW(field_val,"CPWIDE",LTC6950_CPWIDE);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_CPWIDE, field_val);}   // updates selected field
         break;

         case LTC6950_DEL0:
            // DEL1-4 programmed same as DEL0 above, just change DEL0 to DELx
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_DEL0);    // reads selected field   
           field_val=field_menu_RW(field_val,"DEL0",LTC6950_DEL0);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_DEL0, field_val);}   // updates selected field
         break;
         
         case LTC6950_FILTR:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_FILTR);    // reads selected field   
           field_val=field_menu_RW(field_val,"FILTR",LTC6950_FILTR);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_FILTR, field_val);}   // updates selected field
         break;

         case LTC6950_FILTV:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_FILTV);    // reads selected field   
           field_val=field_menu_RW(field_val,"FILTV",LTC6950_FILTV);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_FILTV, field_val);}   // updates selected field
         break;

         case LTC6950_FLDRV0:
            // FLDRV1-4 programmed same as FLDRV0 above, just change FLDRV0 to FLDRVx
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_FLDRV0);    // reads selected field   
           field_val=field_menu_RW(field_val,"FLDRV0",LTC6950_FLDRV0);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_FLDRV0, field_val);}   // updates selected field
         break;

         case LTC6950_IBIAS0:
           // IBIAS1-3 programmed same as IBIAS0 above, just change IBIAS0 to IBIASx
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_IBIAS0);    // reads selected field   
           field_val=field_menu_RW(field_val,"IBIAS0",LTC6950_IBIAS0);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_IBIAS0, field_val);}   // updates selected field
         break;

         case LTC6950_INV_ST1:
            // INV_ST2 programmed same as INV_ST1 above, just change INV_ST1 to INV_STx
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_INV_ST1);    // reads selected field   
           field_val=field_menu_RW(field_val,"INV_ST1",LTC6950_INV_ST1);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_INV_ST1, field_val);}   // updates selected field
         break;

         case LTC6950_LKCT:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_LKCT);    // reads selected field   
           field_val=field_menu_RW(field_val,"LKCT",LTC6950_LKCT);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_LKCT, field_val);}   // updates selected field
         break;

         case LTC6950_LKEN:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_LKEN);    // reads selected field   
           field_val=field_menu_RW(field_val,"LKEN",LTC6950_LKEN);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_LKEN, field_val);}   // updates selected field
         break;

         case LTC6950_LKWIN:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_LKWIN);    // reads selected field   
           field_val=field_menu_RW(field_val,"LKWIN",LTC6950_LKWIN);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_LKWIN, field_val);}   // updates selected field
         break;

         case LTC6950_LOCK:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_LOCK);    // reads selected field   
           field_val=field_menu_RW(field_val,"LOCK",LTC6950_LOCK);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_LOCK, field_val);}   // updates selected field
         break;

         case LTC6950_LVCMS:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_LVCMS);    // reads selected field   
           field_val=field_menu_RW(field_val,"LVCMS",LTC6950_LVCMS);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_LVCMS, field_val);}   // updates selected field
         break;

         case LTC6950_M0:
           // M1-4 programmed same as M0 above, just change M0 to Mx
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_M0);    // reads selected field   
           field_val=field_menu_RW(field_val,"M0",LTC6950_M0);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_M0, field_val);}   // updates selected field
         break;

         case LTC6950_N:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_N);    // reads selected field   
           field_val=field_menu_RW(field_val,"N",LTC6950_N);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_N, field_val);}   // updates selected field
         break;

         case LTC6950_NO_REF:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_NO_REF);    // reads selected field   
           field_val=field_menu_RW(field_val,"NO_REF",LTC6950_NO_REF);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_NO_REF, field_val);}   // updates selected field
         break;

         case LTC6950_NO_VCO:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_NO_VCO);    // reads selected field   
           field_val=field_menu_RW(field_val,"NO_VCO",LTC6950_NO_VCO);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_NO_VCO, field_val);}   // updates selected field
         break;

         case LTC6950_PART:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_PART);    // reads selected field   
           field_val=field_menu_RW(field_val,"PART",LTC6950_PART);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_PART, field_val);}   // updates selected field
         break;

         case LTC6950_PDALL:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_PDALL);    // reads selected field   
           field_val=field_menu_RW(field_val,"PDALL",LTC6950_PDALL);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_PDALL, field_val);}   // updates selected field
         break;

         case LTC6950_PD_DIV0:
           // PD_DIV1-4 programmed same as PD_DIV0 above, just change PD_DIV0 to PD_DIVx
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_PD_DIV0);    // reads selected field   
           field_val=field_menu_RW(field_val,"PD_DIV0",LTC6950_PD_DIV0);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_PD_DIV0, field_val);}   // updates selected field
         break;

         case LTC6950_PD_OUT0:
            // PD_OUT1-4 programmed same as PD_OUT0 above, just change PD_OUT0 to PD_OUTx
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_PD_OUT0);    // reads selected field   
           field_val=field_menu_RW(field_val,"PD_OUT0",LTC6950_PD_OUT0);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_PD_OUT0, field_val);}   // updates selected field
         break;

         case LTC6950_PDPLL:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_PDPLL);    // reads selected field   
           field_val=field_menu_RW(field_val,"PDPLL",LTC6950_PDPLL);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_PDPLL, field_val);}   // updates selected field
         break;

         case LTC6950_PDREFAC:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_PDREFAC);    // reads selected field   
           field_val=field_menu_RW(field_val,"PDREFAC",LTC6950_PDREFAC);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_PDREFAC, field_val);}   // updates selected field
         break;

         case LTC6950_PDVCOAC:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_PDVCOAC);    // reads selected field   
           field_val=field_menu_RW(field_val,"PDVCOAC",LTC6950_PDVCOAC);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_PDVCOAC, field_val);}   // updates selected field
         break;

         case LTC6950_R:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_R);    // reads selected field   
           field_val=field_menu_RW(field_val,"R",LTC6950_R);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_R, field_val);}   // updates selected field
         break;

         case LTC6950_RDIVOUT:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_RDIVOUT);    // reads selected field   
           field_val=field_menu_RW(field_val,"RDIVOUT",LTC6950_RDIVOUT);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_RDIVOUT, field_val);}   // updates selected field
         break;

         case LTC6950_RES6950:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_RES6950);    // reads selected field   
           field_val=field_menu_RW(field_val,"RES6950",LTC6950_RES6950);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_RES6950, field_val);}   // updates selected field
         break;

         case LTC6950_RESET_R:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_RESET_R);    // reads selected field   
           field_val=field_menu_RW(field_val,"RESET_R",LTC6950_RESET_R);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_RESET_R, field_val);}   // updates selected field
         break;

         case LTC6950_RESET_N:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_RESET_N);    // reads selected field   
           field_val=field_menu_RW(field_val,"RESET_N",LTC6950_RESET_N);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_RESET_N, field_val);}   // updates selected field
         break;

         case LTC6950_REV:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_REV);    // reads selected field   
           field_val=field_menu_RW(field_val,"REV",LTC6950_REV);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_REV, field_val);}   // updates selected field
         break;

         case LTC6950_SM1:
            // SM2 programmed same as SM1 above, just change SM1 to SM2
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_SM1);    // reads selected field   
           field_val=field_menu_RW(field_val,"SM1",LTC6950_SM1);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_SM1, field_val);}   // updates selected field
         break;

         case LTC6950_SYNCMD:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_SYNCMD);    // reads selected field   
           field_val=field_menu_RW(field_val,"SYNCMD",LTC6950_SYNCMD);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_SYNCMD, field_val);}   // updates selected field
         break;

         case LTC6950_SYNC_EN0:
           // SYNC_EN1-4 programmed same as SYNC_EN0 above, just change SYNC_EN0 to SYNC_ENx
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_SYNC_EN0);    // reads selected field   
           field_val=field_menu_RW(field_val,"SYNC_EN0",LTC6950_SYNC_EN0);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_SYNC_EN0, field_val);}   // updates selected field
         break;

         case LTC6950_THI:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_THI);    // reads selected field   
           field_val=field_menu_RW(field_val,"THI",LTC6950_THI);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_THI, field_val);}   // updates selected field
         break;

         case LTC6950_TLO:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_TLO);    // reads selected field   
           field_val=field_menu_RW(field_val,"TLO",LTC6950_TLO);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_TLO, field_val);}   // updates selected field
         break;

         case LTC6950_UNLOCK:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_UNLOCK);    // reads selected field   
           field_val=field_menu_RW(field_val,"UNLOCK",LTC6950_UNLOCK);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, LTC6950_UNLOCK, field_val);}   // updates selected field
         break;
         
         default:
           field_val=get_LTC6950_SPI_FIELD(LTC6950_CS,field_num);    // reads selected field   
           field_val=field_menu_RW(field_val," ",field_num);      // user interface control and printout
           if(field_val>-1)  {set_LTC6950_SPI_FIELD(LTC6950_CS, field_num, field_val);}   // updates selected field
         break;
         }  // end of switch statement
      } // end if user_command != 0 statement
   } // end while loop
}  // end menu_3_RW_to_reg_field function


/* ------------------------------------------------------------------------- */
//! verifies VCO frequency is within datasheet specifications
void LTC6950_VCO_Freq_Verification(){
unsigned long temp_val, temp_max_VCO_MHz, temp_min_VCO_MHz, temp_max_VCO_Hz, temp_min_VCO_Hz;
unsigned long fvco_max[2], fvco_min[2], fvco_max_lim[2], fvco_min_lim[2];
boolean valid_input=false;

// USER INPUT
valid_input=false;


while (valid_input==false) {
   temp_max_VCO_MHz=get_LTC6950_global_VCO_MAX_MHz();
   temp_min_VCO_MHz=get_LTC6950_global_VCO_MIN_MHz();
   temp_max_VCO_Hz=get_LTC6950_global_VCO_MAX_Hz();
   temp_min_VCO_Hz=get_LTC6950_global_VCO_MIN_Hz();

   Serial.print(F("What is the upper frequency limit of the VCO (MHZ portion)? ["));
   Serial.print(temp_max_VCO_MHz);
   Serial.print(F("]: "));
   temp_val = read_float();  //! Reads the user command
   // if user selects enter, keep same Fref.  Otherwise set Fref and verify
   if(temp_val!=0) temp_max_VCO_MHz = abs(temp_val);
   Serial.println(temp_max_VCO_MHz);

   Serial.print(F("What is the upper VCO frequency limit (HZ portion)? "));
   temp_max_VCO_Hz = read_float();  //! Reads the user command
   // if user selects enter, keep same Fref.  Otherwise set Fref and verify
   Serial.println(temp_max_VCO_Hz);

   Serial.print(F("\nWhat is the lower frequency limit of the VCO (MHZ portion)? ["));
   Serial.print(temp_min_VCO_MHz);
   Serial.print(F("]: "));
   temp_val = read_float();  //! Reads the user command
   // if user selects enter, keep same Fref.  Otherwise set Fref and verify
   if(temp_val!=0) temp_min_VCO_MHz = abs(temp_val);
   Serial.println(temp_min_VCO_MHz);

   Serial.print(F("What is the lower frequency limit of the VCO (HZ portion)? "));
   temp_min_VCO_Hz = read_float();  //! Reads the user command
   Serial.println(temp_min_VCO_Hz);
   
   HZto64(fvco_max,temp_max_VCO_MHz,temp_max_VCO_Hz);  // convert to 64 bit integer
   HZto64(fvco_min,temp_min_VCO_MHz,temp_min_VCO_Hz);  // convert to 64 bit integer
   HZto64(fvco_max_lim,LTC6950_MAXFREQ,0);  // convert to 64 bit integer
   HZto64(fvco_min_lim,LTC6950_MINFREQ,0);  // convert to 64 bit integer


   // if valid input print the following to the screen
if (lt64(fvco_min_lim,fvco_min) && lt64(fvco_max,fvco_max_lim) &&
    lt64(fvco_min_lim,fvco_max) && lt64(fvco_min,fvco_max_lim) &&
    (eq64(fvco_min, fvco_max) || lt64(fvco_min, fvco_max)) ) {   
      set_LTC6950_global_vcolim(temp_max_VCO_MHz, temp_max_VCO_Hz, temp_min_VCO_MHz, temp_min_VCO_Hz);
      Serial.print(F("VCO Frequencies entered are valid\n"));
      valid_input=true;
      }
    else {
      Serial.print(F("VCO Frequencies must be less than 1400MHz\n"));
      }  // end of if-else
   } // end of while
}  // end of LTC6950_VCO_Freq_Verification


/* ------------------------------------------------------------------------- */
//! verifies reference frequency is within datasheet specifications
void LTC6950_Ref_Freq_Verification(){
unsigned long temp_val, temp_fref_MHz, temp_fref_Hz;
boolean valid_input=false;

// USER INPUT
valid_input=false;


while (valid_input==false) {
   temp_fref_MHz=get_LTC6950_global_fref_MHz();
   temp_fref_Hz=get_LTC6950_global_fref_Hz();
   Serial.print(F("\nWhat is the MHz portion of the Reference Input Frequency(MHZ)? ["));
   Serial.print(temp_fref_MHz);
   Serial.print(F("]: "));
   temp_val = read_float();  //! Reads the user command
   // if user selects enter, keep same Fref.  Otherwise set Fref and verify
   if(temp_val!=0) temp_fref_MHz = abs(temp_val);
   Serial.println(temp_fref_MHz);

   Serial.print(F("What is the sub-MHz portion of the Reference Input Frequency(HZ)? "));
   temp_val = read_float();  //! Reads the user command
   temp_fref_Hz = abs(temp_val);   
   Serial.println(temp_fref_Hz);

   // if valid input print the following to the screen
   if(temp_fref_MHz >=LTC6950_MIN_REF_FREQ & temp_fref_MHz <= LTC6950_MAX_REF_FREQ) {
      set_LTC6950_global_fref(temp_fref_MHz,temp_fref_Hz);
      temp_val= temp_fref_MHz*OneMHz + temp_fref_Hz;
      Serial.print(F("Reference Frequency set to ")); 
      Serial.print(temp_val);
      Serial.println(F("Hz"));
      valid_input=true;
      }
    else {
      Serial.print(F("Reference Frequency must be between 2MHz and 250MHz\n"));
      }  // end of if-else
   } // end of while
}  // end of LTC6950_Ref_Freq_Verification


/* -------------------------------------------------------------------------
   FUNCTION: LTC6950_Fout_Freq_Verification
//! verifies frf frequency is within datasheet specifications
---------------------------------------------------------------------------- */  
void LTC6950_Fout_Freq_Verification(){
unsigned long odiv, temp_fout_MHz, temp_fout_Hz, temp_val;
unsigned long frf[2];
boolean valid_input=false;

// USER INPUT
temp_fout_MHz=get_LTC6950_global_frf_MHz();
temp_fout_Hz=get_LTC6950_global_frf_Hz();

while(valid_input==false){
   Serial.print(F("\nWhat is the MHz portion of the Output Frequency(MHZ)? ["));
   Serial.print(temp_fout_MHz);
   Serial.print(F("]: "));
   temp_val = read_int();  //! Reads the user command
   // if user selects enter, keep same Fout.  Otherwise set Fout and verify
   if(temp_val!=0) temp_fout_MHz = abs(temp_val);
   Serial.println(temp_fout_MHz);

   Serial.print(F("What is the Hz portion of the Output Frequency(HZ)? "));
   temp_val = read_int();  //! Reads the user command
   temp_fout_Hz = abs(temp_val);
   Serial.println(temp_fout_Hz);
   
   HZto64(frf,temp_fout_MHz,temp_fout_Hz);  // convert to 64 bit integer

   // verify desired frequency falls within a divider range (1-6)  
   odiv = LTC6950_calc_odiv(frf);
   valid_input=false;
   if((odiv>=1) && (odiv<=63)) valid_input=true;
 
   // if valid input print the following to the screen
   if(valid_input==true) {
      set_LTC6950_global_frf(temp_fout_MHz,temp_fout_Hz);
      if(temp_fout_MHz < 4294) {
         temp_val= temp_fout_MHz*OneMHz + temp_fout_Hz;
         Serial.print(F("Desired Output Frequency is ")); 
         Serial.print(temp_val);
         Serial.println(F("Hz"));
         }
      else {  // over flow condition
         Serial.print(F("Desired Output Frequency is ")); 
         Serial.print(temp_fout_MHz);
         Serial.print(F("MHz + "));
         Serial.print(temp_fout_Hz);
         Serial.println(F("Hz"));
         }
       }
    // if invalid input print the following to the screen
   else {
      Serial.println(F("Invalid Fout frequency chosen"));
      } // end of if/else (valid_input==true)
   } // end of while(valid_input=false)
} // end of Fout_Freq_Verification


/* ------------------------------------------------------------------------- */
//! Menu 4: Calculates and programs OD, ND, NUM based on desired Frf
//!  This function calculates and programs OD, ND, NUM based on desired Frf,
//!  the reference frequency, and current RD value.  
//!  Linduino One (Arduino Uno) are limited to 32 bit floats, int and doubles.
//!  Significant rounding errors are created with this 32 bit limitation.  Therefore,
//!  This function uses 64bit math functions specifically created to overcome this limitation.
//!  If RD needs to change see menu 2 or menu 3
//! @return void
void menu_4_set_frf(){
Serial.print(F("\nThis function calculates and programs OD and ND\n"));
Serial.print(F("based on the value input for Fvco, Frf and Fref.\n"));
Serial.print(F("It assumes all other register settings are correct\n"));
Serial.print(F("The ClockWizard tool can verify the correctness of the other register settings.\n"));


Serial.print(F("\nThe following frequencies will be entered with 2 integers\n"));
Serial.print(F("1st number is the MHZ portion, the 2nd number is Hz portion\n"));
Serial.print(F(" - Example: A. 100\n"));
Serial.print(F("            B. 25\n"));
Serial.print(F("   equates to 100.000025MHZ\n\n"));
LTC6950_VCO_Freq_Verification();
LTC6950_Ref_Freq_Verification();
LTC6950_Fout_Freq_Verification();
LTC6950_set_frf();
}

/* ------------------------------------------------------------------------- */
//! Store PLL settings to nonvolatile EEPROM on demo board
//! @return void
void menu_5_store_settings() {
// Store the PLL Settings to the EEPROM
uint8_t regval;

uint8_t addr_offset;
uint8_t num_reg;

addr_offset=2;
num_reg = get_LTC6950_REGSIZE();
 
eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, EEPROM_CAL_STATUS_ADDRESS);         // Cal key
  
for (uint8_t i = 0; i <= num_reg ; i++){
   regval = LTC6950_read(LTC6950_CS,i);
   eeprom_write_byte(EEPROM_I2C_ADDRESS,(char) regval, EEPROM_CAL_STATUS_ADDRESS+ i+addr_offset);
   }
Serial.println(F("PLL Settings Stored to EEPROM"));

}


/* ------------------------------------------------------------------------- */
//! Read stored PLL settings from nonvolatile EEPROM on demo board
//! @return void
void menu_6_restore_settings() {
// Read the PLL settings from EEPROM
int16_t cal_key;
uint8_t regval;
uint8_t user_address;

uint8_t addr_offset;
uint8_t num_reg;

addr_offset=2;
num_reg = get_LTC6950_REGSIZE();

// read the cal key from the EEPROM
eeprom_read_int16(EEPROM_I2C_ADDRESS, &cal_key, EEPROM_CAL_STATUS_ADDRESS);
if (cal_key == EEPROM_CAL_KEY) {
   // PLL Settings has been stored, read PLL Settings
   user_address=2;
   for (uint8_t i = 0; i <= num_reg ; i++) {
      eeprom_read_byte(EEPROM_I2C_ADDRESS,(char *) &regval, EEPROM_CAL_STATUS_ADDRESS + i+addr_offset);
      LTC6950_write(LTC6950_CS, (uint8_t)i, regval);
      user_address++;
      }
   Serial.println(F("PLL Settings Restored"));
   }
else {
   Serial.println(F("PLL Settings not found"));
   }

}


/* ------------------------------------------------------------------------- */
//!    Prints the title block when program first starts.
void print_title() {
  
Serial.println(F("*****************************************************************"));
Serial.println(F("* DC1795 Demonstration Program                                  *"));
Serial.println(F("*                                                               *"));
Serial.println(F("* This program demonstrates how to send data to the LTC6950     *"));
Serial.println(F("*  1.4GHz Low Phase Noise, Low Jitter PLL with Clock            *"));
Serial.println(F("*  Distribution.                                                *"));
Serial.println(F("*                                                               *"));
Serial.println(F("* Set the baud rate to 115200 and select the newline terminator.*"));
Serial.println(F("*                                                               *"));
Serial.println(F("* For loop filter design please use the Clock Wizard software.  *"));
Serial.println(F("* - It is recommended to use ClockWizard to determine the       *"));
Serial.println(F("* correct SPI register values for the initial setup.  These     *"));
Serial.println(F("* values can be entered into this program via menu option 2     *"));
Serial.println(F("* below.  These values can then be stored and recalled from the *"));
Serial.println(F("* DC1795 EEPROM using options 5 and 6 below.                    *"));
Serial.println(F("*****************************************************************"));
Serial.println();
} // end of print_title


/* ------------------------------------------------------------------------- */
//!    Prints main menu.
void print_prompt() {
  
Serial.println(F("\nCommand Summary:"));
Serial.println(F("  1-Load Default Settings (same as the Clock Wizard's LTC6950_ALL_CHAN_250MHz.clkset settings)"));
Serial.println(F("  2-READ/WRITE to Registers Addresses"));
Serial.println(F("  3-READ/WRITE to Registers Fields"));
Serial.println(F("  4-Set Output Frequency - OUT0"));
Serial.println(F("  5-Store LTC6950 SPI settings to the DC1795's EEPROM"));
Serial.println(F("  6-Restore LTC6950 SPI settings from the DC1795's EEPROM"));
Serial.println("");
Serial.print(F("Enter a command: "));
} // end of print_prompt


Download LTC6950 - Linduino Header File

/*!
 LTC6950: 1.4GHz Low Phase Noise, Low Jitter PLL with Clock Distribution 

@verbatim
 SPI DATA FORMAT (MSB First):

 Write Sequence:
       Byte #1                    Byte #2
 MOSI: A6 A5 A4 A3 A2 A1 A0 W   D7 D6 D5 D4 D3 D2 D1 D0
 MISO: X  X  X  X  X  X  X  X   X  X  X  X  X  X  X  X

 Read Sequence:
       Byte #1                    Byte #2
 MOSI: A6 A5 A4 A3 A2 A1 A0 R   X  X  X  X  X  X  X  X
 MISO: X  X  X  X  X  X  X  X   D7 D6 D5 D4 D3 D2 D1 D0

 W    : SPI Write (0)
 R    : SPI Read  (1)
 Ax   : Address
 Dx   : Data Bits
 X    : Don't care

@endverbatim

http://www.linear.com/product/LTC6950

http://www.linear.com/product/LTC6950#demoboards

REVISION HISTORY
$Revision: 3018 $
$Date: 2014-12-01 15:53:20 -0800 (Mon, 01 Dec 2014) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

/*! @file
    @ingroup LTC6950
    Header for LTC6950: 1.4GHz Low Phase Noise, Low Jitter PLL with Clock Distribution 
*/

#ifndef LTC6950_H

#define LTC6950_H


//! Define the SPI CS pin
#ifndef LTC6950_CS
#define LTC6950_CS QUIKEVAL_CS  //! SPI Chip Select Pin
#endif


/*! @name LTC6950 Registers Fields in Alphabetical Order */
#define LTC6950_CMSINV 1      //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CP 2          //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CPCHI 3       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CPCLO 4       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CPDN 5        //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CPINV 6       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CPMID 7       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CPRST 8       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CPUP 9        //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_CPWIDE 10     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_DEL0 11       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_DEL1 12       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_DEL2 13       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_DEL3 14       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_DEL4 15       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_FILTR 16      //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_FILTV 17      //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_FLDRV0 18     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_FLDRV1 19     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_FLDRV2 20     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_FLDRV3 21     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_FLDRV4 22     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_IBIAS0 23     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_IBIAS1 24     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_IBIAS2 25     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_IBIAS3 26     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_INV_ST1 27    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_INV_ST2 28    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_LKCT 29       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_LKEN 30       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_LKWIN 31      //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_LOCK 32       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_LVCMS 33      //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_M0 34         //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_M1 35         //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_M2 36         //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_M3 37         //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_M4 38         //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_N 39          //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_NO_REF 40     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_NO_VCO 41     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PART 42       //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PDALL 43      //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_DIV0 44    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_DIV1 45    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_DIV2 46    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_DIV3 47    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_DIV4 48    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_OUT0 49    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_OUT1 50    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_OUT2 51    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_OUT3 52    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PD_OUT4 53    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PDPLL 54      //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PDREFAC 55    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_PDVCOAC 56    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_R 57          //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_RDIVOUT 58    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_RES6950 59    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_RESET_R 60    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_RESET_N 61    //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_REV 62        //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_SM1 63        //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_SM2 64        //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_SYNCMD 65     //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_SYNC_EN0 66   //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_SYNC_EN1 67   //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_SYNC_EN2 68   //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_SYNC_EN3 69   //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_SYNC_EN4 70   //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_THI 71        //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_TLO 72        //!<  for spi_map array, defines location for field specific information used to create the spi map
#define LTC6950_UNLOCK 73     //!<  for spi_map array, defines location for field specific information used to create the spi map


#define LTC6950_NUM_REGADDR 23  //!< Defines number of LTC6950 SPI registers, used in spi_map array
#define LTC6950_NUM_REGFIELD 73 //!< Defines number of LTC6950 SPI fields, used in spi_map array

#define ADDRx 0                 //!< used for 2nd dim of 2d spi_map array
#define DxMSB 1                 //!< used for 2nd dim of 2d spi_map array
#define NUMBITS 2               //!< used for 2nd dim of 2d spi_map array
#define R_ONLY 3                //!< used for 2nd dim of 2d spi_map array

#define OneMHz 1000000L         //!< 1MHz in long format, used in 64 bit math

#define LTC6950_MINFREQ 0     //!< LTC6950 lower freq limit
#define LTC6950_MAXFREQ 1400  //!< LTC6950 upper freq limit

#define LTC6950_MIN_REF_FREQ 2   //!< LTC6950 lower reference frequency limit
#define LTC6950_MAX_REF_FREQ 250 //!< LTC6950 upper reference frequency limit

//! @} */

/* ------------------------------------------------------------------------- */
//! LTC6950 Read Single Address
//!  reads 8 bit Data field to LTC6950.
//!  has to shift data by one bit to account for RW bit
//! @return data that was read from address
uint8_t LTC6950_read(uint8_t cs,    //!< Chip Select Pin
                     int8_t address //!< Register address for the LTC6950.
                    );

                    
/* ------------------------------------------------------------------------- */
//! LTC6950 Read Single Field
//! For SPI FIELDS located in 1 or multiple address location
//!  reads specific address locations
//!  identifies and returns specific field in question
//!  can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
//! @return data that was read from field
 long LTC6950_read_field(uint8_t cs,       //!< Chip Select Pin
                         uint8_t address,  //!< Register address for the LTC6950.
                         uint8_t MSB_loc,  //!< MSB bit location of field
                         uint8_t numbits   //!< length of field (i.e. number of bits in field)                    
                        );
 
 
/* ------------------------------------------------------------------------- */
//! Gets the LTC6950 SPI field value
//! calls function LTC6950_read_field, which
//!  reads specific address locations
//!  identifies and returns specific field in question
//!  can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
//! @return data that was read from field
long get_LTC6950_SPI_FIELD(uint8_t cs,          //!< Chip Select Pin
                           uint8_t f            //!< SPI field number
                          );
        
        
/* ------------------------------------------------------------------------- */
//! LTC6950 Write Single Address
//!  writes 8 bit Data field to LTC6950.
//!  has to shift data by one bit to account for RW bit
//! @return void
void LTC6950_write(uint8_t cs,                  //!< Chip Select Pin
                   uint8_t address,             //!< Register address for the LTC6950.
                   uint8_t Data                 //!< 8-bit data to be written to register
                  );

                  
/* ------------------------------------------------------------------------- */
//! LTC6950 Write Single Field
//!  For SPI FIELDS in 1 or multiple address locations
//!  reads specific address/field location then writes to specific field
//!  can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
//! @return void
 uint8_t LTC6950_write_field(uint8_t cs,        //!< Chip Select Pin
                             long field_data,   //!< Value field value to be set to
                             uint8_t address,   //!< Register address for the LTC6950.
                             uint8_t MSB_loc,   //!< MSB bit location of field
                             uint8_t numbits   //!< length of field (i.e. number of bits in field)
                            );
 
 
/* ------------------------------------------------------------------------- */
//! Sets the LTC6950 SPI field value
//! calls function LTC6950_read_field, which
//!  reads specific address/field location then writes to specific field
//!  can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
//! @return void
void set_LTC6950_SPI_FIELD(uint8_t cs,          //!< Chip Select Pin
                           uint8_t f,           //!< SPI field number
                           long field_data      //!< Value field value to be set to
                          );

                          
/* ------------------------------------------------------------------------- */
//! Writes values to ALL LTC6950 RW addresses
//! @return void
void set_LTC6950_ALLREGS(uint8_t cs,            //!< Chip Select Pin
                         uint8_t reg01,         //!< LTC6950 register 1
                         uint8_t reg02,         //!< LTC6950 register 2   
                         uint8_t reg03,         //!< LTC6950 register 3 
                         uint8_t reg04,         //!< LTC6950 register 4 
                         uint8_t reg05,         //!< LTC6950 register 5 
                         uint8_t reg06,         //!< LTC6950 register 6
                         uint8_t reg07,         //!< LTC6950 register 7
                         uint8_t reg08,         //!< LTC6950 register 8
                         uint8_t reg09,         //!< LTC6950 register 9
                         uint8_t reg0A,         //!< LTC6950 register 10
                         uint8_t reg0B,         //!< LTC6950 register 11
                         uint8_t reg0C,         //!< LTC6950 register 12
                         uint8_t reg0D,         //!< LTC6950 register 13
                         uint8_t reg0E,         //!< LTC6950 register 14
                         uint8_t reg0F,         //!< LTC6950 register 15
                         uint8_t reg10,         //!< LTC6950 register 16
                         uint8_t reg11,         //!< LTC6950 register 17
                         uint8_t reg12,         //!< LTC6950 register 18
                         uint8_t reg13,         //!< LTC6950 register 19
                         uint8_t reg14,         //!< LTC6950 register 20
                         uint8_t reg15          //!< LTC6950 register 21
                        );

/* ------------------------------------------------------------------------- */
//! Initializes the SPI MAP arrays
//! The values set in initialization are used for all the LTC6950 SPI/WRITE and 
//! read functions (set_LTC6950_SPI_FIELD, get_LTC6950_SPI_FIELD,
//! LTC6950_read, LTC6950_write, etc, etc)
//! @return void
void LTC6950_init();


/* ------------------------------------------------------------------------- */
//! returns # of addresses in parts register map (array size)
//! @return # of addresses in parts register map
uint8_t get_LTC6950_REGSIZE();


/* ------------------------------------------------------------------------- */
//! returns the number of bits for a given field name in the SPI map
//! @return the number of bits for a given field name in the SPI map
uint8_t get_LTC6950_SPI_FIELD_NUMBITS(uint8_t f //!< SPI field number 
                                      );

                                      
/* ------------------------------------------------------------------------- */
//! returns if the given field name is (0)read/write or (1)read_only field
//! @return if the given field is a (0)read/write or (1)read_only field
uint8_t get_LTC6950_SPI_FIELD_RW(uint8_t f   //!< SPI field number 
                                ) ; 

                                
/* ------------------------------------------------------------------------- */ 
//! calculates the output divider setting based on the frf and on board
//! VCO frequencies of LTC6950
//! @return odiv = 1-6 divider setting for valid frequency, or 999 for invalid odiv
unsigned long LTC6950_calc_odiv(unsigned long frf[2]    //!< output frequency
                                );  

/* ------------------------------------------------------------------------- */ 
//!   FUNCTION: LTC6950_set_frf
//!   Calculates the integer (N) and output divider (OD) SPI values
//!   using self created 64bit math functions. For Out0 only.  Use menu 3 to set dividers to
//!   achieve desired frequencies on other outputs.
//!   
//!  Datasheet equations
//!   - fvco = fpfd*(N + F)
//!   - frf  = fvco/O
//!   - fpfd = fref/R
//!    
//!    can be modified to the following equations
//!    - N   = (int) (fvco/fpfd)  = (int) frf*O*R/fref
//!    
//!    where
//!    - N = ndiv, O= M0div  in the code below
//!    
//!    Linduino One (Arduino Uno) is limited to 32 bit floats/double/long.
//!    32 bit math functions will create rounding errors with the above equations, 
//!    tha can result in frequency errors.
//!    Therefore, the following code uses self created 64bit functions for 64bit integer math.
//!    
//!    - frf (33 bits) LTC6950 max frf/fvco = 1.4GHZ, which is 23 bit number (2^31 = 2.147G)
//!    - fref (23 bits) LTC6950 min fref = 2MHz, which is a 20 bit number (2^20 = 1.05M)
//!    - O   (6 bits)
//!    - R   (10 bits)
//!    
//!    step 1: create 64 bit frf and fref numbers
//!    
//!    step 2: calculate O (output divider)
//!    
//!    step 3: get current R-divider setting
//!    
//!    step 4: calculate frf*O*R
//!    - max bit count/resolution: 31b+6b+10b= 47b
//!    
//!    step 5: calculate N(11b), using value from step 1
//!    - N = (int) frf*O*R/fref
//!    - max bit count/resolution: 47b-20b = 27b
//!    
//!    step 6: find N for closest frequency - accounts for rounding with integer math
//!    - 64b-47b=17b (using 16b instead of 17b)
//!    
//! @return void                            
void LTC6950_set_frf();
        

/* ------------------------------------------------------------------------- */ 
//! sets globals LTC6950_Fref_MHz and LTC6950_Fref_Hz
//! @return void
void set_LTC6950_global_fref(unsigned long fref_MHz, unsigned long fref_Hz);


/* ------------------------------------------------------------------------- */ 
//! sets globals LTC6950_Frf_MHz and LTC6950_Frf_Hz
//! @return void
void set_LTC6950_global_frf(unsigned long frf_MHz, unsigned long frf_Hz);

/* ------------------------------------------------------------------------- */ 
//! sets globals LTC6950_VCO_Max_Freq_MHz, LTC6950_VCO_Max_Freq_Hz, LTC6950_VCO_Min_Freq_MHz and LTC6950_VCO_Min_Freq_Hz
//! @return void
void set_LTC6950_global_vcolim(unsigned long fvco_max_MHz, unsigned long fvco_max_Hz, unsigned long fvco_min_MHz, unsigned long fvco_min_Hz);


/* ------------------------------------------------------------------------- */ 
//! returns global LTC6950_Fref_MHz 
//! @return LTC6950_Fref_MHz
unsigned long get_LTC6950_global_fref_MHz();


/* ------------------------------------------------------------------------- */ 
//! returns global LTC6950_Fref_Hz 
//! @return LTC6950_Fref_Hz
unsigned long get_LTC6950_global_fref_Hz();


/* ------------------------------------------------------------------------- */ 
//! returns global LTC6950_Frf_MHz 
//! @return LTC6950_Frf_MHz
unsigned long get_LTC6950_global_frf_MHz();


/* ------------------------------------------------------------------------- */ 
//! returns global LTC6950_Frf_Hz 
//! @return LTC6950_Frf_Hz
unsigned long get_LTC6950_global_frf_Hz();


/* ------------------------------------------------------------------------- */ 
//! returns global LTC6950_VCO_Max_Freq_MHz 
//! @return LTC6950_VCO_Max_Freq_MHz
unsigned long get_LTC6950_global_VCO_MAX_MHz();


/* ------------------------------------------------------------------------- */ 
//! returns global LTC6950_VCO_Min_Freq_MHz 
//! @return LTC6950_VCO_Min_Freq_MHz
unsigned long get_LTC6950_global_VCO_MIN_MHz();


/* ------------------------------------------------------------------------- */ 
//! returns global LTC6950_VCO_Max_Freq_Hz 
//! @return LTC6950_VCO_Max_Freq_Hz
unsigned long get_LTC6950_global_VCO_MAX_Hz();


/* ------------------------------------------------------------------------- */ 
//! returns global LTC6950_VCO_Min_Freq_Hz 
//! @return LTC6950_VCO_Min_Freq_Hz
unsigned long get_LTC6950_global_VCO_MIN_Hz();
    
    
/* ------------------------------------------------------------------------- */                                
//!   create a 64 bit Hz number from
//!   32 bit xxxx MHz number and 32 bit yyy yyy Hz number.
//!   A) if an < 2^32 bits:
//!      - an(upper 32b) = 0;
//!      - an(lower 32b) = MHzPart(32b)*1MHz + HzPart (32b)
//!
//!   B) if an > 2^32 bits (4,294,967,296):
//!     - an(upper 32b) = 1
//!     - an(lower 32b) = ((MHzPart-4294)*1MHz+HzPart)-967296
//! @return void                            
void HZto64(unsigned long  an[],            //!< 64 bit number, 1x2 32 bit array
            unsigned long MHzPart,          //!< integer in MHZ 
            unsigned long HzPart            //!< integer in Hz                                
            );                            


/* ------------------------------------------------------------------------- */
//! Creates a equivalent 64 bit number from 2 32 bit numbers
//! - an[0]=bigPart    upper 32 bits
//! - an[1]=littlePart lower 32 bits
//! @return void
void init64(unsigned long an[],        //!< 64 bit number, 1x2 32 bit array
            unsigned long bigPart,     //!< upper 32 bits
            unsigned long littlePart   //!< lower 32 bits
           );

/* ------------------------------------------------------------------------- */
//! Single Bit shift left of equivalent 64 bit number (an[] = an[]<<1)
//! @return void
void shl64(unsigned long  an[]         //!<  an[] = an[]<<1
          );

/* ------------------------------------------------------------------------- */
//! Multi Bit shift left of equivalent 64 bit number (an[] = an[]<<shiftnum)
//! @return void
void shl64by(unsigned long  an[],     //!<  an[] = an[]<<shiftnum
             uint8_t shiftnum         //!<  number of bits to shift left
            );

/* ------------------------------------------------------------------------- */
//! Single Bit shift right of equivalent 64 bit number (an[] = an[]<<1)
//! @return void
void shr64(unsigned long  an[]        //!<  an[] = an[]>>shiftnum
          );

/* ------------------------------------------------------------------------- */
//! Multi Bit shift right of equivalent 64 bit number (an[] = an[]>>shiftnum)
//! @return void
void shr64by(unsigned long  an[],     //!<  an[] = an[]>>shiftnum
             uint8_t shiftnum         //!<  number of bits to shift right
            );

/* ------------------------------------------------------------------------- */
//! 64 bit Add ann to an (an[] = an[] + ann[])
//! @return void
void add64(unsigned long  an[],      //!<  64 bit number, in 1x2 32bit array
           unsigned long  ann[]      //!<  64 bit number, in 1x2 32bit array
          );

/* ------------------------------------------------------------------------- */
//! 64 bit Subtract ann from an (an[] = an[] - ann[])
//! @return void
void sub64(unsigned long  an[],      //!<  64 bit number, in 1x2 32bit array
           unsigned long  ann[]      //!<  64 bit number, in 1x2 32bit array
          );

/* ------------------------------------------------------------------------- */
//! 64 bit, if an == ann, then true
//! @return true, if an==ann; false, if an<>ann
boolean eq64(unsigned long  an[],    //!<  64 bit number, in 1x2 32bit array
             unsigned long  ann[]    //!<  64 bit number, in 1x2 32bit array
            );

/* ------------------------------------------------------------------------- */
//! 64 bit, if an < ann, then true
//! @return true, if an<ann; false, if an=>ann
boolean lt64(unsigned long  an[],     //!<  64 bit number, in 1x2 32bit array
             unsigned long  ann[]     //!<  64 bit number, in 1x2 32bit array
            );

/* ------------------------------------------------------------------------- */
//! 64 bit Divide,   num=num/div
//! @return void
void div64(unsigned long num[],    //!<  numerator: 64 bit number, in 1x2 32bit array
           unsigned long den[]     //!<  denominator: 64 bit number, in 1x2 32bit array
          );


/* ------------------------------------------------------------------------- */
//! 64 bit multiply,   an=an*ann
//! @return void
void mul64(unsigned long an[],     //!<  64 bit number, in 1x2 32bit array
           unsigned long ann[]     //!<  64 bit number, in 1x2 32bit array
          );
 
/* ------------------------------------------------------------------------- */
//! Prints HEX representation of 64 bit an
//! @return void 
void prt(unsigned long  an[]       //!<  64 bit number, in 1x2 32bit array
        ); 

#endif  // LTC6950_H

Download LTC6950 - Linduino.CPP File

/*!
    LTC6950: 1.4GHz Low Phase Noise, Low Jitter PLL with Clock Distribution 

@verbatim

The LTC®6950 is a low phase noise integer-N frequency
synthesizer core with clock distribution. The LTC6950
delivers the low phase noise clock signals demanded in
high frequency, high resolution data acquisition systems.

The frequency synthesizer contains a full low noise PLL core
with a programmable reference divider (R), a programmable
feedback divider (N), a phase/frequency detector (PFD)
and a low noise charge pump (CP). The clock distribution
section of the LTC6950 delivers up to five outputs based on
the VCO input. Each output is individually programmed to
divide the VCO input frequency by any integer from 1 to 63
and to delay the output by 0 to 63 VCO clock cycles. Four
of the outputs feature very low noise, low skew LVPECL
logic signals capable of operation up to 1.4GHz. The fifth
output is selectable as either an LVDS (800MHz) or CMOS
(250MHz) logic type. This output is also programmed to
produce an output signal based on either the VCO input
or the reference divider output.

@endverbatim


http://www.linear.com/product/LTC6950

http://www.linear.com/product/LTC6950#demoboards

REVISION HISTORY
$Revision: 3018 $
$Date: 2014-12-01 15:53:20 -0800 (Mon, 01 Dec 2014) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

//! @defgroup LTC6950 LTC6950: 1.4GHz Low Phase Noise, Low Jitter PLL with Clock Distribution 

/*! @file
    @ingroup LTC6950
    Library for LTC6950: 1.4GHz Low Phase Noise, Low Jitter PLL with Clock Distribution 
*/

#include <stdint.h>
#include <Arduino.h>
#include "Linduino.h"
#include "UserInterface.h"
#include "LT_SPI.h"
#include "LTC6950.h"
#include <SPI.h>

uint8_t LTC6950_reg[LTC6950_NUM_REGADDR];              //!< number of LTC6950 spi addresses  
uint8_t LTC6950_spi_map[(LTC6950_NUM_REGFIELD+1)][4];  //!< LTC6950 spi map, stores MSB address location, MSB bit location, field length in bits, and R or RW capability

unsigned long LTC6950_Fref_MHz = 100;                  //!< Default Fref frequency - MHz portion (xxx);  Fref = xxx, yyy,yyy
unsigned long LTC6950_Fref_Hz = 0;                     //!< Default Fref frequency - Hz portion (yyy,yyy);  Fref = x,xxx, yyy,yyy
unsigned long LTC6950_Frf_MHz = 250;                   //!< Default Frf frequency - MHz portion (xxxx);  Frf = x,xxx, yyy,yyy
unsigned long LTC6950_Frf_Hz  = 0;                     //!< Default Frf frequency - Hz portion (yyy,yyy);  Frf = x,xxx, yyy,yyy
unsigned long LTC6950_VCO_Max_Freq_MHz = 1002;         //!< Max Vco frequency for default on board VCO  - MHz portion (xxxx);  Fvco max = xxx, yyy,yyy
unsigned long LTC6950_VCO_Min_Freq_MHz = 998;          //!< Min Vco frequency for default on board VCO - MHz portion (xxxx);  Fvco min = x,xxx, yyy,yyy
unsigned long LTC6950_VCO_Max_Freq_Hz = 0;             //!< Max Vco frequency for default on board VCO  - Hz portion (yyy,yyy);  Fvco max = x,xxx, yyy,yyy
unsigned long LTC6950_VCO_Min_Freq_Hz = 0;             //!< Min Vco frequency for default on board VCO  - Hz portion (yyy,yyy);  Fvco min= x,xxx, yyy,yyy

unsigned long zero64[]={0,0}; //!< for 64bit math functions

/* -------------------------------------------------------------------------
  FUNCTION: LTC6950_read
  - reads 8 bit Data field to LTC6950.
  - has to shift data by one bit to account for RW bit
 -------------------------------------------------------------------------- */
uint8_t LTC6950_read(uint8_t cs, int8_t address) {
int8_t address_shift;
LT_union_int16_2bytes rx;
  
address_shift =(address << 1) | 0x01; // shift to left to account for R/W bit, set bit high for read
spi_transfer_word(cs, address_shift<<8 , &rx.LT_uint16);
  
LTC6950_reg[address]=rx.LT_byte[0];
return(rx.LT_byte[0]);
}


/* -------------------------------------------------------------------------
  FUNCTION: LTC6950_read_field
  For SPI FIELDS located in 1 or multiple address location
  - reads specific address locations
  - identifies and returns specific field in question
    - can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
--------------------------------------------------------------------------- */
 long LTC6950_read_field(uint8_t cs, uint8_t address, uint8_t MSB_loc, uint8_t numbits){
 int bit_shift, i, num_reg;
 long field_val, maskbits, pow2;

num_reg=0;
field_val=0;
// determines how many register are used
do {
   bit_shift = (MSB_loc+1)- (numbits-num_reg*8);   // determines bit_shift for last register location
   field_val=LTC6950_read(cs, (address+num_reg))+(field_val<<8);  // reads current address locations, shifts previous address location 8 bits
   num_reg++;
}while ((bit_shift<0) && (num_reg<4));
  
// creates a bit mask for complete word, 
maskbits = 1;
pow2=1;
for(i=1, maskbits=1;i<numbits; i++) {
   pow2=pow2*2;
   maskbits = maskbits+pow2;
   }
 
field_val=(field_val >>bit_shift) &maskbits; 
return field_val;
}

/* -------------------------------------------------------------------------
  FUNCTION: get_LTC6950_SPI_FIELD
  For SPI FIELDS
  - reads specific address locations
  - identifies and returns specific field in question
    - can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
--------------------------------------------------------------------------- */
long get_LTC6950_SPI_FIELD(uint8_t cs, uint8_t f) {
 
return LTC6950_read_field(cs, LTC6950_spi_map[f][ADDRx], LTC6950_spi_map[f][DxMSB], LTC6950_spi_map[f][NUMBITS]);
}
 
/* -------------------------------------------------------------------------
  FUNCTION: LTC6950_write
  - writes 8 bit Data field to LTC6950.
  - has to shift data by one bit to account for RW bit
--------------------------------------------------------------------------- */
void LTC6950_write(uint8_t cs, uint8_t address, uint8_t Data) {
LT_union_int16_2bytes rx;
  
address=address << 1; // shift to left to account for R/W bit
spi_transfer_word(cs, (address<<8) | Data, &rx.LT_uint16);
}


 /* -------------------------------------------------------------------------
  FUNCTION: LTC6950_write_field
  For SPI FIELDS
  - reads specific address location
  - identifies and returns specific field in question
    - can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
---------------------------------------------------------------------------- */
uint8_t LTC6950_write_field(uint8_t cs, long field_data, uint8_t address, uint8_t MSB_loc, uint8_t numbits){
long current_content, desired_content, reg_val;
int LSB_loc, i, j, num_reg, bit_shift;
long temp_arr[32];
  
for(i=0; i<32 ; i++) temp_arr[i]=0;   // init temp_arr
  
// read data in current address location and put in a bit array
num_reg=0;
current_content=0;
do {
   bit_shift=(MSB_loc+1)-(numbits-num_reg*8);
   current_content=LTC6950_read(cs, (address+num_reg)) + (current_content<<8);

   num_reg++;
} while((bit_shift<0) && (num_reg<4));
for(i=0; i<(8*num_reg); i++) {temp_arr[i]=(current_content>>i) & 1; }
  
// exchange current bits with desired bits
LSB_loc = 8*(num_reg-1)+MSB_loc-numbits+1;
for(i=LSB_loc, j=0; i<=(MSB_loc+(num_reg-1)*8); i++, j++){
   temp_arr[i] = (field_data>>j) &1;
   } // end of for loop
    
// reconstruct bits into an integer
desired_content = 0;
for(i=0; i<(8*num_reg); i++) {
   desired_content = desired_content | (temp_arr[i]<<i);
   } // end of for loop
    
// write new field value to part
for(i=0; i<num_reg; i++) {
   reg_val = (desired_content >> 8*(num_reg-1-i)) & 0xff;
   LTC6950_write(cs, (address+i), reg_val);
   } // end of for loop
} // end of LTC6950_write_field
 
 
/* -------------------------------------------------------------------------
   FUNCTION: get_LTC6950_REGSIZE
   - returns # of addresses in parts register map (array size)
---------------------------------------------------------------------------- */
uint8_t get_LTC6950_REGSIZE(){
return sizeof(LTC6950_reg);
}
 
 
/* -------------------------------------------------------------------------
   FUNCTION: get_LTC6950_SPI_FIELD_NUMBITS
   - returns the number of bits for a given field name in the SPI map
---------------------------------------------------------------------------- */
uint8_t get_LTC6950_SPI_FIELD_NUMBITS(uint8_t f) {
return LTC6950_spi_map[f][NUMBITS];
}
 
 
/* -------------------------------------------------------------------------
   FUNCTION: get_LTC6950_SPI_FIELD_RW
   - returns if the given field name is (0)read/write or (1)read_only field
---------------------------------------------------------------------------- */
uint8_t get_LTC6950_SPI_FIELD_RW(uint8_t f) {
return LTC6950_spi_map[f][R_ONLY];
}
 
 
/* -------------------------------------------------------------------------
   FUNCTION: set_LTC6950_SPI_FIELD
   For SPI FIELDS 
   - reads specific address location
   - identifies and returns specific field in question
   - can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
---------------------------------------------------------------------------- */
void set_LTC6950_SPI_FIELD(uint8_t cs, uint8_t f, long field_data) {
LTC6950_write_field(cs, field_data, LTC6950_spi_map[f][ADDRx], LTC6950_spi_map[f][DxMSB], LTC6950_spi_map[f][NUMBITS]);
}
 

/* -------------------------------------------------------------------------
   FUNCTION: set_LTC6950_ALLREGS
   - writes data to all registers at once
--------------------------------------------------------------------------- */
void set_LTC6950_ALLREGS(uint8_t cs, uint8_t reg01, uint8_t reg02, uint8_t reg03, uint8_t reg04, uint8_t reg05, uint8_t reg06, uint8_t reg07, 
                         uint8_t reg08, uint8_t reg09, uint8_t reg0A, uint8_t reg0B, uint8_t reg0C, uint8_t reg0D, uint8_t reg0E, uint8_t reg0F,
                         uint8_t reg10, uint8_t reg11, uint8_t reg12, uint8_t reg13, uint8_t reg14, uint8_t reg15) {
uint8_t i;
 
LTC6950_reg[1] = reg01;
LTC6950_reg[2] = reg02;
LTC6950_reg[3] = reg03;
LTC6950_reg[4] = reg04;
LTC6950_reg[5] = reg05;
LTC6950_reg[6] = reg06; 
LTC6950_reg[7] = reg07;
LTC6950_reg[8] = reg08;
LTC6950_reg[9] = reg09;
LTC6950_reg[10] = reg0A;
LTC6950_reg[11] = reg0B;
LTC6950_reg[12] = reg0C; 
LTC6950_reg[13] = reg0D;
LTC6950_reg[14] = reg0E;  
LTC6950_reg[15] = reg0F;
LTC6950_reg[16] = reg10;
LTC6950_reg[17] = reg11;
LTC6950_reg[18] = reg12;
LTC6950_reg[19] = reg13;
LTC6950_reg[20] = reg14;
LTC6950_reg[21] = reg15;

for(i=1; i<22; i++)  LTC6950_write(cs, i, LTC6950_reg[i]);
} // end of set_LTC6950_ALLREGS
 
 
/* -------------------------------------------------------------------------
   FUNCTION: LTC6950_init
   - initializes the SPI MAP
   - for ease of programming there is spreadsheet that automates this some.
----------------------------------------------------------------------------*/
void LTC6950_init() { 
   
// spi map    
LTC6950_spi_map[LTC6950_CMSINV][ADDRx]=0X0b;    LTC6950_spi_map[LTC6950_CMSINV][DxMSB]= 3;   LTC6950_spi_map[LTC6950_CMSINV][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_CP][ADDRx]=0x05;        LTC6950_spi_map[LTC6950_CP][DxMSB]= 3;       LTC6950_spi_map[LTC6950_CP][NUMBITS]= 4;
LTC6950_spi_map[LTC6950_CPCHI][ADDRx]=0x06;     LTC6950_spi_map[LTC6950_CPCHI][DxMSB]= 7;    LTC6950_spi_map[LTC6950_CPCHI][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_CPCLO][ADDRx]=0x06;     LTC6950_spi_map[LTC6950_CPCLO][DxMSB]= 6;    LTC6950_spi_map[LTC6950_CPCLO][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_CPDN][ADDRx]=0x06;      LTC6950_spi_map[LTC6950_CPDN][DxMSB]= 0;     LTC6950_spi_map[LTC6950_CPDN][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_CPINV][ADDRx]=0x06;     LTC6950_spi_map[LTC6950_CPINV][DxMSB]= 4;    LTC6950_spi_map[LTC6950_CPINV][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_CPMID][ADDRx]=0x06;     LTC6950_spi_map[LTC6950_CPMID][DxMSB]= 5;    LTC6950_spi_map[LTC6950_CPMID][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_CPRST][ADDRx]=0x06;     LTC6950_spi_map[LTC6950_CPRST][DxMSB]= 2;    LTC6950_spi_map[LTC6950_CPRST][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_CPUP][ADDRx]=0x06;      LTC6950_spi_map[LTC6950_CPUP][DxMSB]= 1;     LTC6950_spi_map[LTC6950_CPUP][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_CPWIDE][ADDRx]=0x06;    LTC6950_spi_map[LTC6950_CPWIDE][DxMSB]= 3;   LTC6950_spi_map[LTC6950_CPWIDE][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_DEL0][ADDRx]=0x0c;      LTC6950_spi_map[LTC6950_DEL0][DxMSB]= 5;     LTC6950_spi_map[LTC6950_DEL0][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_DEL1][ADDRx]=0x0e;      LTC6950_spi_map[LTC6950_DEL1][DxMSB]= 5;     LTC6950_spi_map[LTC6950_DEL1][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_DEL2][ADDRx]=0x10;      LTC6950_spi_map[LTC6950_DEL2][DxMSB]= 5;     LTC6950_spi_map[LTC6950_DEL2][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_DEL3][ADDRx]=0x12;      LTC6950_spi_map[LTC6950_DEL3][DxMSB]= 5;     LTC6950_spi_map[LTC6950_DEL3][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_DEL4][ADDRx]=0x14;      LTC6950_spi_map[LTC6950_DEL4][DxMSB]= 5;     LTC6950_spi_map[LTC6950_DEL4][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_FILTR][ADDRx]=0x0b;     LTC6950_spi_map[LTC6950_FILTR][DxMSB]= 4;    LTC6950_spi_map[LTC6950_FILTR][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_FILTV][ADDRx]=0x0b;     LTC6950_spi_map[LTC6950_FILTV][DxMSB]= 5;    LTC6950_spi_map[LTC6950_FILTV][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_FLDRV0][ADDRx]=0x0c;    LTC6950_spi_map[LTC6950_FLDRV0][DxMSB]= 6;   LTC6950_spi_map[LTC6950_FLDRV0][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_FLDRV1][ADDRx]=0x0e;    LTC6950_spi_map[LTC6950_FLDRV1][DxMSB]= 6;   LTC6950_spi_map[LTC6950_FLDRV1][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_FLDRV2][ADDRx]=0x10;    LTC6950_spi_map[LTC6950_FLDRV2][DxMSB]= 6;   LTC6950_spi_map[LTC6950_FLDRV2][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_FLDRV3][ADDRx]=0x12;    LTC6950_spi_map[LTC6950_FLDRV3][DxMSB]= 6;   LTC6950_spi_map[LTC6950_FLDRV3][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_FLDRV4][ADDRx]=0x14;    LTC6950_spi_map[LTC6950_FLDRV4][DxMSB]= 6;   LTC6950_spi_map[LTC6950_FLDRV4][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_IBIAS0][ADDRx]=0x0d;    LTC6950_spi_map[LTC6950_IBIAS0][DxMSB]= 7;   LTC6950_spi_map[LTC6950_IBIAS0][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_IBIAS1][ADDRx]=0x0f;    LTC6950_spi_map[LTC6950_IBIAS1][DxMSB]= 7;   LTC6950_spi_map[LTC6950_IBIAS1][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_IBIAS2][ADDRx]=0x11;    LTC6950_spi_map[LTC6950_IBIAS2][DxMSB]= 7;   LTC6950_spi_map[LTC6950_IBIAS2][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_IBIAS3][ADDRx]=0x13;    LTC6950_spi_map[LTC6950_IBIAS3][DxMSB]= 7;   LTC6950_spi_map[LTC6950_IBIAS3][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_INV_ST1][ADDRx]=0x01;   LTC6950_spi_map[LTC6950_INV_ST1][DxMSB]= 7;  LTC6950_spi_map[LTC6950_INV_ST1][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_INV_ST2][ADDRx]=0x02;   LTC6950_spi_map[LTC6950_INV_ST2][DxMSB]= 7;  LTC6950_spi_map[LTC6950_INV_ST2][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_LKCT][ADDRx]=0x05;      LTC6950_spi_map[LTC6950_LKCT][DxMSB]= 5;     LTC6950_spi_map[LTC6950_LKCT][NUMBITS]= 2;
LTC6950_spi_map[LTC6950_LKEN][ADDRx]=0x03;      LTC6950_spi_map[LTC6950_LKEN][DxMSB]= 3;     LTC6950_spi_map[LTC6950_LKEN][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_LKWIN][ADDRx]=0x05;     LTC6950_spi_map[LTC6950_LKWIN][DxMSB]= 7;    LTC6950_spi_map[LTC6950_LKWIN][NUMBITS]= 2;
LTC6950_spi_map[LTC6950_LOCK][ADDRx]=0x00;      LTC6950_spi_map[LTC6950_LOCK][DxMSB]= 2;     LTC6950_spi_map[LTC6950_LOCK][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_LVCMS][ADDRx]=0x0b;     LTC6950_spi_map[LTC6950_LVCMS][DxMSB]= 2;    LTC6950_spi_map[LTC6950_LVCMS][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_M0][ADDRx]=0x0d;        LTC6950_spi_map[LTC6950_M0][DxMSB]= 5;       LTC6950_spi_map[LTC6950_M0][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_M1][ADDRx]=0x0f;        LTC6950_spi_map[LTC6950_M1][DxMSB]= 5;       LTC6950_spi_map[LTC6950_M1][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_M2][ADDRx]=0x11;        LTC6950_spi_map[LTC6950_M2][DxMSB]= 5;       LTC6950_spi_map[LTC6950_M2][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_M3][ADDRx]=0x13;        LTC6950_spi_map[LTC6950_M3][DxMSB]= 5;       LTC6950_spi_map[LTC6950_M3][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_M4][ADDRx]=0x15;        LTC6950_spi_map[LTC6950_M4][DxMSB]= 5;       LTC6950_spi_map[LTC6950_M4][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_N][ADDRx]=0x09;         LTC6950_spi_map[LTC6950_N][DxMSB]= 2;        LTC6950_spi_map[LTC6950_N][NUMBITS]= 11;
LTC6950_spi_map[LTC6950_NO_REF][ADDRx]=0x00;    LTC6950_spi_map[LTC6950_NO_REF][DxMSB]= 4;   LTC6950_spi_map[LTC6950_NO_REF][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_NO_VCO][ADDRx]=0x00;    LTC6950_spi_map[LTC6950_NO_VCO][DxMSB]= 5;   LTC6950_spi_map[LTC6950_NO_VCO][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PART][ADDRx]=0x16;      LTC6950_spi_map[LTC6950_PART][DxMSB]= 4;     LTC6950_spi_map[LTC6950_PART][NUMBITS]= 5;
LTC6950_spi_map[LTC6950_PDALL][ADDRx]=0x03;     LTC6950_spi_map[LTC6950_PDALL][DxMSB]= 7;    LTC6950_spi_map[LTC6950_PDALL][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_DIV0][ADDRx]=0x03;   LTC6950_spi_map[LTC6950_PD_DIV0][DxMSB]= 0;  LTC6950_spi_map[LTC6950_PD_DIV0][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_DIV1][ADDRx]=0x04;   LTC6950_spi_map[LTC6950_PD_DIV1][DxMSB]= 0;  LTC6950_spi_map[LTC6950_PD_DIV1][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_DIV2][ADDRx]=0x04;   LTC6950_spi_map[LTC6950_PD_DIV2][DxMSB]= 2;  LTC6950_spi_map[LTC6950_PD_DIV2][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_DIV3][ADDRx]=0x04;   LTC6950_spi_map[LTC6950_PD_DIV3][DxMSB]= 4;  LTC6950_spi_map[LTC6950_PD_DIV3][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_DIV4][ADDRx]=0x04;   LTC6950_spi_map[LTC6950_PD_DIV4][DxMSB]= 6;  LTC6950_spi_map[LTC6950_PD_DIV4][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_OUT0][ADDRx]=0x03;   LTC6950_spi_map[LTC6950_PD_OUT0][DxMSB]= 1;  LTC6950_spi_map[LTC6950_PD_OUT0][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_OUT1][ADDRx]=0x04;   LTC6950_spi_map[LTC6950_PD_OUT1][DxMSB]= 1;  LTC6950_spi_map[LTC6950_PD_OUT1][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_OUT2][ADDRx]=0x04;   LTC6950_spi_map[LTC6950_PD_OUT2][DxMSB]= 3;  LTC6950_spi_map[LTC6950_PD_OUT2][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_OUT3][ADDRx]=0x04;   LTC6950_spi_map[LTC6950_PD_OUT3][DxMSB]= 5;  LTC6950_spi_map[LTC6950_PD_OUT3][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PD_OUT4][ADDRx]=0x04;   LTC6950_spi_map[LTC6950_PD_OUT4][DxMSB]= 7;  LTC6950_spi_map[LTC6950_PD_OUT4][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PDPLL][ADDRx]=0x03;     LTC6950_spi_map[LTC6950_PDPLL][DxMSB]= 6;    LTC6950_spi_map[LTC6950_PDPLL][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PDREFAC][ADDRx]=0x03;   LTC6950_spi_map[LTC6950_PDREFAC][DxMSB]= 4;  LTC6950_spi_map[LTC6950_PDREFAC][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_PDVCOAC][ADDRx]=0x03;   LTC6950_spi_map[LTC6950_PDVCOAC][DxMSB]= 5;  LTC6950_spi_map[LTC6950_PDVCOAC][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_R][ADDRx]=0x07;         LTC6950_spi_map[LTC6950_R][DxMSB]= 1;        LTC6950_spi_map[LTC6950_R][NUMBITS]= 10;
LTC6950_spi_map[LTC6950_RDIVOUT][ADDRx]=0x15;   LTC6950_spi_map[LTC6950_RDIVOUT][DxMSB]= 7;  LTC6950_spi_map[LTC6950_RDIVOUT][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_RES6950][ADDRx]=0x03;   LTC6950_spi_map[LTC6950_RES6950][DxMSB]= 2;  LTC6950_spi_map[LTC6950_RES6950][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_RESET_R][ADDRx]=0x07;   LTC6950_spi_map[LTC6950_RESET_R][DxMSB]= 3;  LTC6950_spi_map[LTC6950_RESET_R][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_RESET_N][ADDRx]=0x09;   LTC6950_spi_map[LTC6950_RESET_N][DxMSB]= 4;  LTC6950_spi_map[LTC6950_RESET_N][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_REV][ADDRx]=0x16;       LTC6950_spi_map[LTC6950_REV][DxMSB]= 7;      LTC6950_spi_map[LTC6950_REV][NUMBITS]= 3;
LTC6950_spi_map[LTC6950_SM1][ADDRx]=0x01;       LTC6950_spi_map[LTC6950_SM1][DxMSB]= 5;      LTC6950_spi_map[LTC6950_SM1][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_SM2][ADDRx]=0x02;       LTC6950_spi_map[LTC6950_SM2][DxMSB]= 5;      LTC6950_spi_map[LTC6950_SM2][NUMBITS]= 6;
LTC6950_spi_map[LTC6950_SYNCMD][ADDRx]=0x0b;    LTC6950_spi_map[LTC6950_SYNCMD][DxMSB]= 7;   LTC6950_spi_map[LTC6950_SYNCMD][NUMBITS]= 2;
LTC6950_spi_map[LTC6950_SYNC_EN0][ADDRx]=0x0c;  LTC6950_spi_map[LTC6950_SYNC_EN0][DxMSB]= 7; LTC6950_spi_map[LTC6950_SYNC_EN0][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_SYNC_EN1][ADDRx]=0x0e;  LTC6950_spi_map[LTC6950_SYNC_EN1][DxMSB]= 7; LTC6950_spi_map[LTC6950_SYNC_EN1][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_SYNC_EN2][ADDRx]=0x10;  LTC6950_spi_map[LTC6950_SYNC_EN2][DxMSB]= 7; LTC6950_spi_map[LTC6950_SYNC_EN2][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_SYNC_EN3][ADDRx]=0x12;  LTC6950_spi_map[LTC6950_SYNC_EN3][DxMSB]= 7; LTC6950_spi_map[LTC6950_SYNC_EN3][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_SYNC_EN4][ADDRx]=0x14;  LTC6950_spi_map[LTC6950_SYNC_EN4][DxMSB]= 7; LTC6950_spi_map[LTC6950_SYNC_EN4][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_THI][ADDRx]=0x00;       LTC6950_spi_map[LTC6950_THI][DxMSB]= 1;      LTC6950_spi_map[LTC6950_THI][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_TLO][ADDRx]=0x00;       LTC6950_spi_map[LTC6950_TLO][DxMSB]= 0;      LTC6950_spi_map[LTC6950_TLO][NUMBITS]= 1;
LTC6950_spi_map[LTC6950_UNLOCK][ADDRx]=0x00;    LTC6950_spi_map[LTC6950_UNLOCK][DxMSB]= 3;   LTC6950_spi_map[LTC6950_UNLOCK][NUMBITS]= 1;

  
LTC6950_spi_map[LTC6950_CMSINV][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CP][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CPCHI][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CPCLO][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CPDN][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CPINV][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CPMID][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CPRST][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CPUP][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_CPWIDE][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_DEL0][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_DEL1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_DEL2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_DEL3][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_DEL4][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_FILTR][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_FILTV][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_FLDRV0][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_FLDRV1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_FLDRV2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_FLDRV3][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_FLDRV4][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_IBIAS0][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_IBIAS1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_IBIAS2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_IBIAS3][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_INV_ST1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_INV_ST2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_LKCT][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_LKEN][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_LKWIN][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_LOCK][R_ONLY]= 1;
LTC6950_spi_map[LTC6950_LVCMS][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_M0][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_M1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_M2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_M3][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_M4][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_N][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_NO_REF][R_ONLY]= 1;
LTC6950_spi_map[LTC6950_NO_VCO][R_ONLY]= 1;
LTC6950_spi_map[LTC6950_PART][R_ONLY]= 1;
LTC6950_spi_map[LTC6950_PDALL][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_DIV0][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_DIV1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_DIV2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_DIV3][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_DIV4][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_OUT0][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_OUT1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_OUT2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_OUT3][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PD_OUT4][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PDPLL][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PDREFAC][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_PDVCOAC][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_R][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_RDIVOUT][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_RES6950][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_RESET_R][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_RESET_N][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_REV][R_ONLY]= 1;
LTC6950_spi_map[LTC6950_SM1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_SM2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_SYNCMD][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_SYNC_EN0][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_SYNC_EN1][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_SYNC_EN2][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_SYNC_EN3][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_SYNC_EN4][R_ONLY]= 0;
LTC6950_spi_map[LTC6950_THI][R_ONLY]= 1;
LTC6950_spi_map[LTC6950_TLO][R_ONLY]= 1;
LTC6950_spi_map[LTC6950_UNLOCK][R_ONLY]= 1;
} // end of LTC6950_init

void set_LTC6950_global_fref(unsigned long fref_MHz, unsigned long fref_Hz){
LTC6950_Fref_MHz=fref_MHz;
LTC6950_Fref_Hz=fref_Hz;
}

void set_LTC6950_global_frf(unsigned long frf_MHz, unsigned long frf_Hz){
LTC6950_Frf_MHz=frf_MHz;
LTC6950_Frf_Hz=frf_Hz;
}

void set_LTC6950_global_vcolim(unsigned long fvco_max_MHz, unsigned long fvco_max_Hz, unsigned long fvco_min_MHz, unsigned long fvco_min_Hz){
LTC6950_VCO_Max_Freq_MHz=fvco_max_MHz;
LTC6950_VCO_Max_Freq_Hz=fvco_max_Hz;
LTC6950_VCO_Min_Freq_MHz=fvco_min_MHz;
LTC6950_VCO_Min_Freq_Hz=fvco_min_Hz;
}



unsigned long get_LTC6950_global_fref_MHz(){
return LTC6950_Fref_MHz;
}

unsigned long get_LTC6950_global_fref_Hz(){
return LTC6950_Fref_Hz;
}

unsigned long get_LTC6950_global_frf_MHz(){
return LTC6950_Frf_MHz;
}

unsigned long get_LTC6950_global_frf_Hz(){
return LTC6950_Frf_Hz;
}

unsigned long get_LTC6950_global_VCO_MAX_MHz(){
return LTC6950_VCO_Max_Freq_MHz;
}

unsigned long get_LTC6950_global_VCO_MIN_MHz(){
return LTC6950_VCO_Min_Freq_MHz;
}

unsigned long get_LTC6950_global_VCO_MAX_Hz(){
return LTC6950_VCO_Max_Freq_Hz;
}

unsigned long get_LTC6950_global_VCO_MIN_Hz(){
return LTC6950_VCO_Min_Freq_Hz;
}

/* -------------------------------------------------------------------------
   FUNCTION: calc_odiv
   - calculates the output divider setting based on the frf and on board
     VCO frequencies of LTC6950
   - @return odiv = 1-63 for valid setting, 999 as invalid odiv
---------------------------------------------------------------------------- */  
unsigned long LTC6950_calc_odiv(unsigned long frf[2]){
unsigned long odiv, i;
unsigned long max_fout64[2];
unsigned long min_fout64[2];
unsigned long temp_fout[2];
unsigned long temp_i[2];
boolean valid_input=false;


HZto64(max_fout64,LTC6950_VCO_Max_Freq_MHz,LTC6950_VCO_Max_Freq_Hz);
HZto64(min_fout64,LTC6950_VCO_Min_Freq_MHz,LTC6950_VCO_Min_Freq_Hz);
  
// verify desired frequency falls within a divider range (1-6)  
valid_input=false;
for(i=1; i<=63; i++) {
   init64(temp_i,0L,i);
   temp_fout[0] = frf[0];
   temp_fout[1] = frf[1];
   mul64(temp_fout,temp_i);
   if (lt64(temp_fout,max_fout64) || eq64(temp_fout, max_fout64)) {  // same as frf*i <= max_fout
      if (lt64(min_fout64,temp_fout) || eq64(temp_fout, min_fout64)) {// same as frf*i >= min_fout
         valid_input=true;
         odiv=i;
         }
      }
   } // end of for loop
 
if (valid_input == false) odiv= 999L;
return odiv;

} // end of LTC6950_calc_odiv

/* -------------------------------------------------------------------------
   FUNCTION: LTC6950_set_frf
   Calculates the integer (N) and output divider (OD) SPI values
   using self created 64bit math functions. For Out0 only.  Use menu 3 to set dividers to
   achieve desired frequencies on other outputs.
   
  Datasheet equations
  - fvco = fpfd*(N + F)
  - frf  = fvco/O
  - fpfd = fref/R
    
    can be modified to the following equations
    - N   = (int) (fvco/fpfd)  = (int) frf*O*R/fref
    
    where
    - N = ndiv, O= M0div  in the code below
    
    Linduino One (Arduino Uno) is limited to 32 bit floats/double/long.
    32 bit math functions will create rounding errors with the above equations, 
    tha can result in frequency errors.
    Therefore, the following code uses self created 64bit functions for 64bit integer math.
    
    - frf (33 bits) LTC6950 max frf/fvco = 1.4GHZ, which is 23 bit number (2^31 = 2.147G)
    - fref (23 bits) LTC6950 min fref = 2MHz, which is a 20 bit number (2^20 = 1.05M)
    - O   (6 bits)
    - R   (10 bits)
    
    step 1: create 64 bit frf and fref numbers
    
    step 2: calculate O (output divider)
    
    step 3: get current R-divider setting
    
    step 4: calculate frf*O*R
    - max bit count/resolution: 31b+6b+10b= 47b
    
    step 5: calculate N(11b), using value from step 1
    - N = (int) frf*O*R/fref
    - max bit count/resolution: 47b-20b = 27b
    
    step 6: find N for closest frequency - accounts for rounding with integer math
    - 64b-47b=17b (using 16b instead of 17b)
---------------------------------------------------------------------------- */
void LTC6950_set_frf(){
unsigned long frf_MHz, frf_Hz, fref_MHz, fref_Hz, M0div, rdiv, ndiv, N_remainder;
unsigned long N64[2], R64[2], MO64[2], temp_long[2];
char buffer[100];
unsigned long frf[2], frf_act[2];
unsigned long fref[2];
unsigned long temp_math[2];
unsigned long frf_rdiv_M0div[2];
unsigned long frf_rdiv_M0div_int[2];
unsigned long roundup[2];

/* step 1: create 64 bit frf and fref numbers
   32 bit xxxx MHz number and 32 bit yyy yyy Hz number. */
frf_MHz=LTC6950_Frf_MHz;
frf_Hz=LTC6950_Frf_Hz;
HZto64(frf, frf_MHz, frf_Hz);

fref_MHz=LTC6950_Fref_MHz;
fref_Hz=LTC6950_Fref_Hz;
HZto64(fref,fref_MHz,fref_Hz);

// step 2: calculate O (output divider)
M0div=LTC6950_calc_odiv(frf);

// step 3: get current R-divider setting
rdiv=get_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_R);    // reads selected field

// step 3: calculate frf*O*R
frf_rdiv_M0div[0]=0;
frf_rdiv_M0div[1]=M0div*rdiv;
mul64(frf_rdiv_M0div, frf);  // odiv*rdiv*frf
frf_rdiv_M0div_int[0]=frf_rdiv_M0div[0];  // copy odiv*rdiv*frf to another variable
frf_rdiv_M0div_int[1]=frf_rdiv_M0div[1];

// step 4: calculate N(10b), using value from step 3; N = (int) frf*O*R/fref
temp_math[0]=fref[0];   // copy fref to temp variable for math operation
temp_math[1]=fref[1];
div64(frf_rdiv_M0div_int, temp_math);   // frf_rdiv_odiv_int= [(frf*odiv*rdiv)]/fref  -->  int(fvco/fpfd)
ndiv=frf_rdiv_M0div_int[1]; 

// step 6: find N for closest frequency - accounts for rounding with integer math
// 64b-47b=17b (use 16b)
temp_math[0]=fref[0];   // copy fref to temp variable for math operation
temp_math[1]=fref[1];
shl64by(frf_rdiv_M0div,16);            // frf_rdiv_M0div     -->  [(frf*M0div*rdiv)<<16]/fref = N(double) <<16
div64(frf_rdiv_M0div,temp_math);
shl64by(frf_rdiv_M0div_int,16); // frf_rdiv_M0div_int  -->  [(int)((frf*M0div*rdiv)/fref)] <<13 = N(int) <<16
sub64(frf_rdiv_M0div,frf_rdiv_M0div_int);  // N(double) <<16 - N(int)<<16

// at this point frf_rdiv_Modiv is the delta between N(double) and N(int) shifted by 16 bits.
// if this remainder is < 32768, N(int) will give the closest frequency
// if this remainder is >=32768, N(int)+1 will give the closest frequency
// 32768 is mid point of the 16 bit number range
N_remainder = (frf_rdiv_M0div[1] & 65535L);  // 16 bits max code = 65535
if(N_remainder >= 32768) {
  ndiv=ndiv+1; 
  }

// program part and print out results to screen
set_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_M0,M0div);    // programs output divider  - OUT0
Serial.print("M0 = ");
Serial.println(M0div);

Serial.print("RD = ");
Serial.println(rdiv);

set_LTC6950_SPI_FIELD(LTC6950_CS,LTC6950_N,ndiv);    // programs N-divider
Serial.print(F("ND = "));
Serial.println(ndiv);



/////  calculate actual fout here and print out
frf_act[0]=fref[0];
frf_act[1]=fref[1];
N64[0]=0;  R64[0]=0; MO64[0]=0;
N64[1]=ndiv;
R64[1]=rdiv;
MO64[1]=M0div;

mul64(frf_act,N64);  // N*fref  
div64(frf_act,R64);  // N*fref/rdiv (or N*fpfd)
div64(frf_act,MO64); // (N*fpdf)/odiv
if(frf_act[0]==0) {  // no 32 bit overflow case
   Serial.print(F("Actual Output Frequency (closest available) is "));
   Serial.print(frf_act[1]);
   Serial.println("Hz");
   }
else {  // overflow case
   temp_math[0]=frf_act[0];
   temp_math[1]=frf_act[1];
   temp_long[0]=0;
   temp_long[1]=OneMHz;
   div64(temp_math,temp_long);  // frf/1e6
   Serial.print(F("Actual Output Frequency (closest available) is "));
   Serial.print(temp_math[1]);
   Serial.print("MHz + ");
   temp_long[0]=0;
   temp_long[1]=OneMHz;
   mul64(temp_math,temp_long);  // int(frf/1e6)*1e6
   sub64(frf_act,temp_math);    //  frf-int(frf/1e6)*1e6
   Serial.print(frf_act[1]);
   Serial.println("Hz");
   }
}


/* -------------------------------------------------------------------------
   FUNCTION: prt
   Prints HEX representation of 64 bit an
---------------------------------------------------------------------------- */
void prt(unsigned long  an[]){
  Serial.print(an[0],HEX);
  Serial.print(" ");
 Serial.println(an[1],HEX);
}


/* -------------------------------------------------------------------------
   FUNCTION: init64
   Creates a equivalent 64 bit number from 2 32 bit numbers
    an[0]=bigPart    //upper 32 bits
    an[1]=littlePart //lower 32 bits
---------------------------------------------------------------------------- */
void init64(unsigned long  an[], unsigned long bigPart, unsigned long littlePart ){
  an[0]=bigPart;
  an[1]=littlePart;
}

/* -------------------------------------------------------------------------
   FUNCTION: HZto64
   create a 64 bit Hz number from
   32 bit xxxx MHz number and 32 bit yyy yyy Hz number.
   A) if an < 2^32 bits 
      an(upper 32b) = 0
      an(lower 32b) = MHzPart(32b)*1MHz + HzPart (32b)
   B) if an > 2^32 bits (4,294,967,296) 
     an(upper 32b) = 1
     an(lower 32b) = ((MHzPart-4294)*1MHz+HzPart)-967296
---------------------------------------------------------------------------- */
void HZto64(unsigned long  an[], unsigned long MHzPart, unsigned long HzPart ){

if((MHzPart>4295) || ((MHzPart==4294) && (HzPart>=967296))){
  an[0]=1L;                                        // upper 32 bits 
  an[1] =(MHzPart-4294L)*OneMHz + HzPart-967296L;  // lower 32 bits
  }
else {
  an[0] = 0;                        // upper 32 bits
  an[1] = MHzPart*OneMHz+HzPart;    // lower 32 bits
  }
}

/* -------------------------------------------------------------------------
   FUNCTION: shl64
   Single Bit shift left of equivalent 64 bit number (an[] = an[]<<1)
---------------------------------------------------------------------------- */
void shl64(unsigned long  an[]){
 an[0] <<= 1; 
 if(an[1] & 0x80000000)
   an[0]++; 
 an[1] <<= 1; 
}


/* -------------------------------------------------------------------------
   FUNCTION: shr64
   Single Bit shift right of equivalent 64 bit number (an[] = an[]>>1)
---------------------------------------------------------------------------- */
void shr64(unsigned long  an[]){
 an[1] >>= 1; 
 if(an[0] & 0x1)
   an[1]+=0x80000000; 
 an[0] >>= 1; 
}


/* -------------------------------------------------------------------------
   FUNCTION: shl64by
   Multi Bit shift left of equivalent 64 bit number (an[] = an[]<<shiftnum)
---------------------------------------------------------------------------- */
void shl64by(unsigned long  an[], uint8_t shiftnum){
uint8_t i;

for(i=0; i<shiftnum; i++) {
   an[0] <<= 1; 
   if(an[1] & 0x80000000)
      an[0]++; 
   an[1] <<= 1; 
   }
}


/* -------------------------------------------------------------------------
   FUNCTION: shr64by
   Multi Bit shift right of equivalent 64 bit number (an[] = an[]>>shiftnum)
---------------------------------------------------------------------------- */
void shr64by(unsigned long  an[], uint8_t shiftnum){
uint8_t i;

for(i=0; i<shiftnum; i++) {
   an[1] >>= 1; 
   if(an[0] & 0x1)
      an[1]+=0x80000000; 
   an[0] >>= 1; 
   }
}


/* -------------------------------------------------------------------------
   FUNCTION: add64
   64 bit Add ann to an (an[] = an[] + ann[])
---------------------------------------------------------------------------- */
void add64(unsigned long  an[], unsigned long  ann[]){
  an[0]+=ann[0];
  if(an[1] + ann[1] < ann[1])
    an[0]++;
  an[1]+=ann[1];
}


/* -------------------------------------------------------------------------
   FUNCTION: sub64
   64 bit Subtract ann from an (an[] = an[] - ann[])
---------------------------------------------------------------------------- */
void sub64(unsigned long  an[], unsigned long  ann[]){
  an[0]-=ann[0];
  if(an[1] < ann[1]){
    an[0]--;
  }
  an[1]-= ann[1];
}


/* -------------------------------------------------------------------------
   FUNCTION: eq64
   64 bit, if an == ann, then true
---------------------------------------------------------------------------- */
boolean eq64(unsigned long  an[], unsigned long  ann[]){
  return (an[0]==ann[0]) && (an[1]==ann[1]);
}


/* -------------------------------------------------------------------------
   FUNCTION: lt64
   64 bit, if an < ann, then true
---------------------------------------------------------------------------- */
boolean lt64(unsigned long  an[], unsigned long  ann[]){
  if(an[0]>ann[0]) return false;
  return (an[0]<ann[0]) || (an[1]<ann[1]);
}


/* -------------------------------------------------------------------------
   FUNCTION: div64
   64 bit Divide,   num=num/div
---------------------------------------------------------------------------- */
void div64(unsigned long num[], unsigned long den[]){
  unsigned long quot[2];
  unsigned long qbit[2];
  unsigned long tmp[2];
  init64(quot,0,0);
  init64(qbit,0,1);

  if (eq64(num, zero64)) {  //numerator 0, call it 0
    init64(num,0,0);
    return;            
  }

  if (eq64(den, zero64)) { //numerator not zero, denominator 0, infinity in my book.
    init64(num,0xffffffff,0xffffffff);
    return;            
  }

  init64(tmp,0x80000000,0);
  while(lt64(den,tmp)){
    shl64(den);
    shl64(qbit);
  } 
  
  while(!eq64(qbit,zero64)){
    if(lt64(den,num) || eq64(den,num)){
      sub64(num,den);
      add64(quot,qbit);
    }
    shr64(den);
    shr64(qbit);
  }

  //remainder now in num, but using it to return quotient for now  
  init64(num,quot[0],quot[1]); 
}


/* -------------------------------------------------------------------------
   FUNCTION: mul64
   64 bit multiply,   an=an*ann
---------------------------------------------------------------------------- */
void mul64(unsigned long an[], unsigned long ann[]){
  unsigned long p[2] = {0,0};
  unsigned long y[2] = {ann[0], ann[1]};
  while(!eq64(y,zero64)) {
    if(y[1] & 1) 
      add64(p,an);
    shl64(an);
    shr64(y);
  }
  init64(an,p[0],p[1]);
} 

Technical Support