Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

VGA 25MHz, Clock 100MHz, Help!

Hi,

I would like to use a 100MHz clock to drive my logic, but the problem is that VGA needs a clock of 25MHz.

Right now, I am using 2 PLLs to create a 100MHz clock and 25MHz clock by using the CLOCK_50 input (which is 50MHz). But I'm not sure I can simply exchange data generated at the 100MHz clock, to the VGA at 25MHz clock.

Any help?

10 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    if you want to exchange data or signals from one clock domain to another then you must be aware of clock crossing.

    but this easy done, just cascade 2 DFF both clocked by the destination clock. for each signal (if your data is 8 bit wide, you need 2 x 8 DFF)

    another aproach is to let the whole stuff run at 100MHz and create a clock enable signal for the 25MHz (this could be a 2 bit counter and 00 means enable) so you get 1 clock pulse every 4 clocks and this is 25MHz.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    eject is right, I should be using 25.175 MHz, not 25 MHz. This is now corrected.

    I am now using CLOCK_27 to generate the 25.175MHz clock, and CLOCK_50 to generate the 100MHz clock.

    I have included a small test verilog module called vgatest in the vgatest.v attachment. It shows exactly what I am trying to achieve: Generating a counter at the normal clock, and feeding this to vga output.

    However, when I program this test, my vga screen output is shaking.

    When I move all the counter logic into the vga_clk domain, the image is correct and clean. This is ofcourse not an option, since the color needs to be generated from the normal clock.

    MSchmitt, can you explain in more detail the DFF method?

    I don't quite understand what you mean.

    Regards
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    clk is not vga_clk

    clk is ~100MHz

    vga_clk ~25MHz

    in your design the two clocks are different ! so you must obey them and perform clock domain crossing

    first some verilog hints from my side

    within always construct use <= (non-blocking assignment)

    instead of = (blocking assignment)

    second, the compare "vga_y == 0" is correct s long as vga_y is 1 bit wide. if it is an array better use === you will waste lot of time hunting such a bug when using == with arrrays

    so your code a bit shorted

    always @ ( posedge clk )

    counter <= counter + 1;

    and

    always @ ( posedge clk )

    vga_color <= counter

    shows one problem.

    counter is based on a different clock that vga_color, so you could get some glitches and oll other problems.

    the synchronisation is exactly described by the quartus online help, but it says something like taht for your problem

    reg [31:0] counter_piped1;

    reg [31:0] counter_piped2;

    always @ ( posedge vga_clk)

    begin

    counter_piped1 <= counter;

    counter_piped2 <= counter_piped1;

    end

    (you recognized the 2 DFF here both 32bit wide ?)

    now counter_piped2 is syncron with vga_clk

    always @ ( posedge vga_clk)

    vga_color <= counter_piped2;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you, MSchmitt, for your help :). I am understanding things more clearly now.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    About clock domain crossing:

    To pass your data across there are two issues:

    1) data synchronisation to clocks

    2) correct data transfer

    No 1 is to avoid nonbinary states to propagate through other registers. It is implemented as the well known two stage synchroniser.

    No 2 is based on reading each data sample once and without a miss i.e. needs rate control, storage and hand-shaking signals.

    if data is slow changing level signal(every now and then) No 1 is enough to synchronise as well as pass the value in time.

    if data is the usual pattern of changing at any time then you need to store data but synchronise the hand-shake signals...this is not very easy and it is done for you in dc fifos so just use a fifo. In all cases the average rate of data must tend to equality across the domains.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Now that you mention fifo's.. I would like to expand my current design.

    In the 100MHz clock domain, I need to generate pixel data based on video ram (also clocked at 100MHz).

    However, I need a pixel (x, y) coordinate to calculate what color the pixel should be. Currently, the (x, y) pixel coordinate is coming from the VGA controller, which is clocked at 25.175 MHz, so I can't let it cross the 100MHz clock domain without some delay.

    My idea right now is to use a asynchronous FIFO (dcfifo), and simulate the (x, y) coordinate in the 100MHz clock domain. The 100MHz clock will check the "wrfull" signal of the fifo, and only write a pixel to the fifo when the fifo is not full, and in that case, it will also advance the (x,y) coordinate.

    The VGA clock will check the "rdempty" signal of the fifo, and feed the color from the fifo to the VGA output (the fifo should always be non-empty, since the 100MHz clock will make sure of that).

    However, the problem I can foresee is, how do I synchronize the simulated (x, y) coordinate, with the real vga_x and vga_y? Maybe I can somehow reset it during vsync in one way or another?

    And, will things be still sychronized in case of a system reset? What if the FIFO was not empty, and adds some extra delay?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    a VGA controller is realy a pretty simple statemachine, just some counters and a bit combinatorial logic thats it.

    you need a counter for x and one for y

    based on these values you generate the blanking signals

    i could give you an example for 640x480 und you just need to add 2 bit counter to slow down the pixel rate from 100 : 25 = 4 : 1.

    vga runs at 25 very well

    if you just add your own vga controller and let it run at 100MHz you wont need to worry about the clock crossing stuff
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Here is a vga example with a reduced pixel clock (should run at 100MHz for 25MHz Pixelclock)

    If you need other resolution, just modify some counters and fixed values.

    //***************************************************************************************************************************************************

    // definitions, includes

    //======================

    // synthesis translate_off

    `timescale 1ns / 1ps

    // synthesis translate_on

    module video_vga_lcd_640x480 (

    gls_clk,

    reset_n,

    nHSync,

    nVSync,

    HBlank,

    VBlank,

    Red,

    Green,

    Blue,

    ActiveArea,

    XPixel,

    YPixel

    );

    input gls_clk;

    input reset_n;

    output nHSync;

    output nVSync;

    output HBlank;

    output VBlank;

    output Red;

    output Green;

    output Blue;

    output ActiveArea;

    output [ 9: 0] XPixel;

    output [ 9: 0] YPixel;

    reg [1:0] slowdown4to1;

    always @ (posedge gls_clk)

    slowdown4to1 <= slowdown4to1 + 2'd1;

    wire EnablePixelClk;

    assign EnablePixelClk = !slowdown4to1;

    // Horizontal

    // 640 Pixel

    // 48 Front Porch

    // 96 Sync

    // 16 Back Porch

    // 800 Pixel pro Zeile

    reg [ 9: 0] XPixel;

    always @ (posedge gls_clk)

    if ( XPixel === 10'd799 )

    XPixel <= 10'd0;

    else

    XPixel <= ( EnablePixelClk ) ? XPixel + 10'd1 : XPixel;

    reg HBlank;

    always @ ( posedge gls_clk )

    if ( XPixel === 10'd639 ) // Start of Front Porch

    HBlank <= 1'b1;

    else if ( XPixel === 10'd799 ) // End of Back Porch

    HBlank <= 1'b0;

    else

    HBlank <= HBlank;

    reg nHSync; // 640 -1 + 16 till 640 - 1 + 96

    always @ ( posedge gls_clk )

    if ( XPixel === 10'd655 ) // Start of HSync

    nHSync <= 1'b0;

    else if ( XPixel === 10'd735 ) // End of HSync

    nHSync <= 1'b1;

    else

    nHSync <= nHSync;

    // Vertikal

    // 480 Videolines

    // 10 Front Porch

    // 2 Sync

    // 33 Back Porch

    // 525 Lines total

    reg [ 9: 0] YPixel;

    always @ ( posedge gls_clk )

    if ( XPixel === 10'd799 )

    if ( YPixel === 10'd524 )

    YPixel <=10'd0;

    else

    YPixel <= YPixel + 10'd1;

    else

    YPixel <= YPixel;

    reg VBlank;

    always @ ( posedge gls_clk )

    if ( XPixel === 10'd799 )

    if ( YPixel === 10'd479 ) // Start of Front Porch

    VBlank <= 1'b1;

    else if ( YPixel === 10'd524 ) // End of Back Porch

    VBlank <= 1'b0;

    else

    VBlank <= VBlank;

    else

    VBlank <= VBlank;

    reg nVSync; // 480 - 1 + 10 till 480 - 1 + 10 + 2

    always @ ( posedge gls_clk )

    if ( XPixel === 10'd799 )

    if ( YPixel === 10'd489 ) // Start of VSync

    nVSync <= 1'b0;

    else if ( YPixel === 10'd491 ) // End of VSync

    nVSync <= 1'b1;

    else

    nVSync <= nVSync;

    else

    nVSync <= nVSync;

    wire ActiveArea;

    assign ActiveArea = !HBlank && !VBlank;

    wire Red;

    assign Red = ActiveArea && XPixel[2];

    wire Green;

    assign Green = ActiveArea && XPixel[5];

    wire Blue;

    assign Blue = ActiveArea && XPixel[8];

    endmodule