/* ============================================================================================= ============================================================================================= Title: sampck_synth.c Description: C design file for (C) Copyright Alpha Data Parallel Systems Ltd. 1999-2005 Mod Record =========== 1)02/05/07 sampck_synth created 2)13/06/2007 15:29:29 Corrected inversion in CPMode masking. Added routines to set the delays in a given channel ( 5 or 6) based on the nearest fit to the required value. A and B Counters The AD9510 B counter has a bypass mode (B = 1), which is not available on the ADF4106. The B counter bypass mode is valid only when using the prescaler in FD mode. The B counter is bypassed by writing 1 to the B counter bypass bit (0Ah<6> = 1b). The valid range of the B counter is 3 to 8191. The default after a reset is 0, which is invalid. Note that the A counter is not used when the prescaler is in FD mode. Note also that the A/B counters have their own reset bit, which is primarily charended for testing. The A and B counters can also be reset using the R, A, and B counters shared reset bit (09h<0>). Determining Values for P, A, B, and R When operating the AD9510 in a dual-modulus mode, the input reference frequency, FREF, is related to the VCO output frequency, FVCO. FVCO = (FREF/R) �(PB + A) = FREF �N/R When operating the prescaler in fixed divide mode, the A counter is not used and the equation simplifies to FVCO = (FREF/R) �(PB) = FREF �N/R By using combinations of dual modulus and fixed divide modes, the AD9510 can achieve values of N all the way down to N = 1. Table 16 shows how a 10 MHz reference input may be locked to any chareger multiple of N. Note that the same value of N may be derived in different ways, as illustrated by N = 12 Setting the Divide Ratio The divide ratio is determined by the values written via the SCP to the registers that control each individual output, OUT0 to OUT7. These are the even numbered registers beginning at 48h and going through 56h. Each of these registers is divided charo bits that control the number of clock cycles that the divider output stays high (high_cycles <3:0>) and the number of clock cycles that the divider output stays low (low_cycles <7:4>). Each value is 4 bits and has the range of 0 to 15. The divide ratio is set by Divide Ratio = (high_cycles + 1) + (low_cycles + 1) The duty cycle is set by Duty Cycle = (high_cycles + 1)/((high_cycles + 1) + (low_cycles + 1)) MSB/LSB FIRST TRANSFERS The AD9510 instruction word and byte data may be MSB first or LSB first. The default for the AD9510 is MSB first. The LSB first mode may be set by writing 1b to Register 00h<6>. This -------------------------------------------------------------------------------------------------*/ /********************************************************************************************** Type Definitions **********************************************************************************************/ /********************************************************************************************/ /********************************************************************************************* Header Files *********************************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <math.h> #include <unistd.h> #include <stdint.h> #include "PllSynth.h" #define D0 0x1 #define D1 0x2 #define D2 0x4 #define D3 0x8 #define D4 0x10 #define D5 0x20 #define D6 0x40 #define D7 0x80 #define D8 0x100 #define D9 0x200 #define D10 0x400 #define D11 0x800 #define D12 0x1000 #define D13 0x2000 #define D14 0x4000 #define D15 0x8000 #define D16 0x10000 #define D17 0x20000 #define D18 0x40000 #define D19 0x80000 #define D20 0x100000 #define D21 0x200000 #define D22 0x400000 #define D23 0x800000 #define D24 0x1000000 #define D25 0x2000000 #define D26 0x4000000 #define D27 0x8000000 #define D28 0x10000000 #define D29 0x20000000 #define D30 0x40000000 #define D31 0x80000000 const int SYNTH_CNTRL_REG = 0x0080 >> 2; // ADC PLL Registers const int SYNTH_STRB_REG = 0x0088 >> 2; // ADC PLL Registers const int SYNTH_RESET_REG = 0x0090 >> 2; // ADC PLL Registers /******************************************************************************* * Control space SYNTH control register * The serial IO is controlled by a state machine so addresses (and data for writes) must * be set up prior to strobe occurring. ******************************************************************************* */ #define SYNTH_WRDATMASK 0xff #define SYNTH_WRDATSHFT 0 #define SYNTH_ADSHFT 8 #define SYNTH_ADMASK 0xff00 #define SYNTH_RDDATMASK 0xff0000 #define SYNTH_RDDATSHFT 16 #define SYNTH_SMBUSY D24 #define SYNTH_SMBUSY_FLAG D25 #define SYNTH_INIBUSY D26 #define SYNTH_STATUS D27 /******************************************************************************* * Control space SYNTH strobe register * A rising edge on the appropriate bit generates a read or write (read dominant) ******************************************************************************* */ #define SYNTH_RDSTRB D0 #define SYNTH_WRSTRB D1 #define SYNTH_INISTRB D2 #define SYNTH_FUNCSTRB D3 // AD 9510 register map #define SYNTH_SER_CNFG 0x00 #define SYNTH_ACNTR 0x04 /*6 bit A counter */ #define SYNTH_BCNTR_MSB 0x05 /*13 bit B counter , top 5 bits */ #define SYNTH_BCNTR_LSB 0x06 /*13 bit B counter , ls byte */ #define SYNTH_LOR 0x07 /*LOR control */ #define SYNTH_MUX_CP 0x08 /*PLL Mux and charge pump*/ #define SYNTH_CPDRV_RST 0x09 /*Resets and CP drive*/ #define SYNTH_PRESCALE 0x0A /*PLL power down and prescale control*/ #define SYNTH_REFCNTR_MSB 0x0B /*14 bit ref counter, top 6 bits*/ #define SYNTH_REFCNTR_LSB 0x0C /*14 bit ref counter, bottom 8 bits*/ #define SYNTH_LOCK_DTCT 0x0D /*Lock detect and antibacklash*/ /*Out 5 delay control*/ #define SYNTH_OUT5_DELBYP 0x34 /*Out 5 Ramp current*/ #define SYNTH_OUT5_RAMP 0x35 /*Out 5 delay fine adjust*/ #define SYNTH_OUT5_DELADJ 0x36 /*Out 6 delay control*/ #define SYNTH_OUT6_DELBYP 0x38 /*Out 6 Ramp current*/ #define SYNTH_OUT6_RAMP 0x39 /*Out 6 delay fine adjust*/ #define SYNTH_OUT6_DELADJ 0x3a /*Out 0 LVPECL control*/ #define SYNTH_OUT0_CNTRL 0x3c /*Out 1 LVPECL control*/ #define SYNTH_OUT1_CNTRL 0x3d /*Out 2 LVPECL control*/ #define SYNTH_OUT2_CNTRL 0x3e /*Out 3 LVPECL control*/ #define SYNTH_OUT3_CNTRL 0x3f /*Out 4 LVDS/CMOS control*/ #define SYNTH_OUT4_CNTRL 0x40 /*Out 5 LVDS/CMOS control*/ #define SYNTH_OUT5_CNTRL 0x41 /*Out 6 LVDS/CMOS control*/ #define SYNTH_OUT6_CNTRL 0x42 /*Out 7 LVDS/CMOS control*/ #define SYNTH_OUT7_CNTRL 0x43 /*0x44 not used*/ /*Clock control*/ #define SYNTH_CLOCK_CNTRL 0x45 /*0x46 to 0x47 not used*/ /*Out0 cycle divider, high and low periods*/ #define SYNTH_OUT0_DIVHILO 0x48 /*Out0 phase offset, start polarity control*/ #define SYNTH_OUT0_POFFS 0x49 /*Out1 cycle divider, high and low periods*/ #define SYNTH_OUT1_DIVHILO 0x4a /*Out1 phase offset, start polarity control*/ #define SYNTH_OUT1_POFFS 0x4b /*Out2 cycle divider, high and low periods*/ #define SYNTH_OUT2_DIVHILO 0x4c /*Out2 phase offset, start polarity control*/ #define SYNTH_OUT2_POFFS 0x4d /*Out3 cycle divider, high and low periods*/ #define SYNTH_OUT3_DIVHILO 0x4e /*Out3 phase offset, start polarity control*/ #define SYNTH_OUT3_POFFS 0x4f /*Out4 cycle divider, high and low periods*/ #define SYNTH_OUT4_DIVHILO 0x50 /*Out4 phase offset, start polarity control*/ #define SYNTH_OUT4_POFFS 0x51 /*Out5 cycle divider, high and low periods*/ #define SYNTH_OUT5_DIVHILO 0x52 /*Out5 phase offset, start polarity control*/ #define SYNTH_OUT5_POFFS 0x53 /*Out6 cycle divider, high and low periods*/ #define SYNTH_OUT6_DIVHILO 0x54 /*Out6 phase offset, start polarity control*/ #define SYNTH_OUT6_POFFS 0x55 /*Out7 cycle divider, high and low periods*/ #define SYNTH_OUT7_DIVHILO 0x56 /*Out7 phase offset, start polarity control*/ #define SYNTH_OUT7_POFFS 0x57 /*Sync and func pin control*/ #define SYNTH_SYNC_FUNC 0x58 /*0x59 not used*/ /*Update register*/ #define SYNTH_UPDATE 0x5A #define SHOW_ALL_REGS 0xFF // Serial Configuration control bits #define SYNTH_LONG_INSTR D4 #define SYNTH_SOFT_RESET D5 #define SYNTH_LSB_FIRST D6 #define SYNTH_SDO_INACTV D7 // Cntr masks #define SYNTH_ACNTR_MASK 0x3F #define SYNTH_BCNTR_MASK 0x1F #define SYNTH_RCNTR_MASK 0x3F // LOR Control (0x07) #define SYNTH_LOR_ENABLE D2 #define SYNTH_LCK_DTCT_LSB D5 #define SYNTH_LCK_DTCT_MSB D6 #define SYNTH_LOR_DLY3 0x00 #define SYNTH_LOR_DLY6 D5 #define SYNTH_LOR_DLY12 D6 #define SYNTH_LOR_DLY24 (D6|D5) #define SYNTH_LOR_MASK (D6|D5) /******************************************************************************* CP Control (0x08) <5> <4> <3> <2> MUXOUTSignal on STATUS Pin 0 0 0 0 Off (Signal Goes Low) (Default) 0 0 0 1 Digital Lock Detect (Active High) 0 0 1 0 N Divider Output 0 0 1 1 Digital Lock Detect (Active Low) 0 1 0 0 R Divider Output 0 1 0 1 Analog Lock Detect (N Channel, Open-Drain) 0 1 1 0 A Counter Output 0 1 1 1 Prescaler Output (NCLK) 1 0 0 0 PFD Up Pulse 1 0 0 1 PFD Down Pulse 1 0 1 0 Loss-of-Reference (Active High) 1 0 1 1 Tri-State 1 1 0 0 Analog Lock Detect (P Channel, Open-Drain) 1 1 0 1 Loss-of-Reference or Loss-of-Lock (Inverse of DLD) (Active High) 1 1 1 0 Loss-of-Reference or Loss-of-Lock (Inverse of DLD) (Active Low) 1 1 1 1 Loss-of-Reference (Active Low) ******************************************************************************* */ #define SYNTH_CPMODE_PMPTRI 0x00 #define SYNTH_CPMODE_PMPUP D0 #define SYNTH_CPMODE_PMPDN D1 #define SYNTH_CPMODE_PMPNORM (D1|D0) #define SYNTH_CPMODE_MASK (D1|D0) #define SYNTH_MUXOUT_OFF 0x00 #define SYNTH_MUXOUT_DLDHI D2 #define SYNTH_MUXOUT_NDIV D3 #define SYNTH_MUXOUT_DLDLO (D3|D2) #define SYNTH_MUXOUT_RDIV D4 #define SYNTH_MUXOUT_ANALOGUE_N (D4|D2) #define SYNTH_MUXOUT_ACNTR (D4|D3) #define SYNTH_MUXOUT_NCLCK (D4|D3|D2) #define SYNTH_MUXOUT_PFDUP (D5) #define SYNTH_MUXOUT_PFDDN (D5|D2) #define SYNTH_MUXOUT_LORHI (D5|D3) #define SYNTH_MUXOUT_TRI (D5|D3|D2) #define SYNTH_MUXOUT_ANALOGUE_P (D5|D4) #define SYNTH_MUXOUT_LORLLKHI (D5|D4|D2) #define SYNTH_MUXOUT_LORLLKLO (D5|D4|D3) #define SYNTH_MUXOUT_LORLO (D5|D4|D3|D2) #define SYNTH_MUXOUT_MASK (D5|D4|D3|D2) #define SYNTH_PFD_POLPOS D6 /******************************************************************************* 09 <0> Reset All Counters 0 = Normal (Default), 1 = Reset R, A, and B Counters 09 <1> N-Counter Reset 0 = Normal (Default), 1 = Reset A and B Counters 09 <2> R-Counter Reset 0 = Normal (Default), 1 = Reset R Counter 09 <3> Not Used 09 <6:4> Charge Pump (CP) Current Setting <6> <5> <4> ICP (mA) 0 0 0 0.60 0 0 1 1.2 0 1 0 1.8 0 1 1 2.4 1 0 0 3.0 1 0 1 3.6 1 1 0 4.2 1 1 1 4.8 ******************************************************************************* */ #define SYNTH_RST_RAB D0 #define SYNTH_RST_AB D1 #define SYNTH_RST_R D2 #define SYNTH_RST_MASK (D0|D1|D2) #define SYNTH_CP_O6 0x00 #define SYNTH_CP_12 D4 #define SYNTH_CP_18 D5 #define SYNTH_CP_24 (D5|D4) #define SYNTH_CP_30 D6 #define SYNTH_CP_36 (D6|D4) #define SYNTH_CP_42 (D6|D5) #define SYNTH_CP_48 (D6|D5|D4) #define SYNTH_CP_MASK (D6|D5|D4) // Prescale Control (0x0A) #define SYNTH_PDN_NORMOP 0 #define SYNTH_PDN_NRM1 0 #define SYNTH_PDN_ASYNC D0 #define SYNTH_PDN_NRM2 D1 #define SYNTH_PDN_SYNC (D1|D0) #define SYNTH_PDN_MASK (D1|D0) #define SYNTH_PRE_DIV1 0x0 #define SYNTH_PRE_DIV2 D2 #define SYNTH_PRE_DIV23 D3 #define SYNTH_PRE_DIV45 (D3|D2) #define SYNTH_PRE_DIV89 D4 #define SYNTH_PRE_DIV1617 (D4|D2) #define SYNTH_PRE_DIV3233 (D4|D3) #define SYNTH_PRE_DIV3 (D4|D3|D2) #define SYNTH_PRE_MASK (D4|D3|D2) #define SYNTH_BCNTR_BYPS D6 // Anti backlash #define SYNTH_BCKLSH_13 0 #define SYNTH_BCKLSH_29 D0 #define SYNTH_BCKLSH_60 D1 //#define SYNTH_BCKLSH_13 (D1|D0) #define SYNTH_BCKLSH_MASK (D1|D0) #define SYNTH_DLDWIND_0 0 #define SYNTH_DLDWIND_1 D5 #define SYNTH_LCKDET_DISAB D6 // Delay control bit ( chans 5, 6) #define SYNTH_DLY_BYPASS D0 // Ramp current ( chans 5 and 6) #define SYNTH_RAMPI_20 0 #define SYNTH_RAMPI_40 D0 #define SYNTH_RAMPI_60 D1 #define SYNTH_RAMPI_80 (D1|D0) #define SYNTH_RAMPI_100 D2 #define SYNTH_RAMPI_120 (D2|D0) #define SYNTH_RAMPI_140 (D2|D1) #define SYNTH_RAMPI_160 (D2|D1|D0) #define SYNTH_RAMPI_MASK (D2|D1|D0) // determined by the no of zeroes in bits 5-3( add 1) #define SYNTH_RAMPC_MASK (D5|D4|D3) #define SYNTH_RAMP_CAP1 (D5|D4|D3) #define SYNTH_RAMP_CAP2 (D4|D3) #define SYNTH_RAMP_CAP3 D3 #define SYNTH_RAMP_CAP4 0 // LVPECL Drive (Out0-3 only) #define SYNTH_PECLDRV_50 0 #define SYNTH_PECLDRV_34 D2 #define SYNTH_PECLDRV_81 D3 #define SYNTH_PECLDRV_66 (D3|D2) #define SYNTH_PECLDRV_MASK (D3|D2) /*Power down modes*/ #define SYNTH_PDN_PCLNORM 0 #define SYNTH_PDN_PCLSAFE D1 #define SYNTH_PDN_PCLTOTL (D1|D0) #define SYNTH_PDN_PCLMASK (D1|D0) // LVDS Drive (Out4-7 only), suffix =mA*100 /*100R only */ #define SYNTH_LVDSDRV_175 0 #define SYNTH_LVDSDRV_350 D1 /*50R only */ #define SYNTH_LVDSDRV_525 D2 #define SYNTH_LVDSDRV_700 (D2|D1) #define SYNTH_LVDSDRV_MASK (D2|D1) #define SYNTH_PDN_LVDS D0 #define SYNTH_INV_LVDS D4 #define SYNTH_SET_CMOS D3 /******************************************************************************* Clock Control <0> Clock Select 0: CLK2 Drives Distribution Section 1: CLK1 Drives Distribution Section (Default) <1> CLK1 Power-Down 1 = CLK1 Input Is Powered Down (Default = 0b) <2> CLK2 Power-Down 1 = CLK2 Input Is Powered Down (Default = 0b) <3> Prescaler Clock Power-Down 1 = Shut Down Clock Signal to PLL Prescaler (Default = 0b) <4> REFIN Power-Down 1 = Power-Down REFIN (Default = 0b) <5> All Clock Inputs Power-Down 1 = Power-Down CLK1 and CLK2 Inputs and Associated Bias and Internal Clock Tree; (Default = 0b) ******************************************************************************* */ #define SYNTH_CLKSEL_CK2 0 #define SYNTH_CLKSEL_CK1 D0 #define SYNTH_CLK_PWDNNONE 0 #define SYNTH_CLK_PWDNCK1 D1 #define SYNTH_CLK_PWDNCK2 D2 #define SYNTH_CLK_PWDNPRE D3 #define SYNTH_CLK_PWDNREF D4 #define SYNTH_CLK_PWDNALL D5 #define SYNTH_CLK_PWDN_MASK (D5|D4|D3|D2|D1) // Divider duty cycle register, Applies to out0 to out7 (48, 4a etc.) #define SYNTH_DIVHI_MASK (D3|D2|D1|D0) #define SYNTH_DIVLO_MASK (D7|D6|D5|D4) #define SYNTH_DIVLO_SHIFT 4 // Phase offset register, Applies to out0 to out7 #define SYNTH_PHOFFS_MASK (D3|D2|D1|D0) #define SYNTH_START_HI D4 #define SYNTH_FORCE_START D5 #define SYNTH_NOSYNC D6 #define SYNTH_DIV_BYPASS D7 // Sync detect register, Applies to out0 to out7 #define SYNTH_SYNC_ENAB D0 #define SYNTH_SYNC_FLAGLT1 D1 #define SYNTH_SYNC_SOFT D2 #define SYNTH_REF_PWDN D3 #define SYNTH_SYNC_PWDN D4 #define SYNTH_FUNC_RST 0 #define SYNTH_FUNC_SYNC D5 #define SYNTH_SYNC_PDB (D5|D6) #define SYNTH_SYNC_MASK (D5|D6) /******************************************************************************* * Function Prototypes ******************************************************************************* */ /*Never Use */ unsigned char SynthWriteStrobe(void); unsigned char SynthReadStrobe(void); unsigned char SynthWrite(unsigned char WrAddr, unsigned char WrData); unsigned char SynthRead(unsigned char RdAddr,unsigned char * pResult); unsigned char SynthBackLash(unsigned char Sel); unsigned char SynthLVPECLPDn(unsigned char Channel,unsigned char Sel); unsigned char SynthLVPECLDrive(unsigned char Channel,unsigned char Level); unsigned char SynthCMOSSel(unsigned char Channel,unsigned char Sel); unsigned char SynthCMOSInv(unsigned char Channel,unsigned char Sel); /*Use Only if you know what you are doing */ unsigned char SynthCPMode(unsigned char Sel); unsigned char SynthCPCurrent(unsigned char Sel); unsigned char SynthPFDPol(unsigned char Enable); unsigned char SynthForce(unsigned char Channel,unsigned char Sel); unsigned char SynthChipSync(unsigned char Channel,unsigned char Sel); /*Occasional Use */ unsigned char SynthCntrReset(unsigned char Sel); unsigned char SynthADiv(unsigned char Div); unsigned char SynthBDiv(unsigned int Div); unsigned char SynthPDiv(unsigned char Div); unsigned char SynthBDivBypass(unsigned char Enable); unsigned char SynthRDiv(unsigned int Div); unsigned char SynthPhaseOffset(unsigned char Channel,unsigned char Offs); unsigned char SynthStartPol(unsigned char Channel,unsigned char Sel); unsigned char SynthDelayEnab(unsigned char Channel,unsigned char Sel); unsigned char SynthDelayCur(unsigned char Channel,unsigned char Sel); unsigned char SynthDelayCap(unsigned char Channel,unsigned char Sel); unsigned char SynthDelayAdj(unsigned char Channel,unsigned char Value); unsigned char SynthLVDSPDn(unsigned char Channel,unsigned char Sel); unsigned char SynthLVDSDrive(unsigned char Channel,unsigned char Level); unsigned char SynthSyncDetEnab(unsigned char Sel,unsigned char Flag); unsigned char SynthSyncFlag(unsigned char Sel,unsigned char Flag); unsigned char SynthLDWin(unsigned char Sel); /*Use */ unsigned char SynthInit(void); unsigned char SynthPLLPdn(unsigned char Sel); unsigned char SynthRefsPdn(unsigned char Sel); unsigned char SynthSyncPdn(unsigned char Sel); unsigned char SynthCkPDn(unsigned char Sel); unsigned char SynthCkSel(unsigned char Sel); unsigned char SynthSoftReset(void); unsigned char SynthHardReset(void); unsigned char SynthSoftSync(void); unsigned char SynthLORCntrl(unsigned char Enable, unsigned char Delay); unsigned char SynthStatusMode(unsigned char Sel); unsigned char SynthFuncMode(unsigned char Sel); unsigned char SynthLDEnab(unsigned char Sel); unsigned char SynthOpDiv(unsigned char Channel,unsigned char Hi,unsigned char Lo); int ReadSynthRegs(unsigned char Select); int ReadSynthStatusBits(void); int SetChanDelay(double Delay, char Channel ); int SetSampleClock(unsigned int Source, double CkSpeed); int SampleClockInit(void); int SetVCXODirect(void); void sleepMs(int ms){ usleep(ms * 1000); } /*-******************************************************************************************** Global Definitions *********************************************************************************************/ static volatile unsigned int* fpgaSpace; static char * SynthRegNames []= { "SYNTH_SER_CNFG " , "SYNTH_ACNTR " , "SYNTH_BCNTR_MSB " , "SYNTH_BCNTR_LSB " , "SYNTH_LOR " , "SYNTH_MUX_CP " , "SYNTH_CPDRV_RST " , "SYNTH_PRESCALE " , "SYNTH_REFCNTR_MSB " , "SYNTH_REFCNTR_LSB " , "SYNTH_LOCK_DTCT " , "SYNTH_OUT5_DELBYP " , "SYNTH_OUT5_RAMP " , "SYNTH_OUT5_DELADJ " , "SYNTH_OUT6_DELBYP " , "SYNTH_OUT6_RAMP " , "SYNTH_OUT6_DELADJ " , "SYNTH_OUT0_CNTRL " , "SYNTH_OUT1_CNTRL " , "SYNTH_OUT2_CNTRL " , "SYNTH_OUT3_CNTRL " , "SYNTH_OUT4_CNTRL " , "SYNTH_OUT5_CNTRL " , "SYNTH_OUT6_CNTRL " , "SYNTH_OUT7_CNTRL " , "SYNTH_CLOCK_CNTRL " , "SYNTH_OUT0_DIVHILO" , "SYNTH_OUT0_POFFS " , "SYNTH_OUT1_DIVHILO" , "SYNTH_OUT1_POFFS " , "SYNTH_OUT2_DIVHILO" , "SYNTH_OUT2_POFFS " , "SYNTH_OUT3_DIVHILO" , "SYNTH_OUT3_POFFS " , "SYNTH_OUT4_DIVHILO" , "SYNTH_OUT4_POFFS " , "SYNTH_OUT5_DIVHILO" , "SYNTH_OUT5_POFFS " , "SYNTH_OUT6_DIVHILO" , "SYNTH_OUT6_POFFS " , "SYNTH_OUT7_DIVHILO" , "SYNTH_OUT7_POFFS " , "SYNTH_SYNC_FUNC " }; unsigned char SynthRegAddr[]= { SYNTH_SER_CNFG , SYNTH_ACNTR , SYNTH_BCNTR_MSB , SYNTH_BCNTR_LSB , SYNTH_LOR , SYNTH_MUX_CP , SYNTH_CPDRV_RST , SYNTH_PRESCALE , SYNTH_REFCNTR_MSB , SYNTH_REFCNTR_LSB , SYNTH_LOCK_DTCT , SYNTH_OUT5_DELBYP , SYNTH_OUT5_RAMP , SYNTH_OUT5_DELADJ , SYNTH_OUT6_DELBYP , SYNTH_OUT6_RAMP , SYNTH_OUT6_DELADJ , SYNTH_OUT0_CNTRL , SYNTH_OUT1_CNTRL , SYNTH_OUT2_CNTRL , SYNTH_OUT3_CNTRL , SYNTH_OUT4_CNTRL , SYNTH_OUT5_CNTRL , SYNTH_OUT6_CNTRL , SYNTH_OUT7_CNTRL , SYNTH_CLOCK_CNTRL , SYNTH_OUT0_DIVHILO , SYNTH_OUT0_POFFS , SYNTH_OUT1_DIVHILO , SYNTH_OUT1_POFFS , SYNTH_OUT2_DIVHILO , SYNTH_OUT2_POFFS , SYNTH_OUT3_DIVHILO , SYNTH_OUT3_POFFS , SYNTH_OUT4_DIVHILO , SYNTH_OUT4_POFFS , SYNTH_OUT5_DIVHILO , SYNTH_OUT5_POFFS , SYNTH_OUT6_DIVHILO , SYNTH_OUT6_POFFS , SYNTH_OUT7_DIVHILO , SYNTH_OUT7_POFFS , SYNTH_SYNC_FUNC }; double SynthDelayMax[] = { 9.3002 , 7.9716 , 6.643 , 5.3144 , 4.6501 , 3.9858 , 3.3215 , 3.100066667, 2.6572 , 2.32505 , 2.214333333, 1.9929 , 1.86004 , 1.771466667, 1.66075 , 1.59432 , 1.550033333, 1.3286 , 1.162525 , 1.1388 , 1.107166667, 1.06288 , 0.99645 , 0.949 , 0.885733333, 0.830375 , 0.7592 , 0.6643 }; double SynthDelayResln[] = { 0.300006452, 0.257148387, 0.214290323, 0.171432258, 0.150003226, 0.128574194, 0.107145161, 0.100002151, 0.085716129, 0.075001613, 0.071430108, 0.064287097, 0.06000129 , 0.057144086, 0.053572581, 0.051429677, 0.050001075, 0.042858065, 0.037500806, 0.036735484, 0.035715054, 0.034286452, 0.032143548, 0.030612903, 0.028572043, 0.02678629 , 0.024490323, 0.021429032 }; double SynthDelayOffs[] = { 0.57 , 0.54 , 0.51 , 0.48 , 0.505 , 0.49 , 0.475 , 0.47 , 0.46 , 0.4425 , 0.45 , 0.435 , 0.418 , 0.44 , 0.4275 , 0.412 , 0.395 , 0.372857143 , 0.35125 , 0.368571429 , 0.385 , 0.4 , 0.3475 , 0.364285714 , 0.38 , 0.34375 , 0.36 , 0.34 }; char SynthIRamp[] = { SYNTH_RAMPI_20, SYNTH_RAMPI_20, SYNTH_RAMPI_20, SYNTH_RAMPI_20, SYNTH_RAMPI_40, SYNTH_RAMPI_40, SYNTH_RAMPI_40, SYNTH_RAMPI_60, SYNTH_RAMPI_60, SYNTH_RAMPI_80, SYNTH_RAMPI_60, SYNTH_RAMPI_80, SYNTH_RAMPI_100, SYNTH_RAMPI_60, SYNTH_RAMPI_80, SYNTH_RAMPI_100, SYNTH_RAMPI_120, SYNTH_RAMPI_140, SYNTH_RAMPI_160, SYNTH_RAMPI_140, SYNTH_RAMPI_120, SYNTH_RAMPI_100, SYNTH_RAMPI_160, SYNTH_RAMPI_140, SYNTH_RAMPI_120, SYNTH_RAMPI_160, SYNTH_RAMPI_140, SYNTH_RAMPI_160 }; char SynthNoofCaps[] = { SYNTH_RAMP_CAP4, SYNTH_RAMP_CAP3, SYNTH_RAMP_CAP2, SYNTH_RAMP_CAP1, SYNTH_RAMP_CAP4, SYNTH_RAMP_CAP3, SYNTH_RAMP_CAP2, SYNTH_RAMP_CAP4, SYNTH_RAMP_CAP3, SYNTH_RAMP_CAP4, SYNTH_RAMP_CAP2, SYNTH_RAMP_CAP3, SYNTH_RAMP_CAP4, SYNTH_RAMP_CAP1, SYNTH_RAMP_CAP2, SYNTH_RAMP_CAP3, SYNTH_RAMP_CAP4, SYNTH_RAMP_CAP4, SYNTH_RAMP_CAP4, SYNTH_RAMP_CAP3, SYNTH_RAMP_CAP2, SYNTH_RAMP_CAP1, SYNTH_RAMP_CAP3, SYNTH_RAMP_CAP2, SYNTH_RAMP_CAP1, SYNTH_RAMP_CAP2, SYNTH_RAMP_CAP1, SYNTH_RAMP_CAP1 }; /********************************************************************************************/ /*======================================================================= Write to serial interface by generating a rising edge on the synth wr strobe bit. Only one bit should be active at a time whose rising edge genrates a serial write cycle =======================================================================*/ unsigned char SynthWriteStrobe(void) { unsigned char i; unsigned int j; fpgaSpace[SYNTH_STRB_REG] = 0; fpgaSpace[SYNTH_STRB_REG] = SYNTH_WRSTRB; fpgaSpace[SYNTH_STRB_REG] = 0; /*The busy flag rising edge is latched, cleared following a read or write strobe Wait for the BUSY flag to go high or timeout*/ i=0;j=0; do{ j=fpgaSpace[SYNTH_CNTRL_REG]&SYNTH_SMBUSY_FLAG; i++; sleepMs(1); } while ( (i<100) && (j!=SYNTH_SMBUSY_FLAG) ); if (i>=100) return 1; /*Wait for the BUSY bit (not the latched bit) to go low or timeout*/ i=0;j=0; do{ j=fpgaSpace[SYNTH_CNTRL_REG]&SYNTH_SMBUSY; i++; sleepMs(1); } while ((i<100)&& (j==SYNTH_SMBUSY) ); if (i>=100) return 1; else return 0; } /*-----------------------------------------------------------------------*/ /*======================================================================= Read from serial interface by generating a rising edge on the synth wr strobe bit. Only one bit should be active at a time whose rising edge genrates a serial read cycle =======================================================================*/ unsigned char SynthReadStrobe(void) { char i; unsigned int j; fpgaSpace[SYNTH_STRB_REG] = 0; fpgaSpace[SYNTH_STRB_REG] = SYNTH_RDSTRB; fpgaSpace[SYNTH_STRB_REG] = 0; /*The busy flag rising edge is latched, cleared following a read or write strobe Wait for the BUSY flag to go high or timeout*/ i=0;j=0; do{ j=fpgaSpace[SYNTH_CNTRL_REG]; j&=SYNTH_SMBUSY_FLAG; i++; sleepMs(1); } while ((i<100) && (j!=SYNTH_SMBUSY_FLAG) ); if (i>=100) return 1; /*Wait for the BUSY bit to go low or timeout*/ i=0;j=0; do{ j=fpgaSpace[SYNTH_CNTRL_REG]; i++; sleepMs(1); } while ((i<100)&& ((j&SYNTH_SMBUSY)==SYNTH_SMBUSY) ); if (i>=100) return 1; else return 0; } /*-----------------------------------------------------------------------*/ /*======================================================================= Write data to serial interface Data and address ports are only 8 bits wide =======================================================================*/ unsigned char SynthWrite(unsigned char WrAddr, unsigned char WrData) { unsigned char i,j; /*Check that the interface isn't busy */ if( (fpgaSpace[SYNTH_CNTRL_REG] & SYNTH_SMBUSY) ==SYNTH_SMBUSY) return (1); /*Setup the write data and address */ fpgaSpace[SYNTH_CNTRL_REG] = ((WrAddr<<SYNTH_ADSHFT) &SYNTH_ADMASK)| ((WrData<<SYNTH_WRDATSHFT) &SYNTH_WRDATMASK); /*write the data */ i=SynthWriteStrobe(); /*Generate the Wr strobe for the device*/ fpgaSpace[SYNTH_CNTRL_REG] = ((SYNTH_UPDATE<<SYNTH_ADSHFT) &SYNTH_ADMASK)| ((D0<<SYNTH_WRDATSHFT) &SYNTH_WRDATMASK); j=SynthWriteStrobe(); return (i|j); } /*-----------------------------------------------------------------------*/ /*======================================================================= Read data from the serial interface by generating a rising edge on the synth rd strobe bit. =======================================================================*/ unsigned char SynthRead(unsigned char RdAddr,unsigned char * pResult) { unsigned char i; /*Check that the interface isn't busy */ if( (fpgaSpace[SYNTH_CNTRL_REG] & SYNTH_SMBUSY) ==SYNTH_SMBUSY) return (1); /*Setup the read address */ fpgaSpace[SYNTH_CNTRL_REG] = ((RdAddr<<SYNTH_ADSHFT) &SYNTH_ADMASK); /*Generate the Rd strobe */ i= SynthReadStrobe(); /*retrieve result*/ *pResult=( (fpgaSpace[SYNTH_CNTRL_REG]&SYNTH_RDDATMASK)>>SYNTH_RDDATSHFT); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Force the default configuration sequence to run (~100 us) =======================================================================*/ unsigned char SynthInit(void) { unsigned char i,j; /*Reset overrides any current activity */ j=fpgaSpace[SYNTH_STRB_REG]; #ifdef ZAP fpgaSpace[SYNTH_STRB_REG]=j | SYNTH_INISTRB; sleepMs(1); fpgaSpace[SYNTH_STRB_REG]=j ; #else fpgaSpace[SYNTH_RESET_REG]=1; sleepMs(1); fpgaSpace[SYNTH_RESET_REG]=0; #endif /*Wait for the BUSY bit to go low or timeout*/ i=0;j=0; do{ j=fpgaSpace[SYNTH_CNTRL_REG]; i++; sleepMs(1); } while ((i<100)&& ((j&SYNTH_INIBUSY)==SYNTH_INIBUSY) ); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Generates a hardware reset of the AD9510 assumes func pin is configured as reset. Foreces initialisation of clocks to default following a hard reset =======================================================================*/ unsigned char SynthHardReset(void) { unsigned char i; /*Reset overrides any current activity */ i=fpgaSpace[SYNTH_STRB_REG]; fpgaSpace[SYNTH_STRB_REG]=i | SYNTH_FUNCSTRB; sleepMs(1); fpgaSpace[SYNTH_STRB_REG]=i ; sleepMs(1); SynthInit(); return 0; } /*-----------------------------------------------------------------------*/ /*======================================================================= Generates a software reset of the AD9510 addr 0 D5 =======================================================================*/ unsigned char SynthSoftReset(void) { unsigned char i; SynthRead( SYNTH_SER_CNFG,&i); SynthWrite( SYNTH_SER_CNFG, (i|SYNTH_SOFT_RESET)); sleepMs(10); SynthWrite( SYNTH_SER_CNFG,i); return 0; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the divider value for the A counter (6 bits) addr4 =======================================================================*/ unsigned char SynthADiv(unsigned char Div) { unsigned char i; i=SynthWrite( (char) SYNTH_ACNTR, (Div& SYNTH_ACNTR_MASK)); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the divider value for the B counter (13 bits split as a group of 8 and a group of 5) Order is unimportant addr5, addr6 =======================================================================*/ unsigned char SynthBDiv(unsigned int Div) { unsigned char i,j; i=SynthWrite( (char) SYNTH_BCNTR_LSB, (char) (Div& 0xFF)); j=SynthWrite( (char) SYNTH_BCNTR_MSB, (char) ( (Div>>8)& SYNTH_BCNTR_MASK)); return (i|j); } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the loss of reference (LOR) operation addr7 =======================================================================*/ unsigned char SynthLORCntrl(unsigned char Enable, unsigned char Delay) { unsigned char i; SynthRead(SYNTH_LOR,&i); if(Enable) i|=SYNTH_LOR_ENABLE; else i&= ~SYNTH_LOR_ENABLE; switch(Delay) { case SYNTH_LOR_DLY3: case SYNTH_LOR_DLY6: case SYNTH_LOR_DLY12: case SYNTH_LOR_DLY24: i&=~ SYNTH_LOR_MASK; i|=Delay; i=SynthWrite( SYNTH_LOR, i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the charge pump mode addr8 D1 D0 =======================================================================*/ unsigned char SynthCPMode(unsigned char Sel) { unsigned char i; switch(Sel) { case SYNTH_CPMODE_PMPTRI: case SYNTH_CPMODE_PMPUP: case SYNTH_CPMODE_PMPDN: case SYNTH_CPMODE_PMPNORM: SynthRead(SYNTH_MUX_CP,&i); i&= ~ SYNTH_CPMODE_MASK; i|=Sel; i=SynthWrite( SYNTH_MUX_CP, i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the Status pin operation addr8 D5-D2 =======================================================================*/ unsigned char SynthStatusMode(unsigned char Sel) { unsigned char i; switch(Sel) { case SYNTH_MUXOUT_OFF: case SYNTH_MUXOUT_DLDHI: case SYNTH_MUXOUT_DLDLO: case SYNTH_CPMODE_PMPNORM: case SYNTH_MUXOUT_NDIV : case SYNTH_MUXOUT_RDIV : case SYNTH_MUXOUT_ANALOGUE_P : case SYNTH_MUXOUT_ANALOGUE_N : case SYNTH_MUXOUT_ACNTR : case SYNTH_MUXOUT_NCLCK : case SYNTH_MUXOUT_PFDUP : case SYNTH_MUXOUT_PFDDN : case SYNTH_MUXOUT_LORHI : case SYNTH_MUXOUT_TRI : case SYNTH_MUXOUT_LORLLKHI: case SYNTH_MUXOUT_LORLLKLO: case SYNTH_MUXOUT_LORLO : SynthRead(SYNTH_MUX_CP,&i); //printf("Statusmode reads %x\n",i); i&=~SYNTH_MUXOUT_MASK; //printf("Masked %x\n",i); i|=Sel; //printf("Statusmode writes %x\n\n",i); i=SynthWrite( SYNTH_MUX_CP, i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the phase/frequency detector polarity 0= neg = default addr8 D6 =======================================================================*/ unsigned char SynthPFDPol(unsigned char Enable) { unsigned char i; SynthRead(SYNTH_MUX_CP,&i); if(Enable) i|=SYNTH_PFD_POLPOS; else i&= ~SYNTH_PFD_POLPOS; i=SynthWrite( (char) SYNTH_MUX_CP, i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Issue one of 3 counter resets addr9 D0-D2 =======================================================================*/ unsigned char SynthCntrReset(unsigned char Sel) { unsigned char i; switch(Sel) { case SYNTH_RST_RAB: case SYNTH_RST_AB: case SYNTH_RST_R: SynthRead(SYNTH_CPDRV_RST,&i); i&=~SYNTH_RST_MASK; i|=Sel; i=SynthWrite( SYNTH_CPDRV_RST, i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the CP current addr9 D4-D6 =======================================================================*/ unsigned char SynthCPCurrent(unsigned char Sel) { unsigned char i; switch(Sel) { case SYNTH_CP_O6: case SYNTH_CP_12: case SYNTH_CP_18: case SYNTH_CP_24: case SYNTH_CP_30: case SYNTH_CP_36: case SYNTH_CP_42: case SYNTH_CP_48: SynthRead(SYNTH_CPDRV_RST,&i); i&=~SYNTH_CP_MASK; i|=Sel; i=SynthWrite( SYNTH_CPDRV_RST, i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the PLLpower down control addrA D0-D1 Normal/Async/Sync =======================================================================*/ unsigned char SynthPLLPdn(unsigned char Sel) { unsigned char i; switch(Sel) { case SYNTH_PDN_NORMOP: case SYNTH_PDN_ASYNC: case SYNTH_PDN_SYNC: SynthRead(SYNTH_PRESCALE,&i); i&=~SYNTH_PDN_MASK; i|=Sel; i=SynthWrite( SYNTH_PRESCALE, i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the divider value for the P (prescaler) counter addr A D4-D2 =======================================================================*/ unsigned char SynthPDiv(unsigned char Div) { unsigned char i; switch (Div) { case SYNTH_PRE_DIV1: case SYNTH_PRE_DIV2: case SYNTH_PRE_DIV23: case SYNTH_PRE_DIV45: case SYNTH_PRE_DIV89: case SYNTH_PRE_DIV1617: case SYNTH_PRE_DIV3233: case SYNTH_PRE_DIV3: SynthRead( SYNTH_PRESCALE,&i); i&= ~SYNTH_PRE_MASK; i|=Div; i=SynthWrite( SYNTH_PRESCALE,i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set/clear the B divider bypass bit addr A D6 =======================================================================*/ unsigned char SynthBDivBypass(unsigned char Enable) { unsigned char i; SynthRead(SYNTH_PRESCALE,&i); if(Enable) i|=SYNTH_BCNTR_BYPS; else i&= ~SYNTH_BCNTR_BYPS; i=SynthWrite( (char) SYNTH_MUX_CP, i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the divider value for the R (ref input) divider 14 bits max addr B D5-D0, addr C D7-D0 =======================================================================*/ unsigned char SynthRDiv(unsigned int Div) { unsigned char i,j; i=SynthWrite( (char) SYNTH_REFCNTR_LSB, (char) (Div& 0xFF)); j=SynthWrite( (char) SYNTH_REFCNTR_MSB, (char) ( (Div>>8)& SYNTH_RCNTR_MASK)); return (i|j); } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the anti backlash pulse width addrD D0-D1 =======================================================================*/ unsigned char SynthBackLash(unsigned char Sel) { unsigned char i; switch (Sel) { case SYNTH_BCKLSH_13: case SYNTH_BCKLSH_29: case SYNTH_BCKLSH_60: SynthRead( SYNTH_LOCK_DTCT,&i); i&= ~SYNTH_BCKLSH_MASK; i|=Sel; i=SynthWrite( SYNTH_LOCK_DTCT,i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the lock detect window addrD D5 A zero value selects the default of 9.5 ns /15 ns a non-zero value selects 3.5 ns/7 ns. =======================================================================*/ unsigned char SynthLDWin(unsigned char Sel) { unsigned char i; SynthRead( SYNTH_LOCK_DTCT,&i); if(Sel) i|=SYNTH_DLDWIND_1; else i&= ~SYNTH_DLDWIND_1; i=SynthWrite( SYNTH_LOCK_DTCT, i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the lock detect disable bit (note the polarity!) addrD D7 A non-zero value enables lock detection =======================================================================*/ unsigned char SynthLDEnab(unsigned char Sel) { unsigned char i; SynthRead( SYNTH_LOCK_DTCT,&i); if(Sel) i&= ~SYNTH_LCKDET_DISAB; else i|=SYNTH_LCKDET_DISAB; i=SynthWrite( SYNTH_LOCK_DTCT, i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the delay enable bit for the channel specified (channels 5 and 6- normally only channel 5 (the FPGA clock channel) is ever varied addr 34(38) D0 A zero value bypasses and powers down the delay block Note Polarity!! =======================================================================*/ unsigned char SynthDelayEnab(unsigned char Channel,unsigned char Sel) { unsigned char i = 0,j; if (Channel==5) j=SYNTH_OUT5_DELBYP; else { if(Channel==6) j=SYNTH_OUT6_DELBYP; else return 1; } if(Sel) i&= ~SYNTH_DLY_BYPASS; else i|=SYNTH_DLY_BYPASS; i=SynthWrite( j, i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the delay scaling for the channel specified (channels 5 and 6- normally only channel 5 (the FPGA clock channel) is ever varied addr 35 (39) D0-D5 =======================================================================*/ unsigned char SynthDelayCur(unsigned char Channel,unsigned char Sel) { unsigned char i,j; if (Channel==5) j=SYNTH_OUT5_RAMP; else { if(Channel==6) j=SYNTH_OUT6_RAMP; else return 1; } switch (Sel) { case SYNTH_RAMPI_20: case SYNTH_RAMPI_40: case SYNTH_RAMPI_60: case SYNTH_RAMPI_80: case SYNTH_RAMPI_100: case SYNTH_RAMPI_120: case SYNTH_RAMPI_140: case SYNTH_RAMPI_160: SynthRead( j,&i); i&= ~SYNTH_RAMPI_MASK; i|=Sel; i=SynthWrite( j,i); break; default: i=1; break; } // // // switch (Sel) // { // case SYNTH_RAMPI_20: // printf("SYNTH_RAMPI_20\n"); // break; // case SYNTH_RAMPI_40: // printf("SYNTH_RAMPI_40\n"); // break; // case SYNTH_RAMPI_60: // printf("SYNTH_RAMPI_60\n"); // break; // case SYNTH_RAMPI_80: // printf("SYNTH_RAMPI_80\n"); // break; // case SYNTH_RAMPI_100: // printf("SYNTH_RAMPI_100\n"); // break; // case SYNTH_RAMPI_120: // printf("SYNTH_RAMPI_120\n"); // break; // case SYNTH_RAMPI_140: // printf("SYNTH_RAMPI_140\n"); // break; // case SYNTH_RAMPI_160: // printf("SYNTH_RAMPI_160\n"); // break; // default: // printf("SYNTH_RAMPI_DEFAULT\n"); // break; // break; // // } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the delay caps for the channel specified (channels 5 and 6- normally only channel 5 (the FPGA clock channel) is ever varied addr 35 (39) D0-D5 =======================================================================*/ unsigned char SynthDelayCap(unsigned char Channel,unsigned char Sel) { unsigned char i,j; if (Channel==5) j=SYNTH_OUT5_RAMP; else { if(Channel==6) j=SYNTH_OUT6_RAMP; else return 1; } // switch (Sel) // { // case SYNTH_RAMP_CAP1: // printf("1 cap %x\n",SYNTH_RAMP_CAP1); // break; // case SYNTH_RAMP_CAP2: // printf("2 cap %x\n",SYNTH_RAMP_CAP2); // break; // case SYNTH_RAMP_CAP3: // printf("3 cap %x\n",SYNTH_RAMP_CAP3); // break; // case SYNTH_RAMP_CAP4: // printf("4 cap %x\n",SYNTH_RAMP_CAP4); // break; // default: // printf("Default\n"); // break; // } // switch (Sel) { case SYNTH_RAMP_CAP1: case SYNTH_RAMP_CAP2: case SYNTH_RAMP_CAP3: case SYNTH_RAMP_CAP4: SynthRead( j,&i); i&= ~SYNTH_RAMPC_MASK; i|=Sel; i=SynthWrite( j,i); break; default: i=1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the delay value for the channel specified (channels 5 and 6- normally only channel 5 (the FPGA clock channel) is ever varied addr 36(3A) Data sheet specifes 32 levels but only D5 to D1 (!!???) Value is proportion of full scale value =======================================================================*/ unsigned char SynthDelayAdj(unsigned char Channel,unsigned char Value) { unsigned char i,j; if (Channel==5) j=SYNTH_OUT5_DELADJ; else { if(Channel==6) j=SYNTH_OUT6_DELADJ; else return 1; } i=Value&0x3F; i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the power down control for LVPECL outputs( 0-3) 3c-3f,D0-D1 =======================================================================*/ unsigned char SynthLVPECLPDn(unsigned char Channel,unsigned char Sel) { unsigned char i,j; switch (Channel) { case 0: j=SYNTH_OUT0_CNTRL; break; case 1: j=SYNTH_OUT1_CNTRL; break; case 2: j=SYNTH_OUT3_CNTRL; break; case 3: j=SYNTH_OUT3_CNTRL; break; default: return 1; break; } switch (Sel) { case SYNTH_PDN_PCLNORM: case SYNTH_PDN_PCLSAFE: case SYNTH_PDN_PCLTOTL: SynthRead( j,&i); i&= ~SYNTH_PDN_PCLMASK; i|=Sel; i=SynthWrite( j,i); default: i= 1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Controls the output type for the LVPECL outputs( 0-3) 3c-3f,D2-D3 =======================================================================*/ unsigned char SynthLVPECLDrive(unsigned char Channel,unsigned char Level) { unsigned char i,j; switch (Channel) { case 0: j=SYNTH_OUT0_CNTRL; break; case 1: j=SYNTH_OUT1_CNTRL; break; case 2: j=SYNTH_OUT3_CNTRL; break; case 3: j=SYNTH_OUT3_CNTRL; break; default: return 1; break; } switch (Level) { case SYNTH_PECLDRV_50: case SYNTH_PECLDRV_34: case SYNTH_PECLDRV_66: case SYNTH_PECLDRV_81: SynthRead( j,&i); i&= ~SYNTH_PECLDRV_MASK; i|=Level; i=SynthWrite( j,i); default: i= 1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the power down control for LVDS outputs( 4-7) 40-43,D0-D1 a non-zero value powers the outputs down =======================================================================*/ unsigned char SynthLVDSPDn(unsigned char Channel,unsigned char Sel) { unsigned char i,j; switch (Channel) { case 4: j=SYNTH_OUT4_CNTRL; break; case 5: j=SYNTH_OUT5_CNTRL; break; case 6: j=SYNTH_OUT6_CNTRL; break; case 7: j=SYNTH_OUT7_CNTRL; break; default: return 1; break; } SynthRead( j,&i); if(Sel) i|= SYNTH_PDN_LVDS; else i&= ~SYNTH_PDN_LVDS; i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Controls the output type for the LVDS outputs( 4-7) 40-43,D1-D3 a non-zero value selects CMOS outputs =======================================================================*/ unsigned char SynthCMOSSel(unsigned char Channel,unsigned char Sel) { unsigned char i,j; switch (Channel) { case 4: j=SYNTH_OUT4_CNTRL; break; case 5: j=SYNTH_OUT5_CNTRL; break; case 6: j=SYNTH_OUT6_CNTRL; break; case 7: j=SYNTH_OUT7_CNTRL; break; default: return 1; break; } SynthRead( j,&i); if(Sel) i|= SYNTH_SET_CMOS; else i&= ~SYNTH_SET_CMOS; i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Controls the output inverter for CMOS-configured LVDS outputs( 4-7) 40-43,D4 a non-zero value enables the inverter =======================================================================*/ unsigned char SynthCMOSInv(unsigned char Channel,unsigned char Sel) { unsigned char i,j; switch (Channel) { case 4: j=SYNTH_OUT4_CNTRL; break; case 5: j=SYNTH_OUT5_CNTRL; break; case 6: j=SYNTH_OUT6_CNTRL; break; case 7: j=SYNTH_OUT7_CNTRL; break; default: return 1; break; } SynthRead( j,&i); if(Sel) i|= SYNTH_INV_LVDS; else i&= ~SYNTH_INV_LVDS; i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Controls the output type for the LVDS outputs( 4-7) 40-43,D1,D2 =======================================================================*/ unsigned char SynthLVDSDrive(unsigned char Channel,unsigned char Level) { unsigned char i,j; switch (Channel) { case 4: j=SYNTH_OUT4_CNTRL; break; case 5: j=SYNTH_OUT5_CNTRL; break; case 6: j=SYNTH_OUT6_CNTRL; break; case 7: j=SYNTH_OUT7_CNTRL; break; default: return 1; break; } switch (Level) { case SYNTH_LVDSDRV_175: case SYNTH_LVDSDRV_350: case SYNTH_LVDSDRV_525: case SYNTH_LVDSDRV_700: SynthRead( j,&i); i&= ~SYNTH_LVDSDRV_MASK; i|=Level; i=SynthWrite( j,i); default: i= 1; break; } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Controls the power down bits for the clocks 45,D1-D5 =======================================================================*/ unsigned char SynthCkPDn(unsigned char Sel) { unsigned char i,j; /*restrict the select bits to valid values */ j=Sel&SYNTH_CLK_PWDN_MASK;; if(j==0) return 0; else { SynthRead( SYNTH_CLOCK_CNTRL,&i); i&= ~SYNTH_CLK_PWDN_MASK; i|=j; i=SynthWrite( SYNTH_CLOCK_CNTRL,i); } return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Selects the active clock input 45,D0 Sel high selects Ck1, low selects Ck2 Note the polarity! =======================================================================*/ unsigned char SynthCkSel(unsigned char Sel) { unsigned char i; SynthRead( SYNTH_CLOCK_CNTRL,&i); if(Sel==SYNTH_CLKSEL_CK1) i|= SYNTH_CLKSEL_CK1; else i&= ~SYNTH_CLKSEL_CK1; i=SynthWrite( SYNTH_CLOCK_CNTRL,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the divider value for the channel specified (channels 0 to 7) specified as duty cycle for hi and lo - or simple divider plus duty cycle? =======================================================================*/ unsigned char SynthOpDiv(unsigned char Channel,unsigned char Hi,unsigned char Lo) { unsigned char i,j; switch (Channel) { case 0: j=SYNTH_OUT0_DIVHILO; break; case 1: j=SYNTH_OUT1_DIVHILO; break; case 2: j=SYNTH_OUT2_DIVHILO; break; case 3: j=SYNTH_OUT3_DIVHILO; break; case 4: j=SYNTH_OUT4_DIVHILO; break; case 5: j=SYNTH_OUT5_DIVHILO; break; case 6: j=SYNTH_OUT6_DIVHILO; break; case 7: j=SYNTH_OUT7_DIVHILO; break; default: return 1; break; } i= ( (Lo<<SYNTH_DIVLO_SHIFT)&SYNTH_DIVLO_MASK) | (Hi & SYNTH_DIVHI_MASK); i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the phase offset for the channel specified (channels 0 to 7) =======================================================================*/ unsigned char SynthPhaseOffset(unsigned char Channel,unsigned char Offs) { unsigned char i,j; switch (Channel) { case 0: j=SYNTH_OUT0_POFFS; break; case 1: j=SYNTH_OUT1_POFFS; break; case 2: j=SYNTH_OUT2_POFFS; break; case 3: j=SYNTH_OUT3_POFFS; break; case 4: j=SYNTH_OUT4_POFFS; break; case 5: j=SYNTH_OUT5_POFFS; break; case 6: j=SYNTH_OUT6_POFFS; break; case 7: j=SYNTH_OUT7_POFFS; break; default: return 1; break; } SynthRead( j,&i); i&= ~SYNTH_PHOFFS_MASK; i|= (Offs&SYNTH_PHOFFS_MASK); i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the start polarity for the channel specified (channels 0 to 7) =======================================================================*/ unsigned char SynthStartPol(unsigned char Channel,unsigned char Sel) { unsigned char i,j; switch (Channel) { case 0: j=SYNTH_OUT0_POFFS; break; case 1: j=SYNTH_OUT1_POFFS; break; case 2: j=SYNTH_OUT2_POFFS; break; case 3: j=SYNTH_OUT3_POFFS; break; case 4: j=SYNTH_OUT4_POFFS; break; case 5: j=SYNTH_OUT5_POFFS; break; case 6: j=SYNTH_OUT6_POFFS; break; case 7: j=SYNTH_OUT7_POFFS; break; default: return 1; break; } SynthRead( j,&i); if (Sel==1) i|=SYNTH_START_HI; else i&= ~SYNTH_START_HI; i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Force the level for the channel specified (channels 0 to 7) to the programmed start polarity (D5 address 49 odd) (NO chip sync must be ste for this to be active) =======================================================================*/ unsigned char SynthForce(unsigned char Channel,unsigned char Sel) { unsigned char i,j; switch (Channel) { case 0: j=SYNTH_OUT0_POFFS; break; case 1: j=SYNTH_OUT1_POFFS; break; case 2: j=SYNTH_OUT2_POFFS; break; case 3: j=SYNTH_OUT3_POFFS; break; case 4: j=SYNTH_OUT4_POFFS; break; case 5: j=SYNTH_OUT5_POFFS; break; case 6: j=SYNTH_OUT6_POFFS; break; case 7: j=SYNTH_OUT7_POFFS; break; default: return 1; break; } SynthRead( j,&i); if (Sel==1) i|=SYNTH_FORCE_START; else i&= ~SYNTH_FORCE_START; i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Enable/disable chip sync for the channel specified (channels 0 to 7) (D6 address 49 odd) =======================================================================*/ unsigned char SynthChipSync(unsigned char Channel,unsigned char Sel) { unsigned char i,j; switch (Channel) { case 0: j=SYNTH_OUT0_POFFS; break; case 1: j=SYNTH_OUT1_POFFS; break; case 2: j=SYNTH_OUT2_POFFS; break; case 3: j=SYNTH_OUT3_POFFS; break; case 4: j=SYNTH_OUT4_POFFS; break; case 5: j=SYNTH_OUT5_POFFS; break; case 6: j=SYNTH_OUT6_POFFS; break; case 7: j=SYNTH_OUT7_POFFS; break; default: return 1; break; } SynthRead( j,&i); if (Sel==1) i|=SYNTH_NOSYNC; else i&= ~SYNTH_NOSYNC; i=SynthWrite( j,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Set the func pin action - reset, sync( active low), power down 58 bits D5.D6 #define SYNTH_FUNC_RST 0 #define SYNTH_FUNC_SYNC D5 #define SYNTH_SYNC_PDB (D5|D6) #define SYNTH_SYNC_MASK (D5|D6) =======================================================================*/ unsigned char SynthFuncMode(unsigned char Sel) { unsigned char i; switch (Sel) { case SYNTH_FUNC_RST: case SYNTH_FUNC_SYNC: case SYNTH_SYNC_PDB: break; default: return 1; break; } SynthRead( SYNTH_SYNC_FUNC,&i); i&= ~SYNTH_SYNC_MASK; i|=Sel; i=SynthWrite( SYNTH_SYNC_FUNC,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Sync control 1 to enable 58 bit D0 =======================================================================*/ unsigned char SynthSyncDetEnab(unsigned char Sel,unsigned char Flag) { unsigned char i; SynthRead( SYNTH_SYNC_FUNC,&i); if(Sel) i|= SYNTH_SYNC_ENAB; else i&= ~SYNTH_SYNC_ENAB; i=SynthWrite( SYNTH_SYNC_FUNC,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Sync flag time limit ( <1 if set, >1 if clear) 58 bit D1 =======================================================================*/ unsigned char SynthSyncFlag(unsigned char Sel,unsigned char Flag) { unsigned char i; SynthRead( SYNTH_SYNC_FUNC,&i); if(Sel) i|= SYNTH_SYNC_FLAGLT1; else i&= ~SYNTH_SYNC_FLAGLT1; i=SynthWrite( SYNTH_SYNC_FUNC,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Soft sync control high forces sync state so set and clear bit 58 bits D2 =======================================================================*/ unsigned char SynthSoftSync(void) { unsigned char i; SynthRead( SYNTH_SYNC_FUNC,&i); SynthWrite( SYNTH_PRESCALE,(i|SYNTH_SYNC_SOFT)); sleepMs(1); SynthWrite( SYNTH_PRESCALE,(i& ~SYNTH_SYNC_SOFT)); return 0; } /*-----------------------------------------------------------------------*/ /*======================================================================= Power up/down the refs 1 to power down 58 bits D3 =======================================================================*/ unsigned char SynthRefsPdn(unsigned char Sel) { unsigned char i; SynthRead( SYNTH_SYNC_FUNC,&i); if(Sel==1) i|= SYNTH_REF_PWDN; else i&= ~SYNTH_REF_PWDN; i=SynthWrite( SYNTH_SYNC_FUNC,i); return i; } /*-----------------------------------------------------------------------*/ /*======================================================================= Power up/down the sync 1= power down 58 bits D4 =======================================================================*/ unsigned char SynthSyncPdn(unsigned char Sel) { unsigned char i; SynthRead( SYNTH_SYNC_FUNC,&i); if(Sel==1) i|= SYNTH_SYNC_PWDN; else i&= ~SYNTH_SYNC_PWDN; i=SynthWrite( SYNTH_SYNC_FUNC,i); return i; } /*-----------------------------------------------------------------------*/ /*==================================================================== Set the synth to use the VCXO direct, no control voltage ====================================================================*/ int SetVCXODirect(void) { SynthInit(); /*tristate the charge pump */ SynthCPMode(SYNTH_CPMODE_PMPTRI); /*power down the PLL */ SynthPLLPdn(SYNTH_PDN_ASYNC); /*power down ref clock, clock1 and prescaler, use CK2 i/p from VCXO */ SynthCkPDn(SYNTH_CLK_PWDNCK1|SYNTH_CLK_PWDNPRE|SYNTH_CLK_PWDNREF); SynthCkSel(SYNTH_CLKSEL_CK2); return (0); } /*---------------------------------------------------------------------*/ /*==================================================================== Read and display the value of the status bit for various mux settings ====================================================================*/ int ReadSynthStatusBits(void) { unsigned int i; unsigned char j; /*enable LOR bit and leave on*/ SynthRead(SYNTH_LOR,&j); printf(" Initial LOR ENABLE setting %x\n",j); /*mux the sources for the status pin*/ SynthStatusMode(SYNTH_MUXOUT_LORHI); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("LOR (active high) status = %x\n",i); SynthStatusMode(SYNTH_MUXOUT_ANALOGUE_N); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("Analogue_n lock detect status = %x \n",i); SynthStatusMode(SYNTH_MUXOUT_ANALOGUE_P); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("Analogue_p lock detect status = %x \n",i); SynthStatusMode(SYNTH_MUXOUT_PFDUP); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("PFDUP status bit = %x \n",i); SynthStatusMode(SYNTH_MUXOUT_PFDDN); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("PFDDN status bit = %x \n",i); SynthStatusMode(SYNTH_MUXOUT_DLDHI); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("Dig lock detect ( active high) status bit = %x \n",i); SynthStatusMode(SYNTH_MUXOUT_ACNTR); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("A counter status bit = %x \n",i); SynthStatusMode(SYNTH_MUXOUT_NCLCK); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("Prescaler status bit = %x \n",i); SynthStatusMode(SYNTH_MUXOUT_LORLLKHI); i=fpgaSpace[SYNTH_CNTRL_REG]; i&=SYNTH_STATUS; printf("Loss of ref/loss of lock (active high) status bit = %x \n",i); return (0); } /*---------------------------------------------------------------------*/ /*==================================================================== Delay is in ns; Channel is the 9510 channel no ( 5 or 6) Achieved delay is also dependent on the mark space ratio of the signal to be delayed - actual max delay is the width of the '1' in ns The delay range is set by the smallest value which is larger than the requested delay; ramp bit settings are adjusted to give the max resolution for the requested delay. ====================================================================*/ int SetChanDelay(double Delay, char Channel ) { unsigned char i=0,j=0; /*check for valid channel ( 5 or 6) */ if ( (Channel != 5) && (Channel != 6) ) return 1; /*check for delay too large */ if (SynthDelayMax[0]<Delay) return 2; /*Check which value of delay range is required goes max to min so first one less is one past the required one */ for( i=1 ;i< sizeof(SynthNoofCaps); i++) { if (SynthDelayMax[i]<Delay) { j=i-1; break; } } /* disable the delay */ SynthDelayEnab(Channel,0); /*check for delay less than the min offset - leaves delay disabled = min achievable */ if (SynthDelayOffs[j]>Delay) return 3; /*set up the caps */ SynthDelayCap(Channel,SynthNoofCaps[j]); /*set up the ramp current */ SynthDelayCur(Channel,SynthIRamp[j]); /*work out the delay value - round to nearest delay value*/ i = (char) ( 0.5 + ( ( Delay - SynthDelayOffs[j] ) / SynthDelayResln[j]) ); SynthDelayAdj(Channel,i); /* enable the delay */ SynthDelayEnab(Channel,1); return (0); } /*---------------------------------------------------------------------*/ /*==================================================================== Read and display the settings for the synth regs any value other than a specific register ( e.g. FF) dumps all registers ====================================================================*/ int ReadSynthRegs(unsigned char Select) { unsigned char i,j,index=SHOW_ALL_REGS; /*find the corresponding address index */ for(i=0;i<sizeof(SynthRegAddr);i++) { if(SynthRegAddr[i]==Select) { index = i; break; } } /*display results */ switch(index) { case SHOW_ALL_REGS : for(i=0;i<sizeof(SynthRegAddr);i++) { SynthRead(SynthRegAddr[i],&j); printf("%s (addr 0X%2.2x) reads 0X%2.2x\n",SynthRegNames[i],SynthRegAddr[i],j); } break; default : SynthRead(SynthRegAddr[index],&j); printf("%s (addr 0X%2.2x) reads 0X%2.2x\n",SynthRegNames[i],SynthRegAddr[i],j); break; } return (i+j); } /*---------------------------------------------------------------------*/ /*==================================================================== Select the clock source and rate Default ( following reset/initialisation) is the synthesiser with the VCXO locked to the external reference Clock muxing uses test reg 18 downto 16 -only a single bit is active at any time ====================================================================*/ int SetSampleClock(unsigned int Source, double CkSpeed) { //unsigned int Value,CkSrc = 0; //unsigned int i=0,j=0,Sel = 0;; //double Ckset; // // // /*Disable all clock outputs */ // SynthLVDSPDn(4,1); // SynthLVDSPDn(5,1); // SynthLVDSPDn(6,1); // SynthLVDSPDn(7,1); // // /*Check that the selected clock speed is less than the ADC max */ // if(CkSpeed >ADC_MAX_CK) return 1; // // /*Check for a legitimate source // Fixed clocks will give max speed closest to the specified value */ // switch (Source) // { // case VCXO: // i=(int) (VCXO_MAX/CkSpeed); // Sel = VCXO_SEL; // CkSrc = 1; // break; // case PCIE125: // i=(int) (PCIE_MAX/CkSpeed); // Sel = PCIE_SEL; // CkSrc = 2; // break; // case REF200: // i=(int) (REF200_MAX/CkSpeed); // Sel = REF200_SEL; // CkSrc = 2; // break; // case MCLKA: // i=(int) (MCK_MAX/CkSpeed); // Sel = MCKA_SEL; // CkSrc = 2; // /*set mclock to an exact // multiple of the required speed */ // Ckset=(double)i*CkSpeed; // break; // case MCLKB: // i=(int) (MCK_MAX/CkSpeed); // Sel = MCKB_SEL; // CkSrc = 2; // /*set mclock to an exact // multiple of the required speed */ // Ckset=(double)i*CkSpeed; // SetMClock (Ckset, card); // default: // return 1; // break; // } // // // if (CkSrc == 1) // { /*Normal operation using the ref clock */ // SynthInit(); // /*Disable all clock outputs again - init enables them*/ // SynthLVDSPDn(4,1); // SynthLVDSPDn(5,1); // SynthLVDSPDn(6,1); // SynthLVDSPDn(7,1); // } // else // { // /*Ck1 input driven by an FPGA clock */ // SynthCkPDn(SYNTH_CLK_PWDNNONE); // SynthCkPDn(SYNTH_CLK_PWDNCK1); // SynthCkPDn(SYNTH_CLK_PWDNPRE); // SynthCkPDn(SYNTH_CLK_PWDNREF); // SynthCkSel(SYNTH_CLKSEL_CK2); // } // // // // /*Set AD9510 dividers to required value (-should be 50% duty cycle // Divide Ratio = (high_cycles + 1) + (low_cycles + 1) // - LVDS channels only // May need to have non 50 % and use clock stabiliser // */ // SynthOpDiv(4,((i/2)-1),((i/2)-1)); // SynthOpDiv(5,((i/2)-1),((i/2)-1)); // SynthOpDiv(6,((i/2)-1),((i/2)-1)); // SynthOpDiv(7,((i/2)-1),((i/2)-1)); // // /*Set clock source in FPGA and AD9510 */ // SetFPGAClock(Sel); // // // /*Enable all clock outputs */ // SynthLVDSPDn(4,0); // SynthLVDSPDn(5,0); // SynthLVDSPDn(6,0); // SynthLVDSPDn(7,0); // // /*re-sync outputs */ // SynthSoftSync(); return (0); } /*---------------------------------------------------------------------*/ /*********************************************************************** * Class wrapper for PLL code *********************************************************************** */ PllSynth::PllSynth(){ fpgaSpace = ofpga = 0; } BError PllSynth::init(volatile uint32_t* fpgaAddress){ BError err; fpgaSpace = ofpga = fpgaAddress; SetVCXODirect(); return err; } BError PllSynth::setMode(Mode mode){ BError err; fpgaSpace = ofpga; if(mode == VCXO_REF) SynthInit(); else SetVCXODirect(); return err; } void PllSynth::displayRegisters(){ fpgaSpace = ofpga; ReadSynthRegs(0xFF); ReadSynthStatusBits(); } int PllSynth::lockStatus(){ int i; fpgaSpace = ofpga; SynthStatusMode(SYNTH_MUXOUT_DLDHI); i = fpgaSpace[SYNTH_CNTRL_REG] & SYNTH_STATUS; return (i != 0); } void PllSynth::lockReset(){ unsigned char v; fpgaSpace = ofpga; // Reset loss of reference in case the lock has been re-made SynthRead(SYNTH_LOR, &v); v &= ~SYNTH_LOR_ENABLE; SynthWrite(SYNTH_LOR, v); }