协议——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教程
posted @ 2019-03-07 19:50  咸鱼IC  阅读(3548)  评论(0编辑  收藏  举报