赞
踩
I2C(Inter-Integrated Circuit)中文名称“集成电路总线”,是一种串行同步半双工总线。
I2C总线是由Philips公司开发的一种简单,双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传达信息,一根是数据线(SDA),一根是时钟线(SCL)。
I2C总线可实现多主机,多从机之间的互联,具有低功耗,抗干扰,电源电压范围宽,工作温度范围广的特点。其通讯速率为:标准模式0-100kbit/s,快速模式0-400kbit/s,和高速模式0-3.4Mbit/s。可连接很多设备,总电容在400pF。
I2C结构:1, 设备之间互联只需要两根线(SDA,SCL)
2, I2C总线支持任何IC生产过程(NMOS CMOS双极性)
3, SDA双向数据线
4, SCL双向时钟线
5, 每个设备有且只有一个设备地址
6, 设备分为主机(master)和从机,主机允许输出时钟信号
7, 主机发送信号时,发送时钟和数据,当主机发送结束后,数据线高阻,主机继续发送时钟,从机发送数据给主机
I2C硬件连接:1, I2C只使用两条漏极开路(Open Drain)SDA及SCL并利用电阻将电平上拉。
2, VDD通常为+5V或者是+3.3V
3, 逻辑0 = 低电平
4, 逻辑1 = 高点平
I2C总线协议:
写格式:1,主机发start位
2,主机发从机地址和写命令
3,从机回ack
4,主机发寄存器地址
5,从机回ack
6,主机发数据
7,从机回ack
8,主机发stop位
读格式:1,主机发atart位
2,主机发从机地址和写命令
3,从机回ack
4,主机发寄存器地址
5,从机回ack
6,主机发restart位
7,主机发从机地址和读命令
8,从机回ack
9,从机回数据
10,主机发nack
11,主机发stop位
I2C驱动模块:
- `define IIC_FREQ100K 500 //频率100k
- `define IIC_FREQ400K 125 //频率400k
- module i2c_driver #(
- parameter IIC_CNTMAX = `IIC_FREQ100K
- )
- (
- input clk,
- input rst_n,
-
- input wire [1:0] cmd, //2'b00-无操作 2'b01-写操作 2'b10-读操作
- input wire [6:0] device_addr, //从机地址
- input wire [7:0] reg_addr, //寄存器地址
- input wire [7:0] wr_data, //写入的数据
- output reg [7:0] rd_data, //读出的数据
- output reg done, //结束脉冲
- output reg err, //报错信号
- output reg scl, //时钟线
- inout sda //数据线
- );
- reg sda_sel;
- reg sda_reg;
- assign sda = sda_sel ? sda_reg : 1'bz;
-
- localparam IIC_CNTMAX_4_1 = IIC_CNTMAX/4-1,
- IIC_CNTMAX_4_2 = IIC_CNTMAX/2-1,
- IIC_CNTMAX_4_3 = (IIC_CNTMAX/4)*3-1,
- IIC_CNTMAX_4_4 = IIC_CNTMAX-1;
-
-
- reg [25:0] cnt; //时钟计数器
- reg [25:0] delay_cnt; //延迟计数器
- reg ack; //寄存一个从机回的ack信号
- reg [7:0] data_reg; //定义一个八位的数据寄存器
- reg [3:0] num; //定义个计数num
- reg [3:0] state;
- reg [3:0] back_state;
- localparam FSM_START = 0, //主机发start位
- FSM_DEVICE_ADDR_WR_RD = 1, //主机发从机地址和写命令
- FSM_ACK = 2, //从机回ack
- FSM_WR_REG_ADDR = 3, //主机发寄存器地址
- FSM_WR_DATA = 4, //主机发数据
- FSM_RESTART = 5, //主机发restart位
- FSM_RD_DATA = 6, //从机回数据
- FSM_NACK = 7, //主机发nack
- FSM_STOP = 8, //主机发stop位
- FSM_DELAY = 9; //延迟20us
-
-
- reg [1:0] scl_state; //定义个时钟线状态
-
-
- always @(posedge clk or negedge rst_n)
- if (!rst_n)
- cnt <= 0;
- else if (state == FSM_DELAY)
- cnt <= 0;
- else if (cmd == 2'b01 || cmd == 2'b10)
- begin
- if (cnt == IIC_CNTMAX_4_4)
- cnt <= 0;
- else cnt <= cnt + 1;
- end
- else cnt <= 0;
-
-
- always @(posedge clk or negedge rst_n)
- if (!rst_n)
- begin
- scl <= 1;
- scl_state <= 0;
- end
- else if (cmd == 2'b01 || cmd == 2'b10)
- case (scl_state)
- 0 : if (cnt == 0)
- scl <= 1;
- else if (cnt == IIC_CNTMAX_4_3)
- scl <= 0;
- else if (cnt == IIC_CNTMAX_4_4)
- scl_state <= 1;
- else scl_state <= 0;
-
- 1 : if ((back_state == FSM_STOP && state == FSM_ACK && cnt == IIC_CNTMAX_4_4) || (state == FSM_NACK && cnt == IIC_CNTMAX_4_4))
- scl_state <= 2;
- else if (cnt == 0)
- scl <= 0;
- else if (cnt == IIC_CNTMAX_4_1)
- scl <= 1;
- else if (cnt == IIC_CNTMAX_4_3)
- scl <= 0;
- else scl_state <= 1;
-
- 2 : if (cnt == 0)
- scl <= 0;
- else if (cnt == IIC_CNTMAX_4_1)
- scl <= 1;
- else if (cnt == IIC_CNTMAX_4_4)
- scl_state <= 3;
- else scl_state <= 2;
-
- 3 : if (delay_cnt == 999)
- scl_state <= 0;
- else scl_state <= 3;
-
- default : begin scl <= 1; scl_state <= 0; end
- endcase
- else begin
- scl <= 1;
- scl_state <= 0;
- end
-
-
- always @(posedge clk or negedge rst_n)
- if (!rst_n)
- begin
- state <= FSM_START;
- back_state <= 0;
- rd_data <= 0;
- done <= 0;
- sda_sel <= 1;
- sda_reg <= 1;
- delay_cnt <= 0;
- ack <= 1;
- data_reg <= 0;
- num <= 0;
- err <= 0;
- end
-
- else if (cmd == 2'b01 || cmd == 2'b10)
- case (state)
- FSM_START : begin
- done <= 0;
- sda_sel <= 1;
- data_reg <= {device_addr,1'b0};
- back_state <= FSM_WR_REG_ADDR;
- if (cnt == 0)
- sda_reg <= 1;
- else if (cnt == IIC_CNTMAX_4_2)
- sda_reg <= 0;
-
- if (cnt == IIC_CNTMAX_4_4)
- state <= FSM_DEVICE_ADDR_WR_RD;
- else state <= FSM_START;
- end
-
- FSM_DEVICE_ADDR_WR_RD : begin
- sda_sel <= 1;
- if (cnt == 0)
- sda_reg <= data_reg[7-num];
-
- if (cnt == IIC_CNTMAX_4_4 && num == 7)
- begin
- num <= 0;
- state <= FSM_ACK;
- end
- else if (cnt == IIC_CNTMAX_4_4)
- num <= num + 1;
- else state <= FSM_DEVICE_ADDR_WR_RD;
- end
-
- FSM_ACK : begin
- sda_sel <= 0;
- sda_reg <= 1;
- if (cnt == IIC_CNTMAX_4_2)
- ack <= sda;
-
- if (cnt == IIC_CNTMAX_4_4)
- state <= back_state;
- else state <= FSM_ACK;
- end
-
- FSM_WR_REG_ADDR : begin
- if (!ack)
- begin
- sda_sel <= 1;
- if (cmd == 2'b01)
- back_state <= FSM_WR_DATA;
- else if (cmd == 2'b10)
- back_state <= FSM_RESTART;
-
- if (cnt == 0)
- sda_reg <= reg_addr[7-num];
-
- if (cnt == IIC_CNTMAX_4_4 && num == 7)
- begin
- num <= 0;
- state <= FSM_ACK;
- end
- else if (cnt == IIC_CNTMAX_4_4)
- num <= num + 1;
- else state <= FSM_WR_REG_ADDR;
- end
- else begin
- err <= 1;
- state <= FSM_START;
- end
- end
- FSM_WR_DATA : begin
- if (!ack)
- begin
- sda_sel <= 1;
- back_state <= FSM_STOP;
- if (cnt == 0)
- sda_reg <= wr_data[7-num];
-
- if (cnt == IIC_CNTMAX_4_4 && num == 7)
- begin
- num <= 0;
- state <= FSM_ACK;
- end
- else if (cnt == IIC_CNTMAX_4_4)
- num <= num + 1;
- else state <= FSM_WR_DATA;
- end
- else begin
- err <= 1;
- state <= FSM_START;
- end
- end
-
- FSM_RESTART : begin
- if (!ack)
- begin
- sda_sel <= 1;
- data_reg <= {device_addr,1'b1};
- back_state <= FSM_RD_DATA;
- if (cnt == 0)
- sda_reg <= 1;
- else if (cnt == IIC_CNTMAX_4_2)
- sda_reg <= 0;
-
- if (cnt == IIC_CNTMAX_4_4)
- state <= FSM_DEVICE_ADDR_WR_RD;
- else state <= FSM_RESTART;
- end
- else begin
- err <= 1;
- state <= FSM_START;
- end
- end
-
- FSM_RD_DATA : begin
- if (!ack)
- begin
- sda_sel <= 0;
- if (cnt == IIC_CNTMAX_4_2)
- rd_data[7-num] <= sda;
-
- if (cnt == IIC_CNTMAX_4_4 && num == 7)
- begin
- num <= 0;
- state <= FSM_NACK;
- end
- else if (cnt == IIC_CNTMAX_4_4)
- num <= num + 1;
- else state <= FSM_RD_DATA;
- end
- else begin
- err <= 1;
- state <= FSM_START;
- end
- end
-
- FSM_NACK : begin
- sda_sel <= 1;
- sda_reg <= 1;
- if (cnt == IIC_CNTMAX_4_4)
- state <= FSM_STOP;
- else state <= FSM_NACK;
- end
-
- FSM_STOP : begin
- sda_sel <= 1;
- if (cnt == 0)
- sda_reg <= 0;
- else if (cnt == IIC_CNTMAX_4_2)
- sda_reg <= 1;
-
- if (cnt == IIC_CNTMAX_4_4)
- state <= FSM_DELAY;
- else state <= FSM_STOP;
- end
-
- FSM_DELAY : if (delay_cnt == 999) //延迟20us
- begin
- delay_cnt <= 0;
- done <= 1;
- state <= FSM_START;
- end
- else delay_cnt <= delay_cnt + 1;
-
- default : state <= FSM_START;
- endcase
-
- else
- begin
- state <= FSM_START;
- back_state <= 0;
- rd_data <= rd_data;
- done <= 0;
- sda_sel <= 1;
- sda_reg <= 1;
- delay_cnt <= 0;
- ack <= 1;
- data_reg <= 0;
- num <= 0;
- err <= 0;
- end
-
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。