作为项目的一部分,我试图在我的项目中实现一个非常基本的I2C模块(不是自写的)。 I2C模块将数据线用作输入端口。我正在尝试验证数据“ 01010001”,其中包含6位地址+“读”位。我生成了以下添加的代码的位流,并尝试使用示波器测量端口的输出。我可以验证SCL上的时钟,但数据信号始终保持为零。我创建了一个顶部模块,其中包括一个时钟分频器,以为i2c模块和i2c模块提供时钟。我将在下面添加两个VHDL文件。我的问题是:代码中是否存在我无法弄清的错误,或者我已经更改了测量端口的方式?
I2C模块:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity i2c_neuer_ansatz is
Port
( CLK_800kHz_IN, RESET : in STD_LOGIC;
SCL : out STD_LOGIC;
SDA :inout STD_LOGIC
);
end i2c_neuer_ansatz;
architecture i2c_neuer_ansatz_arch of i2c_neuer_ansatz is
signal STATE: STD_LOGIC_VECTOR (7 DOWNTO 0);
signal SDAINT: STD_LOGIC;
signal BITCOUNT: integer range 0 to 8;
constant SLAVEADD_READ: STD_LOGIC_VECTOR (7 DOWNTO 0):= "01010001";
---- I2C slave address + read
constant SLAVEADD_WRITE: STD_LOGIC_VECTOR (7 DOWNTO 0):= "01010000";
---- I2C slave address + write
signal DATA_IN: STD_LOGIC_VECTOR (7 DOWNTO 0):= "00000000";
---- Data to be written to slave
signal DATA_OUT: STD_LOGIC_VECTOR (7 DOWNTO 0):= "00000000";
---- Data to be read from slave
-- ---- for 100 kHz clock
-- constant max200k: integer:= 250;
-- signal clocktick200k: integer range 0 to max200k;
signal CLK_800kHz: STD_LOGIC;
---- CLK_200KHz is a 200 kHz clock and SCL is a 100kHz clock for i2c
begin
---- SDA line is open drain, therefore to set SDA to '1' we need to output a 'Z' value
SDA <= 'Z' when SDAINT = '1' else '0';
---- process for implementing FSM for the I2C master controller
CLK_800kHz <= CLK_800kHz_IN;
Output: process (CLK_800kHz, RESET)
begin
if (RESET = '0') then
---- idle condition, both SDA and SCL = 1
SCL <= '1';
SDAINT <= '1';
State <= x"00"; ---- next state
-- elsif (CLK_800kHz'event and CLK_800kHz = '1')then
elsif rising_edge(CLK_800kHz) then
case STATE is
when x"00" =>
---- when idle, both SDA and SCL = 1
SCL <= '1';
SDAINT <= '1';
state <= x"01"; ---- next state
when x"01" =>
---- send start condition SDA goes from '1' to '0' with SCL = '1'
SCL <= '1';
SDAINT <= '0';
BITCOUNT <= 8; ---- starting bit count
state <= x"40"; ---- next state
when x"02" =>
---- send seven bit address of the slave followed by write/read bit
SCL <= '0';
SDAINT <= SLAVEADD_WRITE (BITCOUNT - 1);
---- sending the seven bit address and write bits on SDA line
state <= x"03"; ---- next state
when x"03" =>
SCL <= '1';
if (BITCOUNT)> 0 then
---- if BITOCUNT > 0, then there are more bits to be sent. Therefore, go to state x"02"
BITCOUNT <= BITCOUNT - 1;
State <= x"02"; ---- next state
else
---- If BITCOUNT = 0, then all bits have been sent. Go to state x"12" and Set the value of BITCOUNT to 8
BITCOUNT <= 8;
State <= x"12"; ---- next state
end if;
---- address and write bits have been sent and now get acknowledgement from slave
when x"12" =>
SCL <= '0';
state <= x"13"; ---- next state
when x"13" =>
SCL <= '1';
if SDA = '1' then
---- if no acknowledgement from slave, go to the idle state. The designer can create an error state if desired and send the FSM there.
state <= x"00"; ---- next state
else
---- if there is acknowledgement from slave, go to state x"40" for reading data to the slave
State <= x"40"; ---- next state
end if;
---- writing data to slave
when x"30" =>
SCL <= '0';
---- sending the data to be written on the SDA line
SDAINT <= DATA_IN (BITCOUNT - 1);
state <= x"31"; ---- next state
when x"31" =>
SCL <= '1';
if (BITCOUNT)> 0 then
---- if BITOCUNT > 0, then there are more bits to be sent. Therefore, go to state x"30"
BITCOUNT <= BITCOUNT - 1;
state <= x"30"; ---- next state
else
---- If BITCOUNT = 0, then all bits have been sent. Go to state x"32"
state <= x"32"; ---- next state
end if;
----get acknowledgement from slave
when x"32" =>
SCL <= '0';
state <= x"33"; ---- next state
when x"33" =>
BITCOUNT <= 8;
SCL <= '1';
if SDA = '1' then
state <= x"00"; ---- next state
else
SDAINT <= '0';
state <= x"34"; ---- next state
end if;
when x"34" =>
SCL <= '0';
-- SDA starts at 0 to prepare for the 0 to 1 transition
SDAINT <= '0';
state <= x"42"; ---- next state
---- read from slave
when x"40" =>
---- send seven bit address of the slave followed by read bit
SCL <= '0';
SDAINT <= SLAVEADD_READ (BITCOUNT - 1);
state <= x"41"; ---- next state
when x"41" =>
SCL <= '1';
if (BITCOUNT)> 0 then
BITCOUNT <= BITCOUNT - 1;
state <= x"40"; ---- next state
else
BITCOUNT <= 8;
state <= x"50";
end if;
---- get acknowledgement from slave
when x"50" =>
BITCOUNT <= 8;
SCL<= '0';
state <= x"51"; ---- next state
when x"51" =>
SCL <= '1';
if SDA = '1' then
state <= x"00";
else
BITCOUNT <= 8;
state <= x"52";
end if;
when x"52" =>
SCL <= '0';
state <= x"53";
when x"53" =>
SCL <= '1';
DATA_OUT(bitcount-1) <= SDA;
if (bitcount - 1) > 0 then
bitcount <= bitcount - 1;
state <= x"54";
else
bitcount <= 8;
state <= x"00";
end if;
when others =>
state <= x"00";
end case;
end if;
end process;
------ process for generating 200 kHz clock from 50 MHz input clock
--Clk200kHz: process
-- begin
-- wait until CLK_50MHz'event and CLK_50MHz = '1';
-- if clocktick200k < max200k then
-- clocktick200k <= clocktick200k + 1;
-- else
-- clocktick200k <= 0;
-- end if;
-- if clocktick200k < max200k/2 then
-- CLK_200KHz <= '0';
-- else
-- CLK_200KHz <= '1';
-- end if;
-- end process;
end i2c_neuer_ansatz_arch;
该模块包含以下代码:
entity i2cNew_clk is
Port
(
MAIN_CLK_IN : in std_logic;
MAIN_RESET_I2C : in std_logic;
MAIN_RESET_CLK : in std_logic;
MAIN_SDA : inout std_logic;
MAIN_SCL : out std_logic;
MAIN_CLK_TEST : out std_logic
);
end i2cNew_clk;
architecture i2cNew_clk_arch of i2cNew_clk is
component i2c_neuer_ansatz is
Port
( CLK_800kHz_IN, RESET : in STD_LOGIC;
SCL : out STD_LOGIC;
SDA :inout STD_LOGIC
);
end component i2c_neuer_ansatz;
signal sign_SCL : std_logic;
signal sign_SDA : std_logic;
signal sign_RESET : std_logic;
component clk_gen is
Generic
(
sysclk_generic : natural := 125000000; --250MHz vom Board
clk_out_generic : natural := 1000000; --1MHz für General
i2c_clk_generic : natural := 800000 --800kHz für I2C
);
Port
(
SYSCLK_IN_CLK_GEN : in std_logic;
RST_IN_CLK_GEN : in std_logic;
CLK_THRU : out std_logic;
CLK_OUT_GENERAL_CLK_GEN : out std_logic;
CLK_OUT_I2C_CLK_GEN : out std_logic
);
end component clk_gen;
signal sign_SYSCLK_IN_CLK_GEN : std_logic;
signal sign_RST_IN_CLK_GEN : std_logic;
signal sign_CLK_THRU : std_logic;
signal sign_CLK_OUT_GENERAL_CLK_GEN : std_logic;
signal sign_CLK_OUT_I2C_CLK_GEN : std_logic;
begin
sign_RESET <= MAIN_RESET_I2C;
sign_RST_IN_CLK_GEN <= MAIN_RESET_CLK;
sign_SYSCLK_IN_CLK_GEN <= MAIN_CLK_IN;
MAIN_SDA <= sign_SDA;
MAIN_SCL <= sign_SCL;
MAIN_CLK_TEST <= sign_CLK_OUT_I2C_CLK_GEN;
i2c_neuer_ansatz_inst : i2c_neuer_ansatz
port map
(
CLK_800kHz_IN => sign_CLK_OUT_I2C_CLK_GEN,
RESET => sign_RESET,
SCL => sign_SCL,
SDA => sign_SDA
);
clk_gen_inst : clk_gen
port map
(
SYSCLK_IN_CLK_GEN => sign_SYSCLK_IN_CLK_GEN,
RST_IN_CLK_GEN => sign_RST_IN_CLK_GEN,
CLK_THRU => sign_CLK_THRU,
CLK_OUT_GENERAL_CLK_GEN => sign_CLK_OUT_GENERAL_CLK_GEN,
CLK_OUT_I2C_CLK_GEN => sign_CLK_OUT_I2C_CLK_GEN
);
end i2cNew_clk_arch;
编辑:更新了i2c模块的代码。我评论了整个部分写给奴隶的情况
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity i2c_neuer_ansatz is
Port
( CLK_800kHz_IN, RESET : in STD_LOGIC;
SCL : out STD_LOGIC;
SDA :inout STD_LOGIC
);
end i2c_neuer_ansatz;
architecture i2c_neuer_ansatz_arch of i2c_neuer_ansatz is
signal STATE: STD_LOGIC_VECTOR (7 DOWNTO 0);
-- signal SDAINT: STD_LOGIC;
signal BITCOUNT: integer range 0 to 8;
constant SLAVEADD_READ: STD_LOGIC_VECTOR (7 DOWNTO 0):= "01010001";
---- I2C slave address + read
constant SLAVEADD_WRITE: STD_LOGIC_VECTOR (7 DOWNTO 0):= "01010000";
---- I2C slave address + write
signal DATA_IN: STD_LOGIC_VECTOR (7 DOWNTO 0):= "00000000";
---- Data to be written to slave
signal DATA_OUT: STD_LOGIC_VECTOR (7 DOWNTO 0):= "00000000";
---- Data to be read from slave
-- ---- for 100 kHz clock
-- constant max200k: integer:= 250;
-- signal clocktick200k: integer range 0 to max200k;
signal CLK_800kHz: STD_LOGIC;
---- CLK_200KHz is a 200 kHz clock and SCL is a 100kHz clock for i2c
signal SDA_OUT : std_logic;
signal SDA_IN : std_logic;
signal SDA_OE : std_logic;
begin
------ SDA line is open drain, therefore to set SDA to '1' we need to output a 'Z' value
-- SDA <= 'Z' when SDAINT = '1' else '0';
SDA <= SDA_OUT when SDA_OE = '1' else 'Z';
SDA_IN <= SDA when SDA_OE = '0' else '0';
---- process for implementing FSM for the I2C master controller
CLK_800kHz <= CLK_800kHz_IN;
Output: process (CLK_800kHz, RESET)
begin
if (RESET = '0') then
---- idle condition, both SDA and SCL = 1
SCL <= '1';
SDA_OUT <= '1';
SDA_OE <= '1';
State <= x"00"; ---- next state
-- elsif (CLK_800kHz'event and CLK_800kHz = '1')then
elsif rising_edge(CLK_800kHz) then
case STATE is
when x"00" =>
---- when idle, both SDA and SCL = 1
SCL <= '1';
SDA_OE <= '1';
SDA_OUT <= '1';
state <= x"01"; ---- next state
when x"01" =>
---- send start condition SDA goes from '1' to '0' with SCL = '1'
SCL <= '1';
SDA_OE <= '1';
SDA_OUT <= '0';
BITCOUNT <= 8; ---- starting bit count
state <= x"40"; ---- next state
-- when x"02" =>
-- ---- send seven bit address of the slave followed by write/read bit
-- SCL <= '0';
-- SDAINT <= SLAVEADD_WRITE (BITCOUNT - 1);
------ sending the seven bit address and write bits on SDA line
-- state <= x"03"; ---- next state
-- when x"03" =>
-- SCL <= '1';
-- if (BITCOUNT)> 0 then
------ if BITOCUNT > 0, then there are more bits to be sent. Therefore, go to state x"02"
-- BITCOUNT <= BITCOUNT - 1;
-- State <= x"02"; ---- next state
-- else
------ If BITCOUNT = 0, then all bits have been sent. Go to state x"12" and Set the value of BITCOUNT to 8
-- BITCOUNT <= 8;
-- State <= x"12"; ---- next state
-- end if;
------ address and write bits have been sent and now get acknowledgement from slave
-- when x"12" =>
-- SCL <= '0';
-- state <= x"13"; ---- next state
-- when x"13" =>
-- SCL <= '1';
-- if SDA = '1' then
------ if no acknowledgement from slave, go to the idle state. The designer can create an error state if desired and send the FSM there.
-- state <= x"00"; ---- next state
-- else
------ if there is acknowledgement from slave, go to state x"40" for reading data to the slave
-- State <= x"40"; ---- next state
-- end if;
-- ---- writing data to slave
-- when x"30" =>
-- SCL <= '0';
------ sending the data to be written on the SDA line
-- SDAINT <= DATA_IN (BITCOUNT - 1);
-- state <= x"31"; ---- next state
-- when x"31" =>
-- SCL <= '1';
-- if (BITCOUNT)> 0 then
------ if BITOCUNT > 0, then there are more bits to be sent. Therefore, go to state x"30"
-- BITCOUNT <= BITCOUNT - 1;
-- state <= x"30"; ---- next state
-- else
------ If BITCOUNT = 0, then all bits have been sent. Go to state x"32"
-- state <= x"32"; ---- next state
-- end if;
-- ----get acknowledgement from slave
-- when x"32" =>
-- SCL <= '0';
-- state <= x"33"; ---- next state
-- when x"33" =>
-- BITCOUNT <= 8;
-- SCL <= '1';
-- if SDA = '1' then
-- state <= x"00"; ---- next state
-- else
-- SDAINT <= '0';
-- state <= x"34"; ---- next state
-- end if;
-- when x"34" =>
-- SCL <= '0';
---- SDA starts at 0 to prepare for the 0 to 1 transition
-- SDAINT <= '0';
-- state <= x"42"; ---- next state
---- read from slave
when x"40" =>
---- send seven bit address of the slave followed by read bit
SCL <= '0';
SDA_OE <= '1';
SDA_OUT <= SLAVEADD_READ (BITCOUNT - 1);
state <= x"41"; ---- next state
when x"41" =>
SCL <= '1';
if (BITCOUNT)> 0 then
BITCOUNT <= BITCOUNT - 1;
state <= x"40"; ---- next state
else
BITCOUNT <= 8;
state <= x"50";
end if;
---- get acknowledgement from slave
when x"50" =>
BITCOUNT <= 8;
SDA_OE <= '0';
SCL<= '0';
state <= x"51"; ---- next state
when x"51" =>
SCL <= '1';
SDA_OE <= '0';
if SDA = '1' then
state <= x"00";
else
BITCOUNT <= 8;
state <= x"52";
end if;
when x"52" =>
SDA_OE <= '0';
SCL <= '0';
state <= x"53";
when x"53" =>
SCL <= '1';
SDA_OE <= '0';
DATA_OUT(bitcount-1) <= SDA;
if (bitcount - 1) > 0 then
bitcount <= bitcount - 1;
state <= x"54";
else
bitcount <= 8;
state <= x"00";
end if;
when others =>
state <= x"00";
end case;
end if;
end process;
------ process for generating 200 kHz clock from 50 MHz input clock
--Clk200kHz: process
-- begin
-- wait until CLK_50MHz'event and CLK_50MHz = '1';
-- if clocktick200k < max200k then
-- clocktick200k <= clocktick200k + 1;
-- else
-- clocktick200k <= 0;
-- end if;
-- if clocktick200k < max200k/2 then
-- CLK_200KHz <= '0';
-- else
-- CLK_200KHz <= '1';
-- end if;
-- end process;
end i2c_neuer_ansatz_arch;
答案 0 :(得分:3)
您的三态管理不好。
您的主要问题在这条线上,我认为此评论有误:
---- SDA line is open drain, therefore to set SDA to '1' we need to output a 'Z' value
SDA <= 'Z' when SDAINT = '1' else '0';
为了管理VHDL中的 INOUT ,您的模块 i2c_neuer_ansatz 中应该有三个内部信号:
这是您应该写的行,而不是我引用的那一行:
SDA <= SDA_OUT when SDA_OE = '1' else 'Z';
您可以使用此行来处理输入模式:
SDA_IN <= SDA when SDA_OE = '0' else '0';
但是第二行不是必需的,您也可以在代码输入中直接使用SDA(您已经做到了)。
在代码中,您只需添加输出启用管理。