Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -----------------------------------------------------------------------------
- -- I2C Master
- -----------------------------------------------------------------------------
- -- PA1 11 oct 2019 SvH Initial empty version
- -- PA2 23 oct 2019 SvH Corrected IO (removed ADR and added STOP)
- -- Added alternative pad implementation for SDA
- -----------------------------------------------------------------------------
- library ieee;
- use ieee.std_logic_1164.all;
- use ieee.numeric_std.all;
- use ieee.std_logic_unsigned.all;
- -- I2C master
- entity I2C_MASTER is
- port(
- -- inputs
- CLK :in std_logic; -- System Clock
- RST :in std_logic; -- Sync reset active high
- EN :in std_logic; -- Enable
- WR_N :in std_logic; -- 0=Write, 1=Read
- DELAY :in std_logic_vector(7 downto 0); -- Delay configuration
- STOP :in std_logic; -- Generate STOP sequense after access
- WR_BYTE :in std_logic_vector(7 downto 0); -- write byte
- -- I2C bus
- SDA :inout std_logic; -- I2C Data
- SCL :out std_logic; -- I2C Clock
- -- outputs
- DONE :out std_logic; -- I2C Master Done
- IDLE :out std_logic; -- I2C Master Idle
- NO_ACK :out std_logic; -- No Ack received from I2C Slave
- RD_BYTE :out std_logic_vector(7 downto 0) -- read byte
- );
- end I2C_MASTER;
- architecture RTL of I2C_MASTER is
- signal SDA_OE : std_logic;
- signal SDA_OUT : std_logic;
- signal SDA_IN : std_logic;
- type t_STATE is (s_IDLE, s_START1, s_START2, s_D_SU, s_D_HIGH, s_D_HOLD, s_A_SU, s_A_HIGH, s_A_HOLD, s_STOP1, s_STOP2);
- signal STATE : t_STATE;
- signal DELAY_CNT : std_logic_vector(7 downto 0);
- signal DELAY_DONE : std_logic;
- signal BIT_CNT : integer range 0 to 7;
- begin
- --delay counter
- delay_proc : process(CLK)
- begin
- if rising_edge(CLK) then
- if RST = '1' or DELAY_DONE = '1' or STATE = s_IDLE then
- DELAY_CNT <= (others => '0');
- end if;
- else
- DELAY_CNT <= DELAY_CNT + 1;
- end if;
- end process;
- DELAY_DONE <= '1' when DELAY_CNT = DELAY else '0';
- --bit counter
- bit_counter : process(CLK)
- begin
- if rising_edge(CLK) then
- if RST = '1' or STATE = s_IDLE then
- BIT_CNT <= 7;
- elsif STATE = s_D_HOLD and DELAY_DONE = '1' then
- BIT_CNT <= BIT_CNT - 1;
- end if;
- end if;
- end process;
- --control FSM
- fsm_proc : process(CLK)
- begin
- if rising_edge(CLK) then
- if RST = '1' then
- STATE <= s_IDLE;
- end if;
- else
- case STATE is
- when s_IDLE =>
- if EN = '1' then
- SDA_OUT <= '1';
- SCL <= '1';
- STATE <= s_START1;
- end if;
- when s_START1 =>
- if DELAY_DONE = '1' then
- SDA_OE <= '1';
- SDA_OUT <= '0';
- SCL <= '1';
- STATE <= s_START2;
- end if;
- when s_START2 =>
- if DELAY_DONE = '1' then
- SDA_OUT <= '0';
- SCL <= '1';
- STATE <= s_D_SU;
- end if;
- when s_D_SU =>
- if DELAY_DONE = '1' then
- STATE <= s_D_HIGH;
- end if;
- when s_D_HIGH =>
- if DELAY_DONE = '1' then
- STATE <= s_D_HOLD;
- end if;
- when s_D_HOLD =>
- if DELAY_DONE = '1' then
- if BIT_CNT = 0 then
- STATE <= s_A_SU;
- else
- STATE <= s_D_SU;
- end if;
- end if;
- when s_A_SU =>
- if DELAY_DONE = '1' then
- STATE <= s_A_HIGH;
- end if;
- when s_A_HIGH =>
- if DELAY_DONE = '1' then
- STATE <= s_A_HOLD;
- end if;
- when s_A_HOLD =>
- if DELAY_DONE = '1' then
- STATE <= s_STOP1;
- end if;
- when s_STOP1 =>
- if DELAY_DONE = '1' then
- STATE <= s_STOP2;
- end if;
- when s_STOP2 =>
- if DELAY_DONE = '1' then
- STATE <= s_IDLE;
- end if;
- end case;
- end if;
- end process;
- -- Her kommer ditt design :-)
- -- Bidirectional Pad
- SDA_IN <= SDA;
- -- implementation with active drive (less confusing)
- SDA <= SDA_OUT when SDA_OE = '1' else 'Z';
- -- implementation with no drive to high level (pullup)
- --SDA <= '0' when SDA_OE = '1' and SDA_OUT = '0' else 'Z';
- end RTL;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement