Video generation with altlvds_tx and external PLL
Hi,
We have a design targeting a Cyclone IV E with LVDS video output for an LCD panel.
There are several different variants of HDL code with different hard-coded display resolutions, but the one I am working on at the moment is for a 1920 x 1080 panel, eight LVDS data pairs and two clock pairs at 72 MHz.
For previous variants with lower resolutions, the configuration we used was
Ext 24 MHz clock -> PLL -> pixel clock -> altlvds_tx with internal PLL
Here is a data sheet extract showing the LVDS timing and encoding for the 1080p panel, this seems to be fairly standard across LCD manufacturers:
There are two instances of altlvds_tx_8bit in the design, for the odd- and even-numbered pixels. The tx_outclock port directly drives its respective LVDS clock pair.
This setup was inherited when I took over the project. It generated a picture and built without any timing warnings, but there were two issues:
- R6 and R7 bits were out of sync with the rest of the data by one pixel_clk cycle. This was never resolved on older variants using only 4 LVDS data pairs, but is a lot more noticeable with dual channel odd/even LVDS as the red 'shadow' is offset by 2 pixels.
- It seemed wasteful using a total of three PLLs.
A bit of reading suggested using the tx_outclock directly is wrong, as the duty cycle is 50/50 not 4/7, and edge alignment with the data is not properly controlled. The suggested method is to add another 7 input and 1 output ports to the altlvds block, and drive the inputs with a fixed pattern 1100011, aligned with the RGB input mapping on the other ports. The new output port then drives the clock pair.
At the same time I put this change in I reconfigured the altlvds_tx block to use an external PLL. This meant I could use a single PLL to generate all the needed clocks:
- PLL c0 output is 252 MHz, this feeds the tx_inclock port of both alt_lvds_tx blocks
- PLL c1 output is 72 MHz, this feeds all the video generation logic and the RGB data input registers of the alt_lvds_tx blocks.
The good news is this appears to work fine when loaded on the target and has fixed the RGB data alignment issue. The bad news is it now doesn't meet timing. The failing paths are all between the pixel clock and the 3.5x multiplied pixel clock domains.
The .sdc file is fairly minimal:
create_clock -name "MainClk" -period 41.667 [get_ports main_clk]
derive_pll_clocks -create_base_clocks -use_tan_name
derive_clock_uncertainty
set_clock_groups -asynchronous -group {MainClk} -group {pixel_clk pixel_lvds_clk}
pixel_clk and pixel_lvds_clk are the c1 and c0 ouputs from the PLL respectively; I have a keep attribute set in the RTL code for both of these signals so I can refer to them in the .sdc.
The .sdc used under the old structure, which did meet timing, was identical except pixel_lvds_clk was missing from the last line, as the equivalent node would have been internal to the altlvds_tx block and I had no idea what it was called.
So the only thing I can think of was there is some configuration option in the alt_lvds and/or alt_pll blocks which I'm missing, which are needed to make the timing relationship the same as in the old structure?
Any suggestions gratefully received.
I fixed it.
It was a case of RTFM - the 'slow' clock input to the atltlvds_tx block needs to be half the pixel clock frequency, I found this buried in the timing reports from the old design. Once I reconfigured the PLL again to give a third output at 36 MHz, it all works perfectly and passes timing.
This info is also in an information panel in the MegaWizard GUI, I didn't see it the first time.