Ail fonitor HDMI i Raspberry Pi3 trwy ryngwyneb DPI a bwrdd FPGA


Mae'r fideo hwn yn dangos: mae bwrdd Raspberry Pi3, sydd wedi'i gysylltu ag ef trwy'r cysylltydd GPIO, yn fwrdd FPGA Mars Rover2rpi (Seiclon IV), y mae monitor HDMI wedi'i gysylltu ag ef. Mae'r ail fonitor wedi'i gysylltu trwy gysylltydd HDMI safonol y Raspberry Pi3. Mae popeth yn gweithio gyda'i gilydd fel system fonitro ddeuol.

Nesaf dywedaf wrthych sut y caiff hyn ei roi ar waith.

Mae gan y bwrdd poblogaidd Raspberry Pi3 gysylltydd GPIO lle gallwch chi gysylltu gwahanol gardiau ehangu: synwyryddion, LEDs, gyrwyr modur stepiwr a llawer mwy. Mae union swyddogaeth pob pin ar gysylltydd yn dibynnu ar gyfluniad y porthladd. Mae cyfluniad GPIO ALT2 yn caniatΓ‘u ichi newid y cysylltydd i fodd rhyngwyneb DPI, Rhyngwyneb Cyfochrog Arddangos. Mae yna gardiau ehangu ar gyfer cysylltu monitorau VGA trwy DPI. Fodd bynnag, yn gyntaf, nid yw monitorau VGA bellach mor gyffredin Γ’ HDMI, ac yn ail, mae'r rhyngwyneb digidol yn gynyddol well na'r un analog. Ar ben hynny, mae'r DAC ar fyrddau ehangu VGA o'r fath fel arfer yn cael ei wneud ar ffurf cadwyni R-2-R ac yn aml dim mwy na 6 did y lliw.

Yn y modd ALT2, mae gan y pinnau cysylltydd GPIO yr ystyr canlynol:

Ail fonitor HDMI i Raspberry Pi3 trwy ryngwyneb DPI a bwrdd FPGA

Yma rwyf wedi lliwio pinnau RGB y cysylltydd yn goch, gwyrdd a glas yn y drefn honno. Arwyddion pwysig eraill yw'r signalau V-SYNC a H-SYNC, yn ogystal Γ’ CLK. Amledd cloc CLK yw'r amlder y mae gwerthoedd picsel yn cael eu hallbynnu i'r cysylltydd; mae'n dibynnu ar y modd fideo a ddewiswyd.

I gysylltu monitor HDMI digidol, mae angen i chi ddal signalau DPI y rhyngwyneb a'u trosi i signalau HDMI. Gellir gwneud hyn, er enghraifft, gan ddefnyddio rhyw fath o fwrdd FPGA. Fel mae'n digwydd, mae bwrdd Mars Rover2rpi yn addas at y dibenion hyn. Mewn gwirionedd, mae'r prif opsiwn ar gyfer cysylltu'r bwrdd hwn trwy addasydd arbennig yn edrych fel hyn:

Ail fonitor HDMI i Raspberry Pi3 trwy ryngwyneb DPI a bwrdd FPGA

Defnyddir y bwrdd hwn i gynyddu nifer y porthladdoedd GPIO ac i gysylltu mwy o ddyfeisiau ymylol i'r mafon. Ar yr un pryd, defnyddir 4 signal GPIO gyda'r cysylltiad hwn ar gyfer signalau JTAG, fel y gall y rhaglen o Raspberry lwytho'r firmware FPGA i'r FPGA. Oherwydd hyn, nid yw'r cysylltiad safonol hwn yn addas i mi; mae 4 signal DPI yn gollwng. Yn ffodus, mae gan y crwybrau ychwanegol ar y bwrdd bin allan sy'n gydnaws Γ’ Mafon. Felly gallaf gylchdroi'r bwrdd 90 gradd a dal i'w gysylltu Γ’'m mafon:

Ail fonitor HDMI i Raspberry Pi3 trwy ryngwyneb DPI a bwrdd FPGA

Wrth gwrs, bydd yn rhaid i chi ddefnyddio rhaglennydd JTAG allanol, ond nid yw hyn yn broblem.

Mae problem fach o hyd. Ni ellir defnyddio pob pin FPGA fel mewnbwn cloc. Dim ond ychydig o binnau pwrpasol y gellir eu defnyddio at y dibenion hyn. Felly daeth allan yma nad yw'r signal GPIO_0 CLK yn cyrraedd mewnbwn FPGA, y gellir ei ddefnyddio fel mewnbwn cloc FPGA. Felly roedd yn rhaid i mi roi un wifren ar y sgarff o hyd. Rwy'n cysylltu GPIO_0 a signal ALLWEDDOL[1] y bwrdd:

Ail fonitor HDMI i Raspberry Pi3 trwy ryngwyneb DPI a bwrdd FPGA

Nawr dywedaf ychydig wrthych am brosiect FPGA. Y prif anhawster wrth gynhyrchu signalau HDMI yw amleddau uchel iawn. Os edrychwch ar y pinout cysylltydd HDMI, gallwch weld bod y signalau RGB bellach yn signalau gwahaniaethol cyfresol:

Ail fonitor HDMI i Raspberry Pi3 trwy ryngwyneb DPI a bwrdd FPGA

Mae defnyddio signal gwahaniaethol yn caniatΓ‘u ichi frwydro yn erbyn ymyrraeth modd cyffredin ar y llinell drosglwyddo. Yn yr achos hwn, mae cod wyth-did gwreiddiol pob signal lliw yn cael ei drawsnewid yn TMDS 10-did (Sylweddu gwahaniaethol wedi'i gyfyngu i'r pontio). Mae hwn yn ddull codio arbennig i dynnu'r gydran DC o'r signal a lleihau newid signal mewn llinell wahaniaethol. Gan fod angen trosglwyddo 10 did dros y llinell gyfresol ar gyfer un beit o liw, mae'n ymddangos bod yn rhaid i gyflymder cloc y cyfresydd fod 10 gwaith yn uwch na chyflymder y cloc picsel. Os cymerwn er enghraifft y modd fideo 1280x720 60Hz, yna amledd picsel y modd hwn yw 74,25 MHz. Dylai'r cyfresydd fod yn 742,5 MHz.

Yn anffodus, nid yw FPGAs rheolaidd yn gallu gwneud hyn. Fodd bynnag, yn ffodus i ni, mae gan yr FPGA binnau DIO wedi'u hymgorffori. Mae'r rhain yn gasgliadau sydd eisoes, fel petai, yn gyfreswyr 2-i-1. Hynny yw, gallant allbynnu dau ddid yn olynol ar ymylon codi a disgyn amledd y cloc. Mae hyn yn golygu, mewn prosiect FPGA, y gallwch chi ddefnyddio nid 740 MHz, ond 370 MHz, ond mae angen i chi ddefnyddio elfennau allbwn DIO yn y FPGA. Nawr mae 370 MHz eisoes yn amlder cwbl gyraeddadwy. Yn anffodus, modd 1280x720 yw'r terfyn. Ni ellir cyflawni datrysiad uwch yn ein FPGA Seiclon IV sydd wedi'i osod ar fwrdd Mars Rover2rpi.

Felly, yn y dyluniad, mae'r amledd picsel mewnbwn CLK yn mynd i'r PLL, lle caiff ei luosi Γ’ 5. Ar yr amlder hwn, mae'r bytes R, G, B yn cael eu trosi'n barau didau. Dyma beth mae'r amgodiwr TMDS yn ei wneud. Mae'r cod ffynhonnell yn Verilog HDL yn edrych fel hyn:

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

Yna mae'r parau allbwn yn cael eu bwydo i'r allbwn DDIO, sy'n cynhyrchu signal un-did yn olynol ar yr ymylon codi a disgyn.

Gellid disgrifio DDIO ei hun gyda'r cod Verilog canlynol:

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

Ond mae'n debyg na fydd yn gweithio felly. Mae angen i chi ddefnyddio megafunction Alter ALTDDIO_OUT i alluogi'r elfennau allbwn DIO. Mae fy mhrosiect yn defnyddio'r gydran llyfrgell ALTDDIO_OUT.

Gall hyn i gyd edrych ychydig yn anodd, ond mae'n gweithio.

Gallwch weld yr holl god ffynhonnell a ysgrifennwyd yn Verilog HDL yma ar github.

Mae'r firmware a luniwyd ar gyfer y FPGA yn cael ei fflachio i'r sglodyn EPCS sydd wedi'i osod ar fwrdd Mars Rover2rpi. Felly, pan fydd pΕ΅er yn cael ei gymhwyso i fwrdd FPGA, bydd y FPGA yn cael ei gychwyn o'r cof fflach a'i gychwyn.

Nawr mae angen i ni siarad ychydig am gyfluniad y Mafon ei hun.

Rwy'n gwneud arbrofion ar Raspberry PI OS (32 bit) yn seiliedig ar Debian Buster, Fersiwn: Awst 2020,
Dyddiad rhyddhau: 2020-08-20, fersiwn Kernel: 5.4.

Mae angen i chi wneud dau beth:

  • golygu'r ffeil config.txt;
  • creu cyfluniad gweinydd X i weithio gyda dau fonitor.

Wrth olygu'r ffeil /boot/config.txt mae angen:

  1. analluogi defnyddio i2c, i2s, spi;
  2. galluogi modd DPI gan ddefnyddio troshaen dtoverlay=dpi24;
  3. ffurfweddu modd fideo 1280 Γ— 720 60Hz, 24 did y picsel ar DPI;
  4. nodwch y nifer gofynnol o fyfferau ffrΓ’m 2 (max_framebuffers = 2, dim ond wedyn y bydd yr ail ddyfais /dev/fb1 yn ymddangos)

Mae testun llawn y ffeil config.txt yn edrych fel hyn.

# 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

Ar Γ΄l hyn, mae angen i chi greu ffeil ffurfweddu i'r gweinydd X ddefnyddio dau fonitor ar ddau fwffer ffrΓ’m /dev/fb0 a /dev/fb1:

Mae fy ffeil ffurfweddu /usr/share/x11/xorg.conf.d/60-dualscreen.conf fel hyn

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

Wel, os nad yw wedi'i osod eisoes, yna mae angen i chi osod Xinerama. Yna bydd y gofod bwrdd gwaith yn cael ei ehangu'n llawn i ddau fonitor, fel y dangosir yn y fideo demo uchod.

Mae'n debyg mai dyna i gyd. Nawr, bydd perchnogion Raspberry Pi3 yn gallu defnyddio dau fonitor.

Gellir dod o hyd i ddisgrifiad a diagram cylched o fwrdd Mars Rover2rpi Edrychwch yma.

Ffynhonnell: hab.com