源码地址:http://www.opencores.org/projects/i2c/
时序图在线绘制工具:https://wavedrom.com/
绘图工具:https://app.diagrams.net/
1 框架结构

i2c_master_top


- 读的时候多写了一次设备地址S_RD_DEV_ADDR1,与第一次不同的是,地址的最低位是1,表示读
- S_WR_ERR_NACK:写了S_WR_DEV_ADDR、S_RD_DEV_ADDR0,却没有ACK
- start:S_WR_DEV_ADDR、S_RD_DEV_ADDR0、S_RD_DEV_ADDR1
- stop:S_WR_STOP、S_RD_STOP
- read:S_RD_DATA
- write:S_WR_DEV_ADDR -> S_WR_DATA,S_RD_DEV_ADDR0 -> S_RD_REG_ADDR1
- i2c_al:仲裁失败(arbitrament lose),The stop signal is detected but no signal is requested.The host setting SDA is high,Actual SDA is low
- done:决定状态跳转
i2c_master_byte_ctrl

八位并行转串行
always @(posedge clk or negedge nReset)
begin
if (!nReset) // asynchronous reset
sr <= #1 8'h0; //the"#"just for modelsim,it's not used when Analysis & Synthesis
else if (rst==1) // synchronous reset
sr <= #1 8'h0;
else if (ld) // load data
sr <= #1 din; // write data to sda
else if (shift)
sr <= #1 {sr[6:0], core_rxd}; // read data from sda
end
八位计数器
always @(posedge clk or negedge nReset)
begin
if (!nReset)
dcnt <= #1 3'h0;
else if (rst)
dcnt <= #1 3'h0;
else if (ld)
dcnt <= #1 3'h7;
else if (shift)
dcnt <= #1 dcnt - 3'h1;
end
assign cnt_done = ~(|dcnt);
- core_ack:更新大条件
- cnt_done:更新小条件,更新8位后可进入下一状态
- core_cmd:更新操作:I2C_CMD_NOP、I2C_CMD_START、I2C_CMD_STOP、I2C_CMD_WRITE、I2C_CMD_READ
- cmd-ack:i2c_master_top中的done,决定状态跳转
i2c_master_bit_ctrl
对串行后的每一位进行输出,每一位的输出可分成5个阶段(a、b、c、d、i),start多了一个e,其中i是idle

开始,读写,停止的时序如下:

start
stop
read
read里的SDA是高阻态,不是1,这样slave可以控制SDA,输出数据给master
write
- 每个都是5个状态,所以它更新的频率是5 * fSCL,如果fSCL=100Khz,sys_clk=50,那么clk_div=99
- start是开始,所以多了个e,e过后是i,但这个i其实是后面那个状态(read,write)的
信号前处理
SDA、SCL的数据并没有直接用,而是经历了很多filter
Capture
always @(posedge clk or negedge nReset)
begin
if (!nReset)
begin
cSCL <= #1 2'b00;
cSDA <= #1 2'b00;
end
else if (rst)
begin
cSCL <= #1 2'b00;
cSDA <= #1 2'b00;
end
else
begin
cSCL <= {cSCL[0],scl_i};
cSDA <= {cSDA[0],sda_i};
end
end
Filter
always @(posedge clk or negedge nReset)//fSCL is the Operation control clock
begin
if(!nReset)
begin
fSCL <= 3'b111;
fSDA <= 3'b111;
end
else if (rst)
begin
fSCL <= 3'b111;
fSDA <= 3'b111;
end
else if (~|filter_cnt)
begin
fSCL <= {fSCL[1:0],cSCL[1]};
fSDA <= {fSDA[1:0],cSDA[1]};
end
end
- filter_cnt频率是fSCL频率的四倍
Synchronized、Delayed
always @(posedge clk or negedge nReset)
begin
if (~nReset)
begin
sSCL <= #1 1'b1;
sSDA <= #1 1'b1;
dSCL <= #1 1'b1;
dSDA <= #1 1'b1;
end
else if (rst)
begin
sSCL <= #1 1'b1;
sSDA <= #1 1'b1;
dSCL <= #1 1'b1;
dSDA <= #1 1'b1;
end
else
begin
sSCL <= #1 &fSCL[2:1] | &fSCL[1:0] | (fSCL[2] & fSCL[0]);
sSDA <= #1 &fSDA[2:1] | &fSDA[1:0] | (fSDA[2] & fSDA[0]);
dSCL <= #1 sSCL;
dSDA <= #1 sSDA;
end
end
// generate dout signal (store SDA on rising edge of SCL)
always @(posedge clk)
if(sSCL & ~dSCL)
dout <= #1 sSDA;
- 四倍频率采样SCL,使用三个连续位决策输出,进行同步
仲裁失败(Aribitration lost)
//仲裁丢失:当检测到停止信号,没有检测到请求信号,主机设置SDA为高电平,但实际上SDA为低电平
always @(posedge clk or negedge nReset)
begin
if(~nReset)
al <= #1 1'b0;
else if(rst)
al <= #1 1'b0;
else
al <= #1 (sda_chk & ~sSDA & sda_oen)|(|c_state & sto_condition & ~cmd_stop);
end
版权声明:本文为xiangsimoyinjiu原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。