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;
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

View File

@ -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;