【FPGA】FPGA实现IIC协议读写EEPROM(二) -----EEPROM读写控制模块实现

写在前面:
FPGA实现IIC协议读写EEPROM相关文章:

IIC通信协议
【FPGA】FPGA实现IIC协议读写EEPROM(一) ----- IIC接口驱动实现
【FPGA】FPGA实现IIC协议读写EEPROM(二) -----EEPROM读写控制模块实现
【FPGA】FPGA实现IIC协议读写EEPROM(三) ----- 汇总篇

在上篇文章中已经对IIC协议和IIC接口驱动实现进行了详细介绍,本文介绍EEPROM读写控制模块的实现。

一、模块功能分析

EEPROM读写控制模块需要根据接收到的按键读写请求信号以及I2C接口模块返回的信号发送读写请求、控制指令、数据字节给I2C接口模块,以及接收I2C接口模块返回的数据。

二、输入/输出信号

EEPROM读写控制模块输入/输出信号如下:
在这里插入图片描述

信号说明:

信号I/O类型说明
rdin[7:0]inputI2C接口模块读回的数据
rdin_vldinputI2C接口模块读回的数据有效标志
rw_doneinputI2C接口读写一字节数据完成标志
rd_reqinput读请求
wr_reqinput写请求
reqoutput输出给I2C接口模块的读写请求
cmd[3:0]output控制命令
wr_dout[7:0]output要发送的数据/控制字节

三、EEPROM读写控制模块状态机

EEPROM读写控制模块状态转移图如下:
在这里插入图片描述

状态说明:
IDLE:空闲状态,等待读写请求。
SEND_WRREQ:发送写请求、控制指令、写控制字、地址、数据字节给I2C接口模块。
SEND_RDREQ :发送读请求、控制指令、写控制字、地址、读控制字给I2C接口模块。
WAIT_WRDONE:等待I2C接口模块写数据完成。
WAIT_RDDONE:等待I2C接口模块读数据完成。
WR_DONE:I2C接口模块写数据完成。
RD_DONE:I2C接口模块读数据完成。

四、EEPROM读写控制模块实现

EEPROM读写控制模块verilog代码如下:

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.13                        
//  Design Name: i2c_eeprom    
//  Module Name: eeprom_ctrl         
//  Target Device: Cyclone IV E (EP4CE6F17C8)             
//  Tool versions: Quartus Prime 18.1             
//  Description: 使用I2C协议读写EEPROM驱动控制模块
//  **************************************************************
module eeprom_ctrl (
    input               clk                 ,
    input               rst_n               ,
    //  key_filter
    input               wr_req              ,       //  读请求
    input               rd_req              ,       //  写请求
    //  i2c_interface
    input   [7:0]       rdin                ,       //  从I2C接口读回的数据
    input               rdin_vld            ,
    input               rw_done             ,       //  读写一字节数据完成标志
    output              req                 ,       //  读写请求
    output  [7:0]       wr_dout             ,       //  要发送的数据
    output  [3:0]       cmd                   
);

    //  参数定义
    //  状态机参数定义
    localparam  IDLE        =   7'b000_0001 ,
                SEND_WRREQ  =   7'b000_0010 ,   //  发送写请求
                SEND_RDREQ  =   7'b000_0100 ,   //  发送读请求
                WAIT_WRDONE =   7'b000_1000 ,   //  等待写数据完成
                WAIT_RDDONE =   7'b001_0000 ,   //  等待读数据完成
                WR_DONE     =   7'b010_0000 ,   //  写数据完成
                RD_DONE     =   7'b100_0000 ;   //  读数据完成

    //  信号定义
    reg     [6:0]       state_c                 ;
    reg     [6:0]       state_n                 ;
    
    reg     [3:0]       byte_num                ;   //  字节数
    reg     [3:0]       cnt_byte                ;   //  字节计数器
    wire                add_cnt_byte            ;
    wire                end_cnt_byte            ;

    reg     [7:0]       wrdata                  ;   //  寄存将要发送的数据
    reg     [3:0]       command                 ;   //  寄存将要发送的命令
    reg                 rw_req                  ;


    //  状态转移条件
    wire                idle2sendwrreq          ;
    wire                idle2sendrdreq          ;
    wire                sendwrreq2waitwrdone    ;
    wire                sendrdreq2waitrddone    ;
    wire                waitwrdone2wrdone       ;
    wire                waitwrdone2sendwrreq    ;
    wire                waitrddone2rddone       ;
    wire                waitrddone2sendrdreq    ;
    wire                wrdone2idle             ;
    wire                rddone2idle             ;

    //  状态机
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            state_c <= IDLE ;
        end
        else begin
            state_c <= state_n ;
        end
    end

    always @(*)begin
        case (state_c)
            IDLE: begin
                if(idle2sendwrreq)
                    state_n = SEND_WRREQ ;
                else if(idle2sendrdreq)
                    state_n = SEND_RDREQ ;
                else
                    state_n = state_c ;
            end
            SEND_WRREQ: begin
                if(sendwrreq2waitwrdone)
                    state_n = WAIT_WRDONE ;
                else
                    state_n = state_c ;
            end
            SEND_RDREQ: begin
                if(sendrdreq2waitrddone)
                    state_n = WAIT_RDDONE ;
                else
                    state_n = state_c ;
            end
            WAIT_WRDONE: begin
                if(waitwrdone2wrdone)
                    state_n = WR_DONE ;
                else if(waitwrdone2sendwrreq)
                    state_n = SEND_WRREQ ;
                else
                    state_n = state_c ;
            end
            WAIT_RDDONE: begin
                if(waitrddone2rddone)
                    state_n = RD_DONE ;
                else if(waitrddone2sendrdreq)
                    state_n = SEND_RDREQ ;
                else
                    state_n = state_c ;
            end
            WR_DONE: begin
                if(wrdone2idle)
                    state_n = IDLE ;
                else
                    state_n = state_c ;
            end
            RD_DONE: begin
                if(rddone2idle)
                    state_n = IDLE ;
                else
                    state_n = state_c ;
            end
            default: state_n = IDLE ;
        endcase
    end
    //  状态转移
    assign idle2sendwrreq      = state_c == IDLE        && wr_req       ;
    assign idle2sendrdreq      = state_c == IDLE        && rd_req       ;  
    assign sendwrreq2waitwrdone= state_c == SEND_WRREQ  && (1'b1)       ;
    assign sendrdreq2waitrddone= state_c == SEND_RDREQ  && (1'b1)       ;
    assign waitwrdone2wrdone   = state_c == WAIT_WRDONE && end_cnt_byte ;
    assign waitwrdone2sendwrreq= state_c == WAIT_WRDONE && (cnt_byte < 2) && rw_done    ;
    assign waitrddone2rddone   = state_c == WAIT_RDDONE && end_cnt_byte ;
    assign waitrddone2sendrdreq= state_c == WAIT_RDDONE && (cnt_byte < 3) && rw_done    ;
    assign wrdone2idle         = state_c == WR_DONE     && (1'b1)       ;
    assign rddone2idle         = state_c == RD_DONE     && (1'b1)       ;

    //  byte_num
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            byte_num <= 0 ;
        end
        else if(wr_req)begin
            byte_num <= 3 ;
        end
        else if(rd_req)begin
            byte_num <= 4 ;
        end
        else if(wrdone2idle | rddone2idle)begin
            byte_num <= 0 ;
        end
    end

    //  cnt_byte
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_byte <= 0 ;
        end
        else if(add_cnt_byte)begin
            if(end_cnt_byte)begin
                cnt_byte <= 0 ;
            end				
            else begin	    
                cnt_byte <= cnt_byte + 1 ;
            end 		    
        end
    end                   
    assign	add_cnt_byte = rw_done ;
    assign	end_cnt_byte = add_cnt_byte && (cnt_byte == byte_num - 1) ;

    //  rw_req
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            rw_req <= 1'b0 ;
        end
        else if(idle2sendwrreq | idle2sendrdreq | sendwrreq2waitwrdone | sendrdreq2waitrddone)begin
            rw_req <= 1'b1 ;
        end
        else begin
            rw_req <= 1'b0 ;
        end
    end

    //  wrdata   command
    always @(*)begin
        if(state_c == SEND_WRREQ)begin
            case (cnt_byte)
                0: begin wrdata = 8'b1010_0000 ;command = 4'b1010 ; end    //  写控制字
                1: begin wrdata = 8'b1101_1001 ;command = 4'b1000 ; end    //  写地址
                2: begin wrdata = 8'b1111_1001 ;command = 4'b1001 ; end    //  写数据
                default: begin wrdata = 8'b0 ;command = 4'b0 ;end
            endcase
        end
        else if(state_c == SEND_RDREQ)begin
            case (cnt_byte)
                0: begin wrdata = 8'b1010_0000 ;command = 4'b1010 ; end    //  写控制字
                1: begin wrdata = 8'b1101_1001 ;command = 4'b1000 ; end    //  读地址
                2: begin wrdata = 8'b1010_0001 ;command = 4'b1010 ; end    //  写读控制字
                3: begin wrdata = 8'b0 ;command = 4'b0101 ;      end    //  读数据
                default: begin wrdata = 8'b0 ;command = 4'b0 ;end     
            endcase
        end
    end

    //  输出
    assign  req = rw_req ;
    assign  cmd = command ;
    assign  wr_dout = wrdata ;

endmodule                               

五、仿真测试

写数据:
在这里插入图片描述
读数据
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值