2
\$\begingroup\$

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:

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 pictures

Scope 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

\$\endgroup\$
  • \$\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 Dec 19 '18 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 Dec 19 '18 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 Dec 19 '18 at 14:00
  • \$\begingroup\$ To @Vance 's comment... check your PAR report for IO assignments. \$\endgroup\$ – CapnJJ Dec 19 '18 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 Jan 8 '19 at 15:57
1
\$\begingroup\$

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.

|improve this answer|||||
\$\endgroup\$
  • \$\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 Jan 8 '19 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 Jan 9 '19 at 3:13
0
\$\begingroup\$

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 
|improve this answer|||||
\$\endgroup\$
  • \$\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 Jan 8 '19 at 15:22
  • \$\begingroup\$ That code should synthesize exactly the same way, while being more difficult to read. \$\endgroup\$ – alex.forencich Jan 9 '19 at 3:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.