From b1782ac316569ec9ac073cf36035aecd680c62cd Mon Sep 17 00:00:00 2001 From: matt Date: Tue, 4 Aug 2020 02:13:00 +0700 Subject: [PATCH] Fixed PSE I2C for read only, not tested --- sim_switcher_pkg.vhd | 35 +++++ sim_switcher_top.vhd | 344 ++++++++++++++++++++++++++----------------- 2 files changed, 247 insertions(+), 132 deletions(-) diff --git a/sim_switcher_pkg.vhd b/sim_switcher_pkg.vhd index 121e009..59f9fd7 100644 --- a/sim_switcher_pkg.vhd +++ b/sim_switcher_pkg.vhd @@ -22,6 +22,27 @@ package sim_switcher_pkg is ); end component sim_mux; + component i2c_master IS + generic ( + input_clk : integer := 50_000_000; --input clock speed from user logic in Hz + bus_clk : integer := 400_000 --speed the i2c bus (scl) will run at in Hz + ); + port ( + clk : in std_logic; --system clock + reset_n : in std_logic; --active low reset + ena : in std_logic; --latch in command + addr : in std_logic_vector(6 downto 0); --address of target slave + rw : in std_logic; --'0' is write, '1' is read + data_wr : in std_logic_vector(7 downto 0); --data to write to slave + busy : out std_logic; --indicates transaction in progress + data_rd : out std_logic_vector(7 downto 0); --data read from slave + ack_error : buffer std_logic; --flag if improper acknowledge from slave + sda : inout std_logic; --serial data output of i2c bus + scl : inout std_logic; --serial clock output of i2c bus + scl_invert: in std_logic --true if need to invert output SCL signal + ); + end component i2c_master; + component i2c_slave is generic ( SLAVE_ADDR : std_logic_vector(6 downto 0) @@ -39,6 +60,20 @@ package sim_switcher_pkg is ); end component i2c_slave; + component i2c_repeater is + generic ( + WAIT_CYCLES : integer := 3 + ); + port ( + clk : in std_logic; + rstn : in std_logic; + pr_scl : inout std_logic; + pr_sda : inout std_logic; + sec_scl : inout std_logic; + sec_sda : inout std_logic + ); + end component i2c_repeater; + component odio_repeater is generic ( WAIT_CYCLES : integer := 3 diff --git a/sim_switcher_top.vhd b/sim_switcher_top.vhd index aae32b6..72cac6b 100644 --- a/sim_switcher_top.vhd +++ b/sim_switcher_top.vhd @@ -106,20 +106,24 @@ architecture rtl of sim_switcher_top is ); end component; - constant FLASHES : natural := 5; -- Number of LED flashes on boot + constant FLASHES : natural := 5; -- Number of LED flashes on boot constant CPU_RST_DURATION : natural := 100_000_000; -- 25_000_000 = 1sec - constant PON_RST_DURATION : natural := 10; -- 25_000_000 = 1sec - constant PON_CPU_DELAY_DURATION : natural := 75_000_000; -- 25_000_000 = 1sec - constant SB_CONF_UPDATE_INTERVAL : natural := 25_000_000; -- 25_000_000 = 1sec + constant PON_RST_DURATION : natural := 10; -- 25_000_000 = 1sec + constant PON_CPU_DELAY_DURATION : natural := 75_000_000; -- 25_000_000 = 1sec + constant SB_CONF_UPDATE_INTERVAL : natural := 25_000_000; -- 25_000_000 = 1sec - constant DEBOUNCING_WAIT_CYCLES : natural := 3; -- Number of debouncing wait cycles - constant REPI2C_DEBOUNCING_WAIT_CYCLES : natural := 3; -- Number of debouncing wait cycles - constant EXPIO_DEBOUNCING_WAIT_CYCLES : natural := 25; -- Number of debouncing wait cycles + constant DEBOUNCING_WAIT_CYCLES : natural := 3; -- Number of debouncing wait cycles + constant REPI2C_DEBOUNCING_WAIT_CYCLES : natural := 3; -- Number of debouncing wait cycles + constant EXPIO_DEBOUNCING_WAIT_CYCLES : natural := 25; -- Number of debouncing wait cycles - constant I2C_CLK : natural := 400_000; -- speed the i2c bus (scl) will run at in Hz + constant I2C_CLK : natural := 400_000; -- speed the i2c bus (scl) will run at in Hz constant I2C_MAX_WAIT : natural := 2_500_000; -- 25_000_000 = 1sec + constant PSE_I2C_ADDR : std_logic_vector(6 downto 0) := "0100000"; -- 0x20 + constant PSE_REG_NUM : natural := 8; + constant PSE_POLL_INTERVAL : natural := 25_000_000; -- 25_000_000 = 1sec + signal s_clk_i : std_logic; -- clock buffer signal s_rstn_i : std_logic; -- reset signal signal s_rst_i : std_logic; -- reset signal @@ -217,6 +221,25 @@ architecture rtl of sim_switcher_top is -- SIM-MODEM switching register signal reg_sim_modemnum: arr_modnum_t(0 to 7); + -- PSE regs and control signals + type arr_regs_t is array (natural range <>) of std_logic_vector(7 downto 0); + signal pse_regs_to_read, pse_regs_value: arr_regs_t(0 to PSE_REG_NUM-1); + + type i2c_pse_fsm_t is (ready, i2c_trn_start, i2c_trn_main, i2c_wr_wait, i2c_rd_wait, wait_ack); + signal i2c_state : i2c_pse_fsm_t := ready; + + signal s_i2c_data_wr : std_logic_vector(7 downto 0); + signal s_i2c_data_rd : std_logic_vector(7 downto 0); + signal s_i2c_txn_start : std_logic; + signal s_i2c_rw_flag : std_logic; + signal s_i2c_busy_flag : std_logic; + signal i2c_busy_prev : std_logic; + signal i2c_core_start : std_logic; + signal i2c_core_busy : std_logic; + signal i2c_wr_done : std_logic; + signal reg_i2c_trn_dir : std_logic; + signal wait_i2c_start : std_logic; + begin -- Interrupt output routing @@ -251,143 +274,168 @@ begin reg_pse_status(0) <= pse_vpwr_pg; -- Connect PSE I2C bus to main I2C bus - -- inst_i2c_master: i2c_master - -- generic map ( - -- input_clk => SYSFREQ, - -- bus_clk => I2C_CLK - -- ) - -- port map ( - -- clk => clk25_i, - -- reset_n => s_rstn_i, - -- ena => s_i2c_txn_start, - -- addr => x"20", - -- rw => s_i2c_rw_flag, - -- data_wr => s_i2c_data_wr, - -- busy => s_i2c_busy_flag, - -- data_rd => s_i2c_data_rd, - -- ack_error => open, - -- sda => pse_i2c_sda_io, - -- scl => pse_i2c_scl_io, - -- scl_invert => '0' - -- ); + inst_i2c_master: i2c_master + generic map ( + input_clk => SYSFREQ, + bus_clk => I2C_CLK + ) + port map ( + clk => clk25_i, + reset_n => s_rstn_i, + ena => s_i2c_txn_start, + addr => PSE_I2C_ADDR, + rw => s_i2c_rw_flag, + data_wr => s_i2c_data_wr, + busy => s_i2c_busy_flag, + data_rd => s_i2c_data_rd, + ack_error => open, + sda => pse_i2c_sda_io, + scl => pse_i2c_scl_io, + scl_invert => '0' + ); - -- -- PSE I2C interaction process - -- pse_i2c_proc: process (clk_i, rstn_i) - -- variable data_wr_cnt : natural := 0; - -- variable data_rd_cnt : natural := 0; - -- begin - -- if (rstn_i = '0') then - -- i2c_state <= ready; - -- i2c_core_busy <= '0'; - -- i2c_busy_prev <= (others => '0'); - -- i2c_ram_we <= (others => '0'); - -- i2c_wr_done <= '0'; + -- SIM attach reset assigment: default is 1-to-1 SIM to MODEM connection + pse_regs_to_read <= ( + 0 => x"0C", -- RO + 1 => x"0D", -- RO + 2 => x"0E", -- RO + 3 => x"0F", -- RO + 4 => x"10", -- RO + 5 => x"12", -- R/W + 6 => x"13", -- R/W + 7 => x"14" -- R/W + ); - -- elsif (rising_edge(clk_i)) then - -- case i2c_state is - -- when ready => - -- if (i2c_core_start = '1') then - -- i2c_state <= i2c_trn_start; - -- i2c_core_busy <= '1'; - -- data_wr_cnt := 0; - -- data_rd_cnt := 0; - -- spi_ram_raddr <= data_wr_cnt; -- Request data from RAM + ------------------------------ + -- PSE read trigger process -- + ------------------------------ + pse_readtrig_proc: process(clk25_i, s_rstn_i, wait_i2c_start, i2c_core_busy) is + variable wait_cnt : natural := 0; + begin + if (s_rstn_i = '0') then + wait_i2c_start <= '0'; + elsif (rising_edge(clk25_i)) then + if (wait_i2c_start = '1') then + if (i2c_core_busy = '1') then + wait_i2c_start <= '0'; + end if; + else + if (i2c_core_start = '1' and i2c_core_busy = '0') then + i2c_core_start <= '0'; + elsif (wait_cnt > PSE_POLL_INTERVAL) then + wait_cnt := 0; + wait_i2c_start <= '1'; + i2c_core_start <= '1'; + end if; + wait_cnt := wait_cnt + 1; + end if; + end if; + end process; - -- i2c_busy_prev <= (i2c_busy_prev'range => '0'); - -- end if; + -- PSE I2C interaction process + pse_i2c_proc: process (clk25_i, s_rstn_i) + variable reg_num_rd : natural := 0; + begin + if (s_rstn_i = '0') then + pse_regs_value <= ( + 0 => x"00", + 1 => x"00", + 2 => x"00", + 3 => x"00", + 4 => x"00", + 5 => x"00", + 6 => x"00", + 7 => x"00" + ); + i2c_state <= ready; + i2c_core_busy <= '0'; + i2c_busy_prev <= '0'; + i2c_wr_done <= '0'; + reg_num_rd := 0; - -- when i2c_trn_start => - -- i2c_txn_start_o <= reg_i2c_mask; -- Initiate the transaction - -- i2c_slv_addr_o <= (others => reg_i2c_addr); -- Set the address of the slave - -- i2c_rw_flag_o <= (others => '0'); -- First byte is always write - -- i2c_data_wr_o <= (others => spi_ram_data_o); -- Data to be written - -- i2c_state <= i2c_trn_main; + elsif (rising_edge(clk25_i)) then + case i2c_state is + when ready => + if (i2c_core_start = '1') then + i2c_state <= i2c_trn_start; + i2c_core_busy <= '1'; + reg_num_rd := 0; + i2c_busy_prev <= '0'; + reg_i2c_trn_dir <= '1'; + end if; - -- when i2c_trn_main => - -- i2c_data_wr_o <= (others => spi_ram_data_o); -- Data to be written to the I2C buses - -- i2c_busy_prev <= i2c_busy_flag_i; -- Capture the value of the previous i2c busy signal - -- if (i2c_busy_prev = (i2c_busy_prev'range => '0') and i2c_busy_flag_i = reg_i2c_mask) then -- I2C busy just went high - -- case reg_i2c_trn_dir is -- Switches to the needed transaction direction - -- when '0' => -- When write - continue to write - -- data_wr_cnt := data_wr_cnt + 1; - -- if (data_wr_cnt > 0 and data_wr_cnt < spi_command_len) then -- Keep writing if there's still data in the RAM - -- spi_ram_raddr <= data_wr_cnt; - -- i2c_state <= wait_ram; - -- else -- Else - finish the transaction - -- i2c_state <= i2c_trn_final_word_wait; - -- i2c_txn_start_o <= (others => '0'); - -- end if; - -- when '1' => -- When read - -- if (data_rd_cnt = 0 and i2c_wr_done = '0') then -- Change the transaction from Write to Read after writing the first byte - -- i2c_rw_flag_o <= (others => '1'); - -- i2c_state <= i2c_wr_wait; -- Switch to read - -- else - -- i2c_state <= i2c_rd_wait; - -- i2c_wr_done <= '0'; - -- end if; - -- i2c_ram_we <= (others => '0'); + when i2c_trn_start => + s_i2c_txn_start <= '1'; -- Initiate the transaction + s_i2c_rw_flag <= '0'; -- First byte is always write + s_i2c_data_wr <= pse_regs_to_read(reg_num_rd); -- Place reg number to I2C master core + i2c_busy_prev <= s_i2c_busy_flag; + i2c_wr_done <= '0'; + i2c_state <= i2c_trn_main; - -- when others => - -- i2c_state <= ready; - -- end case; + when i2c_trn_main => + i2c_busy_prev <= s_i2c_busy_flag; -- Capture the value of the previous i2c busy signal + if (i2c_busy_prev = '0' and s_i2c_busy_flag = '1') then -- I2C busy just went high + case reg_i2c_trn_dir is -- Switches to the needed transaction direction + -- when '0' => -- When write - continue to write + -- data_wr_cnt := data_wr_cnt + 1; + -- if (data_wr_cnt > 0 and data_wr_cnt < spi_command_len) then -- Keep writing if there's still data in the RAM + -- spi_ram_raddr <= data_wr_cnt; + -- i2c_state <= wait_ram; + -- else -- Else - finish the transaction + -- i2c_state <= i2c_trn_final_word_wait; + -- s_i2c_txn_start <= (others => '0'); + -- end if; + when '1' => -- When read + if (i2c_wr_done = '0') then -- Change the transaction from Write to Read after writing the first byte + s_i2c_rw_flag <= '1'; -- Switch to read + i2c_state <= i2c_wr_wait; + else + i2c_wr_done <= '0'; + s_i2c_txn_start <= '0'; -- Stop core after reading 1 byte + i2c_state <= i2c_rd_wait; + end if; - -- end if; + when others => + i2c_state <= ready; + end case; - -- when wait_ram => - -- i2c_state <= i2c_trn_main; + end if; - -- when i2c_trn_final_word_wait => - -- if (i2c_busy_prev = reg_i2c_mask and i2c_busy_flag_i = (i2c_busy_prev'range => '0')) then -- I2C became free - -- i2c_state <= wait_ack; - -- end if; + -- when i2c_trn_final_word_wait => + -- if (i2c_busy_prev = '1' and s_i2c_busy_flag = '0') then -- I2C became free + -- i2c_state <= wait_ack; + -- end if; - -- when i2c_wr_wait => - -- if (i2c_busy_flag_i = (i2c_busy_flag_i'range => '0')) then -- Indicates data read in last command is ready - -- i2c_state <= i2c_trn_main; -- Transaction complete, go to next state in design - -- i2c_wr_done <= '1'; - -- end if; + when i2c_wr_wait => + if (s_i2c_busy_flag = '0') then -- Indicates data read in last command is ready + i2c_state <= i2c_trn_main; -- Transaction complete, go to next state in design + i2c_wr_done <= '1'; + i2c_busy_prev <= s_i2c_busy_flag; + end if; - -- when i2c_rd_wait => - -- if (i2c_busy_flag_i = (i2c_busy_flag_i'range => '0')) then -- Indicates data read in last command is ready - -- data_rd_cnt := data_rd_cnt + 1; - -- i2c_ram_waddr <= (others => data_rd_cnt-1); - -- i2c_ram_we <= reg_i2c_mask; - -- for i in 0 to I2C_NUM-1 loop - -- if (reg_i2c_mask(i) = '1') then - -- i2c_ram_data_i(i) <= i2c_data_rd_i(i); -- Store received byte - -- end if; - -- end loop; - -- if (data_rd_cnt = reg_i2c_read_len) then - -- i2c_state <= wait_ack; -- Transaction complete, go to next state in design - -- else - -- i2c_state <= i2c_trn_main; -- Transaction complete, go to next state in design - -- end if; - -- end if; + when i2c_rd_wait => + if (s_i2c_busy_flag = '0') then -- Indicates data read in last command is ready + pse_regs_value(reg_num_rd) <= s_i2c_data_rd; -- Store received byte + reg_num_rd := reg_num_rd + 1; + if (reg_num_rd = PSE_REG_NUM) then -- All regs are 1 byte length + i2c_state <= wait_ack; -- Transaction complete, go to next state in design + else + i2c_state <= i2c_trn_start; -- Transaction complete, go to next state in design + end if; + end if; - -- if (data_rd_cnt+1 = reg_i2c_read_len) then - -- i2c_txn_start_o <= (others => '0'); - -- end if; - - -- when wait_ack => - -- i2c_core_busy <= '0'; - -- i2c_ram_we <= (others => '0'); - -- i2c_busy_prev <= (others => '0'); - -- if (i2c_core_start = '0') then - -- i2c_state <= ready; - -- end if; - - -- when others => - -- i2c_state <= ready; - -- end case; - -- end if; - -- end process pse_i2c_proc; - --- s_i2c_txn_start --- s_i2c_rw_flag --- s_i2c_data_wr --- s_i2c_busy_flag --- s_i2c_data_rd + when wait_ack => + i2c_core_busy <= '0'; + i2c_busy_prev <= '0'; + if (i2c_core_start = '0') then + i2c_state <= ready; + end if; + when others => + i2c_state <= ready; + end case; + end if; + end process pse_i2c_proc; -- pse_scl_rptr: odio_repeater -- generic map ( @@ -836,6 +884,38 @@ begin i2c_data_to_master <= "0000000" & reg_poepd_ctl; i2c_slv_state <= wait_while_sent; + when x"60" => -- Read PSE register "Port 1 Status" 0x0C + i2c_data_to_master <= pse_regs_value(0); + i2c_slv_state <= wait_while_sent; + + when x"61" => -- Read PSE register "Port 2 Status" 0x0D + i2c_data_to_master <= pse_regs_value(1); + i2c_slv_state <= wait_while_sent; + + when x"62" => -- Read PSE register "Port 3 Status" 0x0E + i2c_data_to_master <= pse_regs_value(2); + i2c_slv_state <= wait_while_sent; + + when x"63" => -- Read PSE register "Port 4 Status" 0x0F + i2c_data_to_master <= pse_regs_value(3); + i2c_slv_state <= wait_while_sent; + + when x"64" => -- Read PSE register "Power Status" 0x10 + i2c_data_to_master <= pse_regs_value(4); + i2c_slv_state <= wait_while_sent; + + when x"65" => -- Read PSE register "Operating Mode" 0x12 + i2c_data_to_master <= pse_regs_value(5); + i2c_slv_state <= wait_while_sent; + + when x"66" => -- Read PSE register "Disconnect Enable" 0x13 + i2c_data_to_master <= pse_regs_value(6); + i2c_slv_state <= wait_while_sent; + + when x"67" => -- Read PSE register "Detect/Class Enable" 0x14 + i2c_data_to_master <= pse_regs_value(7); + i2c_slv_state <= wait_while_sent; + when x"A0" => -- Write SIM1 modem register i2c_slv_state <= receive_byte;