首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带模数转换器的双向I2C总线的VHDL高Z

带模数转换器的双向I2C总线的VHDL高Z
EN

Stack Overflow用户
提问于 2019-07-04 20:25:36
回答 1查看 212关注 0票数 0

我正在尝试实现一个与模数转换器通信的I2C总线。我编写了一个(尚未完成)状态机,它应该实现I2C协议。其功能是:将配置写入ADC,然后从ADC读取两个字节,包括4个起始位和12个数据位。我的问题是:艺术发展局似乎对他的地址没有反应。在我看来,我可以从主机验证工作协议,包括启动条件。起初我以为,ADC拉低了SDA,并确认了他的地址。但问题是:我的SDA总是很低,当主控没有积极地写一个'1‘的时候。现在,我在3,3V电压下添加了一个上拉电阻,我可以确认ADC对他的地址没有反应。我需要在硬件和硬件描述语言代码中查找错误,但我希望有人能看看我的VHDL代码。我对VHDL一点经验都没有,所以可能我做错了什么。

我将添加代码和用于模拟的测试平台。

VHDL代码:

代码语言:javascript
运行
复制
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:

代码语言:javascript
运行
复制
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;
EN

回答 1

Stack Overflow用户

发布于 2019-07-05 15:42:17

好吧,我不得不更新了很多VHDL代码,并在SDA线上添加了一个上拉电阻来完成这项工作。现在它工作得很好了!当我找到时间,我会发布代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56887928

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档