OpenCores
URL https://opencores.org/ocsvn/System09/System09/trunk

Subversion Repositories System09

[/] [System09/] [trunk/] [rtl/] [VHDL/] [twi-master.vhd] - Rev 223

Go to most recent revision | Compare with Previous | Blame | View Log

--===========================================================================--
--
-- SYNTHEZIABLE VHDL TWO WIRE INTERFACE
--
--===========================================================================
--
-- This core adheres to the GNU public license  
--
-- Design units   : TWI Master core
--
-- File name      : twi.vhd
--
-- Purpose        : Implements an I2C master Interface 
--                  
-- Dependencies   : ieee.std_logic_1164
--                  ieee.numeric_std
--                  unisim.vcomponents
--
-- Revision list  :
--
-- Version Author        Date         Changes
--
-- 0.1     John Kent     2010-05-04   New model
--
--         dilbert57@opencores.org
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library unisim;
      use unisim.vcomponents.all;
 
-----------------------------------------------------------------------
-- Entity for TWI                                                    --
-----------------------------------------------------------------------
 
entity twi is
  generic (
    CLK_FREQ : integer := 25_000_000;
  );
 
  port (
    --
    -- CPU signals
    --
    clk      : in  std_logic;                     -- System Clock
    rst      : in  std_logic;                     -- Reset input (active high)
    cs       : in  std_logic;                     -- Chip Select
    rw       : in  std_logic;                     -- Read / Not Write
    irq      : out std_logic;                     -- Interrupt
    addr     : in  std_logic;                     -- Register Select
    data_in  : in  std_logic_vector(7 downto 0);  -- Data Bus In 
    data_out : out std_logic_vector(7 downto 0);  -- Data Bus Out
 
    -- I2C Signals
    --
    scl     : inout std_logic;                    -- serial clock
    sda     : inout std_logic                     -- serial data
    );
end twi;  
 
-------------------------------------------------------------------------------
-- Architecture for Two Wire Interface registers
-------------------------------------------------------------------------------
 
architecture rtl of twi is
 
  -----------------------------------------------------------------------------
  -- Signals
  -----------------------------------------------------------------------------
 
  ----------------------------------------------------------------------
  --  Status Register: twi_status_reg 
  ----------------------------------------------------------------------
  --
  -- IO address + 0 Read
  --
  --+-------+-------+-------+-------+-------+-------+-------+-------+
  --| RXIRQ | TXIRQ | ACKE  |       |       |       | TXRDY | RXRDY |
  --+-------+-------+-------+-------+-------+-------+-------+-------+
  -- RXIRQ - Bit[7] - Receive Interrupt Request
  -- TXIRQ - Bit[6] - Transmit Interrupt Request
  -- ACKE  - Bit[5] - Acknowledge Error
  -- TXRDY - Bit[1] - Transmit Ready (byte transmitted)
  -- RXRDY - Bit[0] - Receive Ready (byte received)
  -- 
  signal twi_status_reg : std_logic_vector(7 downto 0) := (others => '0');
 
  ----------------------------------------------------------------------
  --  Control Register: twi_control_reg
  ----------------------------------------------------------------------
  --
  -- IO address + 0 Write
  --
  --+--------+-------+--------+--------+--------+--------+--------+--------+
  --|  RXIE  | TXIE  | TWPS(1)| TWPS(0)| TWBR(3)| TWBR(2)| TWBR(1)| TWBR(0)|
  --+--------+-------+--------+--------+--------+--------+--------+--------+
  -- RXIE - Bit[7]
  -- 0       - Rx Interrupt disabled
  -- 1       - Rx Interrupt enabled
  -- TXIE - Bit[6]
  -- 0       - Tx Interrupt disabled
  -- 1       - Tx Interrupt enabled
  --
  -- SCL frequency = CPU Clock Frequency / ( 16 + 2(TWBR) . 4^TWPS)
  --
  -- TWPS - Bits[5..4]
  -- 0 0     - Prescale by  1
  -- 0 1     - Prescale by  4
  -- 1 0     - Prescale by 16
  -- 1 1     - Prescale by 64
  --
  -- TWBR - Bits[3..0]
  -- 0 0 0 0   - Baud Clk divide by  1
  -- 0 0 0 1   - Baud Clk divide by  2
  -- 0 0 1 0   - Baud Clk divide by  3
  -- 0 0 1 1   - Baud Clk divide by  4
  -- 0 1 0 0   - Baud Clk divide by  5
  -- 0 1 0 1   - Baud Clk divide by  6
  -- 0 1 1 0   - Baud Clk divide by  7
  -- 0 1 1 1   - Baud Clk divide by  8
  -- 1 0 0 0   - Baud Clk divide by  9
  -- 1 0 0 1   - Baud Clk divide by 10
  -- 1 0 1 0   - Baud Clk divide by 11
  -- 1 0 1 1   - Baud Clk divide by 12
  -- 1 1 0 0   - Baud Clk divide by 13
  -- 1 1 0 1   - Baud Clk divide by 14
  -- 1 1 1 0   - Baud Clk divide by 15
  -- 1 1 1 1   - Baud Clk divide by 16
 
 
  signal twi_control_reg : std_logic_vector(7 downto 0) := (others => '0'); -- control register
 
  ----------------------------------------------------------------------
  -- Receive Register
  ----------------------------------------------------------------------
  --
  -- IO address + 1     Read
  --
  signal twi_rx_reg : std_logic_vector(7 downto 0) := (others => '0');
 
  ----------------------------------------------------------------------
  -- Transmit Register
  ----------------------------------------------------------------------
  --
  -- IO address + 1     Write
  --
  signal twi_tx_reg : std_logic_vector(7 downto 0) := (others => '0');
 
  signal Reset    : std_logic;          -- Reset (Software & Hardware)
  signal RxRst    : std_logic;          -- Receive Reset (Software & Hardware)
  signal TxRst    : std_logic;          -- Transmit Reset (Software & Hardware)
  signal TxDbit   : std_logic;          -- Transmit data bit
  signal RxDR     : std_logic := '0';   -- Receive Data ready
  signal TxIdle   : std_logic;          -- Transmitter idle
  signal TxBE     : std_logic := '0';   -- Transmit buffer empty
  signal TxAck    : std_logic;          -- Byte transmitted to transmitter
  --
  signal FErr     : std_logic := '0';   -- Frame error
  signal OErr     : std_logic := '0';   -- Output error
  signal PErr     : std_logic := '0';   -- Parity Error
  --
  signal TxIEnb   : std_logic := '0';   -- Transmit interrupt enable
  signal RxIEnb   : std_logic := '0';   -- Receive interrupt enable
  --
  signal ReadRR   : std_logic := '0';   -- Read receive buffer
  signal WriteTR  : std_logic := '0';   -- Write transmit buffer
  signal ReadSR   : std_logic := '0';   -- Read Status register
  --
  signal DCDState : DCD_State_Type;     -- DCD Reset state sequencer
  signal DCDDel   : std_logic := '0';   -- Delayed DCD_n
  signal DCDEdge  : std_logic := '0';   -- Rising DCD_N Edge Pulse
  signal DCDInt   : std_logic := '0';   -- DCD Interrupt
 
begin
  -----------------------------------------------------------------------------
  -- Instantiation of internal components
  -----------------------------------------------------------------------------
 
  RxDev : entity ACIA_RX port map (
    Clk    => clk,
    RxRst  => RxRst,
    RxRd   => ReadRR,
    WdFmt  => CtrlReg(4 downto 2),
    BdFmt  => CtrlReg(1 downto 0),
    RxClk  => RxC,
    RxDat  => RxD,
    RxFErr => FErr,
    RxOErr => OErr,
    RxPErr => PErr,
    RxRdy  => RxDR,
    RxDout => RecvReg
   );
 
  TxDev : entity ACIA_TX port map (
    Clk   => clk,
    Reset => TxRst,
    Wr    => WriteTR,
    Din   => TxReg,
    WdFmt => CtrlReg(4 downto 2),
    BdFmt => CtrlReg(1 downto 0),
    TxClk => TxC,
    Dat   => TxDbit,
    Empty => TxIdle
   );
 
---------------------------------------------------------------
-- ACIA Reset may be hardware or software
---------------------------------------------------------------
  ACIA_Reset : process(clk, rst)
  begin
    -- Asynchronous External reset
    if rst = '1' then
      Reset <= '1';
    elsif falling_edge(clk) then
      -- Synchronous Software reset
      Reset <= CtrlReg(1) and CtrlReg(0);
    end if;              
 
  end process;
 
  -- Transmitter reset
  TxRst <= Reset;
  -- Receiver reset
  RxRst <= Reset or DCD_n;
 
  -----------------------------------------------------------------------------
  -- ACIA Status Register
  -----------------------------------------------------------------------------
 
  ACIA_Status : process(Reset, clk)
  begin
    if Reset = '1' then
      StatReg <= (others => '0');
    elsif falling_edge(clk) then
      StatReg(0) <= RxDR;                  -- Receive Data Ready
      StatReg(1) <= TxBE and (not CTS_n);  -- Transmit Buffer Empty
      StatReg(2) <= DCDInt;                -- Data Carrier Detect
      StatReg(3) <= CTS_n;                 -- Clear To Send
      StatReg(4) <= FErr;                  -- Framing error
      StatReg(5) <= OErr;                  -- Overrun error
      StatReg(6) <= PErr;                  -- Parity error
      StatReg(7) <= (RxIEnb and RxDR) or
                    (RxIEnb and DCDInt) or
                    (TxIEnb and TxBE);
    end if;
  end process;
 
 
-----------------------------------------------------------------------------
-- ACIA Transmit Control
-----------------------------------------------------------------------------
 
  ACIA_Control : process(CtrlReg, TxDbit)
  begin
    case CtrlReg(6 downto 5) is
      when "00" =>                      -- Disable TX Interrupts, Assert RTS
        TxD    <= TxDbit;
        TxIEnb <= '0';
      when "01" =>                      -- Enable TX interrupts, Assert RTS
        TxD    <= TxDbit;
        TxIEnb <= '1';
      when "10" =>                      -- Disable Tx Interrupts, Clear RTS
        TxD    <= TxDbit;
        TxIEnb <= '0';
      when "11" =>                      -- Disable Tx interrupts, Assert RTS, send break
        TxD    <= '0';
        TxIEnb <= '0';
      when others =>
        null;
    end case;
 
    RxIEnb <= CtrlReg(7);
  end process;
 
  tx_process : process(clk, reset)
  begin
    if reset = '1' then
      WriteTR <= '0';
      TxAck   <= '0';
    elsif falling_edge(clk) then
      WriteTR <= '0';
      TxAck   <= '0';
      if TxBE = '0' and TxIdle = '1' then
        WriteTR <= '1';
        TxAck   <= '1';
      end if;
    end if;
  end process;
 
-----------------------------------------------------------------------------
-- Generate Read / Write strobes.
-----------------------------------------------------------------------------
 
  ACIA_Read_Write : process(clk, Reset)
  begin
    if reset = '1' then
      CtrlReg <= (others => '0');
      TxReg   <= (others => '0');
      ReadRR  <= '0';
      ReadSR  <= '0';
      TxBE    <= '1';
    elsif falling_edge(clk) then
      ReadRR <= '0';
      ReadSR <= '0';
      if TxAck = '1' then
        TxBE <= '1';
      end if;
      if cs = '1' then
        if Addr = '0' then              -- Control / Status register
          if rw = '0' then              -- write control register
            CtrlReg <= DataIn;
          else                          -- read status register
            ReadSR <= '1';
          end if;
        else                            -- Data Register
          if rw = '0' then              -- write transmiter register
            TxReg <= DataIn;
            TxBE  <= '0';
          else                          -- read receiver register
            ReadRR <= '1';
          end if;
        end if;
      end if;
    end if;
  end process;
 
---------------------------------------------------------------
-- Set Data Output Multiplexer
--------------------------------------------------------------
 
  ACIA_Data_Mux : process(Addr, RecvReg, StatReg)
  begin
    if Addr = '1' then
      DataOut <= RecvReg;               -- read receiver register
    else
      DataOut <= StatReg;               -- read status register
    end if;
  end process;
 
  irq <= StatReg(7);
 
---------------------------------------------------------------
-- Data Carrier Detect Edge rising edge detect
---------------------------------------------------------------
  ACIA_DCD_edge : process(reset, clk)
  begin
    if reset = '1' then
      DCDEdge <= '0';
      DCDDel  <= '0';
    elsif falling_edge(clk) then
      DCDDel  <= DCD_n;
      DCDEdge <= DCD_n and (not DCDDel);
    end if;
  end process;
 
 
---------------------------------------------------------------
-- Data Carrier Detect Interrupt
---------------------------------------------------------------
-- If Data Carrier is lost, an interrupt is generated
-- To clear the interrupt, first read the status register
--      then read the data receive register
 
  ACIA_DCD_Int : process(reset, clk)
  begin
    if reset = '1' then
      DCDInt   <= '0';
      DCDState <= DCD_State_Idle;
    elsif falling_edge(clk) then
      case DCDState is
        when DCD_State_Idle =>
          -- DCD Edge activates interrupt
          if DCDEdge = '1' then
            DCDInt   <= '1';
            DCDState <= DCD_State_Int;
          end if;
        when DCD_State_Int =>
          -- To reset DCD interrupt, 
          -- First read status
          if ReadSR = '1' then
            DCDState <= DCD_State_Reset;
          end if;
        when DCD_State_Reset =>
          -- Then read receive register
          if ReadRR = '1' then
            DCDInt   <= '0';
            DCDState <= DCD_State_Idle;
          end if;
        when others =>
          null;
      end case;
    end if;
  end process;
 
  rts_n <= RxDR;
 
end rtl;
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.