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)?