电子说
01
IIC基础知识
集成电路总线 (Inter-Intergrated Circuit),通常称作IICBUS,简称为IIC,是一种采用多主从结构的串行通信总线。
IIC由PHILIPS公司于1980年推出,利用该总线可实现多主机系统所需的裁决和高低速设备同步等功能。
IIC串行总线一般有两根信号线,分别是时钟线SCL和数据线SDA,所有IIC总线各设备的串行数据SDA接到总线SDA上,时钟线SLC接到总线SCL上。
双向串行数据SDA:输出电路用于向总线发送数据,输入电路用于接收总线上的数据;
双向时钟数据SCL:输出电路用于向总线发送时钟信号,输入电路用于检测总线时钟电平以决定下次时钟脉冲电平时间。
各设备与总线相连的输出端采用高阻态以避免总线信号的混乱,通常采用漏极开路输出或集电极开路输出。总线空闲时,各设备都是开漏输出,通常可采用上拉电阻使总线保持高电平,而任一设备输出低电平都将拉低相应的总线信号。
IIC总线上的设备可分为主设备和从设备两种:主设备有权利主动发起/结束一次通信;从设备只能被动响应。
所有连接在IIC总线上的设备都有各自唯一的地址(原地址位宽为7bits,改进后采用10bits位宽),每个设备都可以作为主设备或从设备,但是同一时刻只能有一个主设备控制。
如果总线上有多个设备同时启用总线,IIC通过检测和仲裁机制解决传输冲突。IIC允许连接的设备传输速率不同,多台设备之间时钟信号的同步过程称为同步化。
02
IIC传输协议
2.1 IIC协议模式
IIC协议为半双工模式,同一条数据线上完成读/写操作,不同操作时的数据帧格式可分为写操作、读操作、读写操作。
2.1.1 写操作数据帧格式
主机向从机写数据的数据帧格式如下:
白色为主机发送数据,灰色为从机发送数据。
2.1.2 读操作数据帧格式
主机从从机读数据的数据帧格式如下:
白色为主机发送数据,灰色为从机发送数据。
2.1.3 读写同时操作数据帧格式
主机先向从机写数据后从从机读数据的数据帧格式如下:
白色为主机发送数据,灰色为从机发送数据。
主机可以在完成写操作后不发送结束信号P,直接进行读操作。该过程主机不可变,而从机可以通过发送不同地址选择不同的从机。
2.2 IIC写时序
IIC协议写时序可分为单字节写时序和连续写时序:
2.2.1 单字节写时序
单字节地址写时序过程:
双字节地址写时序过程:
2.2.2 连续写时序
单字节地址写时序过程:
双字节地址写时序过程:
2.3 IIC读时序
IIC协议读时序可分为单字节读时序和连续读时序:
2.3.1 单字节读时序
单字节地址读时序过程:
双字节地址读时序过程:
2.3.2 连续读时序
单字节地址读时序过程:
双字节地址读时序过程:
03
IIC代码实现
3.1 IIC目标实现功能
设计一个IIC模块,具体要求如下:
设计一个IIC协议提供给主设备,通过查找表实现对从设备寄存器进行配置。按查找表顺序lut_index依次对设备地址为lut_dev_addr的从设备寄存器进行配置,为lut_reg_addr配置寄存器数据lut_reg_data,同时将传输异常和传输结束信号引出以对传输过程进行监控。模块的定义如下:
module i2c(
input rst, //复位信号
input clk, //时钟信号
input[15:0] clk_div_cnt, //时钟计数器
input i2c_addr_2byte, //双字节地址
output reg[9:0] lut_index, //查找表顺序号
input[7:0] lut_dev_addr, //从设备地址
input[15:0] lut_reg_addr, //寄存器地址
input[7:0] lut_reg_data, //寄存器数据
output reg error, //传输异常信号
output done, //传输结束信号
inout i2c_scl, //IIC时钟信号
inout i2c_sda //IIC数据信号
);
3.2 Verilog代码
1. 顶层模块 (i2c):
module i2c(
input rst,
input clk,
input[15:0] clk_div_cnt,
input i2c_addr_2byte,
output reg[9:0] lut_index,
input[7:0] lut_dev_addr,
input[15:0] lut_reg_addr,
input[7:0] lut_reg_data,
output reg error,
output done,
inout i2c_scl,
inout i2c_sda
);
wire scl_pad_i;
wire scl_pad_o;
wire scl_padoen_o;
wire sda_pad_i;
wire sda_pad_o;
wire sda_padoen_o;
assign sda_pad_i = i2c_sda;
assign i2c_sda = ~sda_padoen_o ? sda_pad_o : 1'bz;
assign scl_pad_i = i2c_scl;
assign i2c_scl = ~scl_padoen_o ? scl_pad_o : 1'bz;
reg i2c_read_req;
wire i2c_read_req_ack;
reg i2c_write_req;
wire i2c_write_req_ack;
wire[7:0] i2c_slave_dev_addr;
wire[15:0] i2c_slave_reg_addr;
wire[7:0] i2c_write_data;
wire[7:0] i2c_read_data;
wire err;
reg[2:0] state;
localparam S_IDLE = 0;
localparam S_WR_I2C_CHECK = 1;
localparam S_WR_I2C = 2;
localparam S_WR_I2C_DONE = 3;
assign done = (state == S_WR_I2C_DONE);
assign i2c_slave_dev_addr = lut_dev_addr;
assign i2c_slave_reg_addr = lut_reg_addr;
assign i2c_write_data = lut_reg_data;
//cascatrix carson
always@(posedge clk or posedge rst)
begin
if(rst)
begin
state <= S_IDLE;
error <= 1'b0;
lut_index <= 8'd0;
end
else
case(state)
S_IDLE:
begin
state <= S_WR_I2C_CHECK;
error <= 1'b0;
lut_index <= 8'd0;
end
S_WR_I2C_CHECK:
begin
if(i2c_slave_dev_addr != 8'hff)
begin
i2c_write_req <= 1'b1;
state <= S_WR_I2C;
end
else
begin
state <= S_WR_I2C_DONE;
end
end
S_WR_I2C:
begin
if(i2c_write_req_ack)
begin
error <= err ? 1'b1 : error;
lut_index <= lut_index + 8'd1;
i2c_write_req <= 1'b0;
state <= S_WR_I2C_CHECK;
end
end
S_WR_I2C_DONE:
begin
state <= S_WR_I2C_DONE;
end
default:
state <= S_IDLE;
endcase
end
i2c_ctrl i2c_ctrl
(
.rst(rst),
.clk(clk),
.clk_div_cnt(clk_div_cnt),
// I2C signals
// i2c clock line
.scl_pad_i(scl_pad_i), // SCL-line input
.scl_pad_o(scl_pad_o), // SCL-line output (always 1'b0)
.scl_padoen_o(scl_padoen_o), // SCL-line output enable (active low)
// i2c data line
.sda_pad_i(sda_pad_i), // SDA-line input
.sda_pad_o(sda_pad_o), // SDA-line output (always 1'b0)
.sda_padoen_o(sda_padoen_o), // SDA-line output enable (active low)
.i2c_read_req(i2c_read_req),
.i2c_addr_2byte(i2c_addr_2byte),
.i2c_read_req_ack(i2c_read_req_ack),
.i2c_write_req(i2c_write_req),
.i2c_write_req_ack(i2c_write_req_ack),
.i2c_slave_dev_addr(i2c_slave_dev_addr),
.i2c_slave_reg_addr(i2c_slave_reg_addr),
.i2c_write_data(i2c_write_data),
.i2c_read_data(i2c_read_data),
.error(err)
);
endmodule
全部0条评论
快来发表一下你的评论吧 !