Как реализовать сквозную передачу HDMI на ПЛИС XILINX (Artix-7)

#verilog #xilinx #hdmi #pass-through

#verilog #xilinx #hdmi #сквозная передача

Вопрос:

Я хочу реализовать свой собственный сквозной переход HDMI на плате Nexys-Video, оснащенной ПЛИС Artix-7 и портами приемника / источника HDMI. Моя настройка такова: порт HDMI ПК подключен к порту приемника, а светодиодный монитор подключен к порту HDMI источника.

Поскольку на плате нет кодера / декодера TDMS, мне также нужно будет их реализовать (я не хочу просто брать одну из реализаций с закрытым исходным кодом, легко доступных в Интернете). Но сейчас мне просто нужно подключить порты приемника / источника через ПЛИС, чтобы я мог отображать видео на мониторе. Однако я пока не смог добиться успеха. Изображение не отображается, а на мониторе написано «Нет сигнала». Меня немного беспокоит неправильное использование портов FGPA, что может привести к необратимому повреждению платы. Поэтому я не стал пробовать все, что приходило мне в голову. Я ожидаю советов по исправлению / дополнению моего кода.

Я подключил сигналы HDMI, как показано в следующем коде и схеме:

 module HDMI_Top(RSTN, CLK, BTN, SW, LED,
            HDMIR_TXEN, HDMIR_HPA, HDMIT_HPD, 
            HDMIR_SCL, HDMIR_SDA, HDMIT_SCL, HDMIT_SDA,
            HDMIR_CLK_P, HDMIR_CLK_N, HDMIR_DATA_P, HDMIR_DATA_N,
            HDMIT_CLK_P, HDMIT_CLK_N, HDMIT_DATA_P, HDMIT_DATA_N);

input RSTN;
input CLK;
input [4:0] BTN;
input [7:0] SW;
output [7:0] LED;

output HDMIR_TXEN;
output HDMIR_HPA;
input HDMIT_HPD;
inout HDMIR_SCL;
inout HDMIR_SDA;
inout HDMIT_SCL;
inout HDMIT_SDA;

input HDMIR_CLK_P;
input HDMIR_CLK_N;
input [2:0] HDMIR_DATA_P;
input [2:0] HDMIR_DATA_N;
output HDMIT_CLK_P;
output HDMIT_CLK_N;
output [2:0] HDMIT_DATA_P;
output [2:0] HDMIT_DATA_N;

wire [2:0] HDMI_DATA;
wire HDMI_CLK;
wire w0, w1, w2;

assign LED = SW;
//assign HDMIR_HPA = HDMIT_HPD;
assign HDMIR_TXEN = 1'b1;
assign HDMIT_SCL = HDMIR_SCL;
assign HDMIT_SDA = HDMIR_SDA;

// IBUFDS: Differential Input Buffer
IBUFDS #(
    .DIFF_TERM("FALSE"), // Differential Termination
    .IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUFDS_hdmir_clk (
    .O(HDMI_CLK), // Buffer output
    .I(HDMIR_CLK_P), // Diff_p buffer input (connect directly to top-level port)
    .IB(HDMIR_CLK_N) // Diff_n buffer input (connect directly to top-level port)
);

OBUFDS #(
    .IOSTANDARD("DEFAULT") // Specify the output I/O standard
) OBUFDS_hdmit_clk (
    .O(HDMIT_CLK_P), // Diff_p output (connect directly to top-level port)
    .OB(HDMIT_CLK_N), // Diff_n output (connect directly to top-level port)
    .I(HDMI_CLK) // Buffer input
);

// IBUFDS: Differential Input Buffer
IBUFDS #(
    .DIFF_TERM("FALSE"), // Differential Termination
    .IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUFDS_hdmir_data [2:0] (
    .O(HDMI_DATA), // Buffer output
    .I(HDMIR_DATA_P), // Diff_p buffer input (connect directly to top-level port)
    .IB(HDMIR_DATA_N) // Diff_n buffer input (connect directly to top-level port)
);

OBUFDS #(
    .IOSTANDARD("DEFAULT") // Specify the output I/O standard
) OBUFDS_hdmit_data [2:0] (
    .O(HDMIT_DATA_P), // Diff_p output (connect directly to top-level port)
    .OB(HDMIT_DATA_N), // Diff_n output (connect directly to top-level port)
    .I(HDMI_DATA) // Buffer input
);endmodule
  

Вот схема, соответствующая коду.

Спасибо;

Комментарии:

1. Если HPD неверен, компьютер может вообще не выдавать выходные данные, так что, возможно, стоит проверить (iirc должен быть высоким).

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

3. Спасибо за ваши предложения, Дэвид, я попробую их и дам вам знать, что происходит.

4. Дэвид, установка HPD на стороне приемника решает проблему HPD. Но по-прежнему нет изображения. Я погуглил проблему и обнаружил, что сигналы DDC должны обрабатываться правильно. В моем коде я просто закорачиваю их проводами, которые не синтезированы, как я думал.

Ответ №1:

Наконец-то я заработал. Теперь моя видеокарта Nexys пропускает видео Full HD. Вот подробности:

  1. Для обоих выводов HPA и TXEN должно быть установлено значение ‘1’. В моем случае я назначил вывод HPD порта источника на вывод HPA порта приемника. Проверка схемы платы, вывод HPD привязан к MOSFET с открытым стоком, поэтому его необходимо инвертировать перед назначением.

назначить HDMIR_HPA = ~ HDMIT_HPD;

  1. Кроме того, после тщательного поиска в Google я обнаружил, что соединение выводов SCL и SDA DDC порта приемника с исходным портом кажется невозможным, поскольку два двунаправленных вывода не могут быть (просто) подключены к ПЛИС. Таким образом, решение проблемы заключается в добавлении эмулятора EDID ROM на стороне приемника. Затем сама ПЛИС ведет себя как монитор для устройства-источника видео (т. Е. ПК в моей настройке).

Я нашел реализацию EDID ROM на языке VHDL отсюда. Он эмулирует монитор 1024 x 768, однако я изменил его на 1920 x 1080.

Это пересмотренный код для верхнего модуля:

 module HDMI_Top(
input RSTN,
input CLK,
input [4:0] BTN,
input [7:0] SW,
output [7:0] LED,
output HDMIR_TXEN,
output HDMIR_HPA,
input HDMIT_HPD, 
input HDMIR_SCL,
inout HDMIR_SDA,
output HDMIT_SCL,
inout HDMIT_SDA,
input HDMIR_CLK_P,
input HDMIR_CLK_N,
input [2:0] HDMIR_DATA_P,
input [2:0] HDMIR_DATA_N,
output HDMIT_CLK_P,
output HDMIT_CLK_N,
output [2:0] HDMIT_DATA_P,
output [2:0] HDMIT_DATA_N
);

wire HDMI_CLK;
wire [2:0] HDMI_DATA;

assign LED = SW;

// Whenever a sink is ready and wishes to announce its presence, it connects the 5V0 supply pin to the HPD pin. On
// the Nexys Video, this is done by driving the HPA (Hot Plug Assert) signal high. Note: this should only be done
// after a DDC channel slave has been implemented in the FPGA and is ready to transmit display data.
// FPGA lets the HDMI source (e.g., a PC) connected to its sink port know its presence by setting HPA signal to '1'.
// A monitor connected to the source port sets HPD signal to '0'.
// assign HDMIR_HPA = 1'b1;
assign HDMIR_HPA = ~HDMIT_HPD;

// A pull-down resistor on the TXEN signal makes sure the sink buffer's transmitter facing the FPGA is disabled by default.
// An FPGA design using the sink port needs to actively drive this pin high for the buffer to pass data through.
assign HDMIR_TXEN = 1'b1;

// The Display Data Channel, or DDC, is a collection of protocols that enable communication between the display
// (sink) and graphics adapter (source). The DDC2B variant is based on I2C, the bus master being the source and the
// bus slave the sink. When a source detects high level on the HPD pin, it queries the sink over the DDC bus for video
// capabilities. It determines whether the sink is DVI or HDMI-capable and what resolutions are supported. Only
// afterwards will video transmission begin. Refer to VESA E-DDC specifications for more information.
edid_rom edid_rom_rx0 (.clk(CLK), .sclk_raw(HDMIR_SCL), .sdat_raw(HDMIR_SDA));
    
// IBUFDS: Differential Input Buffer
IBUFDS #(
    .DIFF_TERM("FALSE"), // Differential Termination
    .IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUFDS_hdmir_clk (
    .O(HDMI_CLK), // Buffer output
    .I(HDMIR_CLK_P), // Diff_p buffer input (connect directly to top-level port)
    .IB(HDMIR_CLK_N) // Diff_n buffer input (connect directly to top-level port)
);

OBUFDS #(
    .IOSTANDARD("DEFAULT") // Specify the output I/O standard
) OBUFDS_hdmit_clk (
    .O(HDMIT_CLK_P), // Diff_p output (connect directly to top-level port)
    .OB(HDMIT_CLK_N), // Diff_n output (connect directly to top-level port)
    .I(HDMI_CLK) // Buffer input
);

// IBUFDS: Differential Input Buffer
IBUFDS #(
    .DIFF_TERM("FALSE"), // Differential Termination
    .IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUFDS_hdmir_data [2:0] (
    .O(HDMI_DATA), // Buffer output
    .I(HDMIR_DATA_P), // Diff_p buffer input (connect directly to top-level port)
    .IB(HDMIR_DATA_N) // Diff_n buffer input (connect directly to top-level port)
);

OBUFDS #(
    .IOSTANDARD("DEFAULT") // Specify the output I/O standard
) OBUFDS_hdmit_data [2:0] (
    .O(HDMIT_DATA_P), // Diff_p output (connect directly to top-level port)
    .OB(HDMIT_DATA_N), // Diff_n output (connect directly to top-level port)
    .I(HDMI_DATA) // Buffer input
); endmodule
  

Вы можете найти весь исходный код здесь.

Мой следующий шаг — добавить сериализатор / десериализатор и кодировщик / декодер tmds в проект. Для тех, кто, возможно, пожелает сделать то же самое, вот самая последняя версия моего (рабочего) исходного кода, включая сериализатор / десериализатор и кодировщик / декодер tmds.