mrfioc2  2.3.0
Files | Classes | Macros | Functions
MrfCommon

Files

file  mrfFracSynth.c
 Support routines for the Micrel SY87739L Fractional-N Synthesizer.
 

Classes

struct  PostDivideStruct
 
struct  CorrectionStruct
 
struct  CorrectionValStruct
 
struct  FracSynthComponents
 

Macros

#define DEBUG_PRINT   /* Debug printing always enabled for this module */
 
#define MAX_CORRECTION_RATIO   (17./14.) /* Maximum value for correction term. */
 
#define MAX_VCO_FREQ   729.0 /* Maximum frequency for voltage-controlled oscillator */
 
#define MIN_VCO_FREQ   540.0 /* Minimum frequency for voltage-controlled oscillator */
 
#define MIN_P_VALUE   17 /* Minimum val for integer part of fractional frequency */
 
#define MAX_FRAC_DIVISOR   31 /* Maximum divisor for fractional frequency value */
 
#define NUM_POST_DIVIDES   31 /* Number of unique post-divider values */
 
#define NUM_POST_DIVIDE_VALS   32 /* Number of post-divider codes */
 
#define NUM_CORRECTIONS   23 /* Number of valid correction values (plus one) */
 
#define NUM_CORRECTION_VALS   8 /* Number of correction value codes */
 
#define MAX_ERROR   100.0 /* Artifical error maximum */
 
#define ZERO_THRESHOLD   1.0e-9 /* Floating point threshold for zero detection */
 
#define CONTROL_MDIV_BITS   3 /* Denominator of correction term */
 
#define CONTROL_NDIV_BITS   3 /* Numerator of correction term */
 
#define CONTROL_POSTDIV_BITS   5 /* Post-Divider */
 
#define CONTROL_MFG_BITS   3 /* Must Be Zero */
 
#define CONTROL_P_BITS   4 /* Integer part of fractional frequency */
 
#define CONTROL_QPM1_BITS   5 /* Value for Q(p-1) term of fractional frequency */
 
#define CONTROL_QP_BITS   5 /* Value for Q(p) term of fractional frequency */
 
#define CONTROL_PREAMBLE_BITS   4 /* Must Be Zero */
 
#define CONTROL_MDIV_SHIFT   0 /* Denominator of correction term */
 
#define CONTROL_NDIV_SHIFT   3 /* Numerator of correction term */
 
#define CONTROL_POSTDIV_SHIFT   6 /* Post-Divider */
 
#define CONTROL_MFG_SHIFT   11 /* Must Be Zero */
 
#define CONTROL_P_SHIFT   14 /* Integer part of fractional frequency */
 
#define CONTROL_QPM1_SHIFT   18 /* Value for Q(p-1) term of fractional frequency */
 
#define CONTROL_QP_SHIFT   23 /* Value for Q(p) term of fractional frequency */
 
#define CONTROL_PREAMBLE_SHIFT   28 /* Must Be Zero */
 
#define CONTROL_MDIV_MASK   (((1 << CONTROL_MDIV_BITS) - 1) << CONTROL_MDIV_SHIFT)
 
#define CONTROL_NDIV_MASK   (((1 << CONTROL_NDIV_BITS) - 1) << CONTROL_NDIV_SHIFT)
 
#define CONTROL_POSTDIV_MASK   (((1 << CONTROL_POSTDIV_BITS) - 1) << CONTROL_POSTDIV_SHIFT)
 
#define CONTROL_MFG_MASK   (((1 << CONTROL_MFG_BITS) - 1) << CONTROL_MFG_SHIFT)
 
#define CONTROL_P_MASK   (((1 << CONTROL_P_BITS) - 1) << CONTROL_P_SHIFT)
 
#define CONTROL_QPM1_MASK   (((1 << CONTROL_QPM1_BITS) - 1) << CONTROL_QPM1_SHIFT)
 
#define CONTROL_QP_MASK   (((1 << CONTROL_QP_BITS) - 1) << CONTROL_QP_SHIFT)
 
#define CONTROL_PREAMBLE_MASK   (((1 << CONTROL_PREAMBLE_BITS) - 1) << CONTROL_PREAMBLE_SHIFT)
 
#define CORRECTION_DIV_14   5 /* Numerator or denominator of 14 */
 
#define CORRECTION_DIV_15   7 /* Numerator or denominator of 15 */
 
#define CORRECTION_DIV_16   1 /* Numerator or denominator of 16 */
 
#define CORRECTION_DIV_17   3 /* Numerator or denominator of 17 */
 
#define CORRECTION_DIV_18   2 /* Numerator or denominator of 18 */
 
#define CORRECTION_DIV_31   4 /* Numerator or denominator of 31 */
 
#define CORRECTION_DIV_32   6 /* Numerator or denominator of 32 */
 

Functions

epicsShareExtern epicsStatus mrfSetEventClockSpeed (epicsFloat64 InputClockSpeed, epicsUInt32 InputControlWord, epicsFloat64 ReferenceFreq, epicsFloat64 *OutputClockSpeed, epicsUInt32 *OutputControlWord, epicsInt32 PrintFlag)
 
epicsShareExtern epicsUInt32 FracSynthControlWord (epicsFloat64 DesiredFreq, epicsFloat64 ReferenceFreq, epicsInt32 debugFlag, epicsFloat64 *Error)
 
epicsShareExtern epicsFloat64 FracSynthAnalyze (epicsUInt32 ControlWord, epicsFloat64 ReferenceFreq, epicsInt32 PrintFlag)
 
 epicsExportRegistrar (FracSynthRegistrar)
 

Detailed Description

Macro Definition Documentation

◆ CONTROL_MDIV_BITS

#define CONTROL_MDIV_BITS   3 /* Denominator of correction term */

Definition at line 139 of file mrfFracSynth.c.

◆ CONTROL_MDIV_MASK

#define CONTROL_MDIV_MASK   (((1 << CONTROL_MDIV_BITS) - 1) << CONTROL_MDIV_SHIFT)

Definition at line 165 of file mrfFracSynth.c.

◆ CONTROL_MDIV_SHIFT

#define CONTROL_MDIV_SHIFT   0 /* Denominator of correction term */

Definition at line 152 of file mrfFracSynth.c.

◆ CONTROL_MFG_BITS

#define CONTROL_MFG_BITS   3 /* Must Be Zero */

Definition at line 142 of file mrfFracSynth.c.

◆ CONTROL_MFG_MASK

#define CONTROL_MFG_MASK   (((1 << CONTROL_MFG_BITS) - 1) << CONTROL_MFG_SHIFT)

Definition at line 168 of file mrfFracSynth.c.

◆ CONTROL_MFG_SHIFT

#define CONTROL_MFG_SHIFT   11 /* Must Be Zero */

Definition at line 155 of file mrfFracSynth.c.

◆ CONTROL_NDIV_BITS

#define CONTROL_NDIV_BITS   3 /* Numerator of correction term */

Definition at line 140 of file mrfFracSynth.c.

◆ CONTROL_NDIV_MASK

#define CONTROL_NDIV_MASK   (((1 << CONTROL_NDIV_BITS) - 1) << CONTROL_NDIV_SHIFT)

Definition at line 166 of file mrfFracSynth.c.

◆ CONTROL_NDIV_SHIFT

#define CONTROL_NDIV_SHIFT   3 /* Numerator of correction term */

Definition at line 153 of file mrfFracSynth.c.

◆ CONTROL_P_BITS

#define CONTROL_P_BITS   4 /* Integer part of fractional frequency */

Definition at line 143 of file mrfFracSynth.c.

◆ CONTROL_P_MASK

#define CONTROL_P_MASK   (((1 << CONTROL_P_BITS) - 1) << CONTROL_P_SHIFT)

Definition at line 169 of file mrfFracSynth.c.

◆ CONTROL_P_SHIFT

#define CONTROL_P_SHIFT   14 /* Integer part of fractional frequency */

Definition at line 156 of file mrfFracSynth.c.

◆ CONTROL_POSTDIV_BITS

#define CONTROL_POSTDIV_BITS   5 /* Post-Divider */

Definition at line 141 of file mrfFracSynth.c.

◆ CONTROL_POSTDIV_MASK

#define CONTROL_POSTDIV_MASK   (((1 << CONTROL_POSTDIV_BITS) - 1) << CONTROL_POSTDIV_SHIFT)

Definition at line 167 of file mrfFracSynth.c.

◆ CONTROL_POSTDIV_SHIFT

#define CONTROL_POSTDIV_SHIFT   6 /* Post-Divider */

Definition at line 154 of file mrfFracSynth.c.

◆ CONTROL_PREAMBLE_BITS

#define CONTROL_PREAMBLE_BITS   4 /* Must Be Zero */

Definition at line 146 of file mrfFracSynth.c.

◆ CONTROL_PREAMBLE_MASK

#define CONTROL_PREAMBLE_MASK   (((1 << CONTROL_PREAMBLE_BITS) - 1) << CONTROL_PREAMBLE_SHIFT)

Definition at line 172 of file mrfFracSynth.c.

◆ CONTROL_PREAMBLE_SHIFT

#define CONTROL_PREAMBLE_SHIFT   28 /* Must Be Zero */

Definition at line 159 of file mrfFracSynth.c.

◆ CONTROL_QP_BITS

#define CONTROL_QP_BITS   5 /* Value for Q(p) term of fractional frequency */

Definition at line 145 of file mrfFracSynth.c.

◆ CONTROL_QP_MASK

#define CONTROL_QP_MASK   (((1 << CONTROL_QP_BITS) - 1) << CONTROL_QP_SHIFT)

Definition at line 171 of file mrfFracSynth.c.

◆ CONTROL_QP_SHIFT

#define CONTROL_QP_SHIFT   23 /* Value for Q(p) term of fractional frequency */

Definition at line 158 of file mrfFracSynth.c.

◆ CONTROL_QPM1_BITS

#define CONTROL_QPM1_BITS   5 /* Value for Q(p-1) term of fractional frequency */

Definition at line 144 of file mrfFracSynth.c.

◆ CONTROL_QPM1_MASK

#define CONTROL_QPM1_MASK   (((1 << CONTROL_QPM1_BITS) - 1) << CONTROL_QPM1_SHIFT)

Definition at line 170 of file mrfFracSynth.c.

◆ CONTROL_QPM1_SHIFT

#define CONTROL_QPM1_SHIFT   18 /* Value for Q(p-1) term of fractional frequency */

Definition at line 157 of file mrfFracSynth.c.

◆ CORRECTION_DIV_14

#define CORRECTION_DIV_14   5 /* Numerator or denominator of 14 */

Definition at line 178 of file mrfFracSynth.c.

◆ CORRECTION_DIV_15

#define CORRECTION_DIV_15   7 /* Numerator or denominator of 15 */

Definition at line 179 of file mrfFracSynth.c.

◆ CORRECTION_DIV_16

#define CORRECTION_DIV_16   1 /* Numerator or denominator of 16 */

Definition at line 180 of file mrfFracSynth.c.

◆ CORRECTION_DIV_17

#define CORRECTION_DIV_17   3 /* Numerator or denominator of 17 */

Definition at line 181 of file mrfFracSynth.c.

◆ CORRECTION_DIV_18

#define CORRECTION_DIV_18   2 /* Numerator or denominator of 18 */

Definition at line 182 of file mrfFracSynth.c.

◆ CORRECTION_DIV_31

#define CORRECTION_DIV_31   4 /* Numerator or denominator of 31 */

Definition at line 183 of file mrfFracSynth.c.

◆ CORRECTION_DIV_32

#define CORRECTION_DIV_32   6 /* Numerator or denominator of 32 */

Definition at line 184 of file mrfFracSynth.c.

◆ DEBUG_PRINT

#define DEBUG_PRINT   /* Debug printing always enabled for this module */

Definition at line 92 of file mrfFracSynth.c.

◆ MAX_CORRECTION_RATIO

#define MAX_CORRECTION_RATIO   (17./14.) /* Maximum value for correction term. */

Definition at line 116 of file mrfFracSynth.c.

◆ MAX_ERROR

#define MAX_ERROR   100.0 /* Artifical error maximum */

Definition at line 127 of file mrfFracSynth.c.

◆ MAX_FRAC_DIVISOR

#define MAX_FRAC_DIVISOR   31 /* Maximum divisor for fractional frequency value */

Definition at line 120 of file mrfFracSynth.c.

◆ MAX_VCO_FREQ

#define MAX_VCO_FREQ   729.0 /* Maximum frequency for voltage-controlled oscillator */

Definition at line 117 of file mrfFracSynth.c.

◆ MIN_P_VALUE

#define MIN_P_VALUE   17 /* Minimum val for integer part of fractional frequency */

Definition at line 119 of file mrfFracSynth.c.

◆ MIN_VCO_FREQ

#define MIN_VCO_FREQ   540.0 /* Minimum frequency for voltage-controlled oscillator */

Definition at line 118 of file mrfFracSynth.c.

◆ NUM_CORRECTION_VALS

#define NUM_CORRECTION_VALS   8 /* Number of correction value codes */

Definition at line 125 of file mrfFracSynth.c.

◆ NUM_CORRECTIONS

#define NUM_CORRECTIONS   23 /* Number of valid correction values (plus one) */

Definition at line 124 of file mrfFracSynth.c.

◆ NUM_POST_DIVIDE_VALS

#define NUM_POST_DIVIDE_VALS   32 /* Number of post-divider codes */

Definition at line 123 of file mrfFracSynth.c.

◆ NUM_POST_DIVIDES

#define NUM_POST_DIVIDES   31 /* Number of unique post-divider values */

Definition at line 122 of file mrfFracSynth.c.

◆ ZERO_THRESHOLD

#define ZERO_THRESHOLD   1.0e-9 /* Floating point threshold for zero detection */

Definition at line 128 of file mrfFracSynth.c.

Function Documentation

◆ epicsExportRegistrar()

epicsExportRegistrar ( FracSynthRegistrar  )

◆ FracSynthAnalyze()

epicsShareExtern epicsFloat64 FracSynthAnalyze ( epicsUInt32  ControlWord,
epicsFloat64  ReferenceFreq,
epicsInt32  PrintFlag 
)
Description:
This routine will take a bit pattern representing an SY87739L fractional synthesizer control word, break it down into its constituent parts, and return the effective output frequency (in MegaHertz) that the control word will generate. Depending on the value of the "PrintFlag" parameter, it will also display the constituent parts of the the control word and the resulting values that make up the output frequency, and analyze the control word for programming errors.
Parameters
ControlWord= (input) The control word bit pattern to analyze.
ReferenceFreq= (input) SY87739L input reference frequency in MegaHertz.
PrintFlag= (input) Flag to control output messages. Output levels correspond to the DEBUGPRINT output levels:
DP_NONE (0) = No printed output, just return the effective output frequency.
DP_ERROR (2) = Display any programming errors detected in the control word
DP_DEBUG (5) = Display the actual values of the fields in the control word, along with the constituent parts of the output frequency (VCO frequency, correction term, reference freq.)
Implicit Inputs:
CorrectionValList = (CorrectionValStruct) Array to translate correction term components from their coded values to actual values and classes. PostDivideValList = (epicsInt32) Array to translate the post-divider field from its coded value to its actual value.
Returns
Returns the output frequency generated by the control word.
Returns 0.0 if the analysis discovered programming errors in the control word.

Definition at line 844 of file mrfFracSynth.c.

848 {
849 
850  /*---------------------
851  * Local Variables
852  */
853  epicsFloat64 CorrectionTerm;
854  epicsFloat64 EffectiveFreq = 0.0; /* Computed effective output frequency */
855  int Error = 0; /* Error flag from control word analysis */
856  epicsInt32 i; /* Local loop counter */
857  epicsUInt32 MDiv; /* Coded value of the correction term denominator */
858  epicsInt32 MDivClass; /* Class designator of the correction denominator */
859  epicsFloat64 MDivVal; /* Actual value of the correction term denominator*/
860  epicsUInt32 Mfg; /* MFG field extracted from the control word */
861  epicsUInt32 NDiv; /* Coded value of the correction term numerator */
862  epicsInt32 NDivClass; /* Class designator of the correction numerator */
863  epicsFloat64 NDivVal; /* Actual value of the correction term numerator */
864  epicsUInt32 P; /* Coded value of the frac freq integer component */
865  epicsFloat64 PVal; /* Actual value of the frac freq integer component*/
866  epicsUInt32 PostDivide; /* Coded value of the post-divider */
867  epicsFloat64 PostDivideVal; /* Actual value of the post-divider */
868  epicsUInt32 Preamble; /* Preamble field extracted from the control word */
869  epicsUInt32 Qp; /* Number of times to divide by P */
870  epicsUInt32 Qpm1; /* Number of times to divide by P-1 */
871  epicsFloat64 VcoFreq; /* Computed VCO frequency */
872 
873  /*---------------------
874  * Decompose the control word into its constituent elements
875  */
876  Preamble = (ControlWord & CONTROL_PREAMBLE_MASK) >> CONTROL_PREAMBLE_SHIFT;
877  Qp = (ControlWord & CONTROL_QP_MASK) >> CONTROL_QP_SHIFT;
878  Qpm1 = (ControlWord & CONTROL_QPM1_MASK) >> CONTROL_QPM1_SHIFT;
879  P = (ControlWord & CONTROL_P_MASK) >> CONTROL_P_SHIFT;
880  Mfg = (ControlWord & CONTROL_MFG_MASK) >> CONTROL_MFG_SHIFT;
881  PostDivide = (ControlWord & CONTROL_POSTDIV_MASK) >> CONTROL_POSTDIV_SHIFT;
882  NDiv = (ControlWord & CONTROL_NDIV_MASK) >> CONTROL_NDIV_SHIFT;
883  MDiv = (ControlWord & CONTROL_MDIV_MASK) >> CONTROL_MDIV_SHIFT;
884 
885  /*---------------------
886  * Translate the elements of the correction term fraction from their encoded values
887  * to their actual values.
888  */
889  MDivVal = (double)CorrectionValList[MDiv].Value;
890  NDivVal = (double)CorrectionValList[NDiv].Value;
891 
892  /*---------------------
893  * Obtain the class number for each of the elements of the correction term fraction.
894  */
895  MDivClass = CorrectionValList[MDiv].Class;
896  NDivClass = CorrectionValList[NDiv].Class;
897 
898  /*---------------------
899  * Translate the integer part (P) if the fractional frequency and the post-divider from
900  * their encoded values to their actual values.
901  */
902  PVal = (double)(P + MIN_P_VALUE);
903  PostDivideVal = (double)PostDivideValList[PostDivide];
904 
905  /**********************************************************************************************/
906  /* Check for fatal errors that would prevent us from completing the analysis */
907  /**********************************************************************************************/
908 
909  DEBUGPRINT (DP_DEBUG, PrintFlag,
910  ("Analysis of Control Word 0x%08X:\n", ControlWord));
911 
912  /*---------------------
913  * Check for fractional frequency denominator being zero.
914  */
915  if ((Qp + Qpm1) == 0) {
916  DEBUGPRINT (DP_FATAL, PrintFlag, (" *Error: Q(p) + Q(p-1) [%u + %u] is 0.\n", Qp, Qpm1));
917  Error = 1;
918  }/*end if fractional denominator is zero*/
919 
920  /*---------------------
921  * Abort if there are any fatal errors that would prevent us from computing the effective
922  * frequency.
923  */
924  if (Error) return 0.0;
925 
926  /**********************************************************************************************/
927  /* Analyze the control word */
928  /**********************************************************************************************/
929 
930  /*---------------------
931  * Compute the components of the effective output frequency generated by this control word.
932  */
933  CorrectionTerm = NDivVal / MDivVal;
934  VcoFreq = (PVal - ((double)Qpm1 / (double)(Qp + Qpm1))) * CorrectionTerm * ReferenceFreq;
935  EffectiveFreq = VcoFreq / PostDivideVal;
936 
937  /*---------------------
938  * Display the control word fields and how they combine to produce the effective output
939  * frequency.
940  */
941  Error = 0;
942  DEBUGPRINT (DP_DEBUG, PrintFlag,
943  (" P = %d, Q(p) = %u, Q(p-1) = %u, Post Divider = %d\n",
944  (int)PVal, Qp, Qpm1, (int)PostDivideVal));
945  DEBUGPRINT (DP_DEBUG, PrintFlag,
946  (" Correction Term (N/M) = %d/%d = %f, Reference Frequency = %3.1f MHz.\n",
947  (int)NDivVal, (int)MDivVal, CorrectionTerm, ReferenceFreq));
948  DEBUGPRINT (DP_DEBUG, PrintFlag,
949  (" VCO Frequency = %f MHz. Effective Frequency = %15.12f MHz.\n",
950  VcoFreq, EffectiveFreq));
951 
952  /**********************************************************************************************/
953  /* Check for error conditions */
954  /**********************************************************************************************/
955 
956  /*---------------------
957  * Check for preamble field not zero
958  */
959  if (Preamble != 0) {
960  Error = 1;
961  DEBUGPRINT (DP_ERROR, PrintFlag,
962  (" *Error: PREAMBLE field (bits %d-%d) is 0x%X.\n",
964  Preamble));
965  DEBUGPRINT (DP_ERROR, PrintFlag,
966  (" Should be 0x0.\n"));
967  }/*end if preamble field is not zero*/
968 
969  /*---------------------
970  * Check for MFG field not zero
971  */
972  if (Mfg != 0) {
973  Error = 1;
974  DEBUGPRINT (DP_ERROR, PrintFlag,
975  (" *Error: MFG field (bits %d-%d) is 0x%X.\n",
977  DEBUGPRINT (DP_ERROR, PrintFlag,
978  (" Should be 0x0.\n"));
979  }/*end if mfg field is not zero*/
980 
981  /*---------------------
982  * Check for fractional denominator too big.
983  * (one more than the maximum actually does seem to work, so we'll allow it to pass).
984  */
985  if ((Qp + Qpm1) > MAX_FRAC_DIVISOR) {
986  if ((Qp + Qpm1) > (MAX_FRAC_DIVISOR + 1))
987  Error = 1;
988  DEBUGPRINT (DP_ERROR, PrintFlag,
989  (" *Error: Q(p) + Q(p-1) [%u + %u] is %u.\n", Qp, Qpm1, (Qp+Qpm1)));
990  DEBUGPRINT (DP_ERROR, PrintFlag,
991  (" Sum should be less than or equal to %d.\n", MAX_FRAC_DIVISOR));
992  }/*end if fractional divisor is too large*/
993 
994  /*---------------------
995  * Check for correction term too big.
996  */
997  if ((NDivVal / MDivVal) > MAX_CORRECTION_RATIO) {
998  Error = 1;
999  DEBUGPRINT (DP_ERROR, PrintFlag,
1000  (" *Error: Correction Term Ratio = (N/M) = (%d/%d) = %f is too big.\n",
1001  (int)NDivVal, (int)MDivVal, (NDivVal/MDivVal)));
1002  DEBUGPRINT (DP_ERROR, PrintFlag,
1003  (" Should be less than (17/14) = %f\n", MAX_CORRECTION_RATIO));
1004  }/*end if correction term ratio is too big*/
1005 
1006  /*---------------------
1007  * Check for correction term numerator and denominator being from different classes.
1008  */
1009  if (NDivClass != MDivClass) {
1010  Error = 1;
1011  DEBUGPRINT (DP_ERROR, PrintFlag,
1012  (" *Error: Correction Term numerator (%d) is not compatible with",
1013  (int)NDivVal));
1014  DEBUGPRINT (DP_ERROR, PrintFlag,
1015  (" Correction Term Denominator (%d).\n", (int)MDivVal));
1016  DEBUGPRINT (DP_ERROR, PrintFlag,
1017  (" Valid numerator values are:"));
1018  for (i=1; i < NUM_CORRECTION_VALS; i++) {
1019  if (CorrectionValList[i].Class == MDivClass)
1020  DEBUGPRINT (DP_ERROR, PrintFlag, (" %d", CorrectionValList[i].Value));
1021  }/*end search for valid numerators*/
1022 
1023  DEBUGPRINT (DP_ERROR, PrintFlag, (".\n"));
1024  }/*end if correction term numerator/denominator pair is invalid*/
1025 
1026  /*---------------------
1027  * Check for VCO frequency out of range
1028  */
1029  if ((VcoFreq > MAX_VCO_FREQ) || (VcoFreq < MIN_VCO_FREQ)) {
1030  Error = 1;
1031  DEBUGPRINT (DP_ERROR, PrintFlag,
1032  (" *Error: VCO Frequency (%f MHz.) is outside the valid range.\n", VcoFreq));
1033  DEBUGPRINT (DP_ERROR, PrintFlag,
1034  (" Should be between %5.1f MHz. and %5.1f MHz.\n",
1036  }/*end if VCO Frequency is out of range*/
1037 
1038  /*---------------------
1039  * If the analysis did not uncover any serious errors, return the effective output frequency.
1040  */
1041  if (Error) return 0.0;
1042  else return EffectiveFreq;
1043 
1044 }/*end FracSynthAnalyze()*/
#define MIN_P_VALUE
Definition: mrfFracSynth.c:119
#define CONTROL_QP_SHIFT
Definition: mrfFracSynth.c:158
#define DEBUGPRINT(interest, globalFlag, args)
Definition: debugPrint.h:102
#define CONTROL_NDIV_SHIFT
Definition: mrfFracSynth.c:153
#define CONTROL_P_SHIFT
Definition: mrfFracSynth.c:156
#define CONTROL_QPM1_SHIFT
Definition: mrfFracSynth.c:157
#define CONTROL_MFG_BITS
Definition: mrfFracSynth.c:142
#define CONTROL_PREAMBLE_MASK
Definition: mrfFracSynth.c:172
#define CONTROL_POSTDIV_MASK
Definition: mrfFracSynth.c:167
#define CONTROL_PREAMBLE_BITS
Definition: mrfFracSynth.c:146
#define MAX_FRAC_DIVISOR
Definition: mrfFracSynth.c:120
#define CONTROL_NDIV_MASK
Definition: mrfFracSynth.c:166
#define CONTROL_QP_MASK
Definition: mrfFracSynth.c:171
#define CONTROL_MDIV_MASK
Definition: mrfFracSynth.c:165
#define CONTROL_MDIV_SHIFT
Definition: mrfFracSynth.c:152
#define MIN_VCO_FREQ
Definition: mrfFracSynth.c:118
#define CONTROL_POSTDIV_SHIFT
Definition: mrfFracSynth.c:154
#define CONTROL_P_MASK
Definition: mrfFracSynth.c:169
#define MAX_CORRECTION_RATIO
Definition: mrfFracSynth.c:116
#define DP_ERROR
Definition: debugPrint.h:90
#define DP_FATAL
Definition: debugPrint.h:89
#define MAX_VCO_FREQ
Definition: mrfFracSynth.c:117
#define CONTROL_MFG_MASK
Definition: mrfFracSynth.c:168
#define CONTROL_PREAMBLE_SHIFT
Definition: mrfFracSynth.c:159
#define CONTROL_MFG_SHIFT
Definition: mrfFracSynth.c:155
#define CONTROL_QPM1_MASK
Definition: mrfFracSynth.c:170
#define NUM_CORRECTION_VALS
Definition: mrfFracSynth.c:125
#define DP_DEBUG
Definition: debugPrint.h:93

◆ FracSynthControlWord()

epicsShareExtern epicsUInt32 FracSynthControlWord ( epicsFloat64  DesiredFreq,
epicsFloat64  ReferenceFreq,
epicsInt32  debugFlag,
epicsFloat64 *  Error 
)
Description:

This routine will take a desired output frequency (expressed in MegaHertz)and a reference frequency (also expressed in MegaHertz) and create a control word for the Micrel SY877391L Fractional-N Synthesizer chip that will produce an output frequency as close as possible to the desired frequency. The routine also returns an error value (expressed in parts-per-million) between the actual output frequency and the desired output frequency.

Function:

A complete description of how the Micrel SY87739L chip works is way beyond the scope of a function header comment. The reader who wants a complete understanding of what this routine is doing should refer to the Micrel SY87739L product description sheet available at: www.micrel.com

A brief description of the chip programming is useful, however, and is provided here:

The output frequency is described by the following formulae:

F(out) = F(vco) / PostDiv

where F(vco) is the frequency generated by a voltage-controlled oscillator, and PostDiv is a frequency divider value between 1 and 60 (not inclusive). The PostDiv value must be chosen so that the VCO frequency is within its operating range of 540 - 729 MHz. The VCO frequency is given by:

F(vco) = C * F(frac) * F(ref)

where C is a "Correction Factor" (also referred to as the "wrapper correction" in the documentation0 expressed as (N/M) where N and M are from the set {14, 15, 16, 17, 18, 31, 32}. Not all combinations, however, are legal. F(frac) is the fractional frequency produced by a fractional-N P/P-1 divider circuit. F(ref) is the input reference frequency to the Micrel chip. Typically it is 27 MHz, although in the MRF timing boards it is 24 MHz. The fractional frequency is basically a multiplier for the reference frequency. It is expressed as a rational number with a divisor less than 32 and is given by:

F(frac) = P - (Q(p-1) / (Q(p) + Q(p-1)))

where P is the integer part of the fractional frequency, Q(p) is the number of clock periods where the reference clock is divided by P and Q(p-1) is the number of clock periods where the reference clock is divided by P-1. A hardware implementation of Bresenham's algorithm is used to evenly space out the P and P-1 divisions. Beyond this, you'll have to read the manual for further details.

The routine works by doing an exhaustive search (with some optimizations) of the parameter space {C, Q(p), Q(p-1), PostDiv}. P is predetermined by F(out) and PostDiv, so it does not need to be searched. The Q(p), Q(p-1) search is accomplished by searching all the numerators for the denominator (Q(p) + Q(p-1)) that produce a fraction less than 1. Although an exhaustive search is not the most efficient way to optimize a 4-parameter space, it turns out that the dimensions of each parameter are not that big. PostDiv only has 31 unique values, and we only search the values that produce a valid F(vco). When you rule out duplications and illegal combinations it turns out that C only has 22 valid values, and if you arrange them in ascending order, you only have to search until the error value stops decreasing. For Q(p) and Q(p-1), we only have to search 31 denominators and for each denominator we only have to search n-1 numerators. This gives us n(n+1)/2, or 465 (for n=30) possible numerator/denominator pairs to search, although we stop immediately if we find a denominator that exactly divides the desired fractional frequency.

If we search 22 correction factors for each numerator/denominator pair, and we repeat the process for each of 31 possible PostDiv values, we get a worst case number of 317,130 possible combinations. In practice, the VCO frequency limitations (between 540 and 729 Megahertz) will usually eliminate most of the 31 possible PostDiv values. Given the other optimizations mentioned above, the worst case number is a pretty pathological example. In most cases the number of combinations actually searched will be far less than that.

Parameters
DesiredFreq= (input) Desired output frequency in MegaHertz.
ReferenceFreq= (input) SY87739L input reference frequency in MegaHertz.
debugFlag= (input) Flag for debug output. If the value is 4 (DP_INFO) or higher, the routine will print the value of the control word and the frequency actually produced.
Error= (output) Error between the actual output frequency and the desired output frequency. Expressed in parts-per-million.
Implicit Inputs:
CorrectionList = (CorrectionStruct) List of all valid correction factors and their control-word encodings.
PostDivideList = (PostDivideStruct) List of valid post-divide values and their control-word encodings.
Returns
Returns the SY87739L Control Word for the desired frequency.

Definition at line 552 of file mrfFracSynth.c.

557 {
558 
559  /*---------------------
560  * Local Variables
561  */
562  FracSynthComponents Best; /* Best overall parameters seen so far */
563  FracSynthComponents BestFracFreq; /* Best fractional frequency parameters seen so far */
564  epicsUInt32 ControlWord; /* Computed control word value */
565  epicsFloat64 CorrectionErr; /* Error value for current correction factor */
566  epicsFloat64 CorrectionFreq; /* Frequency after applying the correction factor */
567  epicsInt32 CorrectionIndex; /* Index to correction factor list */
568  epicsFloat64 d; /* FP representation of the current denominator */
569  epicsFloat64 EffectiveFreq = 0.0; /* Effective output frequency */
570  epicsFloat64 FracFreqErr; /* Best fractional frequency error seen so far */
571  epicsFloat64 FractionalFreq; /* Desired fractional frequency */
572  epicsFloat64 FreqErr; /* Error value for the desired frequency */
573  epicsInt32 i, j, k, n; /* Loop indicies */
574  epicsInt32 Numerator = 1; /* Best numerator found for current denominator */
575  epicsFloat64 OldCorrectionErr; /* Error value for previous correction factor */
576  epicsInt32 p; /* Integer part of fractional frequency */
577  epicsInt32 p1; /* Numerator of fractional frequency ratio */
578  epicsInt32 Qp; /* Number of "P" pulses in the frac. div. circuit */
579  epicsInt32 Qpm1; /* Number of "P-1" pulses in the frac. div. circuit */
580  epicsFloat64 TestFreq; /* Fractional frequency to try in correction loop */
581 
582  /*---------------------
583  * Initialize the "Best Fractional Frequency So Far" parameters
584  */
585  BestFracFreq.Error = MAX_ERROR; /* Deviation from desired output frequency */
586  BestFracFreq.EffectiveFreq = 0.0; /* Actual frequency generated by these components */
587  BestFracFreq.PostDivIndex = 0; /* Index into post-divider table */
588  BestFracFreq.CorrectionIndex = 0; /* Index into correction factor table */
589  BestFracFreq.P = 0; /* Integer part of fractional frequency */
590  BestFracFreq.Qp = 1; /* Value of Q(p) term of fractional frequency */
591  BestFracFreq.Qpm1 = 1; /* Value of Q(p-1) term of fractional frequency */
592 
593  Best = BestFracFreq; /* Best overall parameters */
594 
595  /*---------------------
596  * Post-Divider Loop:
597  *---------------------
598  * Check all post-divider values that would put the VCO frequency within
599  * the allowable range (540 - 729 MHz).
600  */
601  Best.Error = MAX_ERROR;
602  for (i=0; i < NUM_POST_DIVIDES; i++) {
603  epicsFloat64 PostDivide = PostDivideList[i].Divisor;
604 
605  /*---------------------
606  * Compute the VCO frequency and make sure it is within the allowable range.
607  */
608  epicsFloat64 VcoFreq = DesiredFreq * PostDivide;
609 
610  if (VcoFreq >= MAX_VCO_FREQ)
611  break;
612 
613  if (VcoFreq >= MIN_VCO_FREQ) {
614 
615  /*---------------------
616  * We have a VCO frequency inside the allowable range.
617  * Now compute the desired fractional frequency.
618  *
619  * The desired fractional frequency is derived by dividing the VCO frequency by the
620  * reference frequency. The actual fractional-N frequency is created by a fractional-N
621  * P/P-1 divider which attempts to represent the desired fractional frequency as a
622  * rational fraction (with a divisor less than 32) of the reference frequency.
623  *
624  * Note that the actual fractional-N frequency may not be exactly identical to the
625  * desired fractional frequency.
626  */
627  FractionalFreq = VcoFreq / ReferenceFreq;
628  BestFracFreq.Error = MAX_ERROR;
629 
630  /*---------------------
631  * Divisor Loop:
632  *---------------------
633  * Search for a divisor that will produce the closest fractional-N P/P-1 frequency to
634  * the desired fractional frequency. If we are lucky, we will find a number that
635  * exactly divides the desired fractional frequency and we can stop the search here.
636  * If not, we will have to try different numerator and correction factor combinations
637  * in order to find the closest fit.
638  */
639  for (j=1; j <= MAX_FRAC_DIVISOR; j++) {
640  d = j; /* Floating point representation of denominator */
641  CorrectionIndex = 0; /* No correction factor */
642 
643  /*---------------------
644  * Compute the integer and fractional parts of the fractional-N frequency
645  */
646  p1 = (epicsInt32)(FractionalFreq * j);
647  p = (p1 / j) + 1;
648  Qpm1 = j - (p1 % j);
649  Qp = j - Qpm1;
650 
651  /*---------------------
652  * Compute the actual frequency generated by the fractional-N P/P-1 divider
653  * for these values. Also compute the error between the actual fractional
654  * frequency and the desired fractional frequency.
655  */
656  EffectiveFreq = (double)p - ((double)Qpm1 / (double)(Qp + Qpm1));
657  FracFreqErr = fabs (FractionalFreq - EffectiveFreq);
658 
659  /*---------------------
660  * If the current divisor does not exactly divide the desired fractional frequency,
661  * search for a numerator and correction-factor pair that will come closest to
662  * generating the desired fractional frequency.
663  */
664  if (FracFreqErr >= ZERO_THRESHOLD) {
665  FracFreqErr = MAX_ERROR;
666 
667  /*---------------------
668  * Numerator Loop:
669  *---------------------
670  * Search for the numerator/correction-factor pair with the lowest error.
671  */
672  for (n = 1; n <= j; n++) {
673  TestFreq = (double)p - ((double)n / d);
674  OldCorrectionErr = MAX_ERROR;
675 
676  /*---------------------
677  * Correction Factor Loop:
678  *---------------------
679  * Search for the correction factor that produces the lowest error
680  * with the current numerator/denominator pair. Note that since the
681  * correction factor list is arranged in ascending order, we can
682  * stop the search as soon as the error value stops decreasing.
683  */
684  for (k = 1; k < NUM_CORRECTIONS; k++) {
685  CorrectionFreq = CorrectionList[k].Ratio * TestFreq;
686  CorrectionErr = fabs (FractionalFreq - CorrectionFreq);
687  if (CorrectionErr > OldCorrectionErr) break;
688  OldCorrectionErr = CorrectionErr;
689 
690  /*---------------------
691  * If we found a numerator/correction-factor pair with a lower error
692  * than the previous error for this denominator, replace the previous
693  * values.
694  */
695  if (CorrectionErr < FracFreqErr) {
696  EffectiveFreq = CorrectionFreq;
697  FracFreqErr = CorrectionErr;
698  Numerator = n;
699  CorrectionIndex = k;
700  }/*end if we found a better numerator/correction pair*/
701 
702  }/*end correction factor loop*/
703  }/*end numerator loop*/
704 
705  /*---------------------
706  * At this point, we now have the best numerator/correction-factor pair
707  * for the current denominator. Recompute the Q(p) and Q(p-1) values
708  * based on the new numerator value.
709  *
710  * It could happen that the numerator/denominator/correction set we found
711  * produces the desired fractional frequency exactly (FracFreqErr == 0).
712  * If this occurs, we will set FracFreqErr to the zero-threshold value so that
713  * the algorithm gives preference to solutions that do not require a correction
714  * factor.
715  */
716  Qpm1 = Numerator;
717  Qp = j - Numerator;
718  if (FracFreqErr < ZERO_THRESHOLD)
719  FracFreqErr = ZERO_THRESHOLD;
720 
721  }/*end denominator does not exactly divide the desired fractional frequency*/
722 
723  /*---------------------
724  * Store the parameters for the numerator/correction pair that produces the lowest
725  * fractional frequency error for this denominator. If it turns out that the
726  * denominator exactly divides the desired fractional frequency (FracFreqErr == 0),
727  * exit the denominator loop now.
728  */
729  if (FracFreqErr < BestFracFreq.Error) {
730  BestFracFreq.Error = FracFreqErr;
731  BestFracFreq.EffectiveFreq = EffectiveFreq;
732  BestFracFreq.P = p;
733  BestFracFreq.Qp = Qp;
734  BestFracFreq.Qpm1 = Qpm1;
735  BestFracFreq.CorrectionIndex = CorrectionIndex;
736  if (FracFreqErr < ZERO_THRESHOLD) break;
737  }/*end if fractional frequency is best so far*/
738 
739  }/*end denominator loop*/
740 
741  /*---------------------
742  * Adjust the fractional frequency error for the current post divider.
743  * If the adjusted frequency error is less than the current best, make
744  * this the current best. If the new parameters produce an exact match
745  * (FreqErr == 0), exit the post-divider loop now.
746  */
747  FreqErr = (BestFracFreq.Error * ReferenceFreq) / PostDivide;
748  if (FreqErr < Best.Error) {
749  Best = BestFracFreq;
750  Best.PostDivIndex = i;
751  Best.Error = FreqErr;
752  Best.EffectiveFreq = (BestFracFreq.EffectiveFreq * ReferenceFreq) / PostDivide;
753  if (FreqErr < ZERO_THRESHOLD) break;
754  }/*end if this post-divide solution is the best so far*/
755 
756  }/*end if VCO frequency is within range*/
757  }/*end for each post divider*/
758 
759  /*---------------------
760  * Abort if we could not come up with a set of parameters that would produce the
761  * desired frequency.
762  */
763  if (MAX_ERROR == Best.Error) return 0;
764 
765  /*---------------------
766  * Construct the control word from the parameters found in the search above.
767  */
768  CorrectionIndex = Best.CorrectionIndex;
769  ControlWord =
770  ((CorrectionList[CorrectionIndex].mDiv << CONTROL_MDIV_SHIFT) & CONTROL_MDIV_MASK) |
771  ((CorrectionList[CorrectionIndex].nDiv << CONTROL_NDIV_SHIFT) & CONTROL_NDIV_MASK) |
772  ((PostDivideList[Best.PostDivIndex].Code << CONTROL_POSTDIV_SHIFT) & CONTROL_POSTDIV_MASK) |
773  (((Best.P - 1) << CONTROL_P_SHIFT) & CONTROL_P_MASK) |
775  ((Best.Qp << CONTROL_QP_SHIFT) & CONTROL_QP_MASK);
776 
777  /*---------------------
778  * Compute the frequency that will actually be generated from these parameters.
779  */
780  EffectiveFreq = CorrectionList[CorrectionIndex].Ratio * ReferenceFreq *
781  ((double)Best.P - ((double)Best.Qpm1 /(double)(Best.Qp + Best.Qpm1))) /
782  PostDivideList[Best.PostDivIndex].Divisor;
783 
784  /*---------------------
785  * Return the error (in parts-per-million) between the desired and actual frequencies.
786  */
787  *Error = 1.e6 * (EffectiveFreq - DesiredFreq) / DesiredFreq;
788 
789  /*---------------------
790  * Output debug information about the results of this call
791  */
792  DEBUGPRINT (DP_INFO, debugFlag,
793  ("Desired Frequency = %f, Control Word = %08X\n", DesiredFreq, ControlWord));
794  DEBUGPRINT (DP_INFO, debugFlag,
795  ("Effective Frequency = %15.12f, Error = %5.3f ppm\n", EffectiveFreq, *Error));
796 
797  /*---------------------
798  * Return the computed control word.
799  */
800  return ControlWord;
801 
802 }/*end FracSynthControlWord()*/
#define CONTROL_QP_SHIFT
Definition: mrfFracSynth.c:158
#define DEBUGPRINT(interest, globalFlag, args)
Definition: debugPrint.h:102
epicsUInt16 nDiv
Definition: mrfFracSynth.c:204
#define CONTROL_NDIV_SHIFT
Definition: mrfFracSynth.c:153
#define CONTROL_P_SHIFT
Definition: mrfFracSynth.c:156
epicsFloat64 Ratio
Definition: mrfFracSynth.c:203
#define CONTROL_QPM1_SHIFT
Definition: mrfFracSynth.c:157
#define NUM_CORRECTIONS
Definition: mrfFracSynth.c:124
epicsFloat64 Error
Definition: mrfFracSynth.c:220
epicsFloat64 EffectiveFreq
Definition: mrfFracSynth.c:221
epicsInt32 PostDivIndex
Definition: mrfFracSynth.c:222
#define DP_INFO
Definition: debugPrint.h:92
epicsFloat64 Divisor
Definition: mrfFracSynth.c:195
#define CONTROL_POSTDIV_MASK
Definition: mrfFracSynth.c:167
#define MAX_ERROR
Definition: mrfFracSynth.c:127
#define MAX_FRAC_DIVISOR
Definition: mrfFracSynth.c:120
#define CONTROL_NDIV_MASK
Definition: mrfFracSynth.c:166
#define CONTROL_QP_MASK
Definition: mrfFracSynth.c:171
#define CONTROL_MDIV_MASK
Definition: mrfFracSynth.c:165
#define CONTROL_MDIV_SHIFT
Definition: mrfFracSynth.c:152
#define MIN_VCO_FREQ
Definition: mrfFracSynth.c:118
#define ZERO_THRESHOLD
Definition: mrfFracSynth.c:128
#define CONTROL_POSTDIV_SHIFT
Definition: mrfFracSynth.c:154
#define CONTROL_P_MASK
Definition: mrfFracSynth.c:169
#define MAX_VCO_FREQ
Definition: mrfFracSynth.c:117
epicsUInt32 Code
Definition: mrfFracSynth.c:196
#define NUM_POST_DIVIDES
Definition: mrfFracSynth.c:122
epicsUInt16 mDiv
Definition: mrfFracSynth.c:205
epicsInt32 CorrectionIndex
Definition: mrfFracSynth.c:223
#define CONTROL_QPM1_MASK
Definition: mrfFracSynth.c:170

◆ mrfSetEventClockSpeed()

epicsShareExtern epicsStatus mrfSetEventClockSpeed ( epicsFloat64  InputClockSpeed,
epicsUInt32  InputControlWord,
epicsFloat64  ReferenceFreq,
epicsFloat64 *  OutputClockSpeed,
epicsUInt32 *  OutputControlWord,
epicsInt32  PrintFlag 
)
Description:

This routine will determine the system's event clock speed (in Megahertz) and/or the value for the fractional synthesizer control word given at least one of these two values.

Function:

If the InputClockSpeed parameter is specified (not zero), the routine will compute the value of the fractional synthesizer control word to produce that frequency.

If the InputControlWord parameter is specified (not zero), the routine will check the control word for programming errors and return the actual frequency (in Megahertz) produced by that control word.

If neither parameter is specified, the routine will output a default event clock frequency and a default control word.

If both parameters are specified, the routine will make sure the frequency generated by the control word is within 100 ppm of the desired clock speed.

If no errors are encountered, the routine will return both the final event clock speed and the fractional synthesizer control word. If errors are encountered, both output parameters will contain zero.

Parameters
InputClockSpeed= (input) Desired event clock speed in Megahertz. 0.0 means no clock speed specified.
InputControlWord= (input) Desired value for the fractional synthesizer control word. 0 means no control word specified.
ReferenceFreq= (input) SY87739L input reference frequency in MegaHertz.
OutputClockSpeed= (output) The input or computed value for the event clock speed
OutputControlWord= (output) The input or computed value for the fractional synthesizer control word.
PrintFlag= (input) Flag to control output messages. Output levels correspond to the DEBUGPRINT output levels:
DP_NONE (0) = Only display errors that prevent us from returning the event clock speed and the control word.
DP_ERROR (2) = Display any programming errors detected in the control word.
DP_WARN (3) = Display warning messages such as the one warning that we are using the default event clock frequency.
DP_INFO (4) = Display the value of the computed control word, its actual output frequency, and the error (in ppm) between the desired and actual frequencies.
DP_DEBUG (5) = Display the actual values of the fields in the control word, along with the constituent parts of the output frequency (VCO frequency, correction term, reference freq.)
Returns
OK if we were able to return both an event clock frequency and a fractional synthesizer control word.
ERROR if we could not.

Definition at line 365 of file mrfFracSynth.c.

372 {
373  /*---------------------
374  * Local Variables
375  */
376  epicsFloat64 ActualClockSpeed; /* Actual frequency generated by the control word */
377  epicsFloat64 Error = 0.0; /* Error (in ppm) between desired & actual freq. */
378 
379  /*---------------------
380  * Zero the output clock speed and control word parameters just in case there is an error.
381  */
382  *OutputClockSpeed = 0.0;
383  *OutputControlWord = 0;
384 
385  /*---------------------
386  * Compute the Fractional Synthesizer control word if one was not provided
387  */
388  if (0 == InputControlWord) {
389 
390  /*---------------------
391  * If a clock speed was not specified either, use the default clock speed.
392  */
393  if (0.0 == InputClockSpeed) {
394  InputClockSpeed = MRF_DEF_CLOCK_SPEED;
395  DEBUGPRINT (DP_WARN, PrintFlag,
396  (" *Warning: Event clock speed not specified, will default to %f MHz.\n",
398  }/*end if neither the control word nor the clock speed were specified*/
399 
400  /*---------------------
401  * Compute the control word for the desired clock speed.
402  * Abort on error.
403  */
404  InputControlWord = FracSynthControlWord (
405  InputClockSpeed,
406  ReferenceFreq,
407  PrintFlag,
408  &Error);
409 
410  if (0 == InputControlWord) {
412  (" *Error: Unable to compute fractional synthesizer control word for %f MHz.\n",
413  InputClockSpeed));
414  return ERROR;
415  }/*end if could not compute fractional synthesizer control word*/
416 
417  }/*end if control word not specified*/
418 
419  /*---------------------
420  * Analyze the control word for programming errors and get the actual frequency it will produce.
421  * Abort if there are any serious problems.
422  */
423  ActualClockSpeed = FracSynthAnalyze (InputControlWord, ReferenceFreq, PrintFlag);
424  if (0.0 == ActualClockSpeed) {
426  (" *Error: Fractional Synthesizer control word 0x%08x is invalid.\n",
427  InputControlWord));
428  return ERROR;
429  }/*end if control word was invalid*/
430 
431  /*---------------------
432  * If a clock speed was not specified, use the actual frequency generated by the control word.
433  */
434  if (0.0 == InputClockSpeed)
435  InputClockSpeed = ActualClockSpeed;
436 
437  /*---------------------
438  * Check to make sure the difference between the requested and the actual frequencies
439  * is within +/- 100 ppm.
440  */
441  if (0.0 == Error)
442  Error = 1.e6 * (ActualClockSpeed - InputClockSpeed) / InputClockSpeed;
443 
444  if (fabs(Error) >= 100.0) {
446  (" *Error: Requested frequency (%f) and actual frequency (%f) ",
447  InputClockSpeed, ActualClockSpeed));
449  ("differ by %6.2f ppm.\n Difference must be less than +/- 100 ppm.\n",
450  Error));
451  return ERROR;
452  }/*end if error is too large*/
453 
454  /*---------------------
455  * If we made it this far, everything checked out OK.
456  * Return the event clock speed and the fractional sythesizer control word.
457  */
458  *OutputClockSpeed = InputClockSpeed;
459  *OutputControlWord = InputControlWord;
460  return OK;
461 
462 }/*end mrfSetEventClockSpeed()*/
epicsShareExtern epicsUInt32 FracSynthControlWord(epicsFloat64 DesiredFreq, epicsFloat64 ReferenceFreq, epicsInt32 debugFlag, epicsFloat64 *Error)
Definition: mrfFracSynth.c:552
#define DEBUGPRINT(interest, globalFlag, args)
Definition: debugPrint.h:102
#define MRF_DEF_CLOCK_SPEED
Definition: mrfCommon.h:100
#define OK
Definition: mrfFracSynth.h:81
#define ERROR
Definition: mrfFracSynth.h:88
#define DP_FATAL
Definition: debugPrint.h:89
#define DP_WARN
Definition: debugPrint.h:91
epicsShareExtern epicsFloat64 FracSynthAnalyze(epicsUInt32 ControlWord, epicsFloat64 ReferenceFreq, epicsInt32 PrintFlag)
Definition: mrfFracSynth.c:844