FPGA上实现IIC读写EEPROM

FPGA上实现IIC读写EEPROM

1、IIC协议简介

IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。I²C的正确读法为“I平方C”(“I-squared-C”),而“I二C”(“I-two-C”)则是另一种错误但被广泛使用的读法。自2006年10月1日起,使用I²C协议已经不需要支付专利费,但制造商仍然需要付费以获取I²C从属设备地址。
IIC协议的起始和结束条件如下图所示:
在这里插入图片描述

2、IIC协议读过程

在这里插入图片描述
这里给出的是针对某个地址的单次读,IIC也有连续读的,就是顺着当前地址一直读下去,不过我个人觉得那种方式用的不多,还是针对某个地址读的方式用的多。

IIC协议写过程

在这里插入图片描述
IIC写过程,也是有连续写的,但是这里只给出针对某个地址写的,单次写数据,也是用的较多的。

FPGA实现IIC读写EEPROM

主要代码:

module iic_rw_test(
	input				clk,
	input				rst_n,
	input				iic_done,
	input		[7:0]	data_read,
	
	output	reg			exc_iic,
	output	reg			iic_rw_ctl,
	output		[7:0]	data_write,
	output	reg	[7:0]	addr,
	output	reg			error
);

reg		[2:0]	cnt_fsm;
reg		[2:0]	cnt;
reg		[9:0]	wait_cnt;

always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		exc_iic <= 1'b0;
//		iic_rw_ctl <= 1'b0;
//		data_write <= 8'd0;
//		addr <= 8'd0;
		cnt_fsm <= 3'd0;
		cnt <= 3'd0;
		wait_cnt <= 10'd0;
	end
	else begin
		if(iic_rw_ctl == 1'b0) begin
			case(cnt_fsm)
				3'd0:begin
					if(cnt == 3'd3) begin
						cnt_fsm <= cnt_fsm + 1'b1;
						cnt <= 3'd0;
					end
					else begin
						cnt <= cnt + 1'b1;
						cnt_fsm <= cnt_fsm;
					end
				end
				3'd1:begin
					exc_iic <= 1'b1;
					cnt_fsm <= cnt_fsm + 1'b1;
				end
				3'd2:begin
					exc_iic <= 1'b0;
					if(iic_done == 1'b1) begin
						cnt_fsm <= cnt_fsm + 1'b1;
					end
					else begin
						cnt_fsm <= cnt_fsm;
					end	
				end
				3'd3:begin
					if(wait_cnt == 10'd500) begin
						cnt_fsm <= 3'd0;
						wait_cnt <= 10'd0;
					end
					else begin
						cnt_fsm <= cnt_fsm;
						wait_cnt <= wait_cnt + 1'b1;
					end
				end
				default: ;
			endcase
		end
		else begin
			case(cnt_fsm)
				3'd0:begin
					if(cnt == 3'd3) begin
						cnt_fsm <= cnt_fsm + 1'b1;
						cnt <= 3'd0;
					end
					else begin
						cnt <= cnt + 1'b1;
						cnt_fsm <= cnt_fsm;
					end
				end
				3'd1:begin
					exc_iic <= 1'b1;
					cnt_fsm <= cnt_fsm + 1'b1;
				end
				3'd2:begin
					exc_iic <= 1'b0;
					if(iic_done == 1'b1) begin
						cnt_fsm <= cnt_fsm + 1'b1;
					end
					else begin
						cnt_fsm <= cnt_fsm;
					end	
				end
				3'd3:begin
					if(wait_cnt == 10'd500) begin
						cnt_fsm <= 3'd0;
						wait_cnt <= 10'd0;
					end
					else begin
						cnt_fsm <= cnt_fsm;
						wait_cnt <= wait_cnt + 1'b1;
					end
				end
				default: ;
			endcase
		end
	end
end

always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		iic_rw_ctl <= 1'b0;
		error <= 1'b0;
		addr <= 8'd0;
	end
	else begin
		if(iic_done == 1'b1) begin
			if(iic_rw_ctl == 1'b0) begin
				if(addr <255) begin
					addr <= addr + 1'b1;
				end
				else begin
					addr <= 8'd0;
					iic_rw_ctl <= 1'b1;
				end
			end
			else begin
				if(addr <255) begin
					addr <= addr + 1'b1;
					if(addr == data_read) begin
						error <= 1'b0;
					end
					else begin
						error <= 1'b1;
					end
				end
				else begin
					addr <= 8'd0;
				end
			end
		end
		else begin
			addr <= addr;
			iic_rw_ctl <= iic_rw_ctl;
		end
	end
end

assign data_write = addr;

endmodule 

如果需要整个工程可以点击这里下载。

猜你喜欢

转载自blog.csdn.net/qq_36662353/article/details/103846151