⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at24c02_rw.v

📁 硬件模块代码
💻 V
字号:
// AT24C02_RW.v
`timescale 1ns / 100ps
module AT24C02_RW(
    clk,
    reset_n,

    addr,
    data_i,
    data_o,
    cs_n,
    wr_n,
    iowait,
    ioend,

    scl,
    sda
);
    parameter   STATE_IDLE      = 0;
    parameter   STATE_START     = 1;
    parameter   STATE_DADDR     = 2;
    parameter   STATE_WADDR     = 3;
    parameter   STATE_WR_DATA   = 4;
    parameter   STATE_WR_WAIT   = 5;
    parameter   STATE_START1    = 6;
    parameter   STATE_DADDR1    = 7;
    parameter   STATE_RD_DATA   = 8;
    parameter   STATE_STOP      = 9;


    input           clk;        //1MHz
    input           reset_n;

    input   [7:0]   addr;
    input   [7:0]   data_i;
    output  [7:0]   data_o;
    input           cs_n;
    input           wr_n;
    input           iowait;
    output          ioend;

    output          scl;
    inout           sda;

//inner signal
	reg			sda_oe;
	reg			sda_o;

    reg [3:0]   opstate;
    reg [1:0]   clkdiv;

    wire    count_en;
    reg     count_ld;
    wire    count_over;
    reg     [10:0]   count_init;

    reg    	sht_en;
    reg    	sht_ld;
    wire    sht_sdo;
    reg    	[7:0]   sht_pdi;
    wire    [7:0]   sht_pdo;

    //i2c gen scl
    always@(posedge clk or negedge reset_n)
        clkdiv  <= reset_n ? clkdiv + 1 : 2'b00;
    wire scl_l  = (clkdiv==2'b00);
    wire scl_up = (clkdiv==2'b01);
    wire scl_h  = (clkdiv==2'b10);
    wire scl_dn = (clkdiv==2'b11);
    assign scl  = ((opstate==STATE_IDLE)||(opstate==STATE_WR_WAIT)) ? 1 : clkdiv[1];
    assign sda  = sda_oe ? sda_o : 1'bz;
    //wire count_over = (bitcount==0);
    //bus io over
    assign ioend = (opstate==STATE_STOP) && (count_over) && (scl_h) && iowait;
    //assign data_o = sht_pdo;

	//迭代器
    dncounter  #(.COUNTER_W	(11)) u_count(
    .clk        (clk),
    .reset      (~reset_n),
    .clk_en     (count_en),
    .load       (count_ld),
    .din        (count_init),
    .dout       (),
    .count_over (count_over)
    );
	//收发缓存
    shiftbuf u_buf(
    .clk        (clk),
    .reset      (~reset_n),
    .clk_en     (sht_en),
    .load       (sht_ld),
    .pdi        (sht_pdi),
    .pdo        (sht_pdo),
    .sdi        (sda),
    .sdo        (sht_sdo)   
    );


    //set counter init
    always@(*) begin
        case(opstate)
        STATE_WR_DATA, STATE_RD_DATA:  //发送数据,接收数据->发送stop
            count_init  = 1;    //准备发送停止
        STATE_STOP:     //发送stop
            count_init  = 1280; //等待内部写5ms 1280*4*0.001=5.12
        STATE_DADDR1:
            count_init  = 8;
        default:
            count_init  = 8;
        endcase
    end
    //set counter load
    always@(*) begin
        case(opstate)
        STATE_START, STATE_START1:       //发送start
            count_ld= scl_h;
        STATE_DADDR, STATE_DADDR1, STATE_WADDR, STATE_WR_DATA, STATE_RD_DATA:   //发送设备地址写,发送读设备地址,发送字地址,发送数据,接收数据
            count_ld = (scl_l && count_over);
        STATE_STOP:         //发送stop
            count_ld = (scl_h && (count_over) && ~wr_n);
        default:
            count_ld = 0;
        endcase
    end
    //set counter enable
    assign  count_en = scl_l;

    //set shift reg init sht_pdi
    always@(*) begin
        case(opstate)
        STATE_START:    sht_pdi = 8'b1010_000_0;    //device address and write
        STATE_DADDR:    sht_pdi = addr;
        STATE_WADDR:    sht_pdi = data_i;
        STATE_START1:   sht_pdi = 8'b1010_000_1;   //device address and read
        default:        sht_pdi = 8'hxx;
        endcase
    end
    //set shift reg load sht_ld
    always@(*) begin
        case(opstate)
        STATE_START, STATE_START1:  sht_ld = scl_h;
        STATE_DADDR, STATE_WADDR:   sht_ld = (scl_l && count_over);
        default:                    sht_ld = 0;
        endcase
    end
    //set shift reg enable sht_en
    always@(*) begin
        case(opstate)
        STATE_DADDR, STATE_DADDR1, STATE_WADDR, STATE_WR_DATA:  //发送
            sht_en = scl_l;
        STATE_RD_DATA:     //接收数据
            sht_en = scl_dn;
        default:
            sht_en = 0;
        endcase
    end

    //oprate state
    reg [7:0]   data_o;
    always@(posedge clk or negedge reset_n) begin
        if(~reset_n) begin
            opstate     <= #1 STATE_IDLE;
            sda_oe      <= #1 1'b1;
            sda_o       <= #1 1'b1;
            data_o  <= 0;
        end else  begin
            case(opstate)
            STATE_IDLE:         //空闲
            begin
                sda_o       <= #1 1'b1;
                sda_oe      <= #1 1'b1;
                if(iowait && scl_dn)   //启动读写操作
                    opstate <= #1 STATE_START;
            end
            
            STATE_START:        //发送start
            begin
                sda_oe  <= #1 1'b1;
                if(scl_h)
                    sda_o       <= #1 1'b0;            //send start
                if(scl_h) 
                    opstate     <= #1 STATE_DADDR;
            end

            STATE_DADDR:     //发送设备地址写
            begin
                if(scl_dn)
                    sda_oe  <= ~count_over;
                if(scl_l) begin
                    if(count_over) begin
                        opstate     <= #1 STATE_WADDR;
                        sda_o       <= #1 1;
                    end else begin
                        sda_o       <= #1 sht_sdo;        //send out
                    end
                end
            end

            STATE_WADDR:     //发送字地址
            begin
                if(scl_dn)
                    sda_oe  <= ~count_over;
                if(scl_l) begin
                    if(count_over) begin
                        opstate     <= #1 wr_n ? STATE_START1 : STATE_WR_DATA;
                        sda_o       <= #1 1;
                    end else begin
                        sda_o       <= #1 sht_sdo;        //send out
                    end
                end
            end

            STATE_WR_DATA:      //发送数据
            begin
                if(scl_dn)
                    sda_oe  <= ~count_over;
                if(scl_l) begin
                    if(count_over) begin
                        opstate     <= #1 STATE_STOP;
                        sda_o       <= #1 0;
                    end else begin
                        sda_o       <= #1 sht_sdo;        //send out
                    end
                end
            end

            STATE_WR_WAIT:           //等待内部写5ms
            begin
                if(scl_l && count_over)
                    opstate     <= #1 STATE_IDLE;
            end

            STATE_START1:       //发送start
            begin
                if(scl_dn) 
                    sda_oe  <= #1 1'b1;
                if(sda_oe && scl_h) begin
                    opstate     <= #1 STATE_DADDR1;
                    sda_o       <= #1 1'b0;            //send start
                end
            end

            STATE_DADDR1:    //发送读设备地址
            begin
                if(scl_dn)
                    sda_oe  <= ~count_over;
                if(scl_l) begin
                    if(count_over) begin
                        opstate     <= #1 STATE_RD_DATA;
                        sda_o       <= #1 0;
                    end else begin
                        sda_o       <= #1 sht_sdo;        //send out
                    end
                end
            end

            STATE_RD_DATA:     //接收数据
            begin
                sda_oe      <= #1 1'b0;            //set Hiz
                sda_o       <= #1 0;
                if(scl_l && count_over) begin
                    opstate     <= #1 STATE_STOP;
                    data_o      <= sht_pdo;
                end
            end

            STATE_STOP:         //发送stop
            begin
                if(scl_dn)
                    sda_oe      <= #1 1'b1;
                if(sda_oe && scl_h) begin
                    opstate     <= #1 wr_n ? STATE_IDLE : STATE_WR_WAIT;
                    sda_o       <= #1 1'b1;            //send start
                end
            end
            endcase
        end
    end

/*
    always@(posedge clk or negedge reset_n) begin
        if(~reset_n) begin
            opstate     <= #1 STATE_IDLE;
            sda_oe      <= #1 1'b1;
            sda_o       <= #1 1'b1;
        end else  begin
            case(opstate)
            STATE_IDLE:         //空闲
            begin
                if(iowait)   //启动读写操作
                    opstate <= #1 STATE_START;
            end
            
            STATE_START:        //发送start
            begin
                sda_oe  <= #1 1'b1;
                if(scl_l) 
                    sda_o       <= #1 1'b1;
                else if(scl_h)
                    sda_o       <= #1 1'b0;            //send start
                if(scl_h) 
                    opstate     <= #1 STATE_DADDR;
            end

            STATE_DADDR:     //发送设备地址写
            begin
                if(scl_dn)
                    sda_oe  <= ~count_over;
                if(scl_l) begin
                    if(count_over) begin
                        opstate     <= #1 STATE_WADDR;
                    end else begin
                        sda_o       <= #1 sht_sdo;        //send out
                    end
                end
            end

            STATE_WADDR:     //发送字地址
            begin
                if(scl_dn)
                    sda_oe  <= ~count_over;
                if(scl_l) begin
                    if(count_over) begin
                        opstate     <= #1 wr_n ? STATE_START1 : STATE_WR_DATA;
                    end else begin
                        sda_o       <= #1 sht_sdo;        //send out
                    end
                end
            end

            STATE_WR_DATA:      //发送数据
            begin
                if(scl_dn)
                    sda_oe  <= ~count_over;
                if(scl_l) begin
                    if(count_over) begin
                        opstate     <= #1 STATE_STOP;
                    end else begin
                        sda_o       <= #1 sht_sdo;        //send out
                    end
                end
            end

            STATE_WR_WAIT:           //等待内部写5ms
            begin
                if(scl_l && count_over)
                    opstate     <= #1 STATE_IDLE;
            end

            STATE_START1:       //发送start
            begin
                if(scl_dn) 
                    sda_oe  <= #1 1'b1;
                if(sda_oe && scl_h) begin
                    opstate     <= #1 STATE_DADDR1;
                    sda_o       <= #1 1'b0;            //send start
                end else if(scl_l) 
                    sda_o       <= #1 1'b1;
            end

            STATE_DADDR1:    //发送读设备地址
            begin
                if(scl_dn)
                    sda_oe  <= ~count_over;
                if(scl_l) begin
                    if(count_over) begin
                        opstate     <= #1 STATE_RD_DATA;
                    end else begin
                        sda_o       <= #1 sht_sdo;        //send out
                    end
                end
            end

            STATE_RD_DATA:     //接收数据
            begin
                sda_oe      <= #1 1'b0;            //set Hiz
                if(scl_h && count_over) 
                        opstate     <= #1 STATE_STOP;
            end

            STATE_STOP:         //发送stop
            begin
                if(scl_dn)
                        sda_oe      <= #1 1'b1;
                if(sda_oe && scl_h) begin
                    opstate     <= #1 wr_n ? STATE_IDLE : STATE_WR_WAIT;
                    sda_o       <= #1 1'b1;            //send start
                end else if(scl_l) 
                    sda_o       <= #1 1'b0;
            end
            endcase
        end
    end
*/
endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -