4) detect start/stop condition
START- falling edge on SDA while SCL is high; STOP - rising edge on SDA while SCL is high
1 -- block 2 signal sta_condition : std_logic; -- start detected 3 signal sto_condition : std_logic; -- stop detected 4 5 detect_sta_sto: process(clk, nRst) 6 begin 7 if (nRst = '0') then 8 sta_condition <= '0'; 9 sto_condition <= '0'; 10 elsif (clk'event and clk = '1') then 11 if (rst = '1') then 12 sta_condition <= '0'; 13 sto_condition <= '0'; 14 else 15 sta_condition <= (not sSDA and dSDA) and sSCL; 16 sto_condition <= (sSDA and not dSDA) and sSCL; 17 end if; 18 end if; 19 end process detect_sta_sto;
5) generate i2c-bus busy signal
1 -- port 2 busy : out std_logic; -- i2c bus busy 3 4 -- architecture 5 signal ibusy : std_logic; -- internal busy signal 6 7 gen_busy: process(clk, nRst) 8 begin 9 if (nRst = '0') then 10 ibusy <= '0'; 11 elsif (clk'event and clk = '1') then 12 if (rst = '1') then 13 ibusy <= '0'; 14 else 15 ibusy <= (sta_condition or ibusy) and not sto_condition; 16 end if; 17 end if; 18 end process gen_busy; 19 20 busy <= ibusy;
6) generate arbitration lost signal
0 -- port
1 al : out std_logic; -- arbitration lost
1 -- architecture 2 constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000"; 3 constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001"; 4 constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010"; 5 constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100"; 6 constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000"; 7 8 signal ial : std_logic; -- internal arbitration lost signal 9 signal sda_chk : std_logic; -- check SDA status (multi-master arbitration) 10 11 -- block 12 signal cmd_stop : std_logic; -- STOP command 13 14 -- aribitration lost when: 15 -- 1) master drives SDA high, but the i2c bus is low 16 -- 2) stop detected while not requested (detect during 'idle' state) 17 gen_al: process(clk, nRst) 18 begin 19 if (nRst = '0') then 20 cmd_stop <= '0'; 21 ial <= '0'; 22 elsif (clk'event and clk = '1') then 23 if (rst = '1') then 24 cmd_stop <= '0'; 25 ial <= '0'; 26 else 27 if (clk_en = '1') then 28 if (cmd = I2C_CMD_STOP) then 29 cmd_stop <= '1'; 30 else 31 cmd_stop <= '0'; 32 end if; 33 end if; 34 35 if (c_state = idle) then 36 ial <= (sda_chk and not sSDA and isda_oen) or (sto_condition and not cmd_stop); 37 else 38 ial <= (sda_chk and not sSDA and isda_oen); 39 end if; 40 end if; 41 end if; 42 end process gen_al; 43 al <= ial;
7) generate dout signal
1 -- store dout on rising edge of SCL 2 gen_dout: process(clk, nReset) 3 begin 4 if (nReset = '0') then 5 dout <= '0'; 6 elsif (clk'event and clk = '1') then 7 if (sSCL = '1' and dSCL = '0') then 8 dout <= sSDA; 9 end if; 10 end if; 11 end process gen_dout; 12 end block bus_status_ctrl;