Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
LTC6948.cpp
Go to the documentation of this file.
1 /*!
2  LTC6948: Ultralow Noise and Spurious 0.37GHz to 6.39GHz FracN Synthesizer with Integrated VCO
3 
4 @verbatim
5 
6 The LTC®6948 is a high performance, low noise, 6.39GHz
7 phase-locked loop (PLL) with a fully integrated VCO,
8 including a reference divider, phase-frequency detector
9 (PFD), ultralow noise charge pump, fractional feedback
10 divider, and VCO output divider.
11 
12 The fractional divider uses an advanced, 4th order ΔΣ
13 modulator which provides exceptionally low spurious
14 levels. This allows wide loop bandwidths, producing extremely
15 low integrated phase noise values.
16 
17 The programmable VCO output divider, with a range of 1
18 through 6, extends the output frequency range.
19 
20 @endverbatim
21 
22 
23 http://www.linear.com/product/LTC6948
24 
25 http://www.linear.com/product/LTC6948#demoboards
26 
27 
28 Copyright 2018(c) Analog Devices, Inc.
29 
30 All rights reserved.
31 
32 Redistribution and use in source and binary forms, with or without
33 modification, are permitted provided that the following conditions are met:
34  - Redistributions of source code must retain the above copyright
35  notice, this list of conditions and the following disclaimer.
36  - Redistributions in binary form must reproduce the above copyright
37  notice, this list of conditions and the following disclaimer in
38  the documentation and/or other materials provided with the
39  distribution.
40  - Neither the name of Analog Devices, Inc. nor the names of its
41  contributors may be used to endorse or promote products derived
42  from this software without specific prior written permission.
43  - The use of this software may or may not infringe the patent rights
44  of one or more patent holders. This license does not release you
45  from the requirement that you obtain separate licenses from these
46  patent holders to use this software.
47  - Use of the software either in source or binary form, must be run
48  on or directly connected to an Analog Devices Inc. component.
49 
50 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
51 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
52 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
54 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
56 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
57 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
58 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 */
61 
62 //! @ingroup RF_Timing
63 //! @{
64 //! @defgroup LTC6948 LTC6948: Ultralow Noise and Spurious 0.37GHz to 6.39GHz FracN Synthesizer with Integrated VCO
65 //! @}
66 
67 /*! @file
68  @ingroup LTC6948
69  Library for LTC6948: Ultralow Noise and Spurious 0.37GHz to 6.39GHz FracN Synthesizer with Integrated VCO
70 */
71 
72 #include <stdint.h>
73 #include <Arduino.h>
74 #include "Linduino.h"
75 #include "UserInterface.h"
76 #include "LT_SPI.h"
77 #include "LTC6948.h"
78 #include <SPI.h>
79 
80 uint8_t LTC6948_reg[LTC6948_NUM_REGADDR]; //!< number of LTC6948 spi addresses
81 uint8_t LTC6948_spi_map[(LTC6948_NUM_REGFIELD+1)][4]; //!< LTC6948 spi map, stores MSB address location, MSB bit location, field length in bits, and R or RW capability
82 
83 unsigned long LTC6948_Fref_MHz = 100; //!< Default Fref frequency - MHz portion (xxx); Fref = xxx, yyy,yyy
84 unsigned long LTC6948_Fref_Hz = 0; //!< Default Fref frequency - Hz portion (yyy,yyy); Fref = x,xxx, yyy,yyy
85 unsigned long LTC6948_Frf_MHz = 907; //!< Default Frf frequency - MHz portion (xxxx); Frf = x,xxx, yyy,yyy
86 unsigned long LTC6948_Frf_Hz = 0; //!< Default Frf frequency - Hz portion (yyy,yyy); Frf = x,xxx, yyy,yyy
87 
88 unsigned long zero64[]= {0,0}; //!< for 64bit math functions
89 
90 /* -------------------------------------------------------------------------
91  FUNCTION: LTC6948_read
92  - reads 8 bit Data field to LTC6948.
93  - has to shift data by one bit to account for RW bit
94  -------------------------------------------------------------------------- */
95 uint8_t LTC6948_read(uint8_t cs, int8_t address)
96 {
97  int8_t address_shift;
99 
100  address_shift =(address << 1) | 0x01; // shift to left to account for R/W bit, set bit high for read
101  spi_transfer_word(cs, address_shift<<8 , &rx.LT_uint16);
102 
103  LTC6948_reg[address]=rx.LT_byte[0];
104  return(rx.LT_byte[0]);
105 }
106 
107 
108 /* -------------------------------------------------------------------------
109  FUNCTION: LTC6948_read_field
110  For SPI FIELDS located in 1 or multiple address location
111  - reads specific address locations
112  - identifies and returns specific field in question
113  - can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
114 --------------------------------------------------------------------------- */
115 long LTC6948_read_field(uint8_t cs, uint8_t address, uint8_t MSB_loc, uint8_t numbits)
116 {
117  int bit_shift, i, num_reg;
118  long field_val, maskbits, pow2;
119 
120  num_reg=0;
121  field_val=0;
122 // determines how many register are used
123  do
124  {
125  bit_shift = (MSB_loc+1)- (numbits-num_reg*8); // determines bit_shift for last register location
126  field_val=LTC6948_read(cs, (address+num_reg))+(field_val<<8); // reads current address locations, shifts previous address location 8 bits
127  num_reg++;
128  }
129  while ((bit_shift<0) && (num_reg<4));
130 
131 // creates a bit mask for complete word,
132  maskbits = 1;
133  pow2=1;
134  for (i=1, maskbits=1; i<numbits; i++)
135  {
136  pow2=pow2*2;
137  maskbits = maskbits+pow2;
138  }
139 
140  field_val=(field_val >>bit_shift) &maskbits;
141  return field_val;
142 }
143 
144 /* -------------------------------------------------------------------------
145  FUNCTION: get_LTC6948_SPI_FIELD
146  For SPI FIELDS
147  - reads specific address locations
148  - identifies and returns specific field in question
149  - can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
150 --------------------------------------------------------------------------- */
151 long get_LTC6948_SPI_FIELD(uint8_t cs, uint8_t f)
152 {
153 
155 }
156 
157 /* -------------------------------------------------------------------------
158  FUNCTION: LTC6948_write
159  - writes 8 bit Data field to LTC6948.
160  - has to shift data by one bit to account for RW bit
161 --------------------------------------------------------------------------- */
162 void LTC6948_write(uint8_t cs, uint8_t address, uint8_t Data)
163 {
165 
166  address=address << 1; // shift to left to account for R/W bit
167  spi_transfer_word(cs, (address<<8) | Data, &rx.LT_uint16);
168 }
169 
170 
171 /* -------------------------------------------------------------------------
172  FUNCTION: LTC6948_write_field
173  For SPI FIELDS
174  - reads specific address location
175  - identifies and returns specific field in question
176  - can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
177 ---------------------------------------------------------------------------- */
178 uint8_t LTC6948_write_field(uint8_t cs, long field_data, uint8_t address, uint8_t MSB_loc, uint8_t numbits)
179 {
180  long current_content, desired_content, reg_val;
181  int LSB_loc, i, j, num_reg, bit_shift;
182  long temp_arr[32];
183 
184  for (i=0; i<32 ; i++) temp_arr[i]=0; // init temp_arr
185 
186 // read data in current address location and put in a bit array
187  num_reg=0;
188  current_content=0;
189  do
190  {
191  bit_shift=(MSB_loc+1)-(numbits-num_reg*8);
192  current_content=LTC6948_read(cs, (address+num_reg)) + (current_content<<8);
193 
194  num_reg++;
195  }
196  while ((bit_shift<0) && (num_reg<4));
197  for (i=0; i<(8*num_reg); i++)
198  {
199  temp_arr[i]=(current_content>>i) & 1;
200  }
201 
202 // exchange current bits with desired bits
203  LSB_loc = 8*(num_reg-1)+MSB_loc-numbits+1;
204  for (i=LSB_loc, j=0; i<=(MSB_loc+(num_reg-1)*8); i++, j++)
205  {
206  temp_arr[i] = (field_data>>j) &1;
207  } // end of for loop
208 
209 // reconstruct bits into an integer
210  desired_content = 0;
211  for (i=0; i<(8*num_reg); i++)
212  {
213  desired_content = desired_content | (temp_arr[i]<<i);
214  } // end of for loop
215 
216 // write new field value to part
217  for (i=0; i<num_reg; i++)
218  {
219  reg_val = (desired_content >> 8*(num_reg-1-i)) & 0xff;
220  LTC6948_write(cs, (address+i), reg_val);
221  } // end of for loop
222 } // end of LTC6948_write_field
223 
224 
225 /* -------------------------------------------------------------------------
226  FUNCTION: get_LTC6948_REGSIZE
227  - returns # of addresses in parts register map (array size)
228 ---------------------------------------------------------------------------- */
230 {
231  return sizeof(LTC6948_reg);
232 }
233 
234 
235 /* -------------------------------------------------------------------------
236  FUNCTION: get_LTC6948_SPI_FIELD_NUMBITS
237  - returns the number of bits for a given field name in the SPI map
238 ---------------------------------------------------------------------------- */
240 {
241  return LTC6948_spi_map[f][NUMBITS];
242 }
243 
244 
245 /* -------------------------------------------------------------------------
246  FUNCTION: get_LTC6948_SPI_FIELD_RW
247  - returns if the given field name is (0)read/write or (1)read_only field
248 ---------------------------------------------------------------------------- */
249 uint8_t get_LTC6948_SPI_FIELD_RW(uint8_t f)
250 {
251  return LTC6948_spi_map[f][R_ONLY];
252 }
253 
254 
255 /* -------------------------------------------------------------------------
256  FUNCTION: set_LTC6948_SPI_FIELD
257  For SPI FIELDS
258  - reads specific address location
259  - identifies and returns specific field in question
260  - can handle SPI fields in multiple addresses, if MSB bit is in the lower number address
261 ---------------------------------------------------------------------------- */
262 void set_LTC6948_SPI_FIELD(uint8_t cs, uint8_t f, long field_data)
263 {
265 }
266 
267 
268 /* -------------------------------------------------------------------------
269  FUNCTION: set_LTC6948_ALLREGS
270  - writes data to all registers at once
271 --------------------------------------------------------------------------- */
272 void set_LTC6948_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)
273 {
274  uint8_t i;
275 
276  LTC6948_reg[1] = reg01;
277  LTC6948_reg[2] = reg02;
278  LTC6948_reg[3] = reg03;
279  LTC6948_reg[4] = reg04;
280  LTC6948_reg[5] = reg05;
281  LTC6948_reg[6] = reg06;
282  LTC6948_reg[7] = reg07;
283  LTC6948_reg[8] = reg08;
284  LTC6948_reg[9] = reg09;
285  LTC6948_reg[10] = reg0A;
286  LTC6948_reg[11] = reg0B;
287  LTC6948_reg[12] = reg0C;
288  LTC6948_reg[13] = reg0D;
289 
290  for (i=1; i<14; i++) LTC6948_write(cs, i, LTC6948_reg[i]);
291 } // end of set_LTC6948_ALLREGS
292 
293 
294 /* -------------------------------------------------------------------------
295  FUNCTION: LTC6948_init
296  - initializes the SPI MAP
297  - for ease of programming there is spreadsheet that automates this some.
298 ----------------------------------------------------------------------------*/
300 {
301 
302 // spi map
453 
504 
505 } // end of LTC6948_init
506 
507 void set_LTC6948_global_fref(unsigned long fref_MHz, unsigned long fref_Hz)
508 {
509  LTC6948_Fref_MHz=fref_MHz;
510  LTC6948_Fref_Hz=fref_Hz;
511 }
512 
513 void set_LTC6948_global_frf(unsigned long frf_MHz, unsigned long frf_Hz)
514 {
515  LTC6948_Frf_MHz=frf_MHz;
516  LTC6948_Frf_Hz=frf_Hz;
517 }
518 
520 {
521  return LTC6948_Fref_MHz;
522 }
523 
525 {
526  return LTC6948_Fref_Hz;
527 }
528 
530 {
531  return LTC6948_Frf_MHz;
532 }
533 
535 {
536  return LTC6948_Frf_Hz;
537 }
538 
539 
540 /* -------------------------------------------------------------------------
541  FUNCTION: calc_odiv
542  - calculates the output divider setting based on the frf and version of LTC6948
543  - @return odiv = 1-6 for valid setting, 999 as invalid frequency
544 ---------------------------------------------------------------------------- */
545 unsigned long LTC6948_calc_odiv(char part_version[], unsigned long frf[2])
546 {
547  unsigned long odiv, max_fout, min_fout, temp_val,i, temp_out;
548  unsigned long max_fout64[2];
549  unsigned long min_fout64[2];
550  unsigned long temp_fout[2];
551  unsigned long temp_i[2];
552  boolean valid_input=false;
553 
554 // Determine which frequency range to verify too based on part version
555  if (part_version[8]=='1') // if this is a LTC6948-1
556  {
557  max_fout=LTC6948_1_MAXFREQ;
558  min_fout=LTC6948_1_MINFREQ;
559  }
560  else if (part_version[8]=='2') // if this is a LTC6948-2
561  {
562  max_fout=LTC6948_2_MAXFREQ;
563  min_fout=LTC6948_2_MINFREQ;
564  }
565  else if (part_version[8]=='3') // if this is a LTC6948-3
566  {
567  max_fout=LTC6948_3_MAXFREQ;
568  min_fout=LTC6948_3_MINFREQ;
569  }
570  else if (part_version[8]=='4') // if this is a LTC6948-4
571  {
572  max_fout=LTC6948_4_MAXFREQ;
573  min_fout=LTC6948_4_MINFREQ;
574  }
575  else
576  {
577  Serial.print("No default Frequencies for this board: ");
578  Serial.println(part_version);
579  } // end if-then-else statement
580  HZto64(max_fout64,max_fout,0L);
581  HZto64(min_fout64,min_fout,0L);
582 
583 // verify desired frequency falls within a divider range (1-6)
584  valid_input=false;
585  for (i=1; i<=6; i++)
586  {
587  init64(temp_i,0L,i);
588  temp_fout[0] = frf[0];
589  temp_fout[1] = frf[1];
590  mul64(temp_fout,temp_i);
591  if (lt64(temp_fout,max_fout64) || eq64(temp_fout, max_fout64)) // same as frf*i <= max_fout
592  {
593  if (lt64(min_fout64,temp_fout) || eq64(temp_fout, min_fout64)) // same as frf*i >= min_fout
594  {
595  valid_input=true;
596  odiv=i;
597  }
598  }
599  } // end of for loop
600 
601  if (valid_input == false) odiv= 999L;
602  return odiv;
603 
604 } // end of LTC6948_calc_odiv
605 
606 /* -------------------------------------------------------------------------
607  FUNCTION: LTC6948_set_frf
608  Calculates the integer (N), fractional (NUM) and output divider (OD) SPI values
609  using self created 64bit math functions.
610 
611  Datasheet equations
612  fvco = fpfd*(N + F)
613  frf = fvco/O
614  fpfd = fref/R
615  F=NUM/2^18 = NUM/262144
616 
617  can be modified to the following equations
618  N = (int) (fvco/fpfd) = (int) frf*O*R/fref
619  NUM = (int) [262144 * (frf*O*R/fref -N)]
620 
621  where
622  N = ndiv, O= odiv, NUM=fracN_num in the code below
623 
624  Linduino One (Arduino Uno) is limited to 32 bit floats/double/long.
625  32 bit math functions will create rounding errors with the above equations,
626  that can result in frequency errors.
627  Therefore, the following code uses self created 64bit functions for 64bit integer math.
628 
629  frf (33 bits) LTC6948-4 max frf/fvco = 6.4GHZ, which is 23 bit number (2^33 = 8.59G)
630  fref (23 bits) LTC6948 min fref = 10MHz, which is a 23 bit number (2^23 = 8.3M)
631  O (3 bits)
632  R (5 bits)
633 
634  step 1: create 64 bit frf and fref numbers
635 
636  step 2: calculate O (output divider)
637 
638  step 3: get current R-divider setting
639 
640  step 4: calculate frf*O*R
641  max bit count/resolution: 33b+3b+5b= 41b
642  step 5: calculate N(10b), using value from step 1
643  N = (int) frf*O*R/fref
644  max bit count/resolution: 41b-23b = 18b
645  step 6: calculate NUM (18b)
646  NUM = (int) [262144 * (frf*O*R/fref -N)]
647  = (int) [2^18 * (frf*O*R/fref -N)]
648  to get the correct value the above calculation are performed like this
649  = ((int)((frf*O*R/fref)<<23) - N<<23 + rounding) >> 5, where << & >> are bit shift left, right
650  * note << 23b was chosen, because step one use 41b, 41b +23b = 64b (max number for 64 bit math)
651  ** note >> 5 was chosen because 23-5 = 2^18, which is the same as multiplying by 262144
652  *** the rounding variable is equivalent to adding 0.5 to the NUM number. The integer operation always
653  rounds down, so adding a 0.5 to the number before rounding down ensures the closest value is
654  selected.
655  In this function the lower 5 bits of (frf*O*R/fref)<<23) - N<<23 (possible variable 0-31)
656  are check to see if they are >=16.
657  If they are then 16 is added to this number before performing the int and >>5 functions.
658 ---------------------------------------------------------------------------- */
659 void LTC6948_set_frf(char part_version[])
660 {
661  unsigned long frf_MHz, frf_Hz, fref_MHz, fref_Hz, odiv, rdiv, ndiv, fracN_num, frac_num_remainder;
662  unsigned long N64[2], NUM64[2], R64[2], O64[2], temp_long[2];
663  char buffer[100];
664  unsigned long frf[2], frf_act[2];
665  unsigned long fref[2];
666  unsigned long temp_math[2];
667  unsigned long frf_rdiv_odiv[2];
668  unsigned long frf_rdiv_odiv_int[2];
669  unsigned long roundup[2];
670 
671  /* step 1: create 64 bit frf and fref numbers
672  32 bit xxxx MHz number and 32 bit yyy yyy Hz number. */
673  frf_MHz=LTC6948_Frf_MHz;
674  frf_Hz=LTC6948_Frf_Hz;
675  HZto64(frf, frf_MHz, frf_Hz);
676 
677  fref_MHz=LTC6948_Fref_MHz;
678  fref_Hz=LTC6948_Fref_Hz;
679  HZto64(fref,fref_MHz,fref_Hz);
680 
681 // step 2: calculate O (output divider)
682  odiv=LTC6948_calc_odiv(part_version,frf);
683 
684 // step 3: get current R-divider setting
685  rdiv=get_LTC6948_SPI_FIELD(LTC6948_CS,LTC6948_RD); // reads selected field
686 
687 // step 3: calculate frf*O*R
688  frf_rdiv_odiv[0]=0;
689  frf_rdiv_odiv[1]=odiv*rdiv;
690  mul64(frf_rdiv_odiv, frf); // odiv*rdiv*frf
691  frf_rdiv_odiv_int[0]=frf_rdiv_odiv[0]; // copy odiv*rdiv*frf to another variable
692  frf_rdiv_odiv_int[1]=frf_rdiv_odiv[1];
693 
694 // step 4: calculate N(10b), using value from step 3; N = (int) frf*O*R/fref
695  temp_math[0]=fref[0]; // copy fref to temp variable for math operation
696  temp_math[1]=fref[1];
697  div64(frf_rdiv_odiv_int, temp_math); // frf_rdiv_odiv_int= [(frf*odiv*rdiv)]/fref --> int(fvco/fpfd)
698  ndiv=frf_rdiv_odiv_int[1];
699 
700 // step 5: calculate NUM (18b), NUM = (int) [262144 * (frf*O*R/fref -N)]
701 // SEE notes in function header for step 5
702 // ((int)((frf*O*R/fref)<<23) - N<<23 + rounding) >> 5, where << & >> are bit shift left, right
703  shl64by(frf_rdiv_odiv,23);
704  div64(frf_rdiv_odiv, fref); // frf_rdiv_odiv --> [(frf*odiv*rdiv)<<23]/fref
705 
706  shl64by(frf_rdiv_odiv_int,23); // frf_rdiv_odiv_int --> [(int)((frf*odiv*rdiv)/fref)] <<23
707 
708  sub64(frf_rdiv_odiv,frf_rdiv_odiv_int);
709 
710 // NUM is a 18 bit number in the spi register
711 // At this point in the program it is represented by 23 bits
712 // if the lower 5 bits are >=16 (16/31),
713 // then add 16 to the frac_num_remainder. After the bits are
714 // shifted down 5 bits this will be close to added 0.5 bits.
715  frac_num_remainder=(frf_rdiv_odiv[1] & 31L);
716  if (frac_num_remainder >= 16L)
717  {
718  roundup[0]=0L;
719  roundup[1]=16L;
720  add64(frf_rdiv_odiv,roundup);
721  }
722 
723 // shift NUM to get desired 18 bit number for SPI map.
724  shr64by(frf_rdiv_odiv,5);
725  fracN_num=frf_rdiv_odiv[1];
726 
727 // program part and print out results to screen
728  set_LTC6948_SPI_FIELD(LTC6948_CS,LTC6948_OD,odiv); // programs output divider
729  Serial.print("OD = ");
730  Serial.println(odiv);
731 
732  Serial.print("RD = ");
733  Serial.println(rdiv);
734 
735  set_LTC6948_SPI_FIELD(LTC6948_CS,LTC6948_ND,ndiv); // programs N-divider
736  Serial.print(F("ND = "));
737  Serial.println(ndiv);
738 
739  if (fracN_num > 0L)
740  {
741  set_LTC6948_SPI_FIELD(LTC6948_CS,LTC6948_INTN,0L); // programs fractional mode
742  set_LTC6948_SPI_FIELD(LTC6948_CS,LTC6948_NUM,fracN_num); // programs NUM
743  if ( (ndiv<35) || (ndiv>1019) ) Serial.print(F("N DIV set to invalid setting - REFER TO DATASHEET\n"));
744  }
745  else
746  {
747  set_LTC6948_SPI_FIELD(LTC6948_CS,LTC6948_INTN,1L); // programs INTN
748  Serial.print(F("When NUM=0, changes to Integer Mode (NUM can not be 0)\n"));
749  if ( (ndiv<32) || (ndiv>1023) ) Serial.print(F("N DIV set to invalid setting - REFER TO DATASHEET\n"));
750  }
751  Serial.print(F("NUM = "));
752  Serial.println(fracN_num);
753 
754  set_LTC6948_SPI_FIELD(LTC6948_CS,LTC6948_CAL,1); // calibrates part
755 
756 
757 ///// calculate actual fout here and print out
758  frf_act[0]=fref[0];
759  frf_act[1]=fref[1];
760  N64[0]=0;
761  NUM64[0]=0;
762  R64[0]=0;
763  O64[0]=0;
764  N64[1]=ndiv;
765  NUM64[1]=fracN_num;
766  R64[1]=rdiv;
767  O64[1]=odiv;
768 
769  shl64by(N64,18);
770  add64(N64,NUM64); // (N*262144 +NUM)
771  div64(frf_act,R64); // fref/rdiv (or fpfd)
772  mul64(frf_act,N64); // (N*262144 +NUM)*fpdf
773  div64(frf_act,O64); // ((N*262144 +NUM)*fpdf)/odiv
774  shr64by(frf_act,17);
775  if (frf_act[0]==0) // no 32 bit overflow case
776  {
777  Serial.print(F("Actual Output Frequency (closest available) is "));
778  Serial.print(frf_act[1]);
779  Serial.println("Hz");
780  }
781  else // overflow case
782  {
783  temp_math[0]=frf_act[0];
784  temp_math[1]=frf_act[1];
785  temp_long[0]=0;
786  temp_long[1]=OneMHz;
787  div64(temp_math,temp_long); // frf/1e6
788  Serial.print(F("Actual Output Frequency (closest available) is "));
789  Serial.print(temp_math[1]);
790  Serial.print("MHz + ");
791  temp_long[0]=0;
792  temp_long[1]=OneMHz;
793  mul64(temp_math,temp_long); // int(frf/1e6)*1e6
794  sub64(frf_act,temp_math); // frf-int(frf/1e6)*1e6
795  Serial.print(frf_act[1]);
796  Serial.println("Hz");
797  }
798 }
799 
800 
801 /* -------------------------------------------------------------------------
802  FUNCTION: prt
803  Prints HEX representation of 64 bit an
804 ---------------------------------------------------------------------------- */
805 void prt(unsigned long an[])
806 {
807  Serial.print(an[0],HEX);
808  Serial.print(" ");
809  Serial.println(an[1],HEX);
810 }
811 
812 
813 /* -------------------------------------------------------------------------
814  FUNCTION: init64
815  Creates a equivalent 64 bit number from 2 32 bit numbers
816  an[0]=bigPart //upper 32 bits
817  an[1]=littlePart //lower 32 bits
818 ---------------------------------------------------------------------------- */
819 void init64(unsigned long an[], unsigned long bigPart, unsigned long littlePart )
820 {
821  an[0]=bigPart;
822  an[1]=littlePart;
823 }
824 
825 /* -------------------------------------------------------------------------
826  FUNCTION: HZto64
827  create a 64 bit Hz number from
828  32 bit xxxx MHz number and 32 bit yyy yyy Hz number.
829  A) if an < 2^32 bits
830  an(upper 32b) = 0
831  an(lower 32b) = MHzPart(32b)*1MHz + HzPart (32b)
832  B) if an > 2^32 bits (4,294,967,296)
833  an(upper 32b) = 1
834  an(lower 32b) = ((MHzPart-4294)*1MHz+HzPart)-967296
835 ---------------------------------------------------------------------------- */
836 void HZto64(unsigned long an[], unsigned long MHzPart, unsigned long HzPart )
837 {
838 
839  if ((MHzPart>4295) || ((MHzPart==4294) && (HzPart>=967296)))
840  {
841  an[0]=1L; // upper 32 bits
842  an[1] =(MHzPart-4294L)*OneMHz + HzPart-967296L; // lower 32 bits
843  }
844  else
845  {
846  an[0] = 0; // upper 32 bits
847  an[1] = MHzPart*OneMHz+HzPart; // lower 32 bits
848  }
849 }
850 
851 /* -------------------------------------------------------------------------
852  FUNCTION: shl64
853  Single Bit shift left of equivalent 64 bit number (an[] = an[]<<1)
854 ---------------------------------------------------------------------------- */
855 void shl64(unsigned long an[])
856 {
857  an[0] <<= 1;
858  if (an[1] & 0x80000000)
859  an[0]++;
860  an[1] <<= 1;
861 }
862 
863 
864 /* -------------------------------------------------------------------------
865  FUNCTION: shr64
866  Single Bit shift right of equivalent 64 bit number (an[] = an[]>>1)
867 ---------------------------------------------------------------------------- */
868 void shr64(unsigned long an[])
869 {
870  an[1] >>= 1;
871  if (an[0] & 0x1)
872  an[1]+=0x80000000;
873  an[0] >>= 1;
874 }
875 
876 
877 /* -------------------------------------------------------------------------
878  FUNCTION: shl64by
879  Multi Bit shift left of equivalent 64 bit number (an[] = an[]<<shiftnum)
880 ---------------------------------------------------------------------------- */
881 void shl64by(unsigned long an[], uint8_t shiftnum)
882 {
883  uint8_t i;
884 
885  for (i=0; i<shiftnum; i++)
886  {
887  an[0] <<= 1;
888  if (an[1] & 0x80000000)
889  an[0]++;
890  an[1] <<= 1;
891  }
892 }
893 
894 
895 /* -------------------------------------------------------------------------
896  FUNCTION: shr64by
897  Multi Bit shift right of equivalent 64 bit number (an[] = an[]>>shiftnum)
898 ---------------------------------------------------------------------------- */
899 void shr64by(unsigned long an[], uint8_t shiftnum)
900 {
901  uint8_t i;
902 
903  for (i=0; i<shiftnum; i++)
904  {
905  an[1] >>= 1;
906  if (an[0] & 0x1)
907  an[1]+=0x80000000;
908  an[0] >>= 1;
909  }
910 }
911 
912 
913 /* -------------------------------------------------------------------------
914  FUNCTION: add64
915  64 bit Add ann to an (an[] = an[] + ann[])
916 ---------------------------------------------------------------------------- */
917 void add64(unsigned long an[], unsigned long ann[])
918 {
919  an[0]+=ann[0];
920  if (an[1] + ann[1] < ann[1])
921  an[0]++;
922  an[1]+=ann[1];
923 }
924 
925 
926 /* -------------------------------------------------------------------------
927  FUNCTION: sub64
928  64 bit Subtract ann from an (an[] = an[] - ann[])
929 ---------------------------------------------------------------------------- */
930 void sub64(unsigned long an[], unsigned long ann[])
931 {
932  an[0]-=ann[0];
933  if (an[1] < ann[1])
934  {
935  an[0]--;
936  }
937  an[1]-= ann[1];
938 }
939 
940 
941 /* -------------------------------------------------------------------------
942  FUNCTION: eq64
943  64 bit, if an == ann, then true
944 ---------------------------------------------------------------------------- */
945 boolean eq64(unsigned long an[], unsigned long ann[])
946 {
947  return (an[0]==ann[0]) && (an[1]==ann[1]);
948 }
949 
950 
951 /* -------------------------------------------------------------------------
952  FUNCTION: lt64
953  64 bit, if an < ann, then true
954 ---------------------------------------------------------------------------- */
955 boolean lt64(unsigned long an[], unsigned long ann[])
956 {
957  if (an[0]>ann[0]) return false;
958  return (an[0]<ann[0]) || (an[1]<ann[1]);
959 }
960 
961 
962 /* -------------------------------------------------------------------------
963  FUNCTION: div64
964  64 bit Divide, num=num/div
965 ---------------------------------------------------------------------------- */
966 void div64(unsigned long num[], unsigned long den[])
967 {
968  unsigned long quot[2];
969  unsigned long qbit[2];
970  unsigned long tmp[2];
971  init64(quot,0,0);
972  init64(qbit,0,1);
973 
974  if (eq64(num, zero64)) //numerator 0, call it 0
975  {
976  init64(num,0,0);
977  return;
978  }
979 
980  if (eq64(den, zero64)) //numerator not zero, denominator 0, infinity in my book.
981  {
982  init64(num,0xffffffff,0xffffffff);
983  return;
984  }
985 
986  init64(tmp,0x80000000,0);
987  while (lt64(den,tmp))
988  {
989  shl64(den);
990  shl64(qbit);
991  }
992 
993  while (!eq64(qbit,zero64))
994  {
995  if (lt64(den,num) || eq64(den,num))
996  {
997  sub64(num,den);
998  add64(quot,qbit);
999  }
1000  shr64(den);
1001  shr64(qbit);
1002  }
1003 
1004  //remainder now in num, but using it to return quotient for now
1005  init64(num,quot[0],quot[1]);
1006 }
1007 
1008 
1009 /* -------------------------------------------------------------------------
1010  FUNCTION: mul64
1011  64 bit multiply, an=an*ann
1012 ---------------------------------------------------------------------------- */
1013 void mul64(unsigned long an[], unsigned long ann[])
1014 {
1015  unsigned long p[2] = {0,0};
1016  unsigned long y[2] = {ann[0], ann[1]};
1017  while (!eq64(y,zero64))
1018  {
1019  if (y[1] & 1)
1020  add64(p,an);
1021  shl64(an);
1022  shr64(y);
1023  }
1024  init64(an,p[0],p[1]);
1025 }
void init64(unsigned long an[], unsigned long bigPart, unsigned long littlePart)
Creates a equivalent 64 bit number from 2 32 bit numbers.
Definition: LTC6948.cpp:819
void mul64(unsigned long an[], unsigned long ann[])
64 bit multiply, an=an*ann
Definition: LTC6948.cpp:1013
#define LTC6948_2_MINFREQ
LTC6948-2 lower freq limit.
Definition: LTC6948.h:149
#define LTC6948_3_MINFREQ
LTC6948-3 lower freq limit.
Definition: LTC6948.h:150
uint8_t LTC6948_read(uint8_t cs, int8_t address)
LTC6948 Read Single Address reads 8 bit Data field to LTC6948.
Definition: LTC6948.cpp:95
void sub64(unsigned long an[], unsigned long ann[])
64 bit Subtract ann from an (an[] = an[] - ann[])
Definition: LTC6948.cpp:930
unsigned long LTC6948_Fref_Hz
Default Fref frequency - Hz portion (yyy,yyy); Fref = x,xxx, yyy,yyy.
Definition: LTC6948.cpp:84
#define LTC6948_UNLOK
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:129
unsigned long LTC6948_Frf_Hz
Default Frf frequency - Hz portion (yyy,yyy); Frf = x,xxx, yyy,yyy.
Definition: LTC6948.cpp:86
#define LTC6948_PDOUT
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:118
#define LTC6948_OMUTE
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:114
#define LTC6948_1_MINFREQ
LTC6948-1 lower freq limit.
Definition: LTC6948.h:148
#define LTC6948_ALCEN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:82
void div64(unsigned long num[], unsigned long den[])
64 bit Divide, num=num/div
Definition: LTC6948.cpp:966
void prt(unsigned long an[])
Prints HEX representation of 64 bit an.
Definition: LTC6948.cpp:805
#define LTC6948_CPCLO
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:94
#define LTC6948_PART
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:115
#define LTC6948_SEED
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:126
#define LTC6948_CPRST
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:99
#define LTC6948_LKWIN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:108
long LTC6948_read_field(uint8_t cs, uint8_t address, uint8_t MSB_loc, uint8_t numbits)
LTC6948 Read Single Field For SPI FIELDS located in 1 or multiple address locations reads specific ad...
Definition: LTC6948.cpp:115
#define LTC6948_LKCT
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:107
long get_LTC6948_SPI_FIELD(uint8_t cs, uint8_t f)
Gets the LTC6948 SPI field value calls function LTC6948_read_field, which reads specific address loca...
Definition: LTC6948.cpp:151
#define LTC6948_ALCULOK
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:86
Header File for Linduino Libraries and Demo Code.
void shl64(unsigned long an[])
Single Bit shift left of equivalent 64 bit number (an[] = an[]<<1)
Definition: LTC6948.cpp:855
#define LTC6948_CPINV
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:96
#define LTC6948_CPCHI
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:93
#define LTC6948_CPUP
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:100
uint8_t get_LTC6948_REGSIZE()
returns # of addresses in parts register map (array size)
Definition: LTC6948.cpp:229
#define LTC6948_RSTFN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:125
#define LTC6948_OD
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:113
void LTC6948_write(uint8_t cs, uint8_t address, uint8_t Data)
LTC6948 Write Single Address writes 8 bit Data field to LTC6948.
Definition: LTC6948.cpp:162
#define LTC6948_NUM
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:112
#define LTC6948_FILT
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:103
#define LTC6948_ALCHI
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:83
#define LTC6948_MTCAL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:110
unsigned long get_LTC6948_global_frf_Hz()
returns global LTC6948_Frf_Hz
Definition: LTC6948.cpp:534
#define LTC6948_AUTORST
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:88
#define OneMHz
1MHz in long format, used in 64 bit math
Definition: LTC6945.h:121
void shr64(unsigned long an[])
Single Bit shift right of equivalent 64 bit number (an[] = an[]<<1)
Definition: LTC6948.cpp:868
#define LTC6948_4_MAXFREQ
LTC6948-4 upper freq limit.
Definition: LTC6948.h:146
void set_LTC6948_SPI_FIELD(uint8_t cs, uint8_t f, long field_data)
Sets the LTC6948 SPI field value calls function LTC6948_read_field, which reads specific address/fiel...
Definition: LTC6948.cpp:262
#define LTC6948_4_MINFREQ
LTC6948-4 lower freq limit.
Definition: LTC6948.h:151
boolean eq64(unsigned long an[], unsigned long ann[])
64 bit, if an == ann, then true
Definition: LTC6948.cpp:945
#define LTC6948_AUTOCAL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:87
unsigned long get_LTC6948_global_fref_Hz()
returns global LTC6948_Fref_Hz
Definition: LTC6948.cpp:524
#define LTC6948_CPMID
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:98
void HZto64(unsigned long an[], unsigned long MHzPart, unsigned long HzPart)
create a 64 bit Hz number from 32 bit xxxx MHz number and 32 bit yyy yyy Hz number.
Definition: LTC6948.cpp:836
#define LTC6948_LDOV
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:106
#define LTC6948_ALCLO
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:84
#define LTC6948_CS
Define the SPI CS pin.
Definition: LTC6948.h:76
#define NUMBITS
Definition: LTC6115.h:69
static uint8_t address
Definition: DC2091A.ino:83
void LTC6948_init()
Initializes the SPI MAP arrays The values set in initialization are used all the LTC6948 SPI/WRITE an...
Definition: LTC6948.cpp:299
#define LTC6948_1_MAXFREQ
LTC6948-1 upper freq limit.
Definition: LTC6948.h:143
uint8_t get_LTC6948_SPI_FIELD_RW(uint8_t f)
returns if the given field name is (0)read/write or (1)read_only field
Definition: LTC6948.cpp:249
void set_LTC6948_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)
Writes values to ALL LTC6948 RW address.
Definition: LTC6948.cpp:272
#define LTC6948_PDFN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:117
#define LTC6948_ND
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:111
uint8_t LTC6948_write_field(uint8_t cs, long field_data, uint8_t address, uint8_t MSB_loc, uint8_t numbits)
LTC6948 Write Single Field For SPI FIELDS in 1 or multiple address locations reads specific address/f...
Definition: LTC6948.cpp:178
uint16_t LT_uint16
16-bit unsigned integer to be converted to two bytes
Definition: Linduino.h:102
#define LTC6948_DITHEN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:102
#define R_ONLY
used for 2nd dim of 2d spi_map array
Definition: LTC6945.h:119
#define LTC6948_PDALL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:116
void spi_transfer_word(uint8_t cs_pin, uint16_t tx, uint16_t *rx)
Reads and sends a word.
Definition: LT_SPI.cpp:98
#define LTC6948_CPWIDE
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:101
#define LTC6948_INTN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:104
#define LTC6948_3_MAXFREQ
LTC6948-3 upper freq limit.
Definition: LTC6948.h:145
uint8_t LTC6948_spi_map[(LTC6948_NUM_REGFIELD+1)][4]
LTC6948 spi map, stores MSB address location, MSB bit location, field length in bits, and R or RW capability.
Definition: LTC6948.cpp:81
#define LTC6948_NUM_REGADDR
Defines number of LTC6948 SPI registers, used in spi_map array.
Definition: LTC6948.h:133
void set_LTC6948_global_fref(unsigned long fref_MHz, unsigned long fref_Hz)
sets globals LTC6948_Fref_MHz and LTC6948_Fref_Hz
Definition: LTC6948.cpp:507
unsigned long zero64[]
for 64bit math functions
Definition: LTC6948.cpp:88
void LTC6948_set_frf(char part_version[])
FUNCTION: LTC6948_set_frf Calculates the integer (N), fractional (NUM) and output divider (OD) SPI va...
Definition: LTC6948.cpp:659
#define LTC6948_POR
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:121
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
#define LTC6948_x
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:130
void set_LTC6948_global_frf(unsigned long frf_MHz, unsigned long frf_Hz)
sets globals LTC6948_Frf_MHz and LTC6948_Frf_Hz
Definition: LTC6948.cpp:513
void add64(unsigned long an[], unsigned long ann[])
64 bit Add ann to an (an[] = an[] + ann[])
Definition: LTC6948.cpp:917
#define LTC6948_CP
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:92
#define LTC6948_THI
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:127
void shr64by(unsigned long an[], uint8_t shiftnum)
Multi Bit shift right of equivalent 64 bit number (an[] = an[]>>shiftnum)
Definition: LTC6948.cpp:899
#define ADDRx
used for 2nd dim of 2d spi_map array
Definition: LTC6945.h:116
unsigned long LTC6948_Fref_MHz
Default Fref frequency - MHz portion (xxx); Fref = xxx, yyy,yyy.
Definition: LTC6948.cpp:83
uint8_t LTC6948_reg[LTC6948_NUM_REGADDR]
number of LTC6948 spi addresses
Definition: LTC6948.cpp:80
#define LTC6948_NUM_REGFIELD
Defines number of LTC6948 SPI fields, used in spi_map array.
Definition: LTC6948.h:134
#define LTC6948_CAL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:91
#define LTC6948_ALCCAL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:81
#define LTC6948_LDOEN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:105
#define LTC6948_REV
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:123
This union splits one int16_t (16-bit signed integer) or uint16_t (16-bit unsigned integer) into two ...
Definition: Linduino.h:99
LTC6948: Ultralow Noise and Spurious 0.37GHz to 6.39GHz FracN Synthesizer with Integrated VCO...
#define LTC6948_ALCMON
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:85
#define LTC6948_BD
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:89
unsigned long get_LTC6948_global_fref_MHz()
returns global LTC6948_Fref_MHz
Definition: LTC6948.cpp:519
static int i
Definition: DC2430A.ino:184
void shl64by(unsigned long an[], uint8_t shiftnum)
Multi Bit shift left of equivalent 64 bit number (an[] = an[]<<shiftnum)
Definition: LTC6948.cpp:881
#define LTC6948_RFO
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:124
#define LTC6948_RD
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:122
uint8_t LT_byte[2]
2 bytes (unsigned 8-bit integers) to be converted to a 16-bit signed or unsigned integer ...
Definition: Linduino.h:103
#define LTC6948_CPLE
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:97
#define LTC6948_2_MAXFREQ
LTC6948-2 upper freq limit.
Definition: LTC6948.h:144
#define LTC6948_PDVCO
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:120
uint8_t get_LTC6948_SPI_FIELD_NUMBITS(uint8_t f)
returns the number of bits for a given field name in the SPI map
Definition: LTC6948.cpp:239
unsigned long LTC6948_calc_odiv(char part_version[], unsigned long frf[2])
calculates the output divider setting based on the frf and version of LTC6948
Definition: LTC6948.cpp:545
unsigned long LTC6948_Frf_MHz
Default Frf frequency - MHz portion (xxxx); Frf = x,xxx, yyy,yyy.
Definition: LTC6948.cpp:85
#define LTC6948_CPDN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:95
#define LTC6948_PDPLL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:119
#define LTC6948_LOCK
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:109
boolean lt64(unsigned long an[], unsigned long ann[])
64 bit, if an < ann, then true
Definition: LTC6948.cpp:955
#define LTC6948_BST
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:90
unsigned long get_LTC6948_global_frf_MHz()
returns global LTC6948_Frf_MHz
Definition: LTC6948.cpp:529
#define DxMSB
used for 2nd dim of 2d spi_map array
Definition: LTC6945.h:117
#define LTC6948_TLO
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6948.h:128