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.
`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.