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 23 to Rev 24
    Reverse comparison

Rev 23 → Rev 24

/trunk/rtl/verilog/i2c_master_bit_ctrl.v
37,10 → 37,10
 
// CVS Log
//
// $Id: i2c_master_bit_ctrl.v,v 1.3 2002-06-15 07:37:03 rherveille Exp $
// $Id: i2c_master_bit_ctrl.v,v 1.4 2002-10-30 18:10:07 rherveille Exp $
//
// $Date: 2002-06-15 07:37:03 $
// $Revision: 1.3 $
// $Date: 2002-10-30 18:10:07 $
// $Revision: 1.4 $
// $Author: rherveille $
// $Locker: $
// $State: Exp $
47,6 → 47,9
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.3 2002/06/15 07:37:03 rherveille
// Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
//
// Revision 1.2 2001/11/05 11:59:25 rherveille
// Fixed wb_ack_o generation bug.
// Fixed bug in the byte_controller statemachine.
82,14 → 85,14
// x | A | B | C | D | i
//
 
// Timing: Normal mode Fast mode
// Timing: Normal mode Fast mode
///////////////////////////////////////////////////////////////////////
// Fscl 100KHz 400KHz
// Th_scl 4.0us 0.6us High period of SCL
// Tl_scl 4.7us 1.3us Low period of SCL
// Tsu:sta 4.7us 0.6us setup time for a repeated start condition
// Tsu:sto 4.0us 0.6us setup time for a stop conditon
// Tbuf 4.7us 1.3us Bus free time between a stop and start condition
// Fscl 100KHz 400KHz
// Th_scl 4.0us 0.6us High period of SCL
// Tl_scl 4.7us 1.3us Low period of SCL
// Tsu:sta 4.7us 0.6us setup time for a repeated start condition
// Tsu:sto 4.0us 0.6us setup time for a stop conditon
// Tbuf 4.7us 1.3us Bus free time between a stop and start condition
//
 
`include "timescale.v"
145,42 → 148,42
 
// synchronize SCL and SDA inputs
always @(posedge clk)
begin
sSCL <= #1 scl_i;
sSDA <= #1 sda_i;
end
begin
sSCL <= #1 scl_i;
sSDA <= #1 sda_i;
end
 
// delay scl_oen
always @(posedge clk)
dscl_oen <= #1 scl_oen;
dscl_oen <= #1 scl_oen;
 
// whenever the slave is not ready it can delay the cycle by pulling SCL low
assign slave_wait = dscl_oen && !sSCL;
 
// generate clk enable signal
always@(posedge clk or negedge nReset)
if (!nReset)
begin
cnt <= #1 16'h0;
clk_en <= #1 1'b1;
end
else if (rst)
begin
cnt <= #1 16'h0;
clk_en <= #1 1'b1;
end
else if ( !(|cnt) || !ena)
begin
cnt <= #1 clk_cnt;
clk_en <= #1 1'b1;
end
else
begin
if (!slave_wait)
cnt <= #1 cnt - 16'h1;
always @(posedge clk or negedge nReset)
if(~nReset)
begin
cnt <= #1 16'h0;
clk_en <= #1 1'b1;
end
else if (rst)
begin
cnt <= #1 16'h0;
clk_en <= #1 1'b1;
end
else if ( !(|cnt) || !ena)
begin
cnt <= #1 clk_cnt;
clk_en <= #1 1'b1;
end
else
begin
if(!slave_wait)
cnt <= #1 cnt - 16'h1;
 
clk_en <= #1 1'b0;
end
clk_en <= #1 1'b0;
end
 
 
// generate bus status controller
190,167 → 193,175
 
// detect start condition => detect falling edge on SDA while SCL is high
// detect stop condition => detect rising edge on SDA while SCL is high
always@(posedge clk)
begin
dSDA <= #1 sSDA; // generate a delayed versio nof sSDA
always @(posedge clk)
begin
dSDA <= #1 sSDA; // generate a delayed version of sSDA
 
sta_condition <= #1 !sSDA && dSDA && sSCL;
sto_condition <= #1 sSDA && !dSDA && sSCL;
end
sta_condition <= #1 !sSDA && dSDA && sSCL;
sto_condition <= #1 sSDA && !dSDA && sSCL;
end
 
// generate bus busy signal
always@(posedge clk or negedge nReset)
if (!nReset)
busy <= #1 1'b0;
else if (rst)
busy <= #1 1'b0;
else
busy <= (sta_condition || busy) && !sto_condition;
always @(posedge clk or negedge nReset)
if(!nReset)
busy <= #1 1'b0;
else if (rst)
busy <= #1 1'b0;
else
busy <= #1 (sta_condition || busy) && !sto_condition;
 
 
// generate statemachine
 
// nxt_state decoder
parameter [14:0] idle = 15'b000_0000_0000_0000;
parameter [14:0] start_a = 15'b000_0000_0000_0001;
parameter [14:0] start_b = 15'b000_0000_0000_0010;
parameter [14:0] start_c = 15'b000_0000_0000_0100;
parameter [14:0] start_d = 15'b000_0000_0000_1000;
parameter [14:0] stop_a = 15'b000_0000_0001_0000;
parameter [14:0] stop_b = 15'b000_0000_0010_0000;
parameter [14:0] stop_c = 15'b000_0000_0100_0000;
parameter [14:0] rd_a = 15'b000_0000_1000_0000;
parameter [14:0] rd_b = 15'b000_0001_0000_0000;
parameter [14:0] rd_c = 15'b000_0010_0000_0000;
parameter [14:0] rd_d = 15'b000_0100_0000_0000;
parameter [14:0] wr_a = 15'b000_1000_0000_0000;
parameter [14:0] wr_b = 15'b001_0000_0000_0000;
parameter [14:0] wr_c = 15'b010_0000_0000_0000;
parameter [14:0] wr_d = 15'b100_0000_0000_0000;
parameter [16:0] idle = 17'b0_0000_0000_0000_0000;
parameter [16:0] start_a = 17'b0_0000_0000_0000_0001;
parameter [16:0] start_b = 17'b0_0000_0000_0000_0010;
parameter [16:0] start_c = 17'b0_0000_0000_0000_0100;
parameter [16:0] start_d = 17'b0_0000_0000_0000_1000;
parameter [16:0] start_e = 17'b0_0000_0000_0001_0000;
parameter [16:0] stop_a = 17'b0_0000_0000_0010_0000;
parameter [16:0] stop_b = 17'b0_0000_0000_0100_0000;
parameter [16:0] stop_c = 17'b0_0000_0000_1000_0000;
parameter [16:0] stop_d = 17'b0_0000_0001_0000_0000;
parameter [16:0] rd_a = 17'b0_0000_0010_0000_0000;
parameter [16:0] rd_b = 17'b0_0000_0100_0000_0000;
parameter [16:0] rd_c = 17'b0_0000_1000_0000_0000;
parameter [16:0] rd_d = 17'b0_0001_0000_0000_0000;
parameter [16:0] wr_a = 17'b0_0010_0000_0000_0000;
parameter [16:0] wr_b = 17'b0_0100_0000_0000_0000;
parameter [16:0] wr_c = 17'b0_1000_0000_0000_0000;
parameter [16:0] wr_d = 17'b1_0000_0000_0000_0000;
 
reg [14:0] c_state, nxt_state; // synopsis enum_state
reg [16:0] c_state, nxt_state; // synopsis enum_state
reg icmd_ack, store_sda;
 
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;
always @(c_state or cmd)
begin
nxt_state = c_state;
icmd_ack = 1'b0; // default no command acknowledge
store_sda = 1'b0;
 
`I2C_CMD_STOP:
nxt_state = stop_a;
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_WRITE:
nxt_state = wr_a;
`I2C_CMD_STOP:
nxt_state = stop_a;
 
`I2C_CMD_READ:
nxt_state = rd_a;
`I2C_CMD_WRITE:
nxt_state = wr_a;
 
default:
nxt_state = idle;
`I2C_CMD_READ:
nxt_state = rd_a;
 
endcase
default:
nxt_state = idle;
 
// start
start_a:
nxt_state = start_b;
endcase
 
start_b:
nxt_state = start_c;
// start
start_a:
nxt_state = start_b;
 
start_c:
nxt_state = start_d;
start_b:
nxt_state = start_c;
 
start_d:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
start_c:
nxt_state = start_d;
 
// stop
stop_a:
nxt_state = stop_b;
start_d:
nxt_state = start_e;
 
stop_b:
nxt_state = stop_c;
start_e:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
 
stop_c:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
// stop
stop_a:
nxt_state = stop_b;
 
// read
rd_a:
nxt_state = rd_b;
stop_b:
nxt_state = stop_c;
 
rd_b:
nxt_state = rd_c;
stop_c:
nxt_state = stop_d;
 
rd_c:
begin
nxt_state = rd_d;
store_sda = 1'b1;
end
stop_d:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
 
rd_d:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
// read
rd_a:
nxt_state = rd_b;
 
// write
wr_a:
nxt_state = wr_b;
rd_b:
nxt_state = rd_c;
 
wr_b:
nxt_state = wr_c;
rd_c:
begin
nxt_state = rd_d;
store_sda = 1'b1;
end
 
wr_c:
nxt_state = wr_d;
rd_d:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
 
wr_d:
begin
nxt_state = idle;
icmd_ack = 1'b1;
end
// write
wr_a:
nxt_state = wr_b;
 
endcase
end
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
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
dout <= #1 1'b0;
end
else if (rst)
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
dout <= #1 1'b0;
end
else
begin
if (clk_en)
begin
c_state <= #1 nxt_state;
if(store_sda)
dout <= #1 sSDA;
end
always @(posedge clk or negedge nReset)
if (!nReset)
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
dout <= #1 1'b0;
end
else if (rst)
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
dout <= #1 1'b0;
end
else
begin
if (clk_en)
begin
c_state <= #1 nxt_state;
if (store_sda)
dout <= #1 sSDA;
end
 
cmd_ack <= #1 icmd_ack && clk_en;
end
cmd_ack <= #1 icmd_ack && clk_en;
end
 
//
// convert states to SCL and SDA signals
361,121 → 372,133
assign sda_o = 1'b0;
 
// 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
// 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
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
 
// start
start_a:
begin
scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 1'b1; // set SDA high
end
// 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
 
start_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA high
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_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // set SDA low
end
start_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA high
end
 
start_d:
begin
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b0; // keep SDA low
end
start_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // set SDA low
end
 
// stop
stop_a:
begin
scl_oen <= #1 1'b0; // keep SCL low
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
 
stop_b:
begin
scl_oen <= #1 1'b1; // set 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
 
stop_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1; // set SDA high
end
// stop
stop_a:
begin
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b0; // set SDA low
end
 
//write
wr_a:
begin
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 din; // set SDA
end
stop_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b0; // keep SDA low
end
 
wr_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 din; // keep SDA
end
stop_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
end
 
wr_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 din;
end
stop_d:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1; // set SDA high
end
 
wr_d:
begin
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 din;
end
//write
wr_a:
begin
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 din; // set SDA
end
 
// read
rd_a:
begin
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
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
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
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
 
endcase
rd_b:
begin
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA tri-stated
end
 
rd_c:
begin
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1;
end
 
rd_d:
begin
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b1;
end
 
endcase
 
endmodule
/trunk/rtl/vhdl/i2c_master_bit_ctrl.vhd
37,10 → 37,10
 
-- CVS Log
--
-- $Id: i2c_master_bit_ctrl.vhd,v 1.2 2002-06-15 07:37:04 rherveille Exp $
-- $Id: i2c_master_bit_ctrl.vhd,v 1.3 2002-10-30 18:09:53 rherveille Exp $
--
-- $Date: 2002-06-15 07:37:04 $
-- $Revision: 1.2 $
-- $Date: 2002-10-30 18:09:53 $
-- $Revision: 1.3 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
47,6 → 47,9
--
-- Change History:
-- $Log: not supported by cvs2svn $
-- Revision 1.2 2002/06/15 07:37:04 rherveille
-- Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
--
-- 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.
83,14 → 86,14
-- x | A | B | C | D | i
--
 
-- Timing: Normal mode Fast mode
-- Timing: Normal mode Fast mode
-----------------------------------------------------------------
-- Fscl 100KHz 400KHz
-- Th_scl 4.0us 0.6us High period of SCL
-- Tl_scl 4.7us 1.3us Low period of SCL
-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
-- Fscl 100KHz 400KHz
-- Th_scl 4.0us 0.6us High period of SCL
-- Tl_scl 4.7us 1.3us Low period of SCL
-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
--
 
library ieee;
133,7 → 136,8
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, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
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;
 
signal iscl_oen, isda_oen : std_logic; -- internal I2C lines
148,18 → 152,18
-- synchronize SCL and SDA inputs
synch_scl_sda: process(clk)
begin
if (clk'event and clk = '1') then
sSCL <= scl_i after Tcq;
sSDA <= sda_i after Tcq;
end if;
if (clk'event and clk = '1') then
sSCL <= scl_i after Tcq;
sSDA <= sda_i after Tcq;
end if;
end process synch_SCL_SDA;
 
-- delay scl_oen
process (clk)
begin
if (clk'event and clk = '1') then
dscl_oen <= iscl_oen after Tcq;
end if;
if (clk'event and clk = '1') then
dscl_oen <= iscl_oen after Tcq;
end if;
end process;
 
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
168,177 → 172,180
-- generate clk enable signal
gen_clken: process(clk, nReset)
begin
if (nReset = '0') then
cnt <= (others => '0') after Tcq;
clk_en <= '1' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
cnt <= (others => '0') after Tcq;
clk_en <= '1' after Tcq;
else
if ( (cnt = 0) or (ena = '0') ) then
clk_en <= '1' after Tcq;
cnt <= clk_cnt after Tcq;
else
if (slave_wait = '0') then
cnt <= cnt -1 after Tcq;
end if;
clk_en <= '0' after Tcq;
end if;
end if;
end if;
if (nReset = '0') then
cnt <= (others => '0') after Tcq;
clk_en <= '1' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
cnt <= (others => '0') after Tcq;
clk_en <= '1' after Tcq;
else
if ( (cnt = 0) or (ena = '0') ) then
clk_en <= '1' after Tcq;
cnt <= clk_cnt after Tcq;
else
if (slave_wait = '0') then
cnt <= cnt -1 after Tcq;
end if;
clk_en <= '0' after Tcq;
end if;
end if;
end if;
end process gen_clken;
 
 
-- generate bus status controller
bus_status_ctrl: block
signal dSDA : std_logic;
signal sta_condition : std_logic;
signal sto_condition : std_logic;
signal dSDA : std_logic;
signal sta_condition : std_logic;
signal sto_condition : std_logic;
 
signal ibusy : std_logic;
signal ibusy : std_logic;
begin
-- detect start condition => detect falling edge on SDA while SCL is high
-- detect stop condition => detect rising edge on SDA while SCL is high
detect_sta_sto: process(clk)
begin
if (clk'event and clk = '1') then
dSDA <= sSDA; -- generate a delayed version of sSDA
-- detect start condition => detect falling edge on SDA while SCL is high
-- detect stop condition => detect rising edge on SDA while SCL is high
detect_sta_sto: process(clk)
begin
if (clk'event and clk = '1') then
dSDA <= sSDA; -- generate a delayed version of sSDA
 
sta_condition <= (not sSDA and dSDA) and sSCL;
sto_condition <= (sSDA and not dSDA) and sSCL;
end if;
end process detect_sta_sto;
sta_condition <= (not sSDA and dSDA) and sSCL;
sto_condition <= (sSDA and not dSDA) and sSCL;
end if;
end process detect_sta_sto;
 
-- generate bus busy signal
gen_busy: process(clk, nReset)
begin
if (nReset = '0') then
ibusy <= '0' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
ibusy <= '0' after Tcq;
else
ibusy <= (sta_condition or ibusy) and not sto_condition after Tcq;
end if;
end if;
end process gen_busy;
-- generate bus busy signal
gen_busy: process(clk, nReset)
begin
if (nReset = '0') then
ibusy <= '0' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
ibusy <= '0' after Tcq;
else
ibusy <= (sta_condition or ibusy) and not sto_condition after Tcq;
end if;
end if;
end process gen_busy;
 
-- assign output
busy <= ibusy;
-- assign output
busy <= ibusy;
end block bus_status_ctrl;
 
 
-- generate statemachine
nxt_state_decoder : process (clk, nReset, c_state, cmd)
variable nxt_state : states;
variable icmd_ack, store_sda : std_logic;
variable nxt_state : states;
variable icmd_ack, store_sda : std_logic;
begin
nxt_state := c_state;
 
nxt_state := c_state;
icmd_ack := '0'; -- default no acknowledge
 
icmd_ack := '0'; -- default no acknowledge
store_sda := '0';
 
store_sda := '0';
case (c_state) is
-- idle
when idle =>
case cmd is
when I2C_CMD_START =>
nxt_state := start_a;
 
case (c_state) is
-- idle
when idle =>
case cmd is
when I2C_CMD_START =>
nxt_state := start_a;
when I2C_CMD_STOP =>
nxt_state := stop_a;
 
when I2C_CMD_STOP =>
nxt_state := stop_a;
when I2C_CMD_WRITE =>
nxt_state := wr_a;
 
when I2C_CMD_WRITE =>
nxt_state := wr_a;
when I2C_CMD_READ =>
nxt_state := rd_a;
 
when I2C_CMD_READ =>
nxt_state := rd_a;
when others => -- NOP command
nxt_state := idle;
end case;
 
when others => -- NOP command
nxt_state := idle;
end case;
-- start
when start_a =>
nxt_state := start_b;
 
-- start
when start_a =>
nxt_state := start_b;
when start_b =>
nxt_state := start_c;
 
when start_b =>
nxt_state := start_c;
when start_c =>
nxt_state := start_d;
 
when start_c =>
nxt_state := start_d;
when start_d =>
nxt_state := start_e;
 
when start_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
when start_e =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
-- stop
when stop_a =>
nxt_state := stop_b;
-- stop
when stop_a =>
nxt_state := stop_b;
 
when stop_b =>
nxt_state := stop_c;
when stop_b =>
nxt_state := stop_c;
 
when stop_c =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
when stop_c =>
nxt_state := stop_d;
 
-- read
when rd_a =>
nxt_state := rd_b;
when stop_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
when rd_b =>
nxt_state := rd_c;
-- read
when rd_a =>
nxt_state := rd_b;
 
when rd_c =>
nxt_state := rd_d;
store_sda := '1';
when rd_b =>
nxt_state := rd_c;
 
when rd_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
when rd_c =>
nxt_state := rd_d;
store_sda := '1';
 
-- write
when wr_a =>
nxt_state := wr_b;
when rd_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
when wr_b =>
nxt_state := wr_c;
-- write
when wr_a =>
nxt_state := wr_b;
 
when wr_c =>
nxt_state := wr_d;
when wr_b =>
nxt_state := wr_c;
 
when wr_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
when wr_c =>
nxt_state := wr_d;
 
end case;
when wr_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
-- 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;
else
if (clk_en = '1') then
c_state <= nxt_state after Tcq;
end case;
 
if (store_sda = '1') then
dout <= sSDA after Tcq;
end if;
end if;
-- 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;
 
cmd_ack <= icmd_ack and clk_en;
end if;
end if;
if (store_sda = '1') then
dout <= sSDA after Tcq;
end if;
end if;
 
cmd_ack <= icmd_ack and clk_en;
end if;
end process nxt_state_decoder;
 
--
345,93 → 352,100
-- convert states to SCL and SDA signals
--
output_decoder: process (clk, nReset, c_state, iscl_oen, isda_oen, din)
variable iscl, isda : std_logic;
variable iscl, isda : std_logic;
begin
case (c_state) is
when idle =>
iscl := iscl_oen; -- keep SCL in same state
isda := isda_oen; -- keep SDA in same state
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
-- 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_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- keep SDA high
 
when start_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- sel SDA low
when start_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- set SDA low
 
when start_d =>
iscl := '0'; -- set SCL low
isda := '0'; -- keep SDA low
when start_d =>
iscl := '1'; -- keep SCL high
isda := '0'; -- keep SDA low
 
-- stop
when stop_a =>
iscl := '0'; -- keep SCL disabled
isda := '0'; -- set SDA low
when start_e =>
iscl := '0'; -- set SCL low
isda := '0'; -- keep SDA low
 
when stop_b =>
iscl := '1'; -- set SCL high
isda := '0'; -- keep SDA low
-- stop
when stop_a =>
iscl := '0'; -- keep SCL disabled
isda := '0'; -- set SDA low
 
when stop_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- set SDA high
when stop_b =>
iscl := '1'; -- set SCL high
isda := '0'; -- keep SDA low
 
-- write
when wr_a =>
iscl := '0'; -- keep SCL low
isda := din; -- set SDA
when stop_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- keep SDA low
 
when wr_b =>
iscl := '1'; -- set SCL high
isda := din; -- keep SDA
when stop_d =>
iscl := '1'; -- keep SCL high
isda := '1'; -- set SDA high
 
when wr_c =>
iscl := '1'; -- keep SCL high
isda := din; -- keep SDA
-- write
when wr_a =>
iscl := '0'; -- keep SCL low
isda := din; -- set SDA
 
when wr_d =>
iscl := '0'; -- set SCL low
isda := din; -- keep SDA
when wr_b =>
iscl := '1'; -- set SCL high
isda := din; -- keep SDA
 
-- read
when rd_a =>
iscl := '0'; -- keep SCL low
isda := '1'; -- tri-state SDA
when wr_c =>
iscl := '1'; -- keep SCL high
isda := din; -- keep SDA
 
when rd_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- tri-state SDA
when wr_d =>
iscl := '0'; -- set SCL low
isda := din; -- keep SDA
 
when rd_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- tri-state SDA
-- read
when rd_a =>
iscl := '0'; -- keep SCL low
isda := '1'; -- tri-state SDA
 
when rd_d =>
iscl := '0'; -- set SCL low
isda := '1'; -- tri-state SDA
end case;
when rd_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- tri-state SDA
 
-- 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;
else
if (clk_en = '1') then
iscl_oen <= iscl after Tcq;
isda_oen <= isda after Tcq;
end if;
end if;
end if;
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
/trunk/rtl/vhdl/readme
0,0 → 1,25
 
 
-- This code is provided for free and may be used and --
-- distributed without restriction provided that the --
-- copyright statement is not removed from the file and --
-- that any derivative work contains the original --
-- copyright notice and the associated disclaimer. --
 
-- Comments and suggestions are always welcom --
 
The i2c_master core consists of three files:
 
- i2c_master_top -- top level
- i2c_master_byte_ctrl -- byte controller
- i2c_master_bit_ctrl -- bit controller
 
VHDL needs to be compiled in order. The files are listed
above in descending order.
 
I2C.VHD and tst_ds1621.vhd are not supported anymore.
They remain mostly for historical purposes, altough they
might prove usefull.
 
Richard Herveille
rherveille@opencores.org

powered by: WebSVN 2.1.0

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