I am using Verilog in Lattice Diamond IDE with a lattice MachXO2 7000HE breakout board.
I built a basic counter with a limit input which generates a variable period clock output. It works fine on its own, however, when I add two instances of this module and connect them in series (to scale the frequency twice), I get an odd result on the FPGA. The simulation, however seems to show what I had expected from the code.
Here is the top module:
module clock_generator (fpga_clock, cnt1_clock, cnt2_clock, cnt2_counter);
output wire fpga_clock;
output wire cnt1_clock;
output wire cnt2_clock;
output wire [7:0] cnt2_counter;
reg [7:0] default_period_1 = 8'b00000011;
reg [7:0] default_period_2 = 8'b00000011;
defparam OSCH_inst.NOM_FREQ = "2.08";
OSCH OSCH_inst(.STDBY(1'b0), .OSC(fpga_clock));
counter Counter_1_inst(.clk_in(fpga_clock), .limit_in(default_period_1), .clk_out(cnt1_clock), .cnt_out());
counter Counter_2_inst(.clk_in(cnt1_clock), .limit_in(default_period_1), .clk_out(cnt2_clock), .cnt_out(cnt2_counter));
endmodule
module counter (clk_in, limit_in, clk_out, cnt_out, rst);
input wire clk_in;
input wire [7:0] limit_in;
output reg clk_out = 1'b1;
output reg [7:0] cnt_out = 8'b00000000;
input wire rst;
always @(posedge clk_in or posedge rst) begin
if (rst) begin
clk_out <=0;
cnt_out <=0;
end else if (cnt_out == limit_in) begin
clk_out <= !clk_out;
cnt_out <= 0;
end else begin
cnt_out <= cnt_out + 1'b1;
end
end
endmodule
And here is the testbench for my simulation:
`timescale 1 ns / 1 ns
module testbench;
wire fpga_clock;
wire cnt1_clock;
wire cnt2_clock;
wire [7:0] cnt2_counter;
clock_generator dut(.fpga_clock(fpga_clock), .cnt1_clock(cnt1_clock), .cnt2_clock(cnt2_clock), .cnt2_counter(cnt2_counter));
initial begin
#1400000000
$finish;
end
endmodule
Here is the simulation output:
And the scope output:
ch1 - fpga_clock
ch2 - cnt1_clock
ch3 - cnt2_clock
ch4 - cnt2_counter[1]
scope output And the probe setup: Setup1
Channel 3 (cnt2_clock) should have twice the period of cnt2_counter[1], as it is in the simulation output. Instead as you can see it's a burst of higher frequency edges where the single edge should be. I've been on this for a while now. What am I missing?
Let me also add the shematic: enter image description here
Thank you!
########## Edit with additional picturesScope output with cnt2_counter[0]
ch1 - fpga_clock
ch2 - cnt1_clock
ch3 - cnt2_counter[0]
ch4 - cnt2_counter[1]
[cnt2_counter0[4] And the probe setup: Setup2
Pin list Pin list
-
\$\begingroup\$ Introduce reset signal, and perform setting of registers on reset signal (rather than assign values at the beginning of the module - I suspect you should get a list of warnings?). According to your readings register changes when its input clock is low. Another input to perform reg state change is its set/reset input, and it is not explicitly routed anywhere here. \$\endgroup\$Anonymous– Anonymous2018年12月19日 08:41:01 +00:00Commented Dec 19, 2018 at 8:41
-
\$\begingroup\$ @Anonymous, no, the only warning is this: .../top.v(12,2-12,49) (VERI-1927) port SEDSTDBY remains unconnected for this instance. I added a reset as you suggested but it didn't have any effect on the scope output. \$\endgroup\$amfast– amfast2018年12月19日 13:24:44 +00:00Commented Dec 19, 2018 at 13:24
-
1\$\begingroup\$ Are you absolutely certain that Ch3 on the scope plot is cnt2_clock? I ask as it is changing synchronously to Ch1 which you have said is fpga_clock. The code you have posted explicitly states that cnt2_clock is updated every cnt1_clock rising edge. \$\endgroup\$Vance– Vance2018年12月19日 14:00:40 +00:00Commented Dec 19, 2018 at 14:00
-
\$\begingroup\$ To @Vance 's comment... check your PAR report for IO assignments. \$\endgroup\$CapnJJ– CapnJJ2018年12月19日 17:08:03 +00:00Commented Dec 19, 2018 at 17:08
-
1\$\begingroup\$ @CapnJJ The only report I found regarding pin assignment is named "Signal/Pad" under "Process Reports". It shows the same pins that I have assigned. \$\endgroup\$amfast– amfast2019年01月08日 15:57:42 +00:00Commented Jan 8, 2019 at 15:57
2 Answers 2
You're using a generated clock. This is usually inadvisable on an FPGA as it has to be done very carefully to prevent glitches and to ensure timing closure is possible. It looks like you might be getting some glitches on cnt1_clock that are screwing up the second instance. Try using clock enables and see what happens.
Also, fpga_clock should be an input and not an output in your top module.
-
\$\begingroup\$ When you say "generated clock" do you mean cnt1_clock and cnt1_clock? Are you saying that I should use clock enable instead of clock divider like described here? The fact that this is a problem is new to me, but reading about it gives the impression that my code is badly written from the start. \$\endgroup\$amfast– amfast2019年01月08日 16:23:42 +00:00Commented Jan 8, 2019 at 16:23
-
\$\begingroup\$ It's generally advisable to avoid doing @(posedge something_that_isn't_a_proper_clock) as this means your logic could be "clocked" by any sort of glitches that might be generated by whatever logic is generating your clock signal, and simulation will not catch this. It also makes timing analysis more complex, and it's more difficult to close timing in this way. Hence, clock enables are preferred. Now, it seems like your generated clock is being directly driven by a flip flop, so in theory there should be no glitches, so I'm not sure exactly why you're seeing the behavior that you are. \$\endgroup\$alex.forencich– alex.forencich2019年01月09日 03:13:11 +00:00Commented Jan 9, 2019 at 3:13
How this should work?
always @(posedge clk_in) begin
cnt_out <= cnt_out + 1'b1;
if (cnt_out == limit_in) begin
clk_out <= !clk_out;
cnt_out <= 0;
end
end
Maybe you mean:
always @(posedge clk_in) begin
cnt_out <= (cnt_out == limit_in) ? 0 : cnt_out + 1;
clk_out <= (cnt_out == limit_in) ? ~clk_out : clk_out;
end
-
\$\begingroup\$ It's supposed to work just as it does in the simulation. And also on the FPGA as far as Counter_1_inst goes. I have now changed the code above to include a reset function as well. \$\endgroup\$amfast– amfast2019年01月08日 15:22:47 +00:00Commented Jan 8, 2019 at 15:22
-
\$\begingroup\$ That code should synthesize exactly the same way, while being more difficult to read. \$\endgroup\$alex.forencich– alex.forencich2019年01月09日 03:14:19 +00:00Commented Jan 9, 2019 at 3:14