URL
https://opencores.org/ocsvn/i2c/i2c/trunk
Subversion Repositories i2c
Compare Revisions
- This comparison shows the changes necessary to convert path
/i2c/trunk
- from Rev 72 to Rev 71
- ↔ Reverse comparison
Rev 72 → Rev 71
/rtl/vhdl/i2c_master_bit_ctrl.vhd
110,24 → 110,24
-- Each command has 5 states, A/B/C/D/idle |
-- |
-- start: SCL ~~~~~~~~~~~~~~\____ |
-- SDA XX/~~~~~~~\______ |
-- x | A | B | C | D | i |
-- SDA XX/~~~~~~~\______ |
-- x | A | B | C | D | i |
-- |
-- repstart SCL ______/~~~~~~~\___ |
-- SDA __/~~~~~~~\______ |
-- x | A | B | C | D | i |
-- SDA __/~~~~~~~\______ |
-- x | A | B | C | D | i |
-- |
-- stop SCL _______/~~~~~~~~~~~ |
-- SDA ==\___________/~~~~~ |
-- x | A | B | C | D | i |
-- SDA ==\___________/~~~~~ |
-- x | A | B | C | D | i |
-- |
--- write SCL ______/~~~~~~~\____ |
-- SDA XXX===============XX |
-- x | A | B | C | D | i |
-- SDA XXX===============XX |
-- x | A | B | C | D | i |
-- |
--- read SCL ______/~~~~~~~\____ |
-- SDA XXXXXXX=XXXXXXXXXXX |
-- x | A | B | C | D | i |
-- SDA XXXXXXX=XXXXXXXXXXX |
-- x | A | B | C | D | i |
-- |
|
-- Timing: Normal mode Fast mode |
142,433 → 142,376
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
use ieee.std_logic_arith.all; |
|
entity i2c_master_bit_ctrl is |
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; -- command completed |
busy : out std_logic; -- i2c bus busy |
al : out std_logic; -- arbitration lost |
cmd : in std_logic_vector(3 downto 0); |
cmd_ack : out std_logic; -- command completed |
busy : out std_logic; -- i2c bus busy |
al : out std_logic; -- arbitration lost |
|
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 entity i2c_master_bit_ctrl; |
|
architecture structural of i2c_master_bit_ctrl is |
constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000"; |
constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001"; |
constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010"; |
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100"; |
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000"; |
constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000"; |
constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001"; |
constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010"; |
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, |
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; |
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 |
signal sda_chk : std_logic; -- check SDA status (multi-master arbitration) |
signal dscl_oen : std_logic; -- delayed scl_oen signals |
signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs |
signal dSCL, dSDA : std_logic; -- delayed versions ofsSCL and sSDA |
signal clk_en : std_logic; -- statemachine clock enable |
signal scl_sync, slave_wait : std_logic; -- clock generation signals |
signal ial : std_logic; -- internal arbitration lost signal |
signal cnt : unsigned(15 downto 0); -- clock divider counter (synthesis) |
signal iscl_oen, isda_oen : std_logic; -- internal I2C lines |
signal sda_chk : std_logic; -- check SDA status (multi-master arbitration) |
signal dscl_oen : std_logic; -- delayed scl_oen signals |
signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs |
signal dSCL, dSDA : std_logic; -- delayed versions ofsSCL and sSDA |
signal clk_en : std_logic; -- statemachine clock enable |
signal scl_sync, slave_wait : std_logic; -- clock generation signals |
signal ial : std_logic; -- internal arbitration lost signal |
-- signal cnt : unsigned(15 downto 0) := clk_cnt; -- clock divider counter (simulation) |
signal cnt : unsigned(15 downto 0); -- clock divider counter (synthesis) |
|
begin |
-- whenever the slave is not ready it can delay the cycle by pulling SCL low |
-- delay scl_oen |
process (clk, nReset) |
begin |
if (nReset = '0') then |
dscl_oen <= '0'; |
elsif (clk'event and clk = '1') then |
dscl_oen <= iscl_oen; |
end if; |
end process; |
-- whenever the slave is not ready it can delay the cycle by pulling SCL low |
-- delay scl_oen |
process (clk) |
begin |
if (clk'event and clk = '1') then |
dscl_oen <= iscl_oen; |
end if; |
end process; |
|
-- slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low |
-- slave_wait remains asserted until the slave releases SCL |
process (clk, nReset) |
begin |
if (nReset = '0') then |
slave_wait <= '0'; |
elsif (clk'event and clk = '1') then |
slave_wait <= (iscl_oen and not dscl_oen and not sSCL) or (slave_wait and not sSCL); |
end if; |
end process; |
-- slave_wait is asserted when master wants to drive SCL high, but the slave (another master) pulls it low |
-- slave_wait remains asserted until the slave (other master) releases SCL |
process (clk, nReset) |
begin |
if (nReset = '0') then |
slave_wait <= '0'; |
elsif (clk'event and clk = '1') then |
slave_wait <= (iscl_oen and not dscl_oen and not sSCL) or (slave_wait and not sSCL); |
end if; |
end process; |
|
-- master drives SCL high, but another master pulls it low |
-- master start counting down its low cycle now (clock synchronization) |
scl_sync <= dSCL and not sSCL and iscl_oen; |
-- master drives SCL high, but another master pulls it low |
-- master start counting down its low cycle now (clock synchronization) |
scl_sync <= dSCL and not sSCL and iscl_oen; |
|
-- generate clk enable signal |
gen_clken: process(clk, nReset) |
begin |
if (nReset = '0') then |
cnt <= (others => '0'); |
clk_en <= '1'; |
elsif (clk'event and clk = '1') then |
if ((rst = '1') or (cnt = 0) or (ena = '0') or (scl_sync = '1')) then |
cnt <= clk_cnt; |
clk_en <= '1'; |
elsif (slave_wait = '1') then |
cnt <= cnt; |
clk_en <= '0'; |
else |
cnt <= cnt -1; |
clk_en <= '0'; |
end if; |
end if; |
end process gen_clken; |
-- generate clk enable signal |
gen_clken: process(clk, nReset) |
begin |
if (nReset = '0') then |
cnt <= (others => '0'); |
clk_en <= '1'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
cnt <= (others => '0'); |
clk_en <= '1'; |
elsif ( (cnt = 0) or (ena = '0') or (scl_sync = '1') ) then |
cnt <= clk_cnt; |
clk_en <= '1'; |
elsif (slave_wait = '1') then |
cnt <= cnt; |
clk_en <= '0'; |
else |
cnt <= cnt -1; |
clk_en <= '0'; |
end if; |
end if; |
end process gen_clken; |
|
|
-- generate bus status controller |
bus_status_ctrl: block |
signal cSCL, cSDA : std_logic_vector( 1 downto 0); -- capture SDA and SCL |
signal fSCL, fSDA : std_logic_vector( 2 downto 0); -- filter inputs for SCL and SDA |
signal filter_cnt : unsigned(13 downto 0); -- clock divider for filter |
signal sta_condition : std_logic; -- start detected |
signal sto_condition : std_logic; -- stop detected |
signal cmd_stop : std_logic; -- STOP command |
signal ibusy : std_logic; -- internal busy signal |
begin |
-- capture SCL and SDA |
capture_scl_sda: process(clk, nReset) |
begin |
if (nReset = '0') then |
cSCL <= "00"; |
cSDA <= "00"; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
cSCL <= "00"; |
cSDA <= "00"; |
else |
cSCL <= (cSCL(0) & scl_i); |
cSDA <= (cSDA(0) & sda_i); |
end if; |
end if; |
end process capture_scl_sda; |
-- generate bus status controller |
bus_status_ctrl: block |
signal sta_condition : std_logic; -- start detected |
signal sto_condition : std_logic; -- stop detected |
signal cmd_stop : std_logic; -- STOP command |
signal ibusy : std_logic; -- internal busy signal |
begin |
-- synchronize SCL and SDA inputs |
synch_scl_sda: process(clk, nReset) |
begin |
if (nReset = '0') then |
sSCL <= '1'; |
sSDA <= '1'; |
|
-- filter SCL and SDA; (attempt to) remove glitches |
filter_divider: process(clk, nReset) |
begin |
if (nReset = '0') then |
filter_cnt <= (others => '0'); |
elsif (clk'event and clk = '1') then |
if ((rst = '1') or (filter_cnt = 0)) then |
filter_cnt <= clk_cnt(15 downto 2); |
else |
filter_cnt <= filter_cnt -1; |
end if; |
end if; |
end process filter_divider; |
dSCL <= '1'; |
dSDA <= '1'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
sSCL <= '1'; |
sSDA <= '1'; |
|
filter_scl_sda: process(clk, nReset) |
begin |
if (nReset = '0') then |
fSCL <= (others => '1'); |
fSDA <= (others => '1'); |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
fSCL <= (others => '1'); |
fSDA <= (others => '1'); |
elsif (filter_cnt = 0) then |
fSCL <= (fSCL(1 downto 0) & cSCL(1)); |
fSDA <= (fSDA(1 downto 0) & cSDA(1)); |
end if; |
end if; |
end process filter_scl_sda; |
dSCL <= '1'; |
dSDA <= '1'; |
else |
sSCL <= scl_i; |
sSDA <= sda_i; |
|
-- generate filtered SCL and SDA signals |
scl_sda: process(clk, nReset) |
begin |
if (nReset = '0') then |
sSCL <= '1'; |
sSDA <= '1'; |
dSCL <= sSCL; |
dSDA <= sSDA; |
end if; |
end if; |
end process synch_SCL_SDA; |
|
dSCL <= '1'; |
dSDA <= '1'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
sSCL <= '1'; |
sSDA <= '1'; |
-- 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, nReset) |
begin |
if (nReset = '0') then |
sta_condition <= '0'; |
sto_condition <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
sta_condition <= '0'; |
sto_condition <= '0'; |
else |
sta_condition <= (not sSDA and dSDA) and sSCL; |
sto_condition <= (sSDA and not dSDA) and sSCL; |
end if; |
end if; |
end process detect_sta_sto; |
|
dSCL <= '1'; |
dSDA <= '1'; |
else |
sSCL <= (fSCL(2) and fSCL(1)) or |
(fSCL(2) and fSCL(0)) or |
(fSCL(1) and fSCL(0)); |
sSDA <= (fSDA(2) and fSDA(1)) or |
(fSDA(2) and fSDA(0)) or |
(fSCL(1) and fSCL(0)); |
-- generate i2c-bus busy signal |
gen_busy: process(clk, nReset) |
begin |
if (nReset = '0') then |
ibusy <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
ibusy <= '0'; |
else |
ibusy <= (sta_condition or ibusy) and not sto_condition; |
end if; |
end if; |
end process gen_busy; |
busy <= ibusy; |
|
dSCL <= sSCL; |
dSDA <= sSDA; |
end if; |
end if; |
end process scl_sda; |
|
-- generate arbitration lost signal |
-- aribitration lost when: |
-- 1) master drives SDA high, but the i2c bus is low |
-- 2) stop detected while not requested (detect during 'idle' state) |
gen_al: process(clk, nReset) |
begin |
if (nReset = '0') then |
cmd_stop <= '0'; |
ial <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
cmd_stop <= '0'; |
ial <= '0'; |
else |
if (clk_en = '1') then |
if (cmd = I2C_CMD_STOP) then |
cmd_stop <= '1'; |
else |
cmd_stop <= '0'; |
end if; |
end if; |
|
-- 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, nReset) |
begin |
if (nReset = '0') then |
sta_condition <= '0'; |
sto_condition <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
sta_condition <= '0'; |
sto_condition <= '0'; |
else |
sta_condition <= (not sSDA and dSDA) and sSCL; |
sto_condition <= (sSDA and not dSDA) and sSCL; |
end if; |
end if; |
end process detect_sta_sto; |
if (c_state = idle) then |
ial <= (sda_chk and not sSDA and isda_oen); |
else |
ial <= (sda_chk and not sSDA and isda_oen) or (sto_condition and not cmd_stop); |
end if; |
|
end if; |
end if; |
end process gen_al; |
al <= ial; |
|
-- generate i2c-bus busy signal |
gen_busy: process(clk, nReset) |
begin |
if (nReset = '0') then |
ibusy <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
ibusy <= '0'; |
else |
ibusy <= (sta_condition or ibusy) and not sto_condition; |
end if; |
end if; |
end process gen_busy; |
busy <= ibusy; |
-- generate dout signal, store dout on rising edge of SCL |
gen_dout: process(clk) |
begin |
if (clk'event and clk = '1') then |
if (sSCL = '1' and dSCL = '0') then |
dout <= sSDA; |
end if; |
end if; |
end process gen_dout; |
end block bus_status_ctrl; |
|
|
-- generate arbitration lost signal |
-- aribitration lost when: |
-- 1) master drives SDA high, but the i2c bus is low |
-- 2) stop detected while not requested (detect during 'idle' state) |
gen_al: process(clk, nReset) |
begin |
if (nReset = '0') then |
cmd_stop <= '0'; |
ial <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
cmd_stop <= '0'; |
ial <= '0'; |
else |
if (clk_en = '1') then |
if (cmd = I2C_CMD_STOP) then |
cmd_stop <= '1'; |
else |
cmd_stop <= '0'; |
end if; |
end if; |
-- generate statemachine |
nxt_state_decoder : process (clk, nReset, c_state, cmd) |
begin |
if (nReset = '0') then |
c_state <= idle; |
cmd_ack <= '0'; |
iscl_oen <= '1'; |
isda_oen <= '1'; |
sda_chk <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1' or ial = '1') then |
c_state <= idle; |
cmd_ack <= '0'; |
iscl_oen <= '1'; |
isda_oen <= '1'; |
sda_chk <= '0'; |
else |
cmd_ack <= '0'; -- default no acknowledge |
|
if (c_state = idle) then |
ial <= (sda_chk and not sSDA and isda_oen) or (sto_condition and not cmd_stop); |
else |
ial <= (sda_chk and not sSDA and isda_oen); |
end if; |
end if; |
end if; |
end process gen_al; |
al <= ial; |
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; |
|
iscl_oen <= iscl_oen; -- keep SCL in same state |
isda_oen <= isda_oen; -- keep SDA in same state |
sda_chk <= '0'; -- don't check SDA |
|
-- generate dout signal, store dout on rising edge of SCL |
gen_dout: process(clk, nReset) |
begin |
if (nReset = '0') then |
dout <= '0'; |
elsif (clk'event and clk = '1') then |
if (sSCL = '1' and dSCL = '0') then |
dout <= sSDA; |
end if; |
end if; |
end process gen_dout; |
end block bus_status_ctrl; |
-- 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 |
sda_chk <= '0'; -- don't check SDA |
|
when start_b => |
c_state <= start_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '1'; -- keep SDA high |
sda_chk <= '0'; -- don't check SDA |
|
-- generate statemachine |
nxt_state_decoder : process (clk, nReset) |
begin |
if (nReset = '0') then |
c_state <= idle; |
cmd_ack <= '0'; |
iscl_oen <= '1'; |
isda_oen <= '1'; |
sda_chk <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1' or ial = '1') then |
c_state <= idle; |
cmd_ack <= '0'; |
iscl_oen <= '1'; |
isda_oen <= '1'; |
sda_chk <= '0'; |
else |
cmd_ack <= '0'; -- default no acknowledge |
when start_c => |
c_state <= start_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- set SDA low |
sda_chk <= '0'; -- don't check SDA |
|
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; |
when start_d => |
c_state <= start_e; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
|
iscl_oen <= iscl_oen; -- keep SCL in same state |
isda_oen <= isda_oen; -- keep SDA in same state |
sda_chk <= '0'; -- don't check SDA |
when start_e => |
c_state <= idle; |
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
|
-- 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 |
sda_chk <= '0'; -- don't check SDA |
-- stop |
when stop_a => |
c_state <= stop_b; |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= '0'; -- set SDA low |
sda_chk <= '0'; -- don't check SDA |
|
when start_b => |
c_state <= start_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '1'; -- keep SDA high |
sda_chk <= '0'; -- don't check SDA |
when stop_b => |
c_state <= stop_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
|
when start_c => |
c_state <= start_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- set SDA low |
sda_chk <= '0'; -- don't check SDA |
when stop_c => |
c_state <= stop_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
|
when start_d => |
c_state <= start_e; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
when stop_d => |
c_state <= idle; |
cmd_ack <= '1'; -- command completed |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '1'; -- set SDA high |
sda_chk <= '0'; -- don't check SDA |
|
when start_e => |
c_state <= idle; |
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
-- read |
when rd_a => |
c_state <= rd_b; |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
|
-- stop |
when stop_a => |
c_state <= stop_b; |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= '0'; -- set SDA low |
sda_chk <= '0'; -- don't check SDA |
when rd_b => |
c_state <= rd_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
|
when stop_b => |
c_state <= stop_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
when rd_c => |
c_state <= rd_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
|
when stop_c => |
c_state <= stop_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
when rd_d => |
c_state <= idle; |
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
|
when stop_d => |
c_state <= idle; |
cmd_ack <= '1'; -- command completed |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '1'; -- set SDA high |
sda_chk <= '0'; -- don't check SDA |
-- write |
when wr_a => |
c_state <= wr_b; |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= din; -- set SDA |
sda_chk <= '0'; -- don't check SDA (SCL low) |
|
-- read |
when rd_a => |
c_state <= rd_b; |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
when wr_b => |
c_state <= wr_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= din; -- keep SDA |
sda_chk <= '1'; -- check SDA |
|
when rd_b => |
c_state <= rd_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
when wr_c => |
c_state <= wr_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= din; -- keep SDA |
sda_chk <= '1'; -- check SDA |
|
when rd_c => |
c_state <= rd_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
when wr_d => |
c_state <= idle; |
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= din; -- keep SDA |
sda_chk <= '0'; -- don't check SDA (SCL low) |
|
when rd_d => |
c_state <= idle; |
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
when others => |
|
-- write |
when wr_a => |
c_state <= wr_b; |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= din; -- set SDA |
sda_chk <= '0'; -- don't check SDA (SCL low) |
end case; |
end if; |
end if; |
end if; |
end process nxt_state_decoder; |
|
when wr_b => |
c_state <= wr_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= din; -- keep SDA |
sda_chk <= '0'; -- don't check SDA yet |
-- Allow some more time for SDA and SCL to settle |
|
when wr_c => |
c_state <= wr_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= din; -- keep SDA |
sda_chk <= '1'; -- check SDA |
|
when wr_d => |
c_state <= idle; |
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= din; -- keep SDA |
sda_chk <= '0'; -- don't check SDA (SCL low) |
|
when others => |
|
end case; |
end if; |
end if; |
end if; |
end process nxt_state_decoder; |
|
|
-- assign outputs |
scl_o <= '0'; |
scl_oen <= iscl_oen; |
sda_o <= '0'; |
sda_oen <= isda_oen; |
-- assign outputs |
scl_o <= '0'; |
scl_oen <= iscl_oen; |
sda_o <= '0'; |
sda_oen <= isda_oen; |
end architecture structural; |
|