So I am trying to make a basic FSM in verilog to turn on 3 different LEDs. I've looked at examples and other people's work, but I can't understand why mine wont work. Maybe someone can help me spot a bug in my code I can't see.
module blink( input rst, output reg [2:0] leds, output LED);
OSCH #("2.08") osc_int ( //"2.03" specifies the operating frequency, 2.03 MHz. Other clock frequencies can be found in the MachX02's documentation
.STDBY(1'b0), //Specifies active state
.OSC(clk), //Outputs clock signal to 'clk' net
.SEDSTDBY());
wire clk_slow; //this will be the slower clock wire
reg [21:0] cnt; //these two lines use the fast clock to increment a 21 bit register
always @(posedge clk) cnt <= cnt+1;
assign clk_slow = cnt[21]; //this is high whenever the 21st bit of the fast clock register is true, thus slowing the clock to about 1 Hz
assign LED = clk_slow ; //status LED so I know my clock is working
reg [1:0] state;
reg [1:0] state_n;
parameter S0 = 2'b00; //state paramenters
parameter S1 = 2'b01;
parameter S2 = 2'b10;
always @ (posedge clk_slow or posedge rst) //state changer
begin
if(!rst)
state <= S0;
else
state <= state_n;
end
always @ (*) //changes next state
begin
case(state)
S0: state_n = S1;
S1: state_n = S2;
S2: state_n = S0;
default state_n = S0;
endcase
end
always @ (*) //decides what leds to light based on state
begin
if (state == S0)
leds = 3'b001;
else if(state == S1)
leds = 3'b010;
else if(state == S2)
leds = 3'b100;
end
endmodule
I'm not quite sure why it isn't working. The status LED I have hooked up is blinking at 1 Hz, which is correct. My other 3 LEDs seem to be stuck in State 0... or something. When I hit the reset button, it sometimes changes my LEDs to state 1, but I think that has to do with clock overlap. Any help is appreciated.
I am using a Lattice Diamond FPGA to program this. I am using the onboard clock to generate the initial clock, and I am using on board LEDs. My reset button is external and active low.
-
\$\begingroup\$ If the reset is active low you need negedge rst. \$\endgroup\$copper.hat– copper.hat2015年05月11日 04:30:41 +00:00Commented May 11, 2015 at 4:30
2 Answers 2
always @ (posedge clk_slow or posedge rst) //state changer
begin
if(!rst)
state <= S0;
else
state <= state_n;
end
If you want an asyncronous active-low reset, this always block should be sensitive to negedge rst
instead of posedge rst
.
If you want an active-high reset, then the condition in your if statement should be rst
instead of !rst
.
Edit
Other minor issues I see in the code (that shouldn't make your system nonfunctional):
Your comment says
cnt
is a 21-bit register, but the actual code makes it a 22-bit register. This should just make the LEDs blink half as fast as you expected.There is no reset logic for
cnt
. This will make the code difficult to simulate (becausecnt
will be stuck in the 'x' state).
-
\$\begingroup\$ Ah, yes thank you! However, my problem persists even after I have changed that. :( \$\endgroup\$Gigaxalus– Gigaxalus2015年05月11日 03:32:02 +00:00Commented May 11, 2015 at 3:32
-
\$\begingroup\$ Hmm ok thanks. I'll try to implement that and see if that helps me find the problem. \$\endgroup\$Gigaxalus– Gigaxalus2015年05月11日 04:39:10 +00:00Commented May 11, 2015 at 4:39
Best practice is not to use clk_slow as your state machine clock. Use clk for your state machine and make clk_slow a sort of flag.
always @ (posedge clk or posedge rst)
begin
if(!rst)
state <= S0;
else if (clk_slow)
state <= state_n;
end
(I don't usually work in Verilog so please verify the syntax)