24LC64_IIC_verilog控制读写

PS:EEPROM单次写时间比较长,24LC64要5ms,才能进行读操作,否则不会响应地址,示波器观察的。

1‘给出单次写仿真图1;(sda上面的蓝色是主从三态门切换时候,未知态,实测波形,也会有小尖峰出现)

2’给出单次读仿真图2;

3‘给出main代码;(用quartus的issp观察数据的)

4’给出testbench代码;(添加了24LC64的verilog模型,读数据不能显示,显示的高阻态)

 

图一

24LC64_IIC_verilog控制读写

 

 

图2

24LC64_IIC_verilog控制读写

 

 

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

上一篇:2021-06-15


下一篇:基于FPGA的AD7606采集程序设计Verilog 开发