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

📄 smbus_control.vhd

📁 可编程器件厂商Xilinx的用于设计SMBus 控制器的源程序
💻 VHD
📖 第 1 页 / 共 3 页
字号:
 				men_bit_reset <= RESET_ACTIVE;
 				next_watchdog_state <= WATCHDOG_IDLE;
 
		end case;
 end process;
 
 scl_watchdog_regs: process (sys_clk, reset)
 begin
 	if reset = RESET_ACTIVE then
 		watchdog_state <= WATCHDOG_IDLE;
 	elsif sys_clk'event and sys_clk='1' then
 		watchdog_state <= next_watchdog_state;
 	end if;
 end process;



-- ************************  SCL_Generator Process ************************
-- This process generates SCL and SDA when in Master mode. It generates the START
-- and STOP conditions. If arbitration is lost, SCL will be generated until the
-- end of the byte transfer.

scl_generator_comb: process (scl_state, arb_lost, sm_stop, gen_stop, rep_start, 
					bus_busy, gen_start, master_slave, stop_scl_reg, 
					clk_cnt, bit_cnt, scl_in, state, sda_out,
					sda_out_reg, master_sda, rep_start_det_reg)

begin

-- state machine defaults
	scl_out <= '1';
	sda_out <= sda_out_reg;
	stop_scl <= stop_scl_reg;
	clk_cnt_en <= '0';
	clk_cnt_rst <= '1';
	next_scl_state <= scl_state;
	rep_start_det <= rep_start_det_reg;
	rsta_rst <= not (RESET_ACTIVE);

		case scl_state is 
	
			when SCL_IDLE =>
				sda_out <= '1';
				stop_scl <= '0';
				-- leave IDLE state when master, bus is idle, and gen_start
				if master_slave = '1' and bus_busy = '0' and gen_start = '1' then
					next_scl_state <= START;
				end if;
					

			when START =>
				-- generate start condition
				clk_cnt_en <= '1';
				clk_cnt_rst <= '0';
				sda_out <= '0';
				stop_scl <= '0';
				if clk_cnt = START_HOLD then
					next_scl_state <= SCL_LOW_EDGE;
					if rep_start = '1' then
						rsta_rst <= RESET_ACTIVE;
						rep_start_det <= '0';
					end if;
				else
					next_scl_state <= START;
				end if;

			
			when SCL_LOW_EDGE =>
				clk_cnt_rst <= '1';
				scl_out <= '0';
				next_scl_state <= SCL_LOW;
				stop_scl <= '0';

			when SCL_LOW =>
				clk_cnt_en <= '1';
				clk_cnt_rst <= '0';
				scl_out <= '0';
				
				-- set SDA_OUT based on control signals
				if arb_lost = '1' then
					stop_scl <= '0';
				elsif ((sm_stop = '1' or gen_stop = '1') and
					(state /= ACK_DATA and state /= ACK_HEADER and state /= WAIT_ACK)) then
					sda_out <= '0';
					stop_scl <= '1';
				elsif rep_start_det_reg = '1' then
					sda_out <= '1';
					stop_scl <= '0';
				elsif clk_cnt = DATA_HOLD then
					sda_out <= master_sda;
					stop_scl <= '0';
				else
					stop_scl <= '0';
				end if;
			
				-- determine next state
				if clk_cnt = LOW_CNT then

					if bit_cnt = CNT_DONE and arb_lost = '1' then
						next_scl_state <= SCL_IDLE;
					else
						next_scl_state <= SCL_HIGH_EDGE;
					end if;
				else
					next_scl_state <= SCL_LOW;
				end if;
				
			when SCL_HIGH_EDGE =>
				clk_cnt_rst <= '1';
				scl_out <= '1';
				if ((sm_stop = '1' or gen_stop = '1') and
				   (state /= ACK_DATA and state /= ACK_HEADER and state /= WAIT_ACK)) then
					stop_scl <= '1';
				else
					stop_scl <= '0';
				end if;

				
				-- this state sets SCL high
				-- stay in this state until SCL_IN = 1
				-- this will hold the counter in reset until all SCL drivers
				-- have released SCL to 1
				if scl_in = '0' then
					next_scl_state <= SCL_HIGH_EDGE;
				else
					next_scl_state <= SCL_HIGH;
				end if;

			when SCL_HIGH =>
				-- now all SCL drivers have set SCL to '1'
				-- begin count for high time
				clk_cnt_en <= '1';
				clk_cnt_rst <= '0';
				scl_out <= '1';	
				-- check to see if a repeated start or a stop needs to be 
				-- generated. If so, only hold SCL high for half of the high time
				if clk_cnt = STOP_REP_START_SU then
					if rep_start = '1' then
						if rep_start_det_reg = '0' then
							rep_start_det <= '1';
							next_scl_state <= SCL_HIGH;
						elsif rep_start_det_reg = '1' then
							clk_cnt_rst <= '1';
							next_scl_state <= START;
						end if;
					elsif stop_scl_reg = '1' then
						clk_cnt_rst <= '1';
						next_scl_state <= STOP_WAIT;
					end if;
				elsif clk_cnt = HIGH_CNT then 
					next_scl_state <= SCL_LOW_EDGE;
				else
					next_scl_state <= SCL_HIGH;
				end if;
			
			when STOP_WAIT =>
				--this state gives the required free time between stop and start
				--conditions
				clk_cnt_en <='1';
				clk_cnt_rst <= '0';
				sda_out <= '1';
				stop_scl <= '0';
				if clk_cnt = TBUF then
					-- clk_cnt_rst <= '1';
					-- clk_cnt_en <= '0';
					next_scl_state <= SCL_IDLE;
				else
					next_scl_state <= STOP_WAIT;
				end if;
				
		end case;
end process;

scl_generator_regs: process (sys_clk, reset)
begin
	if reset = RESET_ACTIVE then
		scl_state <= SCL_IDLE;
		sda_out_reg <= '1';
		scl_out_reg <= '1';
		stop_scl_reg <= '0';
		rep_start_det_reg <= '0';
	elsif sys_clk'event and sys_clk='1' then
		scl_state <= next_scl_state;
		sda_out_reg <= sda_out;
		scl_out_reg <= scl_out;
		stop_scl_reg <= stop_scl;
		rep_start_det_reg <= rep_start_det;
	end if;
end process;

-- ************************  Clock Counter Implementation ************************
-- The following code implements the counter that divides the sys_clock for 
-- creation of SCL. Control lines for this counter are set in SCL state machine

	CLKCNT : UPCNT9
	  port map( data      => cnt_zero,
		      cnt_en    => clk_cnt_en,
		      load      => clk_cnt_rst,
		      clr       => reset,  
		      clk       => sys_clk, 
		      qout      => clk_cnt );
		




-- ************************  Timout Counter Implementation ************************
-- The following code implements the counter that divides the sys_clock for 
-- timout testing of SCL. Control lines for this counter are set in the scl_watchdog
-- process.

	WATCHDOGCNT : UPCNT21
	  port map( data      => timeout_cnt_zero,
		      cnt_en    => timeout_cnt_en,
		      load      => timeout_cnt_rst,
		      clr       => reset,  
		      clk       => sys_clk, 
		      qout      => timeout_cnt );
		




-- ************************  Input Registers Process ************************
-- This process samples the incoming SDA and SCL with the system clock

input_regs: process(sys_clk,reset)
begin
	if reset = RESET_ACTIVE then
		sda_in <= '1';
		scl_in <= '1';
		msta_d1 <= '0';
		sda_out_reg_d1 <= '1';
--		sda_out_reg_d2 <= '1';
	
	elsif sys_clk'event and sys_clk = '1' then

		-- the following if, then, else clauses are used
		-- because scl may equal 'H' or '1'
		if scl = '0' then
			scl_in <= '0';
		else	
			scl_in <= '1';
		end if;
		if sda = '0' then
			sda_in <= '0';
		else
			sda_in <= '1';
		end if;
		sda_out_reg_d1 <= sda_out_reg;
--		sda_out_reg_d2 <= sda_out_reg_d1;
		msta_d1 <= msta;
	end if;
end process;

-- ************************  START/STOP Detect Process ************************
-- This process detects the start and stop conditions.
-- by using SDA as a clock.
start_det: process(sda, reset, state)
begin
	if reset = RESET_ACTIVE or state = HEADER then
		detect_start <= '0';
	elsif sda'event and sda = '0' then
		if scl /= '0' then 
			detect_start <= '1';
		else
			detect_start <= '0';
		end if;
	end if;
end process;

stop_det: process(sda, reset, detect_start)
begin
	if reset = RESET_ACTIVE or detect_start = '1' then
		detect_stop <= '0';
	elsif sda'event and sda /= '0' then
		if scl /= '0' then
			detect_stop <= '1';
		else
			detect_stop <= '0';
		end if;
	end if;
end process;

-- ************************  Bus Busy Process ************************
-- This process detects the start and stop conditions and sets the bus busy bit
-- It also describes a delayed version of the bus busy bit which is used to determine
-- MAL. MAL should be set if a start is detected while the bus is busy, however, the code below
-- sets bus_busy as soon as START is detected which would always set MAL. Therefore, a delayed
-- version of bus_busy is generated and used to determine MAL.

set_bus_busy: process(sys_clk,reset)
begin
	if reset = RESET_ACTIVE then
		bus_busy <= '0';
		bus_busy_d1 <= '0';

	elsif sys_clk'event and sys_clk = '1' then
		
		bus_busy_d1 <= bus_busy;

			if detect_start = '1' then	
				bus_busy <= '1';
			end if;
			if detect_stop = '1' then				
				bus_busy <= '0';
			end if;
		end if;

end process;

-- ************************   uP Control Bits Process ************************
-- This process detects the rising and falling edges of MSTA and sets signals to
-- control generation of start and stop conditions
-- This process also sets the master slave bit based on MSTA if and only if it is not
-- in the middle of a cycle, i.e. bus_busy = '0'
control_bits: process (sys_clk,reset)
begin
	if reset = RESET_ACTIVE then
		gen_start <= '0';
		gen_stop <= '0';
		master_slave <= '0';
	elsif sys_clk'event and sys_clk = '1' then
		if msta_d1 = '0' and msta = '1' then
			-- rising edge of MSTA - generate start condition
			gen_start <= '1';
		elsif detect_start = '1' then
			gen_start <= '0';
		end if;
		if arb_lost = '0' and msta_d1 = '1' and msta = '0' then
			-- falling edge of MSTA - generate stop condition only
			-- if arbitration has not been lost
			gen_stop <= '1';
		elsif detect_stop = '1' then
			gen_stop <= '0';
		end if;
		if bus_busy = '0' then
			master_slave <= msta;
		else
			master_slave <= master_slave;
		end if;
	end if;
end process;

rep_start <= rsta;	-- repeat start signal is RSTA control bit

-- ************************  uP Status Register Bits Processes ************************
-- The following processes and assignments set the bits of the MBUS status register MBSR
-- 
-- MCF - Data transferring bit
-- While one byte of data is being transferred, this bit is cleared. It is set by the falling edge
-- of the 9th clock of a byte transfer and is not cleared at reset
mcf_bit: process(scl, reset)
begin
	if reset = RESET_ACTIVE then 
		mcf <= '0';
	elsif scl'event and scl = '0' then 
		if bit_cnt = CNT_DONE then
			mcf <= '1';
		else
			mcf <= '0';
		end if;
	end if;
end process;

-- MAAS - Addressed As Slave Bit
-- When its own specific address (MADR) matches the SMBUS Address, this bit is set. The CPU is 
-- interrupted provided the MIEN is set. Then the CPU needs to check the SRW bit and set its
-- TX-RX mode accordingly. Writing to the MBCR clears this bit
maas_bit: process(sys_clk, reset)
begin
	if reset = RESET_ACTIVE  then
		maas <= '0';
	elsif sys_clk'event and sys_clk = '1' then

⌨️ 快捷键说明

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