Ikaduha nga HDMI monitor sa Raspberry Pi3 pinaagi sa DPI interface ug FPGA board


Kini nga video nagpakita: usa ka Raspberry Pi3 board, konektado niini pinaagi sa GPIO connector mao ang usa ka FPGA board Mars Rover2rpi (Cyclone IV), diin ang usa ka HDMI monitor konektado. Ang ikaduha nga monitor konektado pinaagi sa standard HDMI connector sa Raspberry Pi3. Ang tanan nagtinabangay sama sa usa ka dual monitor system.

Sunod isulti ko kanimo kung giunsa kini gipatuman.

Ang sikat nga Raspberry Pi3 board adunay GPIO connector diin mahimo nimong ikonektar ang lainlaing mga expansion card: sensor, LED, stepper motor driver ug daghan pa. Ang eksaktong function sa matag pin sa usa ka connector nagdepende sa port configuration. Ang GPIO ALT2 configuration nagtugot kanimo sa pagbalhin sa connector ngadto sa DPI interface mode, Display Parallel Interface. Adunay mga kard sa pagpalapad alang sa pagkonektar sa mga monitor sa VGA pinaagi sa DPI. Apan, una, ang mga monitor sa VGA dili na komon sama sa HDMI, ug ikaduha, ang digital interface mas maayo kay sa analogue. Dugang pa, ang DAC sa maong VGA expansion boards kasagarang gihimo sa porma sa R-2-R nga mga kadena ug kasagaran dili mosobra sa 6 ka bit kada kolor.

Sa ALT2 mode, ang GPIO connector pin adunay mosunod nga kahulogan:

Ikaduha nga HDMI monitor sa Raspberry Pi3 pinaagi sa DPI interface ug FPGA board

Dinhi akong gikoloran ang RGB pin sa connector nga pula, berde ug asul. Ang ubang importante nga signal mao ang V-SYNC ug H-SYNC signal, ingon man ang CLK. Ang frequency sa orasan sa CLK mao ang frequency kung diin ang mga kantidad sa pixel gi-output sa konektor; nagdepende kini sa gipili nga mode sa video.

Aron makonektar ang usa ka digital HDMI monitor, kinahanglan nimo nga makuha ang mga signal sa DPI sa interface ug i-convert kini sa mga signal sa HDMI. Mahimo kini, pananglitan, gamit ang usa ka matang sa FPGA board. Ingon nga kini nahimo, ang Mars Rover2rpi board angay alang niini nga mga katuyoan. Sa tinuud, ang panguna nga kapilian sa pagkonektar niini nga board pinaagi sa usa ka espesyal nga adapter ingon niini:

Ikaduha nga HDMI monitor sa Raspberry Pi3 pinaagi sa DPI interface ug FPGA board

Kini nga board gigamit aron madugangan ang gidaghanon sa mga GPIO port ug aron makonektar ang daghang mga aparato sa peripheral sa raspberry. Sa samang higayon, ang 4 GPIO signal nga adunay kini nga koneksyon gigamit alang sa JTAG signal, aron ang programa gikan sa Raspberry maka-load sa FPGA firmware ngadto sa FPGA. Tungod niini, kini nga sumbanan nga koneksyon dili angay kanako; Ang 4 nga mga signal sa DPI nahulog. Maayo na lang, ang dugang nga mga comb sa board adunay usa ka Raspberry-compatible nga pinout. Aron ma-rotate nako ang board 90 degrees ug makonektar gihapon kini sa akong raspberry:

Ikaduha nga HDMI monitor sa Raspberry Pi3 pinaagi sa DPI interface ug FPGA board

Siyempre, kinahanglan nimo nga mogamit usa ka eksternal nga JTAG programmer, apan dili kini problema.

Naa pay gamay nga problema. Dili tanang FPGA pin mahimong gamiton isip input sa orasan. Adunay pipila lamang nga gipahinungod nga mga lagdok nga mahimong magamit alang niini nga mga katuyoan. Mao nga nahimo dinhi nga ang signal sa GPIO_0 CLK dili makaabot sa input sa FPGA, nga mahimong magamit ingon usa ka input sa orasan sa FPGA. Busa kinahanglan pa nakong ibutang ang usa ka wire sa scarf. Gikonektar nako ang GPIO_0 ug ang KEY[1] signal sa board:

Ikaduha nga HDMI monitor sa Raspberry Pi3 pinaagi sa DPI interface ug FPGA board

Karon isulti ko kanimo ang gamay bahin sa proyekto sa FPGA. Ang nag-unang kalisud sa pagmugna og mga signal sa HDMI mao ang taas kaayo nga mga frequency. Kung imong tan-awon ang HDMI connector pinout, imong makita nga ang RGB signal karon serial differential signals:

Ikaduha nga HDMI monitor sa Raspberry Pi3 pinaagi sa DPI interface ug FPGA board

Ang paggamit sa usa ka differential signal nagtugot kanimo sa pakigbatok sa komon nga mode interference sa transmission line. Sa kini nga kaso, ang orihinal nga walo ka bit nga kodigo sa matag kolor nga signal gihimong 10-bit nga TMDS (Transition-minimized differential signaling). Kini usa ka espesyal nga pamaagi sa pag-coding aron makuha ang sangkap sa DC gikan sa signal ug maminusan ang pagbalhin sa signal sa usa ka linya sa kalainan. Tungod kay ang 10 ka bits karon kinahanglan nga ipadala sa serial line alang sa usa ka byte nga kolor, kini nahimo nga ang serializer clock speed kinahanglan nga 10 ka pilo nga mas taas kay sa pixel clock speed. Kung atong kuhaon pananglitan ang video mode 1280x720 60Hz, nan ang pixel frequency niini nga mode mao ang 74,25 MHz. Ang serializer kinahanglan nga 742,5 MHz.

Ang mga regular nga FPGA, sa walay palad, dili makahimo niini. Apan, maayo na lang alang kanamo, ang FPGA adunay mga built-in nga DDIO pin. Kini ang mga konklusyon nga, ingon nga kaniadto, 2-to-1 nga mga serializer. Sa ato pa, mahimo silang mag-output sa duha ka bit nga sunud-sunod sa pagtaas ug pagkahulog sa mga kilid sa frequency sa orasan. Kini nagpasabot nga sa usa ka proyekto sa FPGA dili nimo magamit ang 740 MHz, apan ang 370 MHz, apan kinahanglan nimo nga gamiton ang mga elemento sa output sa DDIO sa FPGA. Karon ang 370 MHz usa na ka hingpit nga makab-ot nga frequency. Ikasubo, ang 1280x720 mode mao ang limitasyon. Ang mas taas nga resolusyon dili makab-ot sa atong Cyclone IV FPGA nga na-install sa Mars Rover2rpi board.

Busa, sa disenyo, ang input pixel frequency CLK moadto sa PLL, diin kini gipadaghan sa 5. Niini nga frequency, ang R, G, B bytes gi-convert ngadto sa bit pairs. Mao kini ang gibuhat sa TMDS encoder. Ang source code sa Verilog HDL ingon niini:

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

Dayon ang mga pares sa output gipakaon sa output sa DDIO, nga sunodsunod nga nagpatunghag usa ka gamay nga signal sa pagtaas ug pagkahulog sa mga kilid.

Ang DDIO mismo mahimong mahulagway sa mosunod nga Verilog code:

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

Apan lagmit dili kini molihok sa ingon nga paagi. Kinahanglan nimong gamiton ang Alter's megafunction ALTDDIO_OUT aron aktuwal nga magamit ang mga elemento sa output sa DDIO. Ang akong proyekto naggamit sa ALTDDIO_OUT library component.

Mahimong medyo lisud kining tanan, apan kini molihok.

Mahimo nimong tan-awon ang tanan nga source code nga gisulat sa Verilog HDL dinhi sa github.

Ang gihugpong nga firmware para sa FPGA gi-flash sa EPCS chip nga na-install sa Mars Rover2rpi board. Busa, kung ang gahum magamit sa FPGA board, ang FPGA magsugod gikan sa flash memory ug magsugod.

Karon kinahanglan namon nga hisgutan ang gamay bahin sa pag-configure sa Raspberry mismo.

Naghimo ako mga eksperimento sa Raspberry PI OS (32 bit) base sa Debian Buster, Bersyon: Agosto 2020,
Petsa sa pagpagawas:2020-08-20, Kernel nga bersyon:5.4.

Kinahanglan nimong buhaton ang duha ka butang:

  • usba ang config.txt file;
  • paghimo og X server configuration aron magtrabaho uban ang duha ka monitor.

Sa pag-edit sa /boot/config.txt file kinahanglan nimo:

  1. disable ang paggamit sa i2c, i2s, spi;
  2. i-enable ang DPI mode gamit ang overlay dtoverlay=dpi24;
  3. i-configure ang video mode 1280 Γ— 720 60Hz, 24 bits kada pixel sa DPI;
  4. ipiho ang gikinahanglan nga gidaghanon sa mga framebuffers 2 (max_framebuffers=2, unya ang ikaduhang device /dev/fb1 makita)

Ang bug-os nga teksto sa config.txt file ingon niini.

# 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

Pagkahuman niini, kinahanglan ka maghimo usa ka file sa pag-configure alang sa X server aron magamit ang duha nga mga monitor sa duha nga mga framebuffers / dev / fb0 ug / dev / fb1:

Ang akong configuration file /usr/share/x11/xorg.conf.d/60-dualscreen.conf sama niini

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

Aw, kung wala pa kini ma-install, kinahanglan nimo nga i-install ang Xinerama. Dayon ang luna sa desktop bug-os nga mapalapad ngadto sa duha ka monitor, sama sa gipakita sa demo nga video sa ibabaw.

Mao ra siguro. Karon, ang mga tag-iya sa Raspberry Pi3 makagamit na sa duha ka monitor.

Ang paghulagway ug circuit diagram sa Mars Rover2rpi board makit-an tan-awa dinhi.

Source: www.habr.com