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?
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.
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
clk is not vga_clkclk 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;
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.
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?
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
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; wire Green; assign Green = ActiveArea && XPixel; wire Blue; assign Blue = ActiveArea && XPixel; endmodule