Line 1... |
Line 1... |
-- #################################################################################################
|
-- #################################################################################################
|
-- # << NEORV32 - Two-Wire Interface Master (TWI) >> #
|
-- # << NEORV32 - Two-Wire Interface Controller (TWI) >> #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # Supports START and STOP conditions, 8 bit data + ACK/NACK transfers and clock stretching. #
|
-- # Supports START and STOP conditions, 8 bit data + ACK/NACK transfers and clock stretching. #
|
-- # Supports ACKs by the master. No multi-master support and no slave mode support yet! #
|
-- # Supports ACKs by the constroller. No multi-controller support and no peripheral mode support #
|
-- # Interrupt: TWI_transfer_done #
|
-- # yet. Interrupt: TWI_transfer_done #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # BSD 3-Clause License #
|
-- # BSD 3-Clause License #
|
-- # #
|
-- # #
|
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
|
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
|
-- # #
|
-- # #
|
Line 77... |
Line 77... |
constant ctrl_twi_stop_c : natural := 2; -- -/w: Generate STOP condition
|
constant ctrl_twi_stop_c : natural := 2; -- -/w: Generate STOP condition
|
constant ctrl_twi_irq_en_c : natural := 3; -- r/w: transmission done interrupt
|
constant ctrl_twi_irq_en_c : natural := 3; -- r/w: transmission done interrupt
|
constant ctrl_twi_prsc0_c : natural := 4; -- r/w: CLK prsc bit 0
|
constant ctrl_twi_prsc0_c : natural := 4; -- r/w: CLK prsc bit 0
|
constant ctrl_twi_prsc1_c : natural := 5; -- r/w: CLK prsc bit 1
|
constant ctrl_twi_prsc1_c : natural := 5; -- r/w: CLK prsc bit 1
|
constant ctrl_twi_prsc2_c : natural := 6; -- r/w: CLK prsc bit 2
|
constant ctrl_twi_prsc2_c : natural := 6; -- r/w: CLK prsc bit 2
|
constant ctrl_twi_mack_c : natural := 7; -- r/w: generate ACK by master for transmission
|
constant ctrl_twi_mack_c : natural := 7; -- r/w: generate ACK by controller for transmission
|
--
|
--
|
constant ctrl_twi_ack_c : natural := 30; -- r/-: Set if ACK received
|
constant ctrl_twi_ack_c : natural := 30; -- r/-: Set if ACK received
|
constant ctrl_twi_busy_c : natural := 31; -- r/-: Set if TWI unit is busy
|
constant ctrl_twi_busy_c : natural := 31; -- r/-: Set if TWI unit is busy
|
|
|
-- access control --
|
-- access control --
|
Line 199... |
Line 199... |
|
|
-- serial engine --
|
-- serial engine --
|
-- TWI bus signals are set/sampled using 4 clock phases
|
-- TWI bus signals are set/sampled using 4 clock phases
|
case arbiter is
|
case arbiter is
|
|
|
when "100" => -- IDLE: waiting for requests, bus might be still claimed by this master if no STOP condition was generated
|
when "100" => -- IDLE: waiting for requests, bus might be still claimed by this controller if no STOP condition was generated
|
twi_bitcnt <= (others => '0');
|
twi_bitcnt <= (others => '0');
|
if (wr_en = '1') then
|
if (wr_en = '1') then
|
if (addr = twi_ctrl_addr_c) then
|
if (addr = twi_ctrl_addr_c) then
|
if (data_i(ctrl_twi_start_c) = '1') then -- issue START condition
|
if (data_i(ctrl_twi_start_c) = '1') then -- issue START condition
|
arbiter(1 downto 0) <= "01";
|
arbiter(1 downto 0) <= "01";
|
elsif (data_i(ctrl_twi_stop_c) = '1') then -- issue STOP condition
|
elsif (data_i(ctrl_twi_stop_c) = '1') then -- issue STOP condition
|
arbiter(1 downto 0) <= "10";
|
arbiter(1 downto 0) <= "10";
|
end if;
|
end if;
|
elsif (addr = twi_rtx_addr_c) then -- start a data transmission
|
elsif (addr = twi_rtx_addr_c) then -- start a data transmission
|
-- one bit extra for ack, issued by master if ctrl_twi_mack_c is set,
|
-- one bit extra for ack, issued by controller if ctrl_twi_mack_c is set,
|
-- sampled from slave if ctrl_twi_mack_c is cleared
|
-- sampled from peripheral if ctrl_twi_mack_c is cleared
|
if (ben_i(0) = '1') then
|
if (ben_i(0) = '1') then
|
twi_rtx_sreg <= data_i(7 downto 0) & (not ctrl(ctrl_twi_mack_c));
|
twi_rtx_sreg <= data_i(7 downto 0) & (not ctrl(ctrl_twi_mack_c));
|
arbiter(1 downto 0) <= "11";
|
arbiter(1 downto 0) <= "11";
|
end if;
|
end if;
|
end if;
|
end if;
|
Line 277... |
Line 277... |
|
|
-- Clock Stretching Detector --------------------------------------------------------------
|
-- Clock Stretching Detector --------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
clock_stretching: process(arbiter, twi_scl_o, twi_scl_i_ff1)
|
clock_stretching: process(arbiter, twi_scl_o, twi_scl_i_ff1)
|
begin
|
begin
|
-- clock stretching by the slave can happen at "any time"
|
-- clock stretching by the peripheral can happen at "any time"
|
if (arbiter(2) = '1') and -- module enabled
|
if (arbiter(2) = '1') and -- module enabled
|
(twi_scl_o = '1') and -- master wants to pull scl high
|
(twi_scl_o = '1') and -- controller wants to pull scl high
|
(twi_scl_i_ff1 = '0') then -- but scl is pulled low by slave
|
(twi_scl_i_ff1 = '0') then -- but scl is pulled low by peripheral
|
twi_clk_halt <= '1';
|
twi_clk_halt <= '1';
|
else
|
else
|
twi_clk_halt <= '0';
|
twi_clk_halt <= '0';
|
end if;
|
end if;
|
end process clock_stretching;
|
end process clock_stretching;
|