How can I stop the simualtion at stop bit for i2c master verilog code?...

Q

Qazi Zabeer

Guest
I am trying to write Verilog code for I2C master and there are a couple of problems I am facing. I was able to compile and run its testbench on Quartus and modelsim, respectively.However, what I am trying to do is to have it swtich back to reset mode on(reset = 1) once the state reaches STATE_STOP(Basically have it stay in STATE_IDLE), so what can I add to either the code or the testbench to make it that way? The simulation continues after STATE_STOP, which I am not able to understand, and so I have to, at an arbitrary time, add either $finish or reset = 1 in the testbench. Here is the code:

`timescale 1ns/1ps

module I2C_Master(
input wire clk,
input wire reset,
input wire [7:0]data,
input wire [6:0]add,
input wire readorwrite,
output reg i2c_sda,
output reg i2c_scl
);

localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR = 2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_STOP = 6;
localparam STATE_WACK2 = 7;


reg [7:0] state;
reg [7:0] count;

always @(posedge clk) begin
if (reset == 1)
i2c_scl <= 1;
else begin
if (state == STATE_START)
i2c_scl <= 0;
else if (state == STATE_IDLE || state == STATE_STOP)
i2c_scl <= 1;
else
i2c_scl <= ~i2c_scl;
end
end

always @(posedge clk) begin
if (reset == 1) begin
state <= 0;
i2c_sda <= 1;
count <= 8\'d0;
end
else begin
case(state)

STATE_IDLE: begin
i2c_sda <= 1;
state <= STATE_START;
end

STATE_START: begin
i2c_sda <= 0;
state <= STATE_ADDR;
count <= 6;
end

STATE_ADDR: begin
i2c_sda <= add[count];
if (count == 0) state <= STATE_RW;
else count <= count - 1;
end

STATE_RW: begin
i2c_sda <= readorwrite;
state <= STATE_WACK;
end

STATE_WACK: begin
i2c_sda <= 0;
state <= STATE_DATA;
count <= 7;
end

STATE_DATA: begin
i2c_sda <= data[count];
if (count == 0) state <= STATE_WACK;
else count <= count - 1;
end

STATE_WACK2: begin
i2c_sda <= readorwrite;
state <= STATE_STOP;
end

STATE_STOP: begin
i2c_sda <= 0;
end
endcase
end

end
endmodule
The testbench:

module I2C_MasterTB;

reg clk;
reg reset;
reg [7:0]data;
reg [6:0]add;
reg readorwrite;

wire i2c_sda;
wire i2c_scl;

I2C_Master uut (
.clk(clk),
.reset(reset),
.data(data),
.add(add),
.readorwrite(readorwrite),
.i2c_sda(i2c_sda),
.i2c_scl(i2c_scl)
);

initial begin
clk = 0;
forever begin
clk = #1 ~clk;
end
end

initial begin
reset = 1;
add <= 7\'h50;
data <= 8\'haa;
readorwrite <= 0;

#10;

reset = 0;

#100;

reset = 1;

end

endmodule
As I already mentioned, I only arbitrarly chose a time period to finish the simulation, but I cant seem to think of the way to the end the simulation as soon as it reaches the last state and have it stay in idle state.
 
On 6/5/2023 6:15 PM, Qazi Zabeer wrote:
I am trying to write Verilog code for I2C master and there are a couple of problems I am facing. I was able to compile and run its testbench on Quartus and modelsim, respectively.However, what I am trying to do is to have it swtich back to reset mode on(reset = 1) once the state reaches STATE_STOP(Basically have it stay in STATE_IDLE), so what can I add to either the code or the testbench to make it that way? The simulation continues after STATE_STOP, which I am not able to understand, and so I have to, at an arbitrary time, add either $finish or reset = 1 in the testbench. Here is the code:

`timescale 1ns/1ps

module I2C_Master(
input wire clk,
input wire reset,
input wire [7:0]data,
input wire [6:0]add,
input wire readorwrite,
output reg i2c_sda,
output reg i2c_scl
);

localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR = 2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_STOP = 6;
localparam STATE_WACK2 = 7;


reg [7:0] state;
reg [7:0] count;

always @(posedge clk) begin
if (reset == 1)
i2c_scl <= 1;
else begin
if (state == STATE_START)
i2c_scl <= 0;
else if (state == STATE_IDLE || state == STATE_STOP)
i2c_scl <= 1;
else
i2c_scl <= ~i2c_scl;
end
end

always @(posedge clk) begin
if (reset == 1) begin
state <= 0;
i2c_sda <= 1;
count <= 8\'d0;
end
else begin
case(state)

STATE_IDLE: begin
i2c_sda <= 1;
state <= STATE_START;
end

STATE_START: begin
i2c_sda <= 0;
state <= STATE_ADDR;
count <= 6;
end

STATE_ADDR: begin
i2c_sda <= add[count];
if (count == 0) state <= STATE_RW;
else count <= count - 1;
end

STATE_RW: begin
i2c_sda <= readorwrite;
state <= STATE_WACK;
end

STATE_WACK: begin
i2c_sda <= 0;
state <= STATE_DATA;
count <= 7;
end

STATE_DATA: begin
i2c_sda <= data[count];
if (count == 0) state <= STATE_WACK;
else count <= count - 1;
end

STATE_WACK2: begin
i2c_sda <= readorwrite;
state <= STATE_STOP;
end

STATE_STOP: begin
i2c_sda <= 0;
end
endcase
end

end
endmodule

It looks like your \'state machine\' goes into a loop at STATE_DATA and
never gets to STATE_STOP.

STATE_DATA line now: if (count == 0) state <= STATE_WACK;

Probably should be: if (count == 0) state <= STATE_WACK2;

Note the 2 at the end.

Charlie

<snip>
 

Welcome to EDABoard.com

Sponsor

Back
Top