📄 i2cslave.vhd
字号:
--------------------------------------------------------------------------------
-- i2cSlave (i2c Slave Unit)
-- Takashi Kohno (DigiCat)
-- Rev. 0.5.0c / 20, Jun., 2005
--
----------------------------------------
--
-- Copyright (c) 2005 Takashi Kohno
-- This design is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License
-- as published by the Free Software Foundation; either version 2
-- of the License, or any later version.
--
-- This design is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
--
--------------------------------------------------------------------------------
library IEEE ;
use IEEE.std_logic_1164.all ;
use IEEE.std_logic_arith.all ;
use WORK.i2cBasics.all ;
entity i2cSlave is
port( CLK, nRST, syncRST : in std_logic ;
CKE : in std_logic ; -- CLK enable for sampling clock
-- i2c bus
SCL, SDA : in std_logic ;
slvSCL, slvSDA : out std_logic ;
-- Local bus for slave functions
-- Transaction detection
SReq : out std_logic ;
Si2cAdrs : out std_logic_vector(6 downto 0) ;
SRnW : out std_logic ;
SAck : in std_logic ;
-- Slave write stream
SwrDReq : out std_logic ;
SwrData : out std_logic_vector(7 downto 0) ;
SwrTerm : in std_logic ;
SwrDRdy : in std_logic ;
-- Slave read stream
SrdDReq : out std_logic ;
SrdData : in std_logic_vector(7 downto 0) ;
SrdDRdy : in std_logic ;
-- Status Reports
srpTerm : out std_logic ;
srpAbort : out std_logic ;
srpBFree : out std_logic ;
srpBObsc : out std_logic ;
-- Timing Parameters
Dsup : in std_logic_vector(1 downto 0)
) ;
end i2cSlave ;
architecture RTL of i2cSlave is
-- component I/F signals
-- for i2cStDec
signal BSQ : i2cBusState ;
signal BoSCH : std_logic ;
signal EoSCH : std_logic ;
signal STAC : std_logic ;
signal STPC : std_logic ;
signal ReceivedData : std_logic_vector(7 downto 0) ;
signal FirstSBit : std_logic ;
signal LastSBit : std_logic ;
signal vSCL, vSDA : std_logic ;
signal BFree, BObsc : std_logic ;
-- Signals for i2cSlave
type SlaveFunctionState is (slvIdle, slvQuery, slvTr) ;
signal SQ : SlaveFunctionState ;
type SlaveDTrState is (slvDTrIdle, slvDTrReq, slvDTrWait, slvDTrSetup, slvLoadSDA) ;
signal SDTQ : SlaveDTrState ;
type SlaveDRcState is (slvDRcIdle, slvDRcReq0, slvDRcReq1, slvDRcWait) ;
signal SDRQ : SlaveDRcState ;
signal regSRnW : std_logic ;
signal slvDTR : std_logic_vector(7 downto 0) ; -- Shift Reg. for Data Transmitter
signal slvDsupCntr : std_logic_vector(1 downto 0) ; -- setup timer counter for delayed data
signal iSrdDReq : std_logic ; -- SrdDReq for internal reference
signal regSwrTerm : std_logic ; -- checks SWrTerm while 2clocks after rising_edge(SwrDReq)
begin
-- Component instantiations:
slvStDecUnit: i2cStDec
port map( CLK => CLK, nRST => nRST, syncRST => syncRST,
CKE => CKE,
SCL => SCL, SDA => SDA,
BSQ => BSQ,
BoSCH => BoSCH,
EoSCH => EoSCH,
STAC => STAC,
STPC => STPC,
ReceivedData => ReceivedData,
FirstSBit => FirstSBit,
LastSBit => LastSBit,
vSCL => vSCL, vSDA => vSDA,
BFree => BFree, BObsc => BObsc
) ;
---------------------------------------------------------------------------------------------------
-- Transaction detector
---------------------------------------------------------------------------------------------------
-- Root sequencer for slave functions
SlaveFuncitionRootSeq: process(CLK, nRST)
begin
if nRST = '0' then
SQ <= slvIdle ;
elsif rising_edge(CLK) then
if syncRST = '1' then
SQ <= slvIdle ;
else
case SQ is
when slvIdle =>
if BSQ = ATR and LastSBit = '1' then
if BoSCH = '1' then
SQ <= slvQuery ;
end if ;
end if ;
when slvQuery =>
if SAck = '1' then
SQ <= slvTr ;
elsif EoSCH = '1' then
SQ <= slvIdle ;
end if ;
when slvTr =>
if STPC = '1' or STAC = '1' then
SQ <= slvIdle ;
end if ;
when others =>
SQ <= slvIdle ;
end case ;
end if ;
end if ;
end process ;
-- Holds the direction of current transaction
SlaveTrDirHolder: process(CLK, nRST)
begin
if nRST = '0' then
regSRnW <= '0' ;
elsif rising_edge(CLK) then
if syncRST = '1' then
regSRnW <= '0' ;
elsif SQ /= slvTr then
regSRnW <= ReceivedData(0) ;
end if ;
end if ;
end process ;
-- Slave query I/F
SReq <= '1' when SQ = slvQuery else
'0' ;
Si2cAdrs <= ReceivedData(7 downto 1) ;
SRnW <= ReceivedData(0) ;
---------------------------------------------------------------------------------------------------
-- SCL and SDA driver
---------------------------------------------------------------------------------------------------
slvSCL <= '0' when SDTQ = slvDTrWait or SDTQ = slvDTrSetup or SDTQ = slvLoadSDA or SDRQ = slvDRcWait else
'1' ;
SlaveSDADriver: process(CLK, nRST)
begin
if nRST = '0' then
slvSDA <= '1' ;
elsif rising_edge(CLK) then
if syncRST = '1' then
slvSDA <= '1' ;
elsif SQ = slvTr then
case BSQ is
when ATR => -- Generates Ack
if LastSBit = '1' and EoSCH = '1' then
slvSDA <= '0' ;
end if ;
when ACK =>
if EoSCH = '1' then
if regSRnW = '1' and iSrdDReq = '0' then
slvSDA <= slvDTR(7) ;
else
slvSDA <= '1' ;
end if ;
end if ;
when DTR =>
if SDTQ = slvLoadSDA then
slvSDA <= slvDTR(7) ;
else
if EoSCH = '1' then
if regSRnW = '1' then -- Slave Read
slvSDA <= slvDTR(7) ;
else -- Slave Write
if LastSBit = '1' then
slvSDA <= regSwrTerm ;
else
slvSDA <= '1' ;
end if ;
end if ;
end if ;
end if ;
when others =>
slvSDA <= '1' ;
end case ;
else
slvSDA <= '1' ;
end if ;
end if ;
end process ;
---------------------------------------------------------------------------------------------------
-- Data Transmitter (for Slave-Read transaction)
---------------------------------------------------------------------------------------------------
-- SrdDxxx I/F (Generates SrdDReq and Convert SrdData to SDA)
SrdDIF: process(CLK, nRST)
begin
if nRST = '0' then
SDTQ <= slvDTrIdle ;
elsif rising_edge(CLK) then
if syncRST = '1' then
SDTQ <= slvDTrIdle ;
else
case SDTQ is
when slvDTrIdle =>
if SQ = slvTr and regSRnW = '1' and BSQ = ACK and BoSCH = '1' then
if vSDA = '0' then -- not EoStr
SDTQ <= slvDTrReq ;
end if ;
end if ;
when slvDTrReq =>
if SrdDRdy = '1' then
if EoSCH = '0' then
SDTQ <= slvDTrIdle ;
else
SDTQ <= slvLoadSDA ;
end if ;
else
if EoSCH = '1' then
SDTQ <= slvDTrWait ;
end if ;
end if ;
when slvDTrWait =>
if SrdDRdy = '1' then
SDTQ <= slvLoadSDA ;
end if ;
when slvLoadSDA =>
SDTQ <= slvDTrSetup ;
when slvDTrSetup =>
if slvDsupCntr = "00" and CKE = '1' then
SDTQ <= slvDTrIdle ;
end if ;
when others =>
SDTQ <= slvDTrIdle ;
end case ;
end if ;
end if ;
end process ;
iSrdDReq <= '1' when SDTQ = slvDTrReq or SDTQ = slvDTrWait else
'0' ;
SrdDReq <= iSrdDReq ;
-- Acquires data setup time for delayed data
DataSetupTimeCounter: process(CLK, nRST)
begin
if nRST = '0' then
slvDsupCntr <= (others => '0') ;
elsif rising_edge(CLK) then
if syncRST = '1' then
slvDsupCntr <= (others => '0') ;
elsif SDTQ = slvDTrSetup then
if CKE = '1' then
slvDsupCntr <= unsigned(slvDsupCntr) - 1 ;
end if ;
else
slvDsupCntr <= Dsup ;
end if ;
end if ;
end process ;
-- Shift Reg. (SrdData -> SDA)
SlaveDTR: process(CLK, nRST)
begin
if nRST = '0' then
slvDTR <= (others => '0') ;
elsif rising_edge(CLK) then
if syncRST = '1' then
slvDTR <= (others => '0') ;
elsif iSrdDReq = '1' and SrdDRdy = '1' then
slvDTr <= SrdData ;
elsif SDTQ = slvLoadSDA or EoSCH = '1' then
slvDTr(7 downto 1) <= slvDTr(6 downto 0) ;
slvDTr(0) <= '1' ;
end if ;
end if ;
end process ;
---------------------------------------------------------------------------------------------------
-- Data Receiver (for Slave-Write transaction)
---------------------------------------------------------------------------------------------------
-- SwrDxxx I/F (Generates SwrDReq)
SwrDIF: process(CLK, nRST)
begin
if nRST = '0' then
SDRQ <= slvDRcIdle ;
elsif rising_edge(CLK) then
if syncRST = '1' then
SDRQ <= slvDRcIdle ;
else
case SDRQ is
when slvDRcIdle =>
if SQ = slvTr and regSRnW = '0' and BSQ = DTR and LastSBit = '1' and BoSCH = '1' then
SDRQ <= slvDRcReq0 ;
end if ;
when slvDRcReq0 =>
if SwrDRdy = '1' then
SDRQ <= slvDRcIdle ;
else
if EoSCH = '1' then
SDRQ <= slvDRcReq1 ;
end if ;
end if ;
when slvDRcReq1 =>
if SwrDRdy = '1' then
SDRQ <= slvDRcIdle ;
elsif EoSCH = '1' then
SDRQ <= slvDRcWait ;
end if ;
when slvDRcWait =>
if SwrDRdy = '1' then
SDRQ <= slvDRcIdle ;
end if ;
when others =>
SDRQ <= slvDRcIdle ;
end case ;
end if ;
end if ;
end process ;
SwrDReq <= '1' when SDRQ = slvDRcReq0 or SDRQ = slvDRcReq1 or SDRQ = slvDRcWait else
'0' ;
SwrData <= ReceivedData ;
-- SwrTerm detector (regSwrTerm <= '1' if SwrTerm = '1' while SDRQ = slvDRcReq0)
-- SwrTerm can be activeted ('0' -> '1') only while SwrDReq = '0' and the first clock of
-- SwrDReq = '1'
DetectSwrTerm: process(CLK ,nRST)
begin
if nRST = '0' then
regSwrTerm <= '0' ;
elsif rising_edge(CLK) then
if syncRST = '1' then
regSwrTerm <= '0' ;
elsif EoSCH = '1' then
regSwrTerm <= '0' ;
elsif SDRQ = slvDRcReq0 then
if SwrTerm = '1' then
regSwrTerm <= '1' ;
end if ;
end if ;
end if ;
end process ;
---------------------------------------------------------------------------------------------------
-- Status Report Holder
---------------------------------------------------------------------------------------------------
SrpHolder: process(CLK, nRST)
begin
if nRST = '0' then
srpTerm <= '0' ;
srpAbort <= '0' ;
elsif rising_edge(CLK) then
if syncRST = '1' or SAck = '1' then
srpTerm <= '0' ;
srpAbort <= '0' ;
elsif SQ = slvTr and (STAC = '1' or STPC = '1') then
case BSQ is
when STP =>
srpTerm <= '1' ;
srpAbort <= '0' ;
when DTR =>
if FirstSBit = '1' then
srpTerm <= '1' ;
srpAbort <= '0' ;
else
srpTerm <= '0' ;
srpAbort <= '1' ;
end if ;
when STR | ATR | ACK =>
srpTerm <= '0' ;
srpAbort <= '1' ;
when others =>
end case ;
end if ;
end if ;
end process ;
srpBFree <= BFree ;
srpBObsc <= BObsc ;
end RTL ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -