模块代码
module iic_w(
input wire sclk,
input wire rst_n,
input wire w_en,
input wire [7:0] data,
input wire [15:0] addr,
output wire scl,
output tri sda
);
parameter DIV_CNT = 8'd240 - 1;
parameter DIV_CNT_1 = 8'd60 - 1;
parameter DIV_CNT_2 = 8'd120 - 1;
parameter DIV_CNT_3 = 8'd180 - 1;
reg w_start;
reg trans_flag;
reg w_stop;
reg [7:0] div_cnt;
reg [3:0] trans_cnt;
reg [5:0] byte_cnt;
reg scl_p_flag;
reg scl_n_flag;
wire [7:0] fifo_out;
reg [15:0] w_addr_buf;
reg scl_wire;
reg sda_en;
reg sda_w;
reg [7:0] w_buf;
reg r_en;
wire empty;
wire full;
reg data_trans_flag;
reg r_en_n;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
w_start <= 1'b0;
else if(w_en == 1'b1)
w_start <= 1'b1;
else if(div_cnt == DIV_CNT && w_start == 1'b1)
w_start <= 1'b0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
trans_flag <= 1'b0;
else if(w_start == 1'b1 && div_cnt == DIV_CNT)
trans_flag <= 1'b1;
else if(div_cnt == DIV_CNT && trans_cnt == 4'd8 && byte_cnt == 'd32 && trans_flag == 1'b1)
trans_flag <= 1'b0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
w_stop <= 1'b0;
else if(div_cnt == DIV_CNT && trans_cnt == 4'd8 && byte_cnt == 'd32)
w_stop <= 1'b1;
else if(div_cnt ==DIV_CNT && w_stop == 1'b1)
w_stop <= 1'b0;
//注意在判断信号为低时的条件时,加上(w_start trans_flag )
//判断w_stop为低时,是否需要加trans_flag == 1‘b1
//用普通计数器计数器不清零,采用明德杨的计数器正常
/* always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
div_cnt <= 8'd0;
else if(w_start == 1'b1||trans_flag == 1'b1||w_stop == 1'b1)
div_cnt <= div_cnt + 1'b1;
else if(div_cnt == DIV_CNT && (w_start == 1'b1 || trans_flag == 1'b1 || w_stop == 1'b1))
div_cnt <= 'd0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
trans_cnt <= 4'd0;
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT )
trans_cnt <= trans_cnt + 1'b1;
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT && trans_cnt == 4'd8 )
trans_cnt <= 4'd0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
byte_cnt <= 2'd0;
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT && trans_cnt == 4'd8)
byte_cnt <= byte_cnt + 1'b1;
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT && trans_cnt == 4'd8 && byte_cnt == 2'd3 )
byte_cnt <= 2'd0;
*/
always @(posedge sclk or negedge rst_n)begin
if(!rst_n)begin
div_cnt <= 'd0;
end
else if((w_start == 1'b1)||(trans_flag == 1'b1) || (w_stop == 1'b1))begin
if((div_cnt == DIV_CNT)&&((w_start == 1'b1)||(trans_flag == 1'b1) || (w_stop == 1'b1)))
div_cnt <= 'd0;
else
div_cnt <= div_cnt + 1'b1;
end
end
always @(posedge sclk or negedge rst_n)begin
if(!rst_n)begin
trans_cnt <= 'd0;
end
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT)begin
if(trans_flag == 1'b1 && div_cnt == DIV_CNT && trans_cnt == 4'd8)
trans_cnt <= 'd0;
else
trans_cnt <= trans_cnt + 1'b1;
end
end
always @(posedge sclk or negedge rst_n)begin
if(!rst_n)begin
byte_cnt <= 'd0;
end
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT && trans_cnt == 4'd8)begin
if(trans_flag == 1'b1 && div_cnt == DIV_CNT && trans_cnt == 4'd8 && byte_cnt == 'd35 )
byte_cnt <= 'd0;
else
byte_cnt <= byte_cnt + 1'b1;
end
end
//结束条件应在在加一条件满足的情况下
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
scl_p_flag <= 1'd0;
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT_1)
scl_p_flag <= 1'b1;
else
scl_p_flag <= 1'b0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
scl_n_flag <= 1'd0;
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT_3)
scl_n_flag <= 1'b1;
else
scl_n_flag <= 1'b0;
assign scl = scl_wire;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
scl_wire <= 1'b1;
else if(w_start == 1'b1 && div_cnt == DIV_CNT_2)
scl_wire <= 1'b0;
else if(trans_flag == 1'b1 && scl_p_flag == 1'b1)
scl_wire <= 1'b1;
else if(trans_flag == 1'b1 && scl_n_flag == 1'b1)
scl_wire <= 1'b0;
else if(w_stop == 1'b1 && div_cnt == DIV_CNT_2)
scl_wire <= 1'b1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0) begin
w_addr_buf <= 16'd0;
end
else if(w_en == 1'b1) begin
w_addr_buf <= addr;
end
//外接口的数据不能直接用,应该用时序逻辑把数据转存在寄存器中再去使用
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
w_buf <= 8'b1111_1111;
else if(trans_flag == 1'b1 && div_cnt == 'd0 && byte_cnt == 'd0 && trans_cnt == 'd0)
w_buf <= 8'b1010_1110;
else if(trans_flag == 1'b1 && div_cnt == 'd0 && byte_cnt == 'd1 && trans_cnt == 'd0 )
w_buf <= w_addr_buf[15:8];
else if(trans_flag == 1'b1 && div_cnt == 'd0 && byte_cnt == 'd2 && trans_cnt == 'd0)
w_buf <= w_addr_buf[7:0];
else if(r_en_n)
w_buf <= fifo_out;
else if(trans_flag == 1'b1 && div_cnt == 0)
w_buf <= {w_buf[6:0],1'b1};
//尽量用同一条件
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sda_w <= 1'd1;
else if(w_start == 1'b1 && div_cnt == DIV_CNT_3)
sda_w <= 1'b0;
else if(trans_flag == 1'b1 && div_cnt == 'd29 )
sda_w <= w_buf[7];
else if(trans_flag == 1'b1 && div_cnt == 'd209)
sda_w <= 1'd0;
else if(w_stop == 1'b1 && div_cnt == DIV_CNT_1)
sda_w <= 1'd1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sda_en <= 1'b1;
else if(div_cnt == DIV_CNT && trans_cnt == 4'd7)
sda_en <= 1'b0;
else if(div_cnt == DIV_CNT && trans_cnt == 4'd8)
sda_en <= 1'b1;
assign sda = (sda_en == 1)?sda_w:1'bz;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
data_trans_flag <= 1'b0;
else if(trans_flag == 1'b1 && div_cnt == 'd209 && byte_cnt == 'd2 && trans_cnt == 'd8)
data_trans_flag <= 1'b1;
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT && byte_cnt == 'd35 && trans_cnt == 'd8)
data_trans_flag <= 1'b0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
r_en <= 1'b0;
else if(trans_flag == 1'b1 && div_cnt == DIV_CNT && data_trans_flag == 1'b1 && trans_cnt == 'd8)
r_en <= 1'b1;
else
r_en <= 1'b0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
r_en_n = 1'b0;
else
r_en_n = r_en;
fifo_8x64 fifo_8x64_inst (
.clock ( sclk ),
.wrreq ( w_en ),
.data ( data ),
.rdreq ( r_en ),
.q ( fifo_out ),
.empty ( empty ),
.full ( full )
);
endmodule
仿真文件
`timescale 1ns/1ns
module iic_w_tb;
reg sclk;
reg rst_n;
reg w_en;
reg [15:0] addr;
reg [7:0] data;
wire scl;
wire sda;
initial begin
sclk = 0;
rst_n = 0;
#100
rst_n = 1;
end
always #10 sclk = ~sclk;
initial begin
addr = 'd0;
data = 'd0;
w_en = 1'b0;
#150
addr = 16'h5555;
iic_send();
end
iic_w iic_w_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.w_en (w_en ),
.data (data ),
.addr (addr ),
.scl (scl ),
.sda (sda )
);
task iic_send();
integer i;
begin
for(i = 0;i < 32 ;i = i + 1)
begin
@(posedge sclk)
w_en = 1;
data = i;
end
@(posedge sclk)
w_en = 0;
end
endtask
endmodule