FPGA IIC 协议 UART读写EEPROM存储器系统

FPGA IIC 协议

主控芯片不能设置SDA高电平,能用高阻态,外部上拉电阻拉上去。可以直接设置高电平。

三态门

在这里插入图片描述
oe为0:
开关断开作为输入,i2c_id=i2c_SDA ;
oe为1:
若od为1,做输出,高阻态,外部上拉电阻拉高。
若od为0,做输出,输出为低电平。

在这里插入图片描述

I2C 协议起始位: SCL 为高电平时, SDA 出现下降沿,产生一个起始位;
I2C 协议结束位: SCL 为高电平时, SDA 出现上升沿,产生一个结束位;

I2C器件地址,I2C存储器地址

当主机像从机写入数据时,SDA 上的每一位数据在 SCL 的高电平期间被写入从机中。从主机角度来看,需要在 SCL 低电平期间改变要写入的数据。
而当主机读取从机中数据时,从机在 SCL 低电平期间将数据输出到 SDA总线上,在 SCL 的高电平期间保持数据稳定,从主机角度来看,需要在SCL 的高电平期间将 SDA 线上的数据读取并存储。
不管对于从机还是主机, SDA 上的每一位数据在 SCL 的高电平期间保持不变,而数据的改变总是在 SCL 的低电平期间发生。

SDA 上的每一位数据在 SCL 的高电平期间保持不变,而数据的改变总是在SCL 的低电平期间发生。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

嘎嘎嘎
I2C_CLK高低电平计数器计数。高电平开始计数。

状态图

![在这里插入图片描述](https://img-blog.csdnimg.cn/041ab674ece644868f30c71553a5067b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiN5oOz56eD5Y-R,size_20,color_FFFFFF,t_70,g_se,x_16

IIC文件

module IIC(
	Clk,
	Rst_n,
	Wr,
	Read,
	Wdata_num,
	Rdata_num,
	Address_num,
	Device_adress,
	Word_adrr,
	Wr_data,
	
	Rd_data,
	Wr_data_vaule,
	Rd_data_vaule,
	Done,
	Sda,
	Iic_clk
);
	input Clk;
	input Rst_n;
	input Wr;
	input Read;
	input [5:0]Wdata_num; //连续写数据存储单元个数
	input [5:0]Rdata_num; //连续读存储单元个数
	input [1:0]Address_num; //单字节/双字节地址段选择
	
	input [2:0]Device_adress; //器件片选地址
	input [15:0]Word_adrr; //存储单元地址
	
	input [7:0]Wr_data;//写入的数据
	
	output reg[7:0]Rd_data;//读出的数据
	output Wr_data_vaule;//读数据有效标志信号
	output reg Rd_data_vaule;//写数据有效标志信号
	inout  Sda;
	output reg Done;
	output reg Iic_clk;
	
	parameter CLK_FREQUENCY = 50_000_000;
	parameter IIC_CLK_FREQUENCY = 400_000; //I2c clk时钟频率400KHZ
	localparam COUNT_MAX = CLK_FREQUENCY/IIC_CLK_FREQUENCY;
	//独热码
	localparam IDLE      =  9'b000_000_001, 
              WR_START  =  9'b000_000_010,      
				  WR_CTRL   =  9'b000_000_100,//写控制 写器件地址
				  WR_ADDRE  =  9'b000_001_000,//写地址
				  WR_DATA   =  9'b000_010_000,//写数据
			     RD_START  =  9'b000_100_000,//读开始
				  RD_CTRL   =  9'b001_000_000,//读控制
				  RD_DATA   =  9'b010_000_000,//读数据 
				  STOP      =  9'b100_000_000;
			
	reg iic_free_n;//i2c空闲标志位,低电平有效
	wire [7:0]waddress_data;//器件地址数据写
	wire [7:0]raddress_data;//器件地址数据读
	reg [7:0]iic_count; //产生i2C_CLK信号计数寄存器
	reg iic_high; 
	reg iic_low;
	reg [4:0]half_clk_cnt;//计数一个状态中高低电平计数器
	reg [8:0]main_state;//主状态机状态寄存器
	reg ack;//数据接收方对发送方的响应标志位
	reg send_en;//控制Sda线输入输出开关
	reg sda_reg;//sda信号线寄存器
	reg task_en_n;//任务开始结束控制寄存器
	reg [7:0]sda_data_out;//sda待输出的数据
	reg [7:0]sda_data_in;//sda待写入的数据
	reg [5:0]wdata_cnt;//连续写个数计数器
	reg [5:0]rdata_cnt;//连续读个数计数器
	reg [1:0]adress_cnt;//器件地址个数计数器 1/2
	wire be_rd_data_vaule;//读数据有效前寄存器
	reg w_flag;
	reg r_flag;

	//写/读器件地址8位
	assign waddress_data = {4'b1010 , Device_adress , 1'b0};
	assign raddress_data = {4'b1010 , Device_adress , 1'b1};
	
	assign Sda = send_en?sda_reg:1'bz;
	
	//iic_free_n状态判断
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	iic_free_n <= 1'b0;
	else	if(Wr|Read)
	iic_free_n <= 1'b1;
	else	if(Done)
	iic_free_n <= 1'b0;
	else 
	iic_free_n <= iic_free_n;
	
	//iic_count计数
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	iic_count <= 1'b0;
	else	if(iic_free_n)
	begin
		if(iic_count == COUNT_MAX - 1'b1)
		iic_count <= 1'b0;
		else 
		iic_count <= iic_count + 1'b1;
	end
	else 
	iic_count <= 1'b0;
	
	//Iic_clk产生
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	Iic_clk <= 1'b1;
	else if(iic_count == COUNT_MAX >> 1)
		Iic_clk <= 1'b0;
   else if(iic_count == 1'b0)
		Iic_clk <= 1'b1;
	else
	Iic_clk <= Iic_clk;
	
	//标志Iic_clk高电平 iic_high产生
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	iic_high <= 1'b0;
	else if(iic_count == (COUNT_MAX >> 2) )
	iic_high <= 1'b1;
	else 
	iic_high <= 1'b0;

	//标志Iic_clk低电平 iic_low产生
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	iic_low <= 1'b0;
	else if(iic_count == (COUNT_MAX >> 2 )+ (COUNT_MAX >> 1) )
	iic_low <= 1'b1;
	else 
	iic_low <= 1'b0;

	//sda串行收发Iic_clk高低电平计数器
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	half_clk_cnt <= 5'b0;
	else 
	if((main_state == WR_CTRL) || (main_state ==WR_ADDRE)|| (main_state ==WR_DATA) || (main_state ==RD_CTRL) ||(main_state ==RD_DATA))
	begin
		if(iic_high || iic_low)
		begin
			if(half_clk_cnt == 5'd17)
			half_clk_cnt <= 5'b0;		
			else 
			half_clk_cnt <= half_clk_cnt + 1'b1;
		end
	   else
		half_clk_cnt <= half_clk_cnt;
	end
	else 
	half_clk_cnt <= 1'b0;
	
	//数据接收方对发送方的响应标志位ACK
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	ack <= 1'b0;
	else 
	if((half_clk_cnt == 5'd16) && iic_high && (Sda == 1'b0))
	ack <= 1'b1;
	else 
	if(half_clk_cnt == 5'd17 && iic_low)
	ack <= 1'b0;
	else 
	ack <= ack;
	
	//输出串行数据任务
	task send_eight_data;
	if(iic_high && (half_clk_cnt == 5'd16))
		task_en_n <= 1'b1;
	else
	if(half_clk_cnt < 5'd17)
	begin
		sda_reg <= sda_data_out[7];
		if(iic_low)
		sda_data_out <= {sda_data_out[6:0],1'b0};
		else
		sda_data_out <= sda_data_out;
	end
	endtask
	
	//输入串行任务
	task get_eight_data;
	if(iic_low && (half_clk_cnt == 5'd15))
		task_en_n <= 1'b1;
	else 
		if(half_clk_cnt < 5'd15)
		begin
			if(iic_high)
			sda_data_in <= {sda_data_in[6:0],Sda};
			else 
			sda_data_in <= sda_data_in;
		end
	endtask
	
	
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	begin
		sda_reg <= 1'b1; 
		wdata_cnt <= 1'b1;
	   rdata_cnt <= 1'b1;
		adress_cnt <= 1'b1;
		Done <= 1'b0;
		w_flag <= 1'b0;
		r_flag <= 1'b0;
	end
	else 
	begin
		case(main_state)
		
		IDLE :
		begin
		sda_reg <= 1'b1;
		rdata_cnt <= 1'b1;
		wdata_cnt <= 1'b1;
		adress_cnt <=1'b1;
		w_flag <= 1'b0;
		r_flag <= 1'b0;
		Done <= 1'b0;
			if(Wr)
			begin
			main_state <= WR_START;
			w_flag <= 1'b1;
			end
			else if(Read)
			begin
			main_state <= WR_START;
			r_flag <= 1'b1;
			end
		end
		
		WR_START: //10
		begin
		if(iic_low)
			begin
			main_state <= WR_CTRL;
			sda_data_out <= waddress_data;
			task_en_n <= 1'b0;
			end
		else if(iic_high)
			begin
			sda_reg <= 1'b0;
			main_state <= WR_START;
			end
		else
			main_state <= WR_START;
		end
		
		WR_CTRL: //100
		begin
		if(task_en_n == 1'b0)
		send_eight_data;
		else
		if(ack == 1'b1)
			begin
			if(iic_low)
				begin
				main_state <= WR_ADDRE;
				task_en_n <= 1'b0;
				if(adress_cnt == Address_num) 
				sda_data_out <= Word_adrr[7:0];
				else 
				sda_data_out <= Word_adrr[15:8];
				end
			else 
			main_state <= WR_CTRL;
			end
		else 
		main_state <= IDLE;
		end
		
		WR_ADDRE:  //1000
		begin
		if(task_en_n == 1'b0)
		send_eight_data;
		else 
			if(ack == 1'b1)
			begin
				if(adress_cnt == Address_num)
				begin
					if(iic_low && w_flag)
					begin
					main_state <= WR_DATA;
					adress_cnt <= 1'b1;
					task_en_n <= 1'b0;
					sda_data_out <= Wr_data;
					end
					else 
					if(iic_low && r_flag)
					begin
					main_state <= RD_START;
					sda_reg <= 1'b1;
					end
					else 
					main_state <= WR_ADDRE;
				end
				else 
				begin
				main_state <= WR_ADDRE;
				sda_data_out <= Word_adrr[7:0];
				task_en_n <= 1'b0;
				adress_cnt <= adress_cnt + 1'b1;
				end
			end
			else
			main_state <= IDLE;
		end
		
		WR_DATA: //10_000
		begin
		if(task_en_n == 1'b0)
		send_eight_data;
		else 
			if(ack == 1'b1)
			begin
				if(wdata_cnt == Wdata_num)
				begin
					if(iic_low)
					begin
					wdata_cnt <= 1'b1;
					main_state <= STOP;
					sda_reg <= 1'b0; //上升沿停止
					end
					else 
					main_state <= WR_DATA;
				end
				else 
				if(iic_low)
				begin
				wdata_cnt <= wdata_cnt + 1'b1;
				main_state <= WR_DATA;
				sda_data_out <= Wr_data;
				task_en_n <= 1'b0;
				end
				else 
				main_state <= WR_DATA;
			end
			else 
			main_state <= IDLE;
		end
			
		RD_START:
		begin
			if(iic_low)
			begin
			main_state <= RD_CTRL;
			task_en_n <= 1'b0;
			sda_data_out <= raddress_data;
			end
			else 
			if(iic_high)
			begin
			main_state <= RD_START;
			sda_reg <= 1'b0;
			end
			else 
			main_state <= RD_START;
		end
			
		RD_CTRL:
		begin
			if(task_en_n == 1'b0)
			send_eight_data;
			else 
			if(ack == 1'b1)
			begin
				if(iic_low)
				begin
				main_state <= RD_DATA;
				task_en_n <= 1'b0;
				end
				else 
				main_state <= RD_CTRL;
			end
			else 
			main_state <= IDLE;
		end
		
		RD_DATA:
		begin
			if(task_en_n == 1'b0)
			get_eight_data;
			else 
			if(rdata_cnt == Rdata_num)
			begin
			sda_reg <= 1'b1; //产生NOack信号表示不读
				if(iic_low)
				begin
				main_state <= STOP;
				sda_reg <= 1'b0; //产生上升沿停止位
				end
				else 
				main_state <= RD_DATA;
			end
			else 
			begin
			sda_reg <= 1'b0; //产生ack信表示再读
				if(iic_low)
				begin
				main_state <= RD_DATA;
				rdata_cnt <= rdata_cnt + 1'b1;
				task_en_n <= 1'b0;
				end
				else 
				main_state <= RD_DATA;
			end
		end
		
		STOP:
		begin
			if(iic_high)
			begin
			sda_reg <= 1'b1; //产生上升沿停止态
			main_state <= IDLE;
			Done <= 1'b1;
			end
			else 
			main_state <= STOP;		
		end
		
		

		default : main_state <= IDLE;
		endcase
	end
	
		//控制sda开关闭合关闭
	always @(*)  //描述组合逻辑电路
	begin
		case(main_state)
		IDLE:
		send_en = 1'b0;
		
		RD_START,WR_START,STOP:  //写/读开始 停止位
		send_en = 1'b1;		
		
		RD_CTRL,WR_CTRL,WR_ADDRE,WR_DATA:
		if(half_clk_cnt < 16)
		send_en = 1'b1;
		else 
		send_en = 1'b0;
		
		RD_DATA:
		if(half_clk_cnt < 16)
		send_en = 1'b0;
		else 
		send_en = 1'b1;
		
		default:send_en = 1'b0;
		endcase
	
	end
	
	//写输入有效标志位
	assign Wr_data_vaule = ((main_state == WR_ADDRE) && (w_flag && iic_low) && (ack == 1'b1) && (adress_cnt == Address_num))||((main_state == WR_DATA) && (ack == 1'b1) && (iic_low)&&(wdata_cnt != Wdata_num));
	
	//读数据有效标志位前寄存器
	assign be_rd_data_vaule = ((main_state == RD_DATA) && (half_clk_cnt == 5'd15) && (iic_low));
	
	//读数据有效标志位
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	Rd_data_vaule <= 1'b0;
	else if(be_rd_data_vaule)
	Rd_data_vaule <= 1'b1;
	else 
	Rd_data_vaule <= 1'b0;
	
	//读出的有效数据
	always @(posedge Clk or negedge Rst_n)
	if(!Rst_n)
	Rd_data <= 8'd0;
	else if(be_rd_data_vaule)
	Rd_data <= sda_data_in;
	else 
	Rd_data <= Rd_data;
	
endmodule 

IIC仿真文件

`timescale 1ns/1ns
`define CLK_CYCLE 20

//`define TEST_M24LC64 //24LC64   1字节存储器地址
`define TEST_M24LC04 //24LC04B  2字节存储器地址
module IIC_tb;

localparam NUM = 6'd4; //连续读写数据个数

	reg Clk;
	reg Rst_n;
	reg Wr;
	reg Read;
	reg [15:0]Word_adrr;
	reg [7:0]Wr_data;
	
	wire [7:0]Rd_data;
	wire Wr_data_vaule;
	wire Rd_data_vaule;
	wire Done;
	wire Sda;
	wire Iic_clk;

`ifdef TEST_M24LC64
	localparam  Device_adress = 3'b000;//器件地址
	localparam 	Address_num = 2'd2;  //存储器地址字节数
`elsif TEST_M24LC04
	localparam  Device_adress = 3'b001;
	localparam 	Address_num = 2'd1;
`endif

IIC IIC(
	.Clk(Clk),
	.Rst_n(Rst_n),
	.Wr(Wr),
	.Read(Read),
	.Wdata_num(NUM),
	.Rdata_num(NUM),
	.Address_num(Address_num),
	.Device_adress(Device_adress),
	.Word_adrr(Word_adrr),
	.Wr_data(Wr_data),
	
	.Rd_data(Rd_data),
	.Wr_data_vaule(Wr_data_vaule),
	.Rd_data_vaule(Rd_data_vaule),
	.Done(Done),
	.Sda(Sda),
	.Iic_clk(Iic_clk)
);

`ifdef TEST_M24LC64
M24LC64 M24LC64(
	.A0(1'b0),
	.A1(1'b0),
	.A2(1'b0),
	.WP(1'b0),
	.SDA(Sda),
	.SCL(Iic_clk),
	.RESET(!Rst_n)
	);
`elsif TEST_M24LC04
M24LC04B M24LC04(
	.A0(1'b1),
	.A1(1'b0),
	.A2(1'b0),
	.WP(1'b0),
	.SDA(Sda),
	.SCL(Iic_clk),
	.RESET(!Rst_n)
	);
`endif

initial Clk = 1;
always #(`CLK_CYCLE/2) Clk = ~Clk;

initial
begin
	Rst_n = 0;
	Wr = 0;
   Read = 0;
	Word_adrr = 0;
	Wr_data = 0;
	#(`CLK_CYCLE*200 + 1);
	Rst_n = 1;
	#200;
	
`ifdef  TEST_M24LC64//仿真24LC64模型
	Word_adrr = 0;
	Wr_data = 0;
	repeat(20)
	begin
	Wr = 1'b1;
	#(`CLK_CYCLE);
	Wr = 1'b0;
		repeat(NUM)
		begin
		@(posedge Wr_data_vaule)
		Wr_data = Wr_data + 1;
		end
	@(posedge Done)
	#1000;
	Word_adrr = Word_adrr + NUM; 
	end
	#2000;
	//读出数据
	Word_adrr = 0;
	repeat(20)
	begin
	Read = 1'b1;
	#(`CLK_CYCLE);
	Read = 1'b0;
	@(posedge Done)
	#1000;
	Word_adrr = Word_adrr + NUM; //?????
	end
	
`elsif TEST_M24LC04
	Word_adrr = 100;
	Wr_data = 100;
	repeat(20)
	begin
	Wr = 1;
	#(`CLK_CYCLE);
	Wr = 0;
		repeat(NUM)
		begin
		@(posedge Wr_data_vaule)
		Wr_data = Wr_data + 1;
		end
	@(posedge Done);
	#1000;
	Word_adrr = Word_adrr + NUM; 
	end
	#2000;
	//读出数据
	Word_adrr = 100;
	repeat(20)
	begin
	Read = 1;
	#(`CLK_CYCLE);
	Read = 0;
	@(posedge Done);
	#1000;
	Word_adrr = Word_adrr + NUM; 
	end	
`endif

	#4000;

	$stop;
end 

endmodule 

在这里插入图片描述
仿真结果第一个读取的数据为01100101,刚好是十进制数101也是第一个存储的数据。

UART串口读写EEPROM存储器任意地址数据

编写RX接收数据分析模块

规定电脑端发送的数据格式为请添加图片描述
其中,器件地址包括器件的地址字节数和 3 位的器件地址,具体分配如图所示。请添加图片描述
使用左移循环动态判断数据的帧头,判断功能码(功能码为0xf1 表示写数据操作,0xf2 表示读数据操作)。

module DATA_ANALYSIS(
	Clk,
	Rst_n
	Rx_data,
	Rx_done,
	
	Wfifo_reg,
	Wfifo_data,
	Rdata_num,
	Wdata_num,
	Address_num,
	Device_address,
	Word_adrr,
	Rd, //EEPROM读请求信号
	);
	
input	Clk;
input	Rst_n;
input	[7:0]Rx_data;
input	Rx_done;
	
output  	Wfifo_reg;
output  	[7:0]Wfifo_data;
output  	[5:0]Rdata_num;
output  	[5:0]Wdata_num;
output  	[1:0]Address_num;
output  	[2:0]Device_address;
output  	[7:0]Word_adrr;
output  	Rd; //EEPROM读请求信号
reg 		[7:0]an_cnt;//串口数据接收个数计数器
reg[7:0] buff_data[5:0];
reg analysis_done;

//串口接收数据计数器
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
an_cnt <= 8'd0;
else 
if((an_cnt==8'd4)&&Rx_done)
begin
	if(buff_data[1] == 8'hf2)//读操作命令
	an_cnt <= 8'd0;
	else 
	if(buff_data[1] == 8'hf1)//写操作命令
	an_cnt <= an_cnt + 1'b1;
	else 
	an_cnt <= 1'b0; //错误指令
end
else 
if(Rx_done)
begin
	if(an_cnt == (8'd4 + buff_data[4]))
	an_cnt <= 8'd0;
	else 
	an_cnt <= an_cnt + 1'b1;
end
else an_cnt <= an_cnt ;

//串口缓冲寄存器
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
buff_data[0] <= 8'd0;
buff_data[1] <= 8'd0;
buff_data[2] <= 8'd0;
buff_data[3] <= 8'd0;
buff_data[4] <= 8'd0;
end
else 
if((an_cnt < 8'd5) && Rx_done)
buff_data[an_cnt] <= Rx_data;
else ;

//WFIFO写请求使能信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Wfifo_reg <= 1'b0;
else 
if((an_cnt > 8'd4)&& Rx_done)
Wfifo_reg <= 1'b1;
else 
Wfifo_reg <= 1'b0;

//WFIFO写入的数据
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Wfifo_data <= 1'b0;
else 
if((an_cnt > 8'd4)&& Rx_done)
Wfifo_data <= Rx_data;
else 
Wfifo_data <= Wfifo_data;

//IIC读使能信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rd <= 1'b0;
else 
if((an_cnt == 8'd4) && (buff_data[1] == 8'hf2) && Rx_done)
Rd <= 1'b1;
else 
Rd <= 1'b0;

//指令完成标志
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
analysis_done <= 1'b0;
else 
if((an_cnt == 8'd4)&& Rx_done)
analysis_done <= 1'd1;
else 
analysis_done <= 1'd0;
 
//EEPROM存储器地址
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
Rdata_num <= 1'b0;
Wdata_num <= 1'b0;
Address_num <= 1'b0;
Device_address <= 3'b0;
Word_adrr <= 16'b0;
end
else 
if(analysis_done == 1'b1)
begin
Rdata_num <= buff_data[4][5:0];
Wdata_num <= buff_data[4][5:0];
Address_num <= buff_data[0][5:4];
Device_address <= buff_data[0][2:0];
Word_adrr <= {buff_data[2],buff_data[3]};
end
else 
;
endmodule 

串口读写EEPROM系统设计

在这里插入图片描述

编写系统文件
module UART_EEPROM(
	Clk,
	Rst_n,
	Rx,
	
	Tx,
	Iic_clk,
	Sda
);

input	Clk;
input	Rst_n;
input	Rx;
output Tx;
output Iic_clk;
inout Sda;

parameter BPS_SET = 3'd4;


wire [7:0]rx_data;
wire Done_rx;
wire  Wfifo_reg;
wire  [7:0]wfifo_data;
wire  [5:0]rdata_num;//连续读存储单元个数
wire  [5:0]wdata_num;//连续写数据存储单元个数
wire  [1:0]address_num;//单字节/双字节地址段选择
wire  [2:0]device_address;//器件片选地址
wire  [15:0]word_adrr;//存储单元地址
wire  rd; //EEPROM读请求信号
wire	[7:0]q_wfifo;
wire  [7:0]q_rfifo;
wire	[5:0]wfifo_usedw;

wire wr;
wire [7:0]rd_data;//读出的数据
wire wr_data_vaule;//写数据有效标志信号
wire rd_data_vaule;//读数据有效标志信号
wire done;
wire en_tx;
wire [6:0]rfifo_usedw;
wire rfifo_req;
wire done_tx;

uart_data_rx uart_data_rx(  //串口接收模块
  .Clk(Clk),
  .Rst_n(Rst_n),
  .Rs232_rx(Rx),
  .Bps_set(BPS_SET),
  .Data_out(rx_data),
  .Rx_done(Done_rx)
);

DATA_ANALYSIS DATA_ANALYSIS(
	.Clk(Clk),
	.Rst_n(Rst_n),
	.Rx_data(rx_data),
	.Rx_done(Done_rx),
	
	.Wfifo_reg(Wfifo_reg),
	.Wfifo_data(wfifo_data),
	.Rdata_num(rdata_num),
	.Wdata_num(wdata_num),
	.Address_num(address_num),
	.Device_address(device_address),
	.Word_adrr(word_adrr),
	.Rd(rd) //EEPROM读请求信号
	);	
	

	
	//写缓存FIFO
Wfifo Wfifo(
	.clock(Clk),
	.data(wfifo_data),
	.rdreq(wr_data_vaule),
	.wrreq(Wfifo_reg),
	.empty(),
	.full(),
	.q(q_wfifo),
	.usedw(wfifo_usedw)
	);

assign wr = ((wdata_num == wfifo_usedw) && (wfifo_usedw != 1'b0)); 
	//IIC 
IIC IIC(
	.Clk(Clk),
	.Rst_n(Rst_n),
	.Wr(wr),
	.Read(rd),
	.Wdata_num(wdata_num),
	.Rdata_num(rdata_num),
	.Address_num(address_num),
	.Device_adress(device_address),
	.Word_adrr(word_adrr),
	.Wr_data(q_wfifo),
	
	.Rd_data(rd_data),
	.Wr_data_vaule(wr_data_vaule),
	.Rd_data_vaule(rd_data_vaule),
	.Done(done),
	.Sda(Sda),
	.Iic_clk(Iic_clk)
);



	//读FIFO
Rfifo Rfifo(
	.clock(Clk),
	.data(rd_data),
	.rdreq(rfifo_req),
	.wrreq(rd_data_vaule),
	.empty(),
	.full(),
	.q(q_rfifo),
	.usedw(rfifo_usedw)
	);
	//串口发送使能
assign en_tx = ((rdata_num == rfifo_usedw) && done) ||  ((rdata_num > rfifo_usedw) && (rfifo_usedw > 1'b0)&& done_tx );
	//读FIFO使能
assign rfifo_req = en_tx; 
	//tx模组
UART_TX UART_TX(
    .Clk(Clk),
	 .Rst_n(Rst_n),
	 .Bps_set(BPS_SET),
	 .Con_en(en_tx),
	 .Data_in(q_rfifo),
	 
	 .Rs232_tx(Tx),
	 .Done_tx(done_tx),
	 .Uart_state()
  );



endmodule
 
编写系统仿真文件tb
`timescale 1ns/1ns
`define Clk_period 20
module UART_EEPROM_tb;

localparam  DEV_ADDRESS =  3'b000; //器件地址
localparam  BPS_SET =  3'd4;		 //波特率
localparam  ADDRESS_NUM = 2'd2; 

reg Clk;
reg Rst_n;
wire rx;
wire tx;
wire iic_clk;
wire sda;
reg con_en;
reg [7:0]data_in_tx;
wire done_tx;
reg [15:0]addr;
reg [7:0]data_num;
reg [39:0]wdata_cmd;
reg [39:0]rdata_cmd;
reg [7:0]tx_data;
	//数据发送TX
UART_TX UART_TX(
    .Clk(Clk),
	 .Rst_n(Rst_n),
	 .Bps_set(BPS_SET),
	 .Con_en(con_en),
	 .Data_in(tx_data),
	 .Rs232_tx(rx),
	 .Done_tx(done_tx),
	 .Uart_state()
  );



 UART_EEPROM #(.BPS_SET(BPS_SET))
 UART_EEPROM(
	.Clk(Clk),
	.Rst_n(Rst_n),
	.Rx(rx),
	
	.Tx(tx),
	.Iic_clk(iic_clk),
	.Sda(sda)
);

	//EEPROM模型例化
M24LC64 M24LC64(
		.A0(1'b0), 
		.A1(1'b0), 
		.A2(1'b0), 
		.WP(1'b0), 
		.SDA(sda), 
		.SCL(iic_clk), 
		.RESET(!Rst_n)
	);

initial Clk = 1;
always #(`Clk_period/2) Clk = ~Clk;

initial
begin
Rst_n = 0;
addr = 0;
data_num = 0;
wdata_cmd = 0;
rdata_cmd = 0;
con_en = 0;
data_in_tx = 0;
tx_data = 0;
#(`Clk_period*20 + 1);
Rst_n = 1;
#200;

addr= 0;
data_num = 4;
data_in_tx = 0;
send_write_bite;
@(posedge UART_EEPROM.IIC.Done);
#500;
send_read_bite;
@(posedge UART_EEPROM.IIC.Done);
#500;

addr= 0;
data_num = 8;
data_in_tx = 20;
send_write_bite;
@(posedge UART_EEPROM.IIC.Done);
#300;
send_read_bite;
@(posedge UART_EEPROM.IIC.Done);

repeat (data_num)
begin
@(posedge UART_EEPROM.done_tx);
end
#500;

$stop;
end

task send_write_bite;
begin
wdata_cmd = {{2'b00,ADDRESS_NUM,1'b0,DEV_ADDRESS},8'hf1,addr[15:8],addr[7:0],data_num};    
	//传入待写入的命令数据
repeat(5)
	begin
	tx_data = wdata_cmd[39:32];
	con_en = 1;
	#(`Clk_period)
	con_en = 0;
	@(posedge done_tx)
	#100;
	wdata_cmd = {wdata_cmd[31:0],8'h00};
	end
	//数据
tx_data = data_in_tx;
repeat(data_num)
	begin
	con_en = 1;
	tx_data = tx_data + 1'b1;
	#(`Clk_period)
	con_en = 0;
	@(posedge done_tx)
	#200;
	end
end
endtask


task  send_read_bite;
begin
rdata_cmd = {{2'b00,ADDRESS_NUM,1'b0,DEV_ADDRESS},8'hf2,addr[15:8],addr[7:0],data_num}; 
repeat(5)
	begin
	tx_data = rdata_cmd[39:32];
	con_en = 1;
	#(`Clk_period)
	con_en = 0;	
	@(posedge done_tx)
	#100;	
	rdata_cmd = {rdata_cmd[31:0],8'h00};
	end
end
endtask

endmodule

仿真波形

在这里插入图片描述

tx信号成功输出。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA 读写i2c_eeprom_Verilog逻辑源码Quartus工程文件+文档说明,EEPROM 型号24LC04,,FPGA型号Cyclone4E系列中的EP4CE6F17C8,Quartus版本17.1。 module i2c_eeprom_test( input clk, input rst_n, input key1, inout i2c_sda, inout i2c_scl, output [5:0] seg_sel, output [7:0] seg_data ); localparam S_IDLE = 0; localparam S_READ = 1; localparam S_WAIT = 2; localparam S_WRITE = 3; reg[3:0] state; wire button_negedge; reg[7:0] read_data; reg[31:0] timer; wire scl_pad_i; wire scl_pad_o; wire scl_padoen_o; wire sda_pad_i; wire sda_pad_o; wire sda_padoen_o; reg[ 7:0] i2c_slave_dev_addr; reg[15:0] i2c_slave_reg_addr; reg[ 7:0] i2c_write_data; reg i2c_read_req; wire i2c_read_req_ack; reg i2c_write_req; wire i2c_write_req_ack; wire[7:0] i2c_read_data; ax_debounce ax_debounce_m0 ( .clk (clk), .rst (~rst_n), .button_in (key1), .button_posedge (), .button_negedge (button_negedge), .button_out () ); wire[6:0] seg_data_0; seg_decoder seg_decoder_m0( .bin_data (read_data[3:0]), .seg_data (seg_data_0) ); wire[6:0] seg_data_1; seg_decoder seg_decoder_m1( .bin_data (read_data[7:4]), .seg_data (seg_data_1) ); seg_scan seg_scan_m0( .clk (clk), .rst_n (rst_n), .seg_sel (seg_sel), .seg_data (seg_data), .seg_data_0 ({1'b1,7'b1111_111}), .seg_data_1 ({1'b1,7'b1111_111}), .seg_data_2 ({1'b1,7'b1111_111}), .seg_data_3 ({1'b1,7'b1111_111}), .seg_data_4 ({1'b1,seg_data_1}), .seg_data_5 ({1'b1,seg_data_0}) ); always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin state <= S_IDLE; i2c_write_req <= 1'b0; read_data <= 8'h00; timer <= 32'd0; i2c_write_data <= 8'd0; i2c_slave_reg_addr <= 16'd0; i2c_slave_dev_addr <= 8'ha0;//1010 000 0(default address ‘000’ write operation) i2c_read_req <= 1'b0; en
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值