Fixed PSE I2C for write as well, PSE I2Cread and write tested
This commit is contained in:
parent
b1782ac316
commit
7439984c8c
|
|
@ -0,0 +1,253 @@
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- FileName: i2c_master.vhd
|
||||||
|
-- Dependencies: none
|
||||||
|
-- Design Software: Quartus II 64-bit Version 13.1 Build 162 SJ Full Version
|
||||||
|
--
|
||||||
|
-- HDL CODE IS PROVIDED "AS IS." DIGI-KEY EXPRESSLY DISCLAIMS ANY
|
||||||
|
-- WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||||
|
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
-- PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
|
||||||
|
-- BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
|
||||||
|
-- DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
|
||||||
|
-- PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
|
||||||
|
-- BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
|
||||||
|
-- ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
|
||||||
|
--
|
||||||
|
-- Version History
|
||||||
|
-- Version 1.0 11/01/2012 Scott Larson
|
||||||
|
-- Initial Public Release
|
||||||
|
-- Version 2.0 06/20/2014 Scott Larson
|
||||||
|
-- Added ability to interface with different slaves in the same transaction
|
||||||
|
-- Corrected ack_error bug where ack_error went 'Z' instead of '1' on error
|
||||||
|
-- Corrected timing of when ack_error signal clears
|
||||||
|
-- Version 2.1 10/21/2014 Scott Larson
|
||||||
|
-- Replaced gated clock with clock enable
|
||||||
|
-- Adjusted timing of SCL during start and stop conditions
|
||||||
|
-- Version 2.2 02/05/2015 Scott Larson
|
||||||
|
-- Corrected small SDA glitch introduced in version 2.1
|
||||||
|
--
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
LIBRARY ieee;
|
||||||
|
USE ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
--USE ieee.std_logic_unsigned.all;
|
||||||
|
|
||||||
|
ENTITY 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 i2c_master;
|
||||||
|
|
||||||
|
ARCHITECTURE logic OF i2c_master IS
|
||||||
|
CONSTANT divider : INTEGER := (input_clk/bus_clk)/4; --number of clocks in 1/4 cycle of scl
|
||||||
|
TYPE machine IS(ready, start, command, slv_ack1, wr, rd, slv_ack2, mstr_ack, stop); --needed states
|
||||||
|
SIGNAL state : machine; --state machine
|
||||||
|
SIGNAL data_clk : STD_LOGIC; --data clock for sda
|
||||||
|
SIGNAL data_clk_prev : STD_LOGIC; --data clock during previous system clock
|
||||||
|
SIGNAL scl_clk : STD_LOGIC; --constantly running internal scl
|
||||||
|
SIGNAL scl_ena : STD_LOGIC := '0'; --enables internal scl to output
|
||||||
|
SIGNAL sda_int : STD_LOGIC := '1'; --internal sda
|
||||||
|
SIGNAL sda_ena_n : STD_LOGIC; --enables internal sda to output
|
||||||
|
SIGNAL addr_rw : STD_LOGIC_VECTOR(7 DOWNTO 0); --latched in address and read/write
|
||||||
|
SIGNAL data_tx : STD_LOGIC_VECTOR(7 DOWNTO 0); --latched in data to write to slave
|
||||||
|
SIGNAL data_rx : STD_LOGIC_VECTOR(7 DOWNTO 0); --data received from slave
|
||||||
|
SIGNAL bit_cnt : INTEGER RANGE 0 TO 7 := 7; --tracks bit number in transaction
|
||||||
|
SIGNAL stretch : STD_LOGIC := '0'; --identifies if slave is stretching scl
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
--generate the timing for the bus clock (scl_clk) and the data clock (data_clk)
|
||||||
|
PROCESS(clk, reset_n)
|
||||||
|
VARIABLE count : INTEGER RANGE 0 TO divider*4; --timing for clock generation
|
||||||
|
BEGIN
|
||||||
|
IF(reset_n = '0') THEN --reset asserted
|
||||||
|
stretch <= '0';
|
||||||
|
count := 0;
|
||||||
|
ELSIF(clk'EVENT AND clk = '1') THEN
|
||||||
|
data_clk_prev <= data_clk; --store previous value of data clock
|
||||||
|
IF(count = divider*4-1) THEN --end of timing cycle
|
||||||
|
count := 0; --reset timer
|
||||||
|
ELSIF(stretch = '0') THEN --clock stretching from slave not detected
|
||||||
|
count := count + 1; --continue clock generation timing
|
||||||
|
END IF;
|
||||||
|
CASE count IS
|
||||||
|
WHEN 0 TO divider-1 => --first 1/4 cycle of clocking
|
||||||
|
scl_clk <= '0';
|
||||||
|
data_clk <= '0';
|
||||||
|
WHEN divider TO divider*2-1 => --second 1/4 cycle of clocking
|
||||||
|
scl_clk <= '0';
|
||||||
|
data_clk <= '1';
|
||||||
|
WHEN divider*2 TO divider*3-1 => --third 1/4 cycle of clocking
|
||||||
|
scl_clk <= '1'; --release scl
|
||||||
|
IF(scl = '0') THEN --detect if slave is stretching clock
|
||||||
|
stretch <= '1';
|
||||||
|
ELSE
|
||||||
|
stretch <= '0';
|
||||||
|
END IF;
|
||||||
|
data_clk <= '1';
|
||||||
|
WHEN OTHERS => --last 1/4 cycle of clocking
|
||||||
|
scl_clk <= '1';
|
||||||
|
data_clk <= '0';
|
||||||
|
END CASE;
|
||||||
|
END IF;
|
||||||
|
END PROCESS;
|
||||||
|
|
||||||
|
--state machine and writing to sda during scl low (data_clk rising edge)
|
||||||
|
PROCESS(clk, reset_n)
|
||||||
|
BEGIN
|
||||||
|
IF(reset_n = '0') THEN --reset asserted
|
||||||
|
state <= ready; --return to initial state
|
||||||
|
busy <= '1'; --indicate not available
|
||||||
|
scl_ena <= '0'; --sets scl high impedance
|
||||||
|
sda_int <= '1'; --sets sda high impedance
|
||||||
|
ack_error <= '0'; --clear acknowledge error flag
|
||||||
|
bit_cnt <= 7; --restarts data bit counter
|
||||||
|
data_rd <= "00000000"; --clear data read port
|
||||||
|
ELSIF(clk'EVENT AND clk = '1') THEN
|
||||||
|
IF(data_clk = '1' AND data_clk_prev = '0') THEN --data clock rising edge
|
||||||
|
CASE state IS
|
||||||
|
WHEN ready => --idle state
|
||||||
|
IF(ena = '1') THEN --transaction requested
|
||||||
|
busy <= '1'; --flag busy
|
||||||
|
addr_rw <= addr & rw; --collect requested slave address and command
|
||||||
|
data_tx <= data_wr; --collect requested data to write
|
||||||
|
state <= start; --go to start bit
|
||||||
|
ELSE --remain idle
|
||||||
|
busy <= '0'; --unflag busy
|
||||||
|
state <= ready; --remain idle
|
||||||
|
END IF;
|
||||||
|
WHEN start => --start bit of transaction
|
||||||
|
busy <= '1'; --resume busy if continuous mode
|
||||||
|
sda_int <= addr_rw(bit_cnt); --set first address bit to bus
|
||||||
|
state <= command; --go to command
|
||||||
|
WHEN command => --address and command byte of transaction
|
||||||
|
IF(bit_cnt = 0) THEN --command transmit finished
|
||||||
|
sda_int <= '1'; --release sda for slave acknowledge
|
||||||
|
bit_cnt <= 7; --reset bit counter for "byte" states
|
||||||
|
state <= slv_ack1; --go to slave acknowledge (command)
|
||||||
|
ELSE --next clock cycle of command state
|
||||||
|
bit_cnt <= bit_cnt - 1; --keep track of transaction bits
|
||||||
|
sda_int <= addr_rw(bit_cnt-1); --write address/command bit to bus
|
||||||
|
state <= command; --continue with command
|
||||||
|
END IF;
|
||||||
|
WHEN slv_ack1 => --slave acknowledge bit (command)
|
||||||
|
IF(addr_rw(0) = '0') THEN --write command
|
||||||
|
sda_int <= data_tx(bit_cnt); --write first bit of data
|
||||||
|
state <= wr; --go to write byte
|
||||||
|
ELSE --read command
|
||||||
|
sda_int <= '1'; --release sda from incoming data
|
||||||
|
state <= rd; --go to read byte
|
||||||
|
END IF;
|
||||||
|
WHEN wr => --write byte of transaction
|
||||||
|
busy <= '1'; --resume busy if continuous mode
|
||||||
|
IF(bit_cnt = 0) THEN --write byte transmit finished
|
||||||
|
sda_int <= '1'; --release sda for slave acknowledge
|
||||||
|
bit_cnt <= 7; --reset bit counter for "byte" states
|
||||||
|
state <= slv_ack2; --go to slave acknowledge (write)
|
||||||
|
ELSE --next clock cycle of write state
|
||||||
|
bit_cnt <= bit_cnt - 1; --keep track of transaction bits
|
||||||
|
sda_int <= data_tx(bit_cnt-1); --write next bit to bus
|
||||||
|
state <= wr; --continue writing
|
||||||
|
END IF;
|
||||||
|
WHEN rd => --read byte of transaction
|
||||||
|
busy <= '1'; --resume busy if continuous mode
|
||||||
|
IF(bit_cnt = 0) THEN --read byte receive finished
|
||||||
|
IF(ena = '1' AND addr_rw = addr & rw) THEN --continuing with another read at same address
|
||||||
|
sda_int <= '0'; --acknowledge the byte has been received
|
||||||
|
ELSE --stopping or continuing with a write
|
||||||
|
sda_int <= '1'; --send a no-acknowledge (before stop or repeated start)
|
||||||
|
END IF;
|
||||||
|
bit_cnt <= 7; --reset bit counter for "byte" states
|
||||||
|
data_rd <= data_rx; --output received data
|
||||||
|
state <= mstr_ack; --go to master acknowledge
|
||||||
|
ELSE --next clock cycle of read state
|
||||||
|
bit_cnt <= bit_cnt - 1; --keep track of transaction bits
|
||||||
|
state <= rd; --continue reading
|
||||||
|
END IF;
|
||||||
|
WHEN slv_ack2 => --slave acknowledge bit (write)
|
||||||
|
IF(ena = '1') THEN --continue transaction
|
||||||
|
busy <= '0'; --continue is accepted
|
||||||
|
addr_rw <= addr & rw; --collect requested slave address and command
|
||||||
|
data_tx <= data_wr; --collect requested data to write
|
||||||
|
IF(addr_rw = addr & rw) THEN --continue transaction with another write
|
||||||
|
sda_int <= data_wr(bit_cnt); --write first bit of data
|
||||||
|
state <= wr; --go to write byte
|
||||||
|
ELSE --continue transaction with a read or new slave
|
||||||
|
state <= start; --go to repeated start
|
||||||
|
END IF;
|
||||||
|
ELSE --complete transaction
|
||||||
|
state <= stop; --go to stop bit
|
||||||
|
END IF;
|
||||||
|
WHEN mstr_ack => --master acknowledge bit after a read
|
||||||
|
IF(ena = '1') THEN --continue transaction
|
||||||
|
busy <= '0'; --continue is accepted and data received is available on bus
|
||||||
|
addr_rw <= addr & rw; --collect requested slave address and command
|
||||||
|
data_tx <= data_wr; --collect requested data to write
|
||||||
|
IF(addr_rw = addr & rw) THEN --continue transaction with another read
|
||||||
|
sda_int <= '1'; --release sda from incoming data
|
||||||
|
state <= rd; --go to read byte
|
||||||
|
ELSE --continue transaction with a write or new slave
|
||||||
|
state <= start; --repeated start
|
||||||
|
END IF;
|
||||||
|
ELSE --complete transaction
|
||||||
|
state <= stop; --go to stop bit
|
||||||
|
END IF;
|
||||||
|
WHEN stop => --stop bit of transaction
|
||||||
|
busy <= '0'; --unflag busy
|
||||||
|
state <= ready; --go to idle state
|
||||||
|
END CASE;
|
||||||
|
ELSIF(data_clk = '0' AND data_clk_prev = '1') THEN --data clock falling edge
|
||||||
|
CASE state IS
|
||||||
|
WHEN start =>
|
||||||
|
IF(scl_ena = '0') THEN --starting new transaction
|
||||||
|
scl_ena <= '1'; --enable scl output
|
||||||
|
ack_error <= '0'; --reset acknowledge error output
|
||||||
|
END IF;
|
||||||
|
WHEN slv_ack1 => --receiving slave acknowledge (command)
|
||||||
|
IF(sda /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge
|
||||||
|
ack_error <= '1'; --set error output if no-acknowledge
|
||||||
|
END IF;
|
||||||
|
WHEN rd => --receiving slave data
|
||||||
|
data_rx(bit_cnt) <= sda; --receive current slave data bit
|
||||||
|
WHEN slv_ack2 => --receiving slave acknowledge (write)
|
||||||
|
IF(sda /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge
|
||||||
|
ack_error <= '1'; --set error output if no-acknowledge
|
||||||
|
END IF;
|
||||||
|
WHEN stop =>
|
||||||
|
scl_ena <= '0'; --disable scl
|
||||||
|
WHEN OTHERS =>
|
||||||
|
NULL;
|
||||||
|
END CASE;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
END PROCESS;
|
||||||
|
|
||||||
|
--set sda output
|
||||||
|
WITH state SELECT
|
||||||
|
sda_ena_n <= data_clk_prev WHEN start, --generate start condition
|
||||||
|
NOT data_clk_prev WHEN stop, --generate stop condition
|
||||||
|
sda_int WHEN OTHERS; --set to internal sda signal
|
||||||
|
|
||||||
|
--set scl and sda outputs
|
||||||
|
--scl <= '0' WHEN (scl_ena = '1' AND scl_clk = '0') ELSE 'Z';
|
||||||
|
scl <= '0' WHEN (scl_ena = '1' AND scl_clk = '0' AND scl_invert = '0') ELSE
|
||||||
|
'1' WHEN (scl_ena = '1' AND scl_clk = '0' AND scl_invert = '1') ELSE
|
||||||
|
'Z';
|
||||||
|
sda <= '0' WHEN sda_ena_n = '0' ELSE 'Z';
|
||||||
|
|
||||||
|
END logic;
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
library ieee;
|
|
||||||
use ieee.std_logic_1164.all;
|
|
||||||
|
|
||||||
------------------------------------------------------------
|
|
||||||
entity odio_repeater is
|
|
||||||
generic (
|
|
||||||
WAIT_CYCLES : integer := 3
|
|
||||||
);
|
|
||||||
port (
|
|
||||||
clk : in std_logic;
|
|
||||||
rstn : in std_logic;
|
|
||||||
signal_n1 : inout std_logic;
|
|
||||||
signal_n2 : inout std_logic
|
|
||||||
);
|
|
||||||
end entity odio_repeater;
|
|
||||||
------------------------------------------------------------
|
|
||||||
architecture arch of odio_repeater is
|
|
||||||
|
|
||||||
component debounce is
|
|
||||||
generic (
|
|
||||||
WAIT_CYCLES : integer := 5
|
|
||||||
);
|
|
||||||
port (
|
|
||||||
signal_in : in std_logic;
|
|
||||||
signal_out : out std_logic;
|
|
||||||
clk : in std_logic
|
|
||||||
);
|
|
||||||
end component;
|
|
||||||
|
|
||||||
type state_t is (idle, n1_to_n2, n2_to_n1);
|
|
||||||
signal state : state_t := idle;
|
|
||||||
|
|
||||||
signal s_n1_i_raw, s_n1_i, s_n1_o, s_n1_prev : std_logic;
|
|
||||||
signal s_n2_i_raw, s_n2_i, s_n2_o, s_n2_prev : std_logic;
|
|
||||||
|
|
||||||
begin
|
|
||||||
|
|
||||||
-- Tri-state IO handling
|
|
||||||
s_n1_i_raw <= signal_n1;
|
|
||||||
s_n2_i_raw <= signal_n2;
|
|
||||||
signal_n1 <= '0' when s_n1_o = '0' else 'Z';
|
|
||||||
signal_n2 <= '0' when s_n2_o = '0' else 'Z';
|
|
||||||
|
|
||||||
-- Debounce input lines
|
|
||||||
n1_debounce : debounce
|
|
||||||
generic map (
|
|
||||||
WAIT_CYCLES => WAIT_CYCLES
|
|
||||||
)
|
|
||||||
port map (
|
|
||||||
clk => clk,
|
|
||||||
signal_in => s_n1_i_raw,
|
|
||||||
signal_out => s_n1_i
|
|
||||||
);
|
|
||||||
|
|
||||||
n2_debounce : debounce
|
|
||||||
generic map (
|
|
||||||
WAIT_CYCLES => WAIT_CYCLES
|
|
||||||
)
|
|
||||||
port map (
|
|
||||||
clk => clk,
|
|
||||||
signal_in => s_n2_i_raw,
|
|
||||||
signal_out => s_n2_i
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Main open-drain IO repeater process
|
|
||||||
rptr_proc: process(clk, rstn, s_n1_i, s_n2_i) is
|
|
||||||
begin
|
|
||||||
if rstn = '0' then
|
|
||||||
s_n1_o <= '1';
|
|
||||||
s_n2_o <= '1';
|
|
||||||
s_n1_prev <= s_n1_i;
|
|
||||||
s_n2_prev <= s_n2_i;
|
|
||||||
state <= idle;
|
|
||||||
|
|
||||||
elsif (rising_edge(clk)) then
|
|
||||||
s_n1_prev <= s_n1_i;
|
|
||||||
s_n2_prev <= s_n2_i;
|
|
||||||
|
|
||||||
case state is
|
|
||||||
when idle =>
|
|
||||||
if (s_n1_prev = '1' and s_n1_i = '0') then
|
|
||||||
s_n2_o <= '0';
|
|
||||||
state <= n1_to_n2;
|
|
||||||
elsif (s_n2_prev = '1' and s_n2_i = '0') then
|
|
||||||
s_n1_o <= '0';
|
|
||||||
state <= n2_to_n1;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
when n1_to_n2 =>
|
|
||||||
if (s_n1_prev = '0' and s_n1_i = '1') then
|
|
||||||
s_n2_o <= '1';
|
|
||||||
state <= idle;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
when n2_to_n1 =>
|
|
||||||
if (s_n2_prev = '0' and s_n2_i = '1') then
|
|
||||||
s_n1_o <= '1';
|
|
||||||
state <= idle;
|
|
||||||
end if;
|
|
||||||
end case;
|
|
||||||
|
|
||||||
end if;
|
|
||||||
end process;
|
|
||||||
|
|
||||||
end architecture arch;
|
|
||||||
|
|
@ -225,7 +225,7 @@ architecture rtl of sim_switcher_top is
|
||||||
type arr_regs_t is array (natural range <>) of std_logic_vector(7 downto 0);
|
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);
|
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);
|
type i2c_pse_fsm_t is (ready, i2c_trn_start, i2c_trn_main, i2c_trn_final_word_wait, i2c_wr_wait, i2c_rd_wait, wait_ack);
|
||||||
signal i2c_state : i2c_pse_fsm_t := ready;
|
signal i2c_state : i2c_pse_fsm_t := ready;
|
||||||
|
|
||||||
signal s_i2c_data_wr : std_logic_vector(7 downto 0);
|
signal s_i2c_data_wr : std_logic_vector(7 downto 0);
|
||||||
|
|
@ -239,6 +239,11 @@ architecture rtl of sim_switcher_top is
|
||||||
signal i2c_wr_done : std_logic;
|
signal i2c_wr_done : std_logic;
|
||||||
signal reg_i2c_trn_dir : std_logic;
|
signal reg_i2c_trn_dir : std_logic;
|
||||||
signal wait_i2c_start : std_logic;
|
signal wait_i2c_start : std_logic;
|
||||||
|
signal pse_i2c_write_reg : std_logic;
|
||||||
|
signal pse_i2c_write_ack : std_logic;
|
||||||
|
signal pse_i2c_addr_wrtn : std_logic;
|
||||||
|
signal pse_i2c_wr_reg_num : std_logic_vector(7 downto 0);
|
||||||
|
signal pse_i2c_wr_reg_val : std_logic_vector(7 downto 0);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
||||||
|
|
@ -294,7 +299,7 @@ begin
|
||||||
scl_invert => '0'
|
scl_invert => '0'
|
||||||
);
|
);
|
||||||
|
|
||||||
-- SIM attach reset assigment: default is 1-to-1 SIM to MODEM connection
|
-- PSE register addresses
|
||||||
pse_regs_to_read <= (
|
pse_regs_to_read <= (
|
||||||
0 => x"0C", -- RO
|
0 => x"0C", -- RO
|
||||||
1 => x"0D", -- RO
|
1 => x"0D", -- RO
|
||||||
|
|
@ -309,23 +314,40 @@ begin
|
||||||
------------------------------
|
------------------------------
|
||||||
-- PSE read trigger process --
|
-- PSE read trigger process --
|
||||||
------------------------------
|
------------------------------
|
||||||
pse_readtrig_proc: process(clk25_i, s_rstn_i, wait_i2c_start, i2c_core_busy) is
|
pse_readtrig_proc: process(clk25_i, s_rstn_i, wait_i2c_start, i2c_core_busy, pse_i2c_write_reg) is
|
||||||
variable wait_cnt : natural := 0;
|
variable wait_cnt : natural := 0;
|
||||||
begin
|
begin
|
||||||
if (s_rstn_i = '0') then
|
if (s_rstn_i = '0') then
|
||||||
wait_i2c_start <= '0';
|
i2c_core_start <= '0';
|
||||||
|
wait_i2c_start <= '0';
|
||||||
|
reg_i2c_trn_dir <= '1';
|
||||||
|
pse_i2c_write_ack <= '0';
|
||||||
|
|
||||||
elsif (rising_edge(clk25_i)) then
|
elsif (rising_edge(clk25_i)) then
|
||||||
if (wait_i2c_start = '1') then
|
-- Clear write ack flag if pse_i2c_write_reg has been cleared
|
||||||
|
if (pse_i2c_write_reg = '0') then
|
||||||
|
pse_i2c_write_ack <= '0';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Main PSE I2C core control process
|
||||||
|
if (wait_i2c_start = '1') then -- Wait until PSE I2C core goes to busy state if wait_i2c_start is set
|
||||||
if (i2c_core_busy = '1') then
|
if (i2c_core_busy = '1') then
|
||||||
wait_i2c_start <= '0';
|
wait_i2c_start <= '0';
|
||||||
end if;
|
end if;
|
||||||
else
|
elsif (i2c_core_busy = '0') then -- If PSE I2C core is not busy - check for required operation and proceed
|
||||||
if (i2c_core_start = '1' and i2c_core_busy = '0') then
|
if (i2c_core_start = '1') then
|
||||||
i2c_core_start <= '0';
|
i2c_core_start <= '0';
|
||||||
|
elsif (pse_i2c_write_reg = '1') then
|
||||||
|
wait_cnt := 0;
|
||||||
|
wait_i2c_start <= '1';
|
||||||
|
pse_i2c_write_ack <= '1';
|
||||||
|
reg_i2c_trn_dir <= '0'; -- I2C write op
|
||||||
|
i2c_core_start <= '1';
|
||||||
elsif (wait_cnt > PSE_POLL_INTERVAL) then
|
elsif (wait_cnt > PSE_POLL_INTERVAL) then
|
||||||
wait_cnt := 0;
|
wait_cnt := 0;
|
||||||
wait_i2c_start <= '1';
|
wait_i2c_start <= '1';
|
||||||
i2c_core_start <= '1';
|
reg_i2c_trn_dir <= '1'; -- I2C read op
|
||||||
|
i2c_core_start <= '1';
|
||||||
end if;
|
end if;
|
||||||
wait_cnt := wait_cnt + 1;
|
wait_cnt := wait_cnt + 1;
|
||||||
end if;
|
end if;
|
||||||
|
|
@ -361,37 +383,43 @@ begin
|
||||||
i2c_core_busy <= '1';
|
i2c_core_busy <= '1';
|
||||||
reg_num_rd := 0;
|
reg_num_rd := 0;
|
||||||
i2c_busy_prev <= '0';
|
i2c_busy_prev <= '0';
|
||||||
reg_i2c_trn_dir <= '1';
|
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when i2c_trn_start =>
|
when i2c_trn_start =>
|
||||||
s_i2c_txn_start <= '1'; -- Initiate the transaction
|
s_i2c_txn_start <= '1'; -- Initiate the transaction
|
||||||
s_i2c_rw_flag <= '0'; -- First byte is always write
|
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
|
case reg_i2c_trn_dir is
|
||||||
|
when '0' => -- write
|
||||||
|
s_i2c_data_wr <= pse_i2c_wr_reg_num; -- Place reg number to I2C master core
|
||||||
|
pse_i2c_addr_wrtn <= '0';
|
||||||
|
when '1' => -- read
|
||||||
|
s_i2c_data_wr <= pse_regs_to_read(reg_num_rd); -- Place reg number to I2C master core
|
||||||
|
end case;
|
||||||
i2c_busy_prev <= s_i2c_busy_flag;
|
i2c_busy_prev <= s_i2c_busy_flag;
|
||||||
i2c_wr_done <= '0';
|
i2c_wr_done <= '0';
|
||||||
i2c_state <= i2c_trn_main;
|
i2c_state <= i2c_trn_main;
|
||||||
|
|
||||||
when i2c_trn_main =>
|
when i2c_trn_main =>
|
||||||
i2c_busy_prev <= s_i2c_busy_flag; -- Capture the value of the previous i2c busy signal
|
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
|
if (i2c_busy_prev = '0' and s_i2c_busy_flag = '1') then -- I2C busy just went high
|
||||||
-- when '0' => -- When write - continue to write
|
case reg_i2c_trn_dir is -- Switches to the needed transaction direction
|
||||||
-- data_wr_cnt := data_wr_cnt + 1;
|
when '0' => -- When write - continue to write
|
||||||
-- if (data_wr_cnt > 0 and data_wr_cnt < spi_command_len) then -- Keep writing if there's still data in the RAM
|
if (pse_i2c_addr_wrtn = '0') then -- Keep writing if there's still data in the RAM
|
||||||
-- spi_ram_raddr <= data_wr_cnt;
|
pse_i2c_addr_wrtn <= '1';
|
||||||
-- i2c_state <= wait_ram;
|
s_i2c_data_wr <= pse_i2c_wr_reg_val; -- Prepare register value to write
|
||||||
-- else -- Else - finish the transaction
|
else -- Else - finish the transaction
|
||||||
-- i2c_state <= i2c_trn_final_word_wait;
|
i2c_state <= i2c_trn_final_word_wait;
|
||||||
-- s_i2c_txn_start <= (others => '0');
|
s_i2c_txn_start <= '0';
|
||||||
-- end if;
|
end if;
|
||||||
when '1' => -- When read
|
|
||||||
if (i2c_wr_done = '0') then -- Change the transaction from Write to Read after writing the first byte
|
when '1' => -- When read
|
||||||
s_i2c_rw_flag <= '1'; -- Switch to 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;
|
i2c_state <= i2c_wr_wait;
|
||||||
else
|
else
|
||||||
i2c_wr_done <= '0';
|
i2c_wr_done <= '0';
|
||||||
s_i2c_txn_start <= '0'; -- Stop core after reading 1 byte
|
s_i2c_txn_start <= '0'; -- Stop core after reading 1 byte
|
||||||
i2c_state <= i2c_rd_wait;
|
i2c_state <= i2c_rd_wait;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
|
|
@ -401,14 +429,14 @@ begin
|
||||||
|
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- when i2c_trn_final_word_wait =>
|
when i2c_trn_final_word_wait =>
|
||||||
-- if (i2c_busy_prev = '1' and s_i2c_busy_flag = '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 (s_i2c_busy_flag = '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';
|
||||||
i2c_busy_prev <= s_i2c_busy_flag;
|
i2c_busy_prev <= s_i2c_busy_flag;
|
||||||
end if;
|
end if;
|
||||||
|
|
@ -735,6 +763,7 @@ begin
|
||||||
reg_expio_dir <= (others => '0'); -- All Expansion card IOs direction is IN
|
reg_expio_dir <= (others => '0'); -- All Expansion card IOs direction is IN
|
||||||
reg_expio_intdirh2l <= (others => '0'); -- Expansion card GPIO default line interrupt generation for High-to-Low transition is off
|
reg_expio_intdirh2l <= (others => '0'); -- Expansion card GPIO default line interrupt generation for High-to-Low transition is off
|
||||||
reg_expio_intdirl2h <= (others => '0'); -- Expansion card GPIO default line interrupt generation for Low-to-High transition is off
|
reg_expio_intdirl2h <= (others => '0'); -- Expansion card GPIO default line interrupt generation for Low-to-High transition is off
|
||||||
|
pse_i2c_write_reg <= '0';
|
||||||
|
|
||||||
elsif (rising_edge(clk25_i)) then
|
elsif (rising_edge(clk25_i)) then
|
||||||
if (s_int_expio_reset_ack = '1') then
|
if (s_int_expio_reset_ack = '1') then
|
||||||
|
|
@ -748,6 +777,10 @@ begin
|
||||||
case i2c_slv_state is
|
case i2c_slv_state is
|
||||||
when ready =>
|
when ready =>
|
||||||
wait_cnt := 0;
|
wait_cnt := 0;
|
||||||
|
-- Reset pse_i2c_write_reg trigger if PSE I2C core has ACKed the write operation
|
||||||
|
if (pse_i2c_write_ack = '1') then
|
||||||
|
pse_i2c_write_reg <= '0';
|
||||||
|
end if;
|
||||||
i2c_data_to_master <= (others => '0');
|
i2c_data_to_master <= (others => '0');
|
||||||
if (i2c_data_valid = '1') then -- master sent a register addr byte
|
if (i2c_data_valid = '1') then -- master sent a register addr byte
|
||||||
-- Save register address for later use in write procedure
|
-- Save register address for later use in write procedure
|
||||||
|
|
@ -904,7 +937,7 @@ begin
|
||||||
i2c_data_to_master <= pse_regs_value(4);
|
i2c_data_to_master <= pse_regs_value(4);
|
||||||
i2c_slv_state <= wait_while_sent;
|
i2c_slv_state <= wait_while_sent;
|
||||||
|
|
||||||
when x"65" => -- Read PSE register "Operating Mode" 0x12
|
when x"65" => -- Read PSE register "Operating Mode" 0x12, 00 Off, 01 Manual, 10 Semi-Auto, 11 Auto
|
||||||
i2c_data_to_master <= pse_regs_value(5);
|
i2c_data_to_master <= pse_regs_value(5);
|
||||||
i2c_slv_state <= wait_while_sent;
|
i2c_slv_state <= wait_while_sent;
|
||||||
|
|
||||||
|
|
@ -976,6 +1009,15 @@ begin
|
||||||
when x"D5" => -- Write POE IN control register
|
when x"D5" => -- Write POE IN control register
|
||||||
i2c_slv_state <= receive_byte;
|
i2c_slv_state <= receive_byte;
|
||||||
|
|
||||||
|
when x"E5" => -- Write PSE register "Operating Mode" 0x12
|
||||||
|
i2c_slv_state <= receive_byte;
|
||||||
|
|
||||||
|
when x"E6" => -- Write PSE register "Disconnect Enable" 0x13
|
||||||
|
i2c_slv_state <= receive_byte;
|
||||||
|
|
||||||
|
when x"E7" => -- Write PSE register "Detect/Class Enable" 0x14
|
||||||
|
i2c_slv_state <= receive_byte;
|
||||||
|
|
||||||
when others =>
|
when others =>
|
||||||
i2c_slv_state <= ready;
|
i2c_slv_state <= ready;
|
||||||
end case;
|
end case;
|
||||||
|
|
@ -1044,6 +1086,21 @@ begin
|
||||||
when x"D5" => -- Write POE IN control register
|
when x"D5" => -- Write POE IN control register
|
||||||
reg_poepd_ctl <= i2c_data_from_master(0);
|
reg_poepd_ctl <= i2c_data_from_master(0);
|
||||||
|
|
||||||
|
when x"E5" => -- Write PSE register "Operating Mode" 0x12
|
||||||
|
pse_i2c_wr_reg_val <= i2c_data_from_master(7 downto 0);
|
||||||
|
pse_i2c_wr_reg_num <= x"12";
|
||||||
|
pse_i2c_write_reg <= '1';
|
||||||
|
|
||||||
|
when x"E6" => -- Write PSE register "Disconnect Enable" 0x13
|
||||||
|
pse_i2c_wr_reg_val <= i2c_data_from_master(7 downto 0);
|
||||||
|
pse_i2c_wr_reg_num <= x"13";
|
||||||
|
pse_i2c_write_reg <= '1';
|
||||||
|
|
||||||
|
when x"E7" => -- Write PSE register "Detect/Class Enable" 0x14
|
||||||
|
pse_i2c_wr_reg_val <= i2c_data_from_master(7 downto 0);
|
||||||
|
pse_i2c_wr_reg_num <= x"14";
|
||||||
|
pse_i2c_write_reg <= '1';
|
||||||
|
|
||||||
when others =>
|
when others =>
|
||||||
null;
|
null;
|
||||||
end case;
|
end case;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue