Fixed PSE I2C for read only, not tested
This commit is contained in:
parent
611076ca6d
commit
b1782ac316
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -120,6 +120,10 @@ architecture rtl of sim_switcher_top is
|
|||
|
||||
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,63 +274,108 @@ 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 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 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
|
||||
|
|
@ -315,79 +383,59 @@ begin
|
|||
-- i2c_state <= wait_ram;
|
||||
-- else -- Else - finish the transaction
|
||||
-- i2c_state <= i2c_trn_final_word_wait;
|
||||
-- i2c_txn_start_o <= (others => '0');
|
||||
-- s_i2c_txn_start <= (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 '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;
|
||||
|
||||
-- when others =>
|
||||
-- i2c_state <= ready;
|
||||
-- end case;
|
||||
when others =>
|
||||
i2c_state <= ready;
|
||||
end case;
|
||||
|
||||
-- end if;
|
||||
|
||||
-- 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
|
||||
-- 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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue