IIC
由两根线组成,I2C_SCL是串行时钟线,I2C_SDA是串行数据线,一般采用开漏模式于总线项链,所以需接上上拉电阻。
整体时序
1.空闲模式
I2C_SDA和I2C_SCL由于上拉的原因,处于高电平状态
2.起始信号
I2C_SCL为高电平时将 I2C_SDA 线拉低,产生一个起始信号
3.数据传输状态
4.停止信号
I2C_SCL 为高电平时,I2C_ SDA 从低电平跳变到高电平
IIC读写时序
单次写
连续写
连续写和单次写的区别在于在发送完一个地址位的时候发送几个数据
随机读
(写还分为读当前地,连续读当前地址,连续读随机地址,但使用这些方式会导致代码适应范围少)
IIC读写实验
顶层文件
module top_e2prom( input sys_clk , //系统时钟 input sys_rst_n , //系统复位 //eeprom interface output iic_scl , //eeprom的时钟线scl inout iic_sda , //eeprom的数据线sda );
//e2prom读写测试模块 e2prom_rw #( .MAX_BYTE (MAX_BYTE ) //读写测试的字节个数 ) u_e2prom_rw( .clk (dri_clk ), //时钟信号 .rst_n (sys_rst_n ), //复位信号 //i2c interface .i2c_exec (i2c_exec ), //I2C触发执行信号 .i2c_rh_wl (i2c_rh_wl ), //I2C读写控制信号 .i2c_addr (i2c_addr ), //I2C器件内地址 .i2c_data_w (i2c_data_w), //I2C要写的数据 .i2c_data_r (i2c_data_r), //I2C读出的数据 .i2c_done (i2c_done ), //I2C一次操作完成 .i2c_ack (i2c_ack ), //I2C应答标志 //user interface .rw_done (rw_done ), //E2PROM读写测试完成 .rw_result (rw_result ) //E2PROM读写测试结果 0:失败 1:成功 ); //i2c驱动模块 i2c_dri #( .SLAVE_ADDR (SLAVE_ADDR), //EEPROM从机地址 .CLK_FREQ (CLK_FREQ ), //模块输入的时钟频率 .I2C_FREQ (I2C_FREQ ) //IIC_SCL的时钟频率 ) u_i2c_dri( .clk (sys_clk ), .rst_n (sys_rst_n ), //i2c interface .i2c_exec (i2c_exec ), //I2C触发执行信号 .bit_ctrl (BIT_CTRL ), //器件地址位控制(16b/8b) .i2c_rh_wl (i2c_rh_wl ), //I2C读写控制信号 .i2c_addr (i2c_addr ), //I2C器件内地址 .i2c_data_w (i2c_data_w), //I2C要写的数据 .i2c_data_r (i2c_data_r), //I2C读出的数据 .i2c_done (i2c_done ), //I2C一次操作完成 .i2c_ack (i2c_ack ), //I2C应答标志 .scl (iic_scl ), //I2C的SCL时钟信号 .sda (iic_sda ), //I2C的SDA信号 //user interface .dri_clk (dri_clk ) //I2C操作时钟 );
IIC驱动模块
(最重要的模块)
module i2c_dri #( parameter SLAVE_ADDR = 7'b1010000 , //EEPROM从机地址 parameter CLK_FREQ = 26'd50_000_000, //模块输入的时钟频率 parameter I2C_FREQ = 18'd250_000 //IIC_SCL的时钟频率 ) ( input clk , input rst_n , //i2c interface input i2c_exec , //I2C触发执行信号 input bit_ctrl , //字地址位控制(16b/8b) input i2c_rh_wl , //I2C读写控制信号 input [15:0] i2c_addr , //I2C器件内地址 input [ 7:0] i2c_data_w , //I2C要写的数据 output reg [ 7:0] i2c_data_r , //I2C读出的数据 output reg i2c_done , //I2C一次操作完成 output reg i2c_ack , //I2C应答标志 0:应答 1:未应答 output reg scl , //I2C的SCL时钟信号 inout sda , //I2C的SDA信号 //user interface output reg dri_clk //驱动I2C操作的驱动时钟 );
E2PROM读写测试
module e2prom_rw( input clk , //时钟信号 input rst_n , //复位信号 //i2c interface output reg i2c_rh_wl , //I2C读写控制信号 output reg i2c_exec , //I2C触发执行信号 output reg [15:0] i2c_addr , //I2C器件内地址 output reg [ 7:0] i2c_data_w , //I2C要写的数据 input [ 7:0] i2c_data_r , //I2C读出的数据 input i2c_done , //I2C一次操作完成 input i2c_ack , //I2C应答标志 );
移植代码介绍:
读写一体化的组合逻辑时序,通过控制st_data_wr和st_addr_rd信号来操控是需要都还是写
st_idle: begin //空闲状态 if(i2c_exec) begin next_state = st_sladdr; end else next_state = st_idle; end st_sladdr: begin if(st_done) begin if(bit_ctrl) //判断是16位还是8位字地址 next_state = st_addr16; else next_state = st_addr8 ; end else next_state = st_sladdr; end st_addr16: begin //写16位字地址 if(st_done) begin next_state = st_addr8; end else begin next_state = st_addr16; end end st_addr8: begin //8位字地址 if(st_done) begin if(wr_flag==1'b0) //读写判断 next_state = st_data_wr; else next_state = st_addr_rd; end else begin next_state = st_addr8; end end st_data_wr: begin //写数据(8 bit) if(st_done) next_state = st_stop; else next_state = st_data_wr; end st_addr_rd: begin //写地址以进行读数据 if(st_done) begin next_state = st_data_rd; end else begin next_state = st_addr_rd; end end st_data_rd: begin //读取数据(8 bit) if(st_done) next_state = st_stop; else next_state = st_data_rd; end st_stop: begin //结束I2C操作 if(st_done) next_state = st_idle; else next_state = st_stop ; end
通过写两个个.v文件来传递要读数据的地址和数据和要写的数据地址
再通过一个.v文件来控制是还是写