library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity iic is
port(
reset:in std_logic; --system reset
clk :in std_logic;
datain:in std_logic_vector(7 downto 0); --data or control datain;
bit_cmd:in std_logic; --work begin or go on command ;
rd_wr: in std_logic; --rd or wr ;
dataout:out std_logic_vector(7 downto 0); --receive data;
cmd_done:out std_logic; --datatransfer done;
nop :out std_logic; --current state is nop;
sda:inout std_logic; --data wire
scl:out std_logic); --clock wire;
end entity iic;
architecture rtl of iic is
signal in_reg:std_logic_vector(7 downto 0); --dataout tmp;
signal out_reg:std_logic_vector(7 downto 0); --datain tmp;
signal sdat:std_logic;
signal wr :std_logic;
signal r_w :std_logic;
signal rd :integer range 0 to 2;
signal clkcnt:std_logic_vector(1 downto 0);
signal clkdiv:std_logic:='1';
type state is(idle,start,wr_ad,wr_dd,rd_dd,stop);
signal now_state,next_state:state;
signal datacnt:integer range 1 to 9;
begin
process(clk,reset)
begin
if reset='0' then
clkcnt<="00";
clkdiv<='1';
elsif clk'event and clk='1' then
if clkcnt="11" then
clkcnt<="00";
else
clkcnt<=clkcnt+1;
end if;
if clkcnt="01" or clkcnt="11" then
clkdiv<=not clkdiv;
end if;
end if;
end process;
process(clk,reset) --this process deals with state transfer;
begin
if reset='0' then
next_state<=idle;
elsif clk'event and clk='1' then
case now_state is
when idle=> if clkcnt="01" then
if bit_cmd='1' then
next_state<=start;
r_w<=rd_wr;
end if;
end if;
rd<=0;
when start=> if clkcnt="01" then
next_state<=wr_ad;
end if;
datacnt<=1;
when wr_ad=>
if datacnt=9 then
if clkcnt="01" then
if sda='1' then
next_state<=idle;
elsif r_w='0' then
next_state<=wr_dd;
elsif rd=2 then next_state<=rd_dd;
elsif rd=1 then next_state<=start;
rd<=rd+1;
else rd<=rd+1;
end if;
datacnt<=1;
end if;
elsif clkcnt="01" then
datacnt<=datacnt+1;
end if;
when wr_dd=>
if datacnt=9 then
if clkcnt="01" then
if sda='1' then
next_state<=idle;
elsif bit_cmd='0' then
next_state<=stop;
end if;
datacnt<=1;
end if;
elsif clkcnt="01" then
datacnt<=datacnt+1;
end if;
when rd_dd=> if clkcnt="01" then
if datacnt=9 then
datacnt<=1;
next_state<=stop;
else datacnt<=datacnt+1;
end if;
end if;
when stop=> if clkcnt="01" then
next_state<=idle;
else
datacnt<=1;
end if;
rd<=0;
end case;
end if;
end process;
process(clk,reset) -- this process deals with data transfer or receive;
begin
if reset='0' then
sdat<='1';
wr<='1';
elsif clk'event and clk='1' then
case now_state is
when idle=> wr<='0';
sdat<='1';
when start=>if clkcnt="00" then
if rd=0 then
cmd_done<='1';
in_reg<=datain;
end if;
elsif clkcnt="01" then
cmd_done<='0';
sdat<='0';
end if;
wr<='1';
when wr_ad=>if clkcnt="11" then
if datacnt<9 then
sdat<=in_reg(8-datacnt);
wr<='1';
else
in_reg<=datain;
cmd_done<='1';
wr<='0';
end if;
elsif clkcnt="01" then
if datacnt=9 then
end if;
else cmd_done<='0';
end if;
out_reg<=(others=>'1');
when wr_dd=>
if clkcnt="11" then
if datacnt<9 then
sdat<=in_reg(8-datacnt);
wr<='1';
else
in_reg<=datain;
cmd_done<='1';
wr<='0';
end if;
elsif clkcnt="01" then
if datacnt=9 then
sdat<='0';
end if;
else cmd_done<='0';
end if;
when rd_dd=> if clkcnt="01" then
if datacnt<9 then
out_reg(8-datacnt)<=sda;
else
dataout<=out_reg;
cmd_done<='1';
end if;
else cmd_done<='0';
wr<='0';
end if;
sdat<='1';
when stop=> cmd_done<='0';
wr<='1';
if clkcnt="01" then
sdat<='1';
end if;
end case;
end if;
end process;
process(clk,reset) --this process deals with now_state<=next_state;
begin
if reset='0' then
now_state<=idle;
elsif clk'event and clk='1' then
now_state<=next_state;
end if;
end process;
sda<=sdat when wr='1' else 'Z'; --this control the tri_state inout data wire;
process(clk,sda)
begin
if clk'event and clk='1' then
if now_state=idle then
scl<='1';
else scl<=clkdiv;
end if;
end if;
end process; -- this control the scl;
process(clk,reset) --this process show the isbusy?
begin
if reset='0' then
nop<='1';
elsif clk'event and clk='1' then
if now_state=idle then
nop<='1';
else nop<='0';
end if;
end if;
end process;
end rtl;
我把代码发上来,呵呵,现在经测试可以实现读写EEPROM了,支持多种连续读和单地址读等多种模式,希望大家指正。
另外这个程序只是IIC主设备的程序,现在正在写从设备程序,发现从设备程序比主设备程序要麻烦,如果遇到问题,还会继续请教大家的! |