What is the frequency of my timer?

Hi! I have created this code, and I assumed that it would change states with a frequency of 100MHz/2^26, but it is instead changing at 100MHz/2^27. I know this is a lack of my basic understanding as I am new to FPGAs, but can someone explain why this is? Thank you!

module au_top (
    input clk,              // 100MHz clock
    input rst_n,            // reset button (active low)
    input usb_rx,           // USB->Serial input
    output usb_tx,          //
    output br_pin[32],        //Initialise 32 GPIO pins
    output power[8]
  ) {
  
  sig rst;
  dff tmr[26](.clk(clk));   // dff that uses onboard 100MHz clock
  values myValues;          // call values module outside the clock module - it does not have a clock input
      
  .clk(tmr.q[25]) {         // clock is set to 100MHz/2^(25+1) 
    reset_conditioner reset_cond;     
    .rst(rst) {
      counter myCounter;    // call counter module with tmr.q[25] as its clock
    }
  }
  
   always {
    tmr.d = tmr.q + 1;      // increment counter
    reset_cond.in = ~rst_n; // input raw inverted reset signal
    rst = reset_cond.out;   // conditioned reset
    usb_tx = usb_rx;        // loop serial port
    br_pin = 0;             // all GPIO pins initialised to be off
    power = myValues.power;
    br_pin = myValues.out[myCounter.count];  
    // all GPIO pins are equal to the eight bit output defined in the values module
    // the output generated corresponds to the counter's count
    // there is a 100MHz/2^26 pause at each output value
    
    
  }
}
1 Like

I don’t use Lucid and I am looking at this from a Verilog point of view so this advice is maybe not applicable to Lucid, or maybe it is.

First point of advice:
In Verilog at least, when you declare a register you say:

reg [25:0] reggy = 26’b0;

The register (reggy) is actually 26 bits wide, not 25. The position 0 counts as a bit. This might happen in Lucid, but nevertheless I spotted that you put “dff tmr[26]” and I flinched from experience.

I doubt that this is a problem in Lucid, but, at least in Verilog, the always block you have there should have a sensitivity list like:

always @(some_random_pin_or_register_or_clock) {code}

or

always @(*) {code},

and also the assignments inside should be <= not = if you are using a clocked always block, which it appears you are. Take this advice as a clue where to look, not as a definitive answer, because, like I said earlier, I don’t use Lucid.

@Random_FPGA_Guy thanks for offering some help but most of that isn’t applicable to Lucid.

In Lucid, you simply say how big the array is (no extra 0 index). You also don’t need to worry about sensitivity lists and the <= operator doesn’t exist.

@batmanlover.07 First, you generally shouldn’t use anything for a clock other than the clock signal. This will lead to timing issues at some point and your design will fail in the real world.

tmr.q[25] should be toggling with a frequency of 100MHz/2^26 as you expect. I suspect something in counter is dividing it by 2. You could output tmr.q[25] to br_pin and check it.

The “correct” way to trigger something periodically slower than your main clock is to create a single cycle pulse off the tmr.q[25] signal (say on the rising edge) then use that to do whatever you want. If you explain more what you’re trying to do I can give a full example.

2 Likes

@alchitry Please give a full example if you can!

This is my counter module

module counter (
    input clk,      // clock
    input rst,      // reset
    output count[3] // count is 3 bits wide as value is three bits wide
  ) {
  
  .clk(clk), .rst(rst) {
    dff val[3];     // maximum val is 5, so val needs to be three bits wide
                    // if val is two bits wide, it can only have a maximum of 4 (2^2)
  }
  always {

    if (val.q == 5)        // if max value is reached
        val.d = 0;           // reset to 0
    else                   // otherwise
        val.d = val.q + 1;   // add one
     
    count = val.q;
  }
}

Here’s how I would do it.

module alchitry_top (
    input clk,              // 100MHz clock
    input rst_n,            // reset button (active low)
    output led[8],          // 8 user controllable LEDs
    input usb_rx,           // USB->Serial input
    output usb_tx           // USB->Serial output
) {

    sig rst                 // reset signal

    .clk(clk) {
        // The reset conditioner is used to synchronize the reset signal to the FPGA
        // clock. This ensures the entire FPGA comes out of reset at the same time.
        reset_conditioner reset_cond
        .rst(rst) {
            counter myCounter
            dff tmr[26]
            dff lastTmr
        }
    }

    always {
        reset_cond.in = ~rst_n  // input raw inverted reset signal
        rst = reset_cond.out    // conditioned reset

        usb_tx = usb_rx         // echo the serial data
        
        tmr.d = tmr.q + 1
        lastTmr.d = tmr.q[-1] // MSB
        myCounter.pulse = lastTmr.q == 0 && tmr.q[-1] == 1 // rising edge
        led = myCounter.count
    }
}
module counter (
    input clk,      // clock
    input rst,      // reset
    input pulse,
    output count[3] // count is 3 bits wide as value is three bits wide
) {
    
    .clk(clk), .rst(rst) {
        dff val[3]     // maximum val is 5, so val needs to be three bits wide
        // if val is two bits wide, it can only have a maximum of 4 (2^2)
    }
    always {
        
        if (pulse) {
            if (val.q == 5)        // if max value is reached
                val.d = 0           // reset to 0
            else                   // otherwise
                val.d = val.q + 1   // add one
        }
        
        count = val.q
    }
}

Note that I used -1 to index the MSB. It’s just nice if you ever change the size of tmr then you don’t need to change the index.

I use another dff to store the last value of the MSB then use it to detect rising edges and output a single cycle pulse on that edge. You could also simply check the entire tmr for a value like tmr.q == 0 or &tmr.q (for all 1’s) but doing the rising edge version is likely a little more efficient as it doesn’t depend on the size of tmr.

1 Like

Thank you so much!

So was what the reason for the extra division in my initial code? Was it due to the counter taking a clock cycle to do its computation, resulting in an output frequency of 100MHz/2^(26+1)?