zoukankan      html  css  js  c++  java
  • 协议——IIC

      I²C即Inter-Integrated Circuit(集成电路总线),它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代设计出来的一种简单、双向、二线制总线标准。多用于主机和从机在数据量不大且传输距离短的场合下的主从通信。主机启动总线,并产生时钟用于传送数据,此时任何接收数据的器件均被认为是从机。I²C总线由数据线SDA和时钟线SCL构成通信线路,既可用于发送数据,也可接收数据。在主控与被控IC之间可进行双向数据传送,数据的传输速率在标准模式下可达100kbit/s,在快速模式下可达400kbit/s,在高速模式下可达3.4Mbit/s,各种被控器件均并联在总线上,通过器件地址(SLAVE ADDR,具体可查器件手册)识别。I²C总线物理拓扑结构图如下所示:

      图中的IIC_SCL是串行时钟线,IIC_SDA是串行数据线,由于I2C器件一般采用开漏结构与总线相连,所以IIC_SCL和IIC_SDA均需接上拉电阻,也正因此,当总线空闲时,这两条线路都处于高电平状态,当连到总线上的任一器件输出低电平,都将使总线拉低,即各器件的SDA及SCL都是“线与”关系。IIC总线支持多主和主从两种工作方式,通常工作在主从工作方式,我们的开发板就采用主从工作方式。在主从工作方式中,系统中只有一个主机,其它器件都是具有I2C总线的外围从机。在主从工作方式中,主机启动数据的发送(发出启动信号)并产生时钟信号,数据发送完成后,发出停止信号。I2C总线结构虽然简单,使用两线传输,然而要实现器件间的通信,需要通过控制SCL和SDA的时序,使其满足I2C的总线传输协议,方可实现器件间的数据传输。
     
     
    一、起始和结束
      在I2C器件开始通信(传输数据)之前,串行时钟线SCL和串行数据线SDA线由于上拉的原因处于高电平状态,此时I2C总线处于空闲状态。
      如果主机(此处指FPGA)想开始传输数据,只需在SCL为高电平时将SDA线拉低,产生一个起始信号,从机检测到起始信号后,准备接收数据,当数据传输完成,主机只需产生一个停止信号,告诉从机数据传输结束,停止信号的产生是在SCL为高电平时,SDA从低电平跳变到高电平,从机检测到停止信号后,停止接收数据。起始信号之前为空闲状态,起始信号之后到停止信号之前的这一段为数据传输状态,主机可以向从机写数据,也可以读取从机输出的数据,数据的传输由双向数据线(SDA)完成。停止信号产生后,总线再次处于空闲状态。
      起始:SCL为高时,SDA由高拉低。
      停止:SCL为高时,SDA由低拉高
     
     
    二、数据传输和应答期
      先看看数据是怎么通过两根线传过来的,除了起始和结束比较特殊,中间的数据传输所遵循的规律如下所示:
      
    1.数据传输  
      SCL为低时,SDA运行变化。
      SCL为高时,SDA数据锁存。
    2.应答期,SDA总线是三态门
      ①在第8个时钟周期末,主机释放SDA以使从机应答
      ②在第9个时钟周期,从机将SDA拉低以应答
      ③若第9个时钟周期,SCL为高电平时,SDA未被检测到为低电平,视为非应答,表明此次数据传输失败。
      ④在第9个时钟周期末,从机释放SDA以使主机继续传输数据,如果主机发送停止信号,此次传输结束。
     
     
    三、器件地址
      每个I2C器件都有一个器件地址,有些I2C器件的器件地址是固定的,而有些I2C器件的器件地址由一个固定部分和一个可编程的部分构成,这是因为很可能在一个系统中有几个同样的器件,器件地址的可编程部分能最大数量的使这些器件连接到I2C总线上,例如为了增加系统的EEPROM容量,可能需要多个EEPROM。器件可编程地址位的数量由它可使用的管脚决定,比如EEPROM器件一般会留下3个管脚用于可编程地址位,当硬件电路上分别将这3个管脚连接到GND或VCC时,就可以设置不同的可编程地址。但有些I2C器件在出厂时器件地址就设置好了,用户不可以更改(如实时时钟PCF8563的器件地址为固定的7’h51)。所以当主机想给某个器件发送数据时,只需向总线上发送接收器件的器件地址即可。
      进行数据传输时,主机首先向总线上发出开始信号,对应开始位S,然后按照从高到低的位序发送器件地址,一般为7bit,第8bit位为读写控制位R/W,该位为0时表示主机对从机进行写操作,当该位为1时表示主机对从机进行读操作,然后接收从机响应。对于AT24C64来说,其传输器件地址格式如下图所示。
     
     
    四、存储器地址(字地址)
      一般而言,每个兼容I2C协议的器件,内部总会有可供读写的寄存器或存储器,对于我们本次实验用到的EEPROM存储器,内部就是一系列顺序编址的存储单元。所以,当我们对一个器件中的存储单元(包括寄存器)进行读写时,首先要指定存储单元的地址即字地址,然后再向该地址写入内容。该地址为一个或两个字节长度,具体长度由器件内部的存储单元的数量决定,当存储单元数量不超过一个字节所能表示的最大数量(2^8=256)时,用一个字节表示,超过一个字节所能表示的最大数量时,就需要用两个字节来表示。
    1.单字节的字地址
    2.双字节的字地址
     
     
    五、IIC写
      主机发送完字地址,从机正确应答后就把内部的存储单元地址指针指向该单元。如果读写控制位R/W位为“0”即写命令,从机就处于接收数据的状态,此时,主机就开始写数据了。写数据分为单字节写(对于EEPROM而言,称为字节写)和连续写(对于EEPROM而言,称为页写)。
      不管单字节写和连续写,都可概括为:start + 器件地址 + 写命令(0) + 字地址 + 数据 + stop
    1.单字节写
      单字节写:发送完一字节数据后发送结束信号。
    2.连续写
      连续写:发送完一字节数据后继续发送下一字节数据,最后发送的是结束信号。
     
     
    六、IIC读
      主机发送完字地址,从机正确应答后就把内部的存储单元地址指针指向该单元。如果读写控制位R/W位为“1”即读命令,主机就处于接收数据的状态,从机从该地址单元输出数据。读数据分为当前地址读、单字节读和连续读。
      不管是单字节读还是连续读,都可以概括为:start + 器件地址 + 写命令(0) + 字地址 + start + 器件地址 + 读命令(1) + 接收从机的数据 + 主机非应答(1) + stop
    1.单字节读
      发送完器件地址和字地址后又发送起始信号和器件地址,而且第一次发送器件地址时后面的读写控制位为“0”,也就是写命令,第二次发送器件地址时后面的读写控制位为“1”,也就是读。为什么会有这样奇怪的操作呢?这是因为我们需要使从机内的存储单元地址指针指向我们想要读取的存储单元地址处,所以首先发送了一次Dummy Write也就是虚写操作,只所以称为虚写,是因为我们并不是真的要写数据,而是通过这种虚写操作使地址指针指向虚写操作中字地址的位置,等从机应答后,就可以按当前地址读的方式读数据了。因此也可以理解为:没有发送数据的单次写操作 + 当前地址的读操作
        单字节读:读取完一字节数据后,主机发送非应答信号。
     
    2.连续读
      连续读:读取完一字节数据后,主机发送应答信号,读取完最后一个字节数据后,主机发送非应答信号。
     
     
     
     
    七、IIC控制器Verilog代码设计(修改自正点原子FPGA)
      1 //**************************************************************************
      2 // *** 名称 : iic.v
      3 // *** 作者 : xianyu_FPGA
      4 // *** 博客 : https://www.cnblogs.com/xianyufpga/
      5 // *** 日期 : 2019-08-10
      6 // *** 描述 : IIC控制器
      7 //**************************************************************************
      8 
      9 module iic
     10 //========================< 参数 >==========================================
     11 #(
     12 parameter DEVICE_ID         = 7'b1010000            ,  //器件ID
     13 parameter CLK               = 26'd50_000_000        ,  //本模块的时钟频率
     14 parameter SCL               = 18'd250_000              //输出的SCL时钟频率
     15 )
     16 //========================< 端口 >==========================================
     17 (
     18 input                       clk                     , //时钟
     19 input                       rst_n                   , //复位,低电平有效
     20 //IIC control ---------------------------------------
     21 input                       iic_en                  , //IIC触发信号
     22 input                       addr16_en               , //16位地址使能
     23 input                       addr8_en                , //8位地址使能
     24 input                       write_en                , //IIC写使能
     25 input                       read_en                 , //IIC读使能
     26 input        [15:0]         iic_addr                , //IIC器件内地址
     27 input        [ 7:0]         iic_data_wr             , //IIC要写的数据
     28 //IIC output ----------------------------------------
     29 output  reg  [ 7:0]         iic_data_rd             , //IIC读出的数据
     30 output  reg                 iic_done                , //IIC一次操作完成
     31 output  reg                 iic_scl                 , //IIC的SCL时钟信号
     32 inout                       iic_sda                 , //IIC的SDA数据信号
     33 //dri_clk -------------------------------------------
     34 output  reg                 iic_dri_clk               //驱动IIC操作的驱动时钟,1Mhz
     35  );
     36 //========================< 参数 >==========================================
     37 localparam  IDLE            = 8'b0000_0001          ; //空闲状态
     38 localparam  DEVICE          = 8'b0000_0010          ; //写器件地址
     39 localparam  ADDR_16         = 8'b0000_0100          ; //写字地址高8位
     40 localparam  ADDR_8          = 8'b0000_1000          ; //写字地址低8位
     41 localparam  DATA_WR         = 8'b0001_0000          ; //写数据
     42 localparam  DEVICE_RD       = 8'b0010_0000          ; //虚写器件地址
     43 localparam  DATA_RD         = 8'b0100_0000          ; //读数据
     44 localparam  STOP            = 8'b1000_0000          ; //结束
     45 //========================< 信号 >==========================================
     46 reg                         sda_dir                 ; //IIC数据(SDA)方向控制
     47 reg                         sda_out                 ; //SDA输出信号
     48 wire                        sda_in                  ; //SDA输入信号
     49 reg                         state_done              ; //状态结束
     50 reg    [ 6:0]               cnt                     ; //计数
     51 reg    [ 7:0]               state_c                 ; //状态机当前状态
     52 reg    [ 7:0]               state_n                 ; //状态机下一状态
     53 reg    [15:0]               iic_addr_t              ; //地址
     54 reg    [ 7:0]               iic_data_rd_t           ; //读取的数据
     55 reg    [ 7:0]               iic_data_wr_t           ; //IIC需写的数据的临时寄存
     56 reg    [ 9:0]               clk_cnt                 ; //分频时钟计数
     57 wire   [ 8:0]               clk_divide              ; //模块驱动时钟的分频系数
     58 
     59 //==========================================================================
     60 //==    sda控制
     61 //==========================================================================
     62 assign iic_sda = sda_dir ? sda_out : 1'bz;            //SDA数据输出或高阻
     63 assign sda_in  = iic_sda ;                            //SDA数据输入
     64 
     65 //==========================================================================
     66 //==     生成SCL的4倍时钟来驱动后面IIC的操作,生成1Mhz的iic_dri_clk
     67 //==========================================================================
     68 assign clk_divide = (CLK/SCL) >> 3;                   // >>3即除以8
     69 
     70 always @(posedge clk or negedge rst_n) begin
     71     if(!rst_n) begin
     72         iic_dri_clk <=  1'b1;
     73         clk_cnt <= 10'd0;
     74     end
     75     else if(clk_cnt == clk_divide - 1'd1) begin
     76         clk_cnt <= 10'd0;
     77         iic_dri_clk <= ~iic_dri_clk;
     78     end
     79     else
     80         clk_cnt <= clk_cnt + 1'b1;
     81 end
     82 
     83 //==========================================================================
     84 //==    状态机
     85 //==========================================================================
     86 always @(posedge iic_dri_clk or negedge rst_n) begin
     87     if(!rst_n)
     88         state_c <= IDLE;
     89     else
     90         state_c <= state_n;
     91 end
     92 
     93 always @(*) begin
     94     case(state_c)
     95         IDLE: begin                             //空闲状态
     96            if(iic_en) begin
     97                state_n = DEVICE;
     98            end
     99            else
    100                state_n = IDLE;
    101         end
    102         DEVICE: begin                           //写器件ID
    103             if(state_done) begin
    104                 if(addr16_en)
    105                    state_n = ADDR_16;
    106                 else if(addr8_en)
    107                    state_n = ADDR_8 ;
    108             end
    109             else
    110                 state_n = DEVICE;
    111         end
    112         ADDR_16: begin                          //写地址高8位
    113             if(state_done)
    114                 state_n = ADDR_8;
    115             else
    116                 state_n = ADDR_16;
    117         end
    118         ADDR_8: begin                           //写地址低8位
    119             if(state_done) begin
    120                 if(write_en)
    121                     state_n = DATA_WR;
    122                 else if(read_en)
    123                     state_n = DEVICE_RD;
    124             end
    125             else
    126                 state_n = ADDR_8;
    127         end
    128         DATA_WR: begin                          //写数据
    129             if(state_done)
    130                 state_n = STOP;
    131             else
    132                 state_n = DATA_WR;
    133         end
    134         DEVICE_RD: begin                        //虚写器件ID
    135             if(state_done)
    136                 state_n = DATA_RD;
    137             else
    138                 state_n = DEVICE_RD;
    139         end
    140         DATA_RD: begin                          //读数据
    141             if(state_done)
    142                 state_n = STOP;
    143             else
    144                 state_n = DATA_RD;
    145         end
    146         STOP: begin                             //结束
    147             if(state_done)
    148                 state_n = IDLE;
    149             else
    150                 state_n = STOP ;
    151         end
    152         default:state_n= IDLE;
    153     endcase
    154 end
    155 
    156 //==========================================================================
    157 //==    设计各路信号
    158 //==========================================================================
    159 always @(posedge iic_dri_clk or negedge rst_n) begin
    160     if(!rst_n) begin
    161         iic_scl        <= 1'b1;
    162         sda_out        <= 1'b1;
    163         sda_dir        <= 1'b1;
    164         iic_done       <= 1'b0;
    165         cnt            <= 1'b0;
    166         state_done     <= 1'b0;
    167         iic_addr_t     <= 1'b0;
    168         iic_data_rd    <= 1'b0;
    169         iic_data_rd_t  <= 1'b0;
    170         iic_data_wr_t  <= 1'b0; 
    171     end
    172     else begin
    173         state_done <= 1'b0 ;
    174         cnt        <= cnt +1'b1 ;
    175         case(state_c)
    176             //--------------------------------------------------- 空闲状态
    177             IDLE: begin
    178                     iic_scl  <= 1'b1;
    179                     sda_out  <= 1'b1;
    180                     sda_dir  <= 1'b1;
    181                     iic_done <= 1'b0;
    182                     cnt      <= 7'b0;
    183                     if(iic_en) begin
    184                         iic_addr_t    <= iic_addr;
    185                         iic_data_wr_t <= iic_data_wr;
    186                     end
    187             end
    188             //--------------------------------------------------- 写器件ID
    189             DEVICE: begin
    190                 case(cnt)
    191                     7'd1 : sda_out <= 1'b0;
    192                     7'd3 : iic_scl <= 1'b0;
    193                     7'd4 : sda_out <= DEVICE_ID[6];
    194                     7'd5 : iic_scl <= 1'b1;
    195                     7'd7 : iic_scl <= 1'b0;
    196                     7'd8 : sda_out <= DEVICE_ID[5];
    197                     7'd9 : iic_scl <= 1'b1;
    198                     7'd11: iic_scl <= 1'b0;
    199                     7'd12: sda_out <= DEVICE_ID[4];
    200                     7'd13: iic_scl <= 1'b1;
    201                     7'd15: iic_scl <= 1'b0;
    202                     7'd16: sda_out <= DEVICE_ID[3];
    203                     7'd17: iic_scl <= 1'b1;
    204                     7'd19: iic_scl <= 1'b0;
    205                     7'd20: sda_out <= DEVICE_ID[2];
    206                     7'd21: iic_scl <= 1'b1;
    207                     7'd23: iic_scl <= 1'b0;
    208                     7'd24: sda_out <= DEVICE_ID[1];
    209                     7'd25: iic_scl <= 1'b1;
    210                     7'd27: iic_scl <= 1'b0;
    211                     7'd28: sda_out <= DEVICE_ID[0];
    212                     7'd29: iic_scl <= 1'b1;
    213                     7'd31: iic_scl <= 1'b0;
    214                     7'd32: sda_out <= 1'b0;             //0:写
    215                     7'd33: iic_scl <= 1'b1;
    216                     7'd35: iic_scl <= 1'b0;
    217                     7'd36: begin
    218                            sda_dir <= 1'b0;             //从机应答
    219                            sda_out <= 1'b1;
    220                     end
    221                     7'd37: iic_scl <= 1'b1;
    222                     7'd38: state_done <= 1'b1;          //状态结束
    223                     7'd39: begin
    224                            iic_scl <= 1'b0;
    225                            cnt <= 1'b0;
    226                     end
    227                     default :  ;
    228                 endcase
    229             end
    230             //--------------------------------------------------- 写字地址高8位
    231             ADDR_16: begin
    232                 case(cnt)
    233                     7'd0 : begin
    234                            sda_dir <= 1'b1 ;
    235                            sda_out <= iic_addr_t[15];
    236                     end
    237                     7'd1 : iic_scl <= 1'b1;
    238                     7'd3 : iic_scl <= 1'b0;
    239                     7'd4 : sda_out <= iic_addr_t[14];
    240                     7'd5 : iic_scl <= 1'b1;
    241                     7'd7 : iic_scl <= 1'b0;
    242                     7'd8 : sda_out <= iic_addr_t[13];
    243                     7'd9 : iic_scl <= 1'b1;
    244                     7'd11: iic_scl <= 1'b0;
    245                     7'd12: sda_out <= iic_addr_t[12];
    246                     7'd13: iic_scl <= 1'b1;
    247                     7'd15: iic_scl <= 1'b0;
    248                     7'd16: sda_out <= iic_addr_t[11];
    249                     7'd17: iic_scl <= 1'b1;
    250                     7'd19: iic_scl <= 1'b0;
    251                     7'd20: sda_out <= iic_addr_t[10];
    252                     7'd21: iic_scl <= 1'b1;
    253                     7'd23: iic_scl <= 1'b0;
    254                     7'd24: sda_out <= iic_addr_t[9];
    255                     7'd25: iic_scl <= 1'b1;
    256                     7'd27: iic_scl <= 1'b0;
    257                     7'd28: sda_out <= iic_addr_t[8];
    258                     7'd29: iic_scl <= 1'b1;
    259                     7'd31: iic_scl <= 1'b0;
    260                     7'd32: begin
    261                            sda_dir <= 1'b0;             //从机应答
    262                            sda_out <= 1'b1;
    263                     end
    264                     7'd33: iic_scl <= 1'b1;
    265                     7'd34: state_done <= 1'b1;          //状态结束
    266                     7'd35: begin
    267                            iic_scl <= 1'b0;
    268                            cnt <= 1'b0;
    269                     end
    270                     default :  ;
    271                 endcase
    272             end
    273             //--------------------------------------------------- 写字地址低8位
    274             ADDR_8: begin
    275                 case(cnt)
    276                     7'd0: begin
    277                            sda_dir <= 1'b1 ;
    278                            sda_out <= iic_addr_t[7];
    279                     end
    280                     7'd1 : iic_scl <= 1'b1;
    281                     7'd3 : iic_scl <= 1'b0;
    282                     7'd4 : sda_out <= iic_addr_t[6];
    283                     7'd5 : iic_scl <= 1'b1;
    284                     7'd7 : iic_scl <= 1'b0;
    285                     7'd8 : sda_out <= iic_addr_t[5];
    286                     7'd9 : iic_scl <= 1'b1;
    287                     7'd11: iic_scl <= 1'b0;
    288                     7'd12: sda_out <= iic_addr_t[4];
    289                     7'd13: iic_scl <= 1'b1;
    290                     7'd15: iic_scl <= 1'b0;
    291                     7'd16: sda_out <= iic_addr_t[3];
    292                     7'd17: iic_scl <= 1'b1;
    293                     7'd19: iic_scl <= 1'b0;
    294                     7'd20: sda_out <= iic_addr_t[2];
    295                     7'd21: iic_scl <= 1'b1;
    296                     7'd23: iic_scl <= 1'b0;
    297                     7'd24: sda_out <= iic_addr_t[1];
    298                     7'd25: iic_scl <= 1'b1;
    299                     7'd27: iic_scl <= 1'b0;
    300                     7'd28: sda_out <= iic_addr_t[0];
    301                     7'd29: iic_scl <= 1'b1;
    302                     7'd31: iic_scl <= 1'b0;
    303                     7'd32: begin
    304                            sda_dir <= 1'b0;             //从机应答
    305                            sda_out <= 1'b1;
    306                     end
    307                     7'd33: iic_scl <= 1'b1;
    308                     7'd34: state_done <= 1'b1;          //状态结束
    309                     7'd35: begin
    310                            iic_scl <= 1'b0;
    311                            cnt <= 1'b0;
    312                     end
    313                     default :  ;
    314                 endcase
    315             end
    316             //--------------------------------------------------- 写数据
    317             DATA_WR: begin
    318                 case(cnt)
    319                     7'd0: begin
    320                            sda_out <= iic_data_wr_t[7];
    321                            sda_dir <= 1'b1;
    322                     end
    323                     7'd1 : iic_scl <= 1'b1;
    324                     7'd3 : iic_scl <= 1'b0;
    325                     7'd4 : sda_out <= iic_data_wr_t[6];
    326                     7'd5 : iic_scl <= 1'b1;
    327                     7'd7 : iic_scl <= 1'b0;
    328                     7'd8 : sda_out <= iic_data_wr_t[5];
    329                     7'd9 : iic_scl <= 1'b1;
    330                     7'd11: iic_scl <= 1'b0;
    331                     7'd12: sda_out <= iic_data_wr_t[4];
    332                     7'd13: iic_scl <= 1'b1;
    333                     7'd15: iic_scl <= 1'b0;
    334                     7'd16: sda_out <= iic_data_wr_t[3];
    335                     7'd17: iic_scl <= 1'b1;
    336                     7'd19: iic_scl <= 1'b0;
    337                     7'd20: sda_out <= iic_data_wr_t[2];
    338                     7'd21: iic_scl <= 1'b1;
    339                     7'd23: iic_scl <= 1'b0;
    340                     7'd24: sda_out <= iic_data_wr_t[1];
    341                     7'd25: iic_scl <= 1'b1;
    342                     7'd27: iic_scl <= 1'b0;
    343                     7'd28: sda_out <= iic_data_wr_t[0];
    344                     7'd29: iic_scl <= 1'b1;
    345                     7'd31: iic_scl <= 1'b0;
    346                     7'd32: begin
    347                            sda_dir <= 1'b0;             //从机应答
    348                            sda_out <= 1'b1;
    349                     end
    350                     7'd33: iic_scl <= 1'b1;
    351                     7'd34: state_done <= 1'b1;          //状态结束
    352                     7'd35: begin
    353                         iic_scl  <= 1'b0;
    354                         cnt  <= 1'b0;
    355                     end
    356                     default  :  ;
    357                 endcase
    358             end
    359             //--------------------------------------------------- 虚写器件ID
    360             DEVICE_RD: begin
    361                 case(cnt)
    362                     7'd0 : begin
    363                            sda_dir <= 1'b1;
    364                            sda_out <= 1'b1;
    365                     end
    366                     7'd1 : iic_scl <= 1'b1;
    367                     7'd2 : sda_out <= 1'b0;             //重新开始
    368                     7'd3 : iic_scl <= 1'b0;
    369                     7'd4 : sda_out <= DEVICE_ID[6];
    370                     7'd5 : iic_scl <= 1'b1;
    371                     7'd7 : iic_scl <= 1'b0;
    372                     7'd8 : sda_out <= DEVICE_ID[5];
    373                     7'd9 : iic_scl <= 1'b1;
    374                     7'd11: iic_scl <= 1'b0;
    375                     7'd12: sda_out <= DEVICE_ID[4];
    376                     7'd13: iic_scl <= 1'b1;
    377                     7'd15: iic_scl <= 1'b0;
    378                     7'd16: sda_out <= DEVICE_ID[3];
    379                     7'd17: iic_scl <= 1'b1;
    380                     7'd19: iic_scl <= 1'b0;
    381                     7'd20: sda_out <= DEVICE_ID[2];
    382                     7'd21: iic_scl <= 1'b1;
    383                     7'd23: iic_scl <= 1'b0;
    384                     7'd24: sda_out <= DEVICE_ID[1];
    385                     7'd25: iic_scl <= 1'b1;
    386                     7'd27: iic_scl <= 1'b0;
    387                     7'd28: sda_out <= DEVICE_ID[0];
    388                     7'd29: iic_scl <= 1'b1;
    389                     7'd31: iic_scl <= 1'b0;
    390                     7'd32: sda_out <= 1'b1;             //1:读
    391                     7'd33: iic_scl <= 1'b1;
    392                     7'd35: iic_scl <= 1'b0;
    393                     7'd36: begin
    394                            sda_dir <= 1'b0;             //从机应答
    395                            sda_out <= 1'b1;
    396                     end
    397                     7'd37: iic_scl     <= 1'b1;
    398                     7'd38: state_done <= 1'b1;          //状态结束
    399                     7'd39: begin
    400                            iic_scl <= 1'b0;
    401                            cnt <= 1'b0;
    402                     end
    403                     default : ;
    404                 endcase
    405             end
    406             //--------------------------------------------------- 读数据
    407             DATA_RD: begin
    408                 case(cnt)
    409                     7'd0 : sda_dir <= 1'b0;
    410                     7'd1 : begin
    411                            iic_data_rd_t[7] <= sda_in;
    412                            iic_scl <= 1'b1;
    413                     end
    414                     7'd3 : iic_scl <= 1'b0;
    415                     7'd5 : begin
    416                            iic_data_rd_t[6] <= sda_in;
    417                            iic_scl <= 1'b1;
    418                     end
    419                     7'd7 : iic_scl <= 1'b0;
    420                     7'd9 : begin
    421                            iic_data_rd_t[5] <= sda_in;
    422                            iic_scl <= 1'b1;
    423                     end
    424                     7'd11: iic_scl <= 1'b0;
    425                     7'd13: begin
    426                            iic_data_rd_t[4] <= sda_in;
    427                            iic_scl <= 1'b1;
    428                     end
    429                     7'd15: iic_scl <= 1'b0;
    430                     7'd17: begin
    431                            iic_data_rd_t[3] <= sda_in;
    432                            iic_scl <= 1'b1;
    433                     end
    434                     7'd19: iic_scl <= 1'b0;
    435                     7'd21: begin
    436                            iic_data_rd_t[2] <= sda_in;
    437                            iic_scl <= 1'b1;
    438                     end
    439                     7'd23: iic_scl <= 1'b0;
    440                     7'd25: begin
    441                            iic_data_rd_t[1] <= sda_in;
    442                            iic_scl <= 1'b1;
    443                     end
    444                     7'd27: iic_scl <= 1'b0;
    445                     7'd29: begin
    446                            iic_data_rd_t[0] <= sda_in;
    447                            iic_scl <= 1'b1  ;
    448                     end
    449                     7'd31: iic_scl <= 1'b0;
    450                     7'd32: begin
    451                            sda_dir <= 1'b1;             //非应答
    452                            sda_out <= 1'b1;
    453                     end
    454                     7'd33: iic_scl <= 1'b1;
    455                     7'd34: state_done <= 1'b1;          //状态结束
    456                     7'd35: begin
    457                            iic_scl <= 1'b0;
    458                            cnt <= 1'b0;
    459                            iic_data_rd <= iic_data_rd_t;
    460                     end
    461                     default  :  ;
    462                 endcase
    463             end
    464             //--------------------------------------------------- 结束
    465             STOP: begin
    466                 case(cnt)
    467                     7'd0 : begin
    468                            sda_dir <= 1'b1;
    469                            sda_out <= 1'b0;
    470                     end
    471                     7'd1 : iic_scl <= 1'b1;
    472                     7'd3 : sda_out <= 1'b1;
    473                     7'd15: state_done <= 1'b1;          //状态结束
    474                     7'd16: begin
    475                            cnt <= 1'b0;
    476                            iic_done <= 1'b1;            //IIC配置完成
    477                     end
    478                     default  : ;
    479                 endcase
    480             end
    481         endcase
    482     end
    483 end
    484 
    485 
    486 
    487 
    488 endmodule
     参考资料:
    [1]正点原子FPGA教程
    [2]小梅哥FPGA教程
  • 相关阅读:
    DataTable中的增删改查
    如何修改SQLServer的登录验证模式为混合验证模式(转载)
    asp.net C# 技术小点
    利用JQuery动态删除Table表格的行和列
    ASP.NET利用JQuery中的Aajax实现JSON数据后台交互
    MySQL Explain 详解
    Python字符串操作
    Linux中last的用法及参数,查看登陆系统用户的信息
    fedora 16 mysql远程连接
    Linux下MySQL 5.5.21 服务器日志配置
  • 原文地址:https://www.cnblogs.com/xianyufpga/p/11284897.html
Copyright © 2011-2022 走看看