Monitor HDMI kadua ka Raspberry Pi3 via panganteur DPI sareng dewan FPGA


Video ieu nunjukkeun: papan Raspberry Pi3, anu, ngalangkungan konektor GPIO, papan FPGA Mars Rover2rpi (Cyclone IV) disambungkeun, dimana monitor HDMI disambungkeun. Monitor kadua disambungkeun via konektor standar Raspberry Pi3 HDMI. Sadayana tiasa dianggo sapertos sistem monitor ganda.

Salajengna kuring bakal ngabejaan ka maneh kumaha eta dilaksanakeun.

Papan Raspberry Pi3 anu populér ngagaduhan konektor GPIO dimana anjeun tiasa nyambungkeun sababaraha papan ékspansi: sensor, LED, supir motor stepper sareng seueur deui. Fungsi husus unggal pin on konektor gumantung kana konfigurasi port. Konfigurasi GPIO ALT2 ngidinan Anjeun pikeun pindah konektor ka modeu panganteur DPI, Tampilan Parallel Interface. Aya papan ékspansi pikeun nyambungkeun monitor VGA via DPI. Nanging, kahiji, monitor VGA henteu biasa sapertos HDMI, sareng kadua, antarmuka digital langkung saé tibatan analog. Sumawona, DAC dina kartu ékspansi VGA sapertos biasana dilakukeun dina bentuk ranté R-2-R sareng sering henteu langkung ti 6 bit per warna.

Dina modeu ALT2, pin konektor GPIO boga harti handap:

Monitor HDMI kadua ka Raspberry Pi3 via panganteur DPI sareng dewan FPGA

Di dieu kuring ngawarnaan pin RGB tina konektor beureum, héjo sareng biru masing-masing. Sinyal penting séjén nyaéta sinyal sinkronisasi V-SYNC sareng H-SYNC, ogé CLK. Frékuénsi jam CLK nyaéta frékuénsi dimana nilai piksel kaluaran kana konektor sareng gumantung kana modeu pidéo anu dipilih.

Pikeun nyambungkeun monitor HDMI digital, anjeun kedah nyandak sinyal antarmuka DPI sareng ngarobih kana sinyal HDMI. Ieu tiasa dilakukeun, contona, nganggo papan FPGA. Salaku tétéla, dewan Mars Rover2rpi cocog pikeun tujuan ieu. Sabenerna, pilihan utama pikeun nyambungkeun papan ieu ngaliwatan adaptor husus Sigana mah kieu:

Monitor HDMI kadua ka Raspberry Pi3 via panganteur DPI sareng dewan FPGA

dewan ieu dipaké pikeun nambahan jumlah GPIO palabuhan sarta pikeun nyambungkeun langkung périferal kana buah prambus. Dina waktos anu sami, 4 sinyal GPIO sareng sambungan ieu dianggo pikeun sinyal JTAG, supados program tina distribusi tiasa ngamuat firmware FPGA kana FPGA. Kusabab ieu, sambungan biasa sapertos teu cocog kuring, 4 sinyal DPI leupaskeun kaluar. Kabeneran, sisir tambahan dina papan gaduh pinout anu cocog sareng Raspberry. Janten kuring tiasa muterkeun dewan 90 derajat sareng tetep nyambung ka buah prambus kuring:

Monitor HDMI kadua ka Raspberry Pi3 via panganteur DPI sareng dewan FPGA

Tangtu, anjeun kudu make JTAG programmer éksternal, tapi ieu teu jadi masalah.

Aya kénéh masalah leutik. Henteu unggal pin FPGA tiasa dianggo salaku input jam. Aya ngan sababaraha pin dedicated nu bisa dipaké pikeun tujuan ieu. Janten di dieu tétéla yén sinyal GPIO_0 CLK henteu dugi ka input FPGA, anu tiasa dianggo salaku input jam FPGA. Janten sadayana sami, kuring kedah ngalungkeun hiji tulisan dina syal. Kuring nyambungkeun sinyal GPIO_0 sareng KEY [1] dewan:

Monitor HDMI kadua ka Raspberry Pi3 via panganteur DPI sareng dewan FPGA

Ayeuna kuring gé ngabejaan Anjeun saeutik ngeunaan proyék di FPGA. Kasusah utama dina formasi sinyal HDMI nyaéta frékuénsi luhur pisan. Ningali pinout konektor HDMI, anjeun tiasa ningali yén sinyal RGB ayeuna mangrupikeun sinyal diferensial séri:

Monitor HDMI kadua ka Raspberry Pi3 via panganteur DPI sareng dewan FPGA

Pamakéan sinyal diferensial ngidinan Anjeun pikeun nungkulan noise mode umum dina jalur transmisi. Dina hal ieu, kode aslina dalapan bit unggal sinyal warna dirobah jadi 10-bit TMDS (Transition-minimized differential signalling). Ieu métode encoding husus pikeun miceun komponén DC tina sinyal jeung ngaleutikan switching sinyal dina garis diferensial. Kusabab ayeuna aya 10 bit pikeun ngirimkeun per bait warna dina garis serial, tétéla yén frékuénsi jam serializer kudu 10 kali leuwih luhur ti frékuénsi jam tina piksel. Upami urang nyandak contona mode video 1280x720 60Hz, maka frékuénsi piksel tina mode ieu nyaéta 74,25MHz. Serializer kedah 742,5 MHz.

FPGAs konvensional umumna teu sanggup ieu, hanjakalna. Nanging, pikeun kabeneran urang, FPGA gaduh pin DDIO anu diwangun. Ieu mangrupikeun kasimpulan anu parantos, sapertos, 2-to-1 serializers. Hartina, aranjeunna tiasa kaluaran dua bit dina urutan sapanjang frékuénsi jam naék sareng turun. Ieu ngandung harti yén dina proyék FPGA anjeun bisa make teu 740MHz, tapi 370MHz, tapi anjeun kudu make elemen kaluaran DDIO dina FPGA. Di dieu 370 MHz geus cukup frékuénsi achievable. Hanjakalna, modeu 1280 × 720 mangrupikeun watesna. Résolusi anu langkung luhur henteu tiasa dihontal dina FPGA Cyclone IV anu dipasang dina papan Rover2rpi.

Ku kituna, dina proyék éta, frékuénsi piksel input CLK geus fed ka PLL, dimana eta dikali 5. Dina frékuénsi ieu, R, G, B bait dirobah jadi pasangan bit. Ieu anu dilakukeun ku encoder TMDS. Kodeu sumber dina Verilog HDL sapertos kieu:

module hdmi(
	input wire pixclk,		// 74MHz
	input wire clk_TMDS2,	// 370MHz
	input wire hsync,
	input wire vsync,
	input wire active,
	input wire [7:0]red,
	input wire [7:0]green,
	input wire [7:0]blue,
	output wire TMDS_bh,
	output wire TMDS_bl,
	output wire TMDS_gh,
	output wire TMDS_gl,
	output wire TMDS_rh,
	output wire TMDS_rl
);

wire [9:0] TMDS_red, TMDS_green, TMDS_blue;
TMDS_encoder encode_R(.clk(pixclk), .VD(red  ), .CD({vsync,hsync}), .VDE(active), .TMDS(TMDS_red));
TMDS_encoder encode_G(.clk(pixclk), .VD(green), .CD({vsync,hsync}), .VDE(active), .TMDS(TMDS_green));
TMDS_encoder encode_B(.clk(pixclk), .VD(blue ), .CD({vsync,hsync}), .VDE(active), .TMDS(TMDS_blue));

reg [2:0] TMDS_mod5=0;  // modulus 5 counter
reg [4:0] TMDS_shift_bh=0, TMDS_shift_bl=0;
reg [4:0] TMDS_shift_gh=0, TMDS_shift_gl=0;
reg [4:0] TMDS_shift_rh=0, TMDS_shift_rl=0;

wire [4:0] TMDS_blue_l  = {TMDS_blue[9],TMDS_blue[7],TMDS_blue[5],TMDS_blue[3],TMDS_blue[1]};
wire [4:0] TMDS_blue_h  = {TMDS_blue[8],TMDS_blue[6],TMDS_blue[4],TMDS_blue[2],TMDS_blue[0]};
wire [4:0] TMDS_green_l = {TMDS_green[9],TMDS_green[7],TMDS_green[5],TMDS_green[3],TMDS_green[1]};
wire [4:0] TMDS_green_h = {TMDS_green[8],TMDS_green[6],TMDS_green[4],TMDS_green[2],TMDS_green[0]};
wire [4:0] TMDS_red_l   = {TMDS_red[9],TMDS_red[7],TMDS_red[5],TMDS_red[3],TMDS_red[1]};
wire [4:0] TMDS_red_h   = {TMDS_red[8],TMDS_red[6],TMDS_red[4],TMDS_red[2],TMDS_red[0]};

always @(posedge clk_TMDS2)
begin
	TMDS_shift_bh <= TMDS_mod5[2] ? TMDS_blue_h  : TMDS_shift_bh  [4:1];
	TMDS_shift_bl <= TMDS_mod5[2] ? TMDS_blue_l  : TMDS_shift_bl  [4:1];
	TMDS_shift_gh <= TMDS_mod5[2] ? TMDS_green_h : TMDS_shift_gh  [4:1];
	TMDS_shift_gl <= TMDS_mod5[2] ? TMDS_green_l : TMDS_shift_gl  [4:1];
	TMDS_shift_rh <= TMDS_mod5[2] ? TMDS_red_h   : TMDS_shift_rh  [4:1];
	TMDS_shift_rl <= TMDS_mod5[2] ? TMDS_red_l   : TMDS_shift_rl  [4:1];
	TMDS_mod5 <= (TMDS_mod5[2]) ? 3'd0 : TMDS_mod5+3'd1;
end

assign TMDS_bh = TMDS_shift_bh[0];
assign TMDS_bl = TMDS_shift_bl[0];
assign TMDS_gh = TMDS_shift_gh[0];
assign TMDS_gl = TMDS_shift_gl[0];
assign TMDS_rh = TMDS_shift_rh[0];
assign TMDS_rl = TMDS_shift_rl[0];

endmodule

module TMDS_encoder(
	input clk,
	input [7:0] VD,	// video data (red, green or blue)
	input [1:0] CD,	// control data
	input VDE,  	// video data enable, to choose between CD (when VDE=0) and VD (when VDE=1)
	output reg [9:0] TMDS = 0
);

wire [3:0] Nb1s = VD[0] + VD[1] + VD[2] + VD[3] + VD[4] + VD[5] + VD[6] + VD[7];
wire XNOR = (Nb1s>4'd4) || (Nb1s==4'd4 && VD[0]==1'b0);
wire [8:0] q_m = {~XNOR, q_m[6:0] ^ VD[7:1] ^ {7{XNOR}}, VD[0]};

reg [3:0] balance_acc = 0;
wire [3:0] balance = q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7] - 4'd4;
wire balance_sign_eq = (balance[3] == balance_acc[3]);
wire invert_q_m = (balance==0 || balance_acc==0) ? ~q_m[8] : balance_sign_eq;
wire [3:0] balance_acc_inc = balance - ({q_m[8] ^ ~balance_sign_eq} & ~(balance==0 || balance_acc==0));
wire [3:0] balance_acc_new = invert_q_m ? balance_acc-balance_acc_inc : balance_acc+balance_acc_inc;
wire [9:0] TMDS_data = {invert_q_m, q_m[8], q_m[7:0] ^ {8{invert_q_m}}};
wire [9:0] TMDS_code = CD[1] ? (CD[0] ? 10'b1010101011 : 10'b0101010100) : (CD[0] ? 10'b0010101011 : 10'b1101010100);

always @(posedge clk) TMDS <= VDE ? TMDS_data : TMDS_code;
always @(posedge clk) balance_acc <= VDE ? balance_acc_new : 4'h0;

endmodule

Lajeng pasangan kaluaran anu fed kana kaluaran DDIO, nu sequentially ngahasilkeun sinyal hiji-bit dina naek na ragrag.

DDIO sorangan tiasa dijelaskeun nganggo kode Verilog sapertos kieu:

module ddio(
	input wire d0,
	input wire d1,
	input wire clk,
	output wire out
	);

reg r_d0;
reg r_d1;
always @(posedge clk)
begin
	r_d0 <= d0;
	r_d1 <= d1;
end
assign out = clk ? r_d0 : r_d1;
endmodule

Tapi sigana moal jalan kitu. Anjeun kedah nganggo megafungsi ALTDDIO_OUT Altera pikeun leres-leres ngagunakeun elemen kaluaran DDIO. Dina proyék abdi, komponén perpustakaan ALTDDIO_OUT dipaké.

Éta sadayana tiasa katingali sakedik, tapi tiasa dianggo.

Anjeun tiasa ningali sadaya kode sumber anu ditulis dina Verilog HDL di dieu di github.

Firmware anu disusun pikeun FPGA dipasang kana chip EPCS anu dipasang dina papan Mars Rover2rpi. Ku kituna, nalika kakuatan diterapkeun kana dewan FPGA, FPGA bakal initialize tina memori flash tur mimitian.

Ayeuna urang kudu ngobrol saeutik ngeunaan konfigurasi tina buah prambus sorangan.

Kuring ngalakukeun percobaan dina Raspberry PI OS (32 bit) dumasar kana Debian Buster, Vérsi: Agustus 2020,
Tanggal sékrési:2020-08-20, Vérsi kernel:5.4.

Anjeun kedah ngalakukeun dua hal:

  • ngédit file config.txt;
  • nyieun konfigurasi server X pikeun gawé kalawan dua monitor.

Nalika ngédit file /boot/config.txt, anjeun kedah:

  1. nganonaktipkeun pamakéan i2c, i2s, spi;
  2. aktipkeun mode DPI sareng overlay dtoverlay=dpi24;
  3. set mode video 1280 × 720 60Hz, 24 bit per titik per DPI;
  4. nangtukeun jumlah diperlukeun framebuffers 2 (max_framebuffers = 2, ngan lajeng bakal alat kadua / dev / fb1 némbongan)

Téks lengkep file config.txt Sigana mah ieu.

# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on

dtparam=i2c_arm=off
dtparam=spi=off
dtparam=i2s=off

dtoverlay=dpi24
overscan_left=0
overscan_right=0
overscan_top=0
overscan_bottom=0
framebuffer_width=1280
framebuffer_height=720
display_default_lcd=0
enable_dpi_lcd=1
dpi_group=2
dpi_mode=87
#dpi_group=1
#dpi_mode=4
dpi_output_format=0x6f027
dpi_timings=1280 1 110 40 220 720 1 5 5 20 0 0 0 60 0 74000000 3

# Uncomment this to enable infrared communication.
#dtoverlay=gpio-ir,gpio_pin=17
#dtoverlay=gpio-ir-tx,gpio_pin=18

# Additional overlays and parameters are documented /boot/overlays/README

# Enable audio (loads snd_bcm2835)
dtparam=audio=on

[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
#dtoverlay=vc4-fkms-v3d
max_framebuffers=2

[all]
#dtoverlay=vc4-fkms-v3d
max_framebuffers=2

Saatos éta, anjeun kedah nyiptakeun file konfigurasi pikeun server X nganggo dua monitor dina dua framebuffer / dev / fb0 sareng / dev / fb1:

File config kuring nyaéta /usr/share/x11/xorg.conf.d/60-dualscreen.conf sapertos kieu

Section "Device"
        Identifier      "LCD"
        Driver          "fbturbo"
        Option          "fbdev" "/dev/fb0"
        Option          "ShadowFB" "off"
        Option          "SwapbuffersWait" "true"
EndSection

Section "Device"
        Identifier      "HDMI"
        Driver          "fbturbo"
        Option          "fbdev" "/dev/fb1"
        Option          "ShadowFB" "off"
        Option          "SwapbuffersWait" "true"
EndSection

Section "Monitor"
        Identifier      "LCD-monitor"
        Option          "Primary" "true"
EndSection

Section "Monitor"
        Identifier      "HDMI-monitor"
        Option          "RightOf" "LCD-monitor"
EndSection

Section "Screen"
        Identifier      "screen0"
        Device          "LCD"
        Monitor         "LCD-monitor"
EndSection

Section "Screen"
        Identifier      "screen1"
        Device          "HDMI" 
	Monitor         "HDMI-monitor"
EndSection

Section "ServerLayout"
        Identifier      "default"
        Option          "Xinerama" "on"
        Option          "Clone" "off"
        Screen 0        "screen0"
        Screen 1        "screen1" RightOf "screen0"
EndSection

Nya, upami henteu acan dipasang, maka anjeun kedah pasang Xinerama. Teras rohangan desktop bakal dipanjangkeun ka dua monitor, sapertos anu dipidangkeun dina pidéo demo di luhur.

Éta meureun sadayana. Ayeuna, pamilik Raspberry Pi3 bakal tiasa nganggo dua monitor.

Katerangan jeung diagram dewan Mars Rover2rpi tiasa tingali di dieu.

sumber: www.habr.com