VHDL High 'Z' при использовании двунаправленной шины I2C с АЦП - PullRequest
0 голосов
/ 04 июля 2019

Я пытаюсь реализовать шину I2C, которая связывается с АЦП.Я написал (еще не законченный) конечный автомат, который должен реализовать протокол I2C.Функции: записать конфигурацию в АЦП, затем прочитать два байта из АЦП, которые включают в себя 4 начальных бита и 12 битов данных.Моя проблема: АЦП, похоже, не реагирует на его адрес.На мой взгляд, я мог проверить рабочий протокол от мастера, включая условие запуска.Сначала я подумал, что АЦП устанавливает низкий уровень SDA и подтверждает его адрес.Но проблема была в том, что мой SDA всегда был низким, когда мастер не писал активно «1».Теперь я добавил подтягивающий резистор до 3,3 В и могу подтвердить, что АЦП не реагирует на его адрес.Мне нужно искать ошибку как в аппаратном, так и в 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;

Testbench:

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;

1 Ответ

0 голосов
/ 05 июля 2019

Хорошо, мне пришлось обновить большую часть кода VHDL и !! пришлось добавить подтягивающий резистор в линию SDA !! Это добилось цели. Теперь работает нормально! Когда я найду время, я отправлю код.

...