//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// Copyright (C) 2009 Authors and OPENCORES.ORG ////
|
//// Copyright (C) 2009 Authors and OPENCORES.ORG ////
|
//// ////
|
//// ////
|
//// This source file may be used and distributed without ////
|
//// This source file may be used and distributed without ////
|
//// restriction provided that this copyright statement is not ////
|
//// restriction provided that this copyright statement is not ////
|
//// removed from the file and that any derivative work contains ////
|
//// removed from the file and that any derivative work contains ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// ////
|
//// ////
|
//// This source file is free software; you can redistribute it ////
|
//// This source file is free software; you can redistribute it ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// later version. ////
|
//// later version. ////
|
//// ////
|
//// ////
|
//// This source is distributed in the hope that it will be ////
|
//// This source is distributed in the hope that it will be ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// details. ////
|
//// details. ////
|
//// ////
|
//// ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// Public License along with this source; if not, download it ////
|
//// Public License along with this source; if not, download it ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
`include "timescale.v"
|
`include "timescale.v"
|
|
|
|
|
module
|
module
|
i2c_to_wb_fsm
|
i2c_to_wb_fsm
|
(
|
(
|
input i2c_data,
|
input i2c_data,
|
input i2c_data_rise,
|
input i2c_data_rise,
|
input i2c_data_fall,
|
input i2c_data_fall,
|
|
|
input i2c_clk,
|
input i2c_clk,
|
input i2c_clk_rise,
|
input i2c_clk_rise,
|
input i2c_clk_fall,
|
input i2c_clk_fall,
|
|
|
input i2c_r_w_bit,
|
input i2c_r_w_bit,
|
input i2c_ack_out,
|
input i2c_ack_out,
|
output i2c_ack_done,
|
output i2c_ack_done,
|
|
|
output tip_addr_byte,
|
output tip_addr_byte,
|
output tip_read_byte,
|
output tip_read_byte,
|
output tip_write_byte,
|
output tip_write_byte,
|
output tip_wr_ack,
|
output tip_wr_ack,
|
output tip_rd_ack,
|
output tip_rd_ack,
|
output tip_addr_ack,
|
output tip_addr_ack,
|
|
|
output [7:0] state_out,
|
output [7:0] state_out,
|
output i2c_error,
|
output i2c_error,
|
|
|
input wb_clk_i,
|
input wb_clk_i,
|
input wb_rst_i
|
input wb_rst_i
|
);
|
);
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
// wires
|
// wires
|
wire xmt_byte_done;
|
wire xmt_byte_done;
|
|
|
wire tip_ack;
|
wire tip_ack;
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
// start & stop & ack
|
// start & stop & ack
|
|
|
wire start_detected = i2c_data_fall & i2c_clk;
|
wire start_detected = i2c_data_fall & i2c_clk;
|
wire stop_detected = i2c_data_rise & i2c_clk;
|
wire stop_detected = i2c_data_rise & i2c_clk;
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
// state machine
|
// state machine
|
|
|
localparam STATE_IDLE = 8'b00000001;
|
localparam STATE_IDLE = 8'b00000001;
|
localparam STATE_ADDR_BYTE = 8'b00000010;
|
localparam STATE_ADDR_BYTE = 8'b00000010;
|
localparam STATE_ADDR_ACK = 8'b00000100;
|
localparam STATE_ADDR_ACK = 8'b00000100;
|
localparam STATE_WRITE = 8'b00001000;
|
localparam STATE_WRITE = 8'b00001000;
|
localparam STATE_WR_ACK = 8'b00010000;
|
localparam STATE_WR_ACK = 8'b00010000;
|
localparam STATE_READ = 8'b00100000;
|
localparam STATE_READ = 8'b00100000;
|
localparam STATE_RD_ACK = 8'b01000000;
|
localparam STATE_RD_ACK = 8'b01000000;
|
localparam STATE_ERROR = 8'b10000000;
|
localparam STATE_ERROR = 8'b10000000;
|
|
|
reg [7:0] state;
|
reg [7:0] state;
|
reg [7:0] next_state;
|
reg [7:0] next_state;
|
|
|
always @(posedge wb_clk_i or posedge wb_rst_i)
|
always @(posedge wb_clk_i or posedge wb_rst_i)
|
if(wb_rst_i)
|
if(wb_rst_i)
|
state <= STATE_IDLE;
|
state <= STATE_IDLE;
|
else
|
else
|
state <= next_state;
|
state <= next_state;
|
|
|
always @(*)
|
always @(*)
|
case( state )
|
case( state )
|
STATE_IDLE: if( start_detected )
|
STATE_IDLE: if( start_detected )
|
next_state = STATE_ADDR_BYTE;
|
next_state = STATE_ADDR_BYTE;
|
else
|
else
|
next_state = STATE_IDLE;
|
next_state = STATE_IDLE;
|
|
|
STATE_ADDR_BYTE: if( xmt_byte_done )
|
STATE_ADDR_BYTE: if( xmt_byte_done )
|
next_state = STATE_ADDR_ACK;
|
next_state = STATE_ADDR_ACK;
|
else if( start_detected | stop_detected )
|
else if( stop_detected )
|
next_state = STATE_ERROR;
|
next_state = STATE_ERROR;
|
else
|
else
|
next_state = STATE_ADDR_BYTE;
|
next_state = STATE_ADDR_BYTE;
|
|
|
STATE_ADDR_ACK: if(i2c_ack_out)
|
STATE_ADDR_ACK: if(i2c_ack_out)
|
next_state = STATE_IDLE;
|
next_state = STATE_IDLE;
|
else
|
else
|
if( i2c_ack_done )
|
if( i2c_ack_done )
|
if( i2c_r_w_bit )
|
if( i2c_r_w_bit )
|
next_state = STATE_READ;
|
next_state = STATE_READ;
|
else
|
else
|
next_state = STATE_WRITE;
|
next_state = STATE_WRITE;
|
else if( start_detected | stop_detected )
|
else if( start_detected | stop_detected )
|
next_state = STATE_ERROR;
|
next_state = STATE_ERROR;
|
else
|
else
|
next_state = STATE_ADDR_ACK;
|
next_state = STATE_ADDR_ACK;
|
|
|
STATE_WRITE: if( xmt_byte_done )
|
STATE_WRITE: if( xmt_byte_done )
|
next_state = STATE_WR_ACK;
|
next_state = STATE_WR_ACK;
|
else if( start_detected )
|
else if( start_detected )
|
next_state = STATE_ADDR_BYTE;
|
next_state = STATE_ADDR_BYTE;
|
else if( stop_detected )
|
else if( stop_detected )
|
next_state = STATE_IDLE;
|
next_state = STATE_IDLE;
|
else
|
else
|
next_state = STATE_WRITE;
|
next_state = STATE_WRITE;
|
|
|
STATE_WR_ACK: if( i2c_ack_done )
|
STATE_WR_ACK: if( i2c_ack_done )
|
next_state = STATE_WRITE;
|
next_state = STATE_WRITE;
|
else if( start_detected | stop_detected )
|
else if( start_detected | stop_detected )
|
next_state = STATE_ERROR;
|
next_state = STATE_ERROR;
|
else
|
else
|
next_state = STATE_WR_ACK;
|
next_state = STATE_WR_ACK;
|
|
|
STATE_READ: if( xmt_byte_done )
|
STATE_READ: if( xmt_byte_done )
|
next_state = STATE_RD_ACK;
|
next_state = STATE_RD_ACK;
|
else if( start_detected )
|
else if( start_detected )
|
next_state = STATE_ADDR_BYTE;
|
next_state = STATE_ADDR_BYTE;
|
else if( stop_detected )
|
else if( stop_detected )
|
next_state = STATE_IDLE;
|
next_state = STATE_IDLE;
|
else
|
else
|
next_state = STATE_READ;
|
next_state = STATE_READ;
|
|
|
STATE_RD_ACK: if( i2c_ack_done )
|
STATE_RD_ACK: if( i2c_ack_done )
|
if(i2c_data)
|
if(i2c_data)
|
next_state = STATE_IDLE;
|
next_state = STATE_IDLE;
|
else
|
else
|
next_state = STATE_READ;
|
next_state = STATE_READ;
|
else if( start_detected | stop_detected )
|
else if( start_detected | stop_detected )
|
next_state = STATE_ERROR;
|
next_state = STATE_ERROR;
|
else
|
else
|
next_state = STATE_RD_ACK;
|
next_state = STATE_RD_ACK;
|
|
|
STATE_ERROR: next_state = STATE_IDLE;
|
STATE_ERROR: next_state = STATE_IDLE;
|
|
|
default: next_state = STATE_ERROR;
|
default: next_state = STATE_ERROR;
|
endcase
|
endcase
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
// bit counter
|
// bit counter
|
reg [3:0] bit_count;
|
reg [3:0] bit_count;
|
|
|
assign xmt_byte_done = (bit_count == 4'h7) & i2c_clk_rise;
|
assign xmt_byte_done = (bit_count == 4'h7) & i2c_clk_rise;
|
assign tip_ack = (bit_count == 4'h8);
|
assign tip_ack = (bit_count == 4'h8);
|
assign i2c_ack_done = tip_ack & i2c_clk_rise;
|
assign i2c_ack_done = tip_ack & i2c_clk_rise;
|
|
|
always @(posedge wb_clk_i)
|
always @(posedge wb_clk_i)
|
if( wb_rst_i | i2c_ack_done | start_detected )
|
if( wb_rst_i | i2c_ack_done | start_detected )
|
bit_count <= 4'hf;
|
bit_count <= 4'hf;
|
else if( i2c_clk_fall )
|
else if( i2c_clk_fall )
|
bit_count <= bit_count + 1;
|
bit_count <= bit_count + 1;
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
|
// debug
|
|
wire i2c_start_error = (state == STATE_ADDR_BYTE) & start_detected;
|
|
|
|
|
|
// --------------------------------------------------------------------
|
// outputs
|
// outputs
|
|
|
assign state_out = state;
|
assign state_out = state;
|
|
|
assign tip_addr_byte = (state == STATE_ADDR_BYTE);
|
assign tip_addr_byte = (state == STATE_ADDR_BYTE);
|
assign tip_addr_ack = (state == STATE_ADDR_ACK);
|
assign tip_addr_ack = (state == STATE_ADDR_ACK);
|
assign tip_read_byte = (state == STATE_READ);
|
assign tip_read_byte = (state == STATE_READ);
|
assign tip_write_byte = tip_addr_byte | (state == STATE_WRITE);
|
assign tip_write_byte = tip_addr_byte | (state == STATE_WRITE);
|
assign tip_wr_ack = tip_addr_ack | (state == STATE_WR_ACK);
|
assign tip_wr_ack = tip_addr_ack | (state == STATE_WR_ACK);
|
assign tip_rd_ack = (state == STATE_RD_ACK);
|
assign tip_rd_ack = (state == STATE_RD_ACK);
|
|
|
assign i2c_error = (state == STATE_ERROR);
|
assign i2c_error = (state == STATE_ERROR) | i2c_start_error;
|
|
|
endmodule
|
endmodule
|
|
|
|
|
|
|
|
|