دوسرا HDMI مانیٹر Raspberry Pi3 پر DPI انٹرفیس اور FPGA بورڈ کے ذریعے


یہ ویڈیو دکھاتا ہے: ایک Raspberry Pi3 بورڈ، GPIO کنیکٹر کے ذریعے اس سے جڑا ہوا ایک FPGA بورڈ Mars Rover2rpi (سائیکلون IV) ہے، جس سے HDMI مانیٹر منسلک ہے۔ دوسرا مانیٹر Raspberry Pi3 کے معیاری HDMI کنیکٹر کے ذریعے جڑا ہوا ہے۔ سب کچھ ایک ساتھ کام کرتا ہے جیسے ڈوئل مانیٹر سسٹم۔

اگلا میں آپ کو بتاؤں گا کہ یہ کیسے لاگو ہوتا ہے۔

مقبول Raspberry Pi3 بورڈ میں ایک GPIO کنیکٹر ہے جس کے ذریعے آپ مختلف ایکسپینشن کارڈز کو جوڑ سکتے ہیں: سینسرز، ایل ای ڈی، سٹیپر موٹر ڈرائیور اور بہت کچھ۔ کنیکٹر پر ہر پن کا صحیح کام پورٹ کنفیگریشن پر منحصر ہے۔ GPIO ALT2 کنفیگریشن آپ کو کنیکٹر کو DPI انٹرفیس موڈ، ڈسپلے متوازی انٹرفیس میں تبدیل کرنے کی اجازت دیتی ہے۔ VGA مانیٹرز کو DPI کے ذریعے جوڑنے کے لیے توسیعی کارڈ موجود ہیں۔ تاہم، سب سے پہلے، VGA مانیٹر اب HDMI کی طرح عام نہیں ہیں، اور دوسرا، ڈیجیٹل انٹرفیس ینالاگ والے سے بہتر ہوتا جا رہا ہے۔ مزید یہ کہ اس طرح کے VGA توسیعی بورڈز پر DAC عام طور پر R-2-R چینز کی شکل میں بنایا جاتا ہے اور اکثر 6 بٹس فی رنگ سے زیادہ نہیں ہوتا ہے۔

ALT2 موڈ میں، GPIO کنیکٹر پنوں کے مندرجہ ذیل معنی ہیں:

دوسرا HDMI مانیٹر Raspberry Pi3 پر DPI انٹرفیس اور FPGA بورڈ کے ذریعے

یہاں میں نے کنیکٹر کے RGB پنوں کو بالترتیب سرخ، سبز اور نیلے رنگ میں رنگ دیا ہے۔ دیگر اہم سگنلز V-SYNC اور H-SYNC سگنلز کے ساتھ ساتھ CLK ہیں۔ CLK کلاک فریکوئنسی وہ فریکوئنسی ہے جس پر پکسل ویلیو کنیکٹر پر آؤٹ پٹ ہوتی ہے؛ یہ منتخب ویڈیو موڈ پر منحصر ہے۔

ڈیجیٹل HDMI مانیٹر کو جوڑنے کے لیے، آپ کو انٹرفیس کے DPI سگنلز کو پکڑنے اور انہیں HDMI سگنلز میں تبدیل کرنے کی ضرورت ہے۔ یہ کیا جا سکتا ہے، مثال کے طور پر، کسی قسم کے FPGA بورڈ کا استعمال کرتے ہوئے. جیسا کہ یہ پتہ چلتا ہے، Mars Rover2rpi بورڈ ان مقاصد کے لیے موزوں ہے۔ سچ میں، اس بورڈ کو ایک خاص اڈاپٹر کے ذریعے جوڑنے کا بنیادی آپشن اس طرح لگتا ہے:

دوسرا HDMI مانیٹر Raspberry Pi3 پر DPI انٹرفیس اور FPGA بورڈ کے ذریعے

یہ بورڈ GPIO بندرگاہوں کی تعداد بڑھانے اور مزید پردیی آلات کو رسبری سے جوڑنے کے لیے استعمال کیا جاتا ہے۔ ایک ہی وقت میں، اس کنکشن کے ساتھ 4 GPIO سگنلز JTAG سگنلز کے لیے استعمال کیے جاتے ہیں، تاکہ Raspberry کا پروگرام FPGA فرم ویئر کو FPGA میں لوڈ کر سکے۔ اس کی وجہ سے، یہ معیاری کنکشن میرے مطابق نہیں ہے؛ 4 DPI سگنلز چھوڑ دیتے ہیں۔ خوش قسمتی سے، بورڈ پر اضافی کنگھیوں میں راسبیری کے موافق پن آؤٹ ہے۔ لہذا میں بورڈ کو 90 ڈگری گھما سکتا ہوں اور پھر بھی اسے اپنے رسبری سے جوڑ سکتا ہوں:

دوسرا HDMI مانیٹر Raspberry Pi3 پر DPI انٹرفیس اور FPGA بورڈ کے ذریعے

یقینا، آپ کو ایک بیرونی JTAG پروگرامر استعمال کرنا پڑے گا، لیکن یہ کوئی مسئلہ نہیں ہے۔

اب بھی ایک چھوٹا سا مسئلہ ہے۔ ہر FPGA پن کو کلاک ان پٹ کے طور پر استعمال نہیں کیا جا سکتا۔ صرف چند وقف شدہ پن ہیں جو ان مقاصد کے لیے استعمال کیے جا سکتے ہیں۔ تو یہاں پتہ چلا کہ GPIO_0 CLK سگنل FPGA ان پٹ تک نہیں پہنچتا، جسے FPGA کلاک ان پٹ کے طور پر استعمال کیا جا سکتا ہے۔ تو مجھے اب بھی اسکارف پر ایک تار لگانا پڑا۔ میں GPIO_0 اور بورڈ کے KEY[1] سگنل کو جوڑتا ہوں:

دوسرا HDMI مانیٹر Raspberry Pi3 پر DPI انٹرفیس اور FPGA بورڈ کے ذریعے

اب میں آپ کو FPGA پروجیکٹ کے بارے میں تھوڑا سا بتاؤں گا۔ HDMI سگنلز پیدا کرنے میں سب سے بڑی مشکل بہت زیادہ تعدد ہے۔ اگر آپ HDMI کنیکٹر پن آؤٹ پر نظر ڈالتے ہیں، تو آپ دیکھ سکتے ہیں کہ RGB سگنلز اب سیریل ڈیفرینشل سگنلز ہیں:

دوسرا HDMI مانیٹر Raspberry Pi3 پر DPI انٹرفیس اور FPGA بورڈ کے ذریعے

تفریق سگنل کا استعمال آپ کو ٹرانسمیشن لائن پر عام موڈ مداخلت کا مقابلہ کرنے کی اجازت دیتا ہے۔ اس صورت میں، ہر کلر سگنل کے اصل آٹھ بٹ کوڈ کو 10-بٹ TMDS (ٹرانزیشن مائنسائزڈ ڈیفرینشل سگنلنگ) میں تبدیل کیا جاتا ہے۔ یہ سگنل سے DC جزو کو ہٹانے اور فرق والی لائن میں سگنل سوئچنگ کو کم سے کم کرنے کے لیے کوڈنگ کا ایک خاص طریقہ ہے۔ چونکہ اب 10 بٹس کو رنگ کے ایک بائٹ کے لیے سیریل لائن پر منتقل کرنے کی ضرورت ہے، اس لیے یہ پتہ چلتا ہے کہ سیریلائزر کی گھڑی کی رفتار پکسل کی گھڑی کی رفتار سے 10 گنا زیادہ ہونی چاہیے۔ اگر ہم مثال کے طور پر ویڈیو موڈ 1280x720 60Hz لیں تو اس موڈ کی پکسل فریکوئنسی 74,25 MHz ہے۔ سیریلائزر 742,5 میگاہرٹز ہونا چاہیے۔

باقاعدگی سے FPGAs، بدقسمتی سے، اس کے قابل نہیں ہیں۔ تاہم، خوش قسمتی سے ہمارے لیے، FPGA میں بلٹ ان DDIO پن ہیں۔ یہ وہ نتائج ہیں جو پہلے سے ہی ہیں، جیسا کہ یہ تھے، 2 سے 1 سیریلائزر۔ یعنی، وہ گھڑی کی فریکوئنسی کے بڑھتے اور گرتے ہوئے کناروں پر ترتیب وار دو بٹس نکال سکتے ہیں۔ اس کا مطلب ہے کہ FPGA پروجیکٹ میں آپ 740 MHz نہیں بلکہ 370 MHz استعمال کر سکتے ہیں، لیکن آپ کو FPGA میں DDIO آؤٹ پٹ عناصر استعمال کرنے کی ضرورت ہے۔ اب 370 میگاہرٹز پہلے سے ہی مکمل طور پر قابل حصول تعدد ہے۔ بدقسمتی سے، 1280x720 موڈ حد ہے۔ Mars Rover2rpi بورڈ پر نصب ہمارے سائیکلون IV FPGA میں زیادہ ریزولوشن حاصل نہیں کیا جا سکتا۔

لہذا، ڈیزائن میں، ان پٹ پکسل فریکوئنسی CLK PLL میں جاتی ہے، جہاں اسے 5 سے ضرب دیا جاتا ہے۔ اس فریکوئنسی پر، R، G، B بائٹس بٹ جوڑوں میں تبدیل ہو جاتے ہیں۔ یہ وہی ہے جو TMDS انکوڈر کرتا ہے۔ ویریلوگ ایچ ڈی ایل میں سورس کوڈ اس طرح لگتا ہے:

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 کا میگا فنکشن ALTDIO_OUT استعمال کرنے کی ضرورت ہے۔ میرا پروجیکٹ ALTDIO_OUT لائبریری کا حصہ استعمال کرتا ہے۔

یہ سب کچھ تھوڑا مشکل لگ سکتا ہے، لیکن یہ کام کرتا ہے۔

آپ Verilog HDL میں لکھا ہوا تمام سورس کوڈ دیکھ سکتے ہیں۔ یہاں گیتھب پر.

FPGA کے لیے مرتب کردہ فرم ویئر کو Mars Rover2rpi بورڈ پر نصب EPCS چپ میں چمکایا جاتا ہے۔ اس طرح، جب FPGA بورڈ پر پاور لگائی جائے گی، FPGA فلیش میموری سے شروع ہو جائے گا اور شروع ہو جائے گا۔

اب ہمیں راسبیری کی ترتیب کے بارے میں تھوڑی بات کرنے کی ضرورت ہے۔

میں Raspberry PI OS (32 bit) پر ڈیبین بسٹر، ورژن: اگست 2020 کی بنیاد پر تجربات کر رہا ہوں۔
ریلیز کی تاریخ: 2020-08-20، کرنل ورژن: 5.4.

آپ کو دو چیزیں کرنے کی ضرورت ہے:

  • config.txt فائل میں ترمیم کریں؛
  • دو مانیٹر کے ساتھ کام کرنے کے لیے ایک X سرور کنفیگریشن بنائیں۔

/boot/config.txt فائل میں ترمیم کرتے وقت آپ کو ضرورت ہے:

  1. i2c، i2s، spi کے استعمال کو غیر فعال کریں؛
  2. اوورلے کا استعمال کرتے ہوئے DPI موڈ کو فعال کریں dtoverlay=dpi24؛
  3. ویڈیو موڈ 1280×720 60Hz، DPI پر 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

اس کے بعد، آپ کو دو فریم بفرز /dev/fb0 اور /dev/fb1 پر دو مانیٹر استعمال کرنے کے لیے X سرور کے لیے ایک کنفیگریشن فائل بنانے کی ضرورت ہے۔

میری کنفیگریشن فائل /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 مالکان دو مانیٹر استعمال کر سکیں گے۔

Mars Rover2rpi بورڈ کی تفصیل اور سرکٹ ڈایاگرام پایا جا سکتا ہے۔ یہاں دیکھو.

ماخذ: www.habr.com