A src/i2c/rx.vhd => src/i2c/rx.vhd +165 -0
@@ 0,0 1,165 @@
+-- i2c interface
+ -- scl_pulse_i
+ -- scl_stretch_o
+ -- sda_o
+
+-- control interface
+ -- clk_i
+ -- rst_in
+ -- start_read_i
+
+-- read interface
+ -- read_valid_o
+ -- read_ready_o
+ -- read_data_o
+ -- confirm_read_i
+--
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity rx is
+
+ port (
+ -- control part
+ clk_i : in std_logic; -- Clock
+ rst_in : in std_logic; -- Reset (asynchronous)
+ start_read_i : in std_logic; -- Start reading with next scl_pulse
+
+ scl_pulse_i : in std_logic; -- SCL rising edge pulse
+ scl_stretch_o : out std_logic; -- Stretch SCL (keep SCL 0)
+ sda_i : in std_logic; -- SDA data line state
+
+ read_valid_o : out std_logic; -- Are there any data on read_data_o?
+ read_ready_o : out std_logic; -- Is it possible to read anymore, or
+ -- does data have to be read to flush buffer?
+ read_data_o : out std_logic_vector(7 downto 0); -- The received data
+ confirm_read_i : in std_logic); -- Confirm that data have been read
+
+end entity rx;
+
+architecture a1 of rx is
+ -- IDLE - not doing anythign
+ -- RECEIVING - currently receiving data to the buffer
+ -- SAVING - trying to save to the read data output, waiting for data being
+ -- read if cannot save
+ -- SAVING_STRETCHING - waiting for data being read, should
+ -- be sending already, but cannot, since the data are not read,
+ -- so stretching SCL
+ type rx_state_t is (IDLE, RECEIVING, SAVING, SAVING_STRETCHING);
+ signal curr_state : rx_state_t;
+ signal next_state : rx_state_t;
+
+ -- Whether state = RECEIVING
+ signal curr_receiving : std_logic;
+ -- Whether state = SAVING or SAVING_STRETCHING
+ signal curr_saving : std_logic;
+
+ -- Whether the read data output is filled
+ -- already (it's a register)
+ signal curr_read_data_filled : std_logic;
+ signal next_read_data_filled : std_logic;
+
+ -- The received data
+ signal curr_rx_buffer : std_logic_vector(7 downto 0);
+ signal next_rx_buffer : std_logic_vector(7 downto 0);
+
+ -- Bit index that is being received
+ signal curr_bit_index : natural range 0 to 7;
+ signal next_bit_index : natural range 0 to 7;
+
+ signal curr_read_data : std_logic_vector(7 downto 0);
+ signal next_read_data : std_logic_vector(7 downto 0);
+begin -- architecture a1
+ read_ready_o <= '1' when curr_state /= SAVING_STRETCHING else '0';
+ scl_stretch_o <= '1' when curr_state = SAVING_STRETCHING else '0';
+ read_data_o <= curr_read_data;
+
+ -- IDLE -> RECEIVING on start_read,
+ -- RECEIVING -> RECEIVING when not received full data
+ -- RECEIVING -> SAVING when received all data
+ -- SAVING -> SAVING_STRETCHING when cannot overrode data AND start_read
+ -- SAVING -> RECEIVING when start_read AND overriding data now
+ -- SAVING -> SAVING when cannot override data (data not read yet)
+ -- SAVING -> IDLE when can override data
+ -- SAVING_STRETCHING -> SAVING_STRETCHING when data not read yet
+ -- SAVING_STRETCHING -> RECEIVING when data read
+
+ set_next_state: process is
+ begin -- process set_next_state
+ next_state <= curr_state;
+
+ if curr_state = IDLE then
+ if start_read_i = '1' then
+ next_state <= RECEIVING;
+ end if;
+ elsif curr_state = RECEIVING then
+ if curr_bit_index = 0 and scl_pulse_i = '1' then
+ next_state <= SAVING;
+ end if;
+ elsif curr_state = SAVING then
+ if confirm_read_i = '1' then
+ if start_read_i = '1' then
+ next_state <= RECEIVING; -- skip SAVING_STRETCHING
+ else
+ next_state <= IDLE;
+ end if;
+ elsif start_read_i = '1' then
+ next_state <= SAVING_STRETCHING;
+ end if;
+ elsif curr_state = SAVING_STRETCHING then
+ if confirm_read_i = '1' then
+ next_state <= RECEIVING;
+ end if;
+ end if;
+ end process set_next_state;
+
+ curr_receiving <= '1' when curr_state = RECEIVING;
+ curr_saving <= '1' when curr_state = SAVING or curr_state = SAVING_STRETCHING;
+
+ read_valid_o <= curr_read_data_filled;
+
+ -- TODO: (speedup by one cycle when saving?)
+ next_read_data <= curr_read_data when curr_read_data_filled = '1' else
+ next_rx_buffer when next_read_data_filled = '1' and curr_read_data_filled = '0' else
+ (others => '0');
+
+ next_read_data_filled <= '1' when curr_read_data_filled = '1' and confirm_read_i = '0' else
+ '0' when curr_read_data_filled = '1' and confirm_read_i = '1' else
+ '1' when curr_receiving = '1' and curr_bit_index = 0 else
+ '0';
+
+ next_bit_index <= curr_bit_index when scl_pulse_i = '0' else
+ (curr_bit_index - 1) when curr_receiving = '1' and scl_pulse_i = '1' else
+ 7; -- when curr_state /= RECEIVING and next_state = RECEIVING;
+
+ set_next_read_data: process (sda_i, curr_rx_buffer, curr_receiving, curr_saving, curr_bit_index, scl_pulse_i) is
+ begin -- process set_next_read_data
+ next_rx_buffer <= curr_rx_buffer;
+
+ if curr_receiving = '1' and curr_saving = '0' and scl_pulse_i = '1' then
+ next_rx_buffer(curr_bit_index) <= sda_i;
+ end if;
+ end process set_next_read_data;
+
+ set_regs: process (clk_i) is
+ begin -- process set_regs
+ if rising_edge(clk_i) then -- rising clock edge
+ if rst_in = '0' then -- synchronous reset (active low)
+ curr_read_data <= (others => '0');
+ curr_rx_buffer <= (others => '0');
+ curr_bit_index <= 0;
+ curr_read_data_filled <= '0';
+ curr_saving <= '0';
+ curr_receiving <= '0';
+ curr_state <= IDLE;
+ else
+ curr_read_data <= next_read_data;
+ curr_rx_buffer <= next_rx_buffer;
+ curr_bit_index <= next_bit_index;
+ curr_read_data_filled <= next_read_data_filled;
+ curr_state <= next_state;
+ end if;
+ end if;
+ end process set_regs;
+
+end architecture a1;
A src/i2c/tx.vhd => src/i2c/tx.vhd +187 -0
@@ 0,0 1,187 @@
+
+-- i2c interface
+ -- scl_pulse_i
+ -- scl_stretch_o
+ -- sda_o
+
+-- control interface
+ -- clk_i
+ -- rst_in
+ -- start_write_i
+
+-- write interface
+-- ready_o
+-- valid_i
+-- write_data
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+library utils;
+
+entity tx is
+ generic (
+ DELAY_SDA_FOR : natural := 5); -- How many cycles to delay setting SDA
+ -- after falling edge of scl
+ port (
+ clk_i : in std_logic;
+ rst_in : in std_logic;
+ start_write_i : in std_logic;
+
+ scl_rising_pulse_i : in std_logic;
+ scl_falling_pulse_i : in std_logic;
+
+ scl_i : in std_logic;
+ scl_stretch_o : out std_logic;
+ sda_o : out std_logic;
+
+ ready_o : out std_logic;
+ valid_i : in std_logic;
+ write_data_i : in std_logic_vector(7 downto 0));
+
+end entity tx;
+
+architecture a1 of tx is
+ -- IDLE - not doing anything
+ -- SENDING - data are in the buffer, being sent
+ -- WAITING_FOR_SEND there were data written to the buffer, but cannot send now
+ -- WAITING_FOR_DATA should be sending, but there are no data - stretching
+ type tx_state_t is (IDLE, WAITING_FOR_FALLING_EDGE, SENDING, WAITING_FOR_DATA);
+ signal curr_state : tx_state_t;
+ signal next_state : tx_state_t;
+
+ type tx_buffers is array (0 to 1) of std_logic_vector(7 downto 0);
+ signal curr_tx_buffers : tx_buffers;
+ signal next_tx_buffers : tx_buffers;
+
+ -- Index to save next new data to.
+ signal curr_saving_buffer_index : natural range 0 to 1;
+ signal next_saving_buffer_index : natural range 0 to 1;
+
+ signal curr_tx_buffer_index : natural range 0 to 1;
+ signal next_tx_buffer_index : natural range 0 to 1;
+
+ signal curr_tx_buffers_filled : std_logic_vector(1 downto 0);
+ signal next_tx_buffers_filled : std_logic_vector(1 downto 0);
+
+ signal tx_buffer : std_logic_vector(7 downto 0);
+ signal tx_buffer_filled : std_logic;
+
+ signal curr_bit_index : natural range 0 to 7;
+ signal next_bit_index : natural range 0 to 7;
+
+ signal scl_delayed_pulse : std_logic;
+ signal curr_scl : std_logic;
+ signal next_scl : std_logic;
+
+ signal ready : std_logic;
+begin -- architecture a1
+ entity utils.delay
+ generic map (
+ DELAY => DELAY_SDA_FOR)
+ port map (
+ clk_i => clk_i,
+ rst_in => rst_in,
+ signal_i => scl_falling_pulse_i,
+ signal_o => scl_delayed_pulse);
+
+ scl_stretch_o <= '1' when curr_state = WAITING_FOR_DATA else '0';
+ ready_o <= ready;
+ sda_o <= tx_buffer(curr_bit_index) when curr_state = SENDING else '1';
+
+ ready <= '0' when curr_tx_buffers_filled(curr_saving_buffer_index) = '1' else '1';
+ tx_buffer <= curr_tx_buffers(curr_tx_buffer_index);
+ tx_buffer_filled <= curr_tx_buffers_filled(curr_tx_buffer_index);
+
+ next_scl <= '1' when scl_rising_pulse_i = '1' else
+ '0' when scl_falling_pulse_i = '1' else
+ curr_scl;
+
+ next_bit_index <= 0 when start_write_i = '1' else
+ (curr_bit_index + 1) mod 7 when curr_state = SENDING and scl_delayed_pulse = '1' else
+ 0;
+
+ next_tx_buffer_index <= (curr_tx_buffer_index + 1) mod 1 when curr_bit_index = 7 and scl_delayed_pulse = '1' else
+ curr_tx_buffer_index;
+
+ next_saving_buffer_index <= (curr_saving_buffer_index + 1) mod 1 when ready = '1' and valid_i = '1' else
+ curr_saving_buffer_index;
+
+ set_next_tx_buffers: process is
+ begin -- process set_next_tx_buffer
+ next_tx_buffers <= curr_tx_buffers;
+ if ready = '1' and valid_i = '1' then
+ next_tx_buffers(curr_saving_buffer_index) <= write_data_i;
+ end if;
+ end process set_next_tx_buffer;
+
+ set_next_buffer_filled: process is
+ begin -- process set_next_buffer_filled
+ next_tx_buffers_filled <= curr_tx_buffers_filled;
+ if curr_bit_index = 7 and scl_delayed_pulse = '1' then
+ next_tx_buffers_filled(curr_tx_buffer_index) <= '0';
+ end if;
+
+ if ready = '1' and valid_i = '1' then
+ next_tx_buffers_filled(curr_saving_buffer_index) <= '1';
+ end if;
+ end process set_next_buffer_filled;
+
+ set_next_state: process(curr_state, scl_delayed_pulse, scl_scl, tx_buffer_filled, valid_i) is
+ variable start_sending : std_logic := '0';
+ begin -- process set_next_state
+ next_state <= curr_state;
+
+ if curr_state = WAITING_FOR_FALLING_EDGE then
+ if scl_delayed_pulse = '1' then
+ next_state <= SENDING;
+ end if;
+ elsif curr_state = SENDING then
+ if curr_index = 7 and scl_delayed_pulse = '1' then
+ next_state <= IDLE;
+ end if;
+ elsif curr_state = WAITING_FOR_DATA then
+ if valid_i = '1' then
+ start_sending := '1';
+ end if;
+ end if;
+
+ if start_write_i = '1' then
+ if tx_buffer_filled = '1' then
+ start_sending := '1';
+ else
+ next_state <= WAITING_FOR_DATA;
+ end if;
+ end if;
+
+ if start_sending = '1' then
+ if curr_scl = '0' then
+ next_state <= SENDING;
+ else
+ next_state <= WAITING_FOR_FALLING_EDGE;
+ end if;
+ end if;
+ end process set_next_state;
+
+ set_regs: process (clk_i) is
+ begin -- process set_next
+ if rising_edge(clk_i) then -- rising clock edge
+ if rst_in = '0' then -- synchronous reset (active low)
+ curr_state <= IDLE;
+ curr_tx_buffers <= (others => (others => '0'));
+ curr_tx_buffer_index <= 0;
+ curr_tx_buffers_filled <= "00";
+ curr_bit_index <= 0;
+ curr_scl <= '1'; -- assume 1 (the default, no one transmitting)
+ else
+ curr_state <= next_state;
+ curr_tx_buffers <= next_tx_buffers;
+ curr_tx_buffer_index <= next_tx_buffer_index;
+ curr_tx_buffers_filled <= next_tx_buffers_filled;
+ curr_bit_index <= next_bit_index;
+ curr_scl <= next_scl;
+ end if;
+ end if;
+ end process set_regs;
+
+end architecture a1;