/** * This method sets the frequency as close the value specified as possible * Argument : Requested frequency in Hertz * Return : Actual frequency in Hertz */ int64_t Adf4351::SetFrequency( int64_t freqHz ) { double Fin; double Fpsd; double frac; double Fvco; int mul,divCode; unsigned int prevR4; if( mLog & ADF_LOG_FREQ_CALC ){ printf("Adf4351::SetFrequency d=%d f=%f\n",mDevNum,(double)freqHz ); } if( freqHz/1e6 < 34 ){ fprintf(stderr,"f=%f too low\n",(double)freqHz); return(1); } if( freqHz/1e6 > 4500 ){ fprintf(stderr,"f=%f too high\n",(double)freqHz); return(1); } // Reference frequency specified by oscillator on board Fin = 25000000; Fpsd = Fin/mR; // Fvco must be within 2200Mhz - 4400Mhz Fvco = freqHz; mul = 1; while( Fvco < 2200e6 ){ mul = mul * 2; Fvco = Fvco * 2; } if( mLog & ADF_LOG_FREQ_CALC ){ printf("Div=%3d, Fvco=%f Fin=%f Fpsd=%f\n",mul,Fvco,Fin,Fpsd); } mInt = Fvco / Fpsd; frac = ( Fvco - (mInt*Fpsd) )/Fpsd; mFrac= frac * mMod; if( mLog & ADF_LOG_FREQ_CALC ){ printf("INT=%8d, FRAC=%8d\n",mInt,mFrac); } freqHz = (mInt*Fpsd + Fpsd*mFrac/mMod )/mul; if( mLog & ADF_LOG_FREQ_CALC ){ printf("Factual=%f\n",(double)freqHz); } switch( mul ){ case 1: divCode = 0;break; case 2: divCode = 1;break; case 4: divCode = 2;break; case 8: divCode = 3;break; case 16: divCode = 4;break; case 32: divCode = 5;break; case 64: divCode = 6;break; default: divCode = 6;break; } // Update R4 for divider and only program if different prevR4 = mRegs[ADF4351_REG4]; mRegs[ADF4351_REG4] &= ~ADF4351_REG4_RF_DIV_SEL( 0x7 ); mRegs[ADF4351_REG4] |= ADF4351_REG4_RF_DIV_SEL( divCode ); if( mRegs[ADF4351_REG4] != prevR4 ){ (mSpiWriteFunc)(mDevNum,mLog&ADF_LOG_WRITES,mRegs[ADF4351_REG4]); } // Program R0 for int/frac mRegs[ADF4351_REG0] = ADF4351_REG0_FRACT( mFrac ) | ADF4351_REG0_INT( mInt ) | 0x0; (mSpiWriteFunc)(mDevNum,mLog&ADF_LOG_WRITES,mRegs[ADF4351_REG0]); mFactHz = freqHz; return( freqHz ); }
/***************************************************************************//** * @brief Sets the ADF4351 frequency on the specified channel. * * @param st - The selected structure. * @param freq - The desired frequency value. * @param channel - 0 = RX channel, 1 = TX channel * * @return calculatedFrequency - The actual frequency value that was set. *******************************************************************************/ int64_t adf4351_set_freq(struct adf4351_state *st, uint64_t freq, char channel) { struct adf4351_platform_data *pdata = st->pdata; uint64_t tmp; uint32_t div_gcd, prescaler, chspc; uint16_t mdiv, r_cnt = 0; uint8_t band_sel_div; int32_t ret; if ((freq > ADF4351_MAX_OUT_FREQ) || (freq < ADF4351_MIN_OUT_FREQ)) return -1; st->r4_rf_div_sel = 0; while (freq < ADF4351_MIN_VCO_FREQ) { freq <<= 1; st->r4_rf_div_sel++; } if (freq > ADF4351_MAX_FREQ_45_PRESC) { prescaler = ADF4351_REG1_PRESCALER; mdiv = 75; } else { prescaler = 0; mdiv = 23; } /* * Allow a predefined reference division factor * if not set, compute our own */ if (pdata->ref_div_factor) r_cnt = pdata->ref_div_factor - 1; chspc = st->chspc; do { do { do { r_cnt = adf4351_tune_r_cnt(st, r_cnt); st->r1_mod = st->fpfd / chspc; if (r_cnt > ADF4351_MAX_R_CNT) { /* try higher spacing values */ chspc++; r_cnt = 0; } } while ((st->r1_mod > ADF4351_MAX_MODULUS) && r_cnt); } while (r_cnt == 0); tmp = freq * (uint64_t)st->r1_mod + (st->fpfd > 1); tmp = (tmp / st->fpfd); /* Div round closest (n + d/2)/d */ st->r0_fract = tmp % st->r1_mod; tmp = tmp / st->r1_mod; st->r0_int = (uint32_t)tmp; } while (mdiv > st->r0_int); band_sel_div = (((st->fpfd) + (ADF4351_MAX_BANDSEL_CLK) - 1) / (ADF4351_MAX_BANDSEL_CLK)); // DIV_ROUND_UP if (st->fpfd == ADF4351_MAX_FREQ_PFD) band_sel_div = 255; if (st->r0_fract && st->r1_mod) { div_gcd = gcd(st->r1_mod, st->r0_fract); st->r1_mod /= div_gcd; st->r0_fract /= div_gcd; } else { st->r0_fract = 0; st->r1_mod = 1; } st->regs[ADF4351_REG0] = ADF4351_REG0_INT(st->r0_int) | ADF4351_REG0_FRACT(st->r0_fract); st->regs[ADF4351_REG1] = ADF4351_REG1_PHASE(1) | ADF4351_REG1_MOD(st->r1_mod) | prescaler; st->regs[ADF4351_REG2] = ADF4351_REG2_10BIT_R_CNT(r_cnt) | ADF4351_REG2_DOUBLE_BUFF_EN | (pdata->ref_doubler_en ? ADF4351_REG2_RMULT2_EN : 0) | (pdata->ref_div2_en ? ADF4351_REG2_RDIV2_EN : 0) | (pdata->r2_user_settings & (ADF4351_REG2_PD_POLARITY_POS | ADF4351_REG2_LDP_6ns | ADF4351_REG2_LDF_INT_N | ADF4351_REG2_CHARGE_PUMP_CURR_uA(5000) | ADF4351_REG2_MUXOUT(0x7) | ADF4351_REG2_NOISE_MODE(0x3))); st->regs[ADF4351_REG3] = pdata->r3_user_settings & (ADF4351_REG3_12BIT_CLKDIV(0xFFF) | ADF4351_REG3_12BIT_CLKDIV_MODE(0x3) | ADF4351_REG3_12BIT_CSR_EN | ADF4351_REG3_CHARGE_CANCELLATION_EN | ADF4351_REG3_ANTI_BACKLASH_3ns_EN | ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH); st->regs[ADF4351_REG4] = ADF4351_REG4_FEEDBACK_FUND | ADF4351_REG4_RF_DIV_SEL(st->r4_rf_div_sel) | ADF4351_REG4_8BIT_BAND_SEL_CLKDIV(band_sel_div) | ADF4351_REG4_RF_OUT_EN | (pdata->r4_user_settings & (ADF4351_REG4_OUTPUT_PWR(0x3) | ADF4351_REG4_AUX_OUTPUT_PWR(0x3) | ADF4351_REG4_AUX_OUTPUT_EN | ADF4351_REG4_AUX_OUTPUT_FUND | ADF4351_REG4_MUTE_TILL_LOCK_EN)); st->regs[ADF4351_REG5] = ADF4351_REG5_LD_PIN_MODE_DIGITAL + 0x00180000; ret = adf4351_sync_config(st, channel); if(ret < 0) return ret; tmp = (uint64_t)((st->r0_int * st->r1_mod) + st->r0_fract) * (uint64_t)st->fpfd; tmp = tmp / ((uint64_t)st->r1_mod * ((uint64_t)1 << st->r4_rf_div_sel)); return tmp; }
/** * This method tests the spi interface to the device and configures * the registers. */ int Adf4351::Open( Adf4351SpiWriteFuncPtr spiWriteFunc, Adf4351GetLdFuncPtr getLockFunc ) { int err; // Save the io interface we are provided mSpiWriteFunc = spiWriteFunc; mGetLockFunc = getLockFunc; // Test the spi interface and lock detect signal if( mLog & ADF_LOG_SPI_TESTS ){ printf("Adf4351::Open() SPI Test (LD toggle) #######################\n"); } err = this->SpiTest(); if( err ){ fprintf(stderr,"Adf4351::Open SpiTest() failed dev=%d\n",mDevNum); } // Setup the basic configuration mRegs[ADF4351_REG5] = ADF4351_REG5_LD_PIN_MODE_DIGITAL | 0x00180000 | 0x5; mRegs[ADF4351_REG4] = ADF4351_REG4_FEEDBACK_FUND | ADF4351_REG4_RF_DIV_SEL( 6 ) | ADF4351_REG4_8BIT_BAND_SEL_CLKDIV( 255 ) | ADF4351_REG4_AUX_OUTPUT_DIV | ADF4351_REG4_AUX_OUTPUT_EN | ADF4351_REG4_AUX_OUTPUT_PWR(1) | ADF4351_REG4_RF_OUT_EN | ADF4351_REG4_OUTPUT_PWR(1) | 0x4; mRegs[ADF4351_REG3] = ADF4351_REG3_12BIT_CLKDIV(1) | 0x3; mRegs[ADF4351_REG2] = ADF4351_REG2_10BIT_R_CNT( mR ) | ADF4351_REG2_CHARGE_PUMP_CURR_uA( 512 ) | ADF4351_REG2_PD_POLARITY_POS | 0x2; mRegs[ADF4351_REG1] = ADF4351_REG1_PRESCALER | ADF4351_REG1_MOD( mMod ) | 0x1; mRegs[ADF4351_REG0] = ADF4351_REG0_FRACT( mFrac ) | ADF4351_REG0_INT( mInt ) | 0x0; if( mLog & ADF_LOG_SPI_TESTS ){ printf("Adf4351::Open Begin Configure ##############################\n"); } (mSpiWriteFunc)(mDevNum,mLog&ADF_LOG_WRITES,mRegs[ADF4351_REG5]); (mSpiWriteFunc)(mDevNum,mLog&ADF_LOG_WRITES,mRegs[ADF4351_REG4]); (mSpiWriteFunc)(mDevNum,mLog&ADF_LOG_WRITES,mRegs[ADF4351_REG3]); (mSpiWriteFunc)(mDevNum,mLog&ADF_LOG_WRITES,mRegs[ADF4351_REG2]); (mSpiWriteFunc)(mDevNum,mLog&ADF_LOG_WRITES,mRegs[ADF4351_REG1]); (mSpiWriteFunc)(mDevNum,mLog&ADF_LOG_WRITES,mRegs[ADF4351_REG0]); if( mLog & ADF_LOG_SPI_TESTS ){ printf("Adf4351::Open End Configure ##############################\n"); } mIsOpen = 1; return( 0 ); }