Порт VHDL INOUT не обеспечивает сигнал (I2C)

в рамках проекта я пытаюсь внедрить в свой проект очень простой модуль 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;

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
762
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваше управление тремя состояниями не очень хорошо.

Ваша основная проблема в этой строке, и я думаю, что комментарий неверен:

---- 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, у вас должно быть три внутренних сигнала в вашем модуле i2c_neuer_ansatz:

  • Один для поведения ввода: SDA_IN
  • Один для выходного поведения: SDA_OUT (вы назвали его SDAINT)
  • Один для управления между режимами входа и выхода: SDA_OE (обозначает включение выхода)

Это строка, которую вы должны написать вместо той, которую я процитировал:

SDA <= SDA_OUT when SDA_OE = '1' else 'Z';

И вы можете использовать эту строку для обработки режима ввода:

SDA_IN <= SDA when SDA_OE = '0' else '0';

Но эта вторая строка не является обязательной, вы также используете SDA напрямую, как при вводе в свой код (вы уже это сделали).

В вашем коде вам просто нужно добавить управление выход включить.

Здравствуйте Гаутито, спасибо за ответ! Вы уже помогли мне с моей последней проблемой :). Итак, в основном мне нужно объявить три сигнала: SDA_OUT, SDA_IN и SDA_OE. Вы упомянули, что я обычно уже использую SDA в качестве входа, поэтому мне просто нужно управлять, когда порт должен быть выходом. И это, когда я нахожусь в ведущем режиме, поэтому при записи команд и данных и т. д. Поскольку я хочу сосредоточиться на чтении данных с АЦП, я думаю, что могу пропустить запись данных (кроме адреса и т. д.)

user10622651 01.07.2019 14:42

А теперь: мне нужно писать SDA_OUT как «1» и «0» в моем коде, или мне также нужно писать это в «Z»?

user10622651 01.07.2019 14:43

Насколько я понимаю, я добавил свой обновленный код в свой первоначальный пост, пока симуляция выглядит нормально, но я был бы признателен, если бы вы могли проверить мой обновленный код. заранее спасибо

user10622651 01.07.2019 15:04

Привет, Алекс :), да, вы должны установить SDA_OE в «1», когда вы находитесь в состоянии записи, и поставить его в «0», когда вы хотите читать по шине. И нет, вам не нужно устанавливать SDA_OUT в «Z», достаточно присвоения SDA.

Gautitho 01.07.2019 15:05

Ваше управление входом кажется хорошим, но если вы создаете внутренний сигнал SDA_IN (не обязательно), вы должны использовать его вместо самого SDA. Нет ссылки, но в состоянии x53 вы переходите в состояние x54, которого не существует.

Gautitho 01.07.2019 15:17

Хорошо, теперь я вижу ожидаемый сигнал! Кажется, сейчас у меня проблемы с ведомым устройством и получением данных, но я буду работать над этой проблемой. Большое спасибо!

user10622651 01.07.2019 15:27

Другие вопросы по теме