OpenCores
URL https://opencores.org/ocsvn/i2c/i2c/trunk

Subversion Repositories i2c

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 26 to Rev 27
    Reverse comparison

Rev 26 → Rev 27

/trunk/rtl/verilog/i2c_master_byte_ctrl.v
37,10 → 37,10
 
// CVS Log
//
// $Id: i2c_master_byte_ctrl.v,v 1.3 2001-11-05 11:59:25 rherveille Exp $
// $Id: i2c_master_byte_ctrl.v,v 1.4 2002-11-30 22:24:40 rherveille Exp $
//
// $Date: 2001-11-05 11:59:25 $
// $Revision: 1.3 $
// $Date: 2002-11-30 22:24:40 $
// $Revision: 1.4 $
// $Author: rherveille $
// $Locker: $
// $State: Exp $
47,6 → 47,11
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.3 2001/11/05 11:59:25 rherveille
// Fixed wb_ack_o generation bug.
// Fixed bug in the byte_controller statemachine.
// Added headers.
//
 
`include "timescale.v"
`include "i2c_master_defines.v"
122,51 → 127,51
 
// hookup bit_controller
i2c_master_bit_ctrl bit_controller (
.clk(clk),
.rst(rst),
.nReset(nReset),
.ena(ena),
.clk_cnt(clk_cnt),
.cmd(core_cmd),
.cmd_ack(core_ack),
.busy(i2c_busy),
.din(core_txd),
.dout(core_rxd),
.scl_i(scl_i),
.scl_o(scl_o),
.scl_oen(scl_oen),
.sda_i(sda_i),
.sda_o(sda_o),
.sda_oen(sda_oen)
.clk ( clk ),
.rst ( rst ),
.nReset ( nReset ),
.ena ( ena ),
.clk_cnt ( clk_cnt ),
.cmd ( core_cmd ),
.cmd_ack ( core_ack ),
.busy ( i2c_busy ),
.din ( core_txd ),
.dout ( core_rxd ),
.scl_i ( scl_i ),
.scl_o ( scl_o ),
.scl_oen ( scl_oen ),
.sda_i ( sda_i ),
.sda_o ( sda_o ),
.sda_oen ( sda_oen )
);
 
// generate go-signal
assign go = (read || write || stop) && !cmd_ack;
assign go = (read | write | stop) & ~cmd_ack;
 
// assign dout output to shift-register
assign dout = sr;
 
// generate shift register
always@(posedge clk or negedge nReset)
if (!nReset)
sr <= #1 8'h0;
else if (rst)
sr <= #1 8'h0;
else if (ld)
sr <= #1 din;
else if (shift)
sr <= #1 {sr[6:0], core_rxd};
always @(posedge clk or negedge nReset)
if (!nReset)
sr <= #1 8'h0;
else if (rst)
sr <= #1 8'h0;
else if (ld)
sr <= #1 din;
else if (shift)
sr <= #1 {sr[6:0], core_rxd};
 
// generate counter
always@(posedge clk or negedge nReset)
if (!nReset)
dcnt <= #1 3'h0;
else if (rst)
dcnt <= #1 3'h0;
else if (ld)
dcnt <= #1 3'h7;
else if (shift)
dcnt <= #1 dcnt - 3'h1;
always @(posedge clk or negedge nReset)
if (!nReset)
dcnt <= #1 3'h0;
else if (rst)
dcnt <= #1 3'h0;
else if (ld)
dcnt <= #1 3'h7;
else if (shift)
dcnt <= #1 dcnt - 3'h1;
 
assign cnt_done = !(|dcnt);
 
175,158 → 180,147
//
reg [4:0] c_state; // synopsis enum_state
 
always@(posedge clk or negedge nReset)
if (!nReset)
begin
core_cmd <= #1 `I2C_CMD_NOP;
core_txd <= #1 1'b0;
shift <= #1 1'b0;
ld <= #1 1'b0;
 
cmd_ack <= #1 1'b0;
c_state <= #1 ST_IDLE;
 
ack_out <= #1 1'b0;
end
else if (rst)
begin
core_cmd <= #1 `I2C_CMD_NOP;
core_txd <= #1 1'b0;
shift <= #1 1'b0;
ld <= #1 1'b0;
 
cmd_ack <= #1 1'b0;
c_state <= #1 ST_IDLE;
 
ack_out <= #1 1'b0;
end
always @(posedge clk or negedge nReset)
if (!nReset)
begin
core_cmd <= #1 `I2C_CMD_NOP;
core_txd <= #1 1'b0;
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;
c_state <= #1 ST_IDLE;
ack_out <= #1 1'b0;
end
else if (rst)
begin
core_cmd <= #1 `I2C_CMD_NOP;
core_txd <= #1 1'b0;
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;
c_state <= #1 ST_IDLE;
ack_out <= #1 1'b0;
end
else
begin
// initially reset all signals
core_txd <= #1 sr[7];
shift <= #1 1'b0;
ld <= #1 1'b0;
begin
// initially reset all signals
core_txd <= #1 sr[7];
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;
 
cmd_ack <= #1 1'b0;
case (c_state) // synopsis full_case parallel_case
ST_IDLE:
if (go)
begin
if (start)
begin
c_state <= #1 ST_START;
core_cmd <= #1 `I2C_CMD_START;
end
else if (read)
begin
c_state <= #1 ST_READ;
core_cmd <= #1 `I2C_CMD_READ;
end
else if (write)
begin
c_state <= #1 ST_WRITE;
core_cmd <= #1 `I2C_CMD_WRITE;
end
else // stop
begin
c_state <= #1 ST_STOP;
core_cmd <= #1 `I2C_CMD_STOP;
 
case (c_state) // synopsis full_case parallel_case
ST_IDLE:
if (go)
begin
if (start)
begin
c_state <= #1 ST_START;
core_cmd <= #1 `I2C_CMD_START;
end
else if (read)
begin
c_state <= #1 ST_READ;
core_cmd <= #1 `I2C_CMD_READ;
end
else if (write)
begin
c_state <= #1 ST_WRITE;
core_cmd <= #1 `I2C_CMD_WRITE;
end
else // stop
begin
c_state <= #1 ST_STOP;
core_cmd <= #1 `I2C_CMD_STOP;
// generate command acknowledge signal
cmd_ack <= #1 1'b1;
end
 
// generate command acknowledge signal
cmd_ack <= #1 1'b1;
end
ld <= #1 1'b1;
end
 
ld <= #1 1'b1;
end
ST_START:
if (core_ack)
begin
if (read)
begin
c_state <= #1 ST_READ;
core_cmd <= #1 `I2C_CMD_READ;
end
else
begin
c_state <= #1 ST_WRITE;
core_cmd <= #1 `I2C_CMD_WRITE;
end
 
ST_START:
if (core_ack)
begin
if (read)
begin
c_state <= #1 ST_READ;
core_cmd <= #1 `I2C_CMD_READ;
end
else
begin
c_state <= #1 ST_WRITE;
core_cmd <= #1 `I2C_CMD_WRITE;
end
ld <= #1 1'b1;
end
 
ld <= #1 1'b1;
end
ST_WRITE:
if (core_ack)
if (cnt_done)
begin
c_state <= #1 ST_ACK;
core_cmd <= #1 `I2C_CMD_READ;
end
else
begin
c_state <= #1 ST_WRITE; // stay in same state
core_cmd <= #1 `I2C_CMD_WRITE; // write next bit
shift <= #1 1'b1;
end
 
ST_WRITE:
if (core_ack)
if (cnt_done)
begin
c_state <= #1 ST_ACK;
core_cmd <= #1 `I2C_CMD_READ;
end
else
begin
c_state <= #1 ST_WRITE; // stay in same state
core_cmd <= #1 `I2C_CMD_WRITE; // write next bit
ST_READ:
if (core_ack)
begin
if (cnt_done)
begin
c_state <= #1 ST_ACK;
core_cmd <= #1 `I2C_CMD_WRITE;
end
else
begin
c_state <= #1 ST_READ; // stay in same state
core_cmd <= #1 `I2C_CMD_READ; // read next bit
end
 
shift <= #1 1'b1;
end
shift <= #1 1'b1;
core_txd <= #1 ack_in;
end
 
ST_READ:
if (core_ack)
begin
if (cnt_done)
begin
c_state <= #1 ST_ACK;
core_cmd <= #1 `I2C_CMD_WRITE;
end
else
begin
c_state <= #1 ST_READ; // stay in same state
core_cmd <= #1 `I2C_CMD_READ; // read next bit
end
ST_ACK:
if (core_ack)
begin
if (stop)
begin
c_state <= #1 ST_STOP;
core_cmd <= #1 `I2C_CMD_STOP;
end
else
begin
c_state <= #1 ST_IDLE;
core_cmd <= #1 `I2C_CMD_NOP;
end
 
shift <= #1 1'b1;
core_txd <= #1 ack_in;
end
// assign ack_out output to bit_controller_rxd (contains last received bit)
ack_out <= #1 core_rxd;
 
ST_ACK:
if (core_ack)
begin
if (stop)
begin
c_state <= #1 ST_STOP;
core_cmd <= #1 `I2C_CMD_STOP;
end
else
begin
c_state <= #1 ST_IDLE;
core_cmd <= #1 `I2C_CMD_NOP;
end
// generate command acknowledge signal
cmd_ack <= #1 1'b1;
 
// assign ack_out output to bit_controller_rxd (contains last received bit)
ack_out <= #1 core_rxd;
core_txd <= #1 1'b1;
end
else
core_txd <= #1 ack_in;
 
// generate command acknowledge signal
cmd_ack <= #1 1'b1;
core_txd <= #1 1'b1;
end
else
core_txd <= #1 ack_in;
ST_STOP:
if (core_ack)
begin
c_state <= #1 ST_IDLE;
core_cmd <= #1 `I2C_CMD_NOP;
end
 
ST_STOP:
if (core_ack)
begin
c_state <= #1 ST_IDLE;
core_cmd <= #1 `I2C_CMD_NOP;
end
 
endcase
end
endcase
end
endmodule
 
 
/trunk/rtl/verilog/i2c_master_bit_ctrl.v
37,10 → 37,10
 
// CVS Log
//
// $Id: i2c_master_bit_ctrl.v,v 1.4 2002-10-30 18:10:07 rherveille Exp $
// $Id: i2c_master_bit_ctrl.v,v 1.5 2002-11-30 22:24:40 rherveille Exp $
//
// $Date: 2002-10-30 18:10:07 $
// $Revision: 1.4 $
// $Date: 2002-11-30 22:24:40 $
// $Revision: 1.5 $
// $Author: rherveille $
// $Locker: $
// $State: Exp $
47,6 → 47,9
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.4 2002/10/30 18:10:07 rherveille
// Fixed some reported minor start/stop generation timing issuess.
//
// Revision 1.3 2002/06/15 07:37:03 rherveille
// Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
//
197,8 → 200,8
begin
dSDA <= #1 sSDA; // generate a delayed version of sSDA
 
sta_condition <= #1 !sSDA && dSDA && sSCL;
sto_condition <= #1 sSDA && !dSDA && sSCL;
sta_condition <= #1 ~sSDA & dSDA & sSCL;
sto_condition <= #1 sSDA & ~dSDA & sSCL;
end
 
// generate bus busy signal
208,7 → 211,7
else if (rst)
busy <= #1 1'b0;
else
busy <= #1 (sta_condition || busy) && !sto_condition;
busy <= #1 (sta_condition | busy) & ~sto_condition;
 
 
// generate statemachine
233,111 → 236,8
parameter [16:0] wr_c = 17'b0_1000_0000_0000_0000;
parameter [16:0] wr_d = 17'b1_0000_0000_0000_0000;
 
reg [16:0] c_state, nxt_state; // synopsis enum_state
reg icmd_ack, store_sda;
reg [16:0] c_state; // synopsis enum_state
 
always @(c_state or cmd)
begin
nxt_state = c_state;
icmd_ack = 1'b0; // default no command acknowledge
store_sda = 1'b0;
 
case (c_state) // synopsis full_case parallel_case
// idle state
idle:
case (cmd) // synopsis full_case parallel_case
`I2C_CMD_START:
nxt_state = start_a;
 
`I2C_CMD_STOP:
nxt_state = stop_a;
 
`I2C_CMD_WRITE:
nxt_state = wr_a;
 
`I2C_CMD_READ:
nxt_state = rd_a;
 
default:
nxt_state = idle;
 
endcase
 
// start
start_a:
nxt_state = start_b;
 
start_b:
nxt_state = start_c;
 
start_c:
nxt_state = start_d;
 
start_d:
nxt_state = start_e;
 
start_e:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
 
// stop
stop_a:
nxt_state = stop_b;
 
stop_b:
nxt_state = stop_c;
 
stop_c:
nxt_state = stop_d;
 
stop_d:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
 
// read
rd_a:
nxt_state = rd_b;
 
rd_b:
nxt_state = rd_c;
 
rd_c:
begin
nxt_state = rd_d;
store_sda = 1'b1;
end
 
rd_d:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
 
// write
wr_a:
nxt_state = wr_b;
 
wr_b:
nxt_state = wr_c;
 
wr_c:
nxt_state = wr_d;
 
wr_d:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
 
endcase
end
 
 
// generate registers
always @(posedge clk or negedge nReset)
if (!nReset)
begin
344,6 → 244,8
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
dout <= #1 1'b0;
scl_oen <= #1 1'b1;
sda_oen <= #1 1'b1;
end
else if (rst)
begin
350,155 → 252,173
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
dout <= #1 1'b0;
scl_oen <= #1 1'b1;
sda_oen <= #1 1'b1;
end
else
begin
cmd_ack <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle
 
if (clk_en)
begin
c_state <= #1 nxt_state;
if (store_sda)
dout <= #1 sSDA;
end
case (c_state) // synopsis full_case parallel_case
// idle state
idle:
begin
case (cmd) // synopsis full_case parallel_case
`I2C_CMD_START:
c_state <= #1 start_a;
 
cmd_ack <= #1 icmd_ack && clk_en;
end
`I2C_CMD_STOP:
c_state <= #1 stop_a;
 
//
// convert states to SCL and SDA signals
//
`I2C_CMD_WRITE:
c_state <= #1 wr_a;
 
// assign scl and sda output (always gnd)
assign scl_o = 1'b0;
assign sda_o = 1'b0;
`I2C_CMD_READ:
c_state <= #1 rd_a;
 
// assign scl and sda output_enables
always @(posedge clk or negedge nReset)
if (!nReset)
begin
scl_oen <= #1 1'b1;
sda_oen <= #1 1'b1;
end
else if (rst)
begin
scl_oen <= #1 1'b1;
sda_oen <= #1 1'b1;
end
else if (clk_en)
case (c_state) // synopsis full_case parallel_case
default:
c_state <= #1 idle;
endcase
 
// idle state
idle:
begin
scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 sda_oen; // keep SDA in same state
end
scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 sda_oen; // keep SDA in same state
end
 
// start
start_a:
begin
scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 1'b1; // set SDA high
end
// start
start_a:
begin
c_state <= #1 start_b;
scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 1'b1; // set SDA high
end
 
start_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA high
end
start_b:
begin
c_state <= #1 start_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA high
end
 
start_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // set SDA low
end
start_c:
begin
c_state <= #1 start_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // set SDA low
end
 
start_d:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
end
start_d:
begin
c_state <= #1 start_e;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
end
 
start_e:
begin
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b0; // keep SDA low
end
start_e:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b0; // keep SDA low
end
 
// stop
stop_a:
begin
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b0; // set SDA low
end
// stop
stop_a:
begin
c_state <= #1 stop_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b0; // set SDA low
end
 
stop_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b0; // keep SDA low
end
stop_b:
begin
c_state <= #1 stop_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b0; // keep SDA low
end
 
stop_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
end
stop_c:
begin
c_state <= #1 stop_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
end
 
stop_d:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1; // set SDA high
end
stop_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 clk_en;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1; // set SDA high
end
 
//write
wr_a:
begin
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 din; // set SDA
end
// read
rd_a:
begin
c_state <= #1 rd_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b1; // tri-state SDA
end
 
wr_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 din; // keep SDA
end
rd_b:
begin
c_state <= #1 rd_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA tri-stated
end
 
wr_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 din;
end
rd_c:
begin
c_state <= #1 rd_d;
dout <= #1 sSDA;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1;
end
 
wr_d:
begin
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 din;
end
rd_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 clk_en;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b1;
end
 
// read
rd_a:
begin
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b1; // tri-state SDA
end
// write
wr_a:
begin
c_state <= #1 wr_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 din; // set SDA
end
 
rd_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA tri-stated
end
wr_b:
begin
c_state <= #1 wr_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 din; // keep SDA
end
 
rd_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1;
end
wr_c:
begin
c_state <= #1 wr_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 din;
end
 
rd_d:
begin
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b1;
end
wr_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 din;
end
 
endcase
endcase
end
 
 
// assign scl and sda output (always gnd)
assign scl_o = 1'b0;
assign sda_o = 1'b0;
 
endmodule
/trunk/rtl/verilog/i2c_master_top.v
1,6 → 1,6
/////////////////////////////////////////////////////////////////////
//// ////
//// WISHBONE rev.B2 compliant I2C Master controller Top-level ////
//// WISHBONE revB.2 compliant I2C Master controller Top-level ////
//// ////
//// ////
//// Author: Richard Herveille ////
37,10 → 37,10
 
// CVS Log
//
// $Id: i2c_master_top.v,v 1.5 2001-11-10 10:52:55 rherveille Exp $
// $Id: i2c_master_top.v,v 1.6 2002-11-30 22:24:40 rherveille Exp $
//
// $Date: 2001-11-10 10:52:55 $
// $Revision: 1.5 $
// $Date: 2002-11-30 22:24:40 $
// $Revision: 1.6 $
// $Author: rherveille $
// $Locker: $
// $State: Exp $
47,8 → 47,14
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.5 2001/11/10 10:52:55 rherveille
// Changed PRER reset value from 0x0000 to 0xffff, conform specs.
//
 
// synopsys translate_off
`include "timescale.v"
// synopsys translate_on
 
`include "i2c_master_defines.v"
 
module i2c_master_top(
70,12 → 76,14
input [2:0] wb_adr_i; // lower address bits
input [7:0] wb_dat_i; // databus input
output [7:0] wb_dat_o; // databus output
reg [7:0] wb_dat_o;
input wb_we_i; // write enable input
input wb_stb_i; // stobe/core select signal
input wb_cyc_i; // valid bus cycle input
output wb_ack_o; // bus cycle acknowledge output
output wb_inta_o; // interrupt request signal output
 
reg [7:0] wb_dat_o;
reg wb_ack_o;
reg wb_inta_o;
 
// I2C signals
83,6 → 91,7
input scl_pad_i; // SCL-line input
output scl_pad_o; // SCL-line output (always 1'b0)
output scl_padoen_o; // SCL-line output enable (active low)
 
// i2c data line
input sda_pad_i; // SDA-line input
output sda_pad_o; // SDA-line output (always 1'b0)
121,64 → 130,65
 
// generate internal reset
wire rst_i = arst_i ^ ARST_LVL;
 
// generate acknowledge output signal
assign wb_ack_o = wb_cyc_i && wb_stb_i; // because timing is always honored
always @(posedge wb_clk_i)
wb_ack_o <= #1 wb_cyc_i & wb_stb_i & ~wb_ack_o; // because timing is always honored
 
// assign DAT_O
always@(wb_adr_i or prer or ctr or txr or cr or rxr or sr)
always @(posedge wb_clk_i)
begin
case (wb_adr_i) // synopsis full_case parallel_case
3'b000: wb_dat_o = prer[ 7:0];
3'b001: wb_dat_o = prer[15:8];
3'b010: wb_dat_o = ctr;
3'b011: wb_dat_o = rxr; // write is transmit register (txr)
3'b100: wb_dat_o = sr; // write is command register (cr)
3'b101: wb_dat_o = txr;
3'b110: wb_dat_o = cr;
3'b111: wb_dat_o = 0; // reserved
endcase
case (wb_adr_i) // synopsis full_case parallel_case
3'b000: wb_dat_o = prer[ 7:0];
3'b001: wb_dat_o = prer[15:8];
3'b010: wb_dat_o = ctr;
3'b011: wb_dat_o = rxr; // write is transmit register (txr)
3'b100: wb_dat_o = sr; // write is command register (cr)
3'b101: wb_dat_o = txr;
3'b110: wb_dat_o = cr;
3'b111: wb_dat_o = 0; // reserved
endcase
end
 
 
// generate registers
always@(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
begin
prer <= #1 16'hffff;
ctr <= #1 8'h0;
txr <= #1 8'h0;
cr <= #1 8'h0;
end
else if (wb_rst_i)
begin
prer <= #1 16'hffff;
ctr <= #1 8'h0;
txr <= #1 8'h0;
cr <= #1 8'h0;
end
else
if (wb_cyc_i && wb_stb_i && wb_we_i)
begin
if (!wb_adr_i[2])
case (wb_adr_i[1:0]) // synopsis full_case parallel_case
2'b00 : prer [ 7:0] <= #1 wb_dat_i;
2'b01 : prer [15:8] <= #1 wb_dat_i;
2'b10 : ctr <= #1 wb_dat_i;
2'b11 : txr <= #1 wb_dat_i;
endcase
else
if (core_en && (wb_adr_i[1:0] == 2'b00) ) // only take new commands when i2c core enabled, pending commands are finished
cr <= #1 wb_dat_i;
end
else
begin
if (done)
cr[7:4] <= #1 4'h0; // clear command bits when done
always @(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
begin
prer <= #1 16'hffff;
ctr <= #1 8'h0;
txr <= #1 8'h0;
cr <= #1 8'h0;
end
else if (wb_rst_i)
begin
prer <= #1 16'hffff;
ctr <= #1 8'h0;
txr <= #1 8'h0;
cr <= #1 8'h0;
end
else
if (wb_cyc_i && wb_stb_i && wb_we_i)
begin
if (!wb_adr_i[2])
case (wb_adr_i[1:0]) // synopsis full_case parallel_case
2'b00 : prer [ 7:0] <= #1 wb_dat_i;
2'b01 : prer [15:8] <= #1 wb_dat_i;
2'b10 : ctr <= #1 wb_dat_i;
2'b11 : txr <= #1 wb_dat_i;
endcase
else
if (core_en && (wb_adr_i[1:0] == 2'b00) ) // only take new commands when i2c core enabled, pending commands are finished
cr <= #1 wb_dat_i;
end
else
begin
if (done)
cr[7:4] <= #1 4'h0; // clear command bits when done
 
cr[2:1] <= #1 2'b00; // reserved bits
cr[0] <= #1 cr[0] && irq_flag; // clear when irq_flag cleared
end
cr[2:1] <= #1 2'b00; // reserved bits
cr[0] <= #1 cr[0] && irq_flag; // clear when irq_flag cleared
end
 
 
// decode command register
195,75 → 205,65
 
// hookup byte controller block
i2c_master_byte_ctrl byte_controller (
.clk(wb_clk_i),
.rst(wb_rst_i),
.nReset(rst_i),
.ena(core_en),
.clk_cnt(prer),
.start(sta),
.stop(sto),
.read(rd),
.write(wr),
.ack_in(ack),
.din(txr),
.cmd_ack(done),
.ack_out(irxack),
.dout(rxr),
.i2c_busy(i2c_busy),
.scl_i(scl_pad_i),
.scl_o(scl_pad_o),
.scl_oen(scl_padoen_o),
.sda_i(sda_pad_i),
.sda_o(sda_pad_o),
.sda_oen(sda_padoen_o)
.clk ( wb_clk_i ),
.rst ( wb_rst_i ),
.nReset ( rst_i ),
.ena ( core_en ),
.clk_cnt ( prer ),
.start ( sta ),
.stop ( sto ),
.read ( rd ),
.write ( wr ),
.ack_in ( ack ),
.din ( txr ),
.cmd_ack ( done ),
.ack_out ( irxack ),
.dout ( rxr ),
.i2c_busy ( i2c_busy ),
.scl_i ( scl_pad_i ),
.scl_o ( scl_pad_o ),
.scl_oen ( scl_padoen_o ),
.sda_i ( sda_pad_i ),
.sda_o ( sda_pad_o ),
.sda_oen ( sda_padoen_o )
);
 
 
// status register block + interrupt request signal
always@(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
begin
rxack <= #1 1'b0;
tip <= #1 1'b0;
irq_flag <= #1 1'b0;
end
else if (wb_rst_i)
begin
rxack <= #1 1'b0;
tip <= #1 1'b0;
irq_flag <= #1 1'b0;
end
else
begin
rxack <= #1 irxack;
tip <= #1 (rd || wr);
irq_flag <= #1 (done || irq_flag) && !iack; // interrupt request flag is always generated
end
always @(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
begin
rxack <= #1 1'b0;
tip <= #1 1'b0;
irq_flag <= #1 1'b0;
end
else if (wb_rst_i)
begin
rxack <= #1 1'b0;
tip <= #1 1'b0;
irq_flag <= #1 1'b0;
end
else
begin
rxack <= #1 irxack;
tip <= #1 (rd | wr);
irq_flag <= #1 (done | irq_flag) & ~iack; // interrupt request flag is always generated
end
 
// generate interrupt request signals
always@(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
wb_inta_o <= #1 1'b0;
else if (wb_rst_i)
wb_inta_o <= #1 1'b0;
else
wb_inta_o <= #1 irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set)
// generate interrupt request signals
always @(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
wb_inta_o <= #1 1'b0;
else if (wb_rst_i)
wb_inta_o <= #1 1'b0;
else
wb_inta_o <= #1 irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set)
 
// assign status register bits
assign sr[7] = rxack;
assign sr[6] = i2c_busy;
assign sr[5:2] = 4'h0; // reserved
assign sr[1] = tip;
assign sr[0] = irq_flag;
// assign status register bits
assign sr[7] = rxack;
assign sr[6] = i2c_busy;
assign sr[5:2] = 4'h0; // reserved
assign sr[1] = tip;
assign sr[0] = irq_flag;
 
endmodule
 
 
 
 
 
 
 
 
 
 
/trunk/rtl/vhdl/i2c_master_byte_ctrl.vhd
37,10 → 37,10
 
-- CVS Log
--
-- $Id: i2c_master_byte_ctrl.vhd,v 1.1 2001-11-05 12:02:33 rherveille Exp $
-- $Id: i2c_master_byte_ctrl.vhd,v 1.2 2002-11-30 22:24:37 rherveille Exp $
--
-- $Date: 2001-11-05 12:02:33 $
-- $Revision: 1.1 $
-- $Date: 2002-11-30 22:24:37 $
-- $Revision: 1.2 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
47,6 → 47,11
--
-- Change History:
-- $Log: not supported by cvs2svn $
-- Revision 1.1 2001/11/05 12:02:33 rherveille
-- Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version.
-- Code updated, is now up-to-date to doc. rev.0.4.
-- Added headers.
--
 
 
 
61,9 → 66,6
use ieee.std_logic_arith.all;
 
entity i2c_master_byte_ctrl is
generic(
Tcq : time := 1 ns
);
port (
clk : in std_logic;
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible)
70,7 → 72,7
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible)
ena : in std_logic; -- core enable signal
 
clk_cnt : in unsigned(15 downto 0); -- 4x SCL
clk_cnt : in unsigned(15 downto 0); -- 4x SCL
 
-- input signals
start,
98,32 → 100,29
 
architecture structural of i2c_master_byte_ctrl is
component i2c_master_bit_ctrl is
generic(
Tcq : time := Tcq
);
port (
clk : in std_logic;
rst : in std_logic;
nReset : in std_logic;
ena : in std_logic; -- core enable signal
port (
clk : in std_logic;
rst : in std_logic;
nReset : in std_logic;
ena : in std_logic; -- core enable signal
 
clk_cnt : in unsigned(15 downto 0); -- clock prescale value
clk_cnt : in unsigned(15 downto 0); -- clock prescale value
 
cmd : in std_logic_vector(3 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;
cmd : in std_logic_vector(3 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;
 
din : in std_logic;
dout : out std_logic;
din : in std_logic;
dout : out std_logic;
 
-- i2c lines
scl_i : in std_logic; -- i2c clock line input
scl_o : out std_logic; -- i2c clock line output
scl_oen : out std_logic; -- i2c clock line output enable, active low
sda_i : in std_logic; -- i2c data line input
sda_o : out std_logic; -- i2c data line output
sda_oen : out std_logic -- i2c data line output enable, active low
);
-- i2c lines
scl_i : in std_logic; -- i2c clock line input
scl_o : out std_logic; -- i2c clock line output
scl_oen : out std_logic; -- i2c clock line output enable, active low
sda_i : in std_logic; -- i2c data line input
sda_o : out std_logic; -- i2c data line output
sda_oen : out std_logic -- i2c data line output enable, active low
);
end component i2c_master_bit_ctrl;
 
-- commands for bit_controller block
169,7 → 168,7
 
-- generate host-command-acknowledge
cmd_ack <= host_ack;
 
-- generate go-signal
go <= (read or write or stop) and not host_ack;
 
179,33 → 178,33
-- generate shift register
shift_register: process(clk, nReset)
begin
if (nReset = '0') then
sr <= (others => '0') after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
sr <= (others => '0') after Tcq;
elsif (ld = '1') then
sr <= din after Tcq;
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rxd) after Tcq;
end if;
end if;
if (nReset = '0') then
sr <= (others => '0');
elsif (clk'event and clk = '1') then
if (rst = '1') then
sr <= (others => '0');
elsif (ld = '1') then
sr <= din;
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rxd);
end if;
end if;
end process shift_register;
 
-- generate data-counter
data_cnt: process(clk, nReset)
begin
if (nReset = '0') then
dcnt <= (others => '0') after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
dcnt <= (others => '0') after Tcq;
elsif (ld = '1') then
dcnt <= (others => '1') after Tcq; -- load counter with 7
elsif (shift = '1') then
dcnt <= dcnt -1 after Tcq;
end if;
end if;
if (nReset = '0') then
dcnt <= (others => '0');
elsif (clk'event and clk = '1') then
if (rst = '1') then
dcnt <= (others => '0');
elsif (ld = '1') then
dcnt <= (others => '1'); -- load counter with 7
elsif (shift = '1') then
dcnt <= dcnt -1;
end if;
end if;
end process data_cnt;
 
cnt_done <= '1' when (dcnt = 0) else '0';
214,147 → 213,137
-- state machine
--
statemachine : block
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
signal c_state : states;
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
signal c_state : states;
begin
--
-- command interpreter, translate complex commands into simpler I2C commands
--
nxt_state_decoder: process(clk, nReset)
begin
if (nReset = '0') then
core_cmd <= I2C_CMD_NOP after Tcq;
core_txd <= '0' after Tcq;
shift <= '0' after Tcq;
ld <= '0' after Tcq;
--
-- command interpreter, translate complex commands into simpler I2C commands
--
nxt_state_decoder: process(clk, nReset)
begin
if (nReset = '0') then
core_cmd <= I2C_CMD_NOP;
core_txd <= '0';
shift <= '0';
ld <= '0';
host_ack <= '0';
c_state <= st_idle;
ack_out <= '0';
elsif (clk'event and clk = '1') then
if (rst = '1') then
core_cmd <= I2C_CMD_NOP;
core_txd <= '0';
shift <= '0';
ld <= '0';
host_ack <= '0';
c_state <= st_idle;
ack_out <= '0';
else
-- initialy reset all signal
core_txd <= sr(7);
shift <= '0';
ld <= '0';
host_ack <= '0';
 
host_ack <= '0' after Tcq;
c_state <= st_idle after Tcq;
case c_state is
when st_idle =>
if (go = '1') then
if (start = '1') then
c_state <= st_start;
core_cmd <= I2C_CMD_START;
elsif (read = '1') then
c_state <= st_read;
core_cmd <= I2C_CMD_READ;
elsif (write = '1') then
c_state <= st_write;
core_cmd <= I2C_CMD_WRITE;
else -- stop
c_state <= st_stop;
core_cmd <= I2C_CMD_STOP;
host_ack <= '1'; -- generate acknowledge signal
end if;
 
ack_out <= '0' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
core_cmd <= I2C_CMD_NOP after Tcq;
core_txd <= '0' after Tcq;
shift <= '0' after Tcq;
ld <= '0' after Tcq;
ld <= '1';
end if;
 
host_ack <= '0' after Tcq;
c_state <= st_idle after Tcq;
when st_start =>
if (core_ack = '1') then
if (read = '1') then
c_state <= st_read;
core_cmd <= I2C_CMD_READ;
else
c_state <= st_write;
core_cmd <= I2C_CMD_WRITE;
end if;
 
ack_out <= '0' after Tcq;
else
-- initialy reset all signal
core_txd <= sr(7) after Tcq;
ld <= '1';
end if;
 
shift <= '0' after Tcq;
ld <= '0' after Tcq;
when st_write =>
if (core_ack = '1') then
if (cnt_done = '1') then
c_state <= st_ack;
core_cmd <= I2C_CMD_READ;
else
c_state <= st_write; -- stay in same state
core_cmd <= I2C_CMD_WRITE; -- write next bit
shift <= '1';
end if;
end if;
 
host_ack <= '0' after Tcq;
when st_read =>
if (core_ack = '1') then
if (cnt_done = '1') then
c_state <= st_ack;
core_cmd <= I2C_CMD_WRITE;
else
c_state <= st_read; -- stay in same state
core_cmd <= I2C_CMD_READ; -- read next bit
end if;
 
case c_state is
when st_idle =>
if (go = '1') then
if (start = '1') then
c_state <= st_start after Tcq;
core_cmd <= I2C_CMD_START after Tcq;
elsif (read = '1') then
c_state <= st_read after Tcq;
core_cmd <= I2C_CMD_READ after Tcq;
elsif (write = '1') then
c_state <= st_write after Tcq;
core_cmd <= I2C_CMD_WRITE after Tcq;
else -- stop
c_state <= st_stop after Tcq;
core_cmd <= I2C_CMD_STOP after Tcq;
shift <= '1';
core_txd <= ack_in;
end if;
 
host_ack <= '1' after Tcq; -- generate acknowledge signal
end if;
when st_ack =>
if (core_ack = '1') then
-- check for stop; Should a STOP command be generated ?
if (stop = '1') then
c_state <= st_stop;
core_cmd <= I2C_CMD_STOP;
else
c_state <= st_idle;
core_cmd <= I2C_CMD_NOP;
end if;
 
ld <= '1' after Tcq;
end if;
-- assign ack_out output to core_rxd (contains last received bit)
ack_out <= core_rxd;
 
when st_start =>
if (core_ack = '1') then
if (read = '1') then
c_state <= st_read after Tcq;
core_cmd <= I2C_CMD_READ after Tcq;
else
c_state <= st_write after Tcq;
core_cmd <= I2C_CMD_WRITE after Tcq;
end if;
-- generate command acknowledge signal
host_ack <= '1';
 
ld <= '1' after Tcq;
end if;
core_txd <= '1';
else
core_txd <= ack_in;
end if;
 
when st_write =>
if (core_ack = '1') then
if (cnt_done = '1') then
c_state <= st_ack after Tcq;
core_cmd <= I2C_CMD_READ after Tcq;
else
c_state <= st_write after Tcq; -- stay in same state
core_cmd <= I2C_CMD_WRITE after Tcq; -- write next bit
when st_stop =>
if (core_ack = '1') then
c_state <= st_idle;
core_cmd <= I2C_CMD_NOP;
end if;
 
shift <= '1' after Tcq;
end if;
end if;
when others => -- illegal states
c_state <= st_idle;
core_cmd <= I2C_CMD_NOP;
report ("Byte controller entered illegal state.");
 
when st_read =>
if (core_ack = '1') then
if (cnt_done = '1') then
c_state <= st_ack after Tcq;
core_cmd <= I2C_CMD_WRITE after Tcq;
else
c_state <= st_read after Tcq; -- stay in same state
core_cmd <= I2C_CMD_READ after Tcq; -- read next bit
end if;
end case;
 
shift <= '1' after Tcq;
core_txd <= ack_in after Tcq;
end if;
end if;
end if;
end process nxt_state_decoder;
 
when st_ack =>
if (core_ack = '1') then
-- check for stop; Should a STOP command be generated ?
if (stop = '1') then
c_state <= st_stop after Tcq;
core_cmd <= I2C_CMD_STOP after Tcq;
else
c_state <= st_idle after Tcq;
core_cmd <= I2C_CMD_NOP after Tcq;
end if;
 
-- assign ack_out output to core_rxd (contains last received bit)
ack_out <= core_rxd after Tcq;
 
-- generate command acknowledge signal
host_ack <= '1' after Tcq;
 
core_txd <= '1' after Tcq;
else
core_txd <= ack_in after Tcq;
end if;
 
when st_stop =>
if (core_ack = '1') then
c_state <= st_idle after Tcq;
core_cmd <= I2C_CMD_NOP after Tcq;
end if;
 
when others => -- illegal states
c_state <= st_idle after Tcq;
core_cmd <= I2C_CMD_NOP after Tcq;
report ("Byte controller entered illegal state.");
 
end case;
 
end if;
end if;
end process nxt_state_decoder;
 
end block statemachine;
 
end architecture structural;
/trunk/rtl/vhdl/i2c_master_bit_ctrl.vhd
1,6 → 1,6
---------------------------------------------------------------------
---- ----
---- WISHBONE revB2 compl. I2C Master Core; bit-controller ----
---- WISHBONE revB2 I2C Master Core; bit-controller ----
---- ----
---- ----
---- Author: Richard Herveille ----
37,10 → 37,10
 
-- CVS Log
--
-- $Id: i2c_master_bit_ctrl.vhd,v 1.3 2002-10-30 18:09:53 rherveille Exp $
-- $Id: i2c_master_bit_ctrl.vhd,v 1.4 2002-11-30 22:24:37 rherveille Exp $
--
-- $Date: 2002-10-30 18:09:53 $
-- $Revision: 1.3 $
-- $Date: 2002-11-30 22:24:37 $
-- $Revision: 1.4 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
47,6 → 47,9
--
-- Change History:
-- $Log: not supported by cvs2svn $
-- Revision 1.3 2002/10/30 18:09:53 rherveille
-- Fixed some reported minor start/stop generation timing issuess.
--
-- Revision 1.2 2002/06/15 07:37:04 rherveille
-- Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
--
101,9 → 104,6
use ieee.std_logic_arith.all;
 
entity i2c_master_bit_ctrl is
generic(
Tcq : time := 1 ns
);
port (
clk : in std_logic;
rst : in std_logic;
136,7 → 136,7
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100";
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000";
 
type states is (idle, start_a, start_b, start_c, start_d, start_e,
type states is (idle, start_a, start_b, start_c, start_d, start_e,
stop_a, stop_b, stop_c, stop_d, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
signal c_state : states;
 
153,8 → 153,8
synch_scl_sda: process(clk)
begin
if (clk'event and clk = '1') then
sSCL <= scl_i after Tcq;
sSDA <= sda_i after Tcq;
sSCL <= scl_i;
sSDA <= sda_i;
end if;
end process synch_SCL_SDA;
 
162,7 → 162,7
process (clk)
begin
if (clk'event and clk = '1') then
dscl_oen <= iscl_oen after Tcq;
dscl_oen <= iscl_oen;
end if;
end process;
 
173,21 → 173,21
gen_clken: process(clk, nReset)
begin
if (nReset = '0') then
cnt <= (others => '0') after Tcq;
clk_en <= '1' after Tcq;
cnt <= (others => '0');
clk_en <= '1';
elsif (clk'event and clk = '1') then
if (rst = '1') then
cnt <= (others => '0') after Tcq;
clk_en <= '1' after Tcq;
cnt <= (others => '0');
clk_en <= '1';
else
if ( (cnt = 0) or (ena = '0') ) then
clk_en <= '1' after Tcq;
cnt <= clk_cnt after Tcq;
clk_en <= '1';
cnt <= clk_cnt;
else
if (slave_wait = '0') then
cnt <= cnt -1 after Tcq;
cnt <= cnt -1;
end if;
clk_en <= '0' after Tcq;
clk_en <= '0';
end if;
end if;
end if;
218,12 → 218,12
gen_busy: process(clk, nReset)
begin
if (nReset = '0') then
ibusy <= '0' after Tcq;
ibusy <= '0';
elsif (clk'event and clk = '1') then
if (rst = '1') then
ibusy <= '0' after Tcq;
ibusy <= '0';
else
ibusy <= (sta_condition or ibusy) and not sto_condition after Tcq;
ibusy <= (sta_condition or ibusy) and not sto_condition;
end if;
end if;
end process gen_busy;
235,219 → 235,141
 
-- generate statemachine
nxt_state_decoder : process (clk, nReset, c_state, cmd)
variable nxt_state : states;
variable icmd_ack, store_sda : std_logic;
begin
nxt_state := c_state;
if (nReset = '0') then
c_state <= idle;
cmd_ack <= '0';
dout <= '0';
iscl_oen <= '1';
isda_oen <= '1';
elsif (clk'event and clk = '1') then
if (rst = '1') then
c_state <= idle;
cmd_ack <= '0';
dout <= '0';
iscl_oen <= '1';
isda_oen <= '1';
else
cmd_ack <= '0'; -- default no acknowledge
 
icmd_ack := '0'; -- default no acknowledge
if (clk_en = '1') then
case (c_state) is
-- idle
when idle =>
case cmd is
when I2C_CMD_START => c_state <= start_a;
when I2C_CMD_STOP => c_state <= stop_a;
when I2C_CMD_WRITE => c_state <= wr_a;
when I2C_CMD_READ => c_state <= rd_a;
when others => c_state <= idle; -- NOP command
end case;
 
store_sda := '0';
iscl_oen <= iscl_oen; -- keep SCL in same state
isda_oen <= isda_oen; -- keep SDA in same state
 
case (c_state) is
-- idle
when idle =>
case cmd is
when I2C_CMD_START =>
nxt_state := start_a;
-- start
when start_a =>
c_state <= start_b;
iscl_oen <= iscl_oen; -- keep SCL in same state (for repeated start)
isda_oen <= '1'; -- set SDA high
 
when I2C_CMD_STOP =>
nxt_state := stop_a;
when start_b =>
c_state <= start_c;
iscl_oen <= '1'; -- set SCL high
isda_oen <= '1'; -- keep SDA high
 
when I2C_CMD_WRITE =>
nxt_state := wr_a;
when start_c =>
c_state <= start_d;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '0'; -- set SDA low
 
when I2C_CMD_READ =>
nxt_state := rd_a;
when start_d =>
c_state <= start_e;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '0'; -- keep SDA low
 
when others => -- NOP command
nxt_state := idle;
end case;
when start_e =>
c_state <= idle;
cmd_ack <= '1'; -- command completed
iscl_oen <= '0'; -- set SCL low
isda_oen <= '0'; -- keep SDA low
 
-- start
when start_a =>
nxt_state := start_b;
-- stop
when stop_a =>
c_state <= stop_b;
iscl_oen <= '0'; -- keep SCL disabled
isda_oen <= '0'; -- set SDA low
 
when start_b =>
nxt_state := start_c;
when stop_b =>
c_state <= stop_c;
iscl_oen <= '1'; -- set SCL high
isda_oen <= '0'; -- keep SDA low
 
when start_c =>
nxt_state := start_d;
when stop_c =>
c_state <= stop_d;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '0'; -- keep SDA low
 
when start_d =>
nxt_state := start_e;
when stop_d =>
c_state <= idle;
cmd_ack <= '1'; -- command completed
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '1'; -- set SDA high
 
when start_e =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
-- read
when rd_a =>
c_state <= rd_b;
iscl_oen <= '0'; -- keep SCL low
isda_oen <= '1'; -- tri-state SDA
 
-- stop
when stop_a =>
nxt_state := stop_b;
when rd_b =>
c_state <= rd_c;
iscl_oen <= '1'; -- set SCL high
isda_oen <= '1'; -- tri-state SDA
 
when stop_b =>
nxt_state := stop_c;
when rd_c =>
c_state <= rd_d;
dout <= sSDA;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '1'; -- tri-state SDA
 
when stop_c =>
nxt_state := stop_d;
when rd_d =>
c_state <= idle;
cmd_ack <= '1'; -- command completed
iscl_oen <= '0'; -- set SCL low
isda_oen <= '1'; -- tri-state SDA
 
when stop_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
-- write
when wr_a =>
c_state <= wr_b;
iscl_oen <= '0'; -- keep SCL low
isda_oen <= din; -- set SDA
 
-- read
when rd_a =>
nxt_state := rd_b;
when wr_b =>
c_state <= wr_c;
iscl_oen <= '1'; -- set SCL high
isda_oen <= din; -- keep SDA
 
when rd_b =>
nxt_state := rd_c;
when wr_c =>
c_state <= wr_d;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= din; -- keep SDA
 
when rd_c =>
nxt_state := rd_d;
store_sda := '1';
when wr_d =>
c_state <= idle;
cmd_ack <= '1'; -- command completed
iscl_oen <= '0'; -- set SCL low
isda_oen <= din; -- keep SDA
 
when rd_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
when others =>
 
-- write
when wr_a =>
nxt_state := wr_b;
 
when wr_b =>
nxt_state := wr_c;
 
when wr_c =>
nxt_state := wr_d;
 
when wr_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
end case;
 
-- generate regs
if (nReset = '0') then
c_state <= idle after Tcq;
cmd_ack <= '0' after Tcq;
Dout <= '0' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
c_state <= idle after Tcq;
cmd_ack <= '0' after Tcq;
Dout <= '0' after Tcq;
elsif (clk_en = '1') then
c_state <= nxt_state after Tcq;
 
if (store_sda = '1') then
dout <= sSDA after Tcq;
end case;
end if;
end if;
 
cmd_ack <= icmd_ack and clk_en;
end if;
end process nxt_state_decoder;
 
--
-- convert states to SCL and SDA signals
--
output_decoder: process (clk, nReset, c_state, iscl_oen, isda_oen, din)
variable iscl, isda : std_logic;
begin
case (c_state) is
-- idle
when idle =>
iscl := iscl_oen; -- keep SCL in same state
isda := isda_oen; -- keep SDA in same state
 
-- start
when start_a =>
iscl := iscl_oen; -- keep SCL in same state (for repeated start)
isda := '1'; -- set SDA high
 
when start_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- keep SDA high
 
when start_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- set SDA low
 
when start_d =>
iscl := '1'; -- keep SCL high
isda := '0'; -- keep SDA low
 
when start_e =>
iscl := '0'; -- set SCL low
isda := '0'; -- keep SDA low
 
-- stop
when stop_a =>
iscl := '0'; -- keep SCL disabled
isda := '0'; -- set SDA low
 
when stop_b =>
iscl := '1'; -- set SCL high
isda := '0'; -- keep SDA low
 
when stop_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- keep SDA low
 
when stop_d =>
iscl := '1'; -- keep SCL high
isda := '1'; -- set SDA high
 
-- write
when wr_a =>
iscl := '0'; -- keep SCL low
isda := din; -- set SDA
 
when wr_b =>
iscl := '1'; -- set SCL high
isda := din; -- keep SDA
 
when wr_c =>
iscl := '1'; -- keep SCL high
isda := din; -- keep SDA
 
when wr_d =>
iscl := '0'; -- set SCL low
isda := din; -- keep SDA
 
-- read
when rd_a =>
iscl := '0'; -- keep SCL low
isda := '1'; -- tri-state SDA
 
when rd_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- tri-state SDA
 
when rd_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- tri-state SDA
 
when rd_d =>
iscl := '0'; -- set SCL low
isda := '1'; -- tri-state SDA
end case;
 
-- generate registers
if (nReset = '0') then
iscl_oen <= '1' after Tcq;
isda_oen <= '1' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
iscl_oen <= '1' after Tcq;
isda_oen <= '1' after Tcq;
elsif (clk_en = '1') then
iscl_oen <= iscl after Tcq;
isda_oen <= isda after Tcq;
end if;
end if;
end process output_decoder;
 
-- assign outputs
scl_o <= '0';
scl_oen <= iscl_oen;
/trunk/rtl/vhdl/i2c_master_top.vhd
37,10 → 37,10
 
-- CVS Log
--
-- $Id: i2c_master_top.vhd,v 1.2 2001-11-10 10:52:44 rherveille Exp $
-- $Id: i2c_master_top.vhd,v 1.3 2002-11-30 22:24:37 rherveille Exp $
--
-- $Date: 2001-11-10 10:52:44 $
-- $Revision: 1.2 $
-- $Date: 2002-11-30 22:24:37 $
-- $Revision: 1.3 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
47,6 → 47,9
--
-- Change History:
-- $Log: not supported by cvs2svn $
-- Revision 1.2 2001/11/10 10:52:44 rherveille
-- Changed PRER reset value from 0x0000 to 0xffff, conform specs.
--
 
 
library ieee;
55,26 → 58,21
 
entity i2c_master_top is
generic(
ARST_LVL : std_logic := '0'; -- asynchronous reset level
 
-- Register timing parameters.
-- Last parameters in list for
-- verilog compatibility
Tcq : time := 1 ns -- Clock to output delay
ARST_LVL : std_logic := '0' -- asynchronous reset level
);
port (
-- wishbone signals
wb_clk_i : in std_logic; -- master clock input
wb_rst_i : in std_logic := '0'; -- synchronous active high reset
arst_i : in std_logic := not ARST_LVL; -- asynchronous reset
wb_adr_i : in unsigned(2 downto 0); -- lower address bits
wb_dat_i : in std_logic_vector(7 downto 0); -- Databus input
wb_dat_o : out std_logic_vector(7 downto 0); -- Databus output
wb_we_i : in std_logic; -- Write enable input
wb_stb_i : in std_logic; -- Strobe signals / core select signal
wb_cyc_i : in std_logic; -- Valid bus cycle input
wb_ack_o : out std_logic; -- Bus cycle acknowledge output
wb_inta_o : out std_logic; -- interrupt request output signal
wb_clk_i : in std_logic; -- master clock input
wb_rst_i : in std_logic := '0'; -- synchronous active high reset
arst_i : in std_logic := not ARST_LVL; -- asynchronous reset
wb_adr_i : in unsigned(2 downto 0); -- lower address bits
wb_dat_i : in std_logic_vector(7 downto 0); -- Databus input
wb_dat_o : out std_logic_vector(7 downto 0); -- Databus output
wb_we_i : in std_logic; -- Write enable input
wb_stb_i : in std_logic; -- Strobe signals / core select signal
wb_cyc_i : in std_logic; -- Valid bus cycle input
wb_ack_o : out std_logic; -- Bus cycle acknowledge output
wb_inta_o : out std_logic; -- interrupt request output signal
 
-- i2c lines
scl_pad_i : in std_logic; -- i2c clock line input
88,52 → 86,52
 
architecture structural of i2c_master_top is
component i2c_master_byte_ctrl is
generic(
Tcq : time := Tcq
);
port (
clk : in std_logic;
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible)
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible)
ena : in std_logic; -- core enable signal
port (
clk : in std_logic;
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible)
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible)
ena : in std_logic; -- core enable signal
 
clk_cnt : in unsigned(15 downto 0); -- 4x SCL
clk_cnt : in unsigned(15 downto 0); -- 4x SCL
 
-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
din : in std_logic_vector(7 downto 0);
-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
din : in std_logic_vector(7 downto 0);
 
-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
i2c_busy : out std_logic;
dout : out std_logic_vector(7 downto 0);
-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
i2c_busy : out std_logic;
dout : out std_logic_vector(7 downto 0);
 
-- i2c lines
scl_i : in std_logic; -- i2c clock line input
scl_o : out std_logic; -- i2c clock line output
scl_oen : out std_logic; -- i2c clock line output enable, active low
sda_i : in std_logic; -- i2c data line input
sda_o : out std_logic; -- i2c data line output
sda_oen : out std_logic -- i2c data line output enable, active low
);
-- i2c lines
scl_i : in std_logic; -- i2c clock line input
scl_o : out std_logic; -- i2c clock line output
scl_oen : out std_logic; -- i2c clock line output enable, active low
sda_i : in std_logic; -- i2c data line input
sda_o : out std_logic; -- i2c data line output
sda_oen : out std_logic -- i2c data line output enable, active low
);
end component i2c_master_byte_ctrl;
 
-- registers
signal prer : unsigned(15 downto 0); -- clock prescale register
signal ctr : std_logic_vector(7 downto 0); -- control register
signal txr : std_logic_vector(7 downto 0); -- transmit register
signal rxr : std_logic_vector(7 downto 0); -- receive register
signal cr : std_logic_vector(7 downto 0); -- command register
signal sr : std_logic_vector(7 downto 0); -- status register
signal prer : unsigned(15 downto 0); -- clock prescale register
signal ctr : std_logic_vector(7 downto 0); -- control register
signal txr : std_logic_vector(7 downto 0); -- transmit register
signal rxr : std_logic_vector(7 downto 0); -- receive register
signal cr : std_logic_vector(7 downto 0); -- command register
signal sr : std_logic_vector(7 downto 0); -- status register
 
-- internal reset signal
signal rst_i : std_logic;
 
-- internal acknowledge signal
signal iack_o : std_logic;
 
-- done signal: command completed, clear command register
signal done : std_logic;
 
145,10 → 143,10
signal ien : std_logic;
 
-- status register signals
signal irxack, rxack : std_logic; -- received aknowledge from slave
signal tip : std_logic; -- transfer in progress
signal irq_flag : std_logic; -- interrupt pending flag
signal i2c_busy : std_logic; -- bus busy (start signal detected)
signal irxack, rxack : std_logic; -- received aknowledge from slave
signal tip : std_logic; -- transfer in progress
signal irq_flag : std_logic; -- interrupt pending flag
signal i2c_busy : std_logic; -- bus busy (start signal detected)
 
begin
-- generate internal reset signal
155,44 → 153,36
rst_i <= arst_i xor ARST_LVL;
 
-- generate acknowledge output signal
wb_ack_o <= wb_cyc_i and wb_stb_i; -- because timing is always honored
 
-- assign wb_dat_o
assign_dato : process(wb_adr_i, prer, ctr, txr, cr, rxr, sr)
gen_ack_o : process(wb_clk_i)
begin
case wb_adr_i is
when "000" =>
wb_dat_o <= std_logic_vector(prer( 7 downto 0));
if (wb_clk_i'event and wb_clk_i = '1') then
iack_o <= wb_cyc_i and wb_stb_i and not iack_o; -- because timing is always honored
end if;
end process gen_ack_o;
 
when "001" =>
wb_dat_o <= std_logic_vector(prer(15 downto 8));
wb_ack_o <= iack_o;
 
when "010" =>
wb_dat_o <= ctr;
 
when "011" =>
wb_dat_o <= rxr; -- write is transmit register TxR
-- assign wb_dat_o
assign_dato : process(wb_clk_i)
begin
if (wb_clk_i'event and wb_clk_i = '1') then
case wb_adr_i is
when "000" => wb_dat_o <= std_logic_vector(prer( 7 downto 0));
when "001" => wb_dat_o <= std_logic_vector(prer(15 downto 8));
when "010" => wb_dat_o <= ctr;
when "011" => wb_dat_o <= rxr; -- write is transmit register TxR
when "100" => wb_dat_o <= sr; -- write is command register CR
 
when "100" =>
wb_dat_o <= sr; -- write is command register CR
 
-- Debugging registers:
-- These registers are not documented.
-- Functionality could change in future releases
 
when "101" =>
wb_dat_o <= txr;
 
when "110" =>
wb_dat_o <= cr;
 
when "111" =>
wb_dat_o <= (others => '0');
 
when others =>
wb_dat_o <= (others => 'X'); -- for simulation only
 
end case;
-- Debugging registers:
-- These registers are not documented.
-- Functionality could change in future releases
when "101" => wb_dat_o <= txr;
when "110" => wb_dat_o <= cr;
when "111" => wb_dat_o <= (others => '0');
when others => wb_dat_o <= (others => 'X'); -- for simulation only
end case;
end if;
end process assign_dato;
 
 
199,54 → 189,55
-- registers block
regs_block: process(rst_i, wb_clk_i)
begin
if (rst_i = '0') then
prer <= (others => '1') after Tcq;
ctr <= (others => '0') after Tcq;
txr <= (others => '0') after Tcq;
cr <= (others => '0') after Tcq;
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
prer <= (others => '1') after Tcq;
ctr <= (others => '0') after Tcq;
txr <= (others => '0') after Tcq;
cr <= (others => '0') after Tcq;
else
if (wb_cyc_i = '1' and wb_stb_i = '1' and wb_we_i = '1') then
if (wb_adr_i(2) = '0') then
case wb_adr_i(1 downto 0) is
when "00" => prer( 7 downto 0) <= unsigned(wb_dat_i) after Tcq;
when "01" => prer(15 downto 8) <= unsigned(wb_dat_i) after Tcq;
when "10" => ctr <= wb_dat_i after Tcq;
when "11" => txr <= wb_dat_i after Tcq;
if (rst_i = '0') then
prer <= (others => '1');
ctr <= (others => '0');
txr <= (others => '0');
cr <= (others => '0');
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
prer <= (others => '1');
ctr <= (others => '0');
txr <= (others => '0');
cr <= (others => '0');
else
if (wb_cyc_i = '1' and wb_stb_i = '1' and wb_we_i = '1') then
if (wb_adr_i(2) = '0') then
case wb_adr_i(1 downto 0) is
when "00" => prer( 7 downto 0) <= unsigned(wb_dat_i);
when "01" => prer(15 downto 8) <= unsigned(wb_dat_i);
when "10" => ctr <= wb_dat_i;
when "11" => txr <= wb_dat_i;
 
-- illegal cases, for simulation only
when others =>
report ("Illegal write address, setting all registers to unknown.");
prer <= (others => 'X');
ctr <= (others => 'X');
txr <= (others => 'X');
end case;
elsif ( (core_en = '1') and (wb_adr_i(1 downto 0) = 0) ) then
-- only take new commands when i2c ore enabled
-- pending commands are finished
cr <= wb_dat_i after Tcq;
end if;
else
-- clear command bits when done
if (done = '1') then
cr(7 downto 4) <= (others => '0') after Tcq;
end if;
-- illegal cases, for simulation only
when others =>
report ("Illegal write address, setting all registers to unknown.");
prer <= (others => 'X');
ctr <= (others => 'X');
txr <= (others => 'X');
end case;
elsif ( (core_en = '1') and (wb_adr_i(1 downto 0) = 0) ) then
-- only take new commands when i2c ore enabled
-- pending commands are finished
cr <= wb_dat_i;
end if;
else
-- clear command bits when done
if (done = '1') then
cr(7 downto 4) <= (others => '0');
end if;
 
-- reserved bits
cr(2 downto 1) <= (others => '0') after Tcq;
-- reserved bits
cr(2 downto 1) <= (others => '0');
 
-- clear iack when irq_flag cleared
cr(0) <= cr(0) and irq_flag;
end if;
end if;
end if;
-- clear iack when irq_flag cleared
cr(0) <= cr(0) and irq_flag;
end if;
end if;
end if;
end process regs_block;
 
 
-- decode command register
sta <= cr(7);
sto <= cr(6);
264,7 → 255,7
clk => wb_clk_i,
rst => wb_rst_i,
nReset => rst_i,
ena => core_en,
ena => core_en,
clk_cnt => prer,
start => sta,
stop => sto,
288,50 → 279,49
-- status register block + interrupt request signal
st_irq_block : block
begin
-- generate status register bits
gen_sr_bits: process (wb_clk_i, rst_i)
begin
if (rst_i = '0') then
rxack <= '0' after Tcq;
tip <= '0' after Tcq;
irq_flag <= '0' after Tcq;
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
rxack <= '0' after Tcq;
tip <= '0' after Tcq;
irq_flag <= '0' after Tcq;
else
rxack <= irxack after Tcq;
tip <= (rd or wr) after Tcq;
-- generate status register bits
gen_sr_bits: process (wb_clk_i, rst_i)
begin
if (rst_i = '0') then
rxack <= '0';
tip <= '0';
irq_flag <= '0';
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
rxack <= '0';
tip <= '0';
irq_flag <= '0';
else
rxack <= irxack;
tip <= (rd or wr);
 
-- interrupt request flag is always generated
irq_flag <= (done or irq_flag) and not iack after Tcq;
end if;
end if;
end process gen_sr_bits;
-- interrupt request flag is always generated
irq_flag <= (done or irq_flag) and not iack;
end if;
end if;
end process gen_sr_bits;
 
-- generate interrupt request signals
gen_irq: process (wb_clk_i, rst_i)
begin
if (rst_i = '0') then
wb_inta_o <= '0' after Tcq;
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
wb_inta_o <= '0' after Tcq;
else
-- interrupt signal is only generated when IEN (interrupt enable bit) is set
wb_inta_o <= irq_flag and ien after Tcq;
end if;
end if;
end process gen_irq;
-- generate interrupt request signals
gen_irq: process (wb_clk_i, rst_i)
begin
if (rst_i = '0') then
wb_inta_o <= '0';
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
wb_inta_o <= '0';
else
-- interrupt signal is only generated when IEN (interrupt enable bit) is set
wb_inta_o <= irq_flag and ien;
end if;
end if;
end process gen_irq;
 
-- assign status register bits
sr(7) <= rxack;
sr(6) <= i2c_busy;
sr(5 downto 2) <= (others => '0'); -- reserved
sr(1) <= tip;
sr(0) <= irq_flag;
-- assign status register bits
sr(7) <= rxack;
sr(6) <= i2c_busy;
sr(5 downto 2) <= (others => '0'); -- reserved
sr(1) <= tip;
sr(0) <= irq_flag;
end block;
 
end architecture structural;
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.