UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
2,338 Views
Registered: ‎06-20-2013

Zynq LVDS ADC Interfacing issue @ 162MHz

Hi,

 

I am using Vivado 2017.2 to implement a design on a Zynq [xc7z015clg485-1] that interfaces to a ADC via LVDS at 162MHz.

 

The ADC provides a DCLK, FCLK and multiple DATA signals, all LVDS.

 

I have routed the DCLKP/N, FCLKP/N and DATA/P/N all through separate IBUFDS blocks. The DCLK is then routed through a BUFG and used by my own logic to de-serialize the DATA. I have done this rather than use a SERDES module, but could consider using a SERDES module if necessary.

 

I have the following constraints: 

 

create_clock -period 6.143 -name DCLK_P -waveform {0.000 3.072} [get_ports DCLK_P]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -min -add_delay 1.000 [get_ports *_DATA_N]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -max -add_delay 2.000 [get_ports *_DATA_N]
set_input_delay -clock [get_clocks DCLK_P] -min -add_delay 1.000 [get_ports *_DATA_N]
set_input_delay -clock [get_clocks DCLK_P] -max -add_delay 2.000 [get_ports *_DATA_N]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -min -add_delay 1.000 [get_ports *_DATA_P]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -max -add_delay 2.000 [get_ports *_DATA_P]
set_input_delay -clock [get_clocks DCLK_P] -min -add_delay 1.000 [get_ports *_DATA_P]
set_input_delay -clock [get_clocks DCLK_P] -max -add_delay 2.000 [get_ports *_DATA_P]
set_input_delay -clock [get_clocks DCLK_P] -min -add_delay 1.000 [get_ports FCLK_N]
set_input_delay -clock [get_clocks DCLK_P] -max -add_delay 2.000 [get_ports FCLK_N]
set_input_delay -clock [get_clocks DCLK_P] -min -add_delay 1.000 [get_ports FCLK_P]
set_input_delay -clock [get_clocks DCLK_P] -max -add_delay 2.000 [get_ports FCLK_P]

Despite failing to meet timing (hold violations) I have successfully interfaced with the ADC and got the data I expect. However, as the design has grown in size I am starting to experience issues with the ADC interface and really need to get a handle on this and achieve timing closure.

 

I have read loads of posts about others struggling to understand how to interface to the ADC via LVDS and I have been through XAPP524 several times and I think I understand what is required by dynamically adjusting the IODELAY when half the DCLK period is < 2.5ns. However, in my case half the DCLK period is > 2.5ns (it is 3.072ns).

 

Therefore, I cannot necessary use the IDELAY2 to add sufficient delay to realign DCLK with DATA. Never the less I have added an IDELAY2 block in between the IBUFDS and BUFG and investigated the effect of different tap values (set statically). When the tap value is 31 (max) I get a more negative slack and when the tap value is 0 (min, as is the case for the report below) I get the smallest negative slack value.

 

Hold.PNG

So with 9.557ns delay on the clock path this is effectively moving the clock a whole period and more. But with a 4.958ns delay on the data path this is moving the data less than one clock period.

 

Questions:

 

1. Do the tools automatically recognize that the delay to the clock is in excess of a clock period and look at the next clock edge for timing analysis or do I need to tell the tools this by using some kind of constraint?

 

2. I assume that I am trying to achieve a positive slack. How do I do this? Should I remove the IDELAY from the DCLK path and put it in the DATA path instead and then increase the tap to 31 to give an extra 2.5ns delay to the DATA path. This might make the slack positive by a small margin. However, this doesn't appear to be the best more robust method of always achieving timing closure as the design increases in size.

 

3. Am I actually reading the timing report correctly, or have I done something stupid that is causing me loads of issues that can be resolved by doing it a different way?

 

Many Thanks,

 

Simon

 

0 Kudos
8 Replies
Historian
Historian
2,319 Views
Registered: ‎01-23-2009

Re: Zynq LVDS ADC Interfacing issue @ 162MHz

As a first pass, I am going to make a couple of suggestions...

 

First, this interface is just over 3ns per data bit. At this speed, it should be possible to capture this interface statically - without the need to use dynamic calibration. So ignore XAPP524.

 

However, it has to be done "right" - and using a simple BUFG as the clocking mechanism is not "right" - the timing characteristics of this clocking architecture are pretty bad - you need a better one. EIther use an MMCM before the BUFG (to remove the clock insertion uncertainty) or use "ChipSync" clocking, using the BUFIO and BUFR. Take a look a this post on different clocking architectures for input capture.

 

Furthermore, for all interfaces like this, the capture flip-flops really should be (must be?) forced into the IOB using the IOB property. This will make the interface timing independent of everything else in the design.

 

For the constraints, the tools make an assumption about launch and capture edges - they will not try to select the "best" edge based on propagation delays - the launch and capture edges are determined by the un-propagated clock. Start with taking a look a this post on constraining edge aligned source synchronous DDR interfaces (even though your's isn't truly edge aligned) - it will give you an idea of where you need to go next.

 

And just a note (a bit of a pet peeve of mine, since it is the constraints wizard that does it) - the first set of set_input_delays (either rising clock or falling clock) should not have the -add_delay on it, only the second should...

 

Avrum

Tags (1)
0 Kudos
2,304 Views
Registered: ‎06-20-2013

Re: Zynq LVDS ADC Interfacing issue @ 162MHz

Thanks Avrum,

 

So I have removed the BUFG and IDELAY2 and replaced them with a BUFR (which drives all the logic) and BUFIO (which just drives a IDDR).

 

I have multiple ADC chips to interface to and one unfortunately spans two banks (bank 13 and bank 35) so I may need to change the BUFR to a BUFMR. How do you find out if bank 13 and bank 35 are adjacent?

 

I have added...

 

set_property IOB TRUE [all_inputs]
set_property IOB TRUE [all_outputs]

 ... to my constraints file to pack the IOB.

 

On your last comment are you saying that the DCLK_N constraints shouldn't have the -add_delay but the DCLK_P constraints should? Or are you saying that the min constraints should not have the -add_delay but the max constraints should?

 

I am re-running Synthesis now and will post the results. However, I would appreciate if you could comment on if I have interpreted your suggestions correctly.

 

Many Thanks,

 

Simon 

0 Kudos
Historian
Historian
2,277 Views
Registered: ‎01-23-2009

Re: Zynq LVDS ADC Interfacing issue @ 162MHz

Banks 13 and 35 are almost certainly not adjacent - 13 is adjacent to 12 and 14 only (assuming they exist).

 

Furthermore, even if you were going to use the BUFMR, it doesn't replace the BUFR - the connections go through the BUFMR to the BUFIO and BUFR (all of the ones for the interface).

 

BUFMR.jpg

 

It is also important to note that the timing through the BUFMR is significantly worse than the timing through a BUFR alone - at the frequencies you are using, it may not meet timing. In some cases the MMCM->BUFG timing can be better then the BUFMR->BUFIO/BUFR.

 

Finally, whichever mechanism you use, you will almost certainly need a mechanism of adjusting the clock data timing relationship. If you use the BUFIO/BUFR the only mechanism available is the IDELAY either on clock or data (or both) set to fixed values. If you use the MMCM then you can use the phase shift capability of the MMCM to (statically) change the phase of your MMCM clock so that you meet timing.

 

Avrum

Tags (1)
0 Kudos
Highlighted
Historian
Historian
2,273 Views
Registered: ‎01-23-2009

Re: Zynq LVDS ADC Interfacing issue @ 162MHz

As for the constraints - there are a couple of things.

 

First, you only constrain the P side of differential pairs - never the N side (so remove all the N side constraints).

 

Second, you can constrain multiple ports at the same time using a list of ports

 

Third you do not use the -add_delay with the first set of timing (say the ones without the -clock_fall), you only use it on the second (say with the -clock_fall).

 

 

create_clock -period 6.143 -name DCLK_P -waveform {0.000 3.072} [get_ports DCLK_P]
set_input_delay -clock [get_clocks DCLK_P] 2 -max [get_ports {*_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] 1 -min [get_ports (*_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] 2 -max -clock_fall -add_delay [get_ports {*_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] 1 -min -clock_fall -add_delay [get_ports (*_DATA_P FCLK_P}]

 

This is, of course, assuming that the constraint timing is correct - that the delay from DCLK_P to the data is 1-2ns - this is pretty unusual timing for an ADC (which is most often edge aligned, so more like -0.5ns to +0.5ns).

 

Avrum

0 Kudos
2,182 Views
Registered: ‎06-20-2013

Re: Zynq LVDS ADC Interfacing issue @ 162MHz

I have consulted the ADC datasheet further and found the setup (1.3ns) and hold (1.46ns) are provided.

 

Therefore, this gives me the following condition where DCLK changes in the middle of the eye of the data and the setup and hold time are known.

 

ADC.png

 

However, because DCLK goes through the IBUFDS > BUFIO/BURF it is delayed so I have added a IDELAY2 to the DATA and set the tap to 31 giving 2.5ns of delay. This is only for the ADC's that interface with a single bank, those that interface with multiple banks have been ignored for now.

 

So along with removing the N side constraints and the -add_delay I have ended up with the following constraints.

 

set_input_delay -clock [get_clocks DCLK_P] -min  1.46 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] -max -1.30 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -min -add_delay  1.46 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P}]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -max -add_delay -1.30 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P}]

This gives be an implementation that achieves timing closure. But doesn't allow me to get the correct data from the ADC.

 

What have I done wrong?

 

Thanks,

 

Simon

0 Kudos
Historian
Historian
2,170 Views
Registered: ‎01-23-2009

Re: Zynq LVDS ADC Interfacing issue @ 162MHz

So, first, your constraints are wrong (and hence the analysis is meaningless)...

 

The timing you showed gives the data becoming valid 1.3ns before an edge of a clock and stays valid until 1.46ns after the clock. So, if we assume that the clock is a perfect 50/50 duty cycle, lets look at the first "unknown" period - the one that ends at -1.3ns; where does it start? It starts 1.46ns after the previous edge, which is at -3.07ns. So, the unknown period starts at -3.07+1.46 = -1.61ns.

 

So the data starts changing at -1.61ns (the min) and finishes changing at -1.30ns (the max). So the correct constraints are

 

set_input_delay -clock [get_clocks DCLK_P] -min -1.61 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] -max -1.30 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -min -add_delay  -1.61 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P}]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -max -add_delay -1.30 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P}]

 

As a cross check, the min must always be smaller than the max - it was not in your constraints.

 

This is one possible way of specifying the constraints - there is a second one. Take a look at this post on constraining center aligned source synchronous DDR input interfaces... You need to either use the ones above with some commands to change the edge relationships (set_multicycle_path 0 and associated virtual clocks and set_false_paths), or the different other set of constraints; where the rising edge constraints define the window centered around the falling edge; the uncertainty window starts at 1.46ns, and ends 1.3ns before the next edge, which is 3.07-1.30 = 1.77ns.

 

set_input_delay -clock [get_clocks DCLK_P] -min 1.46 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] -max 1.77 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -min -add_delay 1.46 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P}]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -max -add_delay 1.77 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P}]

 

These constraints are correct without any of the other miscellaneous stuff (set_multicycle_path, set_false_path).

 

BUT, neither of these account for things like duty cycle imbalance of the clock, non-perfect length matching on the board, signal integrity issues, jitter, etc... They should probably be derated for all these factors.

 

But once you have the constraints correct, you can focus on the clock structure and IDELAY or MMCM settings required to make this meet timing. With 2.76ns of valid window, you should be able to to it with a number of (reasonable) clocking structures.

 

Avrum

0 Kudos
2,155 Views
Registered: ‎06-20-2013

Re: Zynq LVDS ADC Interfacing issue @ 162MHz

Thanks Avrum,

 

So I think that I am starting to understand now.

 

So whilst the ADC datasheet defines the setup and hold time spanning a clock edge Vivado needs the max and min the same side of the clock edge, either before or after, but not spanning. Furthermore Vivado constraints are defining the window of uncertainty rather than the window of certainty.

 

ADC_VIVADO.png

 

So If I were to use max and min values after the clock edge, 1.46ns (min) and 1.7715ns (max) and derate them to accommodate for duty cycle imbalance, line length matching, signal integrity issues, jitter, etc... I might end up with 1.00ns (min) and 2.00ns (max) or have derated to much?

 

set_input_delay -clock [get_clocks DCLK_P] -min 1.00 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] -max 2.00 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P FCLK_P}]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -min -add_delay 1.00 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P}]
set_input_delay -clock [get_clocks DCLK_P] -clock_fall -max -add_delay 2.00 [get_ports {AB_DATA_P CD_DATA_P EF_DATA_P GH_DATA_P}]

If I understand you correctly these are the only constraints required.

 

Isn't this what I started with? Even though the max and min figures I had in the beginning were derived using a different method, and whilst incorrect for that method, happened to be correct after all.

 

Perhaps the bit I was missing was the IOB Packing, using the IDELAY2 on the DATA (with taps = 31 [2.5ns delay]) and using the BUFIO / BUFR....i'll implement the above and let you know the results. 

 

Many thanks,

 

Simon

0 Kudos
2,136 Views
Registered: ‎06-20-2013

Re: Zynq LVDS ADC Interfacing issue @ 162MHz

I have implemented the design and by manipulating the IDELAY_VALUE I have got a solution that doesn't give me any setup or hold errors. However, I also don't get any meaningful data from the ADC.

 

This suggests that there is another problem. However, are my constraints now correct?

 

Thanks,

 

Simon

0 Kudos