⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c_slave.v

📁 I2c中通信的从机发送和接收信息的Verilog程序测试模块
💻 V
📖 第 1 页 / 共 2 页
字号:
//----------------------------------------------------------------------------
// 
//  Name:  i2c_slave.v   
// 
//  Description: I2C slave simulation model for I2C serial controller
// 
//  $Revision: 1.0 $          
//  
//  Copyright 2004 Lattice Semiconductor Corporation.  All rights reserved.
//
//----------------------------------------------------------------------------
// Permission:
//
//   Lattice Semiconductor grants permission to use this code for use
//   in synthesis for any Lattice programmable logic product.  Other
//   use of this code, including the selling or duplication of any
//   portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL or Verilog source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Lattice Semiconductor provides no warranty
//   regarding the use or functionality of this code.
//----------------------------------------------------------------------------
//
//    Lattice Semiconductor Corporation
//    5555 NE Moore Court
//    Hillsboro, OR 97124
//    U.S.A
//
//    TEL: 1-800-Lattice (USA and Canada)
//    408-826-6000 (other locations)
//
//    web: http://www.latticesemi.com/
//    email: techsupport@latticesemi.com
// 
//----------------------------------------------------------------------------

`timescale  1 ns /  1 ps

/*
This is a generic standard mode slave model for I2C.

*/

module i2c_slave   (     scl,
                         sda);

//-------------------------------------------------------------------
// port list

input   scl;
inout   sda;


//-------------------------------------------------------------------
// wire declarations

wire            scl;
wire            sda;

//-------------------------------------------------------------------
// reg declarations

reg clk, rst_l;
reg [7:0] mem [255:0]; // 2^8 = 256 locations
reg [7:0] word_address; // counts the active byte 
reg start_detect;
reg stop_detect;
reg sda_reg, sda_reg_delayed;
reg scl_reg, scl_reg_delayed;
reg start_pulse, stop_pulse, scl_pulse, scl_neg_pulse;
reg [6:0] address_reg_7;  // All 7 Bits of 7 bit addressing
reg [9:0] temp10;
reg [6:0] address_reg_10_upper; // Upper 2 bits of address
reg [7:0] address_reg_10_lower; // lower 8 bits of address
reg [3:0] current_state, next_state;
reg [7:0] in_reg, out_reg; // registers used to hold the input
                           // and output data to-from the sda line
reg [3:0] bit_counter; // Used to counter what bit is being selected
                       // for the in_reg and out_reg
reg r_w_bit; // used to hold the read write bit;
reg hit_7, hit_10_upper, hit_10_lower; // flags for address hits
reg sda_out;
reg in_reg_enable; // the clock enable for the in_reg registers.
reg out_en; // the output enable
reg word_add_flag, ack_flag;
reg [7:1] temp_add_upper; 
reg [7:0] temp_add_lower; // temp_add_upper & temp_add_lower are
                     // used to hold the first & 
                     // second address bytes of 10 bit
                    // addressing so that during a 10 bit addressing
                    // read the value of the current 10 bit address
                    // can be compared with the last read.
reg read_10_flag; // This flag is set when the temp_add matches the current 
                  // address_reg_10_upper and the r/w is a 1.  This tells
                  // the ack to goto a data read state instead of getting
                  // the second byte of address.

//-------------------------------------------------------------------
// misc variables
integer i;


//-------------------------------------------------------------------
// defines

  // used for address_mode parameter
`define seven_bit 0 
  // used for address_mode parameter
`define ten_bit 1 
  // used in upper 5 bits of address_reg_10_upper 
  // DON'T CHANGE
`define ten_bit_add 5'b11110
 // a 1 turns this on and a 0 off
`define debug 0

//-------------------------------------------------------------------
// parameters 

parameter period = 30;          // using 33 MHz
parameter reset_time = 20;   // hold reset low this long

// DESIGNER SET the following parameter to use 7 or 10 bit addressing
parameter address_mode = `seven_bit; // Use `seven_bit or `ten_bit

// depending on the value in address_mode either seven_bit_address or 
// ten_bit_address will be used.

// DESIGNER SET the next parameter with the 7 bit address the slave
// should respond to. MSB->LSB
// example: 7'b1010_000; 
parameter seven_bit_address = 7'b1010_000;

// DESIGNER SET the next parameter with the 10 bit address the slave
// should respond to. MSB->LSB
// example: 10'b10_1100_1010;
parameter ten_bit_address = 10'b10_1100_1010;

// state bits
parameter [4:0] idle = 0, 
                start = 1,
                address = 2,
                ack = 3,
                data = 4,
                data_ack = 5;
                
parameter tdh = 100; // tdh = data out hold time min


//-------------------------------------------------------------------
// internal clock for the model

always #(period/2) clk = ~clk;


//------------------------------------------------------------------
// print some status
always @(posedge scl)
 if (`debug) begin 
   $display($time,"%m: Received Clock Data = %b",sda);
 end


//-------------------------------------------------------------------
// initialize the address registers, mem array, clk and control the reset

initial 
  begin
    
    // initialize the address registers
    if (address_mode == `seven_bit) begin 
      $display("%m Using 7 Bit Addressing");
      address_reg_7 = seven_bit_address;
    end
    else if (address_mode == `ten_bit) begin 
      $display("%m Using 10 Bit Addressing");
      temp10 = ten_bit_address;
      address_reg_10_upper = {`ten_bit_add, temp10[9:8]}; // 2 MSB
      address_reg_10_lower = temp10[7:0];
    end
    else begin 
      $display( "/n ERROR: address_mode parameter is INVALID in %m !! /n");
    end
    
    // initialize the mem array
    for (i = 0; i < 256; i = i + 1) begin 
      mem[i] = i;  
    end
 
    r_w_bit = 1'b0;
    out_reg = 8'b0;
    out_en = 0; // disable output
    bit_counter = 0;
    word_address = 8'b0; // initialize byte #
    word_add_flag = 0;
    ack_flag = 0;
    in_reg_enable = 0;
    temp_add_upper = 0;
    temp_add_lower = 0;
    read_10_flag = 0;
    hit_10_upper = 0;
    hit_10_lower = 0;
    hit_7 = 0;
    clk = 1'b0;  // initalize clock
    next_state = 5'b0;
    rst_l = 1'b0;  // turn on reset signal 
    #reset_time;                           
    rst_l = 1'b1; // turn off reset signal
    
  end             



//-------------------------------------------------------------------------
// sda_out is an internal reg that is assigned a 0 when the output should be
// 0 and it assigns a Z otherwise.

assign sda = (sda_out == 0 && out_en) ? 1'b0 : 1'bZ;


//--------------------------------------------------------------------
// start and stop detect logic

always @ (posedge clk or negedge rst_l)
  begin 
    if (!rst_l) begin 
      sda_reg <= 1; // bus is active low
      sda_reg_delayed <= 1;
    end
    else begin 
      sda_reg <= sda;
      sda_reg_delayed <= sda_reg;
    end  
  end

// detect a high to low while scl is high 
// start_pulse
always @ (posedge clk or negedge rst_l)
  begin 
    
    if (!rst_l) begin 
      start_pulse = 0;
    end
    else if (!sda_reg && sda_reg_delayed && scl) begin 
      start_pulse = 1;
    end
    else begin 
      start_pulse = 0;
    end
  end

// start flag
always @ (posedge clk or negedge rst_l)
  begin 

    if (!rst_l) begin 
      start_detect <= 0;
    end
    else if (start_pulse) begin 
      start_detect <= 1;  
    end
    else if (!scl) begin 
      start_detect <= 0; // clear start bit 
    end
    else begin 
      start_detect <= start_detect;
    end
    
  end

// detect a low to high while scl is high 
// stop_pulse
always @ (posedge clk or negedge rst_l)
  begin 
    
    if (!rst_l) begin 
      stop_pulse = 0;
    end
    else if (sda_reg && !sda_reg_delayed && scl) begin 
      stop_pulse = 1;
    end
    else begin 
      stop_pulse = 0;
    end
  end

//stop flag
always @ (posedge clk or negedge rst_l)
  begin 

    if (!rst_l) begin 
      stop_detect <= 0;
    end
    else if (stop_pulse) begin 
      stop_detect <= 1;  
    end
  else if (current_state == idle) begin 
      stop_detect <= 0; // clear start bit 
    end
    
  end
  
//--------------------------------------
 

//--------------------------------------
// SCL posedge & nededge detector regs
always @ (posedge clk or negedge rst_l)
  begin 
    
    if (!rst_l) begin 
      scl_reg <= 1;
      scl_reg_delayed <= 1;
    end
    else begin
      scl_reg <= scl;
      scl_reg_delayed <= scl_reg;
    end
    
  end

// SCL posedge detector
always @ (posedge clk or negedge rst_l)
  begin 
    
    if (!rst_l) begin 
      scl_pulse <= 0;    
    end
    else if (scl_reg && !scl_reg_delayed) begin 
      scl_pulse <= 1;
    end
    else begin 
      scl_pulse <= 0; 
    end
  
  end

// SCL negedge detector
always @ (posedge clk or negedge rst_l)
  begin 
    
    if (!rst_l) begin 
      scl_neg_pulse <= 0;
    end
    else if (!scl_reg && scl_reg_delayed) begin 
      scl_neg_pulse <= 1;
    end
    else begin 
      scl_neg_pulse <= 0;
    end
    
  end

//----------------------------------------


//----------------------------------------
// Output Mux

always @ (bit_counter or out_reg)
  case (bit_counter)
    4'd0: sda_out = out_reg[7];
    4'd1: sda_out = out_reg[6];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -