zoukankan      html  css  js  c++  java
  • 基于FPGA的I2C读写EEPROM

      I2C在芯片的配置中应用还是很多的,比如摄像头、VGA转HDMI转换芯片,之前博主分享过一篇I2C协议的基础学习IIC协议学习笔记,这篇就使用Verilog来实现EEPROM的读写,进行一个简单的I2C实战应用。

    EEPROM

    我使用的这个芯片是AT24C32,它手册上还有一种AT24C64,其实操作都是一样的,只是内存大小不同,AT24C32是32k(4096x8)AT24C64是64k(9=8192x8),

    SCL设置为频率200Khz

    SCL clk posedge data输入EEPROM

    SCL clk negedge data输出EEPROM

    SDA 双向Pin

    A2,A1,A0 Device Addr default all 0,只操作一片可悬空引脚。

    WP 接地正常读写,WP接Vcc写操作被禁止

    字节寻址地址,是由12(AT24C32)或13bit(AT24C64)的地址组成,需要操作16位字地址高3或4位忽略即可。

    Device Address    8’hA0写器件地址,8’hA1读器件地址

    写字节操作

    随机读字节操作

        我这个芯片是双字节数据地址,所以在写数据地址时要写两次,先是高字节后是低字节。

     

    开始结束标志

        这个I2C总线的时序是一致的。

     

    EEPROM应答

        输出应答scl的第九个周期给出,低电平应答。如果主机没有收到应答,需要重新配置。

    数据传输时序

        sda数据线在scl时钟的下降沿中间变化,可以避免产生误触开始结束标志。

    I2C Design

     

        i2c_start为高电平有效,传输完成后会产生一个i2c_done结束标志,表示操作完成。

    I2C状态转移图

    I2C写操作

    (1)产生start位

    (2)传送器件地址ID_Address,器件地址的最后一位为数据的传输方向位,R/W,低电平0表示主机往从机写数据(W),1表示主机从从机读数据(R)。这里按照手册给出的操作图,应该是W即低电平。ACK应答,应答是从机发送给主机的应答,这里不用管。

    (3)传送写入器件寄存器地址,即数据要写入的位置。同样ACK应答不用管。

    (4)传送要写入的数据。ACK应答不用管。

    (5)产生stop信号。

    I2C读操作

    (1)产生start信号

    (2)传送器件地址(写ID_Address),这里按照手册给出的操作图,最低位是W即低电平。ACK。

    (3)传送字地址(写REG_Address),ACK。

    (4)再次产生start信号

    (5)再传送一次器件地址,这里根据手册最低位是读R高电平,ACK。

    (6)读取一个字节的数据,读数据最后结束前无应答ACK信号。

    (7)产生stop信号。

        读写操作的写器件地址和写数据地址操作是一样的,状态转移图中读写操作中这两部分复用了,根据读写标志来判断。

        其他部分没啥好说的根据时序图写就行了,需要注意的一点是我们应该在sclk的高电平的中间采样数据,在sclk低电平的中间改变数据,当sclk为高电平的时候,sda为出现下降沿为start位, sda出现上升沿为stop位,所以在sclk为高电平的时候sda应该保持稳定不能随意乱动。这就又回到了数据传输有效的条件,只有在sclk为低电平期间,才允许数据变化,在高电平期间,不允许数据变化,否则就会出现起始位或结束位。

        EEPROM有个仿真模型,在夏雨闻老师的书里面就有,这个模型默认是200khz的sclk驱动,仿真的时候可以将时间参数改小,我这里也分享出来。

     

    仿真模型代码

      1 `timescale 1ns/1ns
      2 `define timeslice 1250
      3 //`define timeslice 300
      4 
      5 module EEPROM_AT24C64(
      6     scl, 
      7     sda
      8 );
      9     input scl;               //串行时钟线
     10     inout sda;               //串行数据线
     11     
     12     reg out_flag;            //SDA数据输出的控制信号
     13     
     14     reg[7:0] memory[8191:0]; //数组模拟存储器
     15     reg[12:0]address;        //地址总线
     16     reg[7:0]memory_buf;      //数据输入输出寄存器
     17     reg[7:0]sda_buf;         //SDA数据输出寄存器
     18     reg[7:0]shift;           //SDA数据输入寄存器
     19     reg[7:0]addr_byte_h;     //EEPROM存储单元地址高字节寄存器
     20     reg[7:0]addr_byte_l;     //EEPROM存储单元地址低字节寄存器
     21     reg[7:0]ctrl_byte;       //控制字寄存器
     22     reg[1:0]State;           //状态寄存器
     23     
     24     integer i;
     25     
     26     //---------------------------
     27     parameter  
     28         r7 = 8'b1010_1111,  w7 = 8'b1010_1110,   //main7
     29         r6 = 8'b1010_1101,  w6 = 8'b1010_1100,   //main6
     30         r5 = 8'b1010_1011,  w5 = 8'b1010_1010,   //main5
     31         r4 = 8'b1010_1001,  w4 = 8'b1010_1000,   //main4
     32         r3 = 8'b1010_0111,  w3 = 8'b1010_0110,   //main3
     33         r2 = 8'b1010_0101,  w2 = 8'b1010_0100,   //main2
     34         r1 = 8'b1010_0011,  w1 = 8'b1010_0010,   //main1
     35         r0 = 8'b1010_0001,  w0 = 8'b1010_0000;   //main0    
     36     //---------------------------
     37     
     38     assign sda = (out_flag == 1) ? sda_buf[7] : 1'bz;
     39     
     40     //------------寄存器和存储器初始化---------------
     41     initial
     42     begin
     43         addr_byte_h    = 0;
     44         addr_byte_l    = 0;
     45         ctrl_byte    = 0;
     46         out_flag     = 0;
     47         sda_buf      = 0;
     48         State        = 2'b00;
     49         memory_buf   = 0;
     50         address      = 0;
     51         shift        = 0;
     52         
     53         for(i=0;i<=8191;i=i+1)
     54             memory[i] = 0;  
     55     end
     56 
     57     //启动信号
     58     always@(negedge sda)
     59     begin
     60         if(scl == 1)
     61         begin
     62             State = State + 1;
     63             if(State == 2'b11)
     64                 disable write_to_eeprom;
     65         end 
     66     end
     67     
     68     //主状态机
     69     always@(posedge sda)
     70     begin
     71         if(scl == 1)                //停止操作
     72             stop_W_R;
     73         else
     74         begin
     75             casex(State)
     76                 2'b01:begin
     77                     read_in;
     78                     if(ctrl_byte == w7 || ctrl_byte == w6 
     79                         || ctrl_byte == w5  || ctrl_byte == w4
     80                         || ctrl_byte == w3  || ctrl_byte == w2
     81                         || ctrl_byte == w1  || ctrl_byte == w0)
     82                     begin
     83                         State = 2'b10;
     84                         write_to_eeprom;    //写操作                 
     85                     end
     86                     else
     87                         State = 2'b00;  
     88                         //State = State;         
     89                 end
     90                 
     91                 2'b11:
     92                     read_from_eeprom;               
     93                 
     94                 default:
     95                     State = 2'b00;          
     96             endcase     
     97         end 
     98     end     //主状态机结束
     99     
    100     //操作停止
    101     task stop_W_R;
    102     begin
    103         State        = 2'b00;
    104         addr_byte_h  = 0;
    105         addr_byte_l  = 0;
    106         ctrl_byte    = 0;
    107         out_flag     = 0;
    108         sda_buf      = 0;   
    109     end
    110     endtask
    111     
    112     //读进控制字和存储单元地址
    113     task read_in;
    114     begin
    115         shift_in(ctrl_byte);
    116         shift_in(addr_byte_h);
    117         shift_in(addr_byte_l);      
    118     end 
    119     endtask
    120     
    121     //EEPROM的写操作
    122     task write_to_eeprom;
    123     begin
    124         shift_in(memory_buf);
    125         address = {addr_byte_h[4:0], addr_byte_l};
    126         memory[address] = memory_buf;       
    127         State = 2'b00;
    128     end
    129     endtask
    130     
    131     //EEPROM的读操作
    132     task read_from_eeprom;
    133     begin
    134         shift_in(ctrl_byte);
    135         if(ctrl_byte == r7 || ctrl_byte == w6 
    136             || ctrl_byte == r5  || ctrl_byte == r4
    137             || ctrl_byte == r3  || ctrl_byte == r2
    138             || ctrl_byte == r1  || ctrl_byte == r0)
    139         begin
    140             address = {addr_byte_h[4:0], addr_byte_l};
    141             sda_buf = memory[address];
    142             shift_out;
    143             State = 2'b00;
    144         end
    145     end
    146     endtask
    147     
    148     //SDA数据线上的数据存入寄存器,数据在SCL的高电平有效
    149     task shift_in;  
    150         output[7:0]shift;
    151         begin
    152             @(posedge scl) shift[7] = sda;
    153             @(posedge scl) shift[6] = sda;
    154             @(posedge scl) shift[5] = sda;
    155             @(posedge scl) shift[4] = sda;
    156             @(posedge scl) shift[3] = sda;
    157             @(posedge scl) shift[2] = sda;
    158             @(posedge scl) shift[1] = sda;
    159             @(posedge scl) shift[0] = sda;
    160             
    161             @(negedge scl)
    162             begin
    163                 #`timeslice;
    164                 out_flag = 1;     //应答信号输出
    165                 sda_buf = 0;
    166             end
    167             
    168             @(negedge scl)
    169             begin
    170                 #`timeslice;
    171                 out_flag = 0;               
    172             end         
    173         end 
    174     endtask
    175     
    176     //EEPROM存储器中的数据通过SDA数据线输出,数据在SCL低电平时变化
    177     task shift_out;
    178     begin
    179         out_flag = 1;
    180         for(i=6; i>=0; i=i-1)
    181         begin
    182             @(negedge scl);
    183             #`timeslice;
    184             sda_buf = sda_buf << 1;         
    185         end
    186         @(negedge scl) #`timeslice sda_buf[7] = 1;    //非应答信号输出
    187         @(negedge scl) #`timeslice out_flag = 0;
    188     end
    189     endtask
    190 
    191 endmodule 
    192 //eeprom.v文件结束

           根据仿真模型仿真的话基本不会有什么问题,需要注意的是操作的完成标志。从仿真上看到输入读写都没问题,但是stop标志没产生好,仿真看到读写操作没问题,但实际还是不行的,需要严格按照EEPROM的手册操作时序进行,差一点就不行。

        I2C的代码我分享出来,我最后使用拨码开关作为读写使能,数码管显示读出来的输出,最后实现了对指定存储地址读写数据。

    I2C设计代码点击阅读原文可以查看。

      1 `timescale      1ns/1ps
      2 // *********************************************************************************
      3 // Project Name :       
      4 // Author       : NingHeChuan
      5 // Email        : ninghechuan@foxmail.com
      6 // Blogs        : http://www.cnblogs.com/ninghechuan/
      7 // File Name    : I2C_Ctrl_EEPROM.v
      8 // Module Name  :
      9 // Called By    :
     10 // Abstract     :
     11 //
     12 // CopyRight(c) 2018, NingHeChuan Studio.. 
     13 // All Rights Reserved
     14 //
     15 // *********************************************************************************
     16 // Modification History:
     17 // Date         By              Version                 Change Description
     18 // -----------------------------------------------------------------------
     19 // 2018/8/15    NingHeChuan       1.0                     Original
     20 //  
     21 // *********************************************************************************
     22 
     23 module I2C_Ctrl_EEPROM(
     24     input                   clk,
     25     input                   rst_n,
     26     input           [31:0]  eeprom_config_data,
     27     input                   i2c_start,          //1 valid
     28     inout                   i2c_sdat,
     29     output                  i2c_sclk,
     30     output                  i2c_done,
     31     output      reg [7:0]   i2c_rd_data 
     32 );
     33 
     34 
     35 //-------------------------------------------------------
     36 parameter       I2C_IDLE        =   'd0;
     37 parameter       I2C_START       =   'd1;
     38 parameter       I2C_WR_IDADDR   =   'd2;
     39 parameter       I2C_WR_ACK1     =   'd3;
     40 parameter       I2C_WR_REGADDR1 =   'd4;
     41 parameter       I2C_WR_ACK2     =   'd5;
     42 parameter       I2C_WR_REGADDR2 =   'd6;
     43 parameter       I2C_WR_ACK3     =   'd7;
     44 parameter       I2C_WR_DATA     =   'd8;
     45 parameter       I2C_WR_ACK4     =   'd9;
     46 parameter       I2C_WR_STOP     =   'd10;
     47 //-------------------------------------------------------
     48 parameter       I2C_RD_START    =   'd11;
     49 parameter       I2C_RD_IDADDR   =   'd12;
     50 parameter       I2C_RD_ACK      =   'd13;
     51 parameter       I2C_RD_DATA     =   'd14;
     52 parameter       I2C_RD_NPACK    =   'd15;
     53 parameter       I2C_RD_STOP     =   'd16;
     54 //i2c_sclk freq
     55 parameter       I2C_FREQ      =   250;    //50Mhz/200Khz/2 = 125
     56 parameter       TRANSFER      =   1;
     57 parameter       CAPTURE       =   125;
     58 //parameter       I2C_FREQ        =   60;    //50Mhz/200Khz/2 = 125
     59 //parameter       TRANSFER        =   1;
     60 //parameter       CAPTURE         =   30;
     61 parameter       SEND_BIT        =   8;
     62 
     63 //-------------------------------------------------------
     64 reg     [4:0]   pre_state;
     65 reg     [4:0]   next_state;
     66 //
     67 reg             i2c_sdat_r;
     68 wire            bir_en;
     69 //
     70 wire            transfer_en;
     71 wire            capture_en;
     72 reg             i2c_sclk_r;
     73 reg     [7:0]   sclk_cnt;
     74 //
     75 reg     [3:0]   tran_cnt;
     76 //
     77 wire    [7:0]   wr_device_addr = {eeprom_config_data[31:25], 1'b0};
     78 wire    [7:0]   rd_device_addr = {eeprom_config_data[31:25], 1'b1};
     79 wire            wr_rd_flag  =   eeprom_config_data[24];
     80 wire    [7:0]   reg_addr1   = eeprom_config_data[23:16];
     81 wire    [7:0]   reg_addr2   = eeprom_config_data[15:8];
     82 wire    [7:0]   wr_data     = eeprom_config_data[7:0];
     83 //
     84 reg             wr_ack1;
     85 reg             wr_ack2;
     86 reg             wr_ack3;
     87 reg             wr_ack4;
     88 reg             rd_ack1;
     89 
     90 //-------------------------------------------------------
     91 //i2c_sclk
     92 always @(posedge clk or negedge rst_n)begin
     93     if(rst_n == 1'b0)
     94         sclk_cnt <= 'd1;
     95     else if(sclk_cnt == I2C_FREQ - 1'b1)
     96         sclk_cnt <= 'd0;
     97     else 
     98         sclk_cnt <= sclk_cnt + 1'b1;
     99 end
    100 
    101 always @(posedge clk or negedge rst_n)begin
    102     if(rst_n == 1'b0)
    103         i2c_sclk_r <= 1'b0;
    104     else if(sclk_cnt >= (I2C_FREQ>>2)*1 && sclk_cnt <= (I2C_FREQ>>2)*3)
    105         i2c_sclk_r <= 1'b1;
    106     else 
    107         i2c_sclk_r <= 1'b0;
    108 end
    109 //
    110 assign  transfer_en = (sclk_cnt == TRANSFER - 1)? 1'b1: 1'b0;
    111 assign  capture_en  = (sclk_cnt == CAPTURE - 1)? 1'b1: 1'b0;
    112 
    113 //-------------------------------------------------------
    114 always @(posedge clk or negedge rst_n)begin
    115     if(rst_n == 1'b0)
    116         tran_cnt <= 'd0;
    117     else if(tran_cnt == SEND_BIT && transfer_en == 1'b1)
    118         tran_cnt <= 'd0;
    119     else if(((next_state == I2C_WR_IDADDR || next_state == I2C_WR_REGADDR1 || 
    120         next_state ==I2C_WR_REGADDR2 || next_state == I2C_WR_DATA || 
    121         next_state == I2C_RD_IDADDR) && transfer_en == 1'b1) || 
    122         (next_state == I2C_RD_DATA && capture_en == 1'b1))
    123         tran_cnt <= tran_cnt + 1'b1;
    124     else 
    125         tran_cnt <= tran_cnt;
    126 end
    127 
    128 //-------------------------------------------------------
    129 //FSM step1
    130 always @(posedge clk or negedge rst_n)begin
    131     if(rst_n == 1'b0)
    132         pre_state <= I2C_IDLE;
    133     else
    134         pre_state <= next_state;
    135 end
    136 
    137 //FSM step2
    138 always @(*)begin
    139     next_state = I2C_IDLE;
    140     case(pre_state)
    141     I2C_IDLE:
    142         if(i2c_start == 1'b1 && transfer_en == 1'b1)
    143             next_state = I2C_START;
    144         else 
    145             next_state = I2C_IDLE;
    146     I2C_START:
    147         if(transfer_en == 1'b1)
    148             next_state = I2C_WR_IDADDR;
    149         else 
    150             next_state = I2C_START;
    151     I2C_WR_IDADDR:
    152         if(transfer_en == 1'b1 && tran_cnt == SEND_BIT)
    153             next_state = I2C_WR_ACK1;
    154         else
    155             next_state = I2C_WR_IDADDR;
    156     I2C_WR_ACK1:
    157         if(transfer_en == 1'b1 && wr_ack1 == 1'b0)
    158             next_state = I2C_WR_REGADDR1;
    159         else if(transfer_en == 1'b1)
    160             next_state = I2C_IDLE;
    161         else 
    162             next_state = I2C_WR_ACK1;
    163     I2C_WR_REGADDR1:
    164         if(transfer_en == 1'b1 && tran_cnt == SEND_BIT)
    165             next_state = I2C_WR_ACK2;
    166         else
    167             next_state = I2C_WR_REGADDR1;
    168     I2C_WR_ACK2:
    169         if(transfer_en == 1'b1 && wr_ack2 == 1'b0)
    170             next_state = I2C_WR_REGADDR2;
    171         else if(transfer_en == 1'b1)
    172             next_state = I2C_IDLE;
    173         else 
    174             next_state = I2C_WR_ACK2;
    175     I2C_WR_REGADDR2:
    176         if(transfer_en == 1'b1 && tran_cnt == SEND_BIT)
    177             next_state = I2C_WR_ACK3;
    178         else
    179             next_state = I2C_WR_REGADDR2;
    180     I2C_WR_ACK3:
    181         if(transfer_en == 1'b1 && wr_ack3 == 1'b0 && wr_rd_flag == 1'b0)
    182             next_state = I2C_WR_DATA;
    183         else if(transfer_en == 1'b1 && wr_ack3 == 1'b0 && wr_rd_flag == 1'b1)
    184             next_state = I2C_RD_START;
    185         else if(transfer_en == 1'b1)
    186             next_state = I2C_IDLE;
    187         else 
    188             next_state = I2C_WR_ACK3;
    189     I2C_WR_DATA:
    190         if(transfer_en == 1'b1 && tran_cnt == SEND_BIT)
    191             next_state = I2C_WR_ACK4;
    192         else
    193             next_state = I2C_WR_DATA;
    194     I2C_WR_ACK4:
    195         if(transfer_en == 1'b1 && wr_ack4 == 1'b0)
    196             next_state = I2C_WR_STOP;
    197         else if(transfer_en == 1'b1)
    198             next_state = I2C_IDLE;
    199         else 
    200             next_state = I2C_WR_ACK4;
    201     I2C_WR_STOP:
    202         if(transfer_en == 1'b1)
    203             next_state = I2C_IDLE;
    204         else 
    205             next_state = I2C_WR_STOP;
    206     I2C_RD_START:
    207         if(transfer_en == 1'b1)
    208             next_state = I2C_RD_IDADDR;
    209         else 
    210             next_state = I2C_RD_START;
    211     I2C_RD_IDADDR:
    212         if(transfer_en == 1'b1 && tran_cnt == SEND_BIT)
    213             next_state = I2C_RD_ACK;
    214         else
    215             next_state = I2C_RD_IDADDR;
    216     I2C_RD_ACK:
    217         if(transfer_en == 1'b1 && rd_ack1 == 1'b0)
    218             next_state = I2C_RD_DATA;
    219         else if(transfer_en == 1'b1)
    220             next_state = I2C_IDLE;
    221         else 
    222             next_state = I2C_RD_ACK;
    223     I2C_RD_DATA:
    224         if(transfer_en == 1'b1 && tran_cnt == SEND_BIT)
    225             next_state = I2C_RD_NPACK;
    226         else
    227             next_state = I2C_RD_DATA;
    228     I2C_RD_NPACK:
    229         if(transfer_en == 1'b1)
    230             next_state = I2C_RD_STOP;
    231         else 
    232             next_state = I2C_RD_NPACK;
    233     I2C_RD_STOP:
    234         if(transfer_en == 1'b1)
    235             next_state = I2C_IDLE;
    236         else 
    237             next_state = I2C_RD_STOP;
    238     default:next_state = I2C_IDLE;
    239     endcase
    240 end
    241 
    242 //FSM step3
    243 always @(posedge clk or negedge rst_n)begin
    244     if(rst_n == 1'b0)
    245         i2c_sdat_r <= 1'b1;
    246     else begin
    247         case(next_state)
    248         I2C_IDLE:   if(capture_en == 1'b1)  i2c_sdat_r <= 1'b1;
    249         I2C_START:  if(capture_en == 1'b1)  i2c_sdat_r <= 1'b0;
    250         I2C_WR_IDADDR:  if(transfer_en == 1'b1) i2c_sdat_r <= wr_device_addr['d7 - tran_cnt];
    251         I2C_WR_REGADDR1:if(transfer_en == 1'b1) i2c_sdat_r <= reg_addr1['d7 - tran_cnt];
    252         I2C_WR_REGADDR2:if(transfer_en == 1'b1) i2c_sdat_r <= reg_addr2['d7 - tran_cnt];
    253         I2C_WR_DATA:    if(transfer_en == 1'b1) i2c_sdat_r <= wr_data['d7 - tran_cnt];
    254         I2C_WR_ACK4:    if(transfer_en == 1'b1) i2c_sdat_r <= 1'b0;
    255         I2C_WR_STOP:    if(capture_en == 1'b1) i2c_sdat_r <= 1'b1;
    256         I2C_RD_START:   if(capture_en == 1'b1)  i2c_sdat_r <= 1'b0;
    257         I2C_RD_IDADDR:  if(transfer_en == 1'b1) i2c_sdat_r <= rd_device_addr['d7 - tran_cnt];
    258         I2C_RD_NPACK:   if(transfer_en == 1'b1) i2c_sdat_r <= 1'b0;
    259         I2C_RD_STOP:    if(capture_en == 1'b1) i2c_sdat_r <= 1'b1;
    260         default:        i2c_sdat_r <= i2c_sdat_r; 
    261         endcase
    262     end
    263 end
    264 
    265 always @(posedge clk or negedge rst_n)begin
    266     if(rst_n == 1'b0)begin
    267         i2c_rd_data <= 8'b0;
    268         wr_ack1   <= 1'b1;
    269         wr_ack2   <= 1'b1;
    270         wr_ack3   <= 1'b1;
    271         wr_ack4   <= 1'b1;
    272         rd_ack1   <= 1'b1;
    273     end
    274     else if(capture_en == 1'b1)begin
    275         case(next_state)
    276         I2C_WR_ACK1: wr_ack1 <= i2c_sdat;
    277         I2C_WR_ACK2: wr_ack2 <= i2c_sdat;
    278         I2C_WR_ACK3: wr_ack3 <= i2c_sdat;
    279         I2C_WR_ACK4: wr_ack4 <= i2c_sdat;
    280         I2C_WR_STOP: begin
    281             wr_ack1   <= 1'b1;
    282             wr_ack2   <= 1'b1;
    283             wr_ack3   <= 1'b1;
    284             wr_ack4   <= 1'b1;
    285             rd_ack1   <= 1'b1;
    286         end
    287         I2C_RD_ACK: rd_ack1 <= i2c_sdat;
    288         I2C_RD_DATA: i2c_rd_data['d7 - tran_cnt] <= i2c_sdat;
    289         I2C_RD_STOP:begin
    290             wr_ack1   <= 1'b1;
    291             wr_ack2   <= 1'b1;
    292             wr_ack3   <= 1'b1;
    293             wr_ack4   <= 1'b1;
    294             rd_ack1   <= 1'b1;
    295         end
    296         default:begin
    297             i2c_rd_data <= i2c_rd_data;
    298             wr_ack1 <= wr_ack1;
    299             wr_ack2 <= wr_ack2;
    300             wr_ack3 <= wr_ack3;
    301             wr_ack4 <= wr_ack4;
    302             rd_ack1 <= rd_ack1;
    303         end
    304         endcase
    305     end
    306     else begin
    307         i2c_rd_data <= i2c_rd_data;
    308         wr_ack1   <= wr_ack1;
    309         wr_ack2   <= wr_ack2;
    310         wr_ack3   <= wr_ack3;
    311         wr_ack4   <= wr_ack4;
    312         rd_ack1   <= rd_ack1;
    313     end
    314 end
    315 
    316 //-------------------------------------------------------
    317 assign  bir_en = (pre_state == I2C_WR_ACK1 || pre_state == I2C_WR_ACK2 || pre_state == I2C_WR_ACK3 ||
    318                   pre_state == I2C_WR_ACK4 || pre_state == I2C_RD_ACK || pre_state == I2C_RD_DATA)? 1'b0: 1'b1;
    319 
    320 assign  i2c_sdat = (bir_en == 1'b1)? i2c_sdat_r: 1'bz;
    321 
    322 assign  i2c_sclk = i2c_sclk_r;
    323 assign  i2c_done = (pre_state == I2C_WR_STOP && next_state == I2C_IDLE ||
    324                     pre_state == I2C_RD_STOP && next_state == I2C_IDLE)? 1'b1: 1'b0;
    325 
    326 endmodule 

    转载请注明出处:NingHeChuan(宁河川)

    个人微信订阅号:开源FPGA

    如果你想及时收到个人撰写的博文推送,可以扫描左边二维码(或者长按识别二维码)关注个人微信订阅号

    知乎ID:NingHeChuan

    微博ID:NingHeChuan

    原文地址:https://www.cnblogs.com/ninghechuan/p/9534893.html 

  • 相关阅读:
    WCF双工通讯以及客户端间的间接通讯
    认识IoC
    学习“迷你ASP.NET MVC框架”后的小结
    MVP的PV模式与SC模式
    Android学习笔记(九) 视图的应用布局效果
    C# 动态编译
    C#中协变与抗变(逆变)
    线程池ThreadPool的初探
    关于异步的初步认识
    仿Office的程序载入窗体
  • 原文地址:https://www.cnblogs.com/ninghechuan/p/9534893.html
Copyright © 2011-2022 走看看