Использование BUFG для управления тактовой нагрузкой

Я пытаюсь работать с пиксельными данными, которые выводятся на микросхему DVI. Используются различные тактовые частоты, потому что регистры микросхемы DVI программируются с использованием I2C (поэтому требуется тактовая частота <500 кГц) - от делителя тактовой частоты.

Микросхему DVI требуется дифференциальная тактовая частота пикселей 40 МГц, однако DVI отображает полбайта дважды за цикл, поэтому необходимы дополнительные тактовые импульсы 80 МГц, чтобы проталкивать каждую половину пикселя на линии данных с каждым полупериодом. из DCM.

Это привело к множеству проблем. Я попытался просто использовать двойную тактовую частоту пикселя, чтобы поменять местами каждую половину пикселя, но получил ошибку:

This design contains a global buffer instance, <out2_bufg>, driving the net, <pxlclk_p_int>, that is driving the following (first 30) non-clock load pins.

Поэтому я добавил элемент BUFG между выходом DCM и компонентами, использующими сигнал, но он ничего не изменил, вместо этого ошибка теперь выдается дважды как на входе, так и на выходе BUFG.

  • Как я могу это исправить - учитывая, что я только что добавил BUFG, и он ему не нравится!

Мой код ниже; Я попытался вырезать несвязанные вещи, которые не имеют отношения к часам, но они все еще довольно длинные!

РЕДАКТИРОВАТЬ 1: Я добавил блок, который при добавлении в систему вызвал ошибку (которой раньше не было). Это во втором блоке кода! В настоящее время я работаю над другими предложениями, касающимися дифференциальной сигнализации, и буду редактировать снова, когда закончу!

Спасибо большое,

Дэйвид

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
library UNISIM;
use UNISIM.VComponents.all;

ENTITY I2CBus IS
    PORT(
        SYSCLK_N   : IN    STD_LOGIC;   --system 200MHz differential clock
        SYSCLK_P   : IN    STD_LOGIC;
        BTN        : IN    STD_LOGIC;   -- to manually change reset

        LED        : OUT   STD_LOGIC_VECTOR(3 downto 0); --to observe reset value
        SCL_DBG    : OUT   STD_LOGIC;   -- copy of SCL to output pin
        SDA_DBG    : OUT   STD_LOGIC;   --copy of SDA to output pin
        SCL        : OUT   STD_LOGIC;   --Serial Clock Line
        SDA        : INOUT STD_LOGIC;   --Serial Data Line

        DVIRESET_N : OUT   STD_LOGIC;   --reset_n to dvi device
        DVI_ENABLE : OUT   STD_LOGIC;   --enable DVI device inputs (active high)
        PXLCLK_P   : OUT   STD_LOGIC;   --pixel clock differential pair through buffers
        PXLCLK_N   : OUT   STD_LOGIC;
        DVI_DATA   : OUT   STD_LOGIC_VECTOR(11 downto 0); --12 bit multiplexed pixel to DVI
        HSYNC      : OUT   STD_LOGIC;   --Horizontal/Vertical sync timing pulses
        VSYNC      : OUT   STD_LOGIC
    );
END I2CBus;
ARCHITECTURE behavior OF I2CBus IS
    COMPONENT IIC_MASTER                --sends data to write out onto SDA bus line in I2C protocol
        PORT(SCL     : IN    STD_LOGIC;
             SCL2X   : IN    STD_LOGIC;
             RESET_N : IN    STD_LOGIC;
             ENA     : IN    STD_LOGIC;
             ADR     : IN    STD_LOGIC_VECTOR(6 DOWNTO 0);
             REG     : IN    STD_LOGIC_VECTOR(7 DOWNTO 0);
             RW      : IN    STD_LOGIC;
             DAT_WR  : IN    STD_LOGIC_VECTOR(7 DOWNTO 0);
             BUSY    : OUT   STD_LOGIC;
             SDA     : INOUT STD_LOGIC;
             ACK_ERR : BUFFER STD_LOGIC);
    END COMPONENT IIC_MASTER;
    COMPONENT DCM                       --takes input system differential clocks, generates further clocks
        PORT(
            SYSCLK_P : IN  STD_LOGIC;   -- CLOCK IN PORTS 200MHZ DIFFERENTIAL
            SYSCLK_N : IN  STD_LOGIC;
            -- CLOCK OUT PORTS
            SYSCLK   : OUT STD_LOGIC;
            PXLCLK   : OUT STD_LOGIC;
            PXLCLK2X : OUT STD_LOGIC
        );
    END COMPONENT;

    COMPONENT CLK_DIVIDER               --divides system clock down for i2c bus clock line
        GENERIC(INPUT_FREQ : INTEGER;
                OUT1_FREQ  : INTEGER;
                OUT2_FREQ  : INTEGER);
        PORT(SYSCLK      : IN  STD_LOGIC;
             RESET_N     : IN  STD_LOGIC;
             RESET_N_OUT : OUT STD_LOGIC;
             OUT1        : OUT STD_LOGIC;
             OUT2        : OUT STD_LOGIC);
    END COMPONENT CLK_DIVIDER;

    COMPONENT DVI_INITIALISE            --initialises CH7301c registers to necessary operation values
        PORT(SYSCLK      : IN  STD_LOGIC;
             ACK_ERR     : IN  STD_LOGIC;
             BUSY        : IN  STD_LOGIC;
             RESET_N     : IN  STD_LOGIC;
             COUNT       : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
             DVI_WR      : OUT STD_LOGIC := '0';
             DVI_REGDATA : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
             DVI_WDATA   : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
    END COMPONENT DVI_INITIALISE;

    COMPONENT DVI_INTERFACE             --outputs sync pulses, controls enable and manages pixel addresses
        PORT(PIXEL_CLK    : IN  STD_LOGIC;
             RESET_N      : IN  STD_LOGIC;
             PXL_ADDR     : OUT STD_LOGIC_VECTOR(19 DOWNTO 0) := (OTHERS => '0');
             HSYNC, VSYNC : OUT STD_LOGIC                     := '1';
             ENABLE       : OUT STD_LOGIC                     := '0');
    END COMPONENT DVI_INTERFACE;

    COMPONENT DVI_MUX
        PORT(PXLCLK   : IN  STD_LOGIC;
             PXLCLK2X : IN  STD_LOGIC;
             PXL_DAT  : IN  STD_LOGIC_VECTOR(23 DOWNTO 0); --pixel as RGB
             DATA     : OUT STD_LOGIC_VECTOR(11 DOWNTO 0); --multiplexed output
             RESET_N  : IN  STD_LOGIC); --reset low signal
    END COMPONENT DVI_MUX;

    --Inputs
    signal reset_n_input : std_logic;   -- input reset from button

    ----Outputs ------
    signal sda_internal : STD_LOGIC;    -- Internal SDA

    ----Clocks-----
    signal SCL_internal   : std_logic;  -- i2c clock
    signal SCL2X_internal : std_logic;  -- i2c x2 to load SDA data
    signal sysclk         : std_logic;  --system clock
    signal pxlclk_p_int   : std_logic;  --differential pixel clock pair
    signal pxlclk_n_int   : std_logic;
    signal pxlclk         : std_logic;  --pxlclk after BUFG
    signal pxlclk2x_int   : STD_LOGIC;  --2x pixel clock for loading pixel data

    -----Internal Control Signals ---
    signal reset_n : std_logic;         --active high
    signal busy    : std_logic;         --low when not i2c not busy
    signal ack_err : std_logic;         --high when i2c ackknowledge error occurs

    ----Internal Data-----
    signal i2c_reg  : STD_LOGIC_VECTOR(7 DOWNTO 0); --register data for I2C
    signal i2c_rw   : STD_LOGIC;        --R/W* for I2C
    signal i2c_data : STD_LOGIC_VECTOR(7 DOWNTO 0); --Data for I2C

BEGIN
    master : IIC_Master
        port map(
            SCL     => SCL_internal,
            SCL2X   => SCL2X_internal,
            RESET_N => RESET_N,
            ENA     => '1',
            ADR     => "1110110",
            REG     => i2c_reg,
            RW      => i2c_rw,
            DAT_WR  => i2c_data,
            BUSY    => busy,
            SDA     => sda_internal,
            ACK_ERR => ack_err
        );
    DCM_SYS : DCM
        port map(
            SYSCLK_P => SYSCLK_P,       --take differential input clock
            SYSCLK_N => SYSCLK_N,
            SYSCLK   => sysclk,         --200 MHz system clock 
            PXLCLK   => pxlclk,         --and pixel clock
            PXLCLK2X => pxlclk2x_int    --pixel clock at double rate
        );

    Clk_Div : Clk_Divider
        generic map(
            INPUT_FREQ => 200000000,    --200 MHz system input
            OUT1_FREQ  => 100000,       --to work correctly, 200 must go into all frequencies (x2).
            OUT2_FREQ  => 200000        --i.e. from 200, cannot generate 40 as 200/40/2 = 2.5, which will be 2
        )
        port map(
            SYSCLK      => sysclk,
            RESET_N     => reset_n_input,
            RESET_N_OUT => reset_n,
            OUT1        => scl_internal,
            OUT2        => scl2x_internal
        );

    data_load : component DVI_INITIALISE
        port map(
            SYSCLK      => sysclk,
            ACK_ERR     => ack_err,
            BUSY        => busy,
            RESET_N     => reset_n,
            COUNT       => LED,
            DVI_WR      => i2c_rw,
            DVI_REGDATA => i2c_reg,
            DVI_WDATA   => i2c_data
        );

    interface : DVI_INTERFACE
        port map(
            PIXEL_CLK => pxlclk_p_int,
            RESET_N   => reset_n,
            PXL_ADDR  => open,
            HSYNC     => HSYNC,
            VSYNC     => VSYNC,
            ENABLE    => DVI_ENABLE
        );

    pxl_mux : DVI_MUX
        port map(
            PXLCLK   => pxlclk_p_int,
            PXLCLK2X => pxlclk2x_int,
            PXL_DAT  => x"FF0000",
            DATA     => DVI_DATA,
            RESET_N  => reset_n
        );
    ------------OUTPUT BUFFERS (CLOCK FORWARDING)------------
    ODDR_pxlclk_p : ODDR2
        generic map(
            DDR_ALIGNMENT => "NONE",
            INIT          => '0',
            SRTYPE        => "SYNC")
        port map(
            Q  => PXLCLK_P,             --output to positive output
            C0 => pxlclk_p_int,         --differential input
            C1 => pxlclk_n_int,
            CE => '1',                  --chip enable tied high
            D0 => '1',
            D1 => '0',
            R  => '0',
            S  => '0'
        );

    ODDR_pxlclk_n : ODDR2
        generic map(
            DDR_ALIGNMENT => "NONE",
            INIT          => '0',
            SRTYPE        => "SYNC")
        port map(
            Q  => PXLCLK_N,             --output to negative output
            C0 => pxlclk_n_int,
            C1 => pxlclk_p_int,
            CE => '1',
            D0 => '1',
            D1 => '0',
            R  => '0',
            S  => '0'
        );

    out2_bufg : BUFG port map(I => pxlclk, O => pxlclk_p_int); --ERROR THROWN ON I/O HERE 
    ----------------Mappings---------------------------
    reset_n_input <= not BTN;           --when button pressed, reset
    SCL           <= 'Z' when scl_internal = '1' else scl_internal;
    SCL_DBG       <= 'Z' when scl_internal = '1' else scl_internal;
    SDA           <= sda_internal;
    SDA_DBG       <= SDA;               --copy SDA to debug line

    DVIRESET_N   <= reset_n;            --reset DVI device 
    pxlclk_n_int <= not pxlclk_p_int;   --create differential pair

end behavior;

DVI_MUX Когда я добавил этот блок в систему, ошибка возникла там, где раньше не было

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

ENTITY DVI_MUX IS
    PORT(
        PXLCLK   : IN  STD_LOGIC;       --pixel clock
        PXLCLK2X : IN  STD_LOGIC;       --double freq. pixel clock
        PXL_DAT  : IN  STD_LOGIC_VECTOR(23 downto 0); --pixel in RGB format
        DATA     : OUT STD_LOGIC_VECTOR(11 downto 0); --
        RESET_N  : IN  STD_LOGIC
    );
END ENTITY DVI_MUX;

architecture RTL of DVI_Mux is
begin
    mux_proc : process(PXLCLK2X)
    begin
        if falling_edge(PXLCLK2X) then
            if PXLCLK = '0' then        -- if pxlclk low, load first half of pixel
                DATA <= PXL_DAT(23 downto 16) & PXL_DAT(11 downto 8);
            else    --else load second half
                DATA <= PXL_DAT(15 downto 12) & PXL_DAT(7 downto 0);
            end if;
            if RESET_N = '0' then --if reset active7
                DATA <= (others => '1');
            end if;
        end if;
    end process;

end architecture RTL;

person davidhood2    schedule 11.12.2015    source источник
comment
Проблема также может быть в компонентах DVI_INTERFACE и DVI_MUX. Метод ошибки указывает, что тактовый сигнал используется как не тактовый сигнал в комбинационной логике.   -  person Martin Zabel    schedule 11.12.2015
comment
@MartinZabel Я вставил новый блок, который вызвал ошибку, но я не понимаю, почему простой просмотр значения часов должен вызывать ошибку?   -  person davidhood2    schedule 11.12.2015
comment
@ davidhood2 спасибо за обновление, я обновил свой ответ   -  person scary_jeff    schedule 11.12.2015


Ответы (3)


Это не дает прямого ответа на ваш вопрос, но похоже, что вы пытаетесь использовать примитив вывода DDR для управления выводом внешней дифференциальной синхронизации. Это хорошее занятие, но то, как вы это сделали, кажется нетрадиционным. Стандартный способ сделать это будет выглядеть примерно так:

РЕДАКТИРОВАТЬ: Я понял, что неправильно понял вопрос, и включил создание экземпляра дифференциального вывода из @StuartVivian

pxclk_inverted <= not pxlclk;

ODDR_pxlclk_p : ODDR2
    generic map(
        DDR_ALIGNMENT => "NONE",
        INIT          => '0',
        SRTYPE        => "SYNC")
    port map(
        Q  => PXLCLK_OUT,
        C0 => pxlclk,
        C1 => pxclk_inverted,
        CE => '1',
        D0 => '1',
        D1 => '0',
        R  => '0',
        S  => '0'
    );

inst_obufds : OBUFDS 
generic map (
  IOSTANDARD=>"LVDS_25"
) 
port map 
(
  O => PXLCLK_OUT_P, 
  OB  => PXLCLK_OUT_N, 
  I   => PXLCLK_OUT
);

При назначении ввода-вывода PXLCLK_OUT_N / P будет затем настроен на использование стандарта дифференциального ввода-вывода. В графическом окне назначения контактов этот порт будет использовать два контакта и позволит вам назначить их только действительной положительной / отрицательной паре. То, что вы пытаетесь сделать, - это вручную создать положительные и отрицательные сигналы перед выходным примитивом DDR, что не так, как должно работать.

Я думаю, если вы воспользуетесь этой техникой и избавитесь от своего BUFG, ваша проблема исчезнет. Если нет, возможно, обновите вопрос этим, и какой бы ни была новая проблема.


Теперь, когда вы обновили вопрос, я вижу, что ваши выходные данные пикселя также кажутся шиной DDR. Вы пытаетесь вывести поведение вывода DDR, реализуя мультиплексор, используя тактовый сигнал в качестве строки выбора.

Более стандартный способ сделать это - создать экземпляры n выходных примитивов DDR, по одному для каждого бита параллельного вывода DDR. Согласно последнему стандарту VHDL (VHDL2008) можно сделать вывод о выходе DDR, но проблема в том, что этот метод еще не имеет широко распространенной поддержки инструментальной цепочки.

person scary_jeff    schedule 11.12.2015
comment
Спасибо ! - один вопрос - как мне установить дифференциал io в ограничениях? - person davidhood2; 11.12.2015
comment
Я предполагаю, что вы используете запуск PlanAhead из Xilinx ISE для планирования ввода-вывода, и в этом случае вам просто нужно найти требуемый вывод и использовать раскрывающийся список стандарта ввода-вывода, чтобы выбрать что-то отличное. - person scary_jeff; 11.12.2015
comment
@ davidhood2 Можно использовать всего два триггера ODDR2. Если вы хотите использовать метод, опубликованный scary_jeff, вы также можете получить дифференциальный выход, создав экземпляр OBUFDS между выходом ODDR2 и контактами. Найдите описание OBUFDS в UG615 от Xilinx. - person Martin Zabel; 11.12.2015
comment
Я попытался изменить свой верхний уровень, чтобы использовать OBUFDS, но дифференциальные часы чипа подключены к контактам C20 и C22 в банке 1 - и в руководстве по ресурсам говорится, что банк 1 не поддерживает дифференциальные стандарты io. Однако - я последовал вашему совету, использовал цикл генерации для создания 11 ODDR, поэтому, хотя все ответы были правильными, я выбрал этот ответ в качестве выбранного мной! Спасибо! - person davidhood2; 11.12.2015

После этого сообщения об ошибке в проекте должен быть список до 30 контактов, которые, по мнению инструмента, вы ведете вместе с часами, но не являются настоящими выводами часов.

Контакты C0 и C1 следует рассматривать как часы, поэтому я сомневаюсь, что он на это жалуется. Поскольку тактовый сигнал поступает в другие блоки, для которых у нас нет кода, могут ли они содержать конечные точки для часов, которые не являются выводами часов?

Я согласен с ответом scary_jeff относительно использования ODDR2. Чтобы сделать дифференциальный вывод из вывода ODDR, вам необходимо создать экземпляр дифференциального драйвера в коде, то есть LVDS_25 или LVDS в архитектуре Xilinx, а затем установить логический стандарт в файлах ограничений ucf или xdc / sdc. Документация по инструментам должна содержать наглядные примеры этого.

inst_obufds : OBUFDS 
generic map ( IOSTANDARD=>"LVDS_25" ) 
port map 
(    O => DIFF_P, 
     OB  => DIFF_N, 
     I   => internal_signal
);
person sv65536    schedule 11.12.2015
comment
После сообщения не было списка контактов (я посмотрел) - но я работаю над изменением системы для использования OBUFDS! - person davidhood2; 11.12.2015
comment
Я понял, что мой ответ на самом деле не обеспечивает требуемого дифференциального вывода, поэтому я добавил ваш экземпляр дифференциального буфера к моему ответу и проголосовал за ваш, надеюсь, это было нормально. - person scary_jeff; 11.12.2015
comment
Я только что отредактировал свой код, чтобы отразить это, но контакты, которые мне нужны для вывода моей дифференциальной пары (C20 и C22), расположены в банке 1, и поэтому LVDS_25 не разрешен. Любые идеи? - person davidhood2; 11.12.2015
comment
Чтобы использовать выход diff, два контакта должны быть частью пары P-N. Используемый логический стандарт должен использовать совместимые напряжения питания со всеми другими вводами-выводами в банке. Поддержка также зависит от используемого вами устройства. 7-я серия имеет два разных типа общего банка ввода-вывода: HR (высокий диапазон) и HP (высокая производительность). HR может использовать 2,5 В постоянного тока и поэтому использует LVDS_25. HP может использовать 1,8 В для LVDS, и я считаю, что стандартной строкой ввода-вывода для этого является LVDS. Спартанцы снова другие. Обратитесь к руководству пользователя по характеристикам постоянного тока для устройства, на которое вы ориентируетесь, на предмет поддерживаемых стандартов. - person sv65536; 11.12.2015

Сообщение передается, потому что pxlclk используется для управления мультиплексором в компоненте DVI_MUX, и этот мультиплексор расположен перед триггером. Чтобы достичь сигнала выбора мультиплексора, сигнал pxlclk должен использовать маршрутизацию общего назначения вместо выделенного дерева синхронизации. О том, как Spartan-6 поддерживает выходы DDR.

Я рекомендую использовать компонент ODDR2 также для контактов данных. Входы D0 и D1 просто предоставляют данные, которые должны выводиться с нарастающим фронтом тактовых импульсов C0 и C1 соответственно. Найдите в UG615 от Xilinx таблицу истинности и дополнительную информацию. . Если документация кажется неясной, я рекомендую сначала смоделировать компонент DVI_MUX автономно.

person Martin Zabel    schedule 11.12.2015