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

📄 i2c_control.v.bak

📁 IIC控制器的verilog实现
💻 BAK
字号:
// File Name: i2c_control.v
//
// Module Description:
// This module implements the I2C slave controller.  This module interprets incoming I2C read and write
// accesses and generates output signals or reads input signals that indicate the type of access that is being performed.

module i2c_control(


reset_i,                // global reset




//  I2C bus.
i2c_scl_i,              // I2C master clock.              
i2c_sda_i,              // I2C data input 
i2c_sda_o,              // I2C data output 
i2c_sda_oe,		// I2C SDA OE

// The external register file control and data signals.
reg_add_o,          // register file address
reg_data_i,         // register file read data
reg_data_o,         // register file write data
reg_wr_o            // register file write strobe


);

input  i2c_scl_i;
input  reset_i;




input  i2c_sda_i;
output i2c_sda_o;
output i2c_sda_oe;

output [2:0] reg_add_o;
input  [7:0] reg_data_i;
output [7:0] reg_data_o;
output reg_wr_o;
reg reg_wr_o;


// Miscellaineous parameters.
parameter COUNT_DONE =          4'h8;
parameter SLAVE_ADD  = 		4'b0100;

// I2C state machine states.
parameter STATE_IDLE =          3'b000;
parameter STATE_HEADER =        3'b001;
parameter STATE_ACK_HEADER =    3'b010;
parameter STATE_RCV_DATA =      3'b011;
parameter STATE_XMT_DATA =      3'b100;
parameter STATE_ACK_DATA =      3'b101;
parameter STATE_ILL1	=	3'b110;  //illegal state 1
parameter STATE_ILL2	=	3'b111;  //illegal state 2

// I2C state variables.
reg [4:0] bit_count;            // number of incoming bits received of current byte
reg [7:0] command;              // command byte captured from incoming I2C stream
reg detect_start;               // I2C start detected
reg detect_stop;                // I2C stop detected
reg [7:0] i2c_data_in;          // data captured from incoming I2C stream
reg [7:0] i2c_data_out;         // data to transmit on I2C bus
reg i2c_sda_o;                  // single bit data stream out to I2C bus
reg [2:0] state /*synthesis syn_encoding = "sequential" */;                // state machine state

reg sda_1;
reg sda_2; 

assign i2c_sda_oe = (state == STATE_XMT_DATA) ? 1 : 0;

always @(posedge i2c_scl_i or negedge reset_i)
begin
	if (~reset_i)
	    detect_stop <= 1'b0;
	else
	    if (sda_1 == 1'b0 && sda_2 == 1'b1)
	        detect_stop <= 1'b1;
	    else
	    	detect_stop <= 1'b0;
end	 

always @(negedge i2c_scl_i or negedge reset_i) //capture on falling edge of scl
begin
	if (~reset_i)
	    sda_2 <= 1'b1;
	else
	    sda_2 <= i2c_sda_i;
end

always @(posedge i2c_scl_i or negedge reset_i) //capture on rising edge of scl
begin
	if (~reset_i)
	    sda_1 <= 1'b1;
	else
	    sda_1 <= i2c_sda_i;
end	    	    

// Signal assignment
assign reg_data_o = i2c_data_in;
assign reg_add_o = command[3:1];
assign reset_start = (state == STATE_HEADER)?1:0;



// Load the I2C output register when a complete address is received.
wire load_i2c_data_in;

assign load_i2c_data_out = (state == STATE_ACK_HEADER);

// Write data to the register when it is completely received.
always @(posedge i2c_scl_i or negedge reset_i)
begin
    if (reset_i == 1'b0)
        reg_wr_o <= 8'h00;
    else
        reg_wr_o <= ((state == STATE_RCV_DATA) && (bit_count == (COUNT_DONE - 1))) ;
end

// Identify the I2C start condition as sda falling when scl is high.
always @(negedge i2c_scl_i or posedge reset_start)
begin
    if (reset_start)
        detect_start <= 0;
    else
        if (i2c_sda_i == 1'b0 && sda_1 == 1'b1 && state == STATE_IDLE)
        begin
            detect_start <= 1;
        end
        else
            detect_start <= 0;
end


// The I2C input register.  Data is shifted into this register MSB to LSB.
// Bits are continually captured from the I2C bus on the rising edge of scl.
always @(posedge i2c_scl_i or negedge reset_i)
begin
    if (reset_i == 1'b0)
        i2c_data_in <= 8'h00;
    else
        
    begin
    	i2c_data_in[7:0] <= {i2c_data_in[6:0], i2c_sda_i};
    end
end

// The I2C read data register back.  Data is shifted out of this register MSB to LSB.
always @(posedge i2c_scl_i or negedge reset_i)
begin
    if (reset_i == 1'b0)
        i2c_data_out <= 8'h00;
    else
        if (load_i2c_data_out)
            i2c_data_out[7:0] <= reg_data_i[7:0];
        else
            // Data is shifted on each scl transition during a I2C bus read.
            if (state == STATE_XMT_DATA)
                i2c_data_out[7:0] <= {i2c_data_out[6:0], 1'b0};
end

//  Track the number of bits received of the current byte on the I2C bus.
wire bit_count_clr;
assign bit_count_clr = (state == STATE_IDLE) || (state == STATE_ACK_HEADER); //   || detect_start 

wire bit_count_en;
assign bit_count_en = (state == STATE_HEADER) || (state == STATE_RCV_DATA) ||  (state == STATE_XMT_DATA) ? 1 : 0;

always @(posedge i2c_scl_i or negedge reset_i)
begin
    if (reset_i == 1'b0)
        bit_count <= 4'h0;
    else
    begin
        if (bit_count_clr)
            bit_count <= 4'h0;
        else
            // Increment the bit count on the rising edge of scl.
            if (bit_count_en )
                bit_count <= bit_count + 1;
    end
end

// Determine if our slave address matches that on the I2C bus, and record the command byte.
wire add_compares;
//assign add_compares = (i2c_data_in[7:4] == SLAVE_ADD);

// Load the command register after 7 address bits, and RWn bit
always @(posedge i2c_scl_i or negedge reset_i)
begin
    if (reset_i == 1'b0)
        command <= 8'h0;
    else
        if (state == STATE_HEADER && bit_count == (COUNT_DONE - 1))
            command <= i2c_data_in;
end

// The I2C state machine.
always @(posedge i2c_scl_i or negedge reset_i)
begin
    if (reset_i == 1'b0)
    begin
        state <= STATE_IDLE;
    end
    else 
    begin
        case (state)

            // Waiting for a I2C bus transaction to begin.
            STATE_IDLE :
            begin
                if (detect_start)
                    state <= STATE_HEADER;
                else
                    state <= STATE_IDLE;
            end

            // Receiving the first byte of the transaction.
            STATE_HEADER :
            begin
                // We'll have received all the bits at the rising edge of scl, but issue acknowledge on falling 
                // edge of scl
                //if (detect_stop)
                //    state <= STATE_IDLE;
                //else
                if ((bit_count == (COUNT_DONE - 1)) && (i2c_data_in[7:4] == SLAVE_ADD))  
                	state <= STATE_ACK_HEADER;
                 
                //else 
                //if (bit_count == COUNT_DONE && (i2c_data_in[7:4] != SLAVE_ADD))
                //        state <= STATE_IDLE;
                //else
                //	state <= STATE_HEADER;
                
            end
            // Delay one scl period while ack is generated.  The master can terminate an
            // access while waiting for an ack.
            STATE_ACK_HEADER :
            begin
                if (detect_stop)
                        state <= STATE_IDLE;
                    else
                        state <= command[0] ? STATE_XMT_DATA: STATE_RCV_DATA;
                        
            end

            // Receive the data when an I2C write is taking place.
            STATE_RCV_DATA :
            begin
                // Check for a repeated start.
                if (detect_stop)
                    state <= STATE_IDLE;
                else
                    // We'll have received all the bits at the rising edge of scl, but wait until
                    // scl falls before issuing an acknowledge.
                    if (bit_count == COUNT_DONE )
                        state <= STATE_ACK_DATA;
                    else
                    	state <= STATE_RCV_DATA;
               end

            // Transmitting the data when an I2C read is taking place.  We will return a single byte
            // and go idle, ignoring the master acknowledge.
            STATE_XMT_DATA :
            begin
                // Check for a repeated start.
                if (detect_stop)
                    state <= STATE_IDLE;
                else
                    if (bit_count == COUNT_DONE )
                        state <= STATE_ACK_DATA;
                    else
                    	state <= STATE_XMT_DATA;
            end

            // Delay one scl period while ack is generated.  The master can terminate an
            // access while waiting for an ack.
            STATE_ACK_DATA :
            begin
                
                    state <= STATE_IDLE;
               
            end

            // Default to idle.
            default:
            begin
                state <= STATE_IDLE;
            end
        endcase
    end
end

// Generate the sda signal.  The sda signal will either be an acknowledge, or data
// being shifted from the i2c_data_out register.
always @(negedge i2c_scl_i or negedge reset_i)
begin
    if (reset_i == 1'b0)
        i2c_sda_o <= 1'b1;
    else
        // I2C header byte and data acknowledges.
        if ((state == STATE_HEADER && bit_count == COUNT_DONE - 1)|| (state == STATE_RCV_DATA && bit_count == COUNT_DONE))
            i2c_sda_o <= 1'b0;
        else
            // Output the requested read data.
            if ((state == STATE_ACK_HEADER && command[0]== 1'b1) || (state == STATE_XMT_DATA))
                i2c_sda_o <= i2c_data_out[7];
            else
                i2c_sda_o <= 1'b1;
end


endmodule

⌨️ 快捷键说明

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