Understanding the heartbeat of your FPGA
The clock is the global synchronizer. Every flip-flop updates on the clock edge. If your clock is wrong, EVERYTHING is wrong.
The board has a 27 MHz crystal oscillator connected to pin H11. This is your primary clock source.
// Using the board clock module top ( input clk_27mhz, // 27 MHz from crystal output reg led ); reg [23:0] counter; always @(posedge clk_27mhz) begin counter <= counter + 1; led <= counter[23]; // Toggle LED every 2^23 clocks (~0.3s) end endmodule
Sometimes you need a slower clock. Use a counter to divide frequency:
// Divide 27 MHz by 27,000 to get 1 kHz module clock_divider ( input clk_in, // 27 MHz input rst, output reg clk_out // 1 kHz ); reg [14:0] counter; // Need to count to 27,000 always @(posedge clk_in) begin if (rst) begin counter <= 0; clk_out <= 0; end else if (counter == 13499) begin // Half period counter <= 0; clk_out <= ~clk_out; // Toggle end else counter <= counter + 1; end endmodule
// Use clock enable instead of divided clock module clock_enable ( input clk, input rst, output reg clk_enable // Pulse every N clocks ); reg [14:0] counter; always @(posedge clk) begin if (rst) begin counter <= 0; clk_enable <= 0; end else if (counter == 26999) begin counter <= 0; clk_enable <= 1; // Pulse high for one cycle end else begin counter <= counter + 1; clk_enable <= 0; end end endmodule // Using the enable signal always @(posedge clk) begin if (clk_enable) begin // This code runs at 1 kHz my_counter <= my_counter + 1; end end
Need a FASTER clock? Or a precise frequency? Use a PLL. It's a hardware frequency multiplier/divider.
Gowin_rPLL// Using PLL in your design module top ( input clk_27mhz, output led ); wire clk_108mhz; wire pll_lock; // PLL locked indicator // Instantiate PLL Gowin_rPLL pll_inst ( .clkin(clk_27mhz), .clkout(clk_108mhz), .lock(pll_lock) ); // Use the 108 MHz clock reg [25:0] counter; always @(posedge clk_108mhz) begin if (pll_lock) counter <= counter + 1; end assign led = counter[25]; endmodule
Tell the tools what clock frequency you're using so they can optimize routing:
// In your .sdc file (Synopsys Design Constraints) // Primary clock: 27 MHz = 37.037 ns period create_clock -name clk_27mhz -period 37.037 [get_ports {clk_27mhz}] // Generated clock from PLL: 108 MHz = 9.259 ns period create_generated_clock -name clk_108mhz -source [get_ports {clk_27mhz}] \ -multiply_by 4 -divide_by 1 [get_nets {clk_108mhz}]
When signals cross between different clock domains, you need synchronizers to prevent metastability:
// 2-stage synchronizer for single-bit signals module synchronizer ( input clk_dest, // Destination clock input async_in, // Asynchronous input output reg sync_out // Synchronized output ); reg sync_stage1; always @(posedge clk_dest) begin sync_stage1 <= async_in; // First flop (may go metastable) sync_out <= sync_stage1; // Second flop (stable output) end endmodule
| Term | Meaning |
|---|---|
| Setup Time | Data must be stable BEFORE clock edge |
| Hold Time | Data must be stable AFTER clock edge |
| Clock-to-Q | Delay from clock edge to output change |
| Max Frequency (Fmax) | Fastest clock that meets all timing |
| Slack | Time margin (positive = good, negative = BAD) |
lock signal from PLL before using the output clock