i2cdrv.vhd
来自「DesignWave 2005 8 Verilog Example」· VHDL 代码 · 共 316 行
VHD
316 行
--------------------------------------------------------------------------------
-- i2cDrv (i2c driver)
-- Takashi Kohno (DigiCat)
-- Rev. 0.5.0c / 27, May., 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 ;
entity i2cDrv is
port( CLK, nRST, syncRST : in std_logic ;
CKE : in std_logic ; -- CLK enable for sampling clock
-- i2c Bus
SCLout, SDAout : out std_logic ;
-- from i2cRcv
rcvSCL, rcvSDA : in std_logic ;
-- i2cDrv I/F
BSY : out std_logic ;
gSTR : in std_logic ;
gDTR : in std_logic ;
gSTP : in std_logic ;
gRSR : in std_logic ;
gDTW : in std_logic ;
Data : in std_logic ;
ABT : in std_logic ;
COL : out std_logic ;
Spre : in std_logic_vector(3 downto 0) ;
Spos : in std_logic_vector(3 downto 0) ;
Tlow : in std_logic_vector(3 downto 0) ;
Thig : in std_logic_vector(3 downto 0) ;
Dhol : in std_logic_vector(1 downto 0)
) ;
end i2cDrv ;
architecture RTL of i2cDrv is
type i2cDrvState is (drvIdle, drvSSS, drvSSH, drvDTW, drvDTL, drvDTT, drvDTH, drvPTL, drvPSS, drvPSH, drvSTL, drvCLD) ;
signal DQ : i2cDrvState ;
signal efPerCnt, inPerCnt : std_logic_vector(3 downto 0) ; -- SCLK counters for SCL
signal efEOC, inEOC : std_logic ;
signal DholCnt : std_logic_vector(1 downto 0) ; -- SCLK counter for SDA
signal dhEOC : std_logic ;
signal vData : std_logic ;
signal iBSY : std_logic ;
begin
-- Root Sequencer for i2cDrv
i2cDrvRootSeq: process(CLK, nRST)
begin
if nRST = '0' then
DQ <= drvIdle ;
elsif rising_edge(CLK) then
if syncRST = '1' or ABT = '1' then
DQ <= drvIdle ;
elsif CKE = '1' then
if iBSY = '0' then -- Idle or the Last CLK
if gSTR = '1' then
DQ <= drvSSS ;
elsif gDTW = '1' then
DQ <= drvDTW ;
elsif gDTR = '1' then
DQ <= drvDTL ;
elsif gRSR = '1' then
DQ <= drvSTL ;
elsif gSTP = '1' then
DQ <= drvPTL ;
else
DQ <= drvIdle ;
end if ;
else
case DQ is
when drvSSS =>
if rcvSDA = '0' or (inEOC = '1' and rcvSCL = '1') then
DQ <= drvSSH ;
end if ;
when drvSSH =>
if rcvSCL = '0' then
DQ <= drvCLD ;
end if ;
when drvDTW =>
when drvDTL =>
if inEOC = '1' then
DQ <= drvDTT ;
end if ;
when drvDTT =>
if inEOC = '1' and rcvSCL = '1' then
DQ <= drvDTH ;
end if ;
when drvDTH =>
if rcvSCL = '0' then
DQ <= drvIdle ;
end if ;
when drvPTL =>
if inEOC = '1' then
DQ <= drvPSS ;
end if ;
when drvPSS =>
if inEOC = '1' and rcvSCL = '1' then
DQ <= drvPSH ;
end if ;
when drvPSH =>
if rcvSCL = '0' then
DQ <= drvCLD ;
end if ;
when drvSTL =>
if inEOC = '1' then
DQ <= drvSSS ;
end if ;
when drvCLD =>
when others =>
DQ <= drvIdle ;
end case ;
end if ;
end if ;
end if ;
end process ;
iBSY <= '0' when DQ = drvIdle or (efEOC = '1' and CKE = '1') else
'1' ;
-- Sample Clock Counter (Generates EOCs)
SCLPerCounter: process(CLK, nRST)
begin
if nRST = '0' then
efPerCnt <= "0000" ;
inPerCnt <= "0000" ;
elsif rising_edge(CLK) then
if syncRST = '1' then
efPerCnt <= "0000" ;
inPerCnt <= "0000" ;
elsif CKE = '1' then
if iBSY = '0' then
if gSTR = '1' then
efPerCnt <= Spos ;
inPerCnt <= Spre ;
elsif gDTR = '1' or gDTW = '1' then
efPerCnt <= Thig ;
inPerCnt <= Tlow ;
elsif gSTP = '1' or gRSR = '1' then
efPerCnt <= Spos ;
inPerCnt <= Tlow ;
end if ;
else
case DQ is
when drvSSS | drvPSS =>
if rcvSCL = '0' then
inPerCnt <= Spre ;
else
inPerCnt <= unsigned(inPerCnt) - 1 ;
end if ;
when drvSSH | drvDTH =>
efPerCnt <= unsigned(efPerCnt) - 1 ;
when drvDTL =>
if inEOC = '0' then
inPerCnt <= unsigned(inPerCnt) - 1 ;
else
inPerCnt <= "0001" ;
end if ;
when drvDTT =>
if inEOC = '0' then
inPerCnt <= unsigned(inPerCnt) - 1 ;
end if ;
when drvPTL | drvSTL =>
if inEOC = '0' then
inPerCnt <= unsigned(inPerCnt) - 1 ;
else
inPerCnt <= Spre ;
end if ;
when drvPSH =>
if rcvSDA = '0' then
efPerCnt <= Spos ;
else
efPerCnt <= unsigned(efPerCnt) - 1 ;
end if ;
when drvDTW =>
if gDTW = '0' then
efPerCnt <= (others => '0') ;
end if ;
when others =>
end case ;
end if ;
end if ;
end if ;
end process ;
efEOC <= '1' when efPerCnt = "0000" else
'0' ;
inEOC <= '1' when inPerCnt = "0000" else
'0' ;
-- SCL Generator
SCLout <= '0' when DQ = drvDTW or DQ = drvDTL or DQ = drvSTL or DQ = drvPTL else
'1' ;
-- SDA Generator
SDADriver: process(CLK, nRST)
begin
if nRST = '0' then
SDAout <= '1' ;
elsif rising_edge(CLK) then
if syncRST = '1' then
SDAout <= '1' ;
elsif CKE = '1' then
if ABT = '1' then
SDAout <= '1' ;
elsif dhEOC = '1' then
SDAout <= vData ;
end if ;
end if ;
end if ;
end process ;
SDAPerCounter: process(CLK, nRST)
begin
if nRST = '0' then
DholCnt <= (others => '0') ;
elsif rising_edge(CLK) then
if syncRST = '1' then
DholCnt <= (others => '0') ;
elsif CKE = '1' then
if iBSY = '0' then
DholCnt <= (others => '0') ;
else
if dhEOC = '0' then
DholCnt <= unsigned(DholCnt) + 1 ;
end if ;
end if ;
end if ;
end if ;
end process ;
dhEOC <= '1' when DholCnt = Dhol else
'0' ;
VaildData: process(CLK, nRST)
begin
if nRST = '0' then
vData <= '1' ;
elsif rising_edge(CLK) then
if syncRST = '1' then
vData <= '1' ;
elsif CKE = '1' then
if ABT = '1' then
vData <= '1' ;
elsif iBSY = '0' then
if gDTR = '1' or gDTW = '1' then
vData <= Data ;
elsif gSTP = '1' then
vData <= '0' ;
else
vData <= '1' ;
end if ;
else
case DQ is
when drvSSS =>
if inEOC = '1' then
vData <= '0' ;
end if ;
when drvPSS =>
if inEOC = '1' then
vData <= '1' ;
end if ;
when others =>
end case ;
end if ;
end if ;
end if ;
end process ;
-- Output generator
BSY <= iBSY ;
COL <= '1' when DQ = drvCLD else
'0' ;
end RTL ;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?