98 #include <epicsTypes.h> 100 #include <registryFunction.h> 102 #include <epicsExport.h> 110 #include <epicsExport.h> 116 #define MAX_CORRECTION_RATIO (17./14.) 117 #define MAX_VCO_FREQ 729.0 118 #define MIN_VCO_FREQ 540.0 119 #define MIN_P_VALUE 17 120 #define MAX_FRAC_DIVISOR 31 122 #define NUM_POST_DIVIDES 31 123 #define NUM_POST_DIVIDE_VALS 32 124 #define NUM_CORRECTIONS 23 125 #define NUM_CORRECTION_VALS 8 127 #define MAX_ERROR 100.0 128 #define ZERO_THRESHOLD 1.0e-9 139 #define CONTROL_MDIV_BITS 3 140 #define CONTROL_NDIV_BITS 3 141 #define CONTROL_POSTDIV_BITS 5 142 #define CONTROL_MFG_BITS 3 143 #define CONTROL_P_BITS 4 144 #define CONTROL_QPM1_BITS 5 145 #define CONTROL_QP_BITS 5 146 #define CONTROL_PREAMBLE_BITS 4 152 #define CONTROL_MDIV_SHIFT 0 153 #define CONTROL_NDIV_SHIFT 3 154 #define CONTROL_POSTDIV_SHIFT 6 155 #define CONTROL_MFG_SHIFT 11 156 #define CONTROL_P_SHIFT 14 157 #define CONTROL_QPM1_SHIFT 18 158 #define CONTROL_QP_SHIFT 23 159 #define CONTROL_PREAMBLE_SHIFT 28 165 #define CONTROL_MDIV_MASK (((1 << CONTROL_MDIV_BITS) - 1) << CONTROL_MDIV_SHIFT) 166 #define CONTROL_NDIV_MASK (((1 << CONTROL_NDIV_BITS) - 1) << CONTROL_NDIV_SHIFT) 167 #define CONTROL_POSTDIV_MASK (((1 << CONTROL_POSTDIV_BITS) - 1) << CONTROL_POSTDIV_SHIFT) 168 #define CONTROL_MFG_MASK (((1 << CONTROL_MFG_BITS) - 1) << CONTROL_MFG_SHIFT) 169 #define CONTROL_P_MASK (((1 << CONTROL_P_BITS) - 1) << CONTROL_P_SHIFT) 170 #define CONTROL_QPM1_MASK (((1 << CONTROL_QPM1_BITS) - 1) << CONTROL_QPM1_SHIFT) 171 #define CONTROL_QP_MASK (((1 << CONTROL_QP_BITS) - 1) << CONTROL_QP_SHIFT) 172 #define CONTROL_PREAMBLE_MASK (((1 << CONTROL_PREAMBLE_BITS) - 1) << CONTROL_PREAMBLE_SHIFT) 178 #define CORRECTION_DIV_14 5 179 #define CORRECTION_DIV_15 7 180 #define CORRECTION_DIV_16 1 181 #define CORRECTION_DIV_17 3 182 #define CORRECTION_DIV_18 2 183 #define CORRECTION_DIV_31 4 184 #define CORRECTION_DIV_32 6 240 { 1.0, 0x00}, { 2.0, 0x02}, { 3.0, 0x03}, { 4.0, 0x04}, { 5.0, 0x05}, { 6.0, 0x06},
241 { 7.0, 0x07}, { 8.0, 0x08}, { 9.0, 0x09}, {10.0, 0x0A}, {11.0, 0x0B}, {12.0, 0x0C},
242 {13.0, 0x0D}, {14.0, 0x0E}, {15.0, 0x0F}, {16.0, 0x10}, {18.0, 0x11}, {20.0, 0x12},
243 {22.0, 0x13}, {24.0, 0x14}, {26.0, 0x15}, {28.0, 0x16}, {30.0, 0x17}, {32.0, 0x18},
244 {36.0, 0x19}, {40.0, 0x1A}, {44.0, 0x1B}, {48.0, 0x1C}, {52.0, 0x1D}, {56.0, 0x1E},
255 1, 3, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
256 16, 18, 20, 22, 24, 26, 28, 30, 32, 36, 40, 44, 48, 52, 56, 60
298 {16, 1}, {16, 1}, {18, 1}, {17, 1}, {31, 2}, {14, 1}, {32, 2}, {15, 1}
366 epicsFloat64 InputClockSpeed,
367 epicsUInt32 InputControlWord,
368 epicsFloat64 ReferenceFreq,
369 epicsFloat64 *OutputClockSpeed,
370 epicsUInt32 *OutputControlWord,
371 epicsInt32 PrintFlag)
376 epicsFloat64 ActualClockSpeed;
377 epicsFloat64 Error = 0.0;
382 *OutputClockSpeed = 0.0;
383 *OutputControlWord = 0;
388 if (0 == InputControlWord) {
393 if (0.0 == InputClockSpeed) {
396 (
" *Warning: Event clock speed not specified, will default to %f MHz.\n",
410 if (0 == InputControlWord) {
412 (
" *Error: Unable to compute fractional synthesizer control word for %f MHz.\n",
423 ActualClockSpeed =
FracSynthAnalyze (InputControlWord, ReferenceFreq, PrintFlag);
424 if (0.0 == ActualClockSpeed) {
426 (
" *Error: Fractional Synthesizer control word 0x%08x is invalid.\n",
434 if (0.0 == InputClockSpeed)
435 InputClockSpeed = ActualClockSpeed;
442 Error = 1.e6 * (ActualClockSpeed - InputClockSpeed) / InputClockSpeed;
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",
458 *OutputClockSpeed = InputClockSpeed;
459 *OutputControlWord = InputControlWord;
553 epicsFloat64 DesiredFreq,
554 epicsFloat64 ReferenceFreq,
555 epicsInt32 debugFlag,
564 epicsUInt32 ControlWord;
565 epicsFloat64 CorrectionErr;
566 epicsFloat64 CorrectionFreq;
567 epicsInt32 CorrectionIndex;
569 epicsFloat64 EffectiveFreq = 0.0;
570 epicsFloat64 FracFreqErr;
571 epicsFloat64 FractionalFreq;
572 epicsFloat64 FreqErr;
573 epicsInt32 i, j, k, n;
574 epicsInt32 Numerator = 1;
575 epicsFloat64 OldCorrectionErr;
580 epicsFloat64 TestFreq;
591 BestFracFreq.
Qpm1 = 1;
603 epicsFloat64 PostDivide = PostDivideList[i].
Divisor;
608 epicsFloat64 VcoFreq = DesiredFreq * PostDivide;
627 FractionalFreq = VcoFreq / ReferenceFreq;
646 p1 = (epicsInt32)(FractionalFreq * j);
656 EffectiveFreq = (double)p - ((
double)Qpm1 / (double)(Qp + Qpm1));
657 FracFreqErr = fabs (FractionalFreq - EffectiveFreq);
672 for (n = 1; n <= j; n++) {
673 TestFreq = (double)p - ((
double)n / d);
685 CorrectionFreq = CorrectionList[k].
Ratio * TestFreq;
686 CorrectionErr = fabs (FractionalFreq - CorrectionFreq);
687 if (CorrectionErr > OldCorrectionErr)
break;
688 OldCorrectionErr = CorrectionErr;
695 if (CorrectionErr < FracFreqErr) {
696 EffectiveFreq = CorrectionFreq;
697 FracFreqErr = CorrectionErr;
729 if (FracFreqErr < BestFracFreq.
Error) {
730 BestFracFreq.
Error = FracFreqErr;
733 BestFracFreq.
Qp = Qp;
734 BestFracFreq.
Qpm1 = Qpm1;
747 FreqErr = (BestFracFreq.
Error * ReferenceFreq) / PostDivide;
748 if (FreqErr < Best.
Error) {
751 Best.
Error = FreqErr;
780 EffectiveFreq = CorrectionList[CorrectionIndex].
Ratio * ReferenceFreq *
781 ((double)Best.
P - ((
double)Best.
Qpm1 /(double)(Best.
Qp + Best.
Qpm1))) /
787 *Error = 1.e6 * (EffectiveFreq - DesiredFreq) / DesiredFreq;
793 (
"Desired Frequency = %f, Control Word = %08X\n", DesiredFreq, ControlWord));
795 (
"Effective Frequency = %15.12f, Error = %5.3f ppm\n", EffectiveFreq, *Error));
845 epicsUInt32 ControlWord,
846 epicsFloat64 ReferenceFreq,
847 epicsInt32 PrintFlag)
853 epicsFloat64 CorrectionTerm;
854 epicsFloat64 EffectiveFreq = 0.0;
858 epicsInt32 MDivClass;
859 epicsFloat64 MDivVal;
862 epicsInt32 NDivClass;
863 epicsFloat64 NDivVal;
866 epicsUInt32 PostDivide;
867 epicsFloat64 PostDivideVal;
868 epicsUInt32 Preamble;
871 epicsFloat64 VcoFreq;
889 MDivVal = (double)CorrectionValList[MDiv].Value;
890 NDivVal = (double)CorrectionValList[NDiv].Value;
895 MDivClass = CorrectionValList[MDiv].
Class;
896 NDivClass = CorrectionValList[NDiv].
Class;
903 PostDivideVal = (double)PostDivideValList[PostDivide];
910 (
"Analysis of Control Word 0x%08X:\n", ControlWord));
915 if ((Qp + Qpm1) == 0) {
916 DEBUGPRINT (
DP_FATAL, PrintFlag, (
" *Error: Q(p) + Q(p-1) [%u + %u] is 0.\n", Qp, Qpm1));
924 if (Error)
return 0.0;
933 CorrectionTerm = NDivVal / MDivVal;
934 VcoFreq = (PVal - ((double)Qpm1 / (
double)(Qp + Qpm1))) * CorrectionTerm * ReferenceFreq;
935 EffectiveFreq = VcoFreq / PostDivideVal;
943 (
" P = %d, Q(p) = %u, Q(p-1) = %u, Post Divider = %d\n",
944 (
int)PVal, Qp, Qpm1, (
int)PostDivideVal));
946 (
" Correction Term (N/M) = %d/%d = %f, Reference Frequency = %3.1f MHz.\n",
947 (
int)NDivVal, (
int)MDivVal, CorrectionTerm, ReferenceFreq));
949 (
" VCO Frequency = %f MHz. Effective Frequency = %15.12f MHz.\n",
950 VcoFreq, EffectiveFreq));
962 (
" *Error: PREAMBLE field (bits %d-%d) is 0x%X.\n",
966 (
" Should be 0x0.\n"));
975 (
" *Error: MFG field (bits %d-%d) is 0x%X.\n",
978 (
" Should be 0x0.\n"));
989 (
" *Error: Q(p) + Q(p-1) [%u + %u] is %u.\n", Qp, Qpm1, (Qp+Qpm1)));
1000 (
" *Error: Correction Term Ratio = (N/M) = (%d/%d) = %f is too big.\n",
1001 (
int)NDivVal, (
int)MDivVal, (NDivVal/MDivVal)));
1009 if (NDivClass != MDivClass) {
1012 (
" *Error: Correction Term numerator (%d) is not compatible with",
1015 (
" Correction Term Denominator (%d).\n", (
int)MDivVal));
1017 (
" Valid numerator values are:"));
1019 if (CorrectionValList[i].Class == MDivClass)
1032 (
" *Error: VCO Frequency (%f MHz.) is outside the valid range.\n", VcoFreq));
1034 (
" Should be between %5.1f MHz. and %5.1f MHz.\n",
1041 if (Error)
return 0.0;
1042 else return EffectiveFreq;
1057 static const iocshArg FracSynthControlWordArg0 = {
"DesiredFreq", iocshArgDouble};
1058 static const iocshArg *
const FracSynthControlWordArgs[1] = {&FracSynthControlWordArg0};
1059 static const iocshFuncDef FracSynthControlWordDef = {
"FracSynthControlWord", 1,
1060 FracSynthControlWordArgs};
1063 void FracSynthControlWordCall (
const iocshArgBuf *
args) {
1073 static const iocshArg FracSynthAnalyzeArg0 = {
"ControlWord", iocshArgInt};
1074 static const iocshArg *
const FracSynthAnalyzeArgs[1] = {&FracSynthAnalyzeArg0};
1075 static const iocshFuncDef FracSynthAnalyzeDef = {
"FracSynthAnalyze", 1,
1076 FracSynthAnalyzeArgs};
1079 void FracSynthAnalyzeCall (
const iocshArgBuf *
args) {
1089 void FracSynthRegistrar () {
1090 iocshRegister (&FracSynthControlWordDef , FracSynthControlWordCall );
1091 iocshRegister (&FracSynthAnalyzeDef , FracSynthAnalyzeCall);
epicsShareExtern epicsUInt32 FracSynthControlWord(epicsFloat64 DesiredFreq, epicsFloat64 ReferenceFreq, epicsInt32 debugFlag, epicsFloat64 *Error)
#define CORRECTION_DIV_15
#define DEBUGPRINT(interest, globalFlag, args)
#define CONTROL_NDIV_SHIFT
#define CORRECTION_DIV_16
#define CONTROL_QPM1_SHIFT
#define MRF_DEF_CLOCK_SPEED
epicsFloat64 EffectiveFreq
#define CONTROL_PREAMBLE_MASK
#define CORRECTION_DIV_14
#define CONTROL_POSTDIV_MASK
#define CONTROL_PREAMBLE_BITS
epicsShareExtern epicsStatus mrfSetEventClockSpeed(epicsFloat64 InputClockSpeed, epicsUInt32 InputControlWord, epicsFloat64 ReferenceFreq, epicsFloat64 *OutputClockSpeed, epicsUInt32 *OutputControlWord, epicsInt32 PrintFlag)
#define NUM_POST_DIVIDE_VALS
epicsExportRegistrar(FracSynthRegistrar)
#define CONTROL_NDIV_MASK
#define CONTROL_MDIV_MASK
#define CONTROL_MDIV_SHIFT
#define CORRECTION_DIV_32
#define CONTROL_POSTDIV_SHIFT
#define MAX_CORRECTION_RATIO
#define CORRECTION_DIV_18
#define MRF_FRAC_SYNTH_REF
#define CORRECTION_DIV_17
#define CONTROL_PREAMBLE_SHIFT
#define CORRECTION_DIV_31
epicsShareExtern epicsFloat64 FracSynthAnalyze(epicsUInt32 ControlWord, epicsFloat64 ReferenceFreq, epicsInt32 PrintFlag)
epicsInt32 CorrectionIndex
#define CONTROL_MFG_SHIFT
#define CONTROL_QPM1_MASK
#define NUM_CORRECTION_VALS