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 + -
显示快捷键?