source: PlatformSupport/CustomPeripherals/pcores/w3_clock_controller_axi_v4_00_a/src/w3_clock_controller.c

Last change on this file was 4324, checked in by murphpo, 9 years ago

adding driver docs for clock controller

File size: 19.9 KB
Line 
1/*****************************************************************
2* File: w3_clock_controller.c
3* Copyright (c) 2015 Mango Communications, all rights reseved
4* Released under the WARP License
5* See http://warpproject.org/license for details
6*****************************************************************/
7
8/** \file w3_clock_controller.c
9
10\mainpage
11This is the driver for the w3_clock_controller_axi core, which implements an SPI master for controlling
12the AD9512 clock buffers on the WARP v3 board. This core also manages the interfaces on CM-MMCX
13and CM-PLL clock modules. Refer to the WARP v3 user guide for more details on the clock options and connections.
14
15@version 4.00.a
16@author Patrick Murphy
17@copyright (c) 2015 Mango Communications, Inc. All rights reserved.<br>
18Released under the WARP open source license (see http://warpproject.org/license)
19
20*/
21
22#include "w3_clock_controller.h"
23
24/**
25\defgroup user_functions Functions
26\brief Functions to call from user code
27\addtogroup user_functions
28
29Example:
30\code{.c}
31//Assumes user code sets CLK_BASEADDR to base address of w3_clock_controller_axi core, as set in xparameters.h
32
33//Initialize the AD9512 clock buffers
34clk_init(CLK_BASEADDR, 3);
35
36//Enable clock outputs to FMC slot
37clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_ON, (CLK_SAMP_OUTSEL_FMC | CLK_RFREF_OUTSEL_FMC));
38
39//Disable clock outputs to clock module header
40clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_OFF, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR));
41
42//Set clock to AD chips to 40MHz (80MHz source divided by 2)
43clk_config_dividers(CLK_BASEADDR, 2, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB));
44
45\endcode
46
47@{
48*/
49
50/**
51\brief Initializes the clock controller. This function must be called once at boot before any AD or
52RF operations will work. The w3_clock_controller_axi HDL applies preliminary configuration values
53to the sampling and RF reference clock buffers, and (if preset) the PLL+buffer on the CM-PLL
54clock module.
55
56The HDL applies the minimum set of configuration values to allow the MicroBlaze
57subsystem to boot. This function does not override any configuration values applied by
58the HDL.
59
60Refer to the pcore user guide for details on the pre-boot configuration process:
61  http://warpproject.org/trac/wiki/cores/w3_clock_controller
62
63Default config is:
64- On board 80MHz TCXO used as source for sampling and RF ref clock buffers
65- 80MHz clock driven to FPGA, RF A and RF B ADC/DACs
66- 40MHz clock driven to RF A and B transceivers
67- FMC and clock module header clocks disabled
68\param baseaddr Base memory address of w3_clock_controller_axi pcore
69\param clkDiv Clock divider for SPI serial clock (set to 3 for 160MHz bus)
70*/
71int clk_init(u32 baseaddr, u8 clkDiv) {
72    u32 x;
73   
74    //Set the SPI clock divider
75    Xil_Out32(baseaddr + CLKCTRL_REG_CONFIG, (clkDiv & CLKCTRL_REG_CONFIG_MASK_CLKDIV));
76
77    //Confirm the SPI interfaces are working
78    // Reads reg 0x00 from both AD9512; both must return 0x10
79    x = 0xFFFF & clk_spi_read(baseaddr, (CLK_SAMP_CS|CLK_RFREF_CS), 0x0);
80    if(x != 0x1010) {
81        xil_printf("First CLK SPI readback was wrong: addr[0]=0x%04x (should be 0x1010)\n", x);
82        return -1;
83    }
84
85    /* Samping Clock Buffer Config
86    Samp clock AD9512 outputs on WARP v3 board:
87     OUT0: AD2 (LVPECL)
88     OUT1: Clock module header (LVPECL)
89     OUT2: AD1 (LVPECL)
90     OUT3: FPGA col2 SRCC (LVDS)
91     OUT4: FMC  (LVDS)
92
93    HDL configures:
94     -Selects CLK1 (on-board) or CLK2 (off-board) as sampling clock source
95     -Sets divider and output type on OUT3 to achieve 80MHz LVDS to FPGA
96
97    clk_init() configures:
98     -Sets divider on OUT0/OUT2 for 40MHz LVPECL to RFA/B converters
99     -Disables OUT1/OUT4 outputs to clock module header and FMC
100
101    clk_init() must *not* change sampling clock source or divider on OUT3
102
103*/
104    //Enable OUT0, OUT2, OUT3; disable OUT1, OUT4; all outputs are on after powerup/reset
105    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x3E, 0x02); //OUT1 = off (PD2 mode, because OUT1 has load resistors)
106    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x41, 0x01); //OUT4 = off
107
108    //Power down divider logic on disabled outputs and 80MHz outputs
109    // Don't touch OUT3 divider config - HDL sets this
110    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4D, 0x80); //OUT1 divider off
111    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x53, 0x80); //OUT4 divider off
112
113    //Divide by 2 on OUT0/OUT2 to RFA/B convterters
114    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4B, 0x00); //OUT0 divider on
115    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4A, 0x00); //OUT0 divide by 2
116    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4F, 0x00); //OUT2 divider on
117    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4E, 0x00); //OUT2 divide by 2
118
119    //Trigger register update
120    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x5A, 0x01); //Self-clearing register update flag
121
122    /* RF Reference Clock Buffer Config
123    RF ref clock AD9512 outputs on WARP v3 board:
124        OUT0: Clock module header (LVPECL)
125        OUT1: NC
126        OUT2: NC
127        OUT3: Both MAX2829 ref (RFA=CMOSp, RFB=CMOSn; must be 20 or 40 MHz)
128        OUT4: FMC (LVDS)
129
130    HDL configures either:
131       -Nothing - in most configurations the HDL does not write RF ref clk buffer registers
132     or
133       -Selects on-board clock source (CLK1) and sets OUT0 divider to 8, providing a 10MHz
134         reference clock to the AD9511 PLL on the CM-PLL
135
136    clk_init() configures:
137      -If OUT0 is not configured for divide-by-8 (i.e. HDL did not write any regs):
138        -Selects CLK1 (on-board) clock source
139        -Disables OUT0 (output to clock module)
140      -Always configures:
141        -Disables OUT1/2 (unconnected on board)
142        -Enables OUT3 as 40MHz CMOS +/-
143        -Disables OUT4 (FMC)
144    */
145
146    //Read reg 0x4A - OUT3 divider config
147    // 0x33 => HDL wrote config
148    // Anything else => HDL did not write registers
149    x = clk_spi_read(baseaddr, (CLK_RFREF_CS), 0x4A);
150    if((x & 0xFF00) != 0x3300) {
151        //HDL didn't write config - apply defaults here
152
153        //Select CLK1 input, power down CLK2
154        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x45, 0x05); //CLK1 on, CLK2 off, CLK1 drives distribution
155
156        //Disable OUT0 (output to clock module)
157        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x3D, 0x02); //OUT0 = off, has load resistors
158        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x4B, 0x80); //OUT0 divider off
159    }
160   
161    //Disable unused outputs
162    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x3E, 0x03); //OUT1 = off, has no load resistors
163    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x3F, 0x03); //OUT2 = off, has no load resistors
164    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x41, 0x01); //OUT4 = off
165
166    //Power down divider logic on disabled ports
167    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x4D, 0x80); //OUT1 divider off
168    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x4F, 0x80); //OUT2 divider off
169    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x53, 0x80); //OUT4 divider off
170
171    //Enable inverted CMOS output on OUT3
172    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x40, 0x18); //OUT3 = CMOS, +/- both on
173
174    //Set divider to 2 on OUT3
175    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x50, 0x00); //OUT3 40MHz (1 cycle down)
176    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x51, 0x00); //Enable OUT3 divider
177
178    //Alternate config: 20MHz RF reference, OUT3 divider = 4
179    //clk_spi_write(baseaddr, CLK_RFREF_CS, 0x50, 0x11); //OUT3 20MHz (2 cycle down)
180    //clk_spi_write(baseaddr, CLK_RFREF_CS, 0x51, 0x00); //Enable OUT3 divider
181
182    //Trigger register update
183    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x5A, 0x01); //Self-clearing register update flag
184   
185    return 0;
186}
187
188/**
189\brief Configures which outputs are en/disabled in both AD9512 clock buffers
190\param baseaddr Base memory address of w3_clock_controller_axi pcore
191\param clkOutMode New mode for selected clock outputs; must be CLK_OUTPUT_ON or CLK_OUTPUT_OFF
192\param clkOutSel Masks to select which clock outputs to affect; must be OR'd combination of:
193 Mask | Selected Output
194 ---- | ----
195 CLK_SAMP_OUTSEL_FMC | Sampling clock buffer to FMC slot
196 CLK_SAMP_OUTSEL_CLKMODHDR | Sampling clock buffer to clock module header
197 CLK_SAMP_OUTSEL_FPGA | Sampling clock buffer to FPGA
198 CLK_SAMP_OUTSEL_AD_RFA | Sampling clock buffer to RF A AD9963 (ADC/DAC ref clock)
199 CLK_SAMP_OUTSEL_AD_RFB | Sampling clock buffer to RF B AD9963 (ADC/DAC ref clock)
200 CLK_RFREF_OUTSEL_FMC | RF ref clock buffer to FMC
201 CLK_RFREF_OUTSEL_CLKMODHDR | RF ref clock buffer to clock module header
202 CLK_RFREF_OUTSEL_RFAB | RF ref clock buffer to RF A and B transceivers
203\return Returns 0 on success, -1 for invalid parameters
204*/
205int clk_config_outputs(u32 baseaddr, u8 clkOutMode, u32 clkOutSel) {
206    if((clkOutMode != CLK_OUTPUT_ON) && (clkOutMode != CLK_OUTPUT_OFF))
207        return -1;
208/*
209    Samp clock AD9512 outputs on WARP v3 board:
210        OUT0: AD2 (LVPECL)
211        OUT1: Clock module header (LVPECL)
212        OUT2: AD1 (LVPECL)
213        OUT3: FPGA col2 SRCC (LVDS)
214        OUT4: FMC  (LVDS)
215
216    RF ref clock AD9512 outputs on WARP v3 board:
217        OUT0: Clock module header (LVPECL)
218        OUT1: NC
219        OUT2: NC
220        OUT3: Both MAX2829 ref (RFA=CMOSp, RFB=CMOSn; must be 20 or 40 MHz)
221        OUT4: FMC (LVDS)
222*/
223   
224    u8 lvpecl_cfg, lvds_cfg, cmos_cfg;
225
226    //Set the register values to write, based on output type and user ON/OFF param
227    if(clkOutMode == CLK_OUTPUT_ON) lvpecl_cfg = 0x8; //LVPECL output on, 805mV drive
228    else lvpecl_cfg = 0x2; //output off (for outputs w/ load resistors)
229
230    if(clkOutMode == CLK_OUTPUT_ON) lvds_cfg = 0x2; //output on, LVDS logic, 3.5mA drive
231    else lvds_cfg = 0x1; //output off
232
233    if(clkOutMode == CLK_OUTPUT_ON) cmos_cfg = 0x18; //+/- outputs on, CMOS logic
234    else cmos_cfg = 0x1; //output off
235   
236    /***** Sampling Clock Buffer Config ******/
237    //reg 0x3D, 0x3E, 0x3F: CLKOUT[0,1,2] config
238    // [1:0] LVPECL power down
239    //   (0x0=on, 0x2=PD2 (power down outputs w/ load resistors), 0x3=PD3 (power down outputs w/out load resistors)
240    // [3:2] LVPECL output drive (set to 0x2 for default 805mv)
241    if(clkOutSel & CLK_SAMP_OUTSEL_AD_RFB)      clk_spi_write(baseaddr, CLK_SAMP_CS, 0x3D, lvpecl_cfg); //CLKOUT0
242    if(clkOutSel & CLK_SAMP_OUTSEL_CLKMODHDR)   clk_spi_write(baseaddr, CLK_SAMP_CS, 0x3E, lvpecl_cfg); //CLKOUT1
243    if(clkOutSel & CLK_SAMP_OUTSEL_AD_RFA)      clk_spi_write(baseaddr, CLK_SAMP_CS, 0x3F, lvpecl_cfg); //CLKOUT2
244
245    //reg 0x40, 0x41: CLKOUT[3,4] config
246    // [0] 0=output on, 1=output off
247    // [2:1] LVDS output current (set to 0x1 for 3.5mA default)
248    // [3] Logic (0=LVDS, 1=CMOS)
249    // [4] CMOS- (0=Disable CMOS inverted output; 1=enable)
250    if(clkOutSel & CLK_SAMP_OUTSEL_FPGA)        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x40, lvds_cfg); //CLKOUT3 (LVDS)
251    if(clkOutSel & CLK_SAMP_OUTSEL_FMC)         clk_spi_write(baseaddr, CLK_SAMP_CS, 0x41, lvds_cfg); //CLKOUT4 (LVDS)
252
253    //Trigger register update
254    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x5A, 0x01); //Self-clearing register update flag
255
256    /***** RF Ref Clock Buffer Config ******/
257    //reg 0x3D: CLKOUT0 config
258    // [1:0] LVPECL power down
259    //   (0x0=on, 0x2=PD2 (power down outputs w/ load resistors), 0x3=PD3 (power down outputs w/out load resistors)
260    // [3:2] LVPECL output drive (set to 0x2 for default 805mv)
261    //CLKOUT1, CLKOUT2 are unused and are disabled in clk_init
262    if(clkOutSel & CLK_RFREF_OUTSEL_CLKMODHDR)  clk_spi_write(baseaddr, CLK_RFREF_CS, 0x3D, lvpecl_cfg); //CLKOUT0
263
264    //reg 0x40, 0x41: CLKOUT[3,4] config
265    // [0] 0=output on, 1=output off
266    // [2:1] LVDS output current (set to 0x1 for 3.5mA default)
267    // [3] Logic (0=LVDS, 1=CMOS)
268    // [4] CMOS- (0=Disable CMOS inverted output; 1=enable)
269    if(clkOutSel & CLK_RFREF_OUTSEL_RFAB)       clk_spi_write(baseaddr, CLK_RFREF_CS, 0x40, cmos_cfg); //CLKOUT3 (CMOS +/-)
270    if(clkOutSel & CLK_RFREF_OUTSEL_FMC)        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x41, lvds_cfg); //CLKOUT4 (LVDS)
271
272    //Trigger register update
273    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x5A, 0x01); //Self-clearing register update flag
274
275    return 0;
276}
277
278/**
279\brief Configures whether the RF Reference Buffer uses the on-board or off-board clock source
280\param baseaddr Base memory address of w3_clock_controller_axi pcore
281\param clkInSel Clock source mask, must be either CLK_INSEL_ONBOARD (for on-board oscillator) or CLK_INSEL_CLKMOD (for off-board clock via clock module header)
282 Mask | Selected Input
283 ---- | ----
284 CLK_INSEL_ONBOARD | Selects on-board TCXO as RF Reference clock source (AD9512 CLK1/CLK1B port)
285 CLK_INSEL_CLKMOD | Selects off-board clock from clock module header as RF Reference clock source (AD9512 CLK2/CLK2B port)
286\return Returns 0 on success, -1 for invalid parameters
287*/
288int clk_config_input_rf_ref(u32 baseaddr, u8 clkInSel) {
289    if((clkInSel != CLK_INSEL_ONBOARD) && (clkInSel != CLK_INSEL_CLKMOD))
290        return -1;
291/*
292    Samp clock AD9512 inputs on WARP v3 board:
293        CLK1: On-board TCXO
294        CLK2: Clock module header
295*/
296   
297    /***** Sampling Clock Buffer Config ******/
298    //reg 0x45
299    // [0] Input sel (0=CLK2, 1=CLK1)
300    // [1] 1=Power down CLK1 input circuit
301    // [2] 1=Power down CLK2 input circuit
302    // [3:4] Reserved
303    // [5] Power down both input circuits
304    // [6:7] Reserved
305    if(clkInSel == CLK_INSEL_ONBOARD)   clk_spi_write(baseaddr, CLK_RFREF_CS, 0x45, 0x05); //Select CLK1, power down CLK2
306    if(clkInSel == CLK_INSEL_CLKMOD)    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x45, 0x02); //Select CLK2, power down CLK1
307
308    //Trigger register update
309    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x5A, 0x01); //Self-clearing register update flag
310
311    return 0;
312}
313
314/**
315\brief Reads the status pins of the currently installed clock module
316\param baseaddr Base memory address of w3_clock_controller_axi pcore
317\return Returns the clock module status; the meaning of the status bits depends on the currently installed module.
318
319For the CM-MMCX, 2 LSB are value of 2-position SIP switch.
320For the CM-PLL, 3 LSB are the value of the 3 LSB of the DIP switch. Bit 0x8 is the PLL status.
321*/
322inline u32 clk_config_read_clkmod_status(u32 baseaddr) {
323    //Status reg in HDL:
324    // [31:28] = {cm_pll_status, cm_switch[2:0]}
325    return (u32)((Xil_In32(baseaddr + CLKCTRL_REG_CONFIG)) >> 28);
326}
327
328/**
329\brief Configures output dividers in both AD9512 clock buffers
330\param baseaddr Base memory address of w3_clock_controller_axi pcore
331\param clkDiv Divider value to set; must be 1 or even integer in [2,32]
332\param clkOutSel Masks to select which clock outputs to affect; must be OR'd combination of:
333 Mask | Selected Output
334 ---- | ----
335 CLK_SAMP_OUTSEL_FMC | Sampling clock buffer to FMC slot
336 CLK_SAMP_OUTSEL_CLKMODHDR | Sampling clock buffer to clock module header
337 CLK_SAMP_OUTSEL_FPGA | Sampling clock buffer to FPGA
338 CLK_SAMP_OUTSEL_AD_RFA | Sampling clock buffer to RF A AD9963 (ADC/DAC ref clock)
339 CLK_SAMP_OUTSEL_AD_RFB | Sampling clock buffer to RF B AD9963 (ADC/DAC ref clock)
340 CLK_RFREF_OUTSEL_FMC | RF ref clock buffer to FMC
341 CLK_RFREF_OUTSEL_CLKMODHDR | RF ref clock buffer to clock module header
342 CLK_RFREF_OUTSEL_RFAB | RF ref clock buffer to RF A and B transceivers
343\return Returns 0 on success, -1 for invalid parameters
344*/
345int clk_config_dividers(u32 baseaddr, u8 clkDiv, u32 clkOutSel) {
346/*
347    AD9512 reg 0x[4A,4C,4E,50,52]: Divider config high/low for CLKOUT[0,1,2,3,4]
348     [3:0] Divider high cycles
349     [7:4] Divider low cycles
350     Clock freq divided by ((high+1)+(low+1))
351     50% duty cycle requkired; only possible with 1 or even division ratios (high==low)
352
353    AD9512 reg 0x[4B,4D,4F,51,53]: Divider power down & sync for CLKOUT[0,1,2,3,4]
354     [7] 1=disable and bypass divider logic, 0=use divider
355     [6:0] Divider sync setup (not currently used)
356    */
357   
358    u8 div_pd, div_cfg;
359
360    //Check for invalid clkDiv value (any odd value besides 1, greater than 32, or 0)
361    if( ((clkDiv != 1) && (clkDiv & 0x1)) || clkDiv > 32 || clkDiv == 0)
362        return -1;
363   
364    if(clkDiv == 1) {
365        div_pd = 0x80; //divide-by-1 requires bypassing divider entirely
366        div_cfg = 0x00;
367    } else {
368        div_pd = 0x00; //enable divider
369
370        //Calculate number of high/low cycles
371        div_cfg = (clkDiv>>1)-1;
372       
373        //Set high=low
374        div_cfg = (div_cfg<<4) | div_cfg;
375    }
376   
377   
378    //Sampling clock buffer
379    if(clkOutSel & CLK_SAMP_OUTSEL_AD_RFB) { //CLKOUT0
380        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4A, div_cfg);
381        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4B, div_pd);
382    }
383    if(clkOutSel & CLK_SAMP_OUTSEL_CLKMODHDR) { //CLKOUT1
384        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4C, div_cfg);
385        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4D, div_pd);
386    }
387    if(clkOutSel & CLK_SAMP_OUTSEL_AD_RFA) { //CLKOUT2
388        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4E, div_cfg);
389        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x4F, div_pd);
390    }
391    if(clkOutSel & CLK_SAMP_OUTSEL_FPGA) { //CLKOUT3
392        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x50, div_cfg);
393        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x51, div_pd);
394    }
395    if(clkOutSel & CLK_SAMP_OUTSEL_FMC) { //CLKOUT4
396        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x52, div_cfg);
397        clk_spi_write(baseaddr, CLK_SAMP_CS, 0x53, div_pd);
398    }
399   
400    //Trigger register update
401    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x5A, 0x01); //Self-clearing register update flag
402
403    // Sync outputs (High -> Low transition on bit 2 - Soft SYNC)
404    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x58, 0x04);
405    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x5A, 0x01); //Self-clearing register update flag
406    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x58, 0x00);
407    clk_spi_write(baseaddr, CLK_SAMP_CS, 0x5A, 0x01); //Self-clearing register update flag
408   
409    //RF reference clock buffer
410    if(clkOutSel & CLK_RFREF_OUTSEL_CLKMODHDR) { //CLKOUT0
411        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x4A, div_cfg);
412        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x4B, div_pd);
413    }
414    //CLKOUT1, CLKOUT2 are unused; dividers are disabled in clk_init
415    if(clkOutSel & CLK_RFREF_OUTSEL_RFAB) { //CLKOUT3
416        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x50, div_cfg);
417        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x51, div_pd);
418    }
419    if(clkOutSel & CLK_RFREF_OUTSEL_FMC) { //CLKOUT4
420        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x52, div_cfg);
421        clk_spi_write(baseaddr, CLK_RFREF_CS, 0x53, div_pd);
422    }
423   
424    //Trigger register update
425    clk_spi_write(baseaddr, CLK_RFREF_CS, 0x5A, 0x01); //Self-clearing register update flag
426
427    return 0;
428}
429
430/**
431\brief Reads the specified register from both AD9963s
432\param baseaddr Base memory address of w3_clock_controller_axi pcore
433\param csMask OR'd combination of CLK_SAMP_CS and CLK_RFREF_CS
434\param regAddr Address of register to read, in [0x00, 0x5A]
435\return Returns concatenation of current values of the specified register for both AD9512s (if selected); samp clock buffer is LSB
436*/
437u32 clk_spi_read(u32 baseaddr,  u32 csMask, u8 regAddr) {
438    u32 txWord, rxWord;
439
440    //SPI Tx register is 4 bytes:
441    // [3]: chip selects (bitwise OR'd ADCTRL_REG_SPITX_ADx_CS)
442    // [2]: {rnw n1 n0 5'b0}, rnw=1 for SPI write, n1=n0=0 for 1 byte write
443    // [1]: reg addr[7:0]
444    // [0]: ignored for read (read value captured in Rx register)
445    txWord = (csMask & (CLK_SAMP_CS | CLK_RFREF_CS | CMPLL_CS)) | //chip selects
446             (CLKCTRL_REG_SPITX_RNW) | //spi_tx_byte[2] = {rnw n1 n0 5'b0}
447             ((regAddr & 0x7F)<<8) | //spi_tx_byte[1] = addr[7:0]
448             (0x00); //spi_tx_byte[0] = ignored for read (AD drives data pin during this byte)
449
450    Xil_Out32(baseaddr + CLKCTRL_REG_SPITX, txWord);
451
452    rxWord = Xil_In32(baseaddr + CLKCTRL_REG_SPIRX);
453
454    return(rxWord);
455}
456
457/**
458\brief Writes the specified register value to the selected AD9512 clock buffers
459\param baseaddr Base memory address of w3_clock_controller_axi pcore
460\param csMask OR'd combination of CLK_SAMP_CS and CLK_RFREF_CS
461\param regAddr Address of register to write, in [0x00, 0x5A]
462\param txByte 8-bit value to write
463*/
464void clk_spi_write(u32 baseaddr, u32 csMask, u8 regAddr, u8 txByte) {
465    u32 txWord;
466
467    //SPI read process:
468    // -Write full SPI word with RNW=1 and address of desired register
469    // -Capture register value in last byte of SPI write process (handled automatically in logic)
470   
471    //SPI Tx register is 4 bytes:
472    // [3]: chip selects (bitwise OR'd ADCTRL_REG_SPITX_ADx_CS)
473    // [2]: {rnw n1 n0 5'b0}, rnw=0 for SPI write, n1=n0=0 for 1 byte write
474    // [1]: reg addr[7:0]
475    // [0]: reg data[7:0]
476    txWord = (csMask & (CLK_SAMP_CS | CLK_RFREF_CS | CMPLL_CS)) | //chip selects
477             (0x00) | //spi_tx_byte[2] = {rnw n1 n0 5'b0}
478             ((regAddr & 0xFF)<<8) | //spi_tx_byte[1] = addr[7:0]
479             (txByte & 0xFF); //spi_tx_byte[0] = data byte to write
480
481    Xil_Out32(baseaddr + CLKCTRL_REG_SPITX, txWord);
482   
483    return;
484}
485
486/** @}*/ //END group user_functions
Note: See TracBrowser for help on using the repository browser.