• IIC协议及其工程【FPGA】


    一、IIC协议

    1、IIC简介

    同步半双工、飞利浦公司设计。

    2、IIC中相关的术语

    1、应答信号(ACK)

    IIC总线上的所有数据都是以字节传输的,发送端每次发送一个字节,就必须在第9个脉冲周期释放SDA,等待接收端反馈一个应答信号。应答信号为低电平,称为有效应答位(ACK)。
    通信双方的回应信号,在时钟高电平期间,数据引脚为低电平。

    2、无应答信号(NOACK)

    应答信号为高电平时,称为非应答位(NACK)。
    通常用于主机发送给从机的信号,在时钟高电平期间,数据引脚为高电平。

    3、虚写

    使从机内的存储单元地址指针指向我们想要读取的存储单元地址处,首先发送了一次Dummy Write也就是虚写操作,只所以称为虚写,是因为我们并不是真的要写数据,而是通过这种虚写操作使地址指针指向虚写操作中字地址的位置,等从机应答后,就可以以当前地址读的方式读数据了

    3、IIC的时序

    sda在时钟低电平期间更新数据
    在时钟高电平期间采集数据

    二、EEPROM

    1、时钟频率

    支持最大400K的频率,跟芯片的供电电压相关,电压越大,支持的时钟频率也就越大

    2、起始位和停止位

    起始位分为高电平持续时间和低电平持续时间,两者的时间长度都为时钟周期的1/4。
    在不同的工作电压下,需要维持的时间也是不同的。

    停止位也是对应有不同的持续时间

    3、总线时序

    需要重点关注SDA引脚数据变化的位置,发生在时钟引脚SCL的低电平期间

    4、控制信号bit分配

    每个IIC设备的地址有一段地址是固定的,有一段是根据外围的引脚设置,最后一个bit(R/W)设置本次控制信号是读还是写,1表示读操作,0表示写操作。
    发送控制字节的时候先发送地址的高位。
    固定的地址信息“1010”,是IIC接口的EEPROM固定的地址头部信息。
    摄像头的地址全都是固定的,没有引脚配置选项。

    5、写操作

    1、字节写

    每次写入一个字节(8bit)的数据。
    主机在数据信号发送完成之后,发送应答信号给从机,并且立即发送停止位信号。

    2、页写

    发送一次地址信息,一直传输数据存储数据,直到发送停止信号。

    6、读操作

    1、随机读

    读取任意地址的数据,读取一次数据之后,主机发送无应答信号停止数据传输

    2、顺序读

    写入一个地址信号之后,连续获取该地址之后的数据,直到主机发送无应答信号(在随机读的基础上),从机才会停止发送数据。

    三、工程

    通过IIC协议完成对eeprom的读写

    读写控制

    `include "param.v"
    
    module eeprom_rw #(parameter WR_LEN = 3,RD_LEN = 4)(
        input               clk     ,
        input               rst_n   ,
        
        input       [7:0]   din     ,
        input               din_vld ,
        input               rd_en   ,
        output      [7:0]   dout    ,//控制器输出数据
        output              dout_vld,
        input               busy    ,
    
        output              req     ,
        output      [3:0]   cmd     ,
        output      [7:0]   wr_data ,
        input       [7:0]   rd_data ,
        input               done     //传输完成标志
      
    );
    
    
    //状态机参数
        localparam      IDLE    = 6'b00_0001    ,
                        WR_REQ  = 6'b00_0010    ,//写传输 发送请求、命令、数据
                        WAIT_WR = 6'b00_0100    ,//等待一个字节传完
                        RD_REQ  = 6'b00_1000    ,//读传输 发送请求、命令、数据
                        WAIT_RD = 6'b01_0000    ,//等待一个自己传完
                        DONE    = 6'b10_0000    ;//一次读或写完成
    //信号定义
        reg     [5:0]   state_c         ;
        reg     [5:0]   state_n         ;
    
        reg     [7:0]   cnt_byte        ;//数据传输 字节计数器
        wire            add_cnt_byte    ;
        wire            end_cnt_byte    ;
    
        reg             tx_req          ;//请求
        reg     [3:0]   tx_cmd          ;
        reg     [7:0]   tx_data         ;
        
        reg     [8:0]   wr_addr         ;//写eeprom地址
        reg     [8:0]   rd_addr         ;//读eeprom地址
        
        wire            wfifo_rd        ; 
        wire            wfifo_wr        ;
        wire            wfifo_empty     ;
        wire            wfifo_full      ;
        wire    [7:0]   wfifo_qout      ;
        wire    [5:0]   wfifo_usedw     ;
       
        wire            rfifo_rd        ;
        wire            rfifo_wr        ;
        wire            rfifo_empty     ;
        wire            rfifo_full      ;
        wire    [7:0]   rfifo_qout      ;
        wire    [5:0]   rfifo_usedw     ;
    
        reg             rd_flag         ;
        reg     [7:0]   user_data       ;
        reg             user_data_vld   ;
    
        wire            idle2wr_req     ; 
        wire            wr_req2wait_wr  ;
        wire            wait_wr2wr_req  ;
        wire            wait_wr2done    ;
        wire            idle2rd_req     ;
        wire            rd_req2wait_rd  ;
        wire            wait_rd2rd_req  ;
        wire            wait_rd2done    ;
        wire            done2idle       ;
    
    //状态机设计
        always @(posedge clk or negedge rst_n) begin 
            if (rst_n==0) begin
                state_c <= IDLE ;
            end
            else begin
                state_c <= state_n;
           end
        end
        
        always @(*) begin 
            case(state_c)  
                IDLE :begin
                    if(idle2wr_req)
                        state_n = WR_REQ ;
                    else if(idle2rd_req)
                        state_n = RD_REQ ;
                    else 
                        state_n = state_c ;
                end
                WR_REQ :begin
                    if(wr_req2wait_wr)
                        state_n = WAIT_WR ;
                    else 
                        state_n = state_c ;
                end
                WAIT_WR :begin
                    if(wait_wr2wr_req)
                        state_n = WR_REQ ;
                    else if(wait_wr2done)
                        state_n = DONE ;
                    else 
                        state_n = state_c ;
                end
                RD_REQ :begin
                    if(rd_req2wait_rd)
                        state_n = WAIT_RD ;
                    else 
                        state_n = state_c ;
                end
                WAIT_RD :begin
                    if(wait_rd2rd_req)
                        state_n = RD_REQ ;
                    else if(wait_rd2done)
                        state_n = DONE ;
                    else 
                        state_n = state_c ;
                end
                DONE :begin
                    if(done2idle)
                        state_n = IDLE ;
                    else 
                        state_n = state_c ;
                end
                default : state_n = IDLE ;
            endcase
        end
        
        assign idle2wr_req      = state_c==IDLE     && (wfifo_usedw > WR_LEN-2);
        assign wr_req2wait_wr   = state_c==WR_REQ   && (1'b1);
        assign wait_wr2wr_req   = state_c==WAIT_WR  && (done & cnt_byte < WR_LEN-1);
        assign wait_wr2done     = state_c==WAIT_WR  && (end_cnt_byte);
        assign idle2rd_req      = state_c==IDLE     && (rd_en);
        assign rd_req2wait_rd   = state_c==RD_REQ   && (1'b1);
        assign wait_rd2rd_req   = state_c==WAIT_RD  && (done & cnt_byte < RD_LEN-1);
        assign wait_rd2done     = state_c==WAIT_RD  && (end_cnt_byte);
        assign done2idle        = state_c==DONE     && (1'b1);
        
    //cnt_byte  
        always @(posedge clk or negedge rst_n) begin 
            if (rst_n==0) begin
                cnt_byte <= 0; 
            end
            else if(add_cnt_byte) begin
                if(end_cnt_byte)
                    cnt_byte <= 0; 
                else
                    cnt_byte <= cnt_byte+1 ;
           end
        end
        assign add_cnt_byte = (state_c==WAIT_WR | state_c==WAIT_RD) & done;
        assign end_cnt_byte = add_cnt_byte  && cnt_byte == ((state_c==WAIT_WR)?
                                                            (WR_LEN-1):(RD_LEN-1));
    //输出
    
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                TX(1'b0,4'd0,8'd0);
            end
            else if(state_c==WR_REQ)begin
                case(cnt_byte)
                    0           :TX(1'b1,{`CMD_START | `CMD_WRITE},{`I2C_ADR,wr_addr[8],`WR_BIT});//发起始位、写控制字
                    1           :TX(1'b1,`CMD_WRITE,wr_addr[7:0]);   //发 写地址
                    WR_LEN-1  :TX(1'b1,{`CMD_WRITE | `CMD_STOP},wfifo_qout);  //最后一个字节时 发数据、停止位
                    default     :TX(1'b1,`CMD_WRITE,wfifo_qout);    //中间发数据(如果有)
                endcase 
            end
            else if(state_c==RD_REQ)begin
                case(cnt_byte)
                    0           :TX(1'b1,{`CMD_START | `CMD_WRITE},{`I2C_ADR,rd_addr[8],`WR_BIT});//发起始位、写控制字
                    1           :TX(1'b1,`CMD_WRITE,rd_addr[7:0]);   //发 读地址
                    2           :TX(1'b1,{`CMD_START | `CMD_WRITE},{`I2C_ADR,rd_addr[8],`RD_BIT});//发起始位、读控制字
                    RD_LEN-1    :TX(1'b1,{`CMD_READ | `CMD_STOP},0);  //最后一个字节时 读数据、发停止位
                    default     :TX(1'b1,`CMD_READ,0);    //中间读数据(如果有)
                endcase 
            end
            else begin 
                 TX(1'b0,tx_cmd,tx_data);
            end 
        end
    //用task发送请求、命令、数据(地址+数据)
        task TX;   
            input                   req     ;
            input       [3:0]       command ;
            input       [7:0]       data    ;
            begin 
                tx_req  = req;
                tx_cmd  = command;
                tx_data = data;
            end 
        endtask 
    
    //wr_addr   rd_addr
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                wr_addr <= 0;
            end
            else if(wait_wr2done)begin
                wr_addr <= wr_addr + WR_LEN-2;
            end
        end
        
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                rd_addr <= 0;
            end
            else if(wait_rd2done)begin
                rd_addr <= rd_addr + RD_LEN - 3;
            end
        end
    
    //rd_flag
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                rd_flag <= 1'b0;
            end
            else if(~rfifo_empty)begin
                rd_flag <= 1'b1;
            end
            else begin 
                rd_flag <= 1'b0;
            end 
        end
    
    //user_data user_data_vld
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                user_data <= 0;
                user_data_vld <= 0;
            end
            else begin
                user_data <= rfifo_qout;
                user_data_vld <= rfifo_rd;
            end
        end
    
      
    //输出
    
        assign req     = tx_req ; 
        assign cmd     = tx_cmd ; 
        assign wr_data = tx_data; 
    
        assign dout    = user_data;//控制器输出数据
        assign dout_vld= user_data_vld;
    
    //fifo例化
    
    wrfifo	u_wrfifo (
    	.aclr   (~rst_n     ),
    	.clock  (clk        ),
    	.data   (din        ),
    	.rdreq  (wfifo_rd   ),
    	.wrreq  (wfifo_wr   ),
    	.empty  (wfifo_empty),
    	.full   (wfifo_full ),
    	.q      (wfifo_qout ),
    	.usedw  (wfifo_usedw)
    	);
    
        assign wfifo_rd = state_c==WAIT_WR && done && cnt_byte > 1;
        assign wfifo_wr = ~wfifo_full & din_vld;
    
    rdfifo	u_rdfifo (
    	.aclr   (~rst_n     ),
    	.clock  (clk        ),
    	.data   (rd_data    ),
    	.rdreq  (rfifo_rd   ),
    	.wrreq  (rfifo_wr   ),
    	.empty  (rfifo_empty),
    	.full   (rfifo_full ),
    	.q      (rfifo_qout ),
    	.usedw  (rfifo_usedw)
    	);
    
        assign rfifo_wr = ~rfifo_full && state_c==WAIT_RD && cnt_byte > 2 && done;
        assign rfifo_rd = rd_flag && ~busy;
    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

    IIC接口

    `include "param.v"
    
    module i2c_master(
        input               clk         ,
        input               rst_n       ,
    
        input               req         ,
        input       [3:0]   cmd         ,
        input       [7:0]   din         ,
    
        output      [7:0]   dout        ,
        output              done        ,
    
        output              i2c_scl     ,
        input               i2c_sda_i   ,
        output              i2c_sda_o   ,
        output              i2c_sda_oe     
        );
    
    //状态机参数定义
    
        localparam  IDLE  = 7'b000_0001,
                    START = 7'b000_0010,
                    WRITE = 7'b000_0100,
                    RACK  = 7'b000_1000,
                    READ  = 7'b001_0000,
                    SACK  = 7'b010_0000,
                    STOP  = 7'b100_0000;
    
    //信号定义
    
        reg     [6:0]       state_c     ;
        reg     [6:0]       state_n     ;
    
        reg     [8:0]       cnt_scl     ;//产生i2c时钟
        wire                add_cnt_scl ;
        wire                end_cnt_scl ;
        reg     [3:0]       cnt_bit     ;//传输数据 bit计数器
        wire                add_cnt_bit ;
        wire                end_cnt_bit ;
        reg     [3:0]       bit_num     ;
        
        reg                 scl         ;//输出寄存器
        reg                 sda_out     ;
        reg                 sda_out_en  ;
    
        reg     [7:0]       rx_data     ;
        reg                 rx_ack      ;
        reg     [3:0]       command     ;
        reg     [7:0]       tx_data     ;//发送数据
    
        wire                idle2start  ; 
        wire                idle2write  ; 
        wire                idle2read   ; 
        wire                start2write ; 
        wire                start2read  ; 
        wire                write2rack  ; 
        wire                read2sack   ; 
        wire                rack2stop   ; 
        wire                sack2stop   ; 
        wire                rack2idle   ; 
        wire                sack2idle   ; 
        wire                stop2idle   ; 
    
    
    //状态机
        always @(posedge clk or negedge rst_n) begin 
            if (rst_n==0) begin
                state_c <= IDLE ;
            end
            else begin
                state_c <= state_n;
           end
        end
        
        always @(*) begin 
            case(state_c)  
                IDLE :begin
                    if(idle2start)
                        state_n = START ;
                    else if(idle2write)
                        state_n = WRITE ;
                    else if(idle2read)
                        state_n = READ ;
                    else 
                        state_n = state_c ;
                end
                START :begin
                    if(start2write)
                        state_n = WRITE ;
                    else if(start2read)
                        state_n = READ ;
                    else 
                        state_n = state_c ;
                end
                WRITE :begin
                    if(write2rack)
                        state_n = RACK ;
                    else 
                        state_n = state_c ;
                end
                RACK :begin
                    if(rack2stop)
                        state_n = STOP ;
                    else if(rack2idle)
                        state_n = IDLE ;
                    else 
                        state_n = state_c ;
                end
                READ :begin
                    if(read2sack)
                        state_n = SACK ;
                    else 
                        state_n = state_c ;
                end
                SACK :begin
                    if(sack2stop)
                        state_n = STOP ;
                    else if(sack2idle)
                        state_n = IDLE ;
                    else 
                        state_n = state_c ;
                end
                STOP :begin
                    if(stop2idle)
                        state_n = IDLE ;
                    else 
                        state_n = state_c ;
                end
                default : state_n = IDLE ;
            endcase
        end
        
        assign idle2start  = state_c==IDLE  && (req && (cmd&`CMD_START));
        assign idle2write  = state_c==IDLE  && (req && (cmd&`CMD_WRITE));
        assign idle2read   = state_c==IDLE  && (req && (cmd&`CMD_READ ));
        assign start2write = state_c==START && (end_cnt_bit && (command&`CMD_WRITE));
        assign start2read  = state_c==START && (end_cnt_bit && (command&`CMD_READ ));
        assign write2rack  = state_c==WRITE && (end_cnt_bit);
        assign read2sack   = state_c==READ  && (end_cnt_bit);
        assign rack2stop   = state_c==RACK  && (end_cnt_bit && ((command&`CMD_STOP ) || rx_ack));
        assign sack2stop   = state_c==SACK  && (end_cnt_bit && (command&`CMD_STOP ));
        assign rack2idle   = state_c==RACK  && (end_cnt_bit && ((command&`CMD_STOP ) == 0));
        assign sack2idle   = state_c==SACK  && (end_cnt_bit && (command&`CMD_STOP ) == 0);
        assign stop2idle   = state_c==STOP  && (end_cnt_bit);
        
    //计数器
        always @(posedge clk or negedge rst_n) begin 
            if (rst_n==0) begin
                cnt_scl <= 0; 
            end
            else if(add_cnt_scl) begin
                if(end_cnt_scl)
                    cnt_scl <= 0; 
                else
                    cnt_scl <= cnt_scl+1 ;
           end
        end
        assign add_cnt_scl = (state_c != IDLE);
        assign end_cnt_scl = add_cnt_scl && cnt_scl == (`SCL_PERIOD)-1 ;
    
        always @(posedge clk or negedge rst_n) begin 
            if (rst_n==0) begin
                cnt_bit <= 0; 
            end
            else if(add_cnt_bit) begin
                if(end_cnt_bit)
                    cnt_bit <= 0; 
                else
                    cnt_bit <= cnt_bit+1 ;
           end
        end
        assign add_cnt_bit = (end_cnt_scl);
        assign end_cnt_bit = add_cnt_bit  && cnt_bit == (bit_num)-1 ;
    
        always  @(*)begin
            if(state_c == WRITE | state_c == READ) begin
                bit_num = 8;
            end
            else begin 
                bit_num = 1;
            end 
        end
    //command
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                command <= 0;
            end
            else if(req)begin
                command <= cmd;
            end
        end
    
    //tx_data
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                tx_data <= 0;
            end
            else if(req)begin
                tx_data <= din;
            end
        end
    
    //scl
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                scl <= 1'b1;
            end
            else if(idle2start | idle2write | idle2read)begin//开始发送时,拉低
                scl <= 1'b0;
            end
            else if(add_cnt_scl && cnt_scl == `SCL_HALF-1)begin//半个周期时拉低
                scl <= 1'b1;
            end 
            else if(end_cnt_scl && ~stop2idle)begin //若继续发送下一bit则继续拉低,否则保持高
                scl <= 1'b0;
            end 
        end
    
    //sda_out
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                sda_out <= 1'b1;
            end
            else if(state_c == START)begin          //发起始位
                if(cnt_scl == `LOW_HLAF)begin       //时钟低电平时拉高sda总线
                    sda_out <= 1'b1;
                end
                else if(cnt_scl == `HIGH_HALF)begin    //时钟高电平时拉低sda总线 
                    sda_out <= 1'b0;                //保证从机能检测到起始位
                end 
            end 
            else if(state_c == WRITE && cnt_scl == `LOW_HLAF)begin  //scl低电平时发送数据   并串转换
                sda_out <= tx_data[7-cnt_bit];      
            end 
            else if(state_c == SACK && cnt_scl == `LOW_HLAF)begin  //发应答位
                sda_out <= (command&`CMD_STOP)?1'b1:1'b0;
            end 
            else if(state_c == STOP)begin //发停止位
                if(cnt_scl == `LOW_HLAF)begin       //时钟低电平时拉低sda总线
                    sda_out <= 1'b0;
                end
                else if(cnt_scl == `HIGH_HALF)begin    //时钟高电平时拉高sda总线 
                    sda_out <= 1'b1;                //保证从机能检测到停止位
                end 
            end 
        end
    
    //sda_out_en  总线输出数据使能
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                sda_out_en <= 1'b0;
            end
            else if(idle2start | idle2write | read2sack | rack2stop)begin
                sda_out_en <= 1'b1;
            end
            else if(idle2read | start2read | write2rack | stop2idle)begin 
                sda_out_en <= 1'b0;
            end 
        end
    
    //rx_data       接收读入的数据
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                rx_data <= 0;
            end
            else if(state_c == READ && cnt_scl == `HIGH_HALF)begin
                rx_data[7-cnt_bit] <= i2c_sda_i;    //串并转换
            end
        end
    
    //rx_ack
        always  @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                rx_ack <= 1'b1;
            end
            else if(state_c == RACK && cnt_scl == `HIGH_HALF)begin
                rx_ack <= i2c_sda_i;
            end
        end
    
    //输出信号
    
        assign i2c_scl    = scl         ;
        assign i2c_sda_o  = sda_out     ;
        assign i2c_sda_oe = sda_out_en  ;
       
        assign dout = rx_data;
        assign done = rack2idle | sack2idle | stop2idle;
    
    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

    其它模块

    按键消抖
    串口

    四、参考

    【FPGA】FPGA基于i2c的eeprom读写

    五、源码

    https://github.com/IvanXiang/FPGA_IIC_EEPROM

  • 相关阅读:
    【CTO变形记】整体系统思维-从现象到本质
    【笔记】ABAQUS弹塑性分析
    南京邮电大学电工电子基础B实验六(组合逻辑电路)
    岭回归与LASSO回归:解析两大经典线性回归方法
    【MySQL】一文带你理解索引事务及其原理
    wsl中安装虚拟环境virtualenv,pycharm中配置wsl解释器
    我开源了团队内部基于SpringBoot Web快速开发的API脚手架v1.6.0更新
    Math对象和Date对象常用方法
    UnityShader入门精要——表面着色器
    【算法练习Day27】买卖股票的最佳时机 II&&跳跃游戏&&跳跃游戏 II
  • 原文地址:https://blog.csdn.net/xyf_fate/article/details/126855953