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

📄 i2c_control.vhd

📁 others example of code VHDL for I2c
💻 VHD
📖 第 1 页 / 共 2 页
字号:
		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 I2C 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
		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 <= i2c_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 i2c_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_I2C
mbdr_i2c_proc: process(sys_clk, reset)
begin	
	if reset = RESET_ACTIVE then
		mbdr_i2c <= (others => '0');
	elsif sys_clk'event and sys_clk = '1' then
		if (state = ACK_DATA) or (state = WAIT_ACK) then
			mbdr_i2c <= shift_reg ;
		else
			mbdr_i2c <= mbdr_i2c;
		end if;
	end if;
end process;

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

-- ************************  Main State Machine Process ************************
-- The following process contains the main I2C 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 I2C_HEADER(0) for direction
							if i2c_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 start
		      if (detect_start = '1') then
			   state <= HEADER;
		      elsif bit_cnt = CNT_DONE then
			   
                           -- Send an acknowledge
			   state <= ACK_DATA;		      
		      
		      end if;


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

		      -- check for repeated start
		      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; 


-- ************************  I2C Data Shift Register ************************
	I2CDATA_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 );

i2cdata_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 i2c_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;
	

	
-- ************************  I2C Header Shift Register ************************
	-- Header/Address Shift Register
	I2CHEADER_REG: SHIFT8
	  port map (  		      
		      clk       => scl_not,
		      clr       => reset,  
		      data_ld   => i2c_header_ld,
		      data_in   => reg_clr,
		      shift_in  => sda_in,
		      shift_en  => i2c_header_en,
		      shift_out => i2c_shiftout,
		      data_out  => i2c_header ); 

i2cheader_reg_ctrl: process(sys_clk, reset)

begin
	if reset = RESET_ACTIVE then
		i2c_header_en <= '0';
	elsif sys_clk'event and sys_clk = '1' then
		if (detect_start = '1') or (state = HEADER) then
			i2c_header_en <= '1';
		else 
			i2c_header_en <= '0';
		end if;
	end if;
end process;
	
	i2c_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 + -