ሁለተኛ የኤችዲኤምአይ መቆጣጠሪያ ወደ Raspberry Pi3 በዲፒአይ በይነገጽ እና በFPGA ሰሌዳ


ይህ ቪዲዮ የሚያሳየው፡ Raspberry Pi3 ሰሌዳ፣ ከሱ ጋር የተገናኘው በ GPIO አያያዥ የFPGA ቦርድ ማርስ ሮቨር2ርፒ (ሳይክሎን IV) ሲሆን የኤችዲኤምአይ ማሳያ የተገናኘ ነው። ሁለተኛው ማሳያ በ Raspberry Pi3 መደበኛ HDMI አያያዥ በኩል ተያይዟል። ሁሉም ነገር እንደ ባለሁለት ማሳያ ስርዓት አንድ ላይ ይሰራል።

በመቀጠል ይህ እንዴት እንደሚተገበር እነግርዎታለሁ.

ታዋቂው Raspberry Pi3 ቦርድ የተለያዩ የማስፋፊያ ካርዶችን ማለትም ሴንሰሮች፣ ኤልኢዲዎች፣ ስቴፐር ሞተር ሾፌሮችን እና ሌሎችንም የሚያገናኙበት የ GPIO ማገናኛ አለው። በእያንዳንዱ ማገናኛ ላይ ያለው የእያንዳንዱ ፒን ትክክለኛ ተግባር በወደቡ ውቅረት ላይ የተመሰረተ ነው. የ GPIO ALT2 ውቅረት ማገናኛውን ወደ ዲፒአይ በይነገጽ ሁነታ, ትይዩ በይነገጽን ለማሳየት ይፈቅድልዎታል. ቪጂኤ ማሳያዎችን በዲፒአይ ለማገናኘት የማስፋፊያ ካርዶች አሉ። ነገር ግን፣ በመጀመሪያ፣ የቪጂኤ ማሳያዎች እንደ ኤችዲኤምአይ የተለመደ አይደሉም፣ ሁለተኛ፣ የዲጂታል በይነገጽ ከአናሎግ የበለጠ እየተሻሻለ ነው። ከዚህም በላይ እንዲህ ባለው የቪጂኤ ማስፋፊያ ቦርዶች ላይ ያለው DAC ብዙውን ጊዜ በ R-2-R ሰንሰለቶች መልክ የተሠራ ሲሆን ብዙውን ጊዜ በአንድ ቀለም ከ 6 ቢት አይበልጥም.

በ ALT2 ሁነታ የ GPIO ማገናኛ ፒኖች የሚከተለው ትርጉም አላቸው፡

ሁለተኛ የኤችዲኤምአይ መቆጣጠሪያ ወደ Raspberry Pi3 በዲፒአይ በይነገጽ እና በFPGA ሰሌዳ

እዚህ የአገናኙን አርጂቢ ፒን ቀይ፣ አረንጓዴ እና ሰማያዊ በቅደም ተከተል ቀልቻለሁ። ሌሎች አስፈላጊ ምልክቶች የ V-SYNC እና H-SYNC ምልክቶች እንዲሁም CLK ናቸው። የ CLK የሰዓት ድግግሞሽ የፒክሰል ዋጋዎች ወደ ማገናኛ የሚወጡበት ድግግሞሽ ነው ፣ እሱ በተመረጠው ቪዲዮ ሁኔታ ላይ የተመሠረተ ነው።

ዲጂታል ኤችዲኤምአይ ማሳያን ለማገናኘት የበይነገጽን የዲፒአይ ምልክቶችን ማንሳት እና ወደ ኤችዲኤምአይ ሲግናሎች መለወጥ ያስፈልግዎታል። ይህ ለምሳሌ አንዳንድ የ FPGA ሰሌዳን በመጠቀም ሊከናወን ይችላል. እንደ ተለወጠ, የማርስ ሮቨር 2rpi ቦርድ ለእነዚህ አላማዎች ተስማሚ ነው. በእውነቱ ፣ ይህንን ሰሌዳ በልዩ አስማሚ ለማገናኘት ዋናው አማራጭ ይህንን ይመስላል።

ሁለተኛ የኤችዲኤምአይ መቆጣጠሪያ ወደ Raspberry Pi3 በዲፒአይ በይነገጽ እና በFPGA ሰሌዳ

ይህ ሰሌዳ የጂፒአይኦ ወደቦችን ቁጥር ለመጨመር እና ተጨማሪ ተጓዳኝ መሳሪያዎችን ከራስበሪ ጋር ለማገናኘት ይጠቅማል። በተመሳሳይ ጊዜ, ከዚህ ግንኙነት ጋር 4 GPIO ምልክቶች ለ JTAG ምልክቶች ጥቅም ላይ ይውላሉ, ስለዚህ ከ Raspberry ያለው ፕሮግራም የ FPGA firmware ወደ FPGA መጫን ይችላል. በዚህ ምክንያት ይህ መደበኛ ግንኙነት አይመቸኝም፤ 4 ዲ ፒ አይ ሲግናሎች ይቋረጣሉ። እንደ እድል ሆኖ, በቦርዱ ላይ ያሉት ተጨማሪ ማበጠሪያዎች Raspberry-ተኳሃኝ ፒኖት አላቸው. ስለዚህ ሰሌዳውን በ 90 ዲግሪ ማሽከርከር እና አሁንም ከራስቤሪዬ ጋር ማገናኘት እችላለሁ:

ሁለተኛ የኤችዲኤምአይ መቆጣጠሪያ ወደ Raspberry Pi3 በዲፒአይ በይነገጽ እና በFPGA ሰሌዳ

እርግጥ ነው፣ ውጫዊ JTAG ፕሮግራመር መጠቀም አለብህ፣ ግን ይህ ችግር አይደለም።

አሁንም ትንሽ ችግር አለ. እያንዳንዱ የ FPGA ፒን እንደ ሰዓት ግቤት መጠቀም አይቻልም። ለእነዚህ ዓላማዎች ጥቅም ላይ ሊውሉ የሚችሉ ጥቂት የወሰኑ ፒኖች ብቻ አሉ። ስለዚህ እዚህ ላይ የ GPIO_0 CLK ሲግናል ወደ FPGA ግቤት አልደረሰም ፣ ይህም እንደ FPGA ሰዓት ግብዓት ሊያገለግል ይችላል። ስለዚህ አሁንም አንድ ሽቦ በሸርተቴ ላይ ማድረግ ነበረብኝ. GPIO_0ን እና የቦርዱን ቁልፍ[1] ምልክት አገናኛለሁ፡-

ሁለተኛ የኤችዲኤምአይ መቆጣጠሪያ ወደ Raspberry Pi3 በዲፒአይ በይነገጽ እና በFPGA ሰሌዳ

አሁን ስለ FPGA ፕሮጀክት ትንሽ እነግርዎታለሁ። የኤችዲኤምአይ ምልክቶችን ለመፍጠር ዋናው ችግር በጣም ከፍተኛ ድግግሞሽ ነው። የኤችዲኤምአይ አያያዥ ፒኖውትን ከተመለከቱ፣ የ RGB ምልክቶች አሁን ተከታታይ ልዩነት ምልክቶች መሆናቸውን ማየት ይችላሉ።

ሁለተኛ የኤችዲኤምአይ መቆጣጠሪያ ወደ Raspberry Pi3 በዲፒአይ በይነገጽ እና በFPGA ሰሌዳ

የልዩነት ምልክት መጠቀም በማስተላለፊያ መስመር ላይ የጋራ ሁነታ ጣልቃገብነትን ለመቋቋም ያስችልዎታል. በዚህ አጋጣሚ የእያንዳንዱ የቀለም ምልክት የመጀመሪያ ስምንት-ቢት ኮድ ወደ 10-ቢት TMDS (የሽግግር-አነስተኛ ልዩነት ምልክት) ይቀየራል። ይህ የዲሲ አካልን ከሲግናል ላይ ለማስወገድ እና በተለየ መስመር ውስጥ የሲግናል መቀያየርን ለመቀነስ ልዩ ኮድ ማድረጊያ ዘዴ ነው. 10 ቢት አሁን በተከታታዩ መስመር ላይ ለአንድ ባይት ቀለም መተላለፍ ስላለበት የተከታታይ ሰዓቱ ፍጥነት ከፒክሰል ሰዓት ፍጥነት በ10 እጥፍ ከፍ ያለ መሆን አለበት። ለምሳሌ የቪዲዮ ሁነታን 1280x720 60Hz ብንወስድ, የዚህ ሁነታ የፒክሰል ድግግሞሽ 74,25 ሜኸር ነው. ተከታታይ 742,5 ሜኸር መሆን አለበት.

መደበኛ FPGAዎች፣ በሚያሳዝን ሁኔታ፣ ይህንን ማድረግ አይችሉም። ሆኖም፣ እንደ እድል ሆኖ፣ FPGA አብሮገነብ የዲዲዮ ፒን አለው። እነዚህ ቀደም ሲል ከ2-ለ-1 ተከታታይ ተከታታይ ድምዳሜዎች ናቸው። ማለትም በሰዓት ድግግሞሽ በሚነሱ እና በሚወድቁ ጠርዞች ላይ ሁለት ቢትዎችን በቅደም ተከተል ማውጣት ይችላሉ። ይህ ማለት በ FPGA ፕሮጀክት ውስጥ 740 ሜኸር ሳይሆን 370 ሜኸር መጠቀም አይችሉም ነገር ግን በ FPGA ውስጥ የዲዲዮ ውፅዓት ክፍሎችን መጠቀም ያስፈልግዎታል. አሁን 370 MHz ቀድሞውኑ ሙሉ በሙሉ ሊደረስበት የሚችል ድግግሞሽ ነው. በሚያሳዝን ሁኔታ, 1280x720 ሁነታ ገደብ ነው. በማርስ Rover2rpi ሰሌዳ ላይ በተጫነው የእኛ Cyclone IV FPGA ውስጥ ከፍተኛ ጥራት ማግኘት አይቻልም።

ስለዚህ, በንድፍ ውስጥ, የግቤት ፒክሴል ድግግሞሽ CLK ወደ PLL ይሄዳል, በ 5 ተባዝቷል. በዚህ ድግግሞሽ, R, G, B ባይት ወደ ቢት ጥንድ ይለወጣሉ. የTMDS ኢንኮደር የሚያደርገው ይህ ነው። በVerilog HDL ውስጥ ያለው የምንጭ ኮድ ይህን ይመስላል።

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

ከዚያም የውጤት ጥንዶች ወደ DDIO ውፅዓት ይመገባሉ, ይህም በተከታታይ በሚነሱ እና በሚወድቁ ጠርዞች ላይ የአንድ-ቢት ምልክት ያመጣል.

DDIO ራሱ በሚከተለው የVerilog ኮድ ሊገለጽ ይችላል።

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

ግን ምናልባት በዚህ መንገድ አይሰራም። የ DDIO ውፅዓት ክፍሎችን በትክክል ለማንቃት Alter's megafunction ALTDDIO_OUTን መጠቀም አለቦት። የእኔ ፕሮጀክት ALTDDIO_OUT የቤተ-መጽሐፍት ክፍልን ይጠቀማል።

ይህ ሁሉ ትንሽ አስቸጋሪ ሊመስል ይችላል, ግን ይሰራል.

በVerilog HDL የተፃፈውን ሁሉንም የምንጭ ኮድ ማየት ትችላለህ እዚህ github ላይ.

ለ FPGA የተጠናቀረው ፈርምዌር በማርስ Rover2rpi ሰሌዳ ላይ በተጫነው EPCS ቺፕ ላይ ብልጭ ድርግም ይላል። ስለዚህ, ኃይል በ FPGA ሰሌዳ ላይ ሲተገበር, FPGA ከፍላሽ ማህደረ ትውስታ ይጀምራል እና ይጀምራል.

አሁን ስለ Raspberry ውቅር ትንሽ ማውራት ያስፈልገናል.

በዴቢያን ቡስተር፣ ስሪት፡ ኦገስት 32፣ በ Raspberry PI OS (2020 ቢት) ላይ ሙከራዎችን እያደረግሁ ነው።
የተለቀቀበት ቀን፡2020-08-20፣ የከርነል ስሪት፡5.4.

ሁለት ነገሮችን ማድረግ ያስፈልግዎታል:

  • የ config.txt ፋይልን ያርትዑ;
  • ከሁለት ማሳያዎች ጋር ለመስራት የ X አገልጋይ ውቅር ይፍጠሩ።

የ /boot/config.txt ፋይልን ሲያርትዑ ያስፈልግዎታል:

  1. የ i2c, i2s, spi አጠቃቀምን ያሰናክሉ;
  2. ተደራቢ dtoverlay=dpi24 በመጠቀም የዲፒአይ ሁነታን አንቃ;
  3. የቪዲዮ ሁነታን 1280 × 720 60Hz, 24 ቢት በፒክሰል በዲፒአይ ያዋቅሩ;
  4. የሚፈለገውን የፍሬምበፋር ቁጥር 2 ይጥቀሱ (max_framebuffers=2፣ ከዚያ በኋላ ብቻ ሁለተኛው መሳሪያ/dev/fb1 ይታያል)

የ config.txt ፋይል ሙሉ ጽሑፍ ይህን ይመስላል።

# 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

ከዚህ በኋላ X አገልጋዩ በሁለት ክፈፎች /dev/fb0 እና /dev/fb1 ላይ ሁለት ማሳያዎችን ለመጠቀም የውቅር ፋይል መፍጠር ያስፈልግዎታል።

የእኔ የማዋቀር ፋይል /usr/share/x11/xorg.conf.d/60-dualscreen.conf ይህን ይመስላል

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

ደህና, አስቀድሞ ካልተጫነ, ከዚያ Xinerama ን መጫን ያስፈልግዎታል. ከዚያ ከላይ ባለው የማሳያ ቪዲዮ ላይ እንደሚታየው የዴስክቶፕ ቦታው ሙሉ በሙሉ ወደ ሁለት ማሳያዎች ይሰፋል።

ያ ብቻ ሳይሆን አይቀርም። አሁን Raspberry Pi3 ባለቤቶች ሁለት ማሳያዎችን መጠቀም ይችላሉ።

የማርስ Rover2rpi ቦርድ መግለጫ እና የወረዳ ዲያግራም ይገኛል። እዚህ ተመልከት.

ምንጭ: hab.com