From a4ed3c1dd113d94d4c9f3ca631fcc34e7077c80c Mon Sep 17 00:00:00 2001 From: Michael Boehmer Date: Wed, 9 Nov 2022 15:06:09 +0100 Subject: [PATCH] direct I2C access --- interface/i2c_gstart.vhd | 338 +++++++++++++++++++------------------- interface/i2c_sendb.vhd | 340 +++++++++++++++++++-------------------- interface/i2c_slim2.vhd | 158 ++++++++++-------- 3 files changed, 433 insertions(+), 403 deletions(-) diff --git a/interface/i2c_gstart.vhd b/interface/i2c_gstart.vhd index a8b3119..e4316e8 100644 --- a/interface/i2c_gstart.vhd +++ b/interface/i2c_gstart.vhd @@ -8,20 +8,20 @@ use IEEE.STD_LOGIC_UNSIGNED.ALL; entity I2C_GSTART is port( - CLK_IN : in std_logic; - RESET_IN : in std_logic; - START_IN : in std_logic; - DOSTART_IN : in std_logic; - I2C_SPEED_IN : in std_logic_vector(8 downto 0); - SDONE_OUT : out std_logic; - SOK_OUT : out std_logic; - SDA_IN : in std_logic; - SCL_IN : in std_logic; - R_SCL_OUT : out std_logic; - S_SCL_OUT : out std_logic; - R_SDA_OUT : out std_logic; - S_SDA_OUT : out std_logic; - BSM_OUT : out std_logic_vector(3 downto 0) + CLK_IN : in std_logic; + RESET_IN : in std_logic; + START_IN : in std_logic; + DOSTART_IN : in std_logic; + I2C_SPEED_IN : in std_logic_vector(8 downto 0); + SDONE_OUT : out std_logic; + SOK_OUT : out std_logic; + SDA_IN : in std_logic; + SCL_IN : in std_logic; + R_SCL_OUT : out std_logic; + S_SCL_OUT : out std_logic; + R_SDA_OUT : out std_logic; + S_SDA_OUT : out std_logic; + BSM_OUT : out std_logic_vector(3 downto 0) ); end entity; @@ -46,14 +46,14 @@ signal sdone : std_logic; -- Start/Stop done signal sok_x : std_logic; signal sok : std_logic; -- Start/Stop OK -signal r_scl_x : std_logic; -signal r_scl : std_logic; -signal s_scl_x : std_logic; -signal s_scl : std_logic; -signal r_sda_x : std_logic; -signal r_sda : std_logic; -signal s_sda_x : std_logic; -signal s_sda : std_logic; +signal r_scl_x : std_logic; +signal r_scl : std_logic; +signal s_scl_x : std_logic; +signal s_scl : std_logic; +signal r_sda_x : std_logic; +signal r_sda : std_logic; +signal s_sda_x : std_logic; +signal s_sda : std_logic; -- Moduls @@ -62,15 +62,15 @@ begin -- Countdown for one half of SCL (adjustable clock width) THE_CYC_CTR_PROC: process( clk_in ) begin - if( rising_edge(clk_in) ) then - if( reset_in = '1' ) then - cctr <= (others => '0'); - elsif( load_cyc = '1' ) then - cctr <= i2c_speed_in; - elsif( dec_cyc = '1' ) then - cctr <= cctr - 1; - end if; - end if; + if( rising_edge(clk_in) ) then + if( reset_in = '1' ) then + cctr <= (others => '0'); + elsif( load_cyc = '1' ) then + cctr <= i2c_speed_in; + elsif( dec_cyc = '1' ) then + cctr <= cctr - 1; + end if; + end if; end process THE_CYC_CTR_PROC; -- end of cycle recognition @@ -80,154 +80,154 @@ cycdone_x <= '1' when (cctr = x"00") else '0'; -- State memory process STATE_MEM: process( clk_in ) begin - if ( rising_edge(clk_in) ) then - if( reset_in = '1' ) then - CURRENT_STATE <= SLEEP; - load_cyc <= '0'; - dec_cyc <= '0'; - sdone <= '0'; - sok <= '0'; - cycdone <= '0'; - r_scl <= '0'; - s_scl <= '0'; - r_sda <= '0'; - s_sda <= '0'; - else - CURRENT_STATE <= NEXT_STATE; - load_cyc <= load_cyc_x; - dec_cyc <= dec_cyc_x; - sdone <= sdone_x; - sok <= sok_x; - cycdone <= cycdone_x; - r_scl <= r_scl_x; - s_scl <= s_scl_x; - r_sda <= r_sda_x; - s_sda <= s_sda_x; - end if; - end if; + if ( rising_edge(clk_in) ) then + if( reset_in = '1' ) then + CURRENT_STATE <= SLEEP; + load_cyc <= '0'; + dec_cyc <= '0'; + sdone <= '0'; + sok <= '0'; + cycdone <= '0'; + r_scl <= '0'; + s_scl <= '0'; + r_sda <= '0'; + s_sda <= '0'; + else + CURRENT_STATE <= NEXT_STATE; + load_cyc <= load_cyc_x; + dec_cyc <= dec_cyc_x; + sdone <= sdone_x; + sok <= sok_x; + cycdone <= cycdone_x; + r_scl <= r_scl_x; + s_scl <= s_scl_x; + r_sda <= r_sda_x; + s_sda <= s_sda_x; + end if; + end if; end process STATE_MEM; -- Transition matrix TRANSFORM: process(CURRENT_STATE, dostart_in, start_in, sda_in, scl_in, cycdone) begin - NEXT_STATE <= SLEEP; - load_cyc_x <= '0'; - dec_cyc_x <= '0'; - sdone_x <= '0'; - sok_x <= '1'; - r_sda_x <= '0'; - s_sda_x <= '0'; - r_scl_x <= '0'; - s_scl_x <= '0'; - case CURRENT_STATE is - when SLEEP => - if ( (dostart_in = '1') and (start_in = '1') ) then - NEXT_STATE <= S_CHK0; -- generate a start condition - load_cyc_x <= '1'; - elsif( (dostart_in = '1') and (start_in = '0') ) then - NEXT_STATE <= WCTR2; -- generate a stop condition - load_cyc_x <= '1'; - else - NEXT_STATE <= SLEEP; --- load_cyc_x <= '1'; - end if; - when WCTR2 => - if( (cycdone = '1') ) then - NEXT_STATE <= P_SCL; - load_cyc_x <= '1'; - s_scl_x <= '1'; - else - NEXT_STATE <= WCTR2; - dec_cyc_x <= '1'; - end if; - when P_SCL => - NEXT_STATE <= WCTR0; - dec_cyc_x <= '1'; - when S_CHK0 => - if( (sda_in = '1') and (scl_in = '1') ) then - NEXT_STATE <= RS_SDA; - r_sda_x <= '1'; - else - NEXT_STATE <= ERROR; - sok_x <= '0'; - end if; - when RS_SDA => - NEXT_STATE <= WCTR0; - dec_cyc_x <= '1'; - when WCTR0 => - if ( (cycdone = '1') and (start_in = '1') ) then - NEXT_STATE <= S_CHK1; - elsif( (cycdone = '1') and (start_in = '0') ) then - NEXT_STATE <= P_SDA; - load_cyc_x <= '1'; - s_sda_x <= '1'; - else - NEXT_STATE <= WCTR0; - dec_cyc_x <= '1'; - end if; - when S_CHK1 => - if( (sda_in = '0') and (scl_in = '1') ) then - NEXT_STATE <= DONE; - else - NEXT_STATE <= ERROR; - sok_x <= '0'; - end if; - when P_SDA => - NEXT_STATE <= WCTR1; - dec_cyc_x <= '1'; - when WCTR1 => - if( (cycdone = '1') ) then - NEXT_STATE <= P_CHK; - else - NEXT_STATE <= WCTR1; - dec_cyc_x <= '1'; - end if; - when P_CHK => - if( (sda_in = '1') and (scl_in = '1') ) then - NEXT_STATE <= DONE; - sdone_x <= '1'; - else - NEXT_STATE <= ERROR; - sok_x <= '0'; - end if; - when ERROR => - if( dostart_in = '0' ) then - NEXT_STATE <= SLEEP; - else - NEXT_STATE <= ERROR; - sdone_x <= '1'; - sok_x <= '0'; - end if; - when DONE => - if( dostart_in = '0' ) then - NEXT_STATE <= SLEEP; - else - NEXT_STATE <= DONE; - sdone_x <= '1'; - end if; - when others => - NEXT_STATE <= SLEEP; - end case; + NEXT_STATE <= SLEEP; + load_cyc_x <= '0'; + dec_cyc_x <= '0'; + sdone_x <= '0'; + sok_x <= '1'; + r_sda_x <= '0'; + s_sda_x <= '0'; + r_scl_x <= '0'; + s_scl_x <= '0'; + case CURRENT_STATE is + when SLEEP => + if ( (dostart_in = '1') and (start_in = '1') ) then + NEXT_STATE <= S_CHK0; -- generate a start condition + load_cyc_x <= '1'; + elsif( (dostart_in = '1') and (start_in = '0') ) then + NEXT_STATE <= WCTR2; -- generate a stop condition + load_cyc_x <= '1'; + else + NEXT_STATE <= SLEEP; +-- load_cyc_x <= '1'; + end if; + when WCTR2 => + if( (cycdone = '1') ) then + NEXT_STATE <= P_SCL; + load_cyc_x <= '1'; + s_scl_x <= '1'; + else + NEXT_STATE <= WCTR2; + dec_cyc_x <= '1'; + end if; + when P_SCL => + NEXT_STATE <= WCTR0; + dec_cyc_x <= '1'; + when S_CHK0 => + if( (sda_in = '1') and (scl_in = '1') ) then + NEXT_STATE <= RS_SDA; + r_sda_x <= '1'; + else + NEXT_STATE <= ERROR; + sok_x <= '0'; + end if; + when RS_SDA => + NEXT_STATE <= WCTR0; + dec_cyc_x <= '1'; + when WCTR0 => + if ( (cycdone = '1') and (start_in = '1') ) then + NEXT_STATE <= S_CHK1; + elsif( (cycdone = '1') and (start_in = '0') ) then + NEXT_STATE <= P_SDA; + load_cyc_x <= '1'; + s_sda_x <= '1'; + else + NEXT_STATE <= WCTR0; + dec_cyc_x <= '1'; + end if; + when S_CHK1 => + if( (sda_in = '0') and (scl_in = '1') ) then + NEXT_STATE <= DONE; + else + NEXT_STATE <= ERROR; + sok_x <= '0'; + end if; + when P_SDA => + NEXT_STATE <= WCTR1; + dec_cyc_x <= '1'; + when WCTR1 => + if( (cycdone = '1') ) then + NEXT_STATE <= P_CHK; + else + NEXT_STATE <= WCTR1; + dec_cyc_x <= '1'; + end if; + when P_CHK => + if( (sda_in = '1') and (scl_in = '1') ) then + NEXT_STATE <= DONE; + sdone_x <= '1'; + else + NEXT_STATE <= ERROR; + sok_x <= '0'; + end if; + when ERROR => + if( dostart_in = '0' ) then + NEXT_STATE <= SLEEP; + else + NEXT_STATE <= ERROR; + sdone_x <= '1'; + sok_x <= '0'; + end if; + when DONE => + if( dostart_in = '0' ) then + NEXT_STATE <= SLEEP; + else + NEXT_STATE <= DONE; + sdone_x <= '1'; + end if; + when others => + NEXT_STATE <= SLEEP; + end case; end process TRANSFORM; -- Output decoding DECODE: process(CURRENT_STATE) begin - case CURRENT_STATE is - when SLEEP => bsm <= x"0"; - when S_CHK0 => bsm <= x"1"; - when RS_SDA => bsm <= x"2"; - when P_SCL => bsm <= x"3"; - when WCTR0 => bsm <= x"4"; - when S_CHK1 => bsm <= x"5"; - when P_SDA => bsm <= x"6"; - when WCTR1 => bsm <= x"7"; - when P_CHK => bsm <= x"8"; - when DONE => bsm <= x"9"; - when WCTR2 => bsm <= x"a"; - when ERROR => bsm <= x"e"; - when others => bsm <= x"f"; - end case; + case CURRENT_STATE is + when SLEEP => bsm <= x"0"; + when S_CHK0 => bsm <= x"1"; + when RS_SDA => bsm <= x"2"; + when P_SCL => bsm <= x"3"; + when WCTR0 => bsm <= x"4"; + when S_CHK1 => bsm <= x"5"; + when P_SDA => bsm <= x"6"; + when WCTR1 => bsm <= x"7"; + when P_CHK => bsm <= x"8"; + when DONE => bsm <= x"9"; + when WCTR2 => bsm <= x"a"; + when ERROR => bsm <= x"e"; + when others => bsm <= x"f"; + end case; end process DECODE; -- Outputs diff --git a/interface/i2c_sendb.vhd b/interface/i2c_sendb.vhd index be4e338..6adf91e 100644 --- a/interface/i2c_sendb.vhd +++ b/interface/i2c_sendb.vhd @@ -5,21 +5,21 @@ use IEEE.STD_LOGIC_UNSIGNED.ALL; entity i2c_sendb is port( - CLK_IN : in std_logic; - RESET_IN : in std_logic; - DOBYTE_IN : in std_logic; - I2C_SPEED_IN : in std_logic_vector(8 downto 0); - I2C_BYTE_IN : in std_logic_vector(8 downto 0); - I2C_BACK_OUT : out std_logic_vector(8 downto 0); - SDA_IN : in std_logic; - R_SDA_OUT : out std_logic; - S_SDA_OUT : out std_logic; + CLK_IN : in std_logic; + RESET_IN : in std_logic; + DOBYTE_IN : in std_logic; + I2C_SPEED_IN : in std_logic_vector(8 downto 0); + I2C_BYTE_IN : in std_logic_vector(8 downto 0); + I2C_BACK_OUT : out std_logic_vector(8 downto 0); + SDA_IN : in std_logic; + R_SDA_OUT : out std_logic; + S_SDA_OUT : out std_logic; -- SCL_IN : in std_logic; - R_SCL_OUT : out std_logic; - S_SCL_OUT : out std_logic; - BDONE_OUT : out std_logic; - BOK_OUT : out std_logic; - BSM_OUT : out std_logic_vector(3 downto 0) + R_SCL_OUT : out std_logic; + S_SCL_OUT : out std_logic; + BDONE_OUT : out std_logic; + BOK_OUT : out std_logic; + BSM_OUT : out std_logic_vector(3 downto 0) ); end entity; @@ -72,15 +72,15 @@ begin -- Bit counter (for byte to send) THE_BIT_CTR_PROC: process( clk_in ) begin - if( rising_edge(clk_in) ) then - if( reset_in = '1' ) then - bctr <= (others => '0'); - elsif( rst_bit = '1' ) then - bctr <= (others => '0'); - elsif( inc_bit = '1' ) then - bctr <= bctr + 1; - end if; - end if; + if( rising_edge(clk_in) ) then + if( reset_in = '1' ) then + bctr <= (others => '0'); + elsif( rst_bit = '1' ) then + bctr <= (others => '0'); + elsif( inc_bit = '1' ) then + bctr <= bctr + 1; + end if; + end if; end process THE_BIT_CTR_PROC; -- end of byte recognition @@ -89,15 +89,15 @@ bytedone <= '1' when (bctr = x"9") else '0'; -- Countdown for one half of SCL (adjustable clock width) THE_CYC_CTR_PROC: process( clk_in ) begin - if( rising_edge(clk_in) ) then - if( reset_in = '1' ) then - cctr <= (others => '0'); - elsif( load_cyc = '1' ) then - cctr <= i2c_speed_in; - elsif( dec_cyc = '1' ) then - cctr <= cctr - 1; - end if; - end if; + if( rising_edge(clk_in) ) then + if( reset_in = '1' ) then + cctr <= (others => '0'); + elsif( load_cyc = '1' ) then + cctr <= i2c_speed_in; + elsif( dec_cyc = '1' ) then + cctr <= cctr - 1; + end if; + end if; end process THE_CYC_CTR_PROC; -- end of cycle recognition @@ -106,44 +106,44 @@ cycdone <= '1' when (cctr = x"00") else '0'; -- Bit output THE_BIT_OUT_PROC: process( clk_in ) begin - if( rising_edge(clk_in) ) then - if( reset_in = '1' ) then - out_sr <= (others => '0'); - i2c_d <= '1'; - elsif( load_sr = '1' ) then - out_sr <= i2c_byte_in; - i2c_d <= '1'; - elsif( shift_o = '1' ) then - i2c_d <= out_sr(8); - out_sr(8 downto 0) <= out_sr(7 downto 0) & '0'; - end if; - end if; + if( rising_edge(clk_in) ) then + if( reset_in = '1' ) then + out_sr <= (others => '0'); + i2c_d <= '1'; + elsif( load_sr = '1' ) then + out_sr <= i2c_byte_in; + i2c_d <= '1'; + elsif( shift_o = '1' ) then + i2c_d <= out_sr(8); + out_sr(8 downto 0) <= out_sr(7 downto 0) & '0'; + end if; + end if; end process THE_BIT_OUT_PROC; -- Bit input THE_BIT_IN_PROC: process( clk_in ) begin - if( rising_edge(clk_in) ) then - if ( reset_in = '1' ) then - in_sr <= (others => '1'); - elsif( shift_o = '1' ) then - in_sr(8 downto 1) <= in_sr(7 downto 0); - in_sr(0) <= sda_in; - end if; - end if; + if( rising_edge(clk_in) ) then + if ( reset_in = '1' ) then + in_sr <= (others => '1'); + elsif( shift_o = '1' ) then + in_sr(8 downto 1) <= in_sr(7 downto 0); + in_sr(0) <= sda_in; + end if; + end if; end process THE_BIT_IN_PROC; -- Output register for readback data (could be reduced to SR_IN_INT) THE_I2C_BACK_PROC: process( clk_in ) begin - if( rising_edge(clk_in) ) then - if( reset_in = '1' ) then - i2c_back <= (others => '1'); - elsif( shift_i = '1' ) then - i2c_back(8 downto 1) <= in_sr(7 downto 0); - i2c_back(0) <= sda_in; - end if; - end if; + if( rising_edge(clk_in) ) then + if( reset_in = '1' ) then + i2c_back <= (others => '1'); + elsif( shift_i = '1' ) then + i2c_back(8 downto 1) <= in_sr(7 downto 0); + i2c_back(0) <= sda_in; + end if; + end if; end process THE_I2C_BACK_PROC; -- ByteOK is the inverted ACK bit from readback data. @@ -153,131 +153,131 @@ bok <= not i2c_back(0); -- BUG -- State memory process STATE_MEM: process( clk_in ) begin - if( rising_edge(clk_in) ) then - if( reset_in = '1') then - CURRENT_STATE <= SLEEP; - inc_bit <= '0'; - rst_bit <= '0'; - load_cyc <= '0'; - dec_cyc <= '0'; - load_sr <= '0'; - shift_o <= '0'; - shift_i <= '0'; - bdone <= '0'; - r_scl <= '0'; - s_scl <= '0'; - else - CURRENT_STATE <= NEXT_STATE; - inc_bit <= inc_bit_x; - rst_bit <= rst_bit_x; - load_cyc <= load_cyc_x; - dec_cyc <= dec_cyc_x; - load_sr <= load_sr_x; - shift_o <= shift_o_x; - shift_i <= shift_i_x; - bdone <= bdone_x; - r_scl <= r_scl_x; - s_scl <= s_scl_x; - end if; - end if; + if( rising_edge(clk_in) ) then + if( reset_in = '1') then + CURRENT_STATE <= SLEEP; + inc_bit <= '0'; + rst_bit <= '0'; + load_cyc <= '0'; + dec_cyc <= '0'; + load_sr <= '0'; + shift_o <= '0'; + shift_i <= '0'; + bdone <= '0'; + r_scl <= '0'; + s_scl <= '0'; + else + CURRENT_STATE <= NEXT_STATE; + inc_bit <= inc_bit_x; + rst_bit <= rst_bit_x; + load_cyc <= load_cyc_x; + dec_cyc <= dec_cyc_x; + load_sr <= load_sr_x; + shift_o <= shift_o_x; + shift_i <= shift_i_x; + bdone <= bdone_x; + r_scl <= r_scl_x; + s_scl <= s_scl_x; + end if; + end if; end process STATE_MEM; -- Transition matrix TRANSFORM: process(CURRENT_STATE, dobyte_in, cycdone, bytedone) begin - NEXT_STATE <= SLEEP; - inc_bit_x <= '0'; - rst_bit_x <= '0'; - load_cyc_x <= '0'; - dec_cyc_x <= '0'; - load_sr_x <= '0'; - shift_o_x <= '0'; - shift_i_x <= '0'; - bdone_x <= '0'; - r_scl_x <= '0'; - s_scl_x <= '0'; - case CURRENT_STATE is - when SLEEP => if( dobyte_in = '1' ) then - NEXT_STATE <= LCL; - inc_bit_x <= '1'; - load_cyc_x <= '1'; - shift_o_x <= '1'; - r_scl_x <= '1'; - else - NEXT_STATE <= SLEEP; - load_sr_x <= '1'; - end if; - when LCL => NEXT_STATE <= WCL; - dec_cyc_x <= '1'; - when WCL => if( cycdone = '1' ) then - NEXT_STATE <= LCH; - load_cyc_x <= '1'; - s_scl_x <= '1'; - else - NEXT_STATE <= WCL; - dec_cyc_x <= '1'; - end if; - when LCH => NEXT_STATE <= WCH; - dec_cyc_x <= '1'; - when WCH => if ( (cycdone = '1') and (bytedone = '0') ) then - NEXT_STATE <= LCL; - inc_bit_x <= '1'; - load_cyc_x <= '1'; - shift_o_x <= '1'; - r_scl_x <= '1'; - elsif( (cycdone = '1') and (bytedone = '1') ) then - NEXT_STATE <= FREE; - shift_o_x <= '1'; - shift_i_x <= '1'; - r_scl_x <= '1'; - else - NEXT_STATE <= WCH; - dec_cyc_x <= '1'; - end if; - when FREE => NEXT_STATE <= DONE; - rst_bit_x <= '1'; - bdone_x <= '1'; - when DONE => if( dobyte_in = '0' ) then - NEXT_STATE <= SLEEP; - else - NEXT_STATE <= DONE; - rst_bit_x <= '1'; - bdone_x <= '1'; - end if; - -- Just in case... - when others => NEXT_STATE <= SLEEP; - end case; + NEXT_STATE <= SLEEP; + inc_bit_x <= '0'; + rst_bit_x <= '0'; + load_cyc_x <= '0'; + dec_cyc_x <= '0'; + load_sr_x <= '0'; + shift_o_x <= '0'; + shift_i_x <= '0'; + bdone_x <= '0'; + r_scl_x <= '0'; + s_scl_x <= '0'; + case CURRENT_STATE is + when SLEEP => if( dobyte_in = '1' ) then + NEXT_STATE <= LCL; + inc_bit_x <= '1'; + load_cyc_x <= '1'; + shift_o_x <= '1'; + r_scl_x <= '1'; + else + NEXT_STATE <= SLEEP; + load_sr_x <= '1'; + end if; + when LCL => NEXT_STATE <= WCL; + dec_cyc_x <= '1'; + when WCL => if( cycdone = '1' ) then + NEXT_STATE <= LCH; + load_cyc_x <= '1'; + s_scl_x <= '1'; + else + NEXT_STATE <= WCL; + dec_cyc_x <= '1'; + end if; + when LCH => NEXT_STATE <= WCH; + dec_cyc_x <= '1'; + when WCH => if ( (cycdone = '1') and (bytedone = '0') ) then + NEXT_STATE <= LCL; + inc_bit_x <= '1'; + load_cyc_x <= '1'; + shift_o_x <= '1'; + r_scl_x <= '1'; + elsif( (cycdone = '1') and (bytedone = '1') ) then + NEXT_STATE <= FREE; + shift_o_x <= '1'; + shift_i_x <= '1'; + r_scl_x <= '1'; + else + NEXT_STATE <= WCH; + dec_cyc_x <= '1'; + end if; + when FREE => NEXT_STATE <= DONE; + rst_bit_x <= '1'; + bdone_x <= '1'; + when DONE => if( dobyte_in = '0' ) then + NEXT_STATE <= SLEEP; + else + NEXT_STATE <= DONE; + rst_bit_x <= '1'; + bdone_x <= '1'; + end if; + -- Just in case... + when others => NEXT_STATE <= SLEEP; + end case; end process TRANSFORM; -- Output decoding DECODE: process(CURRENT_STATE) begin - case CURRENT_STATE is - when SLEEP => bsm <= x"0"; - when LCL => bsm <= x"1"; - when WCL => bsm <= x"2"; - when LCH => bsm <= x"3"; - when WCH => bsm <= x"4"; - when FREE => bsm <= x"5"; - when DONE => bsm <= x"6"; - when others => bsm <= x"f"; - end case; + case CURRENT_STATE is + when SLEEP => bsm <= x"0"; + when LCL => bsm <= x"1"; + when WCL => bsm <= x"2"; + when LCH => bsm <= x"3"; + when WCH => bsm <= x"4"; + when FREE => bsm <= x"5"; + when DONE => bsm <= x"6"; + when others => bsm <= x"f"; + end case; end process DECODE; -- SCL and SDA output pulses THE_SDA_OUT_PROC: process( clk_in ) begin - if( rising_edge(clk_in) ) then - if( reset_in = '1' ) then - load <= '0'; -- was a bug, found 081008 - r_sda <= '0'; - s_sda <= '0'; - else - load <= shift_o; - r_sda <= load and not i2c_d; - s_sda <= load and i2c_d; - end if; - end if; + if( rising_edge(clk_in) ) then + if( reset_in = '1' ) then + load <= '0'; -- was a bug, found 081008 + r_sda <= '0'; + s_sda <= '0'; + else + load <= shift_o; + r_sda <= load and not i2c_d; + s_sda <= load and i2c_d; + end if; + end if; end process THE_SDA_OUT_PROC; -- Outputs diff --git a/interface/i2c_slim2.vhd b/interface/i2c_slim2.vhd index 249c351..568b1aa 100644 --- a/interface/i2c_slim2.vhd +++ b/interface/i2c_slim2.vhd @@ -11,6 +11,7 @@ port( I2C_GO_IN : in std_logic; -- startbit to trigger I2C actions ACTION_IN : in std_logic; -- '0' -> write, '1' -> read WORD_IN : in std_logic; -- '0' -> byte, '1' -> word + DIRECT_IN : in std_logic; -- '0' -> normal access, '1' -> direct read I2C_SPEED_IN : in std_logic_vector(5 downto 0); -- speed adjustment (to be defined) I2C_ADDR_IN : in std_logic_vector(7 downto 0); -- I2C address byte (R/W bit is ignored) I2C_CMD_IN : in std_logic_vector(7 downto 0); -- I2C command byte (sent after address byte) @@ -26,7 +27,7 @@ port( SCL_IN : in std_logic; SCL_OUT : out std_logic; -- Debug - BSM_OUT : out std_logic_vector(4 downto 0) + BSM_OUT : out std_logic_vector(3 downto 0) ); end entity i2c_slim2; @@ -37,7 +38,7 @@ type STATES is (SLEEP, LOADA, GSTART, SENDA, LOADC, SENDC, LOADD, SENDD, GSTOP, INC, DONE, FAILED, LOADD2, SENDD2); signal CURRENT_STATE, NEXT_STATE: STATES; -signal bsm : std_logic_vector( 4 downto 0 ); +signal bsm : std_logic_vector(3 downto 0); signal phase : std_logic; -- '0' => first phase, '1' => second phase of read cycle signal start_x : std_logic; @@ -57,6 +58,8 @@ signal load_dh_x : std_logic; signal load_dh : std_logic; signal load_dl_x : std_logic; signal load_dl : std_logic; +signal clr_data_x : std_logic; +signal clr_data : std_logic; signal sdone : std_logic; -- acknowledge signal from GenStart module signal sok : std_logic; -- status signal from GenStart module @@ -140,7 +143,7 @@ begin end process THE_SYNC_PROC; -- lower limit of speed -i2c_speed <= i2c_speed_in & "000"; +i2c_speed <= i2c_speed_in & b"010"; -- Read phase indicator THE_PHASE_PROC: process( CLOCK ) @@ -148,7 +151,7 @@ begin if( rising_edge(CLOCK) ) then if( RESET = '1' ) then phase <= '0'; - elsif( CURRENT_STATE = INC ) then + elsif( (CURRENT_STATE = INC) ) then phase <= '1'; elsif( (CURRENT_STATE = DONE) or (CURRENT_STATE = SLEEP) ) then phase <= '0'; @@ -166,44 +169,48 @@ begin start <= '0'; dostart <= '0'; dobyte <= '0'; - i2c_done <= '0'; running <= '0'; load_dh <= '0'; load_dl <= '0'; + clr_data <= '1'; valid <= '0'; + i2c_done <= '0'; else CURRENT_STATE <= NEXT_STATE; start <= start_x; dostart <= dostart_x; dobyte <= dobyte_x; - i2c_done <= i2c_done_x; running <= running_x; load_dh <= load_dh_x; load_dl <= load_dl_x; + clr_data <= clr_data_x; valid <= valid_x; + i2c_done <= i2c_done_x; end if; end if; end process STATE_MEM; -- Transition matrix -TRANSFORM: process(CURRENT_STATE, i2c_go_in, sdone, sok, phase, bdone, bok, action_in, word_in) +TRANSFORM: process(CURRENT_STATE, I2C_GO_IN, sdone, sok, phase, bdone, bok, ACTION_IN, WORD_IN) begin NEXT_STATE <= SLEEP; start_x <= '0'; dostart_x <= '0'; dobyte_x <= '0'; - i2c_done_x <= '0'; running_x <= '1'; load_dh_x <= '0'; load_dl_x <= '0'; + clr_data_x <= '0'; valid_x <= '0'; + i2c_done_x <= '0'; errors_x <= x"00"; save_x <= '0'; case CURRENT_STATE is when SLEEP => - if( i2c_go_in = '1' ) then + if( I2C_GO_IN = '1' ) then NEXT_STATE <= LOADA; save_x <= '1'; + clr_data_x <= '1'; else NEXT_STATE <= SLEEP; running_x <= '0'; @@ -232,12 +239,22 @@ begin dostart_x <= '1'; end if; when SENDA => - if ( (bdone = '1') and (bok = '1') and (action_in = '0') ) then - NEXT_STATE <= LOADC; -- I2C write, send command - elsif( (bdone = '1') and (bok = '1') and (action_in = '1') and (phase = '0') ) then - NEXT_STATE <= LOADC; -- I2C read, send command - elsif( (bdone = '1') and (bok = '1') and (action_in = '1') and (phase = '1') ) then - NEXT_STATE <= LOADD; -- I2C read, send 0xff dummy byte + if ( (bdone = '1') and (bok = '1') and (ACTION_IN = '0') and (DIRECT_IN = '0') ) then + NEXT_STATE <= LOADC; -- I2C normal write + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '1') and (DIRECT_IN = '0') and (phase = '0') ) then + NEXT_STATE <= LOADC; -- I2C normal read, address stage (same for byte and word) + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '1') and (phase = '1') and (WORD_IN = '0') ) then + NEXT_STATE <= LOADD2; -- I2C normal read (byte), data stage + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '1') and (phase = '1') and (WORD_IN = '1') ) then + NEXT_STATE <= LOADD; -- I2C normal read (word), data stage + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '0') and (DIRECT_IN = '1') and (WORD_IN = '0') ) then + NEXT_STATE <= LOADD2; -- I2C direct write (byte) + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '0') and (DIRECT_IN = '1') and (WORD_IN = '1') ) then + NEXT_STATE <= LOADD; -- I2C direct write (word) + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '1') and (DIRECT_IN = '1') and (WORD_IN = '0') ) then + NEXT_STATE <= LOADD2; -- I2C direct read (byte) + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '1') and (DIRECT_IN = '1') and (WORD_IN = '1') ) then + NEXT_STATE <= LOADD; -- I2C direct read (word) elsif( (bdone = '1') and (bok = '0') and (phase = '0') ) then NEXT_STATE <= FAILED; -- first address phase failed errors_x <= x"20"; @@ -255,11 +272,11 @@ begin when LOADC => NEXT_STATE <= SENDC; when SENDC => - if ( (bdone = '1') and (bok = '1') and (action_in = '0') and (word_in = '0') ) then + if ( (bdone = '1') and (bok = '1') and (ACTION_IN = '0') and (WORD_IN = '0') ) then NEXT_STATE <= LOADD2; -- I2C byte write, prepare data - elsif( (bdone = '1') and (bok = '1') and (action_in = '0') and (word_in = '1') ) then + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '0') and (WORD_IN = '1') ) then NEXT_STATE <= LOADD; -- I2C word write, prepare data - elsif( (bdone = '1') and (bok = '1') and (action_in = '1') ) then + elsif( (bdone = '1') and (bok = '1') and (ACTION_IN = '1') ) then NEXT_STATE <= GSTOP; -- I2C read, first phase ends dostart_x <= '1'; elsif( (bdone = '1') and (bok = '0') ) then @@ -274,19 +291,12 @@ begin when LOADD => NEXT_STATE <= SENDD; when SENDD => - if ( (bdone = '1') and (bok = '1') and (action_in = '0') and (word_in = '0') ) then - NEXT_STATE <= GSTOP; -- I2C write, byte access, done - dostart_x <= '1'; - elsif( (bdone = '1') and (bok = '1') and (action_in = '0') and (word_in = '1') ) then - NEXT_STATE <= LOADD2; -- I2C write, word access, last byte to send - elsif( (bdone = '1') and (action_in = '1') and (word_in = '0') ) then - NEXT_STATE <= GSTOP; -- I2C read, byte access, data phase - dostart_x <= '1'; - load_dl_x <= '1'; - elsif( (bdone = '1') and (action_in = '1') and (word_in = '1') ) then + if ( (bdone = '1') and (bok = '1') and (ACTION_IN = '0') ) then + NEXT_STATE <= LOADD2; -- I2C write, word access, last byte to send + elsif( (bdone = '1') and (ACTION_IN = '1') ) then NEXT_STATE <= LOADD2; -- I2C read, word access, last byte to receive load_dh_x <= '1'; - elsif( (bdone = '1') and (bok = '0') and (action_in = '0') ) then + elsif( (bdone = '1') and (bok = '0') and (ACTION_IN = '0') ) then NEXT_STATE <= FAILED; -- I2C write, first data phase failed errors_x <= x"04"; save_x <= '1'; @@ -298,14 +308,14 @@ begin when LOADD2 => NEXT_STATE <= SENDD2; when SENDD2 => - if ( (bdone = '1') and (bok = '1') and (action_in = '0') ) then + if ( (bdone = '1') and (bok = '1') and (ACTION_IN = '0') ) then NEXT_STATE <= GSTOP; -- I2C write, done dostart_x <= '1'; - elsif( (bdone = '1') and (action_in = '1') ) then + elsif( (bdone = '1') and (ACTION_IN = '1') ) then NEXT_STATE <= GSTOP; -- I2C read, data phase dostart_x <= '1'; load_dl_x <= '1'; - elsif( (bdone = '1') and (bok = '0') and (action_in = '0') ) then + elsif( (bdone = '1') and (bok = '0') and (ACTION_IN = '0') ) then NEXT_STATE <= FAILED; -- I2C write, data phase failed errors_x <= x"02"; save_x <= '1'; @@ -315,16 +325,20 @@ begin dobyte_x <= '1'; end if; when GSTOP => - if ( (sdone = '1') and (action_in = '0') ) then + if ( (sdone = '1') and (ACTION_IN = '0') ) then NEXT_STATE <= DONE; i2c_done_x <= '1'; valid_x <= '1'; - elsif( (sdone = '1') and (action_in = '1') and (phase = '1') ) then + elsif( (sdone = '1') and (ACTION_IN = '1') and (phase = '1') ) then NEXT_STATE <= DONE; i2c_done_x <= '1'; valid_x <= '1'; - elsif( (sdone = '1') and (action_in = '1') and (phase = '0') ) then + elsif( (sdone = '1') and (ACTION_IN = '1') and (phase = '0') and (DIRECT_IN = '0') ) then NEXT_STATE <= INC; + elsif( (sdone = '1') and (ACTION_IN = '1') and (DIRECT_IN = '1') ) then + NEXT_STATE <= DONE; + i2c_done_x <= '1'; + valid_x <= '1'; else NEXT_STATE <= GSTOP; dostart_x <= '1'; @@ -332,6 +346,7 @@ begin when INC => NEXT_STATE <= LOADA; when FAILED => + -- emergency STOP condition to correctly free the bus if( sdone = '1' ) then NEXT_STATE <= DONE; i2c_done_x <= '1'; @@ -365,50 +380,65 @@ begin end if; end process THE_ERROR_PROC; +---- DONE bit: set by FSM completion, cleared by start of FSM +--THE_DONE_PROC: process( CLOCK ) +--begin +-- if( rising_edge(CLOCK) ) then +-- if ( RESET = '1' ) then +-- i2c_done <= '0'; +-- elsif( CURRENT_STATE = LOADA ) then +-- i2c_done <= '0'; +-- elsif( CURRENT_STATE = DONE ) then +-- i2c_done <= '1'; +-- end if; +-- end if; +--end process THE_DONE_PROC; + -- Output decoding DECODE: process(CURRENT_STATE) begin case CURRENT_STATE is - when SLEEP => bsm <= b"00000"; -- 00 - when LOADA => bsm <= b"00001"; -- 01 - when GSTART => bsm <= b"00010"; -- 02 - when SENDA => bsm <= b"00011"; -- 03 - when LOADC => bsm <= b"00100"; -- 04 - when SENDC => bsm <= b"00101"; -- 05 - when LOADD => bsm <= b"00110"; -- 06 - when SENDD => bsm <= b"00111"; -- 07 - when GSTOP => bsm <= b"01000"; -- 08 - when INC => bsm <= b"01001"; -- 09 - when FAILED => bsm <= b"01010"; -- 0a - when DONE => bsm <= b"01011"; -- 0b - when LOADD2 => bsm <= b"01100"; -- 0c - when SENDD2 => bsm <= b"01101"; -- 0d - when others => bsm <= b"11111"; -- 1f + when SLEEP => bsm <= b"0000"; -- 0 + when LOADA => bsm <= b"0001"; -- 1 + when GSTART => bsm <= b"0010"; -- 2 + when SENDA => bsm <= b"0011"; -- 3 + when LOADC => bsm <= b"0100"; -- 4 + when SENDC => bsm <= b"0101"; -- 5 + when LOADD => bsm <= b"0110"; -- 6 + when SENDD => bsm <= b"0111"; -- 7 + when GSTOP => bsm <= b"1000"; -- 8 + when INC => bsm <= b"1001"; -- 9 + when FAILED => bsm <= b"1010"; -- a + when DONE => bsm <= b"1011"; -- b + when LOADD2 => bsm <= b"1100"; -- c + when SENDD2 => bsm <= b"1101"; -- d + when others => bsm <= b"1111"; -- f end case; end process DECODE; -- We need to load different data sets ---LOAD_DATA_PROC: process( CLOCK, RESET, CURRENT_STATE, action_in, phase) LOAD_DATA_PROC: process( CLOCK ) begin if( rising_edge(CLOCK) ) then if ( RESET = '1' ) then i2c_byte <= (others => '1'); - elsif( (CURRENT_STATE = LOADA) and (phase = '0') ) then + elsif( (CURRENT_STATE = LOADA) and (phase = '0') and (DIRECT_IN = '0') ) then i2c_byte <= i2c_addr_in(7 downto 1) & '0' & '1'; -- send write address, receive ACK + elsif( (CURRENT_STATE = LOADA) and (phase = '0') and (DIRECT_IN = '1') and (ACTION_IN = '0') ) then + i2c_byte <= i2c_addr_in(7 downto 1) & '0' & '1'; -- send write address, receive ACK + elsif( (CURRENT_STATE = LOADA) and (phase = '0') and (DIRECT_IN = '1') and (ACTION_IN = '1') ) then + i2c_byte <= i2c_addr_in(7 downto 1) & '1' & '1'; -- send read address, receive ACK elsif( (CURRENT_STATE = LOADA) and (phase = '1') ) then i2c_byte <= i2c_addr_in(7 downto 1) & '1' & '1'; -- send read address, receive ACK - elsif( (CURRENT_STATE = LOADC) and (action_in = '0') ) then - i2c_byte <= i2c_cmd_in(7 downto 0) & '1'; -- send command byte (WRITE), receive ACK - elsif( (CURRENT_STATE = LOADC) and (action_in = '1') ) then - i2c_byte <= i2c_cmd_in(7 downto 0) & '1'; -- send command byte (READ), receive ACK - elsif( (CURRENT_STATE = LOADD) and (action_in = '0') ) then + elsif( (CURRENT_STATE = LOADC) ) then + i2c_byte <= i2c_cmd_in(7 downto 0) & '1'; -- send command byte (read/write), receive ACK + elsif( (CURRENT_STATE = LOADD) and (ACTION_IN = '0') ) then i2c_byte <= i2c_dw_in(15 downto 8) & '1'; -- send data byte, receive ACK - elsif( (CURRENT_STATE = LOADD2) and (action_in = '0') ) then + elsif( (CURRENT_STATE = LOADD2) and (ACTION_IN = '0') ) then i2c_byte <= i2c_dw_in(7 downto 0) & '1'; -- send data byte, receive ACK - elsif( (CURRENT_STATE = LOADD) and (action_in = '1') ) then + elsif( (CURRENT_STATE = LOADD) and (ACTION_IN = '1') ) then i2c_byte <= x"ff" & '0'; -- send 0xff byte, send ACK - elsif( (CURRENT_STATE = LOADD2) and (action_in = '1') ) then + elsif( (CURRENT_STATE = LOADD2) and (ACTION_IN = '1') ) then i2c_byte <= x"ff" & '1'; -- send 0xff byte, send NACK end if; end if; @@ -490,8 +520,8 @@ end process THE_SDA_PROC; THE_STORE_READ_H_PROC: process( CLOCK ) begin if( rising_edge(CLOCK) ) then - if ( RESET = '1' ) then - i2c_drw(15 downto 8) <= (others => '0'); + if ( clr_data = '1' ) then + i2c_drw(15 downto 8) <= (others => '1'); elsif( rising_edge(CLOCK) ) then if( load_dh = '1' ) then i2c_drw(15 downto 8) <= i2c_dr(8 downto 1); @@ -504,8 +534,8 @@ end process THE_STORE_READ_H_PROC; THE_STORE_READ_L_PROC: process( CLOCK ) begin if( rising_edge(CLOCK) ) then - if ( RESET = '1' ) then - i2c_drw(7 downto 0) <= (others => '0'); + if ( clr_data = '1' ) then + i2c_drw(7 downto 0) <= (others => '1'); elsif( rising_edge(CLOCK) ) then if( load_dl = '1' ) then i2c_drw(7 downto 0) <= i2c_dr(8 downto 1); -- 2.43.0