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

📄 iic_controller.vhd

📁 VHDL基础的编程源代码
💻 VHD
字号:
--/*****************************************************************************
-- * 源文件:	iic_controller.vhd
-- * 模块:   	IIC读写控制模块
-- * 版权:
-- *         	Copyright(C) 北京联华众科科技有限公司
-- *						www.lianhua-zhongke.com.cn
-- * 版本:  	Version 1.0
-- * 
-- * 功能说明:
-- *		   	在输入工作时钟 clock 驱动下,将输入的 8位数据 data 写入IIC总线,或
-- *			读取指定设备,存储单元地址的存储单元存储的数据。
-- *			
-- * 参数说明:
-- *	       	输出
-- *			scl - IIC总线时钟,频率为 400kHz
-- *			stop - 当前操作结束后 stop 输出高电平,通知其他模块
-- *
-- *			输入
-- *			rd - 读操作指令有效
-- *			wr - 写操作指令有效
-- *			dev_addr - IIC设备地址
-- *			addr - 存储单元地址
-- *			clock - 工作时钟,为IIC总线时钟(400kHz)的2倍
-- *			reset - 复位信号,低电平有效
-- *
-- *			双向
-- *			sda - IIC总线数据线,为双向数据线
-- *			data - 读操作的数据输出,写操作的数据输入
-- *
-- *			参数
-- *			无
-- *
-- * 变更记录: 
-- *         2006.01.28, 新建
-- *
-- *****************************************************************************/

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;

ENTITY iic_controller IS
	PORT
	(
		scl : BUFFER STD_LOGIC;
		sda : INOUT STD_LOGIC;
		data : INOUT STD_LOGIC_VECTOR(7 downto 0);
		stop : OUT STD_LOGIC;
		
		rd : IN STD_LOGIC;
		wr : IN STD_LOGIC;

		dev_addr : IN STD_LOGIC_VECTOR(7 downto 0);
		addr : IN STD_LOGIC_VECTOR(7 downto 0);

		clock : IN STD_LOGIC;--400k*2
		reset : IN STD_LOGIC
		
		--oCurrentState:OUT STD_LOGIC_VECTOR(3 downto 0)
	);

END iic_controller;


ARCHITECTURE iic_controller_architecture OF iic_controller IS	
	SIGNAL data_write : STD_LOGIC;
	SIGNAL data_out : STD_LOGIC_VECTOR(7 downto 0);
	SIGNAL data_out_tmp : STD_LOGIC_VECTOR(7 downto 0);

	SIGNAL sda_write : STD_LOGIC;
	SIGNAL sda_out : STD_LOGIC;
	SIGNAL sda_out_tmp : STD_LOGIC;

BEGIN

	data_out_tmp <= data_out WHEN (data_write) = '1' ELSE "ZZZZZZZZ";
	data <= data_out_tmp;
	
	sda_out_tmp <= sda_out WHEN (sda_write) = '1' ELSE 'Z';
	sda <= sda_out_tmp;
	
	PROCESS(clock, reset)--对输入时钟 2 分频产生 SCL 时钟
	BEGIN
		if (reset = '0') then
			scl <= '0';
		elsif(clock = '0' AND clock'EVENT) then
			scl <= not scl;
		end if;
		
	END PROCESS;

	PROCESS(clock, reset)--主状态机
		VARIABLE currentState : INTEGER RANGE 0 TO 15 := 0;
		VARIABLE nextState : INTEGER RANGE 0 TO 15 := 0;
		
		VARIABLE send_data : STD_LOGIC_VECTOR(7 downto 0);--待发送字节缓冲区
		VARIABLE bit_index : INTEGER RANGE 0 TO 15 := 0;--待发送字节位索引
		
		VARIABLE send_devaddr_again_flag : STD_LOGIC;
		VARIABLE acked : STD_LOGIC;

	BEGIN
		if (reset = '0') then
			currentState := 0;--idle
			stop <= '0';
			sda_write <= '1';
			sda_out <= '1';
		elsif(clock = '1' AND clock'EVENT) then
			--oCurrentState <= CONV_STD_LOGIC_VECTOR(currentState, 4);
			
			if (currentState = 0) then--idle
				sda_write <= '1';
				sda_out <= '1';
				stop <= '0';
				
				send_devaddr_again_flag := '0';
				
				if (wr='1' or rd='1') then--写入/读出信号有效
					if (rd = '1') then
						data_write <= '1';--data端口设置为输出方式
					elsif (wr = '1') then
						data_write <= '0';--data端口设置为输入方式
					end if;
					
					currentState := 1;--start
				else
					currentState := 0;
				end if;
			elsif (currentState = 1) then--start, write device address
				if (scl = '1') then--读操作/写操作开始,首先置为 start:scl=1,sdl=1->0
					send_data := dev_addr;--高7位为设备地址
					bit_index := 0;
					
					if (rd='1' and send_devaddr_again_flag='1') then
						if (acked = '0') then
							acked := '1';
						else
							sda_write <= '1';
							sda_out <= '0';
							
							send_devaddr_again_flag := '0';
							send_data(0) := '1';--最低位为1表示是Read
							nextState := 5;
							currentState := 15;--15状态为发送一个字节到IIC总线全过程
						end if;
					else
						sda_write <= '1';
						sda_out <= '0';

						send_data(0) := '0';--最低位为0表示是Write
						nextState := 3;--转到15状态,并在15状态结束时返回状态3
						currentState := 15;--15状态为发送一个字节到IIC总线全过程
					end if;
				else
					if (rd='1' and send_devaddr_again_flag='1') then--产生第二个start
						sda_write <= '1';
						sda_out <= '1';
					end if;
				end if;
			elsif (currentState = 3) then--write memory address
				if (scl = '1') then
					send_data := addr;
					bit_index := 0;
					
					if (wr = '1') then
						nextState := 4;
					elsif (rd = '1') then
						send_devaddr_again_flag := '1';--第二次发送设备地址标志
						nextState := 1;--读操作,调用状态15完成存储器地址发送后,返回状态1第二次发送设备地址
					end if;
				
					currentState := 15;
				end if;
			elsif (currentState = 4) then--write data byte
				if (scl = '1') then
					send_data := data;
					bit_index := 0;
					
					acked := '0';
					nextState := 14;
					currentState := 15;
				end if;
			elsif (currentState = 5) then--从IIC总线 SDA 上读入一字节数据
				if (scl = '1') then
					if (acked = '0') then
						sda_write <= '0';
						acked := '1';
					else
						if (bit_index <= 7) then
							send_data(7-bit_index) := sda;							
							bit_index := bit_index+1;
						elsif (bit_index = 8) then--NO ACK位
							data_out <= send_data;
							bit_index := 0;
							currentState := 14;
						end if;
					end if;
				end if;
			elsif (currentState = 14) then--stop
				if (scl = '0') then
					sda_write <= '1';
					sda_out <= '0';
				else
					if (wr='1' and acked='0') then
						acked := '1';
					else
						sda_write <= '1';
						sda_out <= '1';
						stop <= '1';
						currentState := 0;
					end if;
				end if;
			elsif (currentState = 15) then
				if (bit_index <= 7) then
					if (scl = '0') then
						sda_write <= '1';
						sda_out <= send_data(7-bit_index);
						bit_index := bit_index+1;
					end if;
				elsif (bit_index = 8) then--ack
					if (scl = '0') then
						sda_write <= '0';
						acked := '0';
						bit_index := 0;
						currentState := nextState;
					end if;
				else
					bit_index := 0;
				end if;
			else
				currentState := 0;
			end if;
		end if;
		
	END PROCESS;
END iic_controller_architecture;

⌨️ 快捷键说明

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