欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IIC协议的Verilog代码(1)——主机写模块开发

程序员文章站 2024-02-22 21:39:10
...

Verilog代码

//Module Name:IIC Write
//Author:Yang Cheng Yu
//Date:2020/4/21
//==================defines=====================
`define SIM
module	iic_write(
	//================System Signal================
	input				clk				,
	input				rst_n			,
	//================Interface====================
	output	reg 		scl				,
	inout 				sda				,
	output reg 			flag_wr			,
	input				wr_req			,
	output	reg 		flag_wr_done	,
	input[6:0]			dev_addr		,
	input[7:0]			data_wr			,
	output reg[5:0]		state			
);
	//================parameters===================
	parameter			SYS_FRE				=50_000_000;
	parameter			IIC_FRE				=10_000;
	`ifndef SIM
	localparam			CNT_BAUD			=SYS_FRE/IIC_FRE;
	localparam			CNT_BAUD_HALF		=CNT_BAUD/2;
	`else
	localparam			CNT_BAUD 			= 500;
	localparam			CNT_BAUD_HALF 		= 250;
	`endif
	//state machine
	localparam			S_IDLE				=6'b0000_01;
	localparam			S_START				=6'b0000_10;
	localparam			S_DEV_ADDR			=6'b0001_00;
	localparam			S_ACK_DEV_ADDR		=6'b0010_00;
	localparam			S_DATA				=6'b0100_00;
	localparam			S_ACK_DATA			=6'b1000_00;
	//================System regs==================
	reg[15:0]			cnt_baud;
	reg[2:0]			cnt_bit;
	wire				flag_bit;
	reg 				flag_start_bit;
	reg 				SDA;
	reg 				wr_req_t0;
	reg 				wr_req_t1;
	wire 				wr_req_trig;
	reg 				flag_get_ack;
	reg[6:0]			dev_addr_reg;
	reg[7:0]			data_wr_reg;
	//================Main Codes===================
	//scl
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			scl <= 1'b1;
		else if(flag_start_bit==1'b1&&flag_wr==1'b1)
			scl <= 1'b1;
		else if(flag_start_bit==1'b0&&flag_wr==1'b1)
			if(cnt_baud<=CNT_BAUD_HALF-1)
				scl <= 1'b0;
			else if(cnt_baud>CNT_BAUD_HALF-1)
				scl <= 1'b1;
		else
			scl <= 1'b1;
	end
	
	//flag_wr
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			flag_wr <= 1'b0;
		else if(flag_wr==1'b0&&wr_req_trig==1'b1)
			flag_wr <= 1'b1;
		else if(state==S_ACK_DATA&&flag_bit==1'b1)
			flag_wr <= 1'b0;
	end
	
	//sda	
	assign sda = (state==S_ACK_DATA||state==S_ACK_DEV_ADDR)?1'bz:SDA;
	//cnt_baud
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			cnt_baud <= 'd0;
		else if(flag_start_bit==1'b1&&flag_wr==1'b1)
			if(cnt_baud==CNT_BAUD_HALF-1)
				cnt_baud <= 'd0;
			else
				cnt_baud <= cnt_baud + 1'b1;
		else if(flag_start_bit==1'b0&&flag_wr==1'b1)
			if(cnt_baud==CNT_BAUD-1)
				cnt_baud <= 'd0;
			else
				cnt_baud <= cnt_baud + 1'b1;
		else
			cnt_baud <= 'd0;
	end
	
	//cnt_bit
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			cnt_bit <= 'd0;
		else case(state)
			S_IDLE:cnt_bit <= 'd0;		
			S_START:cnt_bit <= 'd0;
			S_DEV_ADDR:begin
				if(cnt_bit==3'd7&&flag_bit==1'b1)
					cnt_bit <= 'd0;
				else if(flag_bit==1'b1)
					cnt_bit <= cnt_bit + 1'b1;
			end
			S_ACK_DEV_ADDR:cnt_bit <= 'd0;
			S_DATA:begin
				if(cnt_bit==3'd7&&flag_bit==1'b1)
					cnt_bit <= 'd0;
				else if(flag_bit==1'b1)
					cnt_bit <= cnt_bit + 1'b1;
			end
			S_ACK_DATA:cnt_bit <= 'd0;
		endcase
	end
	
	//flag_bit
	assign flag_bit = (cnt_baud==CNT_BAUD-1)?1'b1:1'b0;
	//flag_start_bit
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			flag_start_bit <= 1'b0;
		else if(flag_wr==1'b0&&wr_req_trig==1'b1)
			flag_start_bit <= 1'b1;
		else if(flag_start_bit==1'b1&&cnt_baud==CNT_BAUD_HALF-1)
			flag_start_bit <= 1'b0;
	end
	
	//state machine
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			state <= S_IDLE;
		else case(state)
			S_IDLE:begin
				if(wr_req_trig==1'b1)
					state <= S_START;
				else
					state <= S_IDLE;
			end
			S_START:begin
				if(cnt_baud==CNT_BAUD_HALF-1)
					state <= S_DEV_ADDR;
				else
					state <= S_START;
			end
			S_DEV_ADDR:begin
				if(cnt_bit==3'd7&&flag_bit==1'b1)
					state <= S_ACK_DEV_ADDR;
				else
					state <= S_DEV_ADDR;
			end
			S_ACK_DEV_ADDR:begin
				if(cnt_baud<CNT_BAUD-1&&flag_get_ack==1'b0)
					state <= S_ACK_DEV_ADDR;
				else if(cnt_baud==CNT_BAUD-1&&flag_get_ack==1'b1)
					state <= S_DATA;
				else if(cnt_baud==CNT_BAUD-1&&flag_get_ack==1'b0)
					state <= S_IDLE;
			end
			S_DATA:begin
				if(cnt_bit==3'd7&&flag_bit==1'b1)
					state <= S_ACK_DATA;
				else
					state <= S_DATA;
			end
			S_ACK_DATA:begin
				if(cnt_baud==CNT_BAUD-1)
					state <= S_IDLE;
				else
					state <= S_ACK_DATA;
			end
			default:state <= S_IDLE;
		endcase
	end
	
	//SDA
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			SDA <= 1'b1;
		else case(state)
			S_IDLE:SDA <= 1'b1;
			S_START:SDA <= 1'b0;
			S_DEV_ADDR:begin
				if(cnt_baud==CNT_BAUD_HALF/2-1)
					case(cnt_bit)
						0:SDA <= dev_addr_reg[6];
						1:SDA <= dev_addr_reg[5];
						2:SDA <= dev_addr_reg[4];
						3:SDA <= dev_addr_reg[3];
						4:SDA <= dev_addr_reg[2];
						5:SDA <= dev_addr_reg[1];
						6:SDA <= dev_addr_reg[0];
						7:SDA <= 1'b1;
						default:SDA <= 1'b1;
					endcase
			end
			S_ACK_DEV_ADDR:SDA <= 1'b1;
			S_DATA:begin
				if(cnt_baud==CNT_BAUD_HALF/2-1)
					case(cnt_bit)
						0:SDA <= data_wr_reg[7];
						1:SDA <= data_wr_reg[6];
						2:SDA <= data_wr_reg[5];
						3:SDA <= data_wr_reg[4];
						4:SDA <= data_wr_reg[3];
						5:SDA <= data_wr_reg[2];
						6:SDA <= data_wr_reg[1];
						7:SDA <= data_wr_reg[0];
						default:SDA <= 1'b1;
					endcase
			end
			S_ACK_DATA:SDA <= 1'b1;
			default:SDA <= 1'b1;
		endcase
	end
	
	//wr_req and wr_req_trig
	always	@(posedge clk)begin
		wr_req_t0 <= wr_req;
		wr_req_t1 <= wr_req_t0;
	end
	assign	wr_req_trig = wr_req_t0&(~wr_req_t1);
	//flag_get_ack
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			flag_get_ack <= 1'b0;
		else case(state)
			S_ACK_DEV_ADDR:begin
				if(cnt_baud==CNT_BAUD_HALF+CNT_BAUD_HALF/2-2&&sda==1'b1)
					flag_get_ack <= 1'b1;
			end
			S_ACK_DATA:begin
				if(cnt_baud==CNT_BAUD_HALF+CNT_BAUD_HALF/2-2&&sda==1'b1)
					flag_get_ack <= 1'b1;				
			end
			default:flag_get_ack <= 1'b0;
		endcase
	end
	
	//flag_wr_done
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			flag_wr_done <= 1'b0;
		else if(state==S_ACK_DATA&&flag_get_ack==1'b1)
			flag_wr_done <= 1'b1;
		else
			flag_wr_done <= 1'b0;
	end
	
	//dev_addr_reg
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			dev_addr_reg <= 'd0;
		else if(flag_wr==1'b0&&wr_req_trig==1'b1)
			dev_addr_reg <= dev_addr;
	end
	
	//data_wr_reg
	always	@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)
			data_wr_reg <= 'd0;
		else if(flag_wr==1'b0&&wr_req_trig==1'b1)
			data_wr_reg <= data_wr;
	end
	
endmodule

Test Bench

`timescale	1ns/1ns		//时间精度
`define clock_period 20	//时钟周期
module tb_iic_write;	//实体名称
	//state machine
	localparam			S_IDLE				=6'b0000_01;
	localparam			S_START				=6'b0000_10;
	localparam			S_DEV_ADDR			=6'b0001_00;
	localparam			S_ACK_DEV_ADDR		=6'b0010_00;
	localparam			S_DATA				=6'b0100_00;
	localparam			S_ACK_DATA			=6'b1000_00;
//=====================<系统端口>=============================
	reg				clk				;
	reg				rst_n			;

//=====================<外设端口>=============================
	wire	 		scl				;
	wire 			sda				;
	wire  			flag_wr			;
	reg				wr_req			;
	wire	 		flag_wr_done	;
	reg[6:0]		dev_addr		;
	reg[7:0]		data_wr			;
	wire[5:0]		state			;
	assign	sda = (state==S_ACK_DATA||state==S_ACK_DEV_ADDR)?1'b1:1'bz;
	


iic_write iic_write_inst(
	//================System Signal================
	.clk				(clk),
	.rst_n				(rst_n),
	//================Interface====================
	.scl				(scl),
	.sda				(sda),
	.flag_wr			(flag_wr),
	.wr_req				(wr_req),
	.flag_wr_done		(flag_wr_done),
	.dev_addr			(dev_addr),
	.data_wr			(data_wr),
	.state				(state)
);
//=====================<时钟信号>=============================
initial begin
	clk = 1;
	forever
		#(`clock_period/2)	clk = ~clk;
end

//=====================<复位信号>=============================
initial begin
	rst_n = 0;#(`clock_period*20+1);
	rst_n = 1;
end

//=====================<激励信号>=============================
initial begin
	dev_addr = 7'b011_0101;
	data_wr  = 8'h00;
	wr_req	 = 0;
	#(`clock_period*20+1);//初始化
	data_wr = 8'h56;
	#20;
	wr_req = 1;
	#20;
	wr_req = 0;
	#20_0000;
	data_wr = 8'h78;
	dev_addr = 7'b100_1010;
	#20;
	wr_req = 1;
	#20;
	wr_req = 0;
end	

endmodule

波形图

IIC协议的Verilog代码(1)——主机写模块开发