I am trying to implement the UART transmitter FSM using Verilog, but the FSM is stuck at IDLE
state. Can someone tell what mistakes am I making? The code is as below.
`timescale 1ns / 1ps
module Transmitter(
input clk,
input [7:0] data,
input Tx,
input reset,
output reg TxD
);
parameter BaudRate=921600;
parameter clk_rate=100000000;
integer bit_counter=0;
reg [1:0]state, next_state;
localparam clk_per_bit=(clk_rate/BaudRate);
integer clocks_counter=0;
localparam IDLE=2'd0;
localparam START=2'd1;
localparam TRANSMIT=2'd2;
localparam END=2'd3;
always@(posedge clk or posedge reset)
if(reset)
begin
bit_counter<=0;
clocks_counter<=0;
state<=IDLE;
end
else if (clocks_counter< clk_per_bit)
clocks_counter<=clocks_counter+1;
else begin state<=next_state; clocks_counter<=0; end
always@(*)
case(state)
IDLE: begin
TxD=1;
next_state= Tx ? START:IDLE;
end
START: begin TxD=0;
next_state= TRANSMIT;
end
TRANSMIT:begin TxD=data[bit_counter];
bit_counter=bit_counter+1;
next_state= (bit_counter>7)? END:TRANSMIT;
end
END: begin TxD=1;
next_state= IDLE;
end
endcase
endmodule
Here is the code link to view simulation result:
2 Answers 2
Another problem is that you have the statement
bit_counter = bit_counter + 1;
in an unclocked always
block -- this will not work. You will need to move that to the clocked block, incrementing the bit_counter at the same time you assign the next state, but only if you're in the TRANSMIT state.
-
\$\begingroup\$ Exactly,it will cause an inferred latch other wise which will bring racing issue \$\endgroup\$Rezef– Rezef2024年03月19日 14:34:28 +00:00Commented Mar 19, 2024 at 14:34
The Tx
pulse is too short. You need to keep it high long enough for counter
to roll over (from 108 to 0). In the testbench, change:
#2 Tx=0;
to something like:
#1200 Tx=0;
clk_per_bit
is 108.
Now you will see state
change from IDLE
TO START
:
Explore related questions
See similar questions with these tags.