⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smbus_control.vhd

📁 可编程器件厂商Xilinx的用于设计SMBus 控制器的源程序
💻 VHD
📖 第 1 页 / 共 3 页
字号:
		if mbcr_wr = '1' then
			maas <= '0';
		elsif state = ACK_HEADER then
			maas <= addr_match;	-- the signal address match compares MADR with I2_ADDR
		else
			maas <= maas;
		end if;
	end if;
end process;

-- MBB - Bus Busy Bit
-- This bit indicates the status of the bus. This bit is set when a START signal is detected and 
-- cleared when a stop signal is detected. It is also cleared on reset. This bit is identical to 
-- the signal bus_busy set in the process set_bus_busy.
mbb <= bus_busy;

-- MAL - Arbitration Lost Bit
-- This bit is set when the arbitration procedure is lost. Arbitration is lost when:
--	1. SDA is sampled low when the master drives high during addr or data transmit cycle
--	2. SDA is sampled low when the master drives high during the acknowledge bit of a 
--		data receive cycle
--	3. A start cycle is attempted when the bus is busy
--	4. A repeated start is requested in slave mode
--	5. A stop condition is detected that the master did not request it.
-- This bit is cleared upon reset and when the software writes a '0' to it
-- Conditions 1 & 2 above simply result in SDA_IN not matching SDA_OUT while SCL is high. This
-- design will not generate a START condition while the bus is busy. When a START is detected, this hardware
-- will set the bus busy bit and gen_start stays set until detect_start asserts, therefore will have
-- to compare with a delayed version of bus_busy. Condition 3 is really just 
-- a check on the uP software control registers as is condition 4. Condition 5 is also taken care
-- of by the fact that SDA_IN does not equal SDA_OUT, however, this process also tests for if a stop
-- condition has been detected when this master did not generate it
mal_bit: process(sys_clk, reset)
begin
	if reset = RESET_ACTIVE  then
		mal <= '0';
	elsif sys_clk'event and sys_clk = '1' then
		if mal_bit_reset = '1' then 
			mal <= '0';
		elsif master_slave = '1' then
			if (arb_lost = '1') or
		   	   (bus_busy_d1 = '1' and gen_start = '1') or
		   	   (detect_stop = '1' and gen_stop = '0' and sm_stop = '0') then
					mal <= '1';
			end if;
		elsif rsta = '1' then
			-- repeated start requested while slave
				mal <= '1';
		end if;
	end if;
end process;

-- SRW - Slave Read/Write Bit
-- When MAAS is set, SRW indicates the value of the R/W command bit of the calling address sent 
-- from the master. This bit is only valid when a complete transfer has occurred and no other 
-- transfers have been initiated. The CPU uses this bit to set the slave transmit/receive mode.
-- This bit is reset by reset
srw_bit: process(sys_clk, reset)
begin
	if reset = RESET_ACTIVE then
		srw <= '0';
	elsif sys_clk'event and sys_clk = '1' then
		if state = ACK_HEADER then
			srw <= smbus_header(0);
		else
			srw <= srw;
		end if;
	end if;
end process;

-- MIF - M-bus Interrupt
-- The MIF bit is set when an interrupt is pending, which causes a processor interrupt
-- request provided MIEN is set. MIF is set when:
--	1. Byte transfer is complete (set at the falling edge of the 9th clock
--	2. MAAS is set when in slave receive mode
--	3. Arbitration is lost
-- This bit is cleared by reset and software writting a '0'to it
mif_bit: process(sys_clk, reset)
begin
	if reset = RESET_ACTIVE then
		mif <= '0';
	elsif sys_clk'event and sys_clk = '1' then
		if mif_bit_reset = '1' then 
			mif <= '0';
		elsif mal = '1' or mcf = '1' or 
			(maas = '1' and smbus_header(0) = '0' and master_slave = '0') then
			mif <= '1';
		end if;
	end if;
end process;

-- RXAK - Received Acknowledge
-- RXAK contains the value of SDA during the acknowledge bit of a bus cycle. If =0, then 
-- an acknowledge signal has been received, if 1, then no acknowledge has been received.
-- This bit is not cleared at reset. The CPLD will reset this bit upon power-up
rxak_bit: process(scl)
begin
	if scl'event and scl = '0' then
		if state = ACK_HEADER or state = ACK_DATA or state = WAIT_ACK then
			rxak <= sda_in;
		end if;
	end if;
end process;

-- ************************  uP Data Register ************************
-- Register for uP interface MBDR_SMBUS
mbdr_smbus_proc: process(sys_clk, reset)
begin	
	if reset = RESET_ACTIVE then
		mbdr_smbus <= (others => '0');
	elsif sys_clk'event and sys_clk = '1' then
		if (state = ACK_DATA) or (state = WAIT_ACK) then
			mbdr_smbus <= shift_reg ;
		else
			mbdr_smbus <= mbdr_smbus;
		end if;
	end if;
end process;

-- ************************  uP Address Register ************************
	addr_match <= '1' when smbus_header(7 downto 1) = madr(7 downto 1) 
		          else '0';

-- ************************  Main State Machine Process ************************
-- The following process contains the main SMBUS state machine for both master and slave
-- modes. This state machine is clocked on the falling edge of SCL. DETECT_STOP must stay as
-- an asynchronous reset because once STOP has been generated, SCL clock stops.
state_machine: process (scl, reset, detect_stop)

begin

	if reset = RESET_ACTIVE or detect_stop = '1' then
		state <= IDLE;
		sm_stop <= '0';
	elsif scl'event and scl = '0'  then

		case state is
	
			------------- IDLE STATE -------------
			when IDLE => 
				if detect_start = '1' then
					state <= HEADER;
				end if;

			------------- HEADER STATE -------------	
			when HEADER =>
				if bit_cnt = CNT_DONE then
					state <= ACK_HEADER;
				end if;

			------------- ACK_HEADER STATE -------------
			when ACK_HEADER =>
				if arb_lost = '1' then
					state <= IDLE;
				elsif sda_in = '0' then
					-- ack has been received, check for master/slave
					if master_slave = '1' then
						-- master, so check mtx bit for direction
						if mtx = '0' then
							-- receive mode
							state <= RCV_DATA;
						else
							--transmit mode
							state <= XMIT_DATA;
						end if;
					else
						if addr_match = '1' then
						--if maas = '1' then
							-- addressed slave, so check SMBUS_HEADER(0) for direction
							if smbus_header(0) = '0' then
								-- receive mode
								state <= RCV_DATA;
							else
								-- transmit mode
								state <= XMIT_DATA;
							end if;
						else
							-- not addressed, go back to IDLE
							state <= IDLE;
						end if;
					end if;
				else
					-- no ack received, stop
					state <= IDLE;
					if master_slave = '1' then
						sm_stop <= '1';
					end if;
	
				end if;

		    ------------- RCV_DATA State --------------
		    when RCV_DATA =>
		      
		      	--Check for repeated starts
			if detect_start = '1' then
				state <= HEADER;
		
		      	-- Continue transmitting
		     	elsif bit_cnt = CNT_DONE then
			   
                           -- Send an acknowledge
			   state <= ACK_DATA;		      
		      
		     	end if;


		    ------------ XMIT_DATA State --------------
	            when XMIT_DATA =>

		      	--Check for repeated starts
			if detect_start = '1' then
				state <= HEADER;
		

		      	elsif bit_cnt = CNT_DONE then

			   	-- Wait for acknowledge
			   	state <= WAIT_ACK;

		      	end if;


		    ------------- ACK_DATA State --------------
	            when ACK_DATA =>

		         state <= RCV_DATA;

		
                    ------------- WAIT_ACK State --------------
		    when WAIT_ACK =>
			if arb_lost = '1' then
					state <= IDLE;
		      elsif (sda = '0') then
			      state <= XMIT_DATA;
			 else
				-- no ack received, generate a stop and return
				-- to IDLE state
				if master_slave = '1' then 
					sm_stop <= '1';
				end if;
			      state <= IDLE;
			 end if;
		
		  end case;
		
		end if;
		
	end process;
	
-- ************************  Slave and Master SDA ************************
slv_mas_sda: process(reset, sys_clk)
begin
	if reset = RESET_ACTIVE then
		master_sda <= '1';
		slave_sda <= '1';
	elsif sys_clk'event and sys_clk = '1' then
		if state = HEADER or state = XMIT_DATA then
			master_sda <= shift_out;
		elsif state = ACK_DATA then
			master_sda <= TXAK;
		else
			master_sda <= '1';
		end if;

		-- For the slave SDA, address match (MAAS) only has to be checked when 
		-- state is ACK_HEADER because state
		-- machine will never get to state XMIT_DATA or ACK_DATA
		-- unless address match is a one. 

		if (maas = '1' and state = ACK_HEADER) or
		   (state = ACK_DATA) then
			slave_sda <= TXAK;
		elsif (state = XMIT_DATA) then
			slave_sda <= shift_out;
		else
			slave_sda <= '1';
		end if;
	end if;
end process; 


-- ************************  SMBUS Data Shift Register ************************
	SMBUSDATA_REG: SHIFT8
	  port map (  		      
		      clk       => scl_not,
		      clr       => reset, 
		      data_ld   => shift_reg_ld,
		      data_in   => mbdr_micro,
		      shift_in  => sda_in,
		      shift_en  => shift_reg_en,
		      shift_out => shift_out,
		      data_out  => shift_reg );

smbusdata_reg_ctrl: process(sys_clk, reset)

begin
	if reset = RESET_ACTIVE then
		shift_reg_en <= '0';
		shift_reg_ld <= '0';
	elsif sys_clk'event and sys_clk = '1' then

		if ((master_slave = '1' and state = HEADER)
		    or (state = RCV_DATA) or (state = XMIT_DATA)) then		
			shift_reg_en <= '1';
		else 
			shift_reg_en <= '0';
		end if;

		if ((master_slave = '1' and state = IDLE) or (state = WAIT_ACK)
	         or (state = ACK_HEADER and smbus_header(0) = '1' and master_slave = '0')
		   or (state = ACK_HEADER and mtx = '1' and master_slave = '1')
		   or detect_start = '1') then
				shift_reg_ld <= '1';
		else 
				shift_reg_ld <= '0';
		end if;
	end if;
end process;
	

	
-- ************************  SMBUS Header Shift Register ************************
	-- Header/Address Shift Register
	SMBUSHEADER_REG: SHIFT8
	  port map (  		      
		      clk       => scl_not,
		      clr       => reset,  
		      data_ld   => smbus_header_ld,
		      data_in   => reg_clr,
		      shift_in  => sda_in,
		      shift_en  => smbus_header_en,
		      shift_out => smbus_shiftout,
		      data_out  => smbus_header ); 

smbusheader_reg_ctrl: process(sys_clk, reset)

begin
	if reset = RESET_ACTIVE then
		smbus_header_en <= '0';
	elsif sys_clk'event and sys_clk = '1' then
		if (detect_start = '1') or (state = HEADER) then
			smbus_header_en <= '1';
		else 
			smbus_header_en <= '0';
		end if;
	end if;
end process;
	
	smbus_header_ld <= '0';

-- ************************  Bit Counter  ************************
	BITCNT : UPCNT4
	  port map(   data      => cnt_start,
		      cnt_en    => bit_cnt_en,
		      load      => bit_cnt_ld,
		      clr       => reset,  
		      clk       => scl_not, 
		      qout      => bit_cnt );

	-- Counter control lines
	bit_cnt_en <= '1' when (state = HEADER) or (state = RCV_DATA) 
		                or (state = XMIT_DATA) else '0';

	bit_cnt_ld <= '1' when (state = IDLE) or (state = ACK_HEADER) 
		                or (state = ACK_DATA)
		                or (state = WAIT_ACK) 
		                or (detect_start = '1') 
		                else '0';

		
end behave;


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -