1.APB_IIC架构
①由APB配置级寄存器,在通过byte和bit模块送到iic的SDA上
②这里数据的寄存移位只用到了一个模块,而UART用到了两个buf和移位,主要的原因就是iic属于半双工的传输,一次只能往一个方向传,而UART可以同时双向传输
③三态门总线结构,右边SCL、SDA接有上拉的电阻,使能路通路后,SCL取out的值
④IIC时序:
2.寄存器介绍
① Prescale : 5倍SCL关系
②Control register:使能、中断
③Transmit register:传输地址或者数据格式不一样,传数据的时候,[0]作为LSB,传地址的时候,[0]作为读写控制bit
④cmd_rigister
[7] 开始 [6] 结束 [5] 读 [4] 写 [3] 响应out [0] 响应in
⑤Status register [7]:rx的ack相应位 [6]:iic的busy信号位 [5]:传输数据仲裁 [4:2]:没用到 [1]:传输过程信号位 [0]:中断,一个字节传完会触发一次或者传输异常触发
3.RTL代码
3.1 i2c_master_top.v
①端口描述:APB的一些接口,以及IIC的SDA、SCL
module i2c_master_top
(
input wire PCLKG,
input wire PRESETn,
input wire PSEL,
input wire [11:2] PADDR,
input wire PENABLE,
input wire PWRITE,
input wire [31:0] PWDATA,
output wire [31:0] PRDATA,
output wire PREADY,
output wire PSLVERR,
output reg wb_inta_o,
input scl_pad_i,
output wire scl_pad_o,
output wire scl_padoen_o,
input sda_pad_i,
output wire sda_pad_o,
output wire sda_padoen_o
);
②内部信号:寄存器信号、地址信号、数据信号以及一些中断信号等
//internal sig
wire wb_clk_i;
wire arst_i;
wire [2:0] wb_adr_i;
wire [7:0] wb_dat_i;
wire [7:0] wb_dat_o;
wire wb_we_i; //APB setup开始
reg [15:0] prer;
reg [7:0] ctr;
reg [7:0] txr;
reg [7:0] rxr;
reg [7:0] cr;
reg [7:0] sr;
wire done;
wire core_en;
wire ien;
wire irxack;
reg rxack;
reg tip;
reg irq_flag;
wire i2c_busy;
wire i2c_al;//i2c bus arbitration lost
reg al;//status reg arbitration lost bit
③重新定义了一下一些信号
assign wb_clk_i = PCLKG;
assign arst_i = PRESETn;
assign wb_adr_i = PADDR[4:2];
assign wb_dat_i = PWDATA[7:0];
assign wb_we_i = PSEL & (!PENABLE) & PWRITE;
assign PRDATA = {{24{1'b0}},wb_dat_o};
assign PREADY = 1'b1;
assign PSLVERR = 1'b0;
wire rst_i = arst_i;
wire wb_wacc = wb_we_i;
④由地址决定寄存器:wb_dat_o 给到了PRDATA 的低8位
always@(posedge wb_clk_i)begin
case (wb_adr_i)
3'b000:wb_dat_o <= prer[7:0];
3'b001:wb_dat_o <= prer[15:8];
3'b010:wb_dat_o <= ctr;
3'b011:wb_dat_o <= rxt;
3'b100:wb_dat_o <= sr;
3'b101:wb_dat_o <= txr;
3'b110:wb_dat_o <= cr;
3'b111:wb_dat_o <= 0;
endcase
end
⑤寄存器取值:由输入地址,输入数据给不同的寄存器赋值
always @(posedge wb_clk_i or negedge rst_i)begin
if(!rst_i)begin
prer <= 16'hffff;
ctr <= 8'h0;
txr <= 8'h0;
end
else
if(wb_wacc)
case(wb_adr_i)
3'b000:prer[7:0] <= wb_dat_i;
3'b001:prer[15:8] <= wb_dat_i;
3'b010:ctr <= wb_dat_i;
3'b011:txr <= wb_dat_i;
default: ;
endcase
end
always @(posedge wb_clk_i or negedge rst_i)begin
if(!rst_i)
cr <= 8'h0;
else if(wb_wacc)begin
if(core_en & (wb_adr_i == 3'b100)) //done 、i2c_al由i2c_master_byte_ctrl模块给出
cr <= wb_dat_i;
end
else begin
if(done | i2c_al)
cr[7:4] <= 4'h0;
cr[2:0] <= 3'b0;
end
end
wire sta = cr[7];
wire sto = cr[6];
wire rd = cr[5];
wire wr = cr[4];
wire ack = cr[3];
wire iack = cr[0];
assign core_en = ctr[7];
assign ien = ctr[6];
⑥例化i2c_master_byte_ctrl模块
i2c_master_byte_ctrl byte_controller
(
.clk (wb_clk_i),
.nReset (rst_i),
.ena (core_en),
.clk_cnt (prer),
.start (sta),
.stop (sto),
.read (rd),
.write (wr),
.ack_in (ack),
.din (txr),
.cmd_ack (done),
.ack_out (irxack),
.dout (rxr),
.i2c_busy (i2c_busy),
.i2c_al (i2c_al),
.scl_i (scl_pad_i),
.scl_o (scl_pad_o),
.scl_oen (scl_padoen_o),
.sda_i (sda_pad_i),
.sda_o (sda_pad_o),
.sda_oen (sda_padoen_o)
);
⑦Status register :先定义好每个位的作用,然后根据各个情况分布好功能
[7]:rx的ack响应位 [6]:iic的busy信号位 [5]:传输数据仲裁 [4:2]:没用到 [1]:传输过程信号位 [0]:中断,一个字节传完会触发一次或者传输异常触发
assign sr[7] = rxack;
assign sr[6] = i2c_busy;
assign sr[5] = al;
assign sr[4:2] = 3'h0;
assign sr[1] = tip;
assign sr[0] = irq_flag;
always @(posedge wb_clk_i or negedge rst_i)begin
if(!rst_i)begin
al <= 1'b0;
rxack <= 1'b0;
tip <= 1'b0;
irq_flag <= 1'b0;
end
else begin
al <= i2c_al | (al & !sta);
rxack <= irxack;
tip <= (rd | wr);
irq_flag <= (done | i2c_al | irq_flag) & !iack;
end
end
always @(posedge wb_clk_i or negedge rst_i)begin
if(!rst_i)
wb_inta_o <= 1'b0;
else
wb_inta_o <= irq_flag && ien;
end
endmodule
3.2 i2c_master_byte_ctrl.V
①端口描述:包括时钟命令使能、iic接口、命令信号、数据信号等
module i2c_master_byte_ctrl
(
input clk,
input nReset;
input ena;
input [15:0] clk_cnt;
input start;
input stop;
input read;
input write;
input ack_in;
input [7:0 ] din;
output reg cmd_ack;
output reg ack_out;
output i2c_busy;
output i2c_al;
output [7:0] dout;
input scl_i;
output scl_o;
output scl_oen;
input sda_i;
output sda_o;
output sda_oen;
);
②全局状态机参数
//parameter
parameter [4:0] ST_IDEL = 5'b00000;
parameter [4:0] ST_START = 5'b00001;
parameter [4:0] ST_READ = 5'b00010;
parameter [4:0] ST_WRITE = 5'b00100;
parameter [4:0] ST_ACK = 5'b01000;
parameter [4:0] ST_STOP = 5'b10000;
parameter [3:0] I2C_CMD_NOP = 4'b0000;
parameter [3:0] I2C_CMD_START = 4'b0001;
parameter [3:0] I2C_CMD_STOP = 4'b0010;
parameter [3:0] I2C_CMD_WRITE = 4'b0100;
parameter [3:0] I2C_CMD_READ = 4'b1000;
③内部信号:包括命令信号、tx、rx数据、移位寄存器等
//internal sig
reg [3:0] core_cmd;
reg core_txd;
wire core_ack;
wire core_rxd;
reg [7:0] sr;//移位寄存器
reg shift;//移位指示
reg ld;//load指示
wire go;
reg [2:0] dcnt;
wire cnt_done;
reg [4:0] c_state;
④例化i2c_master_bit_controller模块
//例化bit_controller
i2c_master_bit_controller bit_controller
(
.clk (clk),
.nReset (nReset),
.ena (ena),
.clk_cnt (clk_cnt),
.cmd (core_cmd),
.cmd_ack (core_ack),
.busy (i2c_busy),
.al (i2c_al),
.din (core_txd),
.dout (core_rxd),
.scl_i (scl_i),
.scl_o (scl_o),
.scl_oen (scl_oen),
.sda_i (sda_i),
.sda_o (sda_o),
.sda_oen (sda_oen)
);
⑤起始信号go:当读写停止命令下,且无响应输出时,go拉高
assign go = (read | write |stop) & !cmd_ack;
⑥移位寄存器sr设置
assign dout = sr;
always@(posedge clk or negedge nReset)begin
if(!nReset)
sr <= 8'h0;
else if(ld)
sr <= din;
else if(shift)
sr <= {sr[6:0],core_rxd};
end
always@(posedge clk or negedge nReset)begin
if(!nReset)
dcnt <= 3'h0;
else if(ld)
dcnt <= 3'h7;
else if(shift)
dcnt <= dcnt - 3'h1;
end
assign cnt_done = !(|dcnt);
⑦状态机:给出状态和当前命令
always@(posedge clk or negedge nReset)begin
if(nReset)begin
core_cmd <= I2C_CMD_NOP;
core_txd <= 1'b0;
shift <= 1'b0;
ld <= 1'b0;
cmd_ack <= 1'b0;
c_state <= ST_IDEL;
ack_out <= 1'b0;
end
else if(i2c_al)begin
core_cmd <= I2C_CMD_NOP;
core_txd <= 1'b0;
shift <= 1'b0;
ld <= 1'b0;
cmd_ack <= 1'b0;
c_state <= ST_IDEL;
ack_out <= 1'b0;
end
else begin
core_txd <= sr[7];
shift <= 1'b0;
ld <= 1'b0;
cmd_ack <= 1'b0;
case(c_state)
ST_IDEL:
if(go)begin
if(start)begin
c_state <= ST_START;
core_cmd <= I2C_CMD_START;
end
else if(read)begin
c_state <= ST_READ;
core_cmd <= I2C_CMD_READ;
end
else if(write)begin
c_state <= ST_WRITE;
core_cmd <= I2C_CMD_WRITE;
end
else begin
c_state <= ST_STOP;
core_cmd <= I2C_CMD_STOP;
end
ld <= 1'b1;
end
ST_START:
if(core_ack)begin
if(read)begin
c_state <= ST_READ;
core_cmd <= I2C_CMD_READ;
end
else begin
c_state <= ST_WRITE;
core_cmd <= I2C_CMD_WRITE;
end
ld <= 1'b1;
end
ST_WRITE:
if(core_ack)begin
if(cnt_done)begin
c_state <= ST_ACK;
core_cmd <= I2C_CMD_READ;
end
else begin
c_state <= ST_WRITE;
core_cmd <= I2C_CMD_WRITE;
shift <= 1'b1;
end
end
ST_READ:
if(core_ack)begin
if(cnt_done)begin
c_state <= ST_ACK;
core_cmd <= I2C_CMD_WRITE;
end
else begin
c_state <= ST_READ;
core_cmd <= I2C_CMD_READ;
end
shift <= 1'b1;
core_txd <= ack_in;
end
ST_ACK:
if(core_ack)begin
if(stop)begin
c_state <= ST_STOP;
core_cmd <= I2C_CMD_STOP;
end
else begin
c_state <= ST_IDEL;
core_cmd <= I2C_CMD_NOP;
cmd_ack <= 1'b1;
end
ack_out <= core_rxd;
core_txd <= 1'b1;
end
else begin
core_txd <= ack_in;
end
ST_STOP:
if(core_ack)begin
c_state <= ST_IDEL;
core_cmd <= I2C_CMD_NOP;
cmd_ack <= 1'b1;
end
endcase
end
end
endmodule
3.3 i2c_master_bit_ctrl.v
①端口描述:包括时钟复位命令、IIC接口等
module i2c_master_bit_ctrl (
input clk, // system clock
// input rst, // synchronous active high reset
input nReset, // asynchronous active low reset
input ena, // core enable signal
input [15:0] clk_cnt, // clock prescale value
input [ 3:0] cmd, // command (from byte controller)
output reg cmd_ack, // command complete acknowledge
output reg busy, // i2c bus busy
output reg al, // i2c bus arbitration lost
input din,
output reg dout,
input scl_i, // i2c clock line input
output scl_o, // i2c clock line output
output reg scl_oen, // i2c clock line output enable (active low)
input sda_i, // i2c data line input
output sda_o, // i2c data line output
output reg sda_oen // i2c data line output enable (active low)
);
②全局参数:定义状态
parameter [3:0] I2C_CMD_NOP = 4'b0000;
parameter [3:0] I2C_CMD_START = 4'b0001;
parameter [3:0] I2C_CMD_STOP = 4'b0010;
parameter [3:0] I2C_CMD_WRITE = 4'b0100;
parameter [3:0] I2C_CMD_READ = 4'b1000;
// nxt_state decoder
parameter [17:0] idle = 18'b0_0000_0000_0000_0000;
parameter [17:0] start_a = 18'b0_0000_0000_0000_0001;
parameter [17:0] start_b = 18'b0_0000_0000_0000_0010;
parameter [17:0] start_c = 18'b0_0000_0000_0000_0100;
parameter [17:0] start_d = 18'b0_0000_0000_0000_1000;
parameter [17:0] start_e = 18'b0_0000_0000_0001_0000;
parameter [17:0] stop_a = 18'b0_0000_0000_0010_0000;
parameter [17:0] stop_b = 18'b0_0000_0000_0100_0000;
parameter [17:0] stop_c = 18'b0_0000_0000_1000_0000;
parameter [17:0] stop_d = 18'b0_0000_0001_0000_0000;
parameter [17:0] rd_a = 18'b0_0000_0010_0000_0000;
parameter [17:0] rd_b = 18'b0_0000_0100_0000_0000;
parameter [17:0] rd_c = 18'b0_0000_1000_0000_0000;
parameter [17:0] rd_d = 18'b0_0001_0000_0000_0000;
parameter [17:0] wr_a = 18'b0_0010_0000_0000_0000;
parameter [17:0] wr_b = 18'b0_0100_0000_0000_0000;
parameter [17:0] wr_c = 18'b0_1000_0000_0000_0000;
parameter [17:0] wr_d = 18'b1_0000_0000_0000_0000;
③内部信号:这里多了一个延迟scl的使能和信号,当slave没有准备好时,可以通过把scl拉低进行等待
reg [ 1:0] cSCL, cSDA; // capture SCL and SDA
reg [ 2:0] fSCL, fSDA; // SCL and SDA filter inputs
reg sSCL, sSDA; // filtered and synchronized SCL and SDA inputs
reg dSCL, dSDA; // delayed versions of sSCL and sSDA
reg dscl_oen; // delayed scl_oen
reg sda_chk; // check SDA output (Multi-master arbitration)
reg clk_en; // clock generation signals
reg slave_wait; // slave inserts wait states
reg [15:0] cnt; // clock divider counter (synthesis)
reg [13:0] filter_cnt; // clock divider for filter
// state machine variable
reg [17:0] c_state; // synopsys enum_state
reg sta_condition;
reg sto_condition;
reg cmd_stop;
④slave_wait的相关操作
// whenever the slave is not ready it can delay the cycle by pulling SCL low
// delay scl_oen
always @(posedge clk)
dscl_oen <= #1 scl_oen;
// slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low
// slave_wait remains asserted until the slave releases SCL
always @(posedge clk or negedge nReset)
if (!nReset) slave_wait <= 1'b0;
else slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL);
// master drives SCL high, but another master pulls it low
// master start counting down its low cycle now (clock synchronization)
wire scl_sync = dSCL & ~sSCL & scl_oen;
⑤时钟使能信号的产生:等待的时候不计数,使能为0
// generate clk enable signal
always @(posedge clk or negedge nReset)
if (~nReset)
begin
cnt <= #1 16'h0;
clk_en <= #1 1'b1;
end
else if (rst || ~|cnt || !ena || scl_sync)
begin
cnt <= #1 clk_cnt;
clk_en <= #1 1'b1;
end
else if (slave_wait)
begin
cnt <= #1 cnt;
clk_en <= #1 1'b0;
end
else
begin
cnt <= #1 cnt - 16'h1;
clk_en <= #1 1'b0;
end
⑥总线状态捕获c:减少亚稳态风险
// generate bus status controller
// capture SDA and SCL
// reduce metastability risk
always @(posedge clk or negedge nReset)
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
⑦滤波去毛刺f、同步化s、再做延迟d
// filter SCL and SDA signals; (attempt to) remove glitches
always @(posedge clk or negedge nReset)
if (!nReset ) filter_cnt <= 14'h0;
else if (rst || !ena ) filter_cnt <= 14'h0;
else if (~|filter_cnt) filter_cnt <= clk_cnt >> 2; //16x I2C bus frequency
else filter_cnt <= filter_cnt -1;
always @(posedge clk or negedge nReset)
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
// generate filtered SCL and SDA signals
always @(posedge clk or negedge nReset)
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
⑧开始信号检测:当SCL为高,SDA下降沿时,IIC传输开始 busy :正在传输时,拉高busy
always @(posedge clk or negedge nReset)
if (~nReset)
begin
sta_condition <= #1 1'b0;
sto_condition <= #1 1'b0;
end
else if (rst)
begin
sta_condition <= #1 1'b0;
sto_condition <= #1 1'b0;
end
else
begin
sta_condition <= #1 ~sSDA & dSDA & sSCL;
sto_condition <= #1 sSDA & ~dSDA & sSCL;
end
// generate i2c bus busy signal
always @(posedge clk or negedge nReset)
if (!nReset) busy <= #1 1'b0;
else if (rst ) busy <= #1 1'b0;
else busy <= #1 (sta_condition | busy) & ~sto_condition;
⑨仲裁失败:主机SDA设置为高,I2C总线SDA为低,仲裁失败;没有请求时检测到停止信号,仲裁失败
// generate arbitration lost signal
// aribitration lost when:
// 1) master drives SDA high, but the i2c bus is low
// 2) stop detected while not requested
always @(posedge clk or negedge nReset)
if (~nReset)
cmd_stop <= #1 1'b0;
else if (rst)
cmd_stop <= #1 1'b0;
else if (clk_en)
cmd_stop <= #1 cmd == I2C_CMD_STOP;
always @(posedge clk or negedge nReset)
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);
⑩ 将SDA数据存起来:当SCL上升沿到来,存SDA数据
always @(posedge clk)
if (sSCL & ~dSCL)
dout <= #1 sSDA;
?状态机:每个状态又分为5个小状态_abcde
每个状态分别对应:
下图均是 上SDA 下SCL
always @(posedge clk or negedge nReset)
if (!nReset)
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
scl_oen <= #1 1'b1;
sda_oen <= #1 1'b1;
sda_chk <= #1 1'b0;
end
else if (rst | al)
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
scl_oen <= #1 1'b1;
sda_oen <= #1 1'b1;
sda_chk <= #1 1'b0;
end
else
begin
cmd_ack <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle
if (clk_en)
case (c_state) // synopsys full_case parallel_case
// idle state
idle:
begin
case (cmd) // synopsys full_case parallel_case
I2C_CMD_START: c_state <= #1 start_a;
I2C_CMD_STOP: c_state <= #1 stop_a;
I2C_CMD_WRITE: c_state <= #1 wr_a;
I2C_CMD_READ: c_state <= #1 rd_a;
default: c_state <= #1 idle;
endcase
scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 sda_oen; // keep SDA in same state
sda_chk <= #1 1'b0; // don't check SDA output
end
// start
start_a:
begin
c_state <= #1 start_b;
scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 1'b1; // set SDA high
sda_chk <= #1 1'b0; // don't check SDA output
end
start_b:
begin
c_state <= #1 start_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA high
sda_chk <= #1 1'b0; // don't check SDA output
end
start_c:
begin
c_state <= #1 start_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // set SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end
start_d:
begin
c_state <= #1 start_e;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end
start_e:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b0; // keep SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end
// stop
stop_a:
begin
c_state <= #1 stop_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b0; // set SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end
stop_b:
begin
c_state <= #1 stop_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b0; // keep SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end
stop_c:
begin
c_state <= #1 stop_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end
stop_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1; // set SDA high
sda_chk <= #1 1'b0; // don't check SDA output
end
// read
rd_a:
begin
c_state <= #1 rd_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b1; // tri-state SDA
sda_chk <= #1 1'b0; // don't check SDA output
end
rd_b:
begin
c_state <= #1 rd_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA tri-stated
sda_chk <= #1 1'b0; // don't check SDA output
end
rd_c:
begin
c_state <= #1 rd_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1; // keep SDA tri-stated
sda_chk <= #1 1'b0; // don't check SDA output
end
rd_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b1; // keep SDA tri-stated
sda_chk <= #1 1'b0; // don't check SDA output
end
// write
wr_a:
begin
c_state <= #1 wr_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 din; // set SDA
sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
end
wr_b:
begin
c_state <= #1 wr_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 din; // keep SDA
sda_chk <= #1 1'b0; // don't check SDA output yet
// allow some time for SDA and SCL to settle
end
wr_c:
begin
c_state <= #1 wr_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 din;
sda_chk <= #1 1'b1; // check SDA output
end
wr_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 din;
sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
end
endcase
end
?设置IIC的输出:接地
assign scl_o = 1'b0;
assign sda_o = 1'b0;
endmodule
参考: https://blog.csdn.net/xiangsimoyinjiu/article/details/106175606?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165408452216782395325005%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=165408452216782395325005&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-106175606-null-null.142v11control,157v12control&utm_term=aribitration+lost&spm=1018.2226.3001.4187
|