An dàrna monitor HDMI gu Raspberry Pi3 tro eadar-aghaidh DPI agus bòrd FPGA


Tha am bhidio seo a’ sealltainn: tha bòrd Raspberry Pi3, ceangailte ris tro cheangal GPIO na bhòrd FPGA Mars Rover2rpi (Cyclone IV), ris a bheil monitor HDMI ceangailte. Tha an dàrna monitor ceangailte tron ​​​​cheangal HDMI àbhaisteach den Raspberry Pi3. Bidh a h-uile càil ag obair còmhla mar shiostam sgrùdaidh dùbailte.

An ath rud innsidh mi dhut mar a thèid seo a chuir an gnìomh.

Tha ceangal GPIO aig a’ bhòrd mòr-chòrdte Raspberry Pi3 tron ​​​​urrainn dhut diofar chairtean leudachaidh a cheangal: mothachairean, LEDs, draibhearan motair stepper agus mòran a bharrachd. Tha dearbh ghnìomh gach prìne air ceanglaiche an urra ri rèiteachadh a’ phuirt. Leigidh rèiteachadh GPIO ALT2 leat an ceanglaiche atharrachadh gu modh eadar-aghaidh DPI, Display Parallel Interface. Tha cairtean leudachaidh ann airson sgrùdairean VGA a cheangal tro DPI. Ach, an toiseach, chan eil sgrùdairean VGA tuilleadh cho cumanta ri HDMI, agus san dàrna àite, tha an eadar-aghaidh didseatach a’ sìor fhàs nas fheàrr na an analogue. A bharrachd air an sin, mar as trice bidh an DAC air bùird leudachaidh VGA mar sin air a dhèanamh ann an cruth slabhraidhean R-2-R agus gu tric gun a bhith nas fhaide na 6 pìosan gach dath.

Ann am modh ALT2, tha an ciall a leanas aig prìneachan ceangail GPIO:

An dàrna monitor HDMI gu Raspberry Pi3 tro eadar-aghaidh DPI agus bòrd FPGA

An seo tha mi air prìneachan RGB a’ cheangail a dhath dearg, uaine is gorm fa leth. Is e comharran cudromach eile na comharran V-SYNC agus H-SYNC, a bharrachd air CLK. Is e tricead gleoc CLK an tricead aig a bheil luachan piogsail air an toirt a-mach don cheangal; tha e an urra ris a ’mhodh bhidio taghte.

Gus monitor didseatach HDMI a cheangal, feumaidh tu comharran DPI an eadar-aghaidh a ghlacadh agus an tionndadh gu comharran HDMI. Faodar seo a dhèanamh, mar eisimpleir, a 'cleachdadh seòrsa de bhòrd FPGA. Mar a thionndaidh e, tha bòrd Mars Rover2rpi freagarrach airson na h-adhbharan sin. Gu fìrinneach, tha am prìomh roghainn airson a ’bhòrd seo a cheangal tro inneal-atharrachaidh sònraichte a’ coimhead mar seo:

An dàrna monitor HDMI gu Raspberry Pi3 tro eadar-aghaidh DPI agus bòrd FPGA

Tha am bòrd seo air a chleachdadh gus an àireamh de phuirt GPIO a mheudachadh agus gus barrachd innealan iomaill a cheangal ris an t-sùbh-craoibhe. Aig an aon àm, thathas a’ cleachdadh comharran 4 GPIO leis a’ cheangal seo airson comharran JTAG, gus an urrainn don phrògram bho Raspberry firmware FPGA a luchdachadh a-steach don FPGA. Air sgàth seo, chan eil an ceangal àbhaisteach seo a’ freagairt orm; Bidh comharran 4 DPI a’ tuiteam a-mach. Gu fortanach, tha pinout co-chosmhail ri sùbh-craoibhe air na cìrean a bharrachd air a’ bhòrd. Mar sin is urrainn dhomh am bòrd a thionndadh 90 ceum agus a cheangal fhathast ris an t-sùbh-craoibhe agam:

An dàrna monitor HDMI gu Raspberry Pi3 tro eadar-aghaidh DPI agus bòrd FPGA

Gu dearbh, feumaidh tu prògramadair JTAG taobh a-muigh a chleachdadh, ach chan eil seo na dhuilgheadas.

Tha duilgheadas beag ann fhathast. Chan urrainnear a h-uile prìne FPGA a chleachdadh mar chuir a-steach gleoc. Chan eil ann ach beagan phrìneachan sònraichte a dh'fhaodar a chleachdadh airson nan adhbharan seo. Mar sin thionndaidh e a-mach an seo nach ruig an comharra GPIO_0 CLK cuir a-steach FPGA, a dh’ fhaodar a chleachdadh mar chuir a-steach gleoc FPGA. Mar sin bha agam ri aon uèir a chuir air an sgarfa fhathast. Bidh mi a’ ceangal GPIO_0 agus comharra PRÌOMH[1] a’ bhùird:

An dàrna monitor HDMI gu Raspberry Pi3 tro eadar-aghaidh DPI agus bòrd FPGA

A-nis innsidh mi beagan dhut mu phròiseact FPGA. Is e am prìomh dhuilgheadas ann a bhith a’ gineadh comharran HDMI tricead glè àrd. Ma choimheadas tu air pinout ceangail HDMI, chì thu gu bheil na comharran RGB a-nis nan comharran eadar-dhealaichte sreathach:

An dàrna monitor HDMI gu Raspberry Pi3 tro eadar-aghaidh DPI agus bòrd FPGA

Leigidh cleachdadh comharra eadar-dhealachaidh dhut cuir an-aghaidh bacadh modh cumanta air an loidhne sgaoilidh. Anns a 'chùis seo, tha an còd ochd-bit tùsail de gach comharra dath air a thionndadh gu TMDS 10-bit (Comharran eadar-dhealaichte air a lùghdachadh le gluasad). Is e dòigh còdaidh sònraichte a tha seo gus am pàirt DC a thoirt air falbh bhon chomharra agus lughdachadh atharrachadh chomharran ann an loidhne eadar-dhealachaidh. Leis gu feumar pìosan 10 a-nis a chuir thairis air an loidhne sreathach airson aon byte de dhath, tha e a ’tionndadh a-mach gum feum astar gleoc an t-sreathaiche a bhith 10 tursan nas àirde na astar gleoc picteil. Ma ghabhas sinn mar eisimpleir am modh bhidio 1280x720 60Hz, is e tricead piogsail a’ mhodh seo 74,25 MHz. Bu chòir gum biodh an t-sreathaiche 742,5 MHz.

Gu mì-fhortanach, chan eil FPGAn cunbhalach comasach air seo. Ach, gu fortanach dhuinne, tha prìneachan DIO a-staigh aig an FPGA. Is iad sin co-dhùnaidhean a tha mar-thà, mar gum biodh, serializers 2-to-1. Is e sin, faodaidh iad dà phìos a chuir a-mach ann an sreath air oirean àrdachadh is tuiteam tricead a’ ghleoc. Tha seo a’ ciallachadh, ann am pròiseact FPGA, nach urrainn dhut 740 MHz a chleachdadh, ach 370 MHz, ach feumaidh tu eileamaidean toraidh DIO a chleachdadh anns an FPGA. A-nis tha 370 MHz mar tricead a ghabhas coileanadh gu tur. Gu mì-fhortanach, is e modh 1280x720 an ìre as àirde. Chan urrainnear fuasgladh nas àirde a choileanadh anns an Cyclone IV FPGA againn a chaidh a chuir a-steach air bòrd Mars Rover2rpi.

Mar sin, anns an dealbhadh, bidh an tricead piogsail cuir a-steach CLK a’ dol chun PLL, far a bheil e air iomadachadh le 5. Aig an tricead seo, bidh na bytes R, G, B air an tionndadh gu bhith nan càraidean bit. Is e seo a bhios an encoder TMDS a’ dèanamh. Tha an còd tùsail ann an Verilog HDL a’ coimhead mar seo:

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

An uairsin bidh na paidhrichean toraidh air am biathadh gu toradh DDIO, a bhios ann an sreath a’ toirt a-mach comharra aon-phìos air na h-oirean ag èirigh is a’ tuiteam.

Faodar cunntas a thoirt air DDIO fhèin leis a’ chòd Verilog a leanas:

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

Ach is dòcha nach obraich e mar sin. Feumaidh tu megafunction Alter ALTDDIO_OUT a chleachdadh gus na h-eileamaidean toraidh DDIO a chomasachadh. Tha am pròiseact agam a’ cleachdadh co-phàirt leabharlainn ALTDDIO_OUT.

Is dòcha gu bheil seo uile a ’coimhead beagan duilich, ach tha e ag obair.

Chì thu an còd tùsail gu lèir sgrìobhte ann an Verilog HDL an seo air github.

Tha am firmware cruinnichte airson an FPGA air a lasadh a-steach don chip EPCS a chaidh a chuir a-steach air bòrd Mars Rover2rpi. Mar sin, nuair a thèid cumhachd a chuir air bòrd FPGA, thèid am FPGA a thòiseachadh bho chuimhne flash agus tòiseachadh.

A-nis feumaidh sinn bruidhinn beagan mu rèiteachadh an sùbh-craoibhe fhèin.

Tha mi a’ dèanamh dheuchainnean air Raspberry PI OS (32 bit) stèidhichte air Debian Buster, Tionndadh: Lùnastal 2020,
Ceann-latha fuasglaidh: 2020-08-20, dreach Kernel: 5.4.

Feumaidh tu dà rud a dhèanamh:

  • deasaich am faidhle config.txt;
  • cruthaich rèiteachadh frithealaiche X gus obrachadh le dà sgrùdair.

Nuair a bhios tu a’ deasachadh an fhaidhle /boot/config.txt feumaidh tu:

  1. cuir à comas cleachdadh i2c, i2s, spi;
  2. cuir an comas modh DPI a’ cleachdadh overlay dtoverlay = dpi24;
  3. rèiteachadh modh bhidio 1280 × 720 60Hz, 24 pìosan gach piogsail air DPI;
  4. sònraich an àireamh riatanach de fhrèam-buffers 2 (max_framebuffers = 2, dìreach an uairsin a nochdas an dàrna inneal / dev / fb1)

Tha teacsa slàn an fhaidhle config.txt a' coimhead mar seo.

# 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

Às deidh seo, feumaidh tu faidhle rèiteachaidh a chruthachadh airson an fhrithealaiche X gus dà sgrùdair a chleachdadh air dà fhrèam-buffers / dev/fb0 agus /dev/fb1:

Tha am faidhle rèiteachaidh agam /usr/share/x11/xorg.conf.d/60-dualscreen.conf mar seo

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

Uill, mura h-eil e air a chuir a-steach mu thràth, feumaidh tu Xinerama a stàladh. An uairsin thèid an raon deasg a leudachadh gu dà sgrùdair, mar a chithear anns a ’bhidio demo gu h-àrd.

Is dòcha gur e sin uile. A-nis, bidh e comasach dha sealbhadairean Raspberry Pi3 dà sgrùdair a chleachdadh.

Gheibhear tuairisgeul agus diagram cuairteachaidh de bhòrd Mars Rover2rpi seall an seo.

Source: www.habr.com