Fixed PSE I2C for read only, not tested

This commit is contained in:
matt 2020-08-04 02:13:00 +07:00
parent 611076ca6d
commit b1782ac316
2 changed files with 247 additions and 132 deletions

View File

@ -22,6 +22,27 @@ package sim_switcher_pkg is
); );
end component sim_mux; 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 component i2c_slave is
generic ( generic (
SLAVE_ADDR : std_logic_vector(6 downto 0) SLAVE_ADDR : std_logic_vector(6 downto 0)
@ -39,6 +60,20 @@ package sim_switcher_pkg is
); );
end component i2c_slave; 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 component odio_repeater is
generic ( generic (
WAIT_CYCLES : integer := 3 WAIT_CYCLES : integer := 3

View File

@ -120,6 +120,10 @@ architecture rtl of sim_switcher_top is
constant I2C_MAX_WAIT : natural := 2_500_000; -- 25_000_000 = 1sec 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_clk_i : std_logic; -- clock buffer
signal s_rstn_i : std_logic; -- reset signal signal s_rstn_i : std_logic; -- reset signal
signal s_rst_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 -- SIM-MODEM switching register
signal reg_sim_modemnum: arr_modnum_t(0 to 7); 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 begin
-- Interrupt output routing -- Interrupt output routing
@ -251,63 +274,108 @@ begin
reg_pse_status(0) <= pse_vpwr_pg; reg_pse_status(0) <= pse_vpwr_pg;
-- Connect PSE I2C bus to main I2C bus -- Connect PSE I2C bus to main I2C bus
-- inst_i2c_master: i2c_master inst_i2c_master: i2c_master
-- generic map ( generic map (
-- input_clk => SYSFREQ, input_clk => SYSFREQ,
-- bus_clk => I2C_CLK bus_clk => I2C_CLK
-- ) )
-- port map ( port map (
-- clk => clk25_i, clk => clk25_i,
-- reset_n => s_rstn_i, reset_n => s_rstn_i,
-- ena => s_i2c_txn_start, ena => s_i2c_txn_start,
-- addr => x"20", addr => PSE_I2C_ADDR,
-- rw => s_i2c_rw_flag, rw => s_i2c_rw_flag,
-- data_wr => s_i2c_data_wr, data_wr => s_i2c_data_wr,
-- busy => s_i2c_busy_flag, busy => s_i2c_busy_flag,
-- data_rd => s_i2c_data_rd, data_rd => s_i2c_data_rd,
-- ack_error => open, ack_error => open,
-- sda => pse_i2c_sda_io, sda => pse_i2c_sda_io,
-- scl => pse_i2c_scl_io, scl => pse_i2c_scl_io,
-- scl_invert => '0' scl_invert => '0'
-- ); );
-- -- PSE I2C interaction process -- SIM attach reset assigment: default is 1-to-1 SIM to MODEM connection
-- pse_i2c_proc: process (clk_i, rstn_i) pse_regs_to_read <= (
-- variable data_wr_cnt : natural := 0; 0 => x"0C", -- RO
-- variable data_rd_cnt : natural := 0; 1 => x"0D", -- RO
-- begin 2 => x"0E", -- RO
-- if (rstn_i = '0') then 3 => x"0F", -- RO
-- i2c_state <= ready; 4 => x"10", -- RO
-- i2c_core_busy <= '0'; 5 => x"12", -- R/W
-- i2c_busy_prev <= (others => '0'); 6 => x"13", -- R/W
-- i2c_ram_we <= (others => '0'); 7 => x"14" -- R/W
-- i2c_wr_done <= '0'; );
-- elsif (rising_edge(clk_i)) then ------------------------------
-- case i2c_state is -- PSE read trigger process --
-- when ready => ------------------------------
-- if (i2c_core_start = '1') then pse_readtrig_proc: process(clk25_i, s_rstn_i, wait_i2c_start, i2c_core_busy) is
-- i2c_state <= i2c_trn_start; variable wait_cnt : natural := 0;
-- i2c_core_busy <= '1'; begin
-- data_wr_cnt := 0; if (s_rstn_i = '0') then
-- data_rd_cnt := 0; wait_i2c_start <= '0';
-- spi_ram_raddr <= data_wr_cnt; -- Request data from RAM 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'); -- PSE I2C interaction process
-- end if; 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 => elsif (rising_edge(clk25_i)) then
-- i2c_txn_start_o <= reg_i2c_mask; -- Initiate the transaction case i2c_state is
-- i2c_slv_addr_o <= (others => reg_i2c_addr); -- Set the address of the slave when ready =>
-- i2c_rw_flag_o <= (others => '0'); -- First byte is always write if (i2c_core_start = '1') then
-- i2c_data_wr_o <= (others => spi_ram_data_o); -- Data to be written i2c_state <= i2c_trn_start;
-- i2c_state <= i2c_trn_main; i2c_core_busy <= '1';
reg_num_rd := 0;
i2c_busy_prev <= '0';
reg_i2c_trn_dir <= '1';
end if;
-- when i2c_trn_main => when i2c_trn_start =>
-- i2c_data_wr_o <= (others => spi_ram_data_o); -- Data to be written to the I2C buses s_i2c_txn_start <= '1'; -- Initiate the transaction
-- i2c_busy_prev <= i2c_busy_flag_i; -- Capture the value of the previous i2c busy signal s_i2c_rw_flag <= '0'; -- First byte is always write
-- if (i2c_busy_prev = (i2c_busy_prev'range => '0') and i2c_busy_flag_i = reg_i2c_mask) then -- I2C busy just went high s_i2c_data_wr <= pse_regs_to_read(reg_num_rd); -- Place reg number to I2C master core
-- case reg_i2c_trn_dir is -- Switches to the needed transaction direction i2c_busy_prev <= s_i2c_busy_flag;
i2c_wr_done <= '0';
i2c_state <= i2c_trn_main;
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 -- when '0' => -- When write - continue to write
-- data_wr_cnt := data_wr_cnt + 1; -- 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 -- if (data_wr_cnt > 0 and data_wr_cnt < spi_command_len) then -- Keep writing if there's still data in the RAM
@ -315,79 +383,59 @@ begin
-- i2c_state <= wait_ram; -- i2c_state <= wait_ram;
-- else -- Else - finish the transaction -- else -- Else - finish the transaction
-- i2c_state <= i2c_trn_final_word_wait; -- i2c_state <= i2c_trn_final_word_wait;
-- i2c_txn_start_o <= (others => '0'); -- s_i2c_txn_start <= (others => '0');
-- end if; -- end if;
-- when '1' => -- When read 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 if (i2c_wr_done = '0') then -- Change the transaction from Write to Read after writing the first byte
-- i2c_rw_flag_o <= (others => '1'); s_i2c_rw_flag <= '1'; -- Switch to read
-- i2c_state <= i2c_wr_wait; -- Switch to read i2c_state <= i2c_wr_wait;
-- else else
-- i2c_state <= i2c_rd_wait; i2c_wr_done <= '0';
-- i2c_wr_done <= '0'; s_i2c_txn_start <= '0'; -- Stop core after reading 1 byte
-- end if; i2c_state <= i2c_rd_wait;
-- i2c_ram_we <= (others => '0'); end if;
-- when others => when others =>
-- i2c_state <= ready; i2c_state <= ready;
-- end case; end case;
-- end if; end if;
-- when wait_ram =>
-- i2c_state <= i2c_trn_main;
-- when i2c_trn_final_word_wait => -- 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 -- if (i2c_busy_prev = '1' and s_i2c_busy_flag = '0') then -- I2C became free
-- i2c_state <= wait_ack; -- i2c_state <= wait_ack;
-- end if; -- end if;
-- when i2c_wr_wait => when i2c_wr_wait =>
-- if (i2c_busy_flag_i = (i2c_busy_flag_i'range => '0')) then -- Indicates data read in last command is ready 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_state <= i2c_trn_main; -- Transaction complete, go to next state in design
-- i2c_wr_done <= '1'; i2c_wr_done <= '1';
-- end if; i2c_busy_prev <= s_i2c_busy_flag;
end if;
-- when i2c_rd_wait => when i2c_rd_wait =>
-- if (i2c_busy_flag_i = (i2c_busy_flag_i'range => '0')) then -- Indicates data read in last command is ready if (s_i2c_busy_flag = '0') then -- Indicates data read in last command is ready
-- data_rd_cnt := data_rd_cnt + 1; pse_regs_value(reg_num_rd) <= s_i2c_data_rd; -- Store received byte
-- i2c_ram_waddr <= (others => data_rd_cnt-1); reg_num_rd := reg_num_rd + 1;
-- i2c_ram_we <= reg_i2c_mask; if (reg_num_rd = PSE_REG_NUM) then -- All regs are 1 byte length
-- for i in 0 to I2C_NUM-1 loop i2c_state <= wait_ack; -- Transaction complete, go to next state in design
-- if (reg_i2c_mask(i) = '1') then else
-- i2c_ram_data_i(i) <= i2c_data_rd_i(i); -- Store received byte i2c_state <= i2c_trn_start; -- Transaction complete, go to next state in design
-- end if; end if;
-- end loop; end if;
-- 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;
-- if (data_rd_cnt+1 = reg_i2c_read_len) then when wait_ack =>
-- i2c_txn_start_o <= (others => '0'); i2c_core_busy <= '0';
-- end if; i2c_busy_prev <= '0';
if (i2c_core_start = '0') then
-- when wait_ack => i2c_state <= ready;
-- i2c_core_busy <= '0'; end if;
-- 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 others =>
i2c_state <= ready;
end case;
end if;
end process pse_i2c_proc;
-- pse_scl_rptr: odio_repeater -- pse_scl_rptr: odio_repeater
-- generic map ( -- generic map (
@ -836,6 +884,38 @@ begin
i2c_data_to_master <= "0000000" & reg_poepd_ctl; i2c_data_to_master <= "0000000" & reg_poepd_ctl;
i2c_slv_state <= wait_while_sent; 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 when x"A0" => -- Write SIM1 modem register
i2c_slv_state <= receive_byte; i2c_slv_state <= receive_byte;