FPGA project : IIC_wr_eeprom

简介:

简单双向二线制,同步串行总线。

scl:串行时钟线,用于同步通讯数据。

sda:双向串行数据线。

物理层:

1,支持挂载多设备。

2,二线制。

3,每个设备有其单独的地址。

4,空闲时,sda会被上拉电阻拉高。

5,存在多个主机时,通过仲裁逻辑决定那个主机控制总线。

6,三个速度模式:标准模式(100kb/s);快速模式(400kb/s);高速模式(3.4Mb/s)

地址:

器件地址。7bit,最后1bit为读写控制位。

存储地址:分为单字节和双字节,与存储设备容量有关。就是有多少byte的容量,用几位二进制地址表示。

读写地址。

时序总结:

在scl为高时,若sda变化,则为起始或终止信号。

在scl为低时,(已启动读时隙),sda在scl低电平变化,高电平对sda采样。

读时序:分为随机读(单字节读)和顺序读(页读)。

写时序:单字节写和页写。

框图:

时序图也画了,很多很大,就不放了。

代码:

iic时序驱动模块+指令控制模块+按键消抖+顶层;

/************************************************************
****************    iic 模块说明    ************************
****************    驱动接口模块    ************************
*输入端口:
*sys_clk    :   1Mhz时钟信号。
*iic_start  :   开始进行读写通信标志信号。
*en_w       :   写使能信号,与iic_start同时拉高,iic模块启动写时序。
*addr       :   地址信号,读写公用一个地址信号。
*data_w     :   要通过iic协议写入从机的8bit数据。
*en_r       :   读使能信号,与iic_start同时拉高,iic模块启动读时序。
*addr_num   :   由于地址有单byte和双byte情况,addr_num == 0表示单。
*输出端口:
*scl        :   iic协议的同步时钟信号。串行时钟线,用于同步通讯数据。时钟频率为250kHz
*sda        :   双向端口,双向串行数据线。
*data_out   :   读取到的1byte数据。
*iic_end    :   完成ibyte数据的读写标志信号。
*/
module iic (
    input       wire            sys_clk     , // 虽然写的是sys_clk但是例化时要接iic_clk
    input       wire            sys_rst_n   ,
    input       wire            iic_start   ,
    input       wire            en_w        ,
    input       wire            en_r        ,
    input       wire    [15:0]  byte_addr   ,
    input       wire    [7:0]   data_w      ,
    input       wire            addr_num    ,

    inout       wire            sda         ,

    output      reg             scl         ,
    output      reg     [7:0]   data_out    ,
    output      reg             iic_end     
);
    // parameter
    parameter   DEVICE_ADDR = 7'b1010_011 ; // 器件地址,最后一位要根据读写,来决定。[6:0]
    wire        [7:0]   FIRST_ADDR        ; // AT24C64
    wire        [7:0]   SECOND_ADDR       ; // 可在此设置读写地址。
    assign      FIRST_ADDR  = byte_addr[15:8] ;
    assign      SECOND_ADDR = byte_addr[ 7:0] ;
    // localparam 
    localparam  IDLE                    =4'b0000 ,
                START1                  =4'b0001 ,
                SEND_DEVICE_ADDR        =4'b0011 ,
                ACK1                    =4'b0010 ,

                SEND_FIRST_ADDR         =4'b0110 ,
                ACK2                    =4'b0111 ,
                SEND_SECOND_ADDR        =4'b0101 ,
                ACK3                    =4'b0100 ,

                WR_DATA                 =4'b1100 ,
                ACK4                    =4'b1101 ,
                STOP                    =4'b1111 ,
                START2                  =4'b1110 ,

                SEND_READ_DEVICE_ADDR   =4'b1010 ,
                ACK5                    =4'b1011 ,
                READ_DATA               =4'b1001 ,
                NO_ACK                  =4'b1000 ; 
    // wire signal define
    wire    sda_en ;
    wire    IDLEtoSTART1                ;             
    wire    START1toSEND_DEVICE_ADDR    ; 
    wire    SEND_DEVICE_ADDRtoACK1      ;   
    wire    ACK1toSEND_FIRST_ADDR       ;
    wire    ACK1toSEND_SECOND_ADDR      ;   
    wire    SEND_FIRST_ADDRtoACK2       ;    
    wire    ACK2toSEND_SECOND_ADDR      ;   
    wire    SEND_SECOND_ADDRtoACK3      ;   
    wire    ACK3toWR_DATA               ;            
    wire    ACK3toSTART2                ;             
    wire    WR_DATAtoACK4               ;            
    wire    ACK4toSTOP                  ;               
    wire    STOPtoIDLE                  ;     
    wire    START2toSEND_READ_DEVICE_ADDR;
    wire    SEND_READ_DEVICE_ADDRtoACK5 ; 
    wire    ACK5toREAD_DATA             ;          
    wire    READ_DATAtoNO_ACK           ;        
    wire    NO_ACKtoSTOP                ;             

    // reg signal define
    reg     [3:0]   state_c ;
    reg     [3:0]   state_n ;
    reg     [1:0]   cnt_iic ; // 关键计数器。很多信号赋值都与他有关。
    reg     [2:0]   cnt_bit ; // bit计数器,计数值0-7
    reg             sda_out ;
/***********************************************************************/
    // 状态机描述
    // reg     [3:0]   state_c ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            state_c <= IDLE ;
        else
            state_c <= state_n ;
    end
    // reg     [3:0]   state_n ;
    always @(*) begin
        case(state_c)
                IDLE                 :  if(IDLEtoSTART1) 
                                            state_n = START1 ;
                                        else 
                                            state_n = IDLE ;
                START1               :  if(START1toSEND_DEVICE_ADDR)
                                            state_n = SEND_DEVICE_ADDR ;
                                        else 
                                            state_n = START1 ;
                SEND_DEVICE_ADDR     :  if(SEND_DEVICE_ADDRtoACK1) 
                                            state_n = ACK1 ;
                                        else 
                                            state_n = SEND_DEVICE_ADDR ;
                ACK1                 :  if(ACK1toSEND_FIRST_ADDR) 
                                            state_n = SEND_FIRST_ADDR ;
                                        else if(ACK1toSEND_SECOND_ADDR)
                                            state_n = SEND_SECOND_ADDR ;
                                        else 
                                            state_n = ACK1 ;
                SEND_FIRST_ADDR      :  if(SEND_FIRST_ADDRtoACK2) 
                                            state_n = ACK2 ;
                                        else 
                                            state_n = SEND_FIRST_ADDR ;
                ACK2                 :  if(ACK2toSEND_SECOND_ADDR) 
                                            state_n = SEND_SECOND_ADDR ;
                                        else 
                                            state_n = ACK2 ;
                SEND_SECOND_ADDR     :  if(SEND_SECOND_ADDRtoACK3) 
                                            state_n = ACK3 ;
                                        else 
                                            state_n = SEND_SECOND_ADDR ;
                ACK3                 :  if(ACK3toWR_DATA) 
                                            state_n = WR_DATA ;
                                        else if(ACK3toSTART2)
                                            state_n = START2 ;
                                        else 
                                            state_n = ACK3 ;
                WR_DATA              :  if(WR_DATAtoACK4) 
                                            state_n = ACK4 ;
                                        else 
                                            state_n = WR_DATA ;
                ACK4                 :  if(ACK4toSTOP) 
                                            state_n = STOP ;
                                        else 
                                            state_n = ACK4 ;
                STOP                 :  if(STOPtoIDLE) 
                                            state_n = IDLE ;
                                        else 
                                            state_n = STOP ;
                START2               :  if(START2toSEND_READ_DEVICE_ADDR) 
                                            state_n = SEND_READ_DEVICE_ADDR ;
                                        else 
                                            state_n = START2 ;
                SEND_READ_DEVICE_ADDR:  if(SEND_READ_DEVICE_ADDRtoACK5) 
                                            state_n = ACK5 ;
                                        else 
                                            state_n = SEND_READ_DEVICE_ADDR ;
                ACK5                 :  if(ACK5toREAD_DATA) 
                                            state_n = READ_DATA ;
                                        else 
                                            state_n = ACK5 ;
                READ_DATA            :  if(READ_DATAtoNO_ACK) 
                                            state_n = NO_ACK ;
                                        else 
                                            state_n = READ_DATA ;
                NO_ACK               :  if(NO_ACKtoSTOP) 
                                            state_n = STOP ;
                                        else 
                                            state_n = NO_ACK ;
                default              :      state_n = IDLE ;
        endcase
    end
    // 状态转移条件赋值:
    assign  IDLEtoSTART1             = (state_c == IDLE  ) && (iic_start == 1'b1) ;
    assign  START1toSEND_DEVICE_ADDR = (state_c == START1) && (cnt_iic == 3)      ;
    assign  SEND_DEVICE_ADDRtoACK1   = (state_c == SEND_DEVICE_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK1toSEND_FIRST_ADDR    = (state_c == ACK1  ) && (cnt_iic == 3 && sda == 1'b0 && addr_num == 1) ; //&& sda == 1'b0 由于仿真模型没有相应ack功能,所以要自己模拟。
    assign  ACK1toSEND_SECOND_ADDR   = (state_c == ACK2  ) && (cnt_iic == 3 && sda == 1'b0 && addr_num == 0) ; //&& sda == 1'b0
    assign  SEND_FIRST_ADDRtoACK2    = (state_c == SEND_FIRST_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK2toSEND_SECOND_ADDR   = (state_c == ACK2  ) && (cnt_iic == 3 && sda == 0) ; //&& sda == 0
    assign  SEND_SECOND_ADDRtoACK3   = (state_c == SEND_SECOND_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK3toWR_DATA            = (state_c == ACK3  ) && (cnt_iic == 3 && en_w && sda == 0) ; // && sda == 0 
    assign  ACK3toSTART2             = (state_c == ACK3  ) && (cnt_iic == 3 && en_r && sda == 0) ; // && sda == 0 
    assign  WR_DATAtoACK4            = (state_c == WR_DATA ) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK4toSTOP               = (state_c == ACK4  ) && (cnt_iic == 3 && sda == 0) ; // && sda == 0
    assign  STOPtoIDLE               = (state_c == STOP  ) && (cnt_iic == 3 && cnt_bit == 3) ;
    assign  START2toSEND_READ_DEVICE_ADDR = (state_c == START2) && (cnt_iic == 3)      ;
    assign  SEND_READ_DEVICE_ADDRtoACK5 = (state_c == SEND_READ_DEVICE_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK5toREAD_DATA          = (state_c == ACK5  ) && (cnt_iic == 3 && sda == 0) ; //&& sda == 0
    assign  READ_DATAtoNO_ACK        = (state_c == READ_DATA) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  NO_ACKtoSTOP             = (state_c ==  NO_ACK) && (cnt_iic == 3 && sda == 1) ;
    // reg     [1:0]   cnt_iic ; // 关键计数器。很多信号赋值都与他有关。
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_iic <= 2'd0 ;
        else if(state_c != IDLE)
            cnt_iic <= cnt_iic + 1'b1 ;
        else 
            cnt_iic <= 1'b0 ;
    end
    // reg     [2:0]   cnt_bit ; // bit计数器,计数值0-7
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_bit <= 3'd0 ;
        else if(state_c != IDLE && state_c != START1 && state_c != START2 && state_c != NO_ACK && state_c != ACK1 && state_c != ACK2 && state_c != ACK3 && state_c != ACK4 && state_c != ACK5 && cnt_iic == 3)
            cnt_bit <= cnt_bit + 1'b1 ;
        else if(state_c != IDLE && state_c != START1 && state_c != START2 && state_c != NO_ACK && state_c != ACK1 && state_c != ACK2 && state_c != ACK3 && state_c != ACK4 && state_c != ACK5)
            cnt_bit <= cnt_bit ;
        else 
            cnt_bit <= 3'd0 ;
    end
    // reg             sda_out ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            sda_out <= 1'b1 ; 
        else
        case (state_c)
            IDLE                 :  sda_out <= 1'b1 ;
            START1               :  if(cnt_iic == 0) 
                                        sda_out <= 1'b0 ;
                                    else 
                                        sda_out <= sda_out ;
            SEND_DEVICE_ADDR     :  if(cnt_iic == 0 && cnt_bit != 7) 
                                        sda_out <= DEVICE_ADDR[6 - cnt_bit] ;
                                    else if(cnt_iic == 0 && cnt_bit == 7) 
                                        sda_out <= 1'b0 ; // 写控制位。
            ACK1                 :  sda_out <= 1'b0 ;
            SEND_FIRST_ADDR      :  if(cnt_iic == 0)
                                        sda_out <= FIRST_ADDR[7 - cnt_bit] ;
                                    else 
                                        sda_out <= sda_out ;
            ACK2                 :  sda_out <= 1'b0 ;
            SEND_SECOND_ADDR     :  if(cnt_iic == 0)
                                        sda_out <= SECOND_ADDR[7 - cnt_bit] ;
                                    else 
                                        sda_out <= sda_out ;
            ACK3                 :  sda_out <= 1'b0 ;
            WR_DATA              :  if(cnt_iic == 0)
                                        sda_out <= data_w[7 - cnt_bit] ;
                                    else 
                                        sda_out <= sda_out ;
            ACK4                 :  sda_out <= 1'b0 ;
            STOP                 :  if(cnt_iic == 0 && cnt_bit == 0)
                                        sda_out <= 1'b0 ;
                                    else if(cnt_iic == 2 && cnt_bit == 0)
                                        sda_out <= 1'b1 ;
                                    else    
                                        sda_out <= sda_out ;
            START2               :  if(cnt_iic == 0)
                                        sda_out <= 1'b1 ;
                                    else if(cnt_iic == 2)
                                        sda_out <= 1'b0 ;
                                    else 
                                        sda_out <= sda_out ;
            SEND_READ_DEVICE_ADDR:  if(cnt_iic == 0 && cnt_bit != 7) 
                                        sda_out <= DEVICE_ADDR[6 - cnt_bit] ;
                                    else if(cnt_iic == 0 && cnt_bit == 7) 
                                        sda_out <= 1'b1 ; // 读控制位。
            ACK5                 :  sda_out <= 1'b0 ;
            READ_DATA            :  sda_out <= 1'b0 ;
            NO_ACK               :  sda_out <= 1'b1 ;
            default              :  sda_out <= 1'b1 ;
        endcase
    end
    // wire     sda_en 
    assign sda_en = ((state_c == ACK1) || (state_c == ACK2) || (state_c == ACK3) || (state_c == ACK4) || (state_c == ACK5) || (state_c == READ_DATA)) ? 1'b0 : 1'b1 ;
/***************************************************************************/
    // wire            sda         ,
    assign sda = (sda_en == 1) ? sda_out : 1'bz ;
    // reg             scl         ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            scl <= 1'b1 ;
        else 
        if(state_c != IDLE && state_c != STOP && state_c != START1) begin
            if(cnt_iic == 1 || cnt_iic == 3)
                scl <= ~scl ;
            else 
                scl <=  scl ;
        end 
        else if(state_c == IDLE)
                scl <= 1'b1 ;
        else if(state_c == STOP && (cnt_bit == 0 && cnt_iic == 1))
                scl <= 1'b1 ;
        else if(state_c == STOP)
                scl <= scl ;
        else if(state_c == START1 && cnt_iic == 3)
                scl <= ~scl ;
        else if(state_c == START1)
                scl <= scl ;
        else 
            scl <= 1'b1 ;
    end
    // reg     sda_data ;
    // always @(posedge sys_clk or negedge sys_rst_n) begin
    //     if(~sys_rst_n)
    //         sda_data <= 1'b0 ;
    //     else if(state_c == READ_DATA && cnt_iic == 0)
    //         sda_data <= ~sda_data ;
    //     else    
    //         sda_data <=  sda_data ;
    // end
    // reg [7:0]    data_out
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            data_out <= 8'd0 ;
        else if(state_c == READ_DATA && cnt_iic == 2 && scl == 1)
            data_out <= {data_out[6:0],sda} ; // 这里也需要自己模拟 sda_data
        else 
            data_out <= data_out ;
    end
    // wire            iic_end     
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            iic_end <= 1'b0 ;
        else if(state_c == STOP && cnt_iic == 3 && cnt_bit == 3)
            iic_end <= 1'b1 ;
        else    
            iic_end <= 1'b0 ;
    end
endmodule

/************************************************************
****************    iic_instruct 模块说明    ************************
****************    产生接口时序模块的控制信号,并存储读到的数据,并把数据传给数码管显示模块。
*/
module iic_instruct (
    input       wire            sys_clk   , // 20ns
    input       wire            sys_rst_n ,
    input       wire            iic_clk   , // 1000ns
    input       wire            flag_w    ,
    input       wire            flag_r    ,
    input       wire            iic_end   ,
    input       wire    [7:0]   data_r    , // iic 模块读到的1byte数据。

    output      reg             iic_start ,
    output      reg             en_w      , // 写使能,往eeprom中写数据的使能信号。
    output      reg             en_r      , // 读使能,从eeprom中读数据的使能信号。
    output      reg     [15:0]  byte_addr , // 读写操作的数据地址。
    output      reg     [7:0]   data_w    , // 往eeprom中写入的数据。
    output      wire            addr_num  , // eeprom的存储地址是几个byte。
    output      wire    [7:0]   data_out    // 传给数码管显示的数据。
);
    parameter   ADDR_START          = 16'h00_00 ,
                DATA_WRITE          = 8'd00     , // 写入的起始数据。
                CNT_MAX_START       = 49999     , // 5ms
                CNT_MAX_1S          = 1_000_000 ,
                CNT_MAX_WRITE_BYTE  = 10        , 
                CNT_MAX_READ_BYTE   = 10        ; 
/******************************************************/
    // 第一步:处理输入信号,实现快速时钟域标志信号同步到慢速时钟域。  
    // 也就是保证慢速时钟域可以检测到标志信号。
    reg             valid_write ;
    reg     [7:0]   cnt_write   ;
    reg             valid_read  ;
    reg     [7:0]   cnt_read    ;
    reg     [15:0]  cnt_read_byte   ;
    reg     [15:0]  cnt_start       ;
    reg     [15:0]  cnt_write_byte  ; // 写入eeprom字节计数器
	wire	        empty   ;
	wire	        full    ;
	wire	[9:0]   usedw   ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            valid_write <= 1'b0 ;
        else if(flag_w)
            valid_write <= 1'b1 ;
        else if(cnt_write == 199)
            valid_write <= 1'b0 ;
        else 
            valid_write <=  valid_write ;
    end
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_write <= 8'd0 ;
        else if(valid_write && cnt_write == 199)
            cnt_write <= 8'd0 ;
        else if(valid_write)
            cnt_write <= cnt_write + 1'b1 ;
        else 
            cnt_write <= 8'd0 ;
    end
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            valid_read <= 1'b0 ;
        else if(flag_r)
            valid_read <= 1'b1 ;
        else if(cnt_read == 199)
            valid_read <= 1'b0 ;
        else 
            valid_read <=  valid_read ;
    end
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_read <= 8'd0 ;
        else if(valid_read && cnt_read == 199)
            cnt_read <= 8'd0 ;
        else if(valid_read)
            cnt_read <= cnt_read + 1'b1 ;
        else 
            cnt_read <= 8'd0 ;
    end
    assign addr_num = 1'b1 ;
/**********************************************************************************/
    // 第二步:产生写数据相关信号的产生。在iic_clk时钟域下。
    
    // en_w
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            en_w <= 1'b0 ;
        else if(iic_end && (cnt_write_byte == CNT_MAX_WRITE_BYTE - 1))
            en_w <= 1'b0 ;
        else if(valid_write)
            en_w <= 1'b1 ;
        else 
            en_w <= en_w ;
    end
    //reg    iic_start
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            iic_start <= 1'b0 ;
        else if(en_w == 0 && valid_write == 1 || cnt_start == CNT_MAX_START - 1)
            iic_start <= 1'b1 ;
        else 
            iic_start <= 1'b0 ;
    end
    // reg   [15:0]  cnt_start ;
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_start <= 16'd0 ;
        else if(((en_w == 1) && ((cnt_start == CNT_MAX_START - 1)
                || (iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1))) 
                || ((en_r == 1) && ((cnt_start == CNT_MAX_START - 1)
                || (iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1))))
            cnt_start <= 16'd0 ;
        else if(en_w == 1 || en_r)
            cnt_start <= cnt_start + 1'b1 ;
        else 
            cnt_start <= 16'd0 ;
    end
    // [15:0] byte_addr // 目前只完成了写地址,
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            byte_addr <= ADDR_START ;
        else if((iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1) 
                || (iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1))
            byte_addr <= ADDR_START ;
        else if(iic_end == 1)
            byte_addr <= byte_addr + 1'b1 ;
        else 
            byte_addr <= byte_addr ;
    end
    // [7:0]    data_w
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            data_w <= DATA_WRITE ;
        else if(iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1)
            data_w <= DATA_WRITE ;
        else if(en_w && iic_end == 1)
            data_w <= data_w + 1'b1 ;
        else 
            data_w <= data_w ;
    end
    // [15:0]   cnt_write_byte
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_write_byte <= 16'd0 ;
        else if(en_w && iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1)
            cnt_write_byte <= 16'd0 ;
        else  if(en_w && iic_end == 1)
            cnt_write_byte <= cnt_write_byte + 1'b1 ;
        else 
            cnt_write_byte <= cnt_write_byte ;
    end
/*****************************************************************************/
    // 读相关控制信号产生
    // en_r
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            en_r <= 1'b0 ;
        else if(iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1)
            en_r <= 1'b0 ;
        else if(valid_read)
            en_r <= 1'b1 ;
        else 
            en_r <= en_r ;
    end
    // [15:0]  cnt_read_byte 
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_read_byte <= 16'd0 ;
        else if(en_r && iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1)
            cnt_read_byte <= 16'd0 ;
        else  if(en_r && iic_end == 1)
            cnt_read_byte <= cnt_read_byte + 1'b1 ;
        else 
            cnt_read_byte <= cnt_read_byte ;
    end
/*******************************************************************************/
    reg             valid_fifo_read ;
    reg     [19:0]  cnt_1s          ;
    reg             fifo_rd_en      ;
    // valid_fifo_read
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            valid_fifo_read <= 1'b0 ;
        else if(valid_fifo_read == 1 && usedw == 0)
            valid_fifo_read <= 1'b0 ;
        else if(usedw > (CNT_MAX_READ_BYTE - 1))
            valid_fifo_read <= 1'b1 ;
        else 
            valid_fifo_read <= valid_fifo_read ;
    end
    // [19:0]  cnt_1s    
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_1s <= 20'd0 ;
        else if(valid_fifo_read == 1 && cnt_1s == CNT_MAX_1S - 1)
            cnt_1s <= 20'd0 ;
        else if(valid_fifo_read == 1)
            cnt_1s <= cnt_1s + 1'b1 ;
        else 
            cnt_1s <= 20'd0 ;
    end
    // fifo_rd_en
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            fifo_rd_en <= 1'b0 ;
        else if(valid_fifo_read == 1 && cnt_1s == CNT_MAX_1S - 1)
            fifo_rd_en <= 1'b1 ;
        else 
            fifo_rd_en <= 1'b0 ;
    end

fifo_8x1024 fifo_8x1024_inst(
	.clock       ( iic_clk          ) ,
	.data        ( data_r           ) ,
	.rdreq       ( fifo_rd_en       ) ,
	.wrreq       ( en_r && iic_end  ) ,
	.empty       ( empty            ) ,
	.full        ( full             ) ,
	.q           ( data_out         ) ,
	.usedw       ( usedw            )  
);
endmodule

module top (
    input       wire        sys_clk     ,
    input       wire        sys_rst_n   ,
    input       wire        key_write   ,
    input       wire        key_read    ,

    inout       wire        sda         ,
    output      wire        scl         ,
    output      wire        ds          ,
    output      wire        oe          ,
    output      wire        shcp        ,
    output      wire        stcp        
);
    // 例化间连线
    wire            clk_50mHz   ;
    wire            clk_1mHz    ; 
    wire            locked      ;  
    wire            rst_n       ;
    wire            flag_write  ;
    wire            flag_read   ;
    wire    [05:00] point       ;
    wire            sign        ;
    assign          point  = 5'd0 ;
    assign          sign   = 1'b0 ;
    assign          rst_n = sys_rst_n && locked ;

pll pll_isnt(
	.areset                 ( ~sys_rst_n ) ,
	.inclk0                 ( sys_clk    ) ,
	.c0                     ( clk_50mHz  ) ,
	.c1                     ( clk_1mHz   ) ,
	.locked                 ( locked     ) 
);

key_filter key_filter_inst_w(
    .sys_clk                ( clk_50mHz ) ,
    .sys_rst_n              ( rst_n     ) ,
    .key_in                 ( key_write ) ,

    .key_out                ( flag_write)         
);   
key_filter key_filter_inst_r(
    .sys_clk                ( clk_50mHz ) ,
    .sys_rst_n              ( rst_n     ) ,
    .key_in                 ( key_read  ) ,

    .key_out                ( flag_read )         
); 

    wire            iic_start ;
    wire            en_w      ;
    wire            en_r      ;
    wire    [15:0]  byte_addr ;
    wire    [7:0]   data_w    ;
    wire            addr_num  ;
    wire    [7:0]   data_out  ;
    wire            iic_end   ;
    wire    [7:0]   data_r    ;
iic_instruct iic_instruct_inst(
    .sys_clk                ( clk_50mHz  ) , // 20ns
    .sys_rst_n              ( rst_n      ) ,
    .iic_clk                ( clk_1mHz   ) , // 1000ns
    .flag_w                 ( flag_write ) ,
    .flag_r                 ( flag_read  ) ,
    .iic_end                ( iic_end    ) ,
    .data_r                 ( data_r     ) , // iic 模块读到的1byte数据。

    .iic_start              ( iic_start  ) ,
    .en_w                   ( en_w       ) , // 写使能,往eeprom中写数据的使能信号。
    .en_r                   ( en_r       ) , // 读使能,从eeprom中读数据的使能信号。
    .byte_addr              ( byte_addr  ) , // 读写操作的数据地址。
    .data_w                 ( data_w     ) , // 往eeprom中写入的数据。
    .addr_num               ( addr_num   ) , // eeprom的存储地址是几个byte。
    .data_out               ( data_out   )   // 传给数码管显示的数据。
);

iic iic_inst(
    .sys_clk                ( clk_1mHz   ) , // 虽然写的是sys_clk但是例化时要接iic_clk
    .sys_rst_n              ( rst_n      ) ,
    .iic_start              ( iic_start  ) ,
    .en_w                   ( en_w       ) ,
    .en_r                   ( en_r       ) ,
    .byte_addr              ( byte_addr  ) ,
    .data_w                 ( data_w     ) ,
    .addr_num               ( addr_num   ) ,

    .sda                    ( sda        ) ,

    .scl                    ( scl        ) ,
    .data_out               ( data_r     ) ,
    .iic_end                ( iic_end    )     
);

seg_595_dynamic seg_595_dynamic_isnt(
    .sys_clk                ( clk_50mHz ) ,
    .sys_rst_n              ( rst_n     ) ,
    .data                   ( {12'd0,data_out} ) , 
    .point                  ( point     ) ,
    .sign                   ( sign      ) ,
    .seg_en                 ( rst_n     ) ,

    .ds                     ( ds        ) ,      
    .oe                     ( oe        ) ,      
    .shcp                   ( shcp      ) ,      
    .stcp                   ( stcp      )           
);

endmodule

仿真测试,要用到 M24C64仿真模型。

仿真验证通过,上板验证通过。

相关推荐
DS小龙哥1 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
上理考研周导师11 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战12 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
bigbig猩猩1 天前
FPGA(现场可编程门阵列)的时序分析
fpga开发
Terasic友晶科技1 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪1 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
江山如画,佳人北望1 天前
EDA技术简介
fpga开发
淘晶驰AK1 天前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
最好有梦想~1 天前
FPGA时序分析和约束学习笔记(4、IO传输模型)
笔记·学习·fpga开发