三,基于FPGA的IIC主机与从机通用编程设计

本文详细介绍了IIC(Inter-Integrated Circuit)协议,包括其工作原理、总线结构、时序以及数据传输速率。接着,提供了FPGA实现IIC主机和从机的Verilog代码示例,展示了如何通过控制简单的并行读写接口完成IIC接口时序。代码中包含了起始和停止条件、数据传输、应答信号等关键步骤的实现。
摘要由CSDN通过智能技术生成

1,IIC协议

      IIC,即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代设计出来的一种简单、双向、二线制、同步串行总线。是当今电子设计中应用最为广泛的串行总线之一。在很多领域有着广泛的应用,如存储器、LED及LCD驱动器、AD/DA转换器、传感器、图像处理领域的摄像头配置(SCCB)等等。

      IIC是一种多向控制总线,也就是说多个IIC设备可以连接到同一总线结构下,每个连接到总线的设备都具有唯一的地址,主机可以做为发送器和接收器,这里的发送器指的是主机可以给总线上的IIC设备发送数据,接收器是指主机接收总线上IIC设备发送来的数据。

  IIC协议规定数据传输速度为:标准模式下100Kbps,快速模式下400Kbps,高速模式下3.4Mbps。

2,总线结构

    IIC总线接口由两根线组成,一根是双向的串行数据线sda(serial data),一根是串行时钟线scl(serial clock)。

    在总线不传输数据时,总线上的sda和scl均保持高电平,需要传输数据时,首先是发送开始条件:在scl为高电平期间,数据线sda由“高”变“低”为开始条件;当scl为高电平期间,数据线sda由“低”变“高”为停止条件。在发送数据时,数据线sda必须在scl为高电平期间保持稳定,只有在scl为低电平期间,才允许改变数据sda,发送的数据必须是一个字节,每次发送完一个字节的数据,必须接受来自从设备的一个反馈信号ACK,与应答对应的时钟脉冲由主控制器产生。

3,总线时序

为支持通用设计,该处我们只完成单字节读写。除起始位和停止位之外,每次传输8bit数据加一个ACK,具体读写时序如下:

     写时序

     读时序

        起始位 : SCL高电平时,检测到一个由高到低的电平变化为起始位;

        ID数据 : ID一般由7bit数据表示,由高低依次传输,第8位为读写标志位;

        写地址数据 : 8bit地址数据由高到低依次传输,如果地址位超过8bit,则由两个字段完成传输;

        写数据 : 8bit数据由高到低依次传输;

        应答位 : 每发送完8bit数据,由从机反馈一个应答,一般为低电平;

        停止位 : SCL高电平时,检测到一个由低到高的电平变化为停止位。

4,FPGA实现IIC主机

   FPGA实现IIC主机读写设计,已设计为简单的并行读写控制接口,只要控制改读写接口就能完成IIC接口时序,代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: xy
// 
// Create Date:    11:48:53 08/31/2018 
// Design Name: 
// Module Name:    iic_design_host 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//
 module iic_design_host #(
 parameter SYSCLK = 50000000,
 parameter IICRATE = 200000
 )
 (
   input              clk, //50MHZ
   input              rst, 
   output   reg       scl, 
   inout              sda,
   
   input              rd_en,
   input              wr_en,
   
   input   [7:0]      iic_id,   
   input   [7:0]      iic_addr,
   input   [7:0]      wr_data,
   output reg         wr_done,
   output reg [7:0]   rd_data,
   output reg         rd_done
   );
   
   localparam IIC_BPS = SYSCLK/IICRATE/2;
   localparam IIC_BPS_2 = SYSCLK/IICRATE/4;
   
   reg sda_link; 
   reg sda_buf;
   assign sda 	= (sda_link == 1) ? sda_buf : 1'bz;

//**********scl输出***************	
   reg [9:0] clk_cnt; //499, 
   reg       clk_bps;
   reg       run_en;
   
   always @ (posedge clk) begin  //5Ok驱动时钟生成模块
     if(rst) begin 
       clk_cnt   <= 0;
       clk_bps <= 0;
       end 
     else if(run_en && clk_cnt == IIC_BPS - 1) begin 
       clk_cnt   <= 0;
       clk_bps <= ~clk_bps;
       end 
     else if(run_en) begin 
       clk_cnt   <= clk_cnt + 1;
       clk_bps <= clk_bps;
       end 
     else begin 
       clk_bps <= 1;
       clk_cnt   <= 0;
       end 
   end 
   
   always @ (posedge clk) begin 
     if(rst) 
       scl <= 1;
     else if(run_en) //在有发送有效数据时,发送时钟,空闲状态保持为1
       scl <= clk_bps;
     else 
       scl <= 1;
   end 
  
   wire     scl_flag;
  assign   scl_flag = (clk_cnt == IIC_BPS_2 - 1) ? 1 : 0;
//-------------------------------------------------------------------

///************************************
   reg [31:0] cnt_5ms;
   wire       cnt_5ms_flag;
    
   always @ (posedge clk) begin 
     if(rst)
       cnt_5ms <= 0;
     else if(run_en == 0)
       cnt_5ms <= cnt_5ms + 1;
     else 
       cnt_5ms <= 0;
   end 
	
   assign cnt_5ms_flag = (cnt_5ms == 24999999) ? 1 : 0;
//--------------------------------------------------


  

//*************************IIC时序*************************  
   localparam  idle_state  	     = 'd0 ;  //空闲状态,准备发送起始位
   localparam  startwr_state      = 'd1 ;  //起始状态,发送起始位
   localparam  txidwr_state       = 'd2 ;  //发送器件ID,
   localparam  txidwr_ack_state   = 'd3 ;  //接收一个ACK
   localparam  txaddrwr_state     = 'd4 ;  //发送寄存器地址,
   localparam  txaddrwr_ack_state = 'd5 ;  //接收一个ACK
   localparam  readyrd_state      = 'd6 ;  //准备读数据
   localparam  startrd_state      = 'd7 ;  //发送一个开始信号
   localparam  txidrd_state       = 'd8 ;  //发送器件ID
   localparam  txidrd_ack_state   = 'd9 ;  //接收一个ACK
   localparam  rxaddrrd_state     = 'd10;  //接收数据
   localparam  rxaddrrd_ack_state = 'd11;  //发送读数据ACK
   localparam  readystop_state    = 'd12;  //准备停止
   localparam  stop_state         = 'd13;  //发送停止信号
   localparam  end_state          = 'd14;  //结束空闲状态
   localparam  sel_state          = 'd15;  //读写选择状态
   localparam  txdata_state       = 'd16;  //数据发送状态
   localparam  txdata_ack_state   = 'd17;  //发送ACK
   
   reg [4:0] iic_next_state     = idle_state;
   reg [4:0] iic_current_state  = idle_state;
   reg [3:0] cnt_shift          = 0;
   reg [7:0] data_reg           = 0;
   reg       rd_sel             = 0;
   
   
   always @ (posedge clk) begin 
     if(rst)
       iic_current_state <= idle_state;
     else 
       iic_current_state <= iic_next_state;
   end 

   always @ (*) begin 
     if(rst) 
       iic_next_state = idle_state;
     else case(iic_current_state)
       idle_state          :  if(rd_en || wr_en) 
		                           iic_next_state = startwr_state;
                              else iic_next_state = idle_state;
                          
       startwr_state       :  if(scl == 1 && scl_flag) 
		                           iic_next_state = txidwr_state;
                              else iic_next_state = startwr_state;
                          
       txidwr_state        :  if(scl == 0 && scl_flag && cnt_shift == 8) 
	                               iic_next_state = txidwr_ack_state;
                              else iic_next_state = txidwr_state;
                          
       txidwr_ack_state    :  if(scl == 1 && scl_flag)  
						           iic_next_state = txaddrwr_state;//应答sda == 0
                              else iic_next_state = txidwr_ack_state;         
					       
       txaddrwr_state      :  if(scl == 0 && scl_flag && cnt_shift == 8) 
	                               iic_next_state = txaddrwr_ack_state;
                              else iic_next_state = txaddrwr_state; 
                       
       txaddrwr_ack_state  :  if(scl == 1 && scl_flag)  
								        iic_next_state = sel_state;//应答sda == 0
                              else iic_next_state = txaddrwr_ack_state;   
							  
	   sel_state           :  if(rd_sel) 
	                               iic_next_state = readyrd_state;//应答sda == 0
							        else 
							            iic_next_state = txdata_state;
								   
	   txdata_state        :  if(scl == 0 && scl_flag && cnt_shift == 8) 
	                               iic_next_state = txdata_ack_state;
                              else iic_next_state = txdata_state;  
       
       txdata_ack_state    :  if(scl == 1 && scl_flag)  
	                               iic_next_state = readystop_state;//应答sda == 0
                              else iic_next_state = txdata_ack_state; 
       
       readyrd_state       :  if(scl == 0 && scl_flag) 
							       iic_next_state = startrd_state;
                              else iic_next_state = readyrd_state;  
					       
       startrd_state       :  if(scl == 1 && scl_flag) 
	                               iic_next_state = txidrd_state;
                              else iic_next_state = startrd_state; 
                       
       txidrd_state        :  if(scl == 0 && scl_flag && cnt_shift == 8) 
	                               iic_next_state = txidrd_ack_state;
                              else iic_next_state = txidrd_state;  
       
       txidrd_ack_state    :  if(scl == 1 && scl_flag)  
		                           iic_next_state = rxaddrrd_state;//应答sda == 0
                              else iic_next_state = txidrd_ack_state;                 
       
       rxaddrrd_state      :  if(scl == 1 && scl_flag && cnt_shift == 7)
                                   iic_next_state = rxaddrrd_ack_state;
                              else iic_next_state = rxaddrrd_state;                
       
       rxaddrrd_ack_state  :  if(scl == 0 && scl_flag)  
                                   iic_next_state = readystop_state;
                              else iic_next_state = rxaddrrd_ack_state;  
                                 
       readystop_state     :  if(scl == 0 && scl_flag)   
	                               iic_next_state = stop_state;
                              else iic_next_state = readystop_state; 
                       
       stop_state          :  if(scl == 1 && scl_flag)   
	                               iic_next_state = end_state;
                              else iic_next_state = stop_state;    
                                   
       end_state           :       iic_next_state = idle_state;       
       
                       
       default             :       iic_next_state = idle_state;                                             
       endcase 
   end 
	
	
   always @ (posedge clk) begin 
     if(rst) begin 
       cnt_shift  <= 0; //数据移位计数器
       data_reg   <= 0; //发送数据寄存器
       sda_buf    <= 1; //发送buf
       sda_link   <= 0; //三态控制
       run_en     <= 0;
       rd_data    <= 0;
		 rd_sel     <= 0;
		 wr_done    <= 0;
		 rd_done    <= 0;
       end 
     else case(iic_current_state)
      idle_state           :  if(wr_en) begin
                                cnt_shift <= 0; //数据移位计数器
                                data_reg  <= 0; //发送数据寄存器
                                sda_buf   <= 1; //发送buf
                                sda_link  <= 1; //三态控制
                                run_en    <= 1;
										  rd_sel     <= 0;
										  wr_done    <= 0;
										  rd_done    <= 0;
                                end 
										else if(rd_en) begin 
										  cnt_shift <= 0; //数据移位计数器
                                data_reg  <= 0; //发送数据寄存器
                                sda_buf   <= 1; //发送buf
                                sda_link  <= 1; //三态控制
                                run_en    <= 1;
										  rd_sel     <= 1;
										  wr_done    <= 0;
										  rd_done    <= 0;
										  end
                              else begin 
                                cnt_shift <= 0; //数据移位计数器
                                data_reg  <= 0; //发送数据寄存器
                                sda_buf   <= 1; //发送buf
                                sda_link  <= 1; //三态控制
                                run_en    <= 0;
										  rd_sel <= 0;
										  wr_done <= 0;
										  rd_done <= 0;
                                end 
      
      startwr_state        :  if(scl == 1 && scl_flag) begin 
                                cnt_shift <= 0; //数据移位计数器
                                data_reg  <= {iic_id[7:1],1'b0}; //发送数据寄存器
                                sda_buf   <= 0; //发送buf
                                sda_link  <= 1; //三态控制
                                run_en    <= 1;
                                end 
                              else begin 
                                cnt_shift <= 0; //数据移位计数器
                                data_reg  <= {iic_id[7:1],1'b0}; //发送数据寄存器
                                sda_buf   <= 1; //发送buf
                                sda_link  <= 1; //三态控制
                                run_en    <= 1;
                                end 
                      
      txidwr_state         :  if(scl == 0 && scl_flag && cnt_shift == 8) begin
								data_reg  <= 0;
								cnt_shift <= 0;
								sda_buf   <= 0;
								sda_link  <= 0;
								end
							  else if(scl == 0 && scl_flag && cnt_shift < 8) begin 
								data_reg  <= {data_reg[6:0],data_reg[7]};
								cnt_shift <= cnt_shift + 1;
								sda_buf   <= data_reg[7]; 
								sda_link  <= 1;
								end 
							  else begin 
								data_reg  <= data_reg;
								cnt_shift <= cnt_shift;
								sda_buf   <= sda_buf; 
								sda_link  <= sda_link;
								end 
      
      txidwr_ack_state     :  if(scl == 1 && scl_flag) begin 
								cnt_shift <= 0;
								data_reg  <= iic_addr;
								sda_buf   <= 0;
								sda_link  <= 0;
								end 
							  else begin  
								data_reg  <= iic_addr;
								cnt_shift <= cnt_shift;
								sda_buf   <= sda_buf; 
								sda_link  <= sda_link;
								end 
      
      txaddrwr_state       :  if(scl == 0 && scl_flag && cnt_shift == 8) begin
								data_reg  <= 0;
								cnt_shift <= 0;
								sda_buf   <= 0;
								sda_link  <= 0;
								end
							  else if(scl == 0 && scl_flag && cnt_shift < 8) begin 
								data_reg  <= {data_reg[6:0],data_reg[7]};
								cnt_shift <= cnt_shift + 1;
								sda_buf   <= data_reg[7]; 
								sda_link  <= 1;
								end 
							  else begin 
								data_reg  <= data_reg;
								cnt_shift <= cnt_shift;
								sda_buf   <= sda_buf; 
								sda_link  <= sda_link;
								end 
                      
      txaddrwr_ack_state   :  if(scl == 1 && scl_flag) begin 
								cnt_shift <= 0;
								data_reg  <= 0;
								sda_buf   <= 0;
								sda_link  <= 0;
								end 
							  else begin  
								data_reg  <= data_reg;
								cnt_shift <= cnt_shift;
								sda_buf   <= sda_buf; 
								sda_link  <= sda_link;
								end
      sel_state 	      :   if(rd_sel == 0)
                              	  data_reg <= wr_data;
							  else 
								  data_reg <= 0;
								
	  txdata_state        :  if(scl == 0 && scl_flag && cnt_shift == 8) begin
                                data_reg <= 0;
                                cnt_shift <= 0;
                                sda_buf <= 0;
                                sda_link <= 0;
                                end
                              else if(scl == 0 && scl_flag && cnt_shift < 8) begin 
                                data_reg <= {data_reg[6:0],data_reg[7]};
                                cnt_shift <= cnt_shift + 1;
                                sda_buf <= data_reg[7]; 
                                sda_link <= 1;
                                end 
                              else begin 
                                data_reg <= data_reg;
                                cnt_shift <= cnt_shift;
                                sda_buf <= sda_buf; 
                                sda_link <= sda_link;
                                end   
       
       txdata_ack_state    :  if(scl == 1 && scl_flag) begin 
                                cnt_shift <= 0;
                                data_reg <= 0;
                                sda_buf <= 0;
                                sda_link <= 0;
                                end 
                              else begin  
                                data_reg <= data_reg;
                                cnt_shift <= cnt_shift;
                                sda_buf <= sda_buf; 
                                sda_link <= sda_link;
                                end 
      
      readyrd_state        :  if(scl == 0 && scl_flag) begin 
								cnt_shift <= 0;
								data_reg  <= 0;
								sda_buf   <= 1;
								sda_link  <= 1;
								end 
							  else begin  
								data_reg  <= data_reg;
								cnt_shift <= cnt_shift;
								sda_buf   <= sda_buf; 
								sda_link  <= sda_link;
								end       
		
      startrd_state        :  if(scl == 1 && scl_flag) begin 
								cnt_shift <= 0;
								data_reg  <= {iic_id[7:1],1'b1}; ;
								sda_buf   <= 0;
								sda_link  <= 1;
								end 
							  else begin  
								data_reg  <= {iic_id[7:1],1'b1}; ;
								cnt_shift <= cnt_shift;
								sda_buf   <= sda_buf; 
								sda_link  <= sda_link;
								end   
                      
      txidrd_state         : if(scl == 0 && scl_flag && cnt_shift == 8) begin
								data_reg  <= 0;
								cnt_shift <= 0;
								sda_buf   <= 0;
								sda_link  <= 0;
								end
							  else if(scl == 0 && scl_flag && cnt_shift < 8) begin 
								data_reg  <= {data_reg[6:0],data_reg[7]};
								cnt_shift <= cnt_shift + 1;
								sda_buf   <= data_reg[7]; 
								sda_link  <= 1;
								end 
							  else begin 
								data_reg  <= data_reg;
								cnt_shift <= cnt_shift;
								sda_buf   <= sda_buf; 
								sda_link  <= sda_link;
								end   
      
      txidrd_ack_state     :  if(scl == 1 && scl_flag) begin 
							    cnt_shift <= 0;
							    data_reg  <= 0;
							    sda_buf   <= 0;
							    sda_link  <= 0;
							    end 
							  else begin  
							    data_reg  <= data_reg;
							    cnt_shift <= cnt_shift;
							    sda_buf   <= sda_buf; 
							    sda_link  <= sda_link;
							    end               
      
      rxaddrrd_state       :  if(scl == 1 && scl_flag && cnt_shift == 7) begin 
							    rd_data   <= {rd_data[6:0],sda};
							    cnt_shift <= 0;
							    sda_buf   <= 0;
							    sda_link  <= 0;
							    end
							  else if(scl == 1 && scl_flag && cnt_shift < 7) begin 
							    rd_data   <= {rd_data[6:0],sda};
							    cnt_shift <= cnt_shift + 1;
							    sda_buf   <= 0;
							    sda_link  <= 0;
							    end 
							  else begin 
							    data_reg  <= data_reg;
							    cnt_shift <= cnt_shift;
							    sda_buf   <= sda_buf; 
							    sda_link  <= sda_link; 
							    end               
      
      rxaddrrd_ack_state   :  if(scl == 0 && scl_flag) begin 
							    data_reg  <= data_reg;
							    cnt_shift <= 0;
							    sda_buf   <= 1;
							    sda_link  <= 1;
							    end 
							  else begin  
							    data_reg  <= data_reg;
							    cnt_shift <= cnt_shift;
							    sda_buf   <= sda_buf; 
							    sda_link  <= sda_link; 
							    end  
                                 
      readystop_state 	   :  if(scl == 0 && scl_flag) begin 
							    data_reg  <= data_reg;
							    cnt_shift <= 0;
							    sda_buf   <= 0;
							    sda_link  <= 1;
							    end 
							  else begin  
							    data_reg  <= data_reg;
							    cnt_shift <= cnt_shift;
							    sda_buf   <= sda_buf; 
							    sda_link  <= sda_link; 
							 	end
                   
      stop_state           :  if(scl == 1 && scl_flag) begin 
							    data_reg  <= data_reg;
							    cnt_shift <= 0;
							    sda_buf   <= 1;
							    sda_link  <= 1;
							    run_en    <= 0;
							    end 
							  else begin  
							    data_reg  <= data_reg;
							    cnt_shift <= cnt_shift;
							    sda_buf   <= sda_buf; 
							    sda_link  <= sda_link; 
							    end
                    
      end_state       :  begin 
							    data_reg  <= data_reg;
							    cnt_shift <= 0;
							    sda_buf   <= 1;
							    sda_link  <= 1;
							    run_en    <= 0;
								 if(rd_sel == 1) begin 
								   wr_done    <= 0;
								   rd_done    <= 1;
								   end
								 else begin 
								   wr_done    <= 1;
								   rd_done    <= 0;
								   end 
							  end     
							  
      endcase 
   end 
        
endmodule 

4,FPGA实现IIC从机

   FPGA实现IIC从读写设计,已设计为简单的并行读写控制接口,只要控制改读写接口就能完成IIC接口时序,代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: xy
// 
// Create Date: 2020/08/28 13:37:07
// Design Name: 
// Module Name: iic_slave_design
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module iic_slave_design (
    //external port 
    input                   clk,
    input                   rst,
	input					iic_scl,
	inout					iic_sda,
	//test port
	output     [7:0]        ot_iddata,
	output     [7:0]        ot_addr,
	output     [7:0]        ot_datareg,
	output                  ot_iic_sda,
	output                  ot_iic_scl,
	output     [3:0]        ot_state,
	//internal data port
	input      [7:0]        tx_data,
	output     [7:0]        rx_addr,
	output     [7:0]        rx_data,
	output  				rx_data_en
	
);
	
	reg sda_link = 0; 
	reg sda_buf  = 0;
	assign iic_sda 	= (sda_link == 1) ? sda_buf : 1'bz;
	
//****************************IIC data detection*******************************************************	
    
	reg sda_r1=0,sda_r2=0;
	reg scl_r1=0,scl_r2=0;
	wire iic_riseing;
	wire iic_falling;
	wire scl_riseing; 
	wire scl_falling; 
	reg  [31:0]  time_cnt;
	wire         time_flag;
	
	
	always @ (posedge clk) begin 
	    scl_r1 <= iic_scl;
	    scl_r2 <= scl_r1;
	    
		sda_r1 <= iic_sda;
		sda_r2 <= sda_r1;
	end 
	assign iic_riseing = !sda_r2 && sda_r1; //scl posedge 
	assign iic_falling = sda_r2 && !sda_r1; //scl negedge 
	assign scl_riseing = !scl_r2 && scl_r1;
	assign scl_falling = scl_r2 && !scl_r1;
	
	always @ (posedge clk) begin  //timeout control
		if(rst) 
			time_cnt <= 0;
		else if(scl_riseing || scl_falling || time_flag) 
			time_cnt <= 0;
		else 
			time_cnt <= time_cnt + 1;	
	end 
	
	assign time_flag = (time_cnt == 499999) ? 1 : 0; // 10ms
//------------------------------------------------------------------------------------------------------
	localparam [3:0] ildestate      = 0; 
	localparam [3:0] startwrstate   = 1; 
	localparam [3:0] wr_state       = 2;
	localparam [3:0] wrok_state     = 3; 
	localparam [3:0] wrack_state    = 4;

	localparam [3:0] startrdstate   = 5; 
	localparam [3:0] rdid_state     = 6;
	localparam [3:0] rdidok_state   = 7; 
	localparam [3:0] rdidack_state  = 8;
	localparam [3:0] ready_rdstate  = 9; 
	localparam [3:0] rdda_state     = 10;
	localparam [3:0] rddaok_state   = 11;
	localparam [3:0] rddaack_state  = 12;    
	localparam [3:0] rddasel_state  = 13;    

	reg [3:0] iic_next_state     = ildestate;
	reg [3:0] iic_current_state  = ildestate;
	
	reg [3:0] shift_cnt  = 0; //sda data shift count   
	reg [7:0] iic_sel  = 0;   //data count; 0-ID,1-addr  default : data
	reg [7:0] shift_reg = 0;  //sda data shift reg 
	reg [7:0] data_reg  = 0;  //rxdata reg 
	reg       data_reg_en = 0; //rxdata enable
	
	
	reg [7:0] id_data  = 0;  //ID
	reg [7:0] iic_addr = 0; //iic reg addr 
	wire [7:0] iic_data; //iic reg data 
	assign iic_data = tx_data;
//***********************************IIC Slave FSM ***********************************
	always @ (posedge clk) begin :  FSM_1
		if(rst) 
			iic_current_state <= ildestate;
		else 
			iic_current_state <= iic_next_state;
	end 

	always @ (*) begin  :  FSM_2
		if(rst)
			iic_next_state = ildestate;
	 else case(iic_current_state)
					
			ildestate : if(scl_r2 && iic_falling)       //waiting start 
					iic_next_state = startwrstate;
				else 
					iic_next_state = ildestate;	
					
			startwrstate : if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 0)           	    	
					iic_next_state = wr_state;
				else if(iic_sel == 2 && scl_r2 && iic_falling)  
                    iic_next_state = startrdstate;
				else if(scl_r2 && iic_riseing)       			
					iic_next_state = ildestate;
				else 
					iic_next_state = startwrstate;	
					
			wr_state : if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 && shift_cnt == 7) 			
					iic_next_state = wrok_state;
				else if(scl_r2 && shift_cnt < 7)
					iic_next_state = startwrstate;	
				else 
					iic_next_state = wr_state;	
					
			wrok_state : if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 0)           	     
					iic_next_state = wrack_state;
				else if(scl_r2 && iic_falling)  		
                    iic_next_state = startwrstate;
				else if(scl_r2 && iic_riseing)           
					iic_next_state = ildestate;
				else 
					iic_next_state = wrok_state;	
					
			wrack_state : if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 1) 		         
					iic_next_state = startwrstate;
				else 
					iic_next_state = wrack_state;	
					
			
			startrdstate : if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 0)           	 
					iic_next_state = rdid_state;
				else if(scl_r2 && iic_falling)  		
                    iic_next_state = startwrstate;
				else if(scl_r2 && iic_riseing)           
					iic_next_state = ildestate;
				else 
					iic_next_state = startrdstate;		
					
			rdid_state : if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 && shift_cnt == 7)    
					iic_next_state = rdidok_state;
				else if(scl_r2 && shift_cnt < 7)
					iic_next_state = startrdstate;	
				else 
					iic_next_state = rdid_state;	
			
			rdidok_state: if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 0)           	   
					iic_next_state = rdidack_state;
				else if(scl_r2 && iic_falling)  		   
                    iic_next_state = startwrstate;
				else if(scl_r2 && iic_riseing)             
					iic_next_state = ildestate;
				else 
					iic_next_state = rdidok_state;	
					
			rdidack_state: if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 1 && id_data[0] == 1)
					iic_next_state = ready_rdstate;
				else if(scl_r2 == 1)
					iic_next_state = ildestate;
				else 
					iic_next_state = rdidack_state;
					
			ready_rdstate: if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 0)           	     
					iic_next_state = rdda_state;
				else if(scl_r2 && iic_falling)  		  
                    iic_next_state = startwrstate;
				else if(scl_r2 && iic_riseing)            
					iic_next_state = ildestate;
				else 
					iic_next_state = ready_rdstate;
			
			rdda_state:  if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 && shift_cnt == 7)         
					iic_next_state = rddaok_state;
				else if(scl_r2 && shift_cnt < 7)
					iic_next_state = ready_rdstate;	
				else 
					iic_next_state = rdda_state;	
					
			rddaok_state: if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 0)           	
					iic_next_state = rddaack_state; 
				else 
					iic_next_state = rddaok_state;	
					
			rddaack_state: if(time_flag)
					iic_next_state = ildestate;
				else if(scl_r2 == 1 && sda_r2 == 1)
					iic_next_state = ildestate;
				else if(scl_r2 == 1 && sda_r2 == 0) 		        
					iic_next_state = ready_rdstate;
				else 
					iic_next_state = rddaack_state;

		endcase 
	end 
   
	always @ (posedge clk) begin 
		if(rst) begin 
			sda_link <= 0; 
			sda_buf  <= 0;
			
			shift_cnt  <= 0; 
			iic_sel  <= 0; 
			shift_reg <= 0; 
			
			id_data  <= 0; 
			iic_addr <= 0; 
			data_reg  <= 0;
			data_reg_en <= 0;
			end
		else case(iic_current_state)
			ildestate : begin
						sda_link <= 0; 
						sda_buf  <= 0; 
						iic_sel  <= 0;
						shift_cnt  <= 0; 
						shift_reg <= 0; 
						data_reg_en <= 0;
						end 
					
					
			startwrstate : if(scl_r2 == 0) begin          	     
						sda_link <= 0; 
						sda_buf  <= 0; 
						iic_sel  <= iic_sel;
						shift_cnt  <= shift_cnt; 
						shift_reg <= shift_reg; 
						end 
					else if(iic_sel == 2 && scl_r2 && iic_falling) begin  
						sda_link <= 0; 
						sda_buf  <= 0; 
						iic_sel  <= 0;
						shift_cnt  <= 0; 
						shift_reg <= 0; 
						end 
					else if(scl_r2 && iic_riseing) begin 
						sda_link <= 0; 
						sda_buf  <= 0; 
						shift_cnt  <= 0; 
						iic_sel  <= 0; 
						shift_reg <= 0; 
						end 
					else begin 
						sda_link <= sda_link; 
                        sda_buf  <= sda_buf; 
                        iic_sel  <= iic_sel;
                        shift_cnt  <= shift_cnt;
                        shift_reg <= shift_reg;
						data_reg_en <= 0;
						end 
					
			wr_state : if(scl_r2 && shift_cnt == 7) begin 
							sda_link <= 0; 
							sda_buf  <= 0; 
							iic_sel  <= iic_sel + 1;
							shift_cnt  <= 0; 
							shift_reg <= {shift_reg[6:0],iic_sda}; 
							end 
						else if(scl_r2 && shift_cnt < 7) begin 
							sda_link <= 0; 
							sda_buf  <= 0; 
							iic_sel  <= iic_sel;
							shift_cnt  <= shift_cnt + 1; 
							shift_reg <= {shift_reg[6:0],iic_sda}; 
							end 
						else begin 
							sda_link <= sda_link; 
							sda_buf  <= sda_buf; 
							iic_sel  <= iic_sel;
							shift_cnt  <= shift_cnt;
							shift_reg <= shift_reg;
							data_reg_en <= 0;
							end 
							
					
			wrok_state : if(scl_r2 == 0) begin 
							sda_link <= 1; 
							sda_buf  <= 0; 
							shift_cnt  <= 0; 
							case(iic_sel)
                               1 : id_data  <= shift_reg;
                               2 : iic_addr <= shift_reg;
                               3 : begin data_reg  <= shift_reg; data_reg_en <= 1; end 
							   default : begin iic_addr <= iic_addr + 1; data_reg  <= shift_reg; data_reg_en <= 1;  end 
                            endcase
							end 
						else if(scl_r2 && iic_falling) begin  
							sda_link <= 0; 
							sda_buf  <= 0; 
							iic_sel  <= 0;
							shift_cnt  <= 0; 
							shift_reg <= 0; 
							end 
						else if(scl_r2 && iic_riseing) begin 
							sda_link <= 0; 
							sda_buf  <= 0; 
							shift_cnt  <= 0; 
							iic_sel  <= 0; 
							shift_reg <= 0; 
							end 
						else begin 
							sda_link <= sda_link; 
                            sda_buf  <= sda_buf; 
                            id_data  <= id_data;
                            iic_addr <= iic_addr;
                            data_reg  <= data_reg;
							end 
					
			wrack_state :  begin 
						sda_link <= 1; 
						sda_buf  <= 0; 
						iic_sel  <= iic_sel;
						shift_cnt  <= 0; 
						shift_reg <= 0;
						data_reg_en <= 0;
						end 	
					
			startrdstate: if(scl_r2 == 0) begin          	    
						sda_link <= 0; 
						sda_buf  <= 0; 
						shift_cnt  <= shift_cnt; 
						shift_reg <= shift_reg; 
						end 
					else if(scl_r2 && iic_falling) begin 
						sda_link <= 0; 
						sda_buf  <= 0; 
						iic_sel  <= 0;
						shift_cnt  <= 0; 
						shift_reg <= 0; 
						end 
					else if(scl_r2 && iic_riseing) begin 
						sda_link <= 0; 
						sda_buf  <= 0; 
						shift_cnt  <= 0; 
						iic_sel  <= 0; 
						shift_reg <= 0; 
						end 
					else begin 
						sda_link <= sda_link; 
                        sda_buf  <= sda_buf; 
                        iic_sel  <= 0;
                        shift_cnt  <= shift_cnt;
                        shift_reg <= shift_reg;
						data_reg_en <= 0;
						end 		
					
			rdid_state : if(scl_r2 && shift_cnt == 7) begin
							sda_link <= 0; 
							sda_buf  <= 0; 
							shift_cnt  <= 0; 
							shift_reg <= {shift_reg[6:0],iic_sda}; 
							end 
						else if(scl_r2 && shift_cnt < 7) begin 
							sda_link <= 0; 
							sda_buf  <= 0; 
							shift_cnt  <= shift_cnt + 1; 
							shift_reg <= {shift_reg[6:0],iic_sda}; 
							end 
						else begin 
							sda_link <= sda_link; 
                            sda_buf  <= sda_buf; 
                            iic_sel  <= 0;
                            shift_cnt  <= shift_cnt;
                            shift_reg <= shift_reg;
							data_reg_en <= 0;
							end  
							
			rdidok_state : if(scl_r2 == 0) begin          	     
						sda_link <= 1; 
						sda_buf  <= 0; 
						shift_cnt  <= 0; 
						id_data  <= shift_reg;
						end 
					else if(scl_r2 && iic_falling) begin  
						sda_link <= 0; 
						sda_buf  <= 0; 
						iic_sel  <= 0;
						shift_cnt  <= 0; 
						shift_reg <= 0; 
						end 
					else if(scl_r2 && iic_riseing) begin
						sda_link <= 0; 
						sda_buf  <= 0; 
						shift_cnt  <= 0; 
						iic_sel  <= 0; 
						shift_reg <= 0; 
						end 
					else begin 
						sda_link <= sda_link; 
                        sda_buf  <= sda_buf; 
                        iic_sel  <= 0;
                        shift_cnt  <= shift_cnt;
                        shift_reg <= shift_reg; 
						data_reg_en <= 0;
						end 

					
			rdidack_state:  begin 
						sda_link <= 1; 
						sda_buf  <= 0; 
						iic_sel  <= 0;
						shift_cnt  <= 0; 
						shift_reg <= iic_data;
						data_reg_en <= 0;
						end 
					
			ready_rdstate: if(scl_r2 == 0) begin          	     
						sda_link <= 1; 
						sda_buf  <= shift_reg[7]; 
						shift_cnt  <= shift_cnt; 
						shift_reg <= shift_reg;
						end 
					else if(scl_r2 && iic_falling) begin 
						sda_link <= 0; 
						sda_buf  <= 0; 
						iic_sel  <= 0;
						shift_cnt  <= 0; 
						shift_reg <= 0; 
						end 
					else if(scl_r2 && iic_riseing) begin 
						sda_link <= 0; 
						sda_buf  <= 0; 
						shift_cnt  <= 0; 
						iic_sel  <= 0; 
						shift_reg <= 0; 
						end 
					else begin 
						sda_link <= sda_link; 
                        sda_buf  <= sda_buf; 
                        iic_sel  <= 0;
                        shift_cnt  <= shift_cnt;
                        shift_reg <= shift_reg;
						data_reg_en <= 0;
						end 
			
			rdda_state: if(scl_r2 && shift_cnt == 7) begin 
							sda_link <= 1; 
							sda_buf  <= sda_buf; 
							shift_cnt  <= 0; 
							shift_reg <= {shift_reg[6:0],1'b0}; 
							end 
						else if(scl_r2 && shift_cnt < 7) begin 
							sda_link <= 1; 
							sda_buf  <= sda_buf;
							shift_cnt  <= shift_cnt + 1; 
							shift_reg <= {shift_reg[6:0],1'b0}; 
							end 
						else begin 
							sda_link <= sda_link; 
                            sda_buf  <= sda_buf; 
                            iic_sel  <= 0;
                            shift_cnt  <= shift_cnt;
                            shift_reg <= shift_reg;
							data_reg_en <= 0;
							end 	
					
			rddaok_state: if(scl_r2 == 0) begin          	     
						sda_link <= 0; 
						sda_buf  <= 0; 
						shift_cnt  <= 0; 
						shift_reg <= shift_reg;
						iic_addr <= iic_addr + 8'd1;
						end 
					else begin 
						sda_link <= sda_link; 
                        sda_buf  <= sda_buf; 
                        iic_sel  <= 0;
                        shift_cnt  <= shift_cnt;
                        shift_reg <= shift_reg;
						data_reg_en <= 0;
						end 

			rddaack_state: begin
						sda_link <= 0; 
						sda_buf  <= 0; 
						shift_cnt  <= 0; 
						iic_sel  <= 0; 
						shift_reg <= iic_data;
						data_reg_en <= 0;
						end 
			endcase 	
	end 
//--------------------------------------------------------------------------------------------------------------	
	assign  rx_addr = iic_addr;
	assign  rx_data = data_reg;
	assign  rx_data_en = data_reg_en;
	
	assign ot_iddata = id_data;
	assign ot_addr   = iic_addr;
	assign ot_datareg = shift_reg;
	assign ot_iic_sda = sda_r2;
	assign ot_iic_scl = scl_r2;
	assign ot_state = iic_next_state;
	
endmodule 

 

  • 6
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值