diff --git a/bin/adf4351 b/bin/adf4351 new file mode 100755 index 0000000..5a6b04c Binary files /dev/null and b/bin/adf4351 differ diff --git a/scripts/a.sh b/scripts/a.sh index 8959c73..774a60c 100755 --- a/scripts/a.sh +++ b/scripts/a.sh @@ -97,6 +97,7 @@ case "$MODE_OUTPUT" in OUTPUT=videots MODE=IQ $PATHSCRIPT"/ctlfilter.sh" + $PATHSCRIPT"/ctlvco.sh" #GAIN=0 ;; QPSKRF) diff --git a/scripts/ctlvco.sh b/scripts/ctlvco.sh new file mode 100755 index 0000000..ff35833 --- /dev/null +++ b/scripts/ctlvco.sh @@ -0,0 +1,40 @@ +########## ctlvco.sh ############ + +# Called by a.sh in IQ mode to set ADF4351 +# vco to correct frequency + +############ Set Environment Variables ############### + +PATHSCRIPT=/home/pi/rpidatv/scripts +PATHRPI=/home/pi/rpidatv/bin +CONFIGFILE=$PATHSCRIPT"/rpidatvconfig.txt" + +############### Function to read Config File ############### + +get_config_var() { +lua - "$1" "$2" <. + *********************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adf4351.h" + +// The SPI bus parameters +// Variables as they need to be passed as pointers later on + +const static char *spiDev0 = "/dev/spidev0.0" ; +const static char *spiDev1 = "/dev/spidev0.1" ; +const static uint8_t spiBPW = 8 ; +const static uint16_t spiDelay = 0 ; + +static uint32_t spiSpeeds [2] ; +static int spiFds [2] ; + +int SPIDataRW (int channel, unsigned char *data, int len) +{ + struct spi_ioc_transfer spi ; + + channel &= 1 ; + +// Mentioned in spidev.h but not used in the original kernel documentation +// test program )-: + + memset (&spi, 0, sizeof (spi)) ; + + spi.tx_buf = (unsigned long)data ; + spi.rx_buf = (unsigned long)data ; + spi.len = len ; + spi.delay_usecs = spiDelay ; + spi.speed_hz = spiSpeeds [channel] ; + spi.bits_per_word = spiBPW ; + + //return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ; + return 0; +} + +/***************************************************************************//** + * @brief Was used to open the spi device set up the SPI mode. Now unused + * + * @param data - int channel, int speed, int mode + * + * @return Always Returns 0 +*******************************************************************************/ + +int SPISetupMode (int channel, int speed, int mode) +{ + int fd ; + + mode &= 3 ; // Mode is 0, 1, 2 or 3 + channel &= 1 ; // Channel is 0 or 1 + + return 0; +} + + +/******************************************************************************/ +/************************ Local variables and types ***************************/ +/******************************************************************************/ +static struct adf4350_state +{ + struct adf4350_platform_data *pdata; + uint32_t clkin; + uint32_t chspc; /* Channel Spacing */ + uint32_t fpfd; /* Phase Frequency Detector */ + uint32_t min_out_freq; + uint32_t r0_fract; + uint32_t r0_int; + uint32_t r1_mod; + uint32_t r4_rf_div_sel; + uint32_t regs[6]; + uint32_t regs_hw[6]; + uint32_t val; +}adf4350_st; + +uint8_t adf4350_slave_select; + +/***************************************************************************//** + * @brief Writes 4 bytes (32 bits) of data to ADF4350. + * + * @param data - Data value to write + * + * @return Always Returns 0 +*******************************************************************************/ +int32_t adf4350_write(uint32_t data) +{ + // Nominate pins using WiringPi numbers + + // LE pin 27 wPi 30 + // CLK pin 29 wPi 21 + // Data pin 31 wPi 22 + + uint8_t LE_4351_GPIO = 30; + uint8_t CLK_4351_GPIO = 21; + uint8_t DATA_4351_GPIO = 22; + + // Kick wiringPi into action. Essential! + + //if (wiringPiSetup () == -1) + //printf("Wiring Pi not set up "); + + // Set all nominated pins to outputs + + pinMode(LE_4351_GPIO, OUTPUT); + pinMode(CLK_4351_GPIO, OUTPUT); + pinMode(DATA_4351_GPIO, OUTPUT); + + // Set idle conditions + + digitalWrite(LE_4351_GPIO, HIGH); + digitalWrite(CLK_4351_GPIO, LOW); + digitalWrite(DATA_4351_GPIO, LOW); + + //Select device LE low + + digitalWrite(LE_4351_GPIO, LOW); + + printf(" ADF4351 Register (one of the five) Updated\n"); + // Initialise loop + + uint16_t i; + + // Send all 32 bits + + for (i = 0; i <32; i++) + { + // Test left-most bit + + if (data & 0x80000000) + digitalWrite(DATA_4351_GPIO, HIGH); + else + digitalWrite(DATA_4351_GPIO, LOW); + + // Pulse clock + + digitalWrite(CLK_4351_GPIO, HIGH); + delay(1); + digitalWrite(CLK_4351_GPIO, LOW); + delay(1); + // shift data left so next bit will be leftmost + + data <<= 1; + } + + //Set ADF4351 LE high + + digitalWrite(LE_4351_GPIO, HIGH); + + return 0; +} + +/***************************************************************************//** + * @brief Updates the registers values. + * + * @param st - The selected structure. + * + * @return Returns 0 in case of success or negative error code. +*******************************************************************************/ +int32_t adf4350_sync_config(struct adf4350_state *st) +{ + int32_t ret, i, doublebuf = 0; + + for (i = ADF4350_REG5; i >= ADF4350_REG0; i--) + { + if ((st->regs_hw[i] != st->regs[i]) || + ((i == ADF4350_REG0) && doublebuf)) + { + switch (i) + { + case ADF4350_REG1: + case ADF4350_REG4: + doublebuf = 1; + break; + } + + st->val = (st->regs[i] | i); + ret = adf4350_write(st->val); + if (ret < 0) + return ret; + st->regs_hw[i] = st->regs[i]; + } + } + + return 0; +} + +/***************************************************************************//** + * @brief Increases the R counter value until the ADF4350_MAX_FREQ_PFD is + * greater than PFD frequency. + * + * @param st - The selected structure. + * @param r_cnt - Initial r_cnt value. + * + * @return Returns 0 in case of success or negative error code. +*******************************************************************************/ +int32_t adf4350_tune_r_cnt(struct adf4350_state *st, uint16_t r_cnt) +{ + struct adf4350_platform_data *pdata = st->pdata; + + do + { + r_cnt++; + st->fpfd = (st->clkin * (pdata->ref_doubler_en ? 2 : 1)) / + (r_cnt * (pdata->ref_div2_en ? 2 : 1)); + } while (st->fpfd > ADF4350_MAX_FREQ_PFD); + + return r_cnt; +} + +/***************************************************************************//** + * @brief Computes the greatest common divider of two numbers + * + * @return Returns the gcd. +*******************************************************************************/ +uint32_t gcd(uint32_t x, uint32_t y) +{ + int32_t tmp; + + tmp = y > x ? x : y; + + + while((x % tmp) || (y % tmp)) + { + tmp--; + } + + return tmp; +} + +/***************************************************************************//** + * @brief Sets the ADF4350 frequency. + * + * @param st - The selected structure. + * @param freq - The desired frequency value. + * + * @return calculatedFrequency - The actual frequency value that was set. +*******************************************************************************/ +int64_t adf4350_set_freq(struct adf4350_state *st, uint64_t freq) +{ + struct adf4350_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 > ADF4350_MAX_OUT_FREQ) || (freq < ADF4350_MIN_OUT_FREQ)) + return -1; + + if (freq > ADF4350_MAX_FREQ_45_PRESC) { + prescaler = ADF4350_REG1_PRESCALER; + mdiv = 75; + } + else + { + prescaler = 0; + mdiv = 23; + } + + st->r4_rf_div_sel = 0; + + while (freq < ADF4350_MIN_VCO_FREQ) + { + freq <<= 1; + st->r4_rf_div_sel++; + } + + /* + * 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 = adf4350_tune_r_cnt(st, r_cnt); + st->r1_mod = st->fpfd / chspc; + if (r_cnt > ADF4350_MAX_R_CNT) + { + /* try higher spacing values */ + chspc++; + r_cnt = 0; + } + } while ((st->r1_mod > ADF4350_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 = tmp; + } while (mdiv > st->r0_int); + + band_sel_div = st->fpfd % ADF4350_MAX_BANDSEL_CLK > ADF4350_MAX_BANDSEL_CLK / 2 ? + st->fpfd / ADF4350_MAX_BANDSEL_CLK + 1 : + st->fpfd / ADF4350_MAX_BANDSEL_CLK; + + 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[ADF4350_REG0] = ADF4350_REG0_INT(st->r0_int) | + ADF4350_REG0_FRACT(st->r0_fract); + + st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(1) | + ADF4350_REG1_MOD(st->r1_mod) | + prescaler; + + st->regs[ADF4350_REG2] = + ADF4350_REG2_10BIT_R_CNT(r_cnt) | + ADF4350_REG2_DOUBLE_BUFF_EN | + (pdata->ref_doubler_en ? ADF4350_REG2_RMULT2_EN : 0) | + (pdata->ref_div2_en ? ADF4350_REG2_RDIV2_EN : 0) | + (pdata->r2_user_settings & (ADF4350_REG2_PD_POLARITY_POS | + ADF4350_REG2_LDP_6ns | ADF4350_REG2_LDF_INT_N | + ADF4350_REG2_CHARGE_PUMP_CURR_uA(5000) | + ADF4350_REG2_MUXOUT(0x7) | ADF4350_REG2_NOISE_MODE(0x9))); + + st->regs[ADF4350_REG3] = pdata->r3_user_settings & + (ADF4350_REG3_12BIT_CLKDIV(0xFFF) | + ADF4350_REG3_12BIT_CLKDIV_MODE(0x3) | + ADF4350_REG3_12BIT_CSR_EN); + + st->regs[ADF4350_REG4] = + ADF4350_REG4_FEEDBACK_FUND | + ADF4350_REG4_RF_DIV_SEL(st->r4_rf_div_sel) | + ADF4350_REG4_8BIT_BAND_SEL_CLKDIV(band_sel_div) | + ADF4350_REG4_RF_OUT_EN | + (pdata->r4_user_settings & + (ADF4350_REG4_OUTPUT_PWR(0x3) | + ADF4350_REG4_AUX_OUTPUT_PWR(0x3) | + ADF4350_REG4_AUX_OUTPUT_EN | + ADF4350_REG4_AUX_OUTPUT_FUND | + ADF4350_REG4_MUTE_TILL_LOCK_EN)); + + st->regs[ADF4350_REG5] = ADF4350_REG5_LD_PIN_MODE_DIGITAL | 0x00180000; + + ret = adf4350_sync_config(st); + 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; +} + +/***************************************************************************//** + * @brief Initializes the ADF4350. + * + * @param spiBaseAddr - SPI peripheral AXI base address. + * @param ssNo - Slave select line on which the slave is connected. + * + * @return Returns 0 in case of success or negative error code. +*******************************************************************************/ +int32_t adf4350_setup(uint32_t spi_device_id, uint8_t slave_select, + adf4350_init_param init_param) +{ + struct adf4350_state *st = &adf4350_st; + + adf4350_slave_select = slave_select; + + SPISetupMode(spi_device_id,500000,0);//To CHeck last parameters : fixeme ! + st->pdata = (struct adf4350_platform_data *)malloc(sizeof(*st->pdata)); + if (!st->pdata) + return -1; + + st->pdata->clkin = init_param.clkin; + + st->pdata->channel_spacing = init_param.channel_spacing; + + st->pdata->power_up_frequency = init_param.power_up_frequency; + st->pdata->ref_div_factor = init_param.reference_div_factor; + st->pdata->ref_doubler_en = init_param.reference_doubler_enable; + st->pdata->ref_div2_en = init_param.reference_div2_enable; + + /* r2_user_settings */ + + st->pdata->r2_user_settings = init_param.phase_detector_polarity_positive_enable ? + ADF4350_REG2_PD_POLARITY_POS : 0; + st->pdata->r2_user_settings |= init_param.lock_detect_precision_6ns_enable ? + ADF4350_REG2_LDP_6ns : 0; + st->pdata->r2_user_settings |= init_param.lock_detect_function_integer_n_enable ? + ADF4350_REG2_LDF_INT_N : 0; + st->pdata->r2_user_settings |= ADF4350_REG2_CHARGE_PUMP_CURR_uA(init_param.charge_pump_current); + st->pdata->r2_user_settings |= ADF4350_REG2_MUXOUT(init_param.muxout_select); + st->pdata->r2_user_settings |= init_param.low_spur_mode_enable ? ADF4350_REG2_NOISE_MODE(0x3) : 0; + + /* r3_user_settings */ + + st->pdata->r3_user_settings = init_param.cycle_slip_reduction_enable ? + ADF4350_REG3_12BIT_CSR_EN : 0; + st->pdata->r3_user_settings |= init_param.charge_cancellation_enable ? + ADF4351_REG3_CHARGE_CANCELLATION_EN : 0; + st->pdata->r3_user_settings |= init_param.anti_backlash_3ns_enable ? + ADF4351_REG3_ANTI_BACKLASH_3ns_EN : 0; + st->pdata->r3_user_settings |= init_param.band_select_clock_mode_high_enable ? + ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH : 0; + st->pdata->r3_user_settings |= ADF4350_REG3_12BIT_CLKDIV(init_param.clk_divider_12bit); + st->pdata->r3_user_settings |= ADF4350_REG3_12BIT_CLKDIV_MODE(init_param.clk_divider_mode); + + /* r4_user_settings */ + + st->pdata->r4_user_settings = init_param.aux_output_enable ? + ADF4350_REG4_AUX_OUTPUT_EN : 0; + st->pdata->r4_user_settings |= init_param.aux_output_fundamental_enable ? + ADF4350_REG4_AUX_OUTPUT_FUND : 0; + st->pdata->r4_user_settings |= init_param.mute_till_lock_enable ? + ADF4350_REG4_MUTE_TILL_LOCK_EN : 0; + st->pdata->r4_user_settings |= ADF4350_REG4_OUTPUT_PWR(init_param.output_power); + st->pdata->r4_user_settings |= ADF4350_REG4_AUX_OUTPUT_PWR(init_param.aux_output_power); + + adf4350_out_altvoltage0_refin_frequency(st->pdata->clkin); + adf4350_out_altvoltage0_frequency_resolution(st->pdata->channel_spacing); + adf4350_out_altvoltage0_frequency(st->pdata->power_up_frequency); + + printf("ADF4350 successfully initialized.\n"); + /*int i; + for(i=0;i<6;i++) + printf("RegHw%d %x\n",i,st->regs[i]); + printf("Reg2 %x\n",st->pdata->r2_user_settings); + printf("Reg3 %x\n",st->pdata->r3_user_settings); + printf("Reg4 %x\n",st->pdata->r4_user_settings);*/ + + return 0; +} + +/***************************************************************************//** + * @brief Stores PLL 0 frequency in Hz. + * + * @param Hz - The selected frequency. + * + * @return Returns the selected frequency. +*******************************************************************************/ +int64_t adf4350_out_altvoltage0_frequency(int64_t Hz) +{ + return adf4350_set_freq(&adf4350_st, Hz); +} + +/***************************************************************************//** + * @brief Stores PLL 0 frequency resolution/channel spacing in Hz. + * + * @param Hz - The selected frequency. + * + * @return Returns the selected frequency. +*******************************************************************************/ +int32_t adf4350_out_altvoltage0_frequency_resolution(int32_t Hz) +{ + if(Hz != INT32_MAX) + { + adf4350_st.chspc = Hz; + } + + return adf4350_st.chspc; +} + +/***************************************************************************//** + * @brief Sets PLL 0 REFin frequency in Hz. + * + * @param Hz - The selected frequency. + * + * @return Returns the selected frequency. +*******************************************************************************/ +int64_t adf4350_out_altvoltage0_refin_frequency(int64_t Hz) +{ + if(Hz != INT32_MAX) + { + adf4350_st.clkin = Hz; + } + + return adf4350_st.clkin; +} + +/***************************************************************************//** + * @brief Powers down the PLL. + * + * @param pwd - Power option. + * Example: 0 - Power up the PLL. + * 1 - Power down the PLL. + * + * @return Returns the PLL's power status. +*******************************************************************************/ +int32_t adf4350_out_altvoltage0_powerdown(int32_t pwd) +{ + struct adf4350_state *st = &adf4350_st; + + if(pwd == 1) + { + st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; + adf4350_sync_config(st); + } + if(pwd == 0) + { + st->regs[ADF4350_REG2] &= ~ADF4350_REG2_POWER_DOWN_EN; + adf4350_sync_config(st); + } + + return (st->regs[ADF4350_REG2] & ADF4350_REG2_POWER_DOWN_EN); +} diff --git a/src/adf4351/adf4351.h b/src/adf4351/adf4351.h new file mode 100644 index 0000000..1370709 --- /dev/null +++ b/src/adf4351/adf4351.h @@ -0,0 +1,198 @@ +/***************************************************************************//** + * @file adf4350.h + * @brief Header file of ADF4350 Driver. + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2012-2015(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +*******************************************************************************/ +#ifndef __ADF4350_H__ +#define __ADF4350_H__ + +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ +#include + +/******************************************************************************/ +/********************** Macros and Constants Definitions **********************/ +/******************************************************************************/ + +/* Channels */ +#define ADF4350_RX_CHANNEL 0 +#define ADF4350_TX_CHANNEL 1 + +/* Registers */ +#define ADF4350_REG0 0 +#define ADF4350_REG1 1 +#define ADF4350_REG2 2 +#define ADF4350_REG3 3 +#define ADF4350_REG4 4 +#define ADF4350_REG5 5 + +/* REG0 Bit Definitions */ +#define ADF4350_REG0_FRACT(x) (((x) & 0xFFF) << 3) +#define ADF4350_REG0_INT(x) (((x) & 0xFFFF) << 15) + +/* REG1 Bit Definitions */ +#define ADF4350_REG1_MOD(x) (((x) & 0xFFF) << 3) +#define ADF4350_REG1_PHASE(x) (((x) & 0xFFF) << 15) +#define ADF4350_REG1_PRESCALER (1 << 27) + +/* REG2 Bit Definitions */ +#define ADF4350_REG2_COUNTER_RESET_EN (1 << 3) +#define ADF4350_REG2_CP_THREESTATE_EN (1 << 4) +#define ADF4350_REG2_POWER_DOWN_EN (1 << 5) +#define ADF4350_REG2_PD_POLARITY_POS (1 << 6) +#define ADF4350_REG2_LDP_6ns (1 << 7) +#define ADF4350_REG2_LDP_10ns (0 << 7) +#define ADF4350_REG2_LDF_FRACT_N (0 << 8) +#define ADF4350_REG2_LDF_INT_N (1 << 8) +#define ADF4350_REG2_CHARGE_PUMP_CURR_uA(x) (((((x)-312) / 312) & 0xF) << 9) +#define ADF4350_REG2_DOUBLE_BUFF_EN (1 << 13) +#define ADF4350_REG2_10BIT_R_CNT(x) ((x) << 14) +#define ADF4350_REG2_RDIV2_EN (1 << 24) +#define ADF4350_REG2_RMULT2_EN (1 << 25) +#define ADF4350_REG2_MUXOUT(x) ((x) << 26) +#define ADF4350_REG2_NOISE_MODE(x) ((x) << 29) + +/* REG3 Bit Definitions */ +#define ADF4350_REG3_12BIT_CLKDIV(x) ((x) << 3) +#define ADF4350_REG3_12BIT_CLKDIV_MODE(x) ((x) << 16) +#define ADF4350_REG3_12BIT_CSR_EN (1 << 18) +#define ADF4351_REG3_CHARGE_CANCELLATION_EN (1 << 21) +#define ADF4351_REG3_ANTI_BACKLASH_3ns_EN (1 << 22) +#define ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH (1 << 23) + +/* REG4 Bit Definitions */ +#define ADF4350_REG4_OUTPUT_PWR(x) ((x) << 3) +#define ADF4350_REG4_RF_OUT_EN (1 << 5) +#define ADF4350_REG4_AUX_OUTPUT_PWR(x) ((x) << 6) +#define ADF4350_REG4_AUX_OUTPUT_EN (1 << 8) +#define ADF4350_REG4_AUX_OUTPUT_FUND (1 << 9) +#define ADF4350_REG4_AUX_OUTPUT_DIV (0 << 9) +#define ADF4350_REG4_MUTE_TILL_LOCK_EN (1 << 10) +#define ADF4350_REG4_VCO_PWRDOWN_EN (1 << 11) +#define ADF4350_REG4_8BIT_BAND_SEL_CLKDIV(x) ((x) << 12) +#define ADF4350_REG4_RF_DIV_SEL(x) ((x) << 20) +#define ADF4350_REG4_FEEDBACK_DIVIDED (0 << 23) +#define ADF4350_REG4_FEEDBACK_FUND (1 << 23) + +/* REG5 Bit Definitions */ +#define ADF4350_REG5_LD_PIN_MODE_LOW (0 << 22) +#define ADF4350_REG5_LD_PIN_MODE_DIGITAL (1 << 22) +#define ADF4350_REG5_LD_PIN_MODE_HIGH (3 << 22) + +/* Specifications */ +#define ADF4350_MAX_OUT_FREQ 4400000000ULL /* Hz */ +#define ADF4350_MIN_OUT_FREQ 34375000 /* Hz */ +#define ADF4350_MIN_VCO_FREQ 2200000000ULL /* Hz */ +#define ADF4350_MAX_FREQ_45_PRESC 3000000000ULL /* Hz */ +#define ADF4350_MAX_FREQ_PFD 32000000 /* Hz */ +#define ADF4350_MAX_BANDSEL_CLK 125000 /* Hz */ +#define ADF4350_MAX_FREQ_REFIN 250000000 /* Hz */ +#define ADF4350_MAX_MODULUS 4095 +#define ADF4350_MAX_R_CNT 1023 + +/******************************************************************************/ +/************************ Types Definitions ***********************************/ +/******************************************************************************/ +struct adf4350_platform_data +{ + uint32_t clkin; + uint32_t channel_spacing; + uint64_t power_up_frequency; + + uint16_t ref_div_factor; /* 10-bit R counter */ + uint8_t ref_doubler_en; + uint8_t ref_div2_en; + + uint32_t r2_user_settings; + uint32_t r3_user_settings; + uint32_t r4_user_settings; + int32_t gpio_lock_detect; +}; + +typedef struct +{ + uint32_t clkin; + uint32_t channel_spacing; + uint32_t power_up_frequency; + uint32_t reference_div_factor; + uint8_t reference_doubler_enable; + uint8_t reference_div2_enable; + + /* r2_user_settings */ + uint8_t phase_detector_polarity_positive_enable; + uint8_t lock_detect_precision_6ns_enable; + uint8_t lock_detect_function_integer_n_enable; + uint32_t charge_pump_current; + uint32_t muxout_select; + uint8_t low_spur_mode_enable; + + /* r3_user_settings */ + uint8_t cycle_slip_reduction_enable; + uint8_t charge_cancellation_enable; + uint8_t anti_backlash_3ns_enable; + uint8_t band_select_clock_mode_high_enable; + uint32_t clk_divider_12bit; + uint32_t clk_divider_mode; + + /* r4_user_settings */ + uint8_t aux_output_enable; + uint8_t aux_output_fundamental_enable; + uint8_t mute_till_lock_enable; + uint32_t output_power; + uint32_t aux_output_power; +}adf4350_init_param; + +/******************************************************************************/ +/************************ Functions Declarations ******************************/ +/******************************************************************************/ +/*! Initializes the ADF4350. */ +int32_t adf4350_setup(uint32_t spi_device_id, uint8_t slave_select, + adf4350_init_param init_param); +/*! Writes 4 bytes of data to ADF4350. */ +int32_t adf4350_write(uint32_t data); +/*! Stores PLL 0 frequency in Hz. */ +int64_t adf4350_out_altvoltage0_frequency(int64_t Hz); +/*! Stores PLL 0 frequency resolution/channel spacing in Hz. */ +int32_t adf4350_out_altvoltage0_frequency_resolution(int32_t Hz); +/*! Sets PLL 0 REFin frequency in Hz. */ +int64_t adf4350_out_altvoltage0_refin_frequency(int64_t Hz); +/*! Powers down the PLL. */ +int32_t adf4350_out_altvoltage0_powerdown(int32_t pwd); + +#endif // __ADF4350_H__ + diff --git a/src/adf4351/ctladf4351.c b/src/adf4351/ctladf4351.c new file mode 100644 index 0000000..f98400d --- /dev/null +++ b/src/adf4351/ctladf4351.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adf4351.h" + +adf4350_init_param MyAdf= +{.clkin=25000000, +.channel_spacing=5000, +.power_up_frequency=437000000, +.reference_div_factor=0, +.reference_doubler_enable=0, +.reference_div2_enable=0, + + // r2_user_settings +.phase_detector_polarity_positive_enable=1, +.lock_detect_precision_6ns_enable=0, +.lock_detect_function_integer_n_enable=0, +.charge_pump_current=7, // FixMe +.muxout_select=0, +.low_spur_mode_enable=1, + + // r3_user_settings +.cycle_slip_reduction_enable=1, +.charge_cancellation_enable=0, +.anti_backlash_3ns_enable=0, +.band_select_clock_mode_high_enable=1, +.clk_divider_12bit=0, +.clk_divider_mode=0, + + // r4_user_settings +.aux_output_enable=1, +.aux_output_fundamental_enable=1, +.mute_till_lock_enable=0, +.output_power=0,//-4dbm +.aux_output_power=0 + +}; +uint32_t registers[6] = {0x4580A8, 0x80080C9, 0x4E42, 0x4B3, 0xBC803C, 0x580005}; +//REG 0 +//REG1 1000000000001000000011001 001 +//REG2 100111001000 010 +//REG3 10010110 011 +//REG4 101111001000000000111 100 + + +/***************************************************************************//** + * @brief Powers off or sets the Synth frequency. + * + * @param "off" or freq in MHz (float). + * + * @return 0 or 1 if freq out of bounds +*******************************************************************************/ + +int main(int argc, char *argv[]) +{ + if (wiringPiSetup() == -1); + + if (strcmp(argv[1], "off") == 0) + { + // Turn VCO Off and return + + adf4350_out_altvoltage0_powerdown(1); + + return 0; + } + else if ( atof(argv[1])>=35 && atof(argv[1])<=4400 ) + { + // Valid freq, so set it + uint32_t adf4350_requested_frequency = 1000000 * atof(argv[1]); + + adf4350_setup(0,0,MyAdf); + adf4350_out_altvoltage0_frequency(adf4350_requested_frequency); + + return 0; + } + else + { + // Requested freq out of limits so print error and return 1 + printf("ERROR: Requested Frequency out of limits"); + + return 1; + + } +}