我正在尝试实现与ADC通信的I2C总线。我编写了一个(尚未完成的)状态机,该状态机应实现I2C协议。这些功能是:向ADC写入配置,然后从ADC读取两个字节,其中包括4个起始位和12个数据位。 我的问题是:ADC似乎对他的地址没有反应。我认为,我可以从主服务器验证工作协议,包括启动条件。起初我以为ADC会将SDA拉低并确认他的地址。但是问题是:当主机没有积极地写“ 1”时,我的SDA总是很低。现在,我在3.3V处增加了一个上拉电阻,可以确认ADC对他的地址没有反应。我需要搜索“硬件”和“ VHDL-代码”中的错误,但我希望有人查看我的VHDl代码。我对VHDL完全没有经验,所以也许我做错了。
我将添加代码和一个用于模拟的测试平台。
VHDL代码:
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.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_eigenes is
generic ( Config : STD_LOGIC_VECTOR(7 downto 0) := "00100000"); --Parametrierungsvektor des AD- Wandlers.
PORT
(
-- next_sample : OUT STD_LOGIC; --Das naechste Sample ist bereit um Verschicken.
-- sda_read : IN STD_LOGIC; --Eingelesener Zustand des SDA- Ports.
ack_error : OUT STD_LOGIC; --Fehler in der Datenuebertragung.
sys_clk : IN STD_LOGIC; --Systemtakt.
ena : IN STD_LOGIC; --Enable- Leitung zum Aktivieren des Protokollablaufs.
-- data_rd : OUT STD_LOGIC_VECTOR(15 DOWNTO 0); --Gelesene Daten.
sda : INOUT STD_LOGIC; --SDA (Seriald Data) Leitung bidirektional.
scl : OUT STD_LOGIC; --SCL (Serial Clock) Leitung unidirektional.
sda_clk_out : out std_logic; --Debugging
status_out0 : out std_logic; --Debugging
status_out1 : out std_logic; --Debugging
status_out2 : out std_logic; --Debugging
status_out3 : out std_logic; --Debugging
wait_stop_out : out std_logic --Debugging
);
end i2c_eigenes;
architecture i2c_eigenes_arch of i2c_eigenes is
-- TYPE fsm_machine IS(IDLE, STARTUP, START, INIT, CONF, READ_B1, READ_B2, STOP); --Benötigte Zustände
TYPE fsm_machine IS(IDLE, START, INIT, CONF, PREP_READ, READ_B1, READ_B2, STOP); --Benötigte Zustände
signal current_state : fsm_machine; --Aktueller Zustand
--Taktsignale
signal sda_clk : STD_LOGIC; --Taktsignal fuer SDA.
signal sda_clk_prev : STD_LOGIC; --Speicher des vorherigen Zustands von SDA.
signal scl_clk : STD_LOGIC; --Taktsignal SCL.
signal i : INTEGER := 8; --Pointer auf Bitposition.
signal j : INTEGER := 9; --Pointer auf Bitposition.
signal count : UNSIGNED (9 downto 0):= (others => '0'); --Zaehler fuer Taktung.
--SDA und SCL
signal scl_ena : STD_LOGIC := '0'; --SCL wird aktiviert.
signal scl_ena_hold : STD_LOGIC := '1'; --Signalisiert gehaltene SCL Leitung waehrend des Stretchens.
--Protokollsignale
signal wait_cnt : INTEGER := 1;
signal sign_ack_error : std_logic := '0';
signal bit_cnt : INTEGER RANGE 0 TO 12 := 7; --Pointer auf das zu lesende/schreibende Bit.
signal init_stop : BOOLEAN := FALSE; --Signalisiert (erneute) Stop Bedingung.
signal acknowledged : STD_LOGIC := '0'; --Speichert ob eine Datenuebertargung vom Slave bestaetigt wurde.
signal reset : STD_LOGIC := '1';
signal wait_stop : std_logic := '0';
--Datenbuffer
signal data_send : STD_LOGIC_VECTOR(7 DOWNTO 0); --Zu sendende Daten.
signal data_read : STD_LOGIC_VECTOR(8 DOWNTO 0); --Empfangene Daten.
signal data_col : STD_LOGIC_VECTOR( 15 downto 0) := (others => '0'); --Buffer fuer zusammengefuegte empfangene Daten.
--SDA Zustand
signal sda_in : std_logic;
signal sda_out : std_logic := '1';
signal sda_oe : std_logic := '1'; --Output enable
signal sign_status_out : std_logic_vector(3 downto 0); --debugging
begin
-- Signalzuweisungen
sda <= 'Z' when sda_oe = '0' else sda_out;
-- sda_in <= sda when sda_oe = '0' else '0';
scl <= not scl_clk when (scl_ena = '1') else '1';
-- Internes Clocksignal
scl_clk <= count(j); --SCL wird getaktet durch das hoehere Bit
sda_clk <= count(i) XOR count(j); --SDA wird getaktet durch Exklusivoder des MSB und MSB-1
ack_error <= sign_ack_error;
-- debugging
-- sda <= sda_clk;
-- scl <= scl_clk;
sda_clk_out <= sda_clk;
status_out0 <= sign_status_out(0);
status_out1 <= sign_status_out(1);
status_out2 <= sign_status_out(2);
status_out3 <= sign_status_out(3);
wait_stop_out <= wait_stop;
Taktung: process(sys_clk, reset) --In diesem Prozess werden zwei um 90° verschobenen Taktsignale für SDA und SCL erzeugt.
begin
if(rising_edge(sys_clk)) THEN --Flankengesetuerter Takt.
if(reset = '1')then --Reset aktiv low.
count <= count + 1; --Zaehler fuer Takte.
sda_clk_prev <= sda_clk; --Speichern des alten SDA Werts.;
end if;
end if;
end process;
IIC_Protokoll : process(sys_clk, reset)
begin
if(reset = '0') then --Bei Reset werden alle Signalspeicher auf den Anfangszustand gesetzt.
-- next_sample <= '0'; --Ruecksetzen des validen next_samples.
sda_oe <= '1';
scl_ena <= '0'; --SCL- Takt deaktivieren.
bit_cnt <= 7; --Bitpointer auf Anfang.
current_state <= IDLE; --Wechsel in IDLE Zustand.
-- data_rd <= "0000000000000000"; --Leeren des gelesenen Buffers.
reset <= '1';
sda_out <= '1';
sign_ack_error <= '0';
wait_cnt <= 1;
data_col <= (others => '0');
elsif(rising_edge(sys_clk)) then
-- next_sample <= '0'; --Ruecksetzen des validen next_samples nach einem Sytentakt.
if(sda_clk = '1' and sda_clk_prev = '0') then --Zustandsdurchfuehrung und weitergabe bei steigender Flanke des SDA Takts.
Case current_state is --Abfrage des aktuellen Zustands.
when IDLE =>
sda_oe <= '1';
sign_status_out <= "0000"; --debugging
if( ena = '1')then --Start der FSM bei aktiviertem Enable.
current_state <= START; --Wechsel in den Startup Zustand.
else
current_state <= IDLE; --Schleife um im IDLE Mode zu bleiben.
end if;
when START =>
scl_ena <= '1'; --SCL Takt aktivieren.
sda_out <= '0';
sign_status_out <= "0010"; --debugging
sda_oe <= '1';
data_send <= "01010000"; --IIC 7bit Startadresse mit Write Bit.
current_state <= INIT; --Wechsel in den Initiierungszustand
when INIT =>
sign_status_out <= "0011"; --debugging
scl_ena <= '1';
if(bit_cnt = 0) then --Pruefen ob alle Bits uebertragen wurden.
sda_oe <= '0';
bit_cnt <= 8; --Bitpointer auf Anfangsadresse.
current_state <= CONF; --Naechster Status Konfiguration.
data_send <= Config;
acknowledged <= not sda;
sign_ack_error <= sda;
-- acknowledged <= not sda_in; --Pruefen ob der Slave die Transaktion validiert hat (validiert => sda_in = 0)
-- sign_ack_error <= sda_in; --Meldung des Fehlers an Headerdatei.
else
sda_oe <= '1';
bit_cnt <= bit_cnt - 1; --Dekrementieren des Pointers.
sda_out <= data_send(bit_cnt - 1); --Zuweisen des Bitvektors an SDA in Abhängigkeit des Bitpointers.
end if;
when CONF =>
if(acknowledged = '1')then --Pruefen ob letzte Uebertragung verifiziert wurde.
sign_status_out <= "0100"; --debugging
if( bit_cnt = 0) then
sda_oe <= '0';
bit_cnt <= 8;
current_state <= PREP_READ;
data_send <= "01010001";
acknowledged <= not sda;
sign_ack_error <= sda;
-- acknowledged <= not sda_in; --Pruefen ob der Slave die Transaktion validiert hat.
-- sign_ack_error <= sda_in; --Meldung des Fehlers an Headerdatei.
wait_stop <= '1';
else
sda_oe <= '1';
bit_cnt <= bit_cnt - 1; --Dekrementieren des Pointers.
sda_out <= data_send(bit_cnt-1); --Zuweisen des Bitvektors an SDA in Abhängigkeit des Bitpointers.
end if;
end if;
when PREP_READ =>
sign_status_out <= "0101"; --debugging
if(acknowledged = '1')then
-- if (wait_stop = '1')then --Warte einen Takt, bevor neues Startsignal gegeben wird
-- wait_stop <= '0';
-- sda_oe <= '1';
-- sda_out <= '1';
-- current_state <= PREP_READ;
-- else
if( bit_cnt = 0) then
sda_oe <= '0';
bit_cnt <= 9;
current_state <= READ_B1;
acknowledged <= not sda;
sign_ack_error <= sda;
-- acknowledged <= not sda_in; --Pruefen ob der Slave die Transaktion validiert hat.
-- sign_ack_error <= sda_in; --Meldung des Fehlers an Headerdatei
else
sda_oe <= '1';
bit_cnt <= bit_cnt - 1; --Dekrementieren des Pointers.
sda_out <= data_send(bit_cnt-1); --Zuweisen des Bitvektors an SDA in Abhängigkeit des Bitpointers.
end if;
-- end if;
end if;
when READ_B1 =>
sign_status_out <= "1000"; --debugging
if(acknowledged = '1')then
if(bit_cnt = 1)then
sda_oe <= '1'; --master ack
sda_out <= '0'; --master ack
bit_cnt <= bit_cnt - 1;
elsif(bit_cnt = 0) then
sda_oe <= '0';
data_col(15 downto 8) <= data_read(7 downto 0);
bit_cnt <= 9;
data_read <= (others => '0');
current_state <= READ_B2;
else
sda_oe <= '0';
bit_cnt <= bit_cnt - 1;
-- data_read(bit_cnt - 2) <= sda_in;
data_read(bit_cnt - 2) <= sda;
end if;
end if;
when READ_B2 =>
sign_status_out <= "1001"; --debugging
if(bit_cnt = 1)then
sda_oe <= '1'; --master ack
sda_out <= '0'; --master ack
bit_cnt <= bit_cnt - 1;
elsif(bit_cnt = 0) then
sda_oe <= '0';
data_col(7 downto 0) <= data_read(7 downto 0);
bit_cnt <= 9;
data_read <= (others => '0');
current_state <= READ_B2;
else
sda_oe <= '0';
bit_cnt <= bit_cnt - 1;
-- data_read(bit_cnt - 2) <= sda_in;
data_read(bit_cnt - 2) <= sda;
end if;
when others =>
current_state <= STOP;
end case;
end if;
end if;
end process IIC_Protokoll;
end i2c_eigenes_arch;
测试台:
library IEEE;
use IEEE.STD_LOGIC_1164.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 sim_eigenes_i2c_bis_ReadB2 is
-- Port ( );
end sim_eigenes_i2c_bis_ReadB2;
architecture sim_eigenes_i2c_bis_ReadB2_arch of sim_eigenes_i2c_bis_ReadB2 is
component i2c_eigenes is
generic ( Config : STD_LOGIC_VECTOR(7 downto 0) := "00010000"); --Parametrierungsvektor des AD- Wandlers.
PORT
(
-- next_sample : OUT STD_LOGIC; --Das naechste Sample ist bereit um Verschicken.
-- sda_read : IN STD_LOGIC; --Eingelesener Zustand des SDA- Ports.
ack_error : OUT STD_LOGIC; --Fehler in der Datenuebertragung.
sys_clk : IN STD_LOGIC; --Systemtakt.
ena : IN STD_LOGIC; --Enable- Leitung zum Aktivieren des Protokollablaufs.
-- data_rd : OUT STD_LOGIC_VECTOR(15 DOWNTO 0); --Gelesene Daten.
sda : INOUT STD_LOGIC; --SDA (Seriald Data) Leitung bidirektional.
scl : OUT STD_LOGIC; --SCL (Serial Clock) Leitung unidirektional.
sda_clk_out : out std_logic; --Debugging
status_out0 : out std_logic; --Debugging
status_out1 : out std_logic; --Debugging
status_out2 : out std_logic; --Debugging
status_out3 : out std_logic; --Debugging
wait_stop_out : out std_logic --Debugging
);
end component i2c_eigenes;
signal sign_ack_error : std_logic;
signal sign_sys_clk : std_logic;
signal sign_ena : std_logic := '1';
signal sign_data_rd : std_logic_vector (15 downto 0);
signal sign_sda : std_logic;
signal sign_scl : std_logic;
signal sign_status_out0 : std_logic;
signal sign_status_out1 : std_logic;
signal sign_status_out2 : std_logic;
signal sign_status_out3 : std_logic;
signal sign_sda_clk_out : std_logic;
signal sign_wait_stop_out : std_logic;
begin
dut : i2c_eigenes
port map
(
ack_error => sign_ack_error, --Fehler in der Datenuebertragung.
sys_clk => sign_sys_clk, --Systemtakt.
ena => sign_ena, --Enable- Leitung zum Aktivieren des Protokollablaufs.
-- data_rd => sign_data_rd, --Gelesene Daten.
sda => sign_sda, --SDA (Seriald Data) Leitung bidirektional.
scl => sign_scl, --SCL (Serial Clock) Leitung unidirektional.
sda_clk_out => sign_sda_clk_out,
status_out0 => sign_status_out0,
status_out1 => sign_status_out1,
status_out2 => sign_status_out2,
status_out3 => sign_status_out3,
wait_stop_out => sign_wait_stop_out
);
clk_gen : process
begin
sign_sys_clk <= '1';
wait for 4ns;
sign_sys_clk <= '0';
wait for 4ns;
end process clk_gen;
end sim_eigenes_i2c_bis_ReadB2_arch;
答案 0 :(得分:0)
好的,我不得不更新许多VHDL代码,而且!必须在SDA线上增加一个上拉电阻!做到了。现在工作正常!有时间的时候,我会发布代码。