• 基于FPGA的I2C读写EEPROM


    前言

    本次项目所用开发板FPGA芯片型号为:EP4CE6F17C8 EEPROM芯片型号为:24LC04B UART串口设置为:波特率115200
    无校验位

    本次项目仅实现了EEPROM的单字节读写。若要实现连续读写可以在下文的EEPROM控制模块设置计数器控制读写字数。

    一、I2C协议

    1.1 I2C协议简介

    I2C总线是Philips公司在八十年代初推出的一种同步、串行、半双工 的总线,主要用于近距离、低速的芯片之间的通信;I2C总线有两根双向的信号线,一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步;I2C总线硬件结构简单,简化了PCB布线,降低了系统成本,提高了系统可靠性,因此在各个领域得到了广泛应用。

    I2C是一种多主机多从机总线,通过呼叫应答的方式实现主机与从机间的通信。每一个I2C设备都有一个唯一的7位地址,也就是说同一根线上最多挂载127个I2C从机设备(主机自己占一个地址)。主机有权发起和结束一次通信,从机只能被动呼叫;当总线上有多个主机同时启用总线时,I2C也具备冲突检测和仲裁的功能来防止错误产生。

    1.2 物理层

    在这里插入图片描述

    • I2C支持多主机多从机

    • I2C有两条线,一条SCL串行时钟线,用于数据收发同步;一条SDA串行数据线,用来表示数据

    • 每个连接到IIC总线的设备都有一个唯一的地址(ID),主机可以通过地址与不同的从机建立连接

    • I2C 总线通过上拉电阻接到电源。当 IIC 设备空闲时,设备会输出高阻态,当所有设备都空闲,都输出高阻态时,由上拉电阻把 IIC总线拉成高电平。

    • I2C总线有仲裁机制:当多个主机同时发起传输时,触发仲裁机制,最终只给一个主机授权。

    • 具有三种传输模式,每种传输模式对应的传输速率不同,具体速率如下:
      在这里插入图片描述
      有些I2C变种还包含了快速+(1Mbit/s)和超高速(5Mbit/s 单向传输)模式。

    1.3 协议层

    • 空闲状态:I2C协议规定,在空闲状态下SDA数据线和SCL时钟线均处于高电平。
    • 开始位:当SCL处于高电平时,SDA数据线被拉低,则认为检测到起始位,一次数据传输开始。
    • 数据传输:同时,协议规定在SCL高电平时期SDA数据线必须保持稳定,在SCL低电平时,SDA才允许发生改变。主机进行数据读写时,I2C协议规定,数据传输时先发送寻址字节,即7位从机地址+0/1。其中0表示主机写,1表示主机读。寻址字节发送完成后才是数据字节
    • 应答位:I2C协议规定,主机每次向从机传输1字节数据后,需要接收一次从机的应答信号。0为接收成功;1为接受失败,没有响应。
    • 停止位:当SCL为高电平时,数据线SDA拉高,则认为检测到停止位,一次数据传输结束。
      在这里插入图片描述
      在这里插入图片描述

    二、EEPROM

    2.1 型号及硬件规格

    EEPROM的全称是“电可擦除可编程只读存储器”,即Electrically Erasable Programmable Read-Only Memory。本次项目中使用的EEPROM型号为24LC04B。

    在这里插入图片描述
    由手册可以看出,24LC04B支持的最大时钟频率为400KHz。

    在这里插入图片描述
    由手册得出该型号EEPROM共有两个Block 每个Block的存储容量为256×8bit。
    在这里插入图片描述
    在这里插入图片描述

    由手册得出,设备地址为1010xxB0共七位(xx为dont care B0为块选择),1为读操作,0为写操作。

    2.2 各种读写时序

    单字节写

    在这里插入图片描述

    • 先写开始位
    • 然后写控制字节,从机接收到发应答信号
    • 然后写数据地址,从机接收到发应答信号,如果数据地址是2位的话,就继续写数据地址,从机接收到发应答信号
    • 然后写数据,从机接收到发应答信号
    • 最后写结束位

    页写

    在这里插入图片描述

    • 页节写先开始位
    • 然后写控制字节,从机接收到应答信号
    • 然后写数据地址,从机接收到应答信号,如果数据地址是2位的话,就继续写数据地址,从机接收到应答信号
    • 然后写数据,从机接收到应答信号
    • 然后继续写数据,直到写完全部的数据
    • 最后是结束位

    当前地址读

    在这里插入图片描述

    • 当前地址读先开始位
    • 然后写控制字节,从机接收到应答信号,然后读数据,无应答信号
    • 最后结束位

    随机地址读和顺序读

    在这里插入图片描述

    • 随机读先写开始位
    • 然后写控制字节,从机接收到应答信号
    • 然后dummuy write 虚写,写数据地址,从机接收到应答信号
    • 然后开始位
    • 然后读控制字节,从机接收到应答信号
    • 然后读数据
    • 最后结束位

    三、状态机设计

    I2C接口模块:
    在这里插入图片描述
    EEPROM控制模块:
    在这里插入图片描述

    四、项目源码:

    EEPROM驱动模块:

    /**************************************功能介绍***********************************
    Date	: 2023年8月28日 
    Author	: majiko
    Version	: 1.0
    Description: eeprom驱动模块
                 
                 cmd       0      1
                 开始位    NO    YES          
                 写数据    NO    YES      
                 读数据    NO    YES          
                 停止位    NO    YES              
                 应答位    ACK   NO_ACK
    *********************************************************************************/
        
    module eeprom_driver( 
        input       wire            clk         ,
        input       wire            rst_n       ,
        input       wire    [7:0]   wr_data     ,
        input       wire    [4:0]   cmd         ,
        input       wire            cmd_vld     ,
    
        inout       wire            i2c_sda     ,
        output      reg             i2c_scl     ,
    
        output      wire    [7:0]   rd_data     ,
        output      wire            rd_data_vld ,
        output      reg             done        ,
        output      reg             rev_ack         
    );
    
    //内部参数定义
        //命令宏定义
        `define START_BIT  5'b00001
        `define WRITE_BIT  5'b00010
        `define READ_BIT   5'b00100
        `define STOP_BIT   5'b01000
        `define ACK_BIT    5'b10000
    
        `define ACK        0
        `define NO_ACK     1
    
        //状态定义
        parameter   IDLE    = 7'b000_0001,
                    START   = 7'b000_0010,
                    WR_DATA = 7'b000_0100,
                    R_ACK   = 7'b000_1000,
                    STOP    = 7'b001_0000,
                    RD_DATA = 7'b010_0000,
                    T_ACK   = 7'b100_0000;
    
        //i2c速率以及采样点定义
        parameter   SCL_MAX = 50_000_000/100_000; //100K速率
        parameter   SCL_1_4 = SCL_MAX/4;
        parameter   SCL_3_4 = SCL_MAX*3/4;
    
    
        
    
    //内部信号定义
        //状态寄存器
        reg         [6:0]   cstate          ;
        reg         [6:0]   nstate          ;
    
        reg         [7:0]   wr_data_r       ;//输入数据寄存
        reg         [4:0]   cmd_r           ;//输入命令寄存
    
        reg         [7:0]   rev_data        ;         
    
        //跳转条件定义
        wire                idle2start      ;
        wire                idle2wr_data    ;
        wire                idle2rd_data    ;
        wire                start2wr_data   ;
        wire                wr_data2r_ack   ;
        wire                r_ack2stop      ;
        wire                r_ack2idle      ;
        wire                stop2idle       ;
        wire                rd_data2t_ack   ;
        wire                t_ack2stop      ;
        wire                t_ack2idle      ;
    
        //bit计数器
        reg			[3:0]	cnt_bit	   	    ;
        wire				add_cnt_bit	    ;
        wire				end_cnt_bit	    ;
        reg         [3:0]   bit_max         ;
    
        //i2c分频计数器
        reg			[8:0]	cnt_scl	   	    ;
        wire				add_cnt_scl	    ;
        wire				end_cnt_scl	    ;
    
        //三态门信号定义
        reg                 sda_out         ;
        wire                sda_in          ;
        reg                 sda_en          ;
        
    
    //****************************************************************
    //--数据寄存 命令寄存
    //****************************************************************
        always@(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                wr_data_r <= 1'b0;
            end
            else if(cmd_vld)begin
                wr_data_r <= wr_data;
            end
            else begin
                wr_data_r <= wr_data_r;
            end
        end
    
        always@(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                cmd_r <= 1'b0;
            end
            else if(cmd_vld)begin
                cmd_r <= cmd;
            end
            else begin
                cmd_r <= cmd_r;
            end
        end
    //****************************************************************
    //--读写状态机
    //****************************************************************
        //第一段 状态定义
        always @(posedge clk or negedge rst_n) begin
            if(!rst_n)begin
                cstate <= IDLE;
            end
            else begin
                cstate <= nstate;
            end
        end
    
        //第二段 状态转移规律
        always@(*)begin
            case (cstate)
                IDLE    :   begin
                                if(idle2start)begin
                                    nstate = START;
                                end
                                else if(idle2wr_data)begin
                                    nstate = WR_DATA;
                                end
                                else if(idle2rd_data)begin
                                    nstate = RD_DATA;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                START   :   begin
                                if(start2wr_data)begin
                                    nstate = WR_DATA;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                WR_DATA :   begin
                                if(wr_data2r_ack)begin
                                    nstate = R_ACK;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end            
                R_ACK   :   begin
                                if(r_ack2stop)begin
                                    nstate = STOP;
                                end
                                else if(r_ack2idle)begin
                                    nstate = IDLE;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                STOP    :   begin
                                if(stop2idle)begin
                                    nstate = IDLE;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                RD_DATA :   begin
                                if(rd_data2t_ack)begin
                                    nstate = T_ACK;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                 T_ACK  :   begin
                                if(t_ack2stop)begin
                                    nstate = STOP;
                                end
                                else if(t_ack2idle)begin
                                    nstate = IDLE;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end                                
                default:    nstate = IDLE;
            endcase
        end
    
        assign idle2start    = (cstate == IDLE) && cmd_vld && (cmd & `START_BIT); 
        assign idle2wr_data  = (cstate == IDLE) && cmd_vld && (cmd & `WRITE_BIT);  
        assign idle2rd_data  = (cstate == IDLE) && cmd_vld && (cmd & `READ_BIT);
    
        assign start2wr_data = (cstate == START  ) && end_cnt_bit && (cmd_r & `WRITE_BIT);
    
        assign wr_data2r_ack = (cstate == WR_DATA) && end_cnt_bit;
    
        assign r_ack2stop    = (cstate == R_ACK)   && end_cnt_bit && (cmd_r & `STOP_BIT);       
        assign r_ack2idle    = (cstate == R_ACK)   && end_cnt_bit && !(cmd_r & `STOP_BIT);
    
        assign stop2idle     = (cstate == STOP   ) && end_cnt_bit;   
        assign rd_data2t_ack = (cstate == RD_DATA) && end_cnt_bit;
    
        assign t_ack2stop    = (cstate == T_ACK)   && end_cnt_bit && (cmd_r & `STOP_BIT);   
        assign t_ack2idle    = (cstate == T_ACK)   && end_cnt_bit && !(cmd_r & `STOP_BIT);   
    
    //****************************************************************
    //--i2c时钟分频
    //****************************************************************
        
        always @(posedge clk or negedge rst_n)begin 
           if(!rst_n)begin
                cnt_scl <= 'd0;
            end 
            else if(add_cnt_scl)begin 
                if(end_cnt_scl)begin 
                    cnt_scl <= 'd0;
                end
                else begin 
                    cnt_scl <= cnt_scl + 1'b1;
                end 
            end
        end 
        
        assign add_cnt_scl = cstate != IDLE;
        assign end_cnt_scl = add_cnt_scl && cnt_scl == SCL_MAX - 1'b1;
    
        //assign i2c_scl = (cnt_scl == (SCL_MAX - 1'b1) >> 1'b1 || stop2idle) ? 1'b1 : 1'b0;
        
        always@(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                i2c_scl <= 1'b1;
            end
            else if(cnt_scl == (SCL_MAX - 1) >> 1'b1 || stop2idle)begin
                i2c_scl <= 1'b1;
            end
            else if(end_cnt_scl)begin
                i2c_scl <= 1'b0;
            end
            else begin
                i2c_scl <= i2c_scl;
            end
        end
        
    //****************************************************************
    //--bit计数器
    //****************************************************************
        
        always @(posedge clk or negedge rst_n)begin 
           if(!rst_n)begin
                cnt_bit <= 'd0;
            end 
            else if(add_cnt_bit)begin 
                if(end_cnt_bit)begin 
                    cnt_bit <= 'd0;
                end
                else begin 
                    cnt_bit <= cnt_bit + 1'b1;
                end 
            end
        end 
        
        assign add_cnt_bit = end_cnt_scl;
        assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max - 1'b1;
        
        always @(*)begin
            if(cstate == WR_DATA || cstate == RD_DATA)begin
                bit_max = 'd8;
            end
            else begin
                bit_max = 'd1;
            end
        end
    
    //****************************************************************
    //--三态门控制
    //****************************************************************
        assign sda_in = i2c_sda;
        assign i2c_sda = sda_en ? sda_out : 1'bz;
    
        //使能信号开启
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                sda_en <= 1'b0;
            end
            else if(wr_data2r_ack || stop2idle || idle2rd_data)begin
                sda_en <= 1'b0;
            end
            else if(idle2wr_data || idle2start || rd_data2t_ack || r_ack2stop || start2wr_data)begin
                sda_en <= 1'b1;
            end
            else begin
                sda_en <= sda_en;
            end
        end
    //****************************************************************
    //--数据发送
    //****************************************************************
        always@(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                sda_out <= 1'b1;
            end
            else begin
                case(cstate)
                    IDLE    :   sda_out <= 1'b1;
                    START   :   begin
                                    if(cnt_scl == SCL_1_4)begin
                                        sda_out <= 1'b1;
                                    end
                                    else if(cnt_scl == SCL_3_4)begin
                                        sda_out <= 1'b0;
                                    end
                                    else begin
                                        sda_out <= sda_out;
                                    end
                                end
                    WR_DATA :   begin
                                    if(cnt_scl == SCL_1_4)begin
                                        sda_out <= wr_data_r[7-cnt_bit];
                                    end
                                    else begin
                                        sda_out <= sda_out;
                                    end
                                end
                    T_ACK   :   begin
                                    if(cnt_scl == SCL_1_4)begin
                                        if(cmd & `ACK_BIT)begin
                                            sda_out <= `NO_ACK;
                                        end
                                        else begin
                                            sda_out <= `ACK;
                                        end
                                    end
                                    else begin
                                        sda_out <= sda_out;
                                    end
                                end
                    STOP    :   begin
                                    if(cnt_scl == SCL_1_4)begin
                                        sda_out <= 1'b0;
                                    end
                                    else if(cnt_scl == SCL_3_4)begin
                                        sda_out <= 1'b1;
                                    end
                                    else begin
                                        sda_out <= sda_out;
                                    end
                                end
                    default :   sda_out <= 1'b1;
                endcase
            end
        end
    
    //****************************************************************
    //--数据接收
    //****************************************************************
    
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                rev_ack <= 1'b0;
                rev_data <= 1'b0;
            end
            else begin
                case(cstate)
                R_ACK   :   begin
                                if(cnt_scl == SCL_3_4)begin
                                    rev_ack <= sda_in;
                                end
                                else begin
                                    rev_ack <= rev_ack;
                                end
                            end
                RD_DATA :   begin
                                if(cnt_scl == SCL_3_4)begin
                                    rev_data[7-cnt_bit] <= sda_in;
                                end
                                else begin
                                    rev_data <= rev_data;
                                end
                            end
                default :   ;
                endcase
            end
        end
    
    //****************************************************************
    //--接口输出
    //****************************************************************
       
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                done <= 1'b0;
            end
            else begin
                done <= t_ack2idle || r_ack2idle || stop2idle;
            end
        end
    
        //assign done = (t_ack2idle || r_ack2idle || stop2idle) ? 1'b1 : 1'b0;
    
        assign rd_data = (t_ack2idle || t_ack2stop) ? rev_data : 1'b0;
        assign rd_data_vld = t_ack2idle || t_ack2stop;
    
    
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429

    EEPROM控制模块:

    /**************************************功能介绍***********************************
    Date	: 2023年8月30日 
    Author	: majiko
    Version	: 1.0
    Description: EEPROM控制模块
    *********************************************************************************/
        
    module eeprom_control
    #(
        parameter ADDR_BIT = 8              //从机寄存器地址
    )
    (
        input       wire                        clk             ,
        input       wire                        rst_n           ,
        input       wire    [6:0]               device_id       ,//i2c从机设备地址
        input       wire                        wr_req          ,
        input       wire                        rd_req          ,
        input       wire    [ADDR_BIT - 1:0]    reg_addr        ,//配置寄存器地址
        input       wire                        reg_addr_vld    ,
        input       wire    [7:0]               wr_data         ,
        input       wire                        wr_data_vld     ,
    
        output      wire    [7:0]               rd_data         ,
        output      wire                        rd_data_vld     ,
        output      wire                        ready           ,
    
        output      wire                        i2c_scl         ,
        inout       wire                        i2c_sda          
    );
    
    //参数定义
        //命令宏定义
        `define START_BIT 5'b00001
        `define WRITE_BIT 5'b00010
        `define READ_BIT  5'b00100
        `define STOP_BIT  5'b01000
        `define ACK_BIT   5'b10000
    
        parameter   IDLE    = 6'b000_001,
                    WR_REQ  = 6'b000_010,
                    WR_WAIT = 6'b000_100,
                    RD_REQ  = 6'b001_000,
                    RD_WAIT = 6'b010_000,
                    DONE    = 6'b100_000;
    
        parameter   WR_CTRL_BYTE = 8'b1010_0000,
                    RD_CTRL_BYTE = 8'b1010_0001;
    
    //内部信号定义
        //状态寄存器
        reg         [5:0]   cstate          ;
        reg         [5:0]   nstate          ;
    
        //跳转条件定义
        wire                idle2rd_req     ;
        wire                idle2wr_req     ;
        wire                wr_req2wr_wait  ;
        wire                wr_wait2wr_req  ;
        wire                wr_wait2done    ;
        wire                rd_req2rd_wait  ;
        wire                rd_wait2done    ;
        wire                rd_wait2rd_req  ;
        wire                done2idle       ;
    
        wire                done            ;
    
    
        reg         [4:0]   cmd             ;
        reg                 cmd_vld         ;
        reg         [7:0]   op_wr_data      ;
    
        reg         [7:0]   addr_r          ;
        reg         [7:0]   wr_data_r       ;
    
        //字节计数器
        reg			[2:0]	cnt_byte	   	;
        wire				add_cnt_byte	;
        wire				end_cnt_byte	;
        reg         [2:0]   byte_mawr_addr  ;
    
    //****************************************************************
    //--寄存输入数据
    //****************************************************************
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                addr_r <= 1'b0;
            end
            else if(reg_addr_vld)begin
                addr_r <= reg_addr;
            end
            else begin
                addr_r <= addr_r;
            end
        end
    
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                wr_data_r <= 1'b0;
            end
            else if(wr_data_vld)begin
                wr_data_r <= wr_data;
            end
            else begin
                wr_data_r <= wr_data_r;
            end
        end
    
    //****************************************************************
    //--状态机
    //****************************************************************
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                cstate <= IDLE;
            end
            else begin
                cstate <= nstate;
            end
        end
    
        always @(*)begin
            case(cstate)
                IDLE    :   begin
                                if(idle2rd_req)begin
                                    nstate = RD_REQ;
                                end
                                else if(idle2wr_req)begin
                                    nstate = WR_REQ;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                WR_REQ  :   begin
                                if(wr_req2wr_wait)begin
                                    nstate = WR_WAIT;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                WR_WAIT :   begin
                                if(wr_wait2done)begin
                                    nstate = DONE;
                                end
                                else if(wr_wait2wr_req)begin
                                    nstate = WR_REQ;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                RD_REQ  :   begin
                                if(rd_req2rd_wait)begin
                                    nstate = RD_WAIT;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                RD_WAIT :   begin
                                if(rd_wait2done)begin
                                    nstate = DONE;
                                end
                                else if(rd_wait2rd_req)begin
                                    nstate = RD_REQ;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                DONE    :   begin
                                if(done2idle)begin
                                    nstate = IDLE;
                                end
                                else begin
                                    nstate = cstate;
                                end
                            end
                default :   ;
            endcase
        end
    
    
    assign idle2rd_req    = cstate == IDLE && rd_req;
    assign idle2wr_req    = cstate == IDLE && wr_req;
    
    assign wr_req2wr_wait = cstate == WR_REQ  && 1'b1;
    assign wr_wait2wr_req = cstate == WR_WAIT && done;
    assign wr_wait2done   = cstate == WR_WAIT && end_cnt_byte;
    
    assign rd_req2rd_wait = cstate == RD_REQ  && 1'b1;
    assign rd_wait2done   = cstate == RD_WAIT && end_cnt_byte;
    assign rd_wait2rd_req = cstate == RD_WAIT && done;
    
    assign done2idle      = cstate == DONE && 1'b1;
    
    //****************************************************************
    //--字节计数器
    //****************************************************************
        
        always @(posedge clk or negedge rst_n)begin 
           if(!rst_n)begin
                cnt_byte <= 'd0;
            end 
            else if(add_cnt_byte)begin 
                if(end_cnt_byte)begin 
                    cnt_byte <= 'd0;
                end
                else begin 
                    cnt_byte <= cnt_byte + 1'b1;
                end 
            end
        end 
        
        assign add_cnt_byte = done;
        assign end_cnt_byte = add_cnt_byte && cnt_byte == byte_mawr_addr - 1'b1;
        
        always @(posedge clk or negedge rst_n) begin
            if(!rst_n)begin
                byte_mawr_addr <= 1'b1;
            end
            else if(wr_req)begin
                byte_mawr_addr <= 'd3;
            end
            else if(rd_req)begin
                byte_mawr_addr <= 'd4;
            end
            else if(end_cnt_byte)begin
                byte_mawr_addr <= 1'b1;
            end
            else begin
                byte_mawr_addr <= byte_mawr_addr;
            end
        end
    
    //****************************************************************
    //--接口模块控制
    //****************************************************************
    
        task TX;
            input           task_cmd_vld;
            input   [4:0]   task_cmd;
            input   [7:0]   task_wr_data;
            begin
                cmd_vld    = task_cmd_vld;
                cmd        = task_cmd;
                op_wr_data = task_wr_data;
            end
        endtask
    
        always @(posedge clk or negedge rst_n) begin
            if(!rst_n)begin
                TX(0,5'h0,8'h00);
            end
            else begin
                case(cstate)
                    RD_REQ  :   case(cnt_byte)
                                    0   :   TX(1,(`START_BIT | `WRITE_BIT),WR_CTRL_BYTE);//写控制字节
                                    1   :   TX(1,(`WRITE_BIT),addr_r[7:0]);//写地址
                                    2   :   TX(1,(`START_BIT | `WRITE_BIT),RD_CTRL_BYTE);//读控制字节
                                    3   :   TX(1,(`ACK_BIT| `READ_BIT | `STOP_BIT),8'h00);//读数据
                                    default :   TX(0,cmd,op_wr_data);
                                endcase
                    WR_REQ  :   case(cnt_byte)
                                    0   :   TX(1,(`START_BIT | `WRITE_BIT),WR_CTRL_BYTE);//写控制字节
                                    1   :   TX(1,(`WRITE_BIT),addr_r[7:0]);//写地址
                                    2   :   TX(1,(`WRITE_BIT | `STOP_BIT),wr_data_r);//写数据
                                    default :   TX(0,cmd,op_wr_data);
                                endcase
                    default :   TX(0,cmd,op_wr_data);
                endcase
            end
        end
    
    
        eeprom_driver u_eeprom_driver( 
            /*input       wire            */.clk         (clk           ),
            /*input       wire            */.rst_n       (rst_n         ),
            /*input       wire    [7:0]   */.wr_data     (op_wr_data    ),
            /*input       wire    [4:0]   */.cmd         (cmd           ),
            /*input       wire            */.cmd_vld     (cmd_vld       ),
    
            /*inout       wire            */.i2c_sda     (i2c_sda       ),
            /*output      wire            */.i2c_scl     (i2c_scl       ),
    
            /*output      wire    [7:0]   */.rd_data     (rd_data       ),
            /*output      wire            */.rd_data_vld (rd_data_vld   ),
            /*output      wire            */.done        (done          ),
            /*output      reg             */.rev_ack     () 
        );
    
        // iic_interface iic_interface_inst(
            // /* input            */.clk          (clk        ),
            // /* input            */.rst_n        (rst_n      ),
            // /* input   [4:0]    */.cmd          (cmd        ),
            // /* input            */.cmd_vld      (cmd_vld    ),
            // /* output           */.done         (done       ),   //操作结束
            // /* output  reg      */.rev_ack      (           ),   //接收到的响应信号
            // /* input   [7:0]    */.wr_data      (op_wr_data ),   //伴随cmd_vld信号一起接收写数据
            // /* output  [7:0]    */.rd_data      (rd_data    ),
            // /* output           */.rd_data_vld  (rd_data_vld),
            // /* output reg       */.iic_scl      (i2c_scl    ),
            // /* inout            */.iic_sda      (i2c_sda    ) 
        // );
    
    
        assign ready = cstate == IDLE;
    
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310

    UART RX模块:

    //****************************************************************
    //--majiko 2023-8-15 UART RX模块
    //****************************************************************
    module uart_rx 
    #(
        parameter   BORT        = 20'd115200,
        parameter   CLOCK       = 50_000_000,
        parameter   CHECK_BIT   = "None"      //"None" 无校验,"Odd" 奇校验,"Even" 偶校验
    )
    (
        input       wire             clk         ,
        input       wire             rst_n       ,
        input       wire             ready       ,//准备接受数据信号
        input       wire             rx          ,
    
        output      wire             rx_data_vld ,//数据有效信号
        output      wire     [7:0]   rx_data      
    );
    
    //参数定义
        parameter TIME_BORT = CLOCK/BORT;
    
        //状态机状态定义
        parameter   IDLE  = 4'b0001,//空闲状态电平默认拉高
                    START = 4'b0010,//起始位赋值
                    DATA  = 4'b0100,//数据位赋值
                    CHECK = 4'b1000;
        
        //波特率115200 1bit传输时间计数器参数
    
    //内部信号定义
        //状态寄存器
        reg         [3:0]   cstate          ;
        reg         [3:0]   nstate          ;
    
        //状态跳转条件
        wire                idle2start      ;
        wire                start2data      ;
        wire                data2idle       ;
        wire                data2check      ;
        wire                check2idle      ;
    
        //1Baud时间计数器
        reg			[8:0]	cnt_bort	   	;
        wire				add_cnt_bort	;
        wire				end_cnt_bort	;
    
        //比特计数器(复用)
        reg			[2:0]	cnt_bit	   	    ;
        wire				add_cnt_bit	    ;
        wire				end_cnt_bit	    ;
        reg         [3:0]   bit_max         ;//计数器复用信号
    
        reg         [7:0]   rx_temp         ;    
        
        reg                 check_bit       ;
        wire                check_temp      ;
    
        reg                 rx_r1           ;
        reg                 rx_r2           ;
        wire                rx_nedge        ;
    
    //rx同步至时钟域 并检测下降沿
        always@(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                rx_r1 <= 1'b1;
                rx_r2 <= 1'b1;
            end
            else begin
                rx_r1 <= rx;
                rx_r2 <= rx_r1;
            end
        end
    
        assign rx_nedge = ~rx_r1 && rx_r2;
    
    //三段式状态机
        //第一段 时序逻辑
        always @(posedge clk or negedge rst_n) begin
            if(!rst_n)begin
                cstate <= IDLE;
            end
            else begin
                cstate <= nstate;
            end
        end
    
    
        //第二段 组合逻辑
        always @(*)begin
            case (cstate)
                IDLE :  begin
                            if(idle2start)begin
                                nstate = START;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
                START:  begin
                            if(start2data)begin
                                nstate = DATA;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
                DATA :  begin
                            if(data2idle)begin
                                nstate = IDLE;
                            end
                            else if(data2check)begin
                                nstate = CHECK;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
                CHECK:  begin
                            if(check2idle)begin
                                nstate = IDLE;
                            end
                            else begin
                                nstate = cstate;
                            end
                        end
                default :   nstate = IDLE;
            endcase
        end
    
        assign idle2start = cstate == IDLE  && rx_nedge;//检测到开始位,结束空闲状态,开始接收数据
        assign start2data = cstate == START && end_cnt_bit;
        assign data2idle  = cstate == DATA  && end_cnt_bit && CHECK_BIT == "None";
        assign data2check = cstate == DATA  && end_cnt_bit;
        assign check2idle = cstate == CHECK && end_cnt_bit;
    
        //1Baud所需时间
        always @(posedge clk or negedge rst_n)begin 
           if(!rst_n)begin
                cnt_bort <= 'd0;
            end 
            else if(add_cnt_bort)begin 
                if(end_cnt_bort)begin 
                    cnt_bort <= 'd0;
                end
                else begin 
                    cnt_bort <= cnt_bort + 1'b1;
                end 
            end
        end 
        
        assign add_cnt_bort = cstate != IDLE;
        assign end_cnt_bort = add_cnt_bort && cnt_bort == TIME_BORT - 1'b1;
    
        //8bit共需时间
        always @(posedge clk or negedge rst_n)begin 
           if(!rst_n)begin
                cnt_bit <= 'd0;
            end 
            else if(add_cnt_bit)begin 
                if(end_cnt_bit)begin 
                    cnt_bit <= 'd0;
                end
                else begin 
                    cnt_bit <= cnt_bit + 1'b1;
                end 
            end
        end 
        
        assign add_cnt_bit = end_cnt_bort;
        assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max - 1'b1;
    
    //bit计数器复用
        always@(*)begin
            case(cstate)
                IDLE    :   bit_max = 1'b0;
                START   :   bit_max = 1'b1;
                DATA    :   bit_max = 4'd8;//8位数据位
                CHECK   :   bit_max = 1'b1;//校验位
                default :   bit_max = 1'b0;
            endcase
        end
    
    
    //状态输出
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                rx_temp <= 1'b0;
            end
            else if(cstate == DATA && cnt_bort == (TIME_BORT >> 1))begin
                rx_temp[cnt_bit] <= rx_r1;
            end
            else begin
                rx_temp <= rx_temp;
            end
        end
    
        assign rx_data = rx_temp;
    
    //校验位
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                check_bit <= 1'b0;
            end
            else if(cstate == CHECK && cnt_bort == (TIME_BORT >> 1))begin
                check_bit <= rx;
            end
            else begin
                check_bit <= check_bit;
            end
        end
        
        assign check_temp = CHECK_BIT == "Odd" ? ~^rx_data : ^rx_data;
    
        assign rx_data_vld = CHECK_BIT == "None" ? data2idle 
                            : (check2idle && check_temp == check_bit) ? 1
                            : 0;
        
        
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220

    UART TX模块:

    //****************************************************************
    //--majiko 2023-8-15 UART TX模块
    //****************************************************************
    module uart_tx 
    #( 
        parameter   BORT      = 20'd115200,//波特率
        parameter   CLOCK     = 50_000_000,//系统时钟参数
        parameter   CHECK_BIT = "None"     //"None" 无校验,"Odd" 奇校验,"Even" 偶校验
    ) 
    (
        input       wire             clk         ,
        input       wire             rst_n       ,
        input       wire    [7:0]    tx_data     ,
        input       wire             tx_data_vld ,//数据有效信号
    
        output      wire             ready       ,//准备接受数据信号
        output      reg              tx  
    );
    
    //参数定义
        parameter TIME_BORT = CLOCK/BORT;
    
        //状态机状态定义
        parameter   IDLE  = 5'b00001,//空闲状态电平默认拉高
                    START = 5'b00010,//起始位赋值
                    DATA  = 5'b00100,//数据位赋值
                    CHECK = 5'b01000,//奇偶校验位
                    STOP  = 5'b10000;//停止位赋值
        
        //波特率115200 1bit传输时间计数器参数
    
    //内部信号定义
        //状态寄存器
        reg         [4:0]   cstate          ;
        reg         [4:0]   nstate          ;
    
        //状态跳转条件
        wire                idle2start      ;
        wire                start2data      ;
        wire                data2check      ;
        wire                data2stop       ;              
        wire                check2stop      ;
        wire                stop2idle       ;
    
        //1Baud时间计数器
        reg			[8:0]	cnt_bort	   	;
        wire				add_cnt_bort	;
        wire				end_cnt_bort	;
    
        //比特计数器(复用)
        reg			[2:0]	cnt_bit	   	    ;
        wire				add_cnt_bit	    ;
        wire				end_cnt_bit	    ;
        reg         [3:0]   bit_max         ;//计数器复用信号
    
        reg         [7:0]   tx_data_r       ;//寄存数据
    
        wire                check_bit       ;
         
    
    //三段式状态机
        //第一段 时序逻辑
        always @(posedge clk or negedge rst_n) begin
            if(!rst_n)begin
                cstate <= IDLE;
            end
            else begin
                cstate <= nstate;
            end
        end
    
    
        //第二段 组合逻辑
        always @(*)begin
            case (cstate)
                IDLE :  begin
                            if(idle2start)begin
                                nstate <= START;
                            end
                            else begin
                                nstate <= cstate;
                            end
                        end
                START:  begin
                            if(start2data)begin
                                nstate <= DATA;
                            end
                            else begin
                                nstate <= cstate;
                            end
                        end
                DATA :  begin
                            if(data2check)begin
                                nstate <= CHECK;
                            end
                            else if(data2stop)begin
                                nstate <= STOP;
                            end
                            else begin
                                nstate <= cstate;
                            end
                        end
                CHECK:  begin
                            if(check2stop)begin
                                nstate <= STOP;
                            end
                            else begin
                                nstate <= cstate;
                            end
                        end
                STOP :  begin
                            if(stop2idle)begin
                                nstate <= IDLE;
                            end
                            else begin
                                nstate <= cstate;
                            end
                        end
                default :   nstate <= IDLE;
            endcase
        end
    
        assign idle2start = cstate == IDLE  && tx_data_vld;//数据有效信号拉高,结束空闲状态,开始接收数据
        assign start2data = cstate == START && end_cnt_bit;
        assign data2check = cstate == DATA  && end_cnt_bit;
        assign data2stop  = cstate == DATA  && end_cnt_bit && CHECK_BIT == "None"; 
        assign check2stop = cstate == CHECK && end_cnt_bit;
        assign stop2idle  = cstate == STOP  && end_cnt_bit;
    
        //1Baud所需时间
        always @(posedge clk or negedge rst_n)begin 
           if(!rst_n)begin
                cnt_bort <= 'd0;
            end 
            else if(add_cnt_bort)begin 
                if(end_cnt_bort)begin 
                    cnt_bort <= 'd0;
                end
                else begin 
                    cnt_bort <= cnt_bort + 1'b1;
                end 
            end
        end 
        
        assign add_cnt_bort = cstate != IDLE;
        assign end_cnt_bort = add_cnt_bort && cnt_bort == TIME_BORT - 1'b1;
    
        //不同状态bit数所需时间
        always @(posedge clk or negedge rst_n)begin 
           if(!rst_n)begin
                cnt_bit <= 'd0;
            end 
            else if(add_cnt_bit)begin 
                if(end_cnt_bit)begin 
                    cnt_bit <= 'd0;
                end
                else begin 
                    cnt_bit <= cnt_bit + 1'b1;
                end 
            end
        end 
    
        assign add_cnt_bit = end_cnt_bort;
        assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max - 1'b1;
    
    //bit计数器复用
        always@(*)begin
            case(cstate)
                IDLE    :   bit_max = 1'b0;
                START   :   bit_max = 1'b1;//1位起始位数据
                DATA    :   bit_max = 4'd8;//8位数据位
                CHECK   :   bit_max = 1'b1;//1位奇偶校验位
                STOP    :   bit_max = 1'b1;//1位停止位数据
                default :   bit_max = 1'b0;
            endcase
        end
        
    
    //状态输出
        //输入数据寄存
        always@(posedge clk or negedge rst_n)begin
            if(!rst_n)begin
                tx_data_r <= 1'b0;
            end
            else if(tx_data_vld)begin
                tx_data_r <= tx_data;
            end
            else begin
                tx_data_r <= tx_data_r;
            end
        end
    
        //奇偶校验位
        assign check_bit = CHECK_BIT == "Odd" ? ~^tx_data_r : ^tx_data_r;
    
        //数据输出
        always@(*)begin
            case(cstate)
                IDLE    :   tx = 1'b1;//空闲时为高电平
                START   :   tx = 1'b0;//起始位低电平
                DATA    :   tx = tx_data_r[cnt_bit];//数据位从低位开始发送
                CHECK   :   tx = check_bit;
                STOP    :   tx = 1'b1;//停止位高电平
                default :   tx = 1'b1;
            endcase
        end
    
        assign ready = cstate == IDLE;
        
        
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211

    顶层模块:

    module top(
        input       wire            clk         ,
        input       wire            rst_n       ,
        input       wire            rx          ,
    	input	    wire            key_in		,
    
        inout       wire            i2c_sda     ,
        output      wire            i2c_scl     ,
        output      wire            tx 
    
    );
    
        wire             ready       ;
        wire    [7:0]    rx_data     ;
        wire    [7:0]    tx_data     ;
        wire             rx_data_vld ;
        wire             tx_data_vld ;
    
        wire             key_out     ;
    
    
    
    //模块例化
        eeprom_control  u_eeprom_control
        (
            /*input       wire                        */.clk             (clk           ),
            /*input       wire                        */.rst_n           (rst_n         ),
            /*input       wire    [6:0]               */.device_id       (7'b1010_000   ),
            /*input       wire                        */.wr_req          (rx_data_vld   ),
            /*input       wire                        */.rd_req          (key_out       ),
            /*input       wire    [ADDR_BIT - 1:0]    */.reg_addr        (0),
            /*input       wire                        */.reg_addr_vld    (rx_data_vld   ),
            /*input       wire    [7:0]               */.wr_data         (rx_data       ),
            /*input       wire                        */.wr_data_vld     (rx_data_vld   ),
    
            /*output      wire    [7:0]               */.rd_data         (tx_data       ),
            /*output      wire                        */.rd_data_vld     (tx_data_vld   ),
            /*output      wire                        */.ready           (),
    
            /*output      wire                        */.i2c_scl         (i2c_scl       ),
            /*inout       wire                        */.i2c_sda         (i2c_sda       )
        );
    
    
        // iic_control u_eeprom_control2
        // (
            // /*input       wire                        */.clk             (clk           ),
            // /*input       wire                        */.rst_n           (rst_n         ),
            // /*input       wire    [6:0]               */.device_id       (7'b1010_000   ),
            // /*input       wire                        */.wr_req          (rx_data_vld   ),
            // /*input       wire                        */.rd_req          (key_out       ),
            // /*input       wire    [ADDR_BIT - 1:0]    */.addr            (0),
            // /*input       wire                        */.addr_vld        (rx_data_vld   ),
            // /*input       wire    [7:0]               */.wr_data         (rx_data       ),
            // /*input       wire                        */.wr_data_vld     (rx_data_vld   ),
            // /*output      wire    [7:0]               */.rd_data         (tx_data       ),
            // /*output      wire                        */.rd_data_vld     (tx_data_vld   ),
            // /*output      wire                        */.ready           (),
            // /*output      wire                        */.iic_scl         (i2c_scl       ),
            // /*inout       wire                        */.iic_sda         (i2c_sda       )
        // );
    
        uart_rx u_uart_rx
        (
           .clk         (clk         ),
           .rst_n       (rst_n       ),
           .ready       (            ),
           .rx          (rx          ),
        
           .rx_data_vld (rx_data_vld ),
           .rx_data     (rx_data     ) 
        );
        
        uart_tx u_uart_tx
        (
           .clk         (clk         ),
           .rst_n       (rst_n       ),
           .tx_data     (tx_data     ),
           .tx_data_vld (tx_data_vld ),
        
           .ready       (ready       ),
           .tx          (tx          ) 
        );
    
        // ctrl u_ctrl (
            //  /*input        wire               */.clk         (clk         ),
            //  /*input        wire               */.rst_n       (rst_n       ),
            //  /*input        wire               */.rx_data_vld (rx_data_vld ),
            //  /*input        reg        [7:0]   */.rx_data     (rx_data     ),
            //  /*input        wire               */.ready       (ready       ),
            //  /*output       wire       [7:0]   */.tx_data     (),
            //  /*output       wire               */.tx_data_vld ()
        // );
    
    
        key_filter#(.WIDTH(1)) u_key_filter          
        (
            /*input       wire                    */.clk     (clk       ),
            /*input       wire                    */.rst_n   (rst_n     ),
            /*input       wire  [WIDTH - 1:0]     */.key_in  (key_in    ),
            /*output      reg   [WIDTH - 1:0]     */.key_out (key_out   )
        );
    
    
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106

    按键消抖模块:

    module key_filter#(parameter WIDTH = 4)           //参数化按键位宽
    (
        input       wire                    clk     ,
        input       wire                    rst_n   ,
        input       wire  [WIDTH - 1:0]     key_in  ,//按键输入信号
    
        output      reg   [WIDTH - 1:0]     key_out  //输出稳定的脉冲信号
    );
    
    parameter MAX = 20'd1_000_000;
    
    reg     [19:0]                  cnt_delay       ; //20ms延时计数寄存器
    wire                            add_cnt_delay   ; //开始计数的标志
    wire                            end_cnt_delay   ; //结束计数的标志
    
    reg     [WIDTH - 1:0]           key_r0          ; //同步
    reg     [WIDTH - 1:0]           key_r1          ; //打一拍
    reg     [WIDTH - 1:0]           key_r2          ; //打两拍
    
    wire    [WIDTH - 1:0]           nedge           ; //下降沿寄存器
    
    
    //同步打拍
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            key_r0 <= {WIDTH{1'b1}};
            key_r1 <= {WIDTH{1'b1}};
            key_r2 <= {WIDTH{1'b1}};
        end
        else begin
            key_r0 <= key_in; //同步
            key_r1 <= key_r0; //寄存一拍
            key_r2 <= key_r1; //寄存两拍
        end
    end
    
    //20ms计数器
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_delay <= 1'b0;
        end
        else if(add_cnt_delay )begin
            if(nedge)begin //检测到下降沿从0开始计数
                cnt_delay <= 1'b0;
            end
            else if(cnt_delay == MAX - 1'b1)begin
                cnt_delay <= cnt_delay; //计数计满结束后保持,避免产生多个输出脉冲
            end
            else begin
                cnt_delay <= cnt_delay + 1'b1;
            end
        end
        else begin
            cnt_delay <= 1'b0;
        end
    end
    
    assign nedge = ~key_r1 & key_r2; //下降沿检测
    assign add_cnt_delay = 1'b1; 
    assign end_cnt_delay = add_cnt_delay && cnt_delay == MAX - 1'b1;
    
    
    //key_out脉冲信号赋值
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            key_out <= 'd0;
        end
        else if(cnt_delay == MAX - 2'd2)begin //计数计满前一个脉冲时产生按键脉冲
            key_out <= ~key_in;
        end
        else begin
            key_out <= 'd0;
        end
    end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    五、实现效果

    在这里插入图片描述
    可以看出,能够正常进行单个字节的收发。

    参考资料

    https://blog.csdn.net/zhangduang_KHKW/article/details/121953275

  • 相关阅读:
    【Python 技能树共建】requests-html 库初识
    配置Tomcat时系统环境变量已经配置好,但是启动Tomcat时还是闪退的解决办法
    程序员如何转型做产品经理-我的转型之路
    java 选择排序
    【698. 划分为k个相等的子集】
    【译】.NET 8 网络改进(二)
    控制I/O设备四种方式
    Java中String对象的replaceAll方法调用性能优化小技巧
    【C++模拟实现】vector的模拟实现
    Java基础:通过Callable创建多线程
  • 原文地址:https://blog.csdn.net/qq_54347584/article/details/133646396