📄 iic_controller.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 + -