PS:EEPROM单次写时间比较长,24LC64要5ms,才能进行读操作,否则不会响应地址,示波器观察的。
1‘给出单次写仿真图1;(sda上面的蓝色是主从三态门切换时候,未知态,实测波形,也会有小尖峰出现)
2’给出单次读仿真图2;
3‘给出main代码;(用quartus的issp观察数据的)
4’给出testbench代码;(添加了24LC64的verilog模型,读数据不能显示,显示的高阻态)
图一
图2
main代码
module eeprom_iic ( input sys_clk, input sys_rst_n, output reg iic_sck, inout wire iic_sda ); reg [3:0] current_state; reg [3:0] next_state; reg [7:0] clk_1mhz_cnt; reg flag; reg [7:0] clk_1mhz_bit; reg [11:0] cnt_byte; reg sda; reg write_flag; wire read_flag; reg ack; reg [7:0] rd_data_reg; reg [7:0] rd_data; wire sda_ctrl; wire [7:0] D_ADDR_DATA; wire [7:0] B_ADDR_H_DATA; wire [7:0] B_ADDR_L_DATA; wire [7:0] WR_DATA_DATA; wire [7:0] RD_ADDR_DATA; //~~~~~~~~~~~~~~~~~~~~~~~~~~parameter~~~~~~~~~~~~~~~~~~~~~~ parameter IDLE = 4'd00; parameter START_1 = 4'd01; parameter SEND_D_ADDR = 4'd02; parameter ACK_1 = 4'd03; parameter SEND_B_ADDR_H = 4'd04; parameter ACK_2 = 4'd05; parameter SEND_B_ADDR_L = 4'd06; parameter ACK_3 = 4'd07; parameter WR_DATA = 4'd08; parameter ACK_4 = 4'd09; parameter START_2 = 4'd10; parameter SEND_RD_ADDR = 4'd11; parameter ACK_5 = 4'd12; parameter RD_DATA = 4'd13; parameter N_ACK = 4'd14; parameter STOP = 4'd15; parameter CNT_1MHZ = 8'd49; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ assign sda_ctrl = ((current_state == ACK_1)||(current_state == ACK_2)|| (current_state == ACK_3)||(current_state == ACK_4)|| (current_state == ACK_5)||(current_state == RD_DATA) ) ? 1'b1 :1'b0; assign iic_sda = (sda_ctrl == 1'b1) ? 1'bz : sda ; assign D_ADDR_DATA = 8'b1010_0000; assign B_ADDR_H_DATA = 8'b0000_0100; assign B_ADDR_L_DATA = 8'b0000_0110; // assign WR_DATA_DATA = 8'b0101_1010; assign RD_ADDR_DATA = 8'b1010_0001; unnamed u000 ( .source (WR_DATA_DATA), // sources.source .probe (rd_data) // probes.probe ); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) clk_1mhz_cnt <= 8'd0; else if(current_state != IDLE) begin if(clk_1mhz_cnt < CNT_1MHZ ) clk_1mhz_cnt <= clk_1mhz_cnt + 1'b1; else clk_1mhz_cnt <= 8'd0 ; end else clk_1mhz_cnt <= 8'd0; always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) write_flag <= 1'b1; else if(flag == 1'b1) write_flag <= ~ write_flag; else write_flag <= write_flag; assign read_flag = ~ write_flag; always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) flag <= 1'b0; else if((current_state == STOP)&&(cnt_byte == 8'd1)&&(clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd3)) flag <= 1'b1; else flag <= 1'b0; always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) clk_1mhz_bit <= 8'd0; else if(current_state != IDLE) begin if(clk_1mhz_cnt == CNT_1MHZ) begin if(clk_1mhz_bit < 8'd3) clk_1mhz_bit <= clk_1mhz_bit + 1'b1; else clk_1mhz_bit <= 8'd0 ; end else clk_1mhz_bit <= clk_1mhz_bit; end else clk_1mhz_bit <= 8'd0; always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) cnt_byte <= 8'd0; else if((current_state == SEND_D_ADDR)||(current_state == SEND_B_ADDR_H)|| (current_state == SEND_B_ADDR_L)||(current_state == WR_DATA)|| (current_state == SEND_RD_ADDR)||(current_state == RD_DATA) ) begin if(cnt_byte <= 8'd7) begin if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd3)) cnt_byte <= cnt_byte + 1'b1; else cnt_byte <= cnt_byte ; end else cnt_byte <= 8'd0; end else if(current_state == STOP) begin if(cnt_byte <= 12'd2000) begin if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd3)) cnt_byte <= cnt_byte + 1'b1; else cnt_byte <= cnt_byte ; end else cnt_byte <= 8'd0; end else cnt_byte <= 8'd0; //~~~~~~~~~~~~~~~~~~~~~~~~~~fsm~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) current_state <= IDLE ; else current_state <= next_state; always@(*) begin case(current_state) IDLE : if((write_flag == 1'b1)||(read_flag == 1'b1)) next_state = START_1; else next_state = IDLE; START_1 : if((clk_1mhz_cnt == CNT_1MHZ )&&(clk_1mhz_bit == 8'd3)) next_state = SEND_D_ADDR; else next_state = START_1; SEND_D_ADDR : if((clk_1mhz_cnt == CNT_1MHZ )&&(cnt_byte == 8'd7)&&(clk_1mhz_bit == 8'd3)) next_state = ACK_1; else next_state = SEND_D_ADDR; ACK_1 : if((clk_1mhz_cnt == CNT_1MHZ )&&(clk_1mhz_bit == 8'd3)&&(ack == 1'b0)) next_state = SEND_B_ADDR_H; else next_state = ACK_1; SEND_B_ADDR_H: if((clk_1mhz_cnt == CNT_1MHZ )&&(cnt_byte == 8'd7)&&(clk_1mhz_bit == 8'd3)) next_state = ACK_2; else next_state = SEND_B_ADDR_H; ACK_2 : if((clk_1mhz_cnt == CNT_1MHZ )&&(clk_1mhz_bit == 8'd3)&&(ack == 1'b0)) next_state = SEND_B_ADDR_L; else next_state = ACK_2; SEND_B_ADDR_L: if((clk_1mhz_cnt == CNT_1MHZ )&&(cnt_byte == 8'd7)&&(clk_1mhz_bit == 8'd3)) next_state = ACK_3; else next_state = SEND_B_ADDR_L; ACK_3 : if((clk_1mhz_cnt == CNT_1MHZ )&&(clk_1mhz_bit == 8'd3)&&(ack == 1'b0)) begin if(write_flag == 1'b1) next_state = WR_DATA; else if((read_flag == 1'b1)) next_state = START_2; else next_state = ACK_3; end else next_state = ACK_3; WR_DATA : if((clk_1mhz_cnt == CNT_1MHZ )&&(cnt_byte == 8'd7)&&(clk_1mhz_bit == 8'd3)) next_state = ACK_4; else next_state = WR_DATA; ACK_4 : if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd3)&&(ack == 1'b0)) next_state = STOP; else next_state = ACK_4; START_2 : if((clk_1mhz_cnt == CNT_1MHZ )&&(clk_1mhz_bit == 8'd3)) next_state = SEND_RD_ADDR; else next_state = START_2; SEND_RD_ADDR: if((clk_1mhz_cnt == CNT_1MHZ)&&(cnt_byte == 8'd7)&&(clk_1mhz_bit == 8'd3)) next_state = ACK_5; else next_state = SEND_RD_ADDR; ACK_5 : if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd3)&&(ack == 1'b0)) next_state = RD_DATA; else next_state = ACK_5; RD_DATA : if((clk_1mhz_cnt == CNT_1MHZ)&&(cnt_byte == 8'd7)&&(clk_1mhz_bit == 8'd3)) next_state = N_ACK; else next_state = RD_DATA; N_ACK : if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd3)) next_state = STOP; else next_state = N_ACK; STOP : if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd3)&&(cnt_byte == 12'd2000)) next_state = IDLE; else next_state = STOP; default : next_state = IDLE; endcase end always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) iic_sck <= 1'b1; else if(current_state == START_1) begin if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd2)) iic_sck <= 1'b0; else iic_sck <= iic_sck; end else if(current_state == STOP) begin if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd0)&&(cnt_byte == 8'd0)) iic_sck <= 1'b1; else iic_sck <= iic_sck; end else if((current_state != IDLE)&&(current_state != START_1)&&(current_state != STOP)) begin if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd0)) iic_sck <= 1'b1; else if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd2)) iic_sck <= 1'b0; else iic_sck <= iic_sck; end else iic_sck <= 1'b1; always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) rd_data_reg <= 8'd0; else if(current_state == RD_DATA) begin if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit <= 8'd7)&&(clk_1mhz_bit == 8'd1)) rd_data_reg <= {rd_data_reg[6:0],iic_sda}; else rd_data_reg <= rd_data_reg; end else rd_data_reg <= 8'd0; always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) rd_data <= 8'd06; else if(current_state == RD_DATA) begin if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd3)&&(cnt_byte == 8'd7)) rd_data <= rd_data_reg; else rd_data <= rd_data; end else rd_data <= rd_data; always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) ack <= 1'b1; else if((current_state == ACK_1)||(current_state == ACK_2 )||(current_state == ACK_3 ) ||(current_state == ACK_4 )||(current_state == ACK_5 )) begin if((clk_1mhz_cnt == CNT_1MHZ)&& (clk_1mhz_bit == 8'd1)) ack <= iic_sda ; else ack <= ack; end else ack <= 1'b1; always@(posedge sys_clk or negedge sys_rst_n) if(!sys_rst_n) sda <= 1'b1; else if(current_state == START_1) begin if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd0)) sda <= 1'b0; else sda <= sda; end else if(current_state == START_2) begin if((clk_1mhz_cnt == 1'b0)&&(clk_1mhz_bit == 8'd0)) sda <= 1'b1; else if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd1)) sda <= 1'b0; else sda <= sda; end else if(current_state == N_ACK) begin if((clk_1mhz_cnt == 1'b0)&&(clk_1mhz_bit == 8'd0)) sda <= 1'b1; else sda <= sda; end else if(current_state == STOP) begin if((clk_1mhz_cnt == 1'b0)&&(clk_1mhz_bit == 8'd0)&&(cnt_byte == 8'd0)) sda <= 1'b0; else if((clk_1mhz_cnt == CNT_1MHZ)&&(clk_1mhz_bit == 8'd2)&&(cnt_byte == 8'd0)) sda <= 1'b1; else sda <= sda; end else if(current_state == SEND_D_ADDR) begin if((clk_1mhz_cnt == 1'b0)&&(clk_1mhz_bit == 8'd0)) sda <= D_ADDR_DATA[(4'd7 - cnt_byte)]; else sda <= sda; end else if(current_state == SEND_B_ADDR_H) begin if((clk_1mhz_cnt == 1'b0)&&(clk_1mhz_bit == 8'd0)) sda <= B_ADDR_H_DATA[(4'd7 - cnt_byte)]; else sda <= sda; end else if(current_state == SEND_B_ADDR_L) begin if((clk_1mhz_cnt == 1'b0)&&(clk_1mhz_bit == 8'd0)) sda <= B_ADDR_L_DATA[(4'd7 - cnt_byte)]; else sda <= sda; end else if(current_state == WR_DATA) begin if((clk_1mhz_cnt == 1'b0)&&(clk_1mhz_bit == 8'd0)) sda <= WR_DATA_DATA[(4'd7 - cnt_byte)]; else sda <= sda; end else if(current_state == SEND_RD_ADDR) begin if((clk_1mhz_cnt == 1'b0)&&(clk_1mhz_bit == 8'd0)) sda <= RD_ADDR_DATA[(4'd7 - cnt_byte)]; else sda <= sda; end else sda <= 1'b1; endmodule
testbench
`timescale 1ns/1ns module eeprom_iic_tb; reg sys_clk; reg sys_rst_n; wire iic_sck; wire iic_sda; /* reg sda_link; reg sda_ack; assign iic_sda = (sda_link == 1'b1) ? 1'bz : sda_ack; */ initial begin sys_clk = 1'b1; sys_rst_n = 1'b0; # 36000; sys_rst_n = 1'b1; /* sda_link = 1'b1; sda_ack <= 1'b1; # 36000; sys_rst_n = 1'b1; #36020; sda_link = 1'b0; //ack1 sda_ack <= 1'b0; #4000; sda_link = 1'b1; //ack up sda_ack <= 1'b1; #32000; sda_link = 1'b0; //ack2 sda_ack <= 1'b0; #4000; sda_link = 1'b1; //ack up sda_ack <= 1'b1; #32000; sda_link = 1'b0; sda_ack <= 1'b0; //ack3 #4000; sda_link = 1'b1; //ack up sda_ack <= 1'b1; #32000; sda_link = 1'b0; sda_ack <= 1'b0; //ack4 #4000; sda_link = 1'b1; //ack up sda_ack <= 1'b1; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #52000; sda_link = 1'b0; sda_ack <= 1'b0; //ack1 #4000; sda_link = 1'b1; //ack up sda_ack <= 1'b1; #32000; sda_link = 1'b0; sda_ack <= 1'b0; //ack2 #4000; sda_link = 1'b1; //ack up sda_ack <= 1'b1; #32000; sda_link = 1'b0; sda_ack <= 1'b0; //ack3 #4000; sda_link = 1'b1; //ack up sda_ack <= 1'b1; #36000; sda_link = 1'b0; sda_ack <= 1'b0; //ack5 #4000; sda_link = 1'b0; //ack up sda_ack <= 1'b1; #8000; sda_ack <= 1'b0; #8000; sda_ack <= 1'b1; #8000; sda_ack <= 1'b0; #8000; sda_link = 1'b1; #4000; sda_link = 1'b1; //ack up sda_ack <= 1'b1; */ end always #10 sys_clk = ~sys_clk; eeprom_iic ee_u0 ( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n), .iic_sck (iic_sck), .iic_sda (iic_sda) ); M24LC64 M24LC64( .A0(1'b0), .A1(1'b0), .A2(1'b0), .WP(1'b0), .SDA(iic_sda), .SCL(iic_sck), .RESET(!sys_rst_n) ); endmodule