I'm still just getting started with all of this, and am starting to play around with clock frequency generation. I'm in the process of writing a module to generate a sub-frequency, based off of the initial system frequency and a phase term.
This is real rough around the edges, but I thought I would post it to attempt to get feedback and learn something! So please, feel free to pick apart.
People also talk a lot about DLL and PLL units (Delay Locked Loop, Phase Locked Loop?) that might allow non-integer scales, but I wouldn't begin to know how to implement one.
I have an ongoing webpage here documenting my progress on this module. However, I will also include the code in this post:
How I'm calling the module:
Code: Select all
clock_gen gen_2(.sys_clk(clk), .out_clk(LINE_OUT)); defparam gen_2.sys_freq = 50000000; defparam gen_2.out_freq = 100000; defparam gen_2.phase = 90;
Code: Select all
// Module to generate a clock based off of the system clock and a desired frequency. // Note: only frequencies that are factors of 2n of the system clock can be generated. module clock_gen( input sys_clk, // System clock input output out_clk // Generated clock output ); // A register to hold the output value reg out_signal; assign out_clk = out_signal; // Continuous assignment to the module output // User-settable parameters to control functionality of the clock parameter sys_freq = 0; parameter out_freq = 0; parameter phase = 0; // 0->360: Undefined behavior out of this range. // Internal parameter (Do not set outside of the module!) // The frequency scale is the ratio of the input and output frequencies. // The scale is divided by two, because each count changes the edge, and // two edge changes make a single clock cycle. // In order to round to the nearest integer instead of truncating, the value is // bitshifted left, scaled, and bitshifted right. The second bitshift // right is the /2. parameter _internal_freq_scale = ((((sys_freq/out_freq) << 1) + 2) >> 2); // Create a register the proper width to hold a prescale counter // NOTE: The use of $clog2 requires that sys_freq and out_freq be // determined at compile time. reg[($clog2(_internal_freq_scale)-1):0] prescale; // Initial setup for the clock initial begin // To set the phase, start the frequency at some fraction of the // period. // However, as one full count 0->_internal_freq_scale is a half //period, we have to // do some extra work to get the phase right. if (phase < 180) begin prescale = _internal_freq_scale - (_internal_freq_scale * phase)/360; out_signal = 0; end else begin prescale = _internal_freq_scale - (_internal_freq_scale * phase)/360; out_signal = 1; end end // Every edge of the system clock, increment the prescalar. When it hits // the proper value, flip the always @(posedge sys_clk) begin prescale = prescale + 1'b1; if (prescale == _internal_freq_scale) begin out_signal = ~out_signal; prescale = 0; end end endmodule