FPGA驱动24C04实现读写操作,提供工程源码和技术支持

时间:2022-12-17 14:53:21

1.24c04芯片手册解读

24c04芯片手册很简单,原理图设计页很简单,这里只说代码设计需要注意的点:
1、写操作延时周期大于等于2ms,如下:
FPGA驱动24C04实现读写操作,提供工程源码和技术支持
这个其实也很好理解,这毕竟是写一次数据就可以保存200年的东西,你写操作难道不应该多花点时间让期间“固化”完毕吗?
具体在代码层面如何体现呢?
那就是写完一次数据后要求等待至少2ms后才能发起下一次写操作,本设计采用延时4ms的稳妥方案;
2、器件地址,如下:
FPGA驱动24C04实现读写操作,提供工程源码和技术支持
常规操作,3个地址引脚的电平决定器件地址,我的板子原理图如下:
FPGA驱动24C04实现读写操作,提供工程源码和技术支持
所以器件地址就是7’b1010000;也就是0xa0;
3、穿行时钟,如下:
FPGA驱动24C04实现读写操作,提供工程源码和技术支持
100k到400k,用100k最保险,宜小不宜大;本设计也是用的100k;

2.纯verilog的i2c驱动

详细代码不在这里给出,因为粘贴出来会很长,影响阅读体验,私我可得源码慢慢欣赏;
下面给出i2c驱动的顶层接口说明:


rst               //高电平复位
clk               //输入系统时钟
clk_div_cnt       //i2c_scl分配系数:clk_div_cnt=clk/(5*i2c_scl)-1
scl_pad_i         // SCL-line input
scl_pad_o         // SCL-line output (always 1'b0)
scl_padoen_o      // SCL-line output enable (active low)                           
sda_pad_i         // SDA-line input
sda_pad_o         // SDA-line output (always 1'b0)
sda_padoen_o      // SDA-line output enable (active low)
i2c_addr_2byte    // 地址位宽选择:1-->16bit ? 0-->8bit
i2c_read_req      // 发起读操作,高电平有效
i2c_read_req_ack  // 读操作完成反馈高脉冲信号
i2c_write_req     // 发写读操作,高电平有效
i2c_write_req_ack // 写操作完成反馈高脉冲信号
i2c_slave_dev_addr// I2c device address
i2c_slave_reg_addr// I2c register address
i2c_write_data    // I2c write register data
i2c_read_data     // I2c read register data
error             // 读写错误反馈信号

3.24c04读写状态机设计

设计很简单,分为一下几步:
1:上电等待250ms,让24c04准备好;
2:发起一次写操作,并给出写地址和写数据;
3:完成写操作后,写地址和写数据累加,并循环写255次;
4:写完255个数据后,发起读操作,并给出读地址;
5:完成读操作后,读地址累加,并循环读255次;
6:读完255个数据后,再从第一步开始循环;
状态机部分代码如下:

always @(posedge clk) begin
	if(~rstn) begin
		ST                <='d0;
		i2c_read_req      <='d0;
		i2c_write_req     <='d0;
		i2c_slave_reg_addr<='d0;
		w_slave_reg_addr  <='d0;
		r_slave_reg_addr  <='d0;
		i2c_write_data    <='d0;
		write_data_cnt    <='d0;
		read_data_cnt     <='d0;
		r_i2c_write_data  <='d0;
		e2p_cnt           <='d0;
	end
	else begin
		case(ST)
			'd0: begin
				if(e2p_cnt==E2P_DELAY) begin	//上电后延时250ms,让24c04准备好
					ST<='d1;
					e2p_cnt<='d0;
				end
				else e2p_cnt<=e2p_cnt+'d1;
			end
			'd1: begin	
				if(i2c_write_req_ack) begin		//写操作完成,进入等待写周期和地址、数据累加
					i2c_write_req<='d0;
					ST<='d2;
				end
				else begin
					i2c_write_req<='d1;						//发起写操作
					i2c_write_data<=r_i2c_write_data;		//给出写数据
					i2c_slave_reg_addr<=w_slave_reg_addr;	//给出写地址
				end
			end
			'd2: begin	
				if(write_data_cnt=='d255) begin		//写满255个数据后进入读数据状态
					write_data_cnt    <='d0;
					i2c_write_data    <='d0;
					r_i2c_write_data  <='d0;
					w_slave_reg_addr  <='d0;
					i2c_slave_reg_addr<='d0;
					ST<='d4;
				end
				else begin
					if(wr_delay==WR_CYCEL) begin	//延时4ms写周期,写数据和地址累加
						write_data_cnt  <=write_data_cnt+'d1;
						r_i2c_write_data<=r_i2c_write_data+'d1;
						w_slave_reg_addr<=w_slave_reg_addr+'d1;	
						ST<='d3;
					end
				end
			end
			'd3: ST<='d1;	//打一排再循环写,保证写数据和地址在发起写操作前已经更新
			'd4: begin	
				if(i2c_read_req_ack) begin
					i2c_read_req<='d0;
					ST<='d5;
				end
				else begin
					i2c_read_req<='d1;						//发起读操作
					i2c_slave_reg_addr<=r_slave_reg_addr;	//给出读地址
				end					
			end
			'd5: begin	
				if(read_data_cnt=='d255) begin	//读完255个数据后重新开始状态机
					read_data_cnt  <='d0;
					r_slave_reg_addr<='d0;
					i2c_slave_reg_addr<='d0;
					ST<='d0;
				end
				else begin
					read_data_cnt  <=read_data_cnt+'d1;			
					r_slave_reg_addr  <=r_slave_reg_addr+'d1;	//读地址累加
				    ST<='d6;
				end
			end	
			'd6: ST<='d4;
			default: ST<='d0;
		endcase
	end
end

4.上板调试验证

开发板:Xilinx Artix7-35T开发板;
开发环境:vivado2019.1;
ila抓取波形如下:
写操作:
随机抓取写地址为100的波形,此时写地址为100,写数据也应该为100;抓取结果如下:
FPGA驱动24C04实现读写操作,提供工程源码和技术支持
再抓读地址为100时的波形,此时读数据也应该是100才对,抓取结果如下:
FPGA驱动24C04实现读写操作,提供工程源码和技术支持
可以看到,当读反馈信号i2c_read_req_ack为高时,地址为100,读数据也为100;
我们的读写完全正确。。。

5.福利:工程源码获取

福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
资料如下:获取方式:私。
FPGA驱动24C04实现读写操作,提供工程源码和技术支持