In my main/top module I instantiate the following:
longint baudRate = 9600;
UART_BaudRate_generator BaudGen1(
.Clk( clk ),
.Tick( baudTick ),
.BaudRate( baudRate )
);
…
module UART_BaudRate_generator( Clk, Tick, BaudRate );
input Clk ; // Clock input
input longint BaudRate ; // Bits per second
output Tick ; // Each "BaudRate" pulses we create a tick pulse
longint BaudRateClocks; // Number of FPGA clock cycles requires for 1 baud period
longint freqFPGA;
longint currClockCount; // Register used to count
initial
begin
Tick = 0;
currClockCount = 0;
freqFPGA = 50000000; // 50MHz
//BaudRateClocks = 50000000 / 9600; // Works OK
//BaudRateClocks = 50000000 / BaudRate; // FAILS
//BaudRateClocks = freqFPGA / 9600; // Works OK
BaudRateClocks = freqFPGA / BaudRate; // FAILS
end
always @(posedge Clk)
begin
currClockCount ++;
if(currClockCount >= BaudRateClocks)
begin
Tick = ! Tick;
currClockCount = 0;
end
else
begin
currClockCount ++;
end
end
endmodule
I try to calculate 50000000 / 9600 within the module and I don’t get the correct value. If I try a literal value of 9600 within the module then I do get the correct result. What am I doing wrong? I’m assuming that the initial block is called when the module is instantiated.
In reply to SparkyNZ:
BTW, when asking questions, it always helps when you explain the correct value you expect versus what you were actually seeing.
I’m guessing you are seeing a 0 result, because BaudRate is still 0 at the time the initial block gets executed. That’s because you have a race condition between the initial block and the propagation of the input port. If you don’t expect BaudRate to change at any time, then you probably should declare it as a parameter instead of an input port.
module UART_BaudRate_generator #(longint BaudRate) (
input Clk , // Clock input
output bit Tick // Each "BaudRate" pulses we create a tick pulse
);
localparam longint freqFPGA = 50000000; // 50MHz;
localparam longint BaudRateClocks = freqFPGA/BaudRate; // Number of FPGA clock cycles requires for 1 baud period
longint currClockCount; // Register used to count
initial
begin
Tick = 0;
currClockCount = 0;
end
always @(posedge Clk)
begin
currClockCount ++;
if(currClockCount >= BaudRateClocks)
begin
Tick = ! Tick;
currClockCount = 0;
end
else
begin
currClockCount ++;
end
end
endmodule
parameter longint baudRate = 9600;
UART_BaudRate_generator #(.BaudRate(baudRate))
BaudGen1(
.Clk( clk ),
.Tick( baudTick )
);
In reply to dave_59:
Thanks for that Dave. As you may have guessed I am from a software developer background. You’ve certainly given me a few points to read up on. I didn’t realise you could pass parameters as such. Definitely in this case I would have been aiming for passing in a constant value.
For me it’s quite hard to seperate or think about applying solutions in an asynchronous manner. I’m quite happy doing so on a breadboard etc but when it comes to FPGA programming it’s a bit of a challenge. :) I still don’t feel as though I have found the right learning resource/reference for me yet. I only switched to SystemVerilog a few days ago upon discovering that I could use better functions for handling strings and the likes - I’m trying to set up my own serial terminal interface for debugging.
I wondered whether or not I should have tried all of this out with modelsim so I could have witnessed debug and see what my actual values were but I kept tinkering with the actual hardware and scope until I couldn’t take any more :-)
Anyway thanks again for getting me over this hurdle!
In reply to SparkyNZ:
I had to massage things around a little but this seems to work now:
Calling code:
parameter longint baudRate = 9600;
UART_BaudRate_generator #(baudRate) BaudGen1(
.Clk( clk ),
.Tick( baudTick )
);
Implementation:
module UART_BaudRate_generator #(parameter longint BaudRate=19200) // Bits per second
(
input Clk,
output Tick // Each "BaudRate" pulses we create a tick pulse
);
localparam longint freqFPGA = 50000000; // 50MHz
localparam longint BaudRateClocks = freqFPGA / BaudRate; // Number of FPGA clock cycles requires for 1 baud period
etc..
I just added the 19200 default for the parameter to make sure it was using the 9600 value passed in. My scope is now happy!