赞
踩
本实验采用Xilinx artix 7芯片,型号为xc7a35t_2fgg484。
任务目标:设计一个可进行读写操作的 I2C 控制器,实现 FPGA对 EEPROM 存储器的数据写入和数据读取操作。
I2C(Inter-Integrated Circuit)总线协议是一种用于在集成电路(IC)之间进行通信的串行通信协议。它由飞利浦(Philips)公司于上世纪80年代开发,并成为一种广泛应用于各种电子设备中的通信协议。
I2C总线协议使用两根线(SDA和SCL)进行通信。SDA(Serial Data Line)是数据线,用于传输数据,而SCL(Serial Clock Line)是时钟线,用于同步数据传输。这种双线制的结构使得多个IC可以在同一总线上进行通信。
1、主从结构:I2C总线协议采用主从结构。主设备(Master)负责发起通信并控制总线上的时序,而从设备(Slave)则被动地响应主设备的请求。主设备可以与多个从设备进行通信,每个从设备都有一个唯一的地址。
2、数据传输:数据传输通过起始位(2)、地址/数据(3)和停止位(4)来完成。空闲时(1),主设备发起通信时,发送一个起始位(Start)信号,然后发送从设备的地址和读/写指令位。接下来,主设备发送读/写地址并等待从设备响应,接着发送或接收数据,并等待从设备的确认信号。通信结束时,主设备发送停止位(Stop)信号,如图1所示。具体来说,它有4种传输模式:单字节写、多字节写、单字节读、多字节读。值得注意的是,每种读写模式里面须根据从设备存储空间大小来确定WORD ADDRESS的长度,对于一些大容量设备,这里的长度可以为双字节(16bit),每字节地址都需要一个ACK信号。地址和数据都是高位在前、低位在后。
注意,读操作与写操作的不同点在于,主机写完存储地址之后,再次给个start信号,其后再给一次设备地址+读指令位,响应后开始接收读数据。
3、速度和可靠性:I2C总线协议支持多种传输速率,通常有标准模式(100 kbps)和快速模式(400 kbps)。此外,还有高速模式(3.4 Mbps)和超高速模式(5 Mbps)等。总线上的设备可以根据自身的能力选择适当的速率。
I2C总线协议在许多电子设备中得到广泛应用。一些常见的场景包括:
工程主要由3个子模块构成,包括按键消抖模块(通过按键控制读/写)、读写数据模块、i2c驱动模块。整个工程的模块划分如下图所示:
按下数据写操作按键,写触发信号传入按键消抖模块(key_filter),经消抖处理后的写触发信号传入数据收发模块(i2c_rw_data),模块接收到有效的写触发信号后,生成写使能信号、待写入数据、数据地址传入 I2C 驱动模块(i2c_ctrl), I2C 驱动模块按照 I2C 协议将数据写入 EEPROM 存储芯片;
数据写入完成后,按下数据读操作按键,读触发信号传入按键消抖模块(key_filter),经消抖处理后的读触发信号传入数据收发模块(i2c_rw_data),模块接收到有效的读触发信号后,生成读使能信号、数据地址传入 I2C 驱动模块(i2c_ctrl), I2C 驱动模块自 EEPROM存储芯片读取数据,将读取到的数据回传给数据收发模块(i2c_rw_data),数据收发模块将数据暂存,待所有数据均读取完成后,将数据输出。
I2C 驱动模块的主要功能是按照 I2C 协议对 EERPROM 存储芯片执行数据读写操作。
- module i2c_ctrl #(
- parameter sys_clk_freq = 50_000_000,
- i2c_clk_freq = 1_000_000 ,
- i2c_scl_freq = 250_000,
- parameter device_addr_w = 8'b1010_0110,
- device_addr_r = 8'b1010_0111
- )
- (
- input wire sys_clk ,
- input wire sys_rst_n ,
- input wire i2c_start ,
- input wire wr_en ,
- input wire rd_en ,
- input wire [15:0] address ,
- input wire [7:0] wr_data ,
- input wire addr_num ,
-
- inout wire i2c_sda ,
-
- output reg i2c_scl ,
- output reg i2c_clk ,
- output reg [7:0] rd_data ,
- output reg i2c_end
- );
-
-
- localparam IDLE = 5'd1 ,
- START = 5'd2 ,
- SEND_DEV_ADDR = 5'd3 ,
- ACK_1 = 5'd4 ,
- SEND_H = 5'd5 ,
- ACK_2 = 5'd6 ,
- SEND_B_L = 5'd7 ,
- ACK_3 = 5'd8 ,
- WR_DAT = 5'd9 ,
- ACK_4 = 5'd10,
- STOP = 5'd11;
- localparam START_2 = 5'd12,
- SEND_RD_A = 5'd13,
- ACK_5 = 5'd14,
- RD_DAT = 5'd15,
- NO_ACK = 5'd16;
- localparam cnt_sys_clk_max = 5'd24;
-
- reg [4:0] cnt_sys_clk ;
- reg cnt_i2c_clk_en ;
- reg [1:0] cnt_i2c_clk ;
- (*mark_debug="true"*)reg [4:0] state ;
- (*mark_debug="true"*)reg [2:0] cnt_bit ;
- reg ack ;
- reg i2c_sda_out ;
- (*mark_debug="true"*)wire i2c_sda_in ;
- (*mark_debug="true"*)wire sda_en ;
- reg [7:0] rd_data_reg ;
-
- wire ack_flag;
-
- always @(posedge sys_clk or negedge sys_rst_n) //生成i2c_clk时钟
- if (sys_rst_n == 1'b0) begin
- cnt_sys_clk <= 5'b0;
- i2c_clk <= 1'b0;
- end
- else if (cnt_sys_clk == cnt_sys_clk_max) begin
- cnt_sys_clk <= 5'd0;
- i2c_clk <= ~i2c_clk ;
- end
- else
- cnt_sys_clk <= cnt_sys_clk + 5'd1;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c_clk时钟计数起始信号
- if (sys_rst_n == 1'b0)
- cnt_i2c_clk_en <= 1'b0;
- else if (state == STOP && cnt_bit == 3'd3 && cnt_i2c_clk == 2'd3)
- cnt_i2c_clk_en <= 1'b0;
- else if (i2c_start == 1'b1)
- cnt_i2c_clk_en <= 1'b1;
- else
- cnt_i2c_clk_en <= cnt_i2c_clk_en;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c_clk计数生成cnt_bit控制信号
- if (sys_rst_n == 1'b0)
- cnt_i2c_clk <= 2'd0;
- else if (cnt_i2c_clk_en == 1'b1) begin
- if (cnt_i2c_clk == 2'd3)
- cnt_i2c_clk <= 2'd0;
- else
- cnt_i2c_clk <= cnt_i2c_clk + 2'd1;
- end
- else
- cnt_i2c_clk <= 2'd0;
-
- always@(*) //i2c_scl ?
- case (state)
- IDLE:
- i2c_scl <= 1'b1;
- START:if(cnt_i2c_clk == 2'd3)
- i2c_scl <= 1'b0;
- else
- i2c_scl <= 1'b1;
- SEND_DEV_ADDR,ACK_1,SEND_H,ACK_2,SEND_B_L,
- ACK_3,WR_DAT,ACK_4,START_2,SEND_RD_A,ACK_5,RD_DAT,NO_ACK:
- if((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2))
- i2c_scl <= 1'b1;
- else
- i2c_scl <= 1'b0;
- STOP:
- if((cnt_bit == 3'd0) &&(cnt_i2c_clk == 2'd0))
- i2c_scl <= 1'b0;
- else
- i2c_scl <= 1'b1;
- default: i2c_scl <= 1'b1;
- endcase
-
- always @(posedge i2c_clk or negedge sys_rst_n) //收发字节的计 ?
- if (sys_rst_n == 1'b0)
- cnt_bit <= 3'b0;
- else if ((cnt_bit == 3'd7&&cnt_i2c_clk == 2'd3) || (state == ACK_1 || state == ACK_2 || state == ACK_3
- || state == ACK_4 ||state == ACK_5||state == IDLE||state == NO_ACK||state == START_2||state == START)
- ||(state == STOP && cnt_bit == 3'd3&&cnt_i2c_clk == 2'd3))
- cnt_bit <= 3'b0;
- else if ((cnt_i2c_clk == 2'd3) && (state != IDLE))
- cnt_bit <= cnt_bit + 1'd1;
- else
- cnt_bit <= cnt_bit;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //状 ? 机的跳 ?
- if(sys_rst_n == 1'b0)
- state <= IDLE;
- else case(state)
- IDLE:
- if (i2c_start == 1'b1)
- state <= START;
- else
- state <= IDLE;
- START: if (cnt_i2c_clk == 2'd3)
- state <= SEND_DEV_ADDR;
- else
- state <= START;
- SEND_DEV_ADDR: if(cnt_bit == 3'd7 && cnt_i2c_clk==2'd3)
- state <= ACK_1;
- else
- ;
- ACK_1: if(ack == 1'b0 && cnt_i2c_clk==2'd3)begin
- if(addr_num == 1'b0)
- state <= SEND_B_L;
- else
- state <= SEND_H;
- end
- else
- ;
- SEND_H: if(cnt_bit == 3'd7 && cnt_i2c_clk==2'd3)
- state <= ACK_2;
- else
- ;
- ACK_2: if(ack == 1'b0 && cnt_i2c_clk==2'd3)
- state <= SEND_B_L;
- else
- ;
- SEND_B_L: if(cnt_bit == 3'd7 && cnt_i2c_clk==2'd3)
- state <= ACK_3;
- else
- ;
- ACK_3: if(ack == 1'b0 && cnt_i2c_clk==2'd3)begin
- if(rd_en == 1'b1)
- state <= START_2;
- else if(wr_en == 1'b1)
- state <= WR_DAT;
- else
- ;
- end
- else
- ;
- WR_DAT: if(cnt_bit == 3'd7 && cnt_i2c_clk==2'd3)
- state <= ACK_4;
- else
- ;
- ACK_4: if(ack == 1'b0 && cnt_i2c_clk==2'd3)
- state <= STOP;
- else
- ;
- STOP: if(cnt_bit == 3'd3 && cnt_i2c_clk == 2'd3)
- state <= IDLE;
- else
- ;
- START_2: if(cnt_i2c_clk == 2'd3)
- state <= SEND_RD_A;
- else
- ;
- SEND_RD_A: if(cnt_bit == 3'd7 && cnt_i2c_clk == 2'd3)
- state <= ACK_5;
- else
- ;
- ACK_5: if(ack == 1'b0 && cnt_i2c_clk == 2'd3)
- state <= RD_DAT;
- else
- ;
- RD_DAT: if(cnt_bit == 3'd7 && cnt_i2c_clk == 2'd3)
- state <= NO_ACK;
- else
- ;
- NO_ACK: if(i2c_sda_out == 1'b1 && cnt_i2c_clk == 2'd3)
- state <= STOP;
- else
- ;
- default: state <= IDLE;
- endcase
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c的结束信 ?
- if(sys_rst_n == 1'b0)
- i2c_end <= 1'b0;
- else if(state == STOP && cnt_bit == 3'd3 && cnt_i2c_clk ==2'd3)
- i2c_end <= 1'b1;
- else
- i2c_end <= 1'b0;
-
- /*always @(posedge i2c_clk or negedge sys_rst_n) //使用时序逻辑给sda线输出时的数据赋 ?
- if(sys_rst_n == 1'b0)
- i2c_sda_out = 1'b1;
- else if(state == START)
- i2c_sda_out = 1'b0;
- else if(state == START && cnt_i2c_clk == 2'd3)
- i2c_sda_out <= device_addr_w[7];
- else if(state == SEND_DEV_ADDR) begin
- if (cnt_i2c_clk == 2'd3) begin
- case(cnt_bit)
- 0: i2c_sda_out <= device_addr_w[6];
- 1: i2c_sda_out <= device_addr_w[5];
- 2: i2c_sda_out <= device_addr_w[4];
- 3: i2c_sda_out <= device_addr_w[3];
- 4: i2c_sda_out <= device_addr_w[2];
- 5: i2c_sda_out <= device_addr_w[1];
- 6: i2c_sda_out <= device_addr_w[0];
- default: i2c_sda_out <= 1'b1;
- endcase
- end
- else
- ;
- end
- else if(state == ACK_1 && cnt_i2c_clk == 2'd3)
- i2c_sda_out <= address[15];
- else if(state == SEND_H) begin
- if (cnt_i2c_clk == 2'd3) begin
- case(cnt_bit)
- 0: i2c_sda_out <= address[14];
- 1: i2c_sda_out <= address[13];
- 2: i2c_sda_out <= address[12];
- 3: i2c_sda_out <= address[11];
- 4: i2c_sda_out <= address[10];
- 5: i2c_sda_out <= address[9];
- 6: i2c_sda_out <= address[8];
- default: i2c_sda_out <= 1'b1;
- endcase
- end
- else
- ;
- end
- else if(state == ACK_2 && cnt_i2c_clk == 2'd3)
- i2c_sda_out <= address[7];
- else if(state == SEND_B_L) begin
- if (cnt_i2c_clk == 2'd3) begin
- case(cnt_bit)
- 0: i2c_sda_out <= address[6];
- 1: i2c_sda_out <= address[5];
- 2: i2c_sda_out <= address[4];
- 3: i2c_sda_out <= address[3];
- 4: i2c_sda_out <= address[2];
- 5: i2c_sda_out <= address[1];
- 6: i2c_sda_out <= address[0];
- default: i2c_sda_out <= 1'b1 ;
- endcase
- end
- else
- ;
- end
- else if(state == ACK_3 && cnt_i2c_clk == 2'd3)
- i2c_sda_out <= wr_data[7];
- else if(state == WR_DAT) begin
- if (cnt_i2c_clk == 2'd3) begin
- case(cnt_bit)
- 0: i2c_sda_out <= wr_data[6];
- 1: i2c_sda_out <= wr_data[5];
- 2: i2c_sda_out <= wr_data[4];
- 3: i2c_sda_out <= wr_data[3];
- 4: i2c_sda_out <= wr_data[2];
- 5: i2c_sda_out <= wr_data[1];
- 6: i2c_sda_out <= wr_data[0];
- default: i2c_sda_out <= 1'b1 ;
- endcase
- end
- else
- ;
- end
- else if(state == ACK_4 && cnt_i2c_clk == 2'd3)
- i2c_sda_out <= 1'b0;
- else if(state == START_2 && cnt_i2c_clk == 2'd1) //随机写操作的 ? ?
- i2c_sda_out <= 1'b0;
- else if(state == START_2 && cnt_i2c_clk == 2'd3)
- i2c_sda_out <= device_addr_r[7];
- else if(state == SEND_RD_A) begin
- if (cnt_i2c_clk == 2'd3) begin
- case(cnt_bit)
- 0: i2c_sda_out <= device_addr_r[6];
- 1: i2c_sda_out <= device_addr_r[5];
- 2: i2c_sda_out <= device_addr_r[4];
- 3: i2c_sda_out <= device_addr_r[3];
- 4: i2c_sda_out <= device_addr_r[2];
- 5: i2c_sda_out <= device_addr_r[1];
- 6: i2c_sda_out <= device_addr_r[0];
- default: i2c_sda_out <= 1'b1 ;
- endcase
- end
- else
- ;
- end
- else if(state == NO_ACK && cnt_i2c_clk == 2'd3)
- i2c_sda_out <= 1'b0;
- else if(state == STOP && cnt_i2c_clk == 2'd2)
- i2c_sda_out <= 1'b1;
- else if(state == IDLE)
- i2c_sda_out <= 1'b1;
- else
- i2c_sda_out <= i2c_sda_out;
- always @(posedge i2c_scl or negedge sys_rst_n) //sda作为输入时,接收到的数据串转 ?
- if(sys_rst_n == 1'b0)
- rd_data <= 8'b0;
- else if(state == RD_DAT && cnt_i2c_clk == 2'd2) begin
- rd_data= {rd_data[6:0],i2c_sda_in};
- end
- else if(state == IDLE)
- rd_data <= 8'b0;
- else
- ;
- */
-
- always @(*)
- case(state)
- IDLE,START,SEND_DEV_ADDR,SEND_H,SEND_B_L,WR_DAT,STOP,START_2,SEND_RD_A,RD_DAT,NO_ACK:
- ack <= 1'b1;
- ACK_1,ACK_2,ACK_3,ACK_4,ACK_5:
- if(cnt_i2c_clk == 2'd0)
- ack <= i2c_sda;
- else
- ack <= ack;
- default : ack <= 1'b1;
- endcase
-
- always @(*) //使用组合逻辑对sda线的输出和读取寄存器赋 ??,更方 ?
- case(state)
- IDLE:
- begin
- i2c_sda_out <= 1'b1;
- rd_data_reg <= 8'd0;
- end
- START:
- i2c_sda_out <= 1'b0;
- SEND_DEV_ADDR:
- if(cnt_bit <= 3'd7)
- i2c_sda_out <= device_addr_w[7 - cnt_bit];
- else
- ;
- ACK_1:
- i2c_sda_out <= 1'b1;
- SEND_H:
- i2c_sda_out <= address[15-cnt_bit];
- ACK_2:
- i2c_sda_out <= 1'b1;
- SEND_B_L:
- i2c_sda_out <= address[7-cnt_bit];
- ACK_3:
- i2c_sda_out <= 1'b1;
- WR_DAT:
- i2c_sda_out <= wr_data[7-cnt_bit];
- ACK_4:
- i2c_sda_out <= 1'b1;
- STOP:
- if(cnt_bit == 3'd0 && cnt_i2c_clk < 2'd3)
- i2c_sda_out <= 1'b0;
- else
- i2c_sda_out <= 1'b1;
-
- START_2:
- if(cnt_i2c_clk == 2'd0)
- i2c_sda_out <= 1'b1;
- else if(cnt_i2c_clk == 2'd2)
- i2c_sda_out <= 1'b0;
- else
- ;
- SEND_RD_A:
- i2c_sda_out <= device_addr_r[7-cnt_bit];
- ACK_5:
- i2c_sda_out <= 1'b1;
- RD_DAT:
- if(cnt_i2c_clk == 2'd2)
- rd_data_reg[7-cnt_bit] <= i2c_sda_in;
- else
- rd_data_reg <= rd_data_reg;
- default: begin
- i2c_sda_out <= 1'b1;
- rd_data_reg <= rd_data_reg;
- end
- endcase
- always @(posedge i2c_clk or negedge sys_rst_n) //读数据输出赋 ?
- if(sys_rst_n == 1'b0)
- rd_data <= 8'd0;
- else if(state == RD_DAT && cnt_bit == 3'd7 && cnt_i2c_clk == 2'd3)
- rd_data <= rd_data_reg; //在读数据寄存器收集数据完成后赋 ??
- else
- ;
-
- //assign ack = ((state == ACK_1) || (state == ACK_2) ||(state == ACK_3) || (state == ACK_4) || (state == ACK_5)) ? i2c_sda_in: 1'b1;
- assign i2c_sda_in = i2c_sda; //sda作为输入时,接收到的数据
- assign sda_en = ( (state == ACK_1) || (state == ACK_2) ||(state == ACK_3) || (state == ACK_4) || (state == ACK_5)|| (state == RD_DAT)) ? 1'b0 : 1'b1;
- assign i2c_sda = (sda_en == 1'b1) ? i2c_sda_out : 1'bz; //数据使能时作为输出,否则输出为高阻 ??
-
-
- //IOBUF #(
- // .DRIVE(12), // Specify the output drive strength
- // .IBUF_LOW_PWR("FALSE"), // Low Power - "TRUE", High Performance = "FALSE"
- // .IOSTANDARD("DEFAULT"), // Specify the I/O standard
- // .SLEW("SLOW") // Specify the output slew rate
- // ) IOBUF_i2c(
- // .O(i2c_sda_in), // Buffer output
- // .IO(i2c_sda), // Buffer inout port (connect directly to top-level port)
- // .I(i2c_sda_out), // Buffer input
- // .T(~sda_en) // 3-state enable input, high=input, low=output
- // );
-
- endmodule
数据收发模块的主要功能是:为 I2C 驱动模块提供读/写数据存储地址、待写入数据以及作为 EEPROM 读出数据缓存。
- module i2c_rw_data(
- input wire sys_clk ,
- input wire sys_rst_n ,
- input wire write ,
- input wire read ,
- input wire i2c_clk ,
- input wire [7:0] rd_data ,
- input wire i2c_end ,
- output reg i2c_start ,
- output reg wr_en ,
- output reg rd_en ,
- output reg [15:0] byte_addr ,
- output reg [7:0] wr_data ,
- output wire[7:0] fifo_rd_data
- );
- parameter cnt_sys_clk_m = 8'd200, cnt_wr_m = 4'd10,
- cnt_start_m = 32'd4999,cnt_fifo_wait_m=28'd499999;
-
-
- reg [7:0] cnt_wr_valid;
- reg [7:0] cnt_rd_valid;
- reg wr_valid ;
- reg rd_valid ;
-
- reg [31:0] cnt_i2c_start; //每次“开始 ? 信号的间隔时间
- reg [3:0] cnt_wr ; //发 ? 数据个数计 ?
- reg [3:0] cnt_rd ; //读取数据个数计数
-
-
- reg fifo_rd_valid; //fifo读取有效信号
- reg [27:0] cnt_fifo_wait; //每次从FIFO读出数据的时间间隔,方便观察
- reg fifo_rd_en ; //从fifo读数据的使能信号
- reg [3:0] rd_fifo_num ; //从fifo读出数据的个 ?
- wire [7:0] fifo_num ; //fifo中的数据个数
- wire full ;
- wire empty ;
-
- always @(posedge sys_clk or negedge sys_rst_n) //信号从高频到低频跨时钟域,延 ?
- if(sys_rst_n == 1'b0) begin
- cnt_wr_valid <= 8'd0;
- wr_valid <= 1'b0;
- cnt_rd_valid <= 8'd0;
- rd_valid <= 1'b0;
- end
- else if (cnt_wr_valid == cnt_sys_clk_m) begin
- cnt_wr_valid <= 8'd0;
- wr_valid <= 1'b0;
- end
- else if (write == 1'b1)
- wr_valid <= 1'b1;
- else if (wr_valid == 1'b1)
- cnt_wr_valid <= cnt_wr_valid + 8'd1;
- else if (cnt_rd_valid == cnt_sys_clk_m)begin
- cnt_rd_valid <= 8'd0;
- rd_valid <= 1'b0;
- end
- else if(read == 1'b1)
- rd_valid <= 1'b1;
- else if(rd_valid == 1'b1)
- cnt_rd_valid <= cnt_rd_valid + 8'd1;
- else begin
- wr_valid <= wr_valid;
- rd_valid <= rd_valid;
- end
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c的读写使能信 ?
- if(sys_rst_n == 1'b0) begin
- wr_en <= 1'b0;
- rd_en <= 1'b0;
- end
- else if(wr_valid == 1'b1)
- wr_en <= 1'b1;
- else if (rd_valid == 1'b1)
- rd_en <= 1'b1;
- else if (cnt_wr == cnt_wr_m - 1 && i2c_end == 1'b1)
- wr_en <= 1'b0;
- else if (cnt_rd == cnt_wr_m - 1 && i2c_end == 1'b1)
- rd_en <= 1'b0;
- else
- ;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c的开始信 ?
- if(sys_rst_n == 1'b0)
- cnt_i2c_start <= 32'd0;
- else if(cnt_i2c_start == cnt_start_m)
- cnt_i2c_start <= 32'd0;
- else if(wr_en == 1'b0 && rd_en == 1'b0)
- cnt_i2c_start <= 32'd0;
- else if(wr_en == 1'b1 || rd_en == 1'b1)
- cnt_i2c_start <= cnt_i2c_start + 32'd1;
- else
- ;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c的开始信 ?
- if(sys_rst_n == 1'b0)
- i2c_start <= 1'b0;
- else if(cnt_i2c_start == cnt_start_m)
- i2c_start <= 1'b1;
- else
- i2c_start <= 1'b0;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c写 ? 读的次数计 ?
- if(sys_rst_n == 1'b0)
- cnt_wr <= 4'd0;
- else if(wr_en == 1'b0)
- cnt_wr <= 4'd0;
- else if((i2c_end == 1'b1) && (wr_en == 1'b1))
- cnt_wr <= cnt_wr + 4'd1;
- else
- ;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c写 ? 读的次数计 ?
- if(sys_rst_n == 1'b0)
- cnt_rd <= 4'd0;
- else if(rd_en == 1'b0)
- cnt_rd <= 4'd0;
- else if((i2c_end == 1'b1) && (rd_en == 1'b1))
- cnt_rd <= cnt_rd + 4'd1;
- else
- ;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //fifo读有效信 ?
- if(sys_rst_n == 1'b0)
- fifo_rd_valid <= 1'b0;
- else if (cnt_rd == 4'd10)
- fifo_rd_valid <= 1'b1;
- else if(rd_fifo_num == 8'd10 && cnt_fifo_wait == cnt_fifo_wait_m)
- fifo_rd_valid <= 1'b0;
- else
- ;
- always @(posedge i2c_clk or negedge sys_rst_n) //每次从fifo读数据的等待时间
- if(sys_rst_n == 1'b0)
- cnt_fifo_wait <= 28'b0;
- else if(cnt_fifo_wait == cnt_fifo_wait_m)
- cnt_fifo_wait <= 28'd0;
- else if(fifo_rd_valid == 1'b1)
- cnt_fifo_wait <= cnt_fifo_wait + 28'd1;
- else if(fifo_rd_valid == 1'b0)
- cnt_fifo_wait <= 28'd0;
- else
- ;
- always @(posedge i2c_clk or negedge sys_rst_n) //fifo读使能信 ?
- if(sys_rst_n == 1'b0)
- fifo_rd_en <= 1'b0;
- else if(fifo_rd_valid == 1'b1 && (cnt_fifo_wait==cnt_fifo_wait_m))
- fifo_rd_en <= 1'b1;
- else
- fifo_rd_en <= 1'b0;
- always @(posedge i2c_clk or negedge sys_rst_n) //从FIFO中读取的次数
- if(sys_rst_n == 1'b0)
- rd_fifo_num <= 4'd0;
- else if(fifo_rd_en == 1'b1)
- rd_fifo_num <= rd_fifo_num + 4'd1;
- else if(fifo_rd_valid == 1'b0)
- rd_fifo_num <= 4'd0;
- else
- ;
-
- always @(posedge i2c_clk or negedge sys_rst_n) //i2c写入的eeprom存储地址和数 ?
- if(sys_rst_n == 1'b0 ) begin
- byte_addr <= 16'h005a;
- wr_data <= 8'h01;
- end
- else if(((cnt_wr == 4'd9)||(cnt_rd == 4'd9)) && i2c_end == 1'b1)begin
- byte_addr <= 16'h005a;
- wr_data <= 8'h01;
- end
- else if((rd_en == 1'b1) && (i2c_end == 1'b1)&&(wr_en == 1'b0))
- byte_addr <= byte_addr + 16'h1;
- else if((wr_en == 1'b1) && (i2c_end == 1'b1)) begin
- wr_data <= wr_data + 8'h1;
- byte_addr <= byte_addr + 16'h1;
- end
- else
- ;
-
- fifo_i2c_read fifo_i2c_read_i2c(
- .clk(i2c_clk ), // input wire clk
- .din(rd_data ), // input wire [7 : 0] din
- .wr_en(rd_en && i2c_end ), // input wire wr_en
- .rd_en(fifo_rd_en ), // input wire rd_en
- .dout(fifo_rd_data ), // output wire [7 : 0] dout
- .full(full ), // output wire full
- .empty(empty ), // output wire empty
- .data_count(fifo_num ) // output wire [7 : 0] data_count
- );
-
-
- endmodule
- module key_filter
- #(
- parameter cnt_max=20'd999_999
- )
- (
- input clk,
- input rst_n,
- input key_n,
-
- output key_flag
- );
- reg [19:0] cnt_20ms;
- reg key_flag1;
- always @(posedge clk or negedge rst_n)
- if(rst_n == 1'b0)
- cnt_20ms <= 20'd0;
- else if(cnt_20ms == cnt_max)
- cnt_20ms <= cnt_max;
- else if(key_n == 1'b1)
- cnt_20ms <= 20'd0;
- else
- cnt_20ms <= cnt_20ms+1'd1;
-
- always @(posedge clk or negedge rst_n)
- if(rst_n == 1'b0)
- key_flag1 <= 1'b0;
- else if (cnt_20ms == cnt_max - 20'd1)
- key_flag1 <= 1'b1;
- else
- key_flag1 <= 1'b0;
-
- assign key_flag = key_flag1;
- endmodule
- module i2c_eeprom(
- input sys_clk ,
- input sys_rst_n ,
- input [1:0] key ,
- output reg [2:0] led ,
- output i2c_scl ,
- output i2c_sda
- );
- wire write;
- wire read ;
-
- wire i2c_clk;
- wire i2c_end;
- wire [7:0] i2c_rd_data;
- wire i2c_start ;
- wire wr_en ;
- wire rd_en ;
- wire [15:0] byte_addr ;
- wire [7:0] wr_data ;
- wire [7:0] fifo_rd_data;
-
- always @(*)
- if(sys_rst_n == 1'b0)
- led <= 3'b000;
- else if(wr_data == 8'h0a)
- led <= 3'b001;
- else if (i2c_rd_data == 8'h0a)
- led <= 3'b011;
- else if (fifo_rd_data == 8'h0a)
- led <= 3'b111;
- else
- ;
-
- key_filter
- #(
- .cnt_max (20'd999_999)
- )key_filter_a
- (
- .clk ( sys_clk ),
- .rst_n ( sys_rst_n ),
- .key_n ( key[0] ),
-
- .key_flag ( write )
- );
-
- key_filter
- #(
- .cnt_max (20'd999_999)
- )key_filter_b
- (
- .clk ( sys_clk ),
- .rst_n ( sys_rst_n ),
- .key_n ( key[1] ),
-
- .key_flag ( read )
- );
-
- i2c_rw_data i2c_rw_data_inst(
- .sys_clk ( sys_clk ),
- .sys_rst_n ( sys_rst_n ),
- .write ( write ),
- .read ( read ),
- .i2c_clk ( i2c_clk ),
- .rd_data ( i2c_rd_data ),
- .i2c_end ( i2c_end ),
- .i2c_start ( i2c_start ),
- .wr_en ( wr_en ),
- .rd_en ( rd_en ),
- .byte_addr ( byte_addr ),
- .wr_data ( wr_data ),
- .fifo_rd_data ( fifo_rd_data )
- );
-
- i2c_ctrl #(
- .sys_clk_freq (50_000_000),
- .i2c_clk_freq (1_000_000 ),
- .i2c_scl_freq (250_000 ),
- .device_addr_w (8'b1010_0110),
- .device_addr_r (8'b1010_0111)
- )i2c_ctrl_top
- (
- .sys_clk ( sys_clk ),
- .sys_rst_n ( sys_rst_n ),
- .i2c_start ( i2c_start ),
- .wr_en ( wr_en ),
- .rd_en ( rd_en ),
- .address ( byte_addr ),
- .wr_data ( wr_data ),
- .addr_num ( 1'b1 ), // i2c ַ ֽ
-
- .i2c_sda ( i2c_sda ),
-
- .i2c_scl ( i2c_scl ),
- .i2c_clk ( i2c_clk ),
- .rd_data ( i2c_rd_data ),
- .i2c_end ( i2c_end )
- );
-
- ila_i2c_eeprom ila_i2c_eeprom_inst(
- .clk(sys_clk), // input wire clk
-
-
- .probe0(sys_rst_n), // input wire [0:0] probe0
- .probe1(key), // input wire [1:0] probe1
- .probe2(i2c_clk), // input wire [0:0] probe2
- .probe3(i2c_rd_data), // input wire [7:0] probe3
- .probe4(wr_data), // input wire [7:0] probe4
- .probe5(i2c_end), // input wire [0:0] probe5
- .probe6(i2c_scl), // input wire [0:0] probe6
- .probe7(i2c_sda), // input wire [0:0] probe7
- .probe8(rd_en) // input wire [0:0] probe8
- );
-
- endmodule
- module i2c_eeprom_tb( );
-
- reg sys_clk ;
- reg sys_rst_n ;
- reg [1:0] key ;
-
- wire [2:0] led ;
- wire i2c_scl ;
- wire i2c_sda ;
-
- initial
- begin
- sys_clk <= 1'b1;
- sys_rst_n <= 1'b0;
- key <= 2'b11;
- #200
- sys_rst_n <= 1'b1;
- #2000
- key <= 2'b10;
- #400
- key <= 2'b11;
- #51_000_000
- key <= 2'b01;
- #400
- key <= 2'b11;
- end
-
-
-
- always #10 sys_clk = ~sys_clk;
-
- defparam i2c_eeprom_testbench.key_filter_a.cnt_max = 5;
- defparam i2c_eeprom_testbench.key_filter_b.cnt_max = 5;
- defparam i2c_eeprom_testbench.i2c_rw_data_inst.cnt_fifo_wait_m = 28'd1000;
- defparam i2c_eeprom_testbench.i2c_ctrl_top.device_addr_w = 8'b1010_0000;
- defparam i2c_eeprom_testbench.i2c_ctrl_top.device_addr_r = 8'b1010_0001;
-
- i2c_eeprom i2c_eeprom_testbench(
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n ),
- .key (key ),
- .led ( led ),
- .i2c_scl (i2c_scl ),
- .i2c_sda (i2c_sda )
- );
-
- M24LC64 M24LC64_inst(
- .A0 ( 1'b0 ), // ַ
- .A1 ( 1'b0 ), // ַ
- .A2 ( 1'b0 ), // ַ
- .WP ( 1'b0 ), //д źţ ߵ ƽ Ч
- .SDA ( i2c_sda ),
- .SCL ( i2c_scl ),
- .RESET ( ~sys_rst_n )
- );
-
- endmodule
其中,M24LC64为EEPROM器件的fpga实现,相关v文件在网上查得,供参考。
- `timescale 1ns/10ps
- module M24LC64 (A0, A1, A2, WP, SDA, SCL, RESET);
-
- input A0; // chip select bit
- input A1; // chip select bit
- input A2; // chip select bit
-
- input WP; // write protect pin
-
- inout SDA; // serial data I/O
- input SCL; // serial data clock
-
- input RESET; // system reset
-
-
- // *******************************************************************************************************
- // ** DECLARATIONS **
- // *******************************************************************************************************
-
- reg SDA_DO; // serial data - output
- reg SDA_OE; // serial data - output enable
-
- wire SDA_DriveEnable; // serial data output enable
- reg SDA_DriveEnableDlyd; // serial data output enable - delayed
-
- wire [02:00] ChipAddress; // hardwired chip address
-
- reg [03:00] BitCounter; // serial bit counter
-
- reg START_Rcvd; // START bit received flag
- reg STOP_Rcvd; // ACK_4 bit received flag
- reg CTRL_Rcvd; // control byte received flag
- reg ADHI_Rcvd; // byte address hi received flag
- reg ADLO_Rcvd; // byte address lo received flag
- reg MACK_Rcvd; // master acknowledge received flag
-
- reg WrCycle; // memory write cycle
- reg RdCycle; // memory read cycle
-
- reg [07:00] ShiftRegister; // input data shift register
-
- reg [07:00] ControlByte; // control byte register
- wire RdWrBit; // read/write control bit
-
- reg [12:00] StartAddress; // memory access starting address
- reg [04:00] PageAddress; // memory page address
-
- reg [07:00] WrDataByte [0:31]; // memory write data buffer
- wire [07:00] RdDataByte; // memory read data
-
- reg [15:00] WrCounter; // write buffer counter
-
- reg [04:00] WrPointer; // write buffer pointer
- reg [12:00] RdPointer; // read address pointer
-
- reg WriteActive; // memory write cycle active
-
- reg [07:00] MemoryBlock [0:8191]; // EEPROM data memory array
-
- integer LoopIndex; // iterative loop index
-
- integer tAA; // timing parameter
- integer tWC; // timing parameter
-
-
- // *******************************************************************************************************
- // ** INITIALIZATION **
- // *******************************************************************************************************
-
- //----------------------------
- //------写数据间隔改 ?----------
- initial tAA = 900; // SCL to SDA output delay
- initial tWC = 500; // memory write cycle time
-
- // initial tAA = 900; // SCL to SDA output delay
- // initial tWC = 5000000; // memory write cycle time
-
-
- initial begin
- SDA_DO = 0;
- SDA_OE = 0;
- end
-
- initial begin
- START_Rcvd = 0;
- STOP_Rcvd = 0;
- CTRL_Rcvd = 0;
- ADHI_Rcvd = 0;
- ADLO_Rcvd = 0;
- MACK_Rcvd = 0;
- end
-
- initial begin
- BitCounter = 0;
- ControlByte = 0;
- end
-
- initial begin
- WrCycle = 0;
- RdCycle = 0;
-
- WriteActive = 0;
- end
-
- assign ChipAddress = {A2,A1,A0};
-
-
- // *******************************************************************************************************
- // ** CORE LOGIC **
- // *******************************************************************************************************
- // -------------------------------------------------------------------------------------------------------
- // 1.01: START Bit Detection
- // -------------------------------------------------------------------------------------------------------
-
- always @(negedge SDA) begin
- if (SCL == 1) begin
- START_Rcvd <= 1;
- STOP_Rcvd <= 0;
- CTRL_Rcvd <= 0;
- ADHI_Rcvd <= 0;
- ADLO_Rcvd <= 0;
- MACK_Rcvd <= 0;
-
- WrCycle <= #1 0;
- RdCycle <= #1 0;
-
- BitCounter <= 0;
- end
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.02: ACK_4 Bit Detection
- // -------------------------------------------------------------------------------------------------------
-
- always @(posedge SDA) begin
- if (SCL == 1) begin
- START_Rcvd <= 0;
- STOP_Rcvd <= 1;
- CTRL_Rcvd <= 0;
- ADHI_Rcvd <= 0;
- ADLO_Rcvd <= 0;
- MACK_Rcvd <= 0;
-
- WrCycle <= #1 0;
- RdCycle <= #1 0;
-
- BitCounter <= 10;
- end
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.03: Input Shift Register
- // -------------------------------------------------------------------------------------------------------
-
- always @(posedge SCL) begin
- ShiftRegister[00] <= SDA;
- ShiftRegister[01] <= ShiftRegister[00];
- ShiftRegister[02] <= ShiftRegister[01];
- ShiftRegister[03] <= ShiftRegister[02];
- ShiftRegister[04] <= ShiftRegister[03];
- ShiftRegister[05] <= ShiftRegister[04];
- ShiftRegister[06] <= ShiftRegister[05];
- ShiftRegister[07] <= ShiftRegister[06];
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.04: Input Bit Counter
- // -------------------------------------------------------------------------------------------------------
-
- always @(posedge SCL) begin
- if (BitCounter < 10) BitCounter <= BitCounter + 1;
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.05: Control Byte Register
- // -------------------------------------------------------------------------------------------------------
-
- always @(negedge SCL) begin
- if (START_Rcvd & (BitCounter == 8)) begin
- if (!WriteActive & (ShiftRegister[07:01] == {4'b1010,ChipAddress[02:00]})) begin
- if (ShiftRegister[00] == 0) WrCycle <= 1;
- if (ShiftRegister[00] == 1) RdCycle <= 1;
-
- ControlByte <= ShiftRegister[07:00];
-
- CTRL_Rcvd <= 1;
- end
-
- START_Rcvd <= 0;
- end
- end
-
- assign RdWrBit = ControlByte[00];
-
- // -------------------------------------------------------------------------------------------------------
- // 1.06: Byte Address Register
- // -------------------------------------------------------------------------------------------------------
-
- always @(negedge SCL) begin
- if (CTRL_Rcvd & (BitCounter == 8)) begin
- if (RdWrBit == 0) begin
- StartAddress[12:08] <= ShiftRegister[04:00];
- RdPointer[12:08] <= ShiftRegister[04:00];
-
- ADHI_Rcvd <= 1;
- end
-
- WrCounter <= 0;
- WrPointer <= 0;
-
- CTRL_Rcvd <= 0;
- end
- end
-
- always @(negedge SCL) begin
- if (ADHI_Rcvd & (BitCounter == 8)) begin
- if (RdWrBit == 0) begin
- StartAddress[07:00] <= ShiftRegister[07:00];
- RdPointer[07:00] <= ShiftRegister[07:00];
-
- ADLO_Rcvd <= 1;
- end
-
- WrCounter <= 0;
- WrPointer <= 0;
-
- ADHI_Rcvd <= 0;
- end
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.07: Write Data Buffer
- // -------------------------------------------------------------------------------------------------------
-
- always @(negedge SCL) begin
- if (ADLO_Rcvd & (BitCounter == 8)) begin
- if (RdWrBit == 0) begin
- WrDataByte[WrPointer] <= ShiftRegister[07:00];
-
- WrCounter <= WrCounter + 1;
- WrPointer <= WrPointer + 1;
- end
- end
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.08: Acknowledge Generator
- // -------------------------------------------------------------------------------------------------------
-
- always @(negedge SCL) begin
- if (!WriteActive) begin
- if (BitCounter == 8) begin
- if (WrCycle | (START_Rcvd & (ShiftRegister[07:01] == {4'b1010,ChipAddress[02:00]}))) begin
- SDA_DO <= 0;
- SDA_OE <= 1;
- end
- end
- if (BitCounter == 9) begin
- BitCounter <= 0;
-
- if (!RdCycle) begin
- SDA_DO <= 0;
- SDA_OE <= 0;
- end
- end
- end
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.09: Acknowledge Detect
- // -------------------------------------------------------------------------------------------------------
-
- always @(posedge SCL) begin
- if (RdCycle & (BitCounter == 8)) begin
- if ((SDA == 0) & (SDA_OE == 0)) MACK_Rcvd <= 1;
- end
- end
-
- always @(negedge SCL) MACK_Rcvd <= 0;
-
- // -------------------------------------------------------------------------------------------------------
- // 1.10: Write Cycle Timer
- // -------------------------------------------------------------------------------------------------------
-
- always @(posedge STOP_Rcvd) begin
- if (WrCycle & (WP == 0) & (WrCounter > 0)) begin
- WriteActive = 1;
- #(tWC);
- WriteActive = 0;
- end
- end
-
- always @(posedge STOP_Rcvd) begin
- #(1.0);
- STOP_Rcvd = 0;
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.11: Write Cycle Processor
- // -------------------------------------------------------------------------------------------------------
-
- always @(negedge WriteActive) begin
- for (LoopIndex = 0; LoopIndex < WrCounter; LoopIndex = LoopIndex + 1) begin
- PageAddress = StartAddress[04:00] + LoopIndex;
-
- MemoryBlock[{StartAddress[12:05],PageAddress[04:00]}] = WrDataByte[LoopIndex[04:00]];
- end
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.12: Read Data Multiplexor
- // -------------------------------------------------------------------------------------------------------
-
- always @(negedge SCL) begin
- if (BitCounter == 8) begin
- if (WrCycle & ADLO_Rcvd) begin
- RdPointer <= StartAddress + WrPointer + 1;
- end
- if (RdCycle) begin
- RdPointer <= RdPointer + 1;
- end
- end
- end
-
- assign RdDataByte = MemoryBlock[RdPointer[12:00]];
-
- // -------------------------------------------------------------------------------------------------------
- // 1.13: Read Data Processor
- // -------------------------------------------------------------------------------------------------------
-
- always @(negedge SCL) begin
- if (RdCycle) begin
- if (BitCounter == 8) begin
- SDA_DO <= 0;
- SDA_OE <= 0;
- end
- else if (BitCounter == 9) begin
- SDA_DO <= RdDataByte[07];
-
- if (MACK_Rcvd) SDA_OE <= 1;
- end
- else begin
- SDA_DO <= RdDataByte[7-BitCounter];
- end
- end
- end
-
- // -------------------------------------------------------------------------------------------------------
- // 1.14: SDA Data I/O Buffer
- // -------------------------------------------------------------------------------------------------------
-
- bufif1 (SDA, 1'b0, SDA_DriveEnableDlyd);
-
- assign SDA_DriveEnable = !SDA_DO & SDA_OE;
- always @(SDA_DriveEnable) SDA_DriveEnableDlyd <= #(tAA) SDA_DriveEnable;
-
-
- // *******************************************************************************************************
- // ** DEBUG LOGIC **
- // *******************************************************************************************************
- // -------------------------------------------------------------------------------------------------------
- // 2.01: Memory Data Bytes
- // -------------------------------------------------------------------------------------------------------
-
- wire [07:00] MemoryByte_000 = MemoryBlock[00];
- wire [07:00] MemoryByte_001 = MemoryBlock[01];
- wire [07:00] MemoryByte_002 = MemoryBlock[02];
- wire [07:00] MemoryByte_003 = MemoryBlock[03];
- wire [07:00] MemoryByte_004 = MemoryBlock[04];
- wire [07:00] MemoryByte_005 = MemoryBlock[05];
- wire [07:00] MemoryByte_006 = MemoryBlock[06];
- wire [07:00] MemoryByte_007 = MemoryBlock[07];
- wire [07:00] MemoryByte_008 = MemoryBlock[08];
- wire [07:00] MemoryByte_009 = MemoryBlock[09];
- wire [07:00] MemoryByte_00A = MemoryBlock[10];
- wire [07:00] MemoryByte_00B = MemoryBlock[11];
- wire [07:00] MemoryByte_00C = MemoryBlock[12];
- wire [07:00] MemoryByte_00D = MemoryBlock[13];
- wire [07:00] MemoryByte_00E = MemoryBlock[14];
- wire [07:00] MemoryByte_00F = MemoryBlock[15];
-
- // -------------------------------------------------------------------------------------------------------
- // 2.02: Write Data Buffer
- // -------------------------------------------------------------------------------------------------------
-
- wire [07:00] WriteData_00 = WrDataByte[00];
- wire [07:00] WriteData_01 = WrDataByte[01];
- wire [07:00] WriteData_02 = WrDataByte[02];
- wire [07:00] WriteData_03 = WrDataByte[03];
- wire [07:00] WriteData_04 = WrDataByte[04];
- wire [07:00] WriteData_05 = WrDataByte[05];
- wire [07:00] WriteData_06 = WrDataByte[06];
- wire [07:00] WriteData_07 = WrDataByte[07];
- wire [07:00] WriteData_08 = WrDataByte[08];
- wire [07:00] WriteData_09 = WrDataByte[09];
- wire [07:00] WriteData_0A = WrDataByte[10];
- wire [07:00] WriteData_0B = WrDataByte[11];
- wire [07:00] WriteData_0C = WrDataByte[12];
- wire [07:00] WriteData_0D = WrDataByte[13];
- wire [07:00] WriteData_0E = WrDataByte[14];
- wire [07:00] WriteData_0F = WrDataByte[15];
-
- wire [07:00] WriteData_10 = WrDataByte[16];
- wire [07:00] WriteData_11 = WrDataByte[17];
- wire [07:00] WriteData_12 = WrDataByte[18];
- wire [07:00] WriteData_13 = WrDataByte[19];
- wire [07:00] WriteData_14 = WrDataByte[20];
- wire [07:00] WriteData_15 = WrDataByte[21];
- wire [07:00] WriteData_16 = WrDataByte[22];
- wire [07:00] WriteData_17 = WrDataByte[23];
- wire [07:00] WriteData_18 = WrDataByte[24];
- wire [07:00] WriteData_19 = WrDataByte[25];
- wire [07:00] WriteData_1A = WrDataByte[26];
- wire [07:00] WriteData_1B = WrDataByte[27];
- wire [07:00] WriteData_1C = WrDataByte[28];
- wire [07:00] WriteData_1D = WrDataByte[29];
- wire [07:00] WriteData_1E = WrDataByte[30];
- wire [07:00] WriteData_1F = WrDataByte[31];
-
-
- // *******************************************************************************************************
- // ** TIMING CHECKS **
- // *******************************************************************************************************
-
- wire TimingCheckEnable = (RESET == 0) & (SDA_OE == 0);
- wire StopTimingCheckEnable = TimingCheckEnable && SCL;
-
- //--------------------------------
- //-------仿真时时序约束需改动--------
- //--------------------------------
- specify
- specparam
- tHI = 600, // SCL pulse width - high
- // tLO = 1300, // SCL pulse width - low
- tLO = 600,
- tSU_STA = 600, // SCL to SDA setup time
- tHD_STA = 600, // SCL to SDA hold time
- tSU_DAT = 100, // SDA to SCL setup time
- tSU_STO = 600, // SCL to SDA setup time
- tSU_WP = 600, // WP to SDA setup time
- tHD_WP = 1300, // WP to SDA hold time
- // tBUF = 1300; // Bus free time
- tBUF = 600;
-
- $width (posedge SCL, tHI);
- $width (negedge SCL, tLO);
-
- $width (posedge SDA &&& SCL, tBUF);
-
- $setup (posedge SCL, negedge SDA &&& TimingCheckEnable, tSU_STA);
- $setup (SDA, posedge SCL &&& TimingCheckEnable, tSU_DAT);
- $setup (posedge SCL, posedge SDA &&& TimingCheckEnable, tSU_STO);
- $setup (WP, posedge SDA &&& StopTimingCheckEnable, tSU_WP);
-
- $hold (negedge SDA &&& TimingCheckEnable, negedge SCL, tHD_STA);
- $hold (posedge SDA &&& StopTimingCheckEnable, WP, tHD_WP);
- endspecify
-
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。