iic接口 verilog

模块代码

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 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值