Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Valued Contributor III
835 Views

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?
0 Kudos
10 Replies
Highlighted
Valued Contributor III
23 Views

It's nothing to worry about this. The PLL can fit it's output

0 Kudos
Highlighted
Valued Contributor III
23 Views

isn't it 25.175MHz ?

0 Kudos
Highlighted
Valued Contributor III
23 Views

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.
0 Kudos
Highlighted
Valued Contributor III
23 Views

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
0 Kudos
Highlighted
Valued Contributor III
23 Views

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;
0 Kudos
Highlighted
Valued Contributor III
23 Views

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

0 Kudos
Highlighted
Valued Contributor III
23 Views

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.
0 Kudos
Highlighted
Valued Contributor III
23 Views

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?
0 Kudos
Highlighted
Valued Contributor III
23 Views

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
0 Kudos
Highlighted
Valued Contributor III
23 Views

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
0 Kudos