一.原理图
此开发板的24LC04芯片与之前所用的AT24C02芯片有所不同,此芯片的A2,A1,A0管脚为无效管脚,不能用于器件地址的选择!
二.IIC驱动及代码解释(i2c_dri.v)
由于黑金的代码是使用网上开源的代码,不易于理解,因此使用正点原子的代码进行解释。
IIC的驱动是使用状态机的方式进行编写。
由于iic驱动比较重要,因此单独拆开讲解。(此驱动只包含单字节读写,没有连续读写)
1.端口定义、I/O说明和变量声明
module i2c_dri
#(
parameter SLAVE_ADDR = 7'b1010000 , // slave address(器件地址),放此处方便参数传递
//下面两个参数用于后续对系统时钟分频从而获得I2C的SCL时钟
parameter CLK_FREQ = 26'd50_000_000, // i2c_dri模块的驱动时钟频率(CLK_FREQ),即50MHz系统时钟
parameter I2C_FREQ = 18'd250_000 // 需要的I2C的SCL时钟频率(250KHz)
)
(
//global clock
input clk , // i2c_dri模块的驱动时钟(CLK_FREQ),系统时钟50MHz
input sys_rst_n , // 复位信号
//i2c interface
input i2c_exec , // I2C触发执行信号,为1时代表开始和器件进行读或写
input bit_ctrl , // 器件内地址位控制(16b/8b),=1时16位,=0时8位,
// 对于EEPROM即为存储地址的位数
input i2c_rh_wl , // I2C读写控制信号,=1时读,=0时写,
input [15:0] i2c_addr , // I2C器件内地址,EEPROM即为芯片内部存储地址
input [ 7:0] i2c_data_w , // I2C要写的数据
output reg [ 7:0] i2c_data_r , // I2C读出的数据
output reg i2c_done , // I2C一次操作完成(读或写)
output reg scl , // I2C的SCL时钟信号线
inout sda , // I2C的SDA信号
//user interface
output reg dri_clk // 驱动I2C操作的驱动时钟
);
//localparam define,状态机的8种状态
localparam st_idle = 8'b0000_0001; // 空闲状态
localparam st_sladdr = 8'b0000_0010; // 发送器件地址(slave address)状态
localparam st_addr16 = 8'b0000_0100; // 发送16位字地址状态
localparam st_addr8 = 8'b0000_1000; // 发送8位字地址状态
localparam st_data_wr = 8'b0001_0000; // 写数据(8 bit)状态
localparam st_addr_rd = 8'b0010_0000; // 发送器件地址读状态
localparam st_data_rd = 8'b0100_0000; // 读数据(8 bit)状态
localparam st_stop = 8'b1000_0000; // 结束I2C操作状态
//reg define
reg sda_dir ; // I2C数据(SDA)方向控制,输出或高阻态(输入)
reg sda_out ; // SDA输出信号,暂存sda的输出
reg wr_flag ; // 写标志,暂存i2c_rh_wl输入
reg st_done ; // 当前状态结束标志
reg [ 6:0] cnt ; // 计数,后面代码出现时再解释
reg [ 7:0] cur_state ; // 状态机当前状态
reg [ 7:0] next_state ; // 状态机下一状态
reg [15:0] addr_t ; // 暂存器件内地址,即i2c_addr输入
reg [ 7:0] data_r ; // 暂存读取的数据,即i2c_data_r输出
reg [ 7:0] data_wr_t ; // 暂存写入的数据,即i2c_data_w输入
reg [ 9:0] clk_cnt ; // 分频时钟计数
//wire define
wire sda_in ; // SDA输入信号
wire [8:0] clk_divide ; // 模块驱动时钟的分频系数
2.SDA控制及IIC驱动时钟
代码中出现了三态门的使用,sda设置为高阻时,为输入模式。
详细请看:FPGA中的INOUT接口和高阻态
//SDA控制
assign sda = sda_dir ? sda_out : 1'bz; // SDA数据输出或高阻(输入)
assign sda_in = sda ; // SDA数据输入
assign clk_divide = (CLK_FREQ/I2C_FREQ) >> 2'd3;// 模块驱动时钟的分频系数,
// 50_000_000/250_000=200,200/2/4=25
// 由于除以8,此处的分频系数输出的实际为1MHz,原因见后面代码
//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作
always @(posedge clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
dri_clk <= 1'b1;
clk_cnt <= 10'd0;
end
else if(clk_cnt == clk_divide - 1'd1) begin
clk_cnt <= 10'd0;
dri_clk <= ~dri_clk; //此为1MHz,后面操作时还会再4分频
end
else
clk_cnt <= clk_cnt + 1'b1;
end
3.状态机
数据手册的说明:
程序状态图:
与上面的两个相对应。
//(三段式状态机)同步时序描述状态转移
always @(posedge dri_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
cur_state <= st_idle;
else
cur_state <= next_state;
end
//组合逻辑判断状态转移条件
always @( * ) begin
// next_state = st_idle;
case(cur_state)
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
default: next_state= st_idle;
endcase
end
4.时序图描述
//时序电路描述状态输出
always @(posedge dri_clk or negedge sys_rst_n) begin //1MHz的时钟频率触发
//复位初始化
if(sys_rst_n == 1'b0) begin
scl <= 1'b1;
sda_out <= 1'b1;
sda_dir <= 1'b1;
i2c_done <= 1'b0;
cnt <= 1'b0;
st_done <= 1'b0;
data_r <= 1'b0;
i2c_data_r <= 1'b0;
wr_flag <= 1'b0;
addr_t <= 1'b0;
data_wr_t <= 1'b0;
end
else begin
st_done <= 1'b0 ;
cnt <= cnt +1'b1 ; //计数自加,用于时序步骤递增
case(cur_state) //判断当前状态
st_idle: begin // 空闲状态
scl <= 1'b1; // IIC协议规定,时钟线和数据线均为高时,代表空闲
sda_out <= 1'b1;
sda_dir <= 1'b1; // sda为输出模式,
i2c_done<= 1'b0;
cnt <= 7'b0;
if(i2c_exec) begin
wr_flag <= i2c_rh_wl ; //读写信号
addr_t <= i2c_addr ; //I2C器件内地址
data_wr_t <= i2c_data_w; //需要写入的数据
end
end
st_sladdr: begin // 写器件地址和“写”信号
case(cnt)
7'd1 : sda_out <= 1'b0; // 开始I2C,参考IIC协议时序图
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= SLAVE_ADDR[6]; // 传送器件地址
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;//此处scl的高低电平变化为每4个时钟一个周期,即250KHz,因此跳过6
7'd8 : sda_out <= SLAVE_ADDR[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= SLAVE_ADDR[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= SLAVE_ADDR[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= SLAVE_ADDR[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= SLAVE_ADDR[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= SLAVE_ADDR[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: sda_out <= 1'b0; // 0:写
7'd33: scl <= 1'b1;
7'd35: scl <= 1'b0;
7'd36: begin
sda_dir <= 1'b0; // sda变为高阻态
sda_out <= 1'b1; // 拉高sda,等待从机应答
end
7'd37: scl <= 1'b1;
7'd38: st_done <= 1'b1; // 一个状态结束信号
7'd39: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr16: begin
case(cnt)
7'd0 : begin
sda_dir <= 1'b1 ;
sda_out <= addr_t[15]; // 传送内地址的高8位
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= addr_t[14];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= addr_t[13];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= addr_t[12];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= addr_t[11];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= addr_t[10];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= addr_t[9];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= addr_t[8];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr8: begin
case(cnt)
7'd0: begin
sda_dir <= 1'b1 ;
sda_out <= addr_t[7]; // 16位时传输内地址的低8位,8位时传送8位地址
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= addr_t[6];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= addr_t[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= addr_t[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= addr_t[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= addr_t[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= addr_t[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= addr_t[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_data_wr: begin // 写数据(8 bit)
case(cnt)
7'd0: begin
sda_out <= data_wr_t[7]; // I2C写8位数据
sda_dir <= 1'b1;
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= data_wr_t[6];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= data_wr_t[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= data_wr_t[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= data_wr_t[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= data_wr_t[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= data_wr_t[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= data_wr_t[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr_rd: begin // 写器件地址和“读”信号以进行读数据
case(cnt)
7'd0 : begin
sda_dir <= 1'b1;
sda_out <= 1'b1;
end
7'd1 : scl <= 1'b1;
7'd2 : sda_out <= 1'b0; // 重新开始
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= SLAVE_ADDR[6]; // 传送器件地址
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= SLAVE_ADDR[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= SLAVE_ADDR[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= SLAVE_ADDR[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= SLAVE_ADDR[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= SLAVE_ADDR[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= SLAVE_ADDR[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: sda_out <= 1'b1; // 1:读
7'd33: scl <= 1'b1;
7'd35: scl <= 1'b0;
7'd36: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd37: scl <= 1'b1;
7'd38: st_done <= 1'b1;
7'd39: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_data_rd: begin // 读取数据(8 bit)
case(cnt)
7'd0: sda_dir <= 1'b0; // sda高阻态,等待读数据
7'd1: begin
data_r[7] <= sda_in;
scl <= 1'b1;
end
7'd3: scl <= 1'b0;
7'd5: begin
data_r[6] <= sda_in ;
scl <= 1'b1 ;
end
7'd7: scl <= 1'b0;
7'd9: begin
data_r[5] <= sda_in;
scl <= 1'b1 ;
end
7'd11: scl <= 1'b0;
7'd13: begin
data_r[4] <= sda_in;
scl <= 1'b1 ;
end
7'd15: scl <= 1'b0;
7'd17: begin
data_r[3] <= sda_in;
scl <= 1'b1 ;
end
7'd19: scl <= 1'b0;
7'd21: begin
data_r[2] <= sda_in;
scl <= 1'b1 ;
end
7'd23: scl <= 1'b0;
7'd25: begin
data_r[1] <= sda_in;
scl <= 1'b1 ;
end
7'd27: scl <= 1'b0;
7'd29: begin
data_r[0] <= sda_in;
scl <= 1'b1 ;
end
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b1; // sda输出,将由主机给出是否应答
sda_out <= 1'b1; // 主机将sda拉高,表示非应答,结束本次读取
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
i2c_data_r <= data_r;
end
default : ;
endcase
end
st_stop: begin // 结束I2C操作
case(cnt)
7'd0: begin
sda_dir <= 1'b1; // 结束I2C
sda_out <= 1'b0;
end
7'd1 : scl <= 1'b1;
7'd3 : sda_out <= 1'b1;
7'd15: st_done <= 1'b1;
7'd16: begin
cnt <= 1'b0;
i2c_done <= 1'b1; // 向上层模块传递I2C结束信号
end
default : ;
endcase
end
endcase
end
end
endmodule
三.其余模块
实验效果:led灯先闪烁几秒,然后保持常亮,说明读写正确。如果一直闪烁说明读写有误。
顶层结构图:
1.EEPROM_rw.v
此模块先向EEPROM写入数据,然后读出,并进行对比,如果不同则输出错误信号,LED闪烁。
module EEPROM_rw
(
input clk,
input sys_rst_n,
output i2c_rh_wl, //读/写标志
output reg i2c_exec, //I2C触发信号
output reg [15:0] i2c_addr, //器件内地址
output reg [7:0] i2c_data_w, //写入的数据字节
input [7:0] i2c_data_r, //读出的数据字节
input i2c_done, //操作结束标记
output reg error_flag //错误信号
);
parameter WAIT = 14'd5000; //等待时间
parameter BYTE_N = 16'd255; //共写入256个字节,从0开始
reg addr_over ; // 地址结束标志
reg rom_w_done; // 一个字节全部写入e2prom的标志
reg [ 1:0] flow_cnt ; // 状态流控制
reg [13:0] wait_cnt ; // 等待计数
assign i2c_rh_wl = addr_over & rom_w_done; //所有字节都以写入eeprom(地址结束且最后一个字节结束)
always @(posedge clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
begin
i2c_addr <= 16'd0;
addr_over <= 1'b0;
end
else if(i2c_done == 1'b1) //I2C的一次操作完成
begin
if(i2c_rh_wl == 1'b1) //如果开始读数据
begin
if(i2c_addr < BYTE_N)
i2c_addr <= i2c_addr + 1'b1;
else
i2c_addr <= i2c_addr;
end
else //还没有写完数据
begin
if(i2c_addr == BYTE_N)
begin
i2c_addr <= 16'd0;
addr_over <= 1'b1; //地址结束,
end
else
i2c_addr <= i2c_addr + 1'd1;
end
end
else
i2c_addr <= i2c_addr;
end
always @(posedge clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
flow_cnt <= 2'b0;
wait_cnt <= 14'b0;
i2c_exec <= 1'b0;
i2c_data_w <= 8'd0;
rom_w_done <= 1'b0;
error_flag <= 1'b1;
end
else begin
i2c_exec <= 1'b0;
//从eeprom的第1页的第1个字节到第8页的第32个字节(共256字节)写入数据0~255
if(i2c_rh_wl == 1'b0) begin //写数据
case(flow_cnt)
2'd0: begin
rom_w_done <= 1'b0;
wait_cnt <= wait_cnt + 1'b1;
if(wait_cnt == 14'd100) begin //等待100*0.02=2us
wait_cnt <= 14'd0;
flow_cnt <= flow_cnt + 1'b1;
end
end
2'd1: begin
i2c_exec <= 1'b1; //触发I2C
i2c_data_w <= i2c_addr[7:0]; //需要写入的数据为当前写入数据的内地址
flow_cnt <= flow_cnt + 1'b1;
end
2'd2: begin
if(i2c_done == 1'b1) //I2C操作已经结束
flow_cnt <= flow_cnt + 1'b1;
end
2'd3:begin
if(wait_cnt == WAIT) begin //写间隔控制,5000*0.02us=1ms
flow_cnt <= 2'b0;
wait_cnt <= 14'd0;
rom_w_done <= 1'b1; //一个字节完成写入
end
else
wait_cnt <= wait_cnt + 1'b1;
end
endcase
end
//读取从eeprom的第1页的第1个字节开始的共256字节的值并判断值是否正确
else begin //读数据
case(flow_cnt)
2'd0: begin
wait_cnt <= wait_cnt + 1'b1;
if(wait_cnt == 14'd100) begin //2us
flow_cnt <= flow_cnt + 1'b1;
wait_cnt <= 14'd0;
end
end
2'd1: begin
i2c_exec <= 1'b1;
flow_cnt <= flow_cnt + 1'b1;
end
2'd2: begin
if(i2c_done == 1'b1) begin // 判断I2C操作是否完成
if(i2c_addr[7:0] == i2c_data_r) begin // 判断读到的值正确与否(读到的值等于当前地址)
error_flag <= 1'b0; // 读到的值正确
flow_cnt <= 2'b0; // 返回状态0
end
else begin
error_flag <= 1'b1; // 读到的值错误
end
end
end
default: flow_cnt <= 2'b0;
endcase
end
end
end
endmodule
3.led_alarm.v
module led_alarm
#(
parameter L_TIME = 25'd25_000_000 // 控制led闪烁时间(此为500ms)
)
(
//system clock
input clk , // 时钟信号
input rst_n , // 复位信号
//led interface
output [3:0] led , // LED 灯
//user interface
input error_flag // 错误标志
);
//reg define
reg led_t ; // 使用的led灯
reg [24:0] led_cnt; // led计数
//led输出
assign led = {4{led_t}};
//错误标志为1时led闪烁,否则,LED0常亮
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
led_cnt <= 25'd0;
led_t <= 1'b0;
end
else begin
if(error_flag) begin // 读到的值错误
led_cnt <= led_cnt + 25'd1;
if(led_cnt == L_TIME) begin // 数据错误时LED灯每隔L_TIME时间闪烁一次
led_cnt <= 25'd0;
led_t <= ~led_t;
end
end
else begin // 读完且读到的值正确
led_cnt <= 25'd0;
led_t <= 1'b1; // led灯常亮
end
end
end
endmodule
4.I2C_EEPROM_test.v
此芯片的器件地址:
高四位由器件固定为“1010”,第3、2位无效,第1位选择存储块,第0位为读写控制。
module I2C_EEPROM_test(
//system clock
input sys_clk , // 系统时钟
input sys_rst_n , // 系统复位
//eeprom interface
output rom_scl , // eeprom的时钟线scl
inout rom_sda , // eeprom的数据线sda
//user interface
output [3:0] led // led显示
);
//parameter define
parameter SLAVE_ADDR = 7'b1010000 ; // 器件地址(SLAVE_ADDR)
parameter BIT_CTRL = 1'b0 ; // 字地址位控制参数(16b/8b)
parameter CLK_FREQ = 26'd50_000_000; // i2c_dri模块的驱动时钟频率(CLK_FREQ)
parameter I2C_FREQ = 18'd250_000 ; // I2C的SCL时钟频率
parameter L_TIME = 17'd125_000 ; // led闪烁时间参数
//wire define
wire clk ; // I2C操作时钟
wire i2c_exec ; // i2c触发控制
wire [15:0] i2c_addr ; // i2c操作地址
wire [ 7:0] i2c_data_w; // i2c写入的数据
wire i2c_done ; // i2c操作结束标志
wire i2c_rh_wl ; // i2c读写控制
wire [ 7:0] i2c_data_r; // i2c读出的数据
wire error_flag; // 错误标志
//例化e2prom读写模块
EEPROM_rw u_eeprom_rw(
//global clock
.clk (clk ), // 时钟信号
.sys_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一次操作完成
//user interface
.error_flag (error_flag) // 错误标志
);
//例化i2c_dri
i2c_dri #(
.SLAVE_ADDR (SLAVE_ADDR), // slave address从机地址,放此处方便参数传递
.CLK_FREQ (CLK_FREQ ), // i2c_dri模块的驱动时钟频率(CLK_FREQ)
.I2C_FREQ (I2C_FREQ ) // I2C的SCL时钟频率
) u_i2c_dri(
//global clock
.clk (sys_clk ), // i2c_dri模块的驱动时钟(CLK_FREQ)
.sys_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 ), // I 2C一次操作完成
.scl (rom_scl ), // I2C的SCL时钟信号
.sda (rom_sda ), // I2C的SDA信号
//user interface
.dri_clk (clk ) // I2C操作时钟
);
//例化led_alarm模块
led_alarm #(.L_TIME(L_TIME ) // 控制led闪烁时间
) u_led_alarm(
//system clock
.clk (clk ), // 时钟信号
.rst_n (sys_rst_n ), // 复位信号
//led interface
.led (led ), // LED 灯
//user interface
.error_flag (error_flag) // 错误标志
);
endmodule