zynq 實現液晶顯示器顯示(ADV7511)

      首先來明確下設計結構,不管是用HDMI,VGA還是DP,最重要的過程是把幀緩衝中的RGB數據轉換成顯示掃描時序。顯示掃描時序這個詞並不存在於顯示行業,只是我認爲這樣說能概括問題。

     來解釋下顯示掃描時序。先說幾個名詞,之後會用上:

1、像素時鐘(CLK):屏幕上每個像素點顯示動態顯示都需要像素時鐘來刷新;

2、行同步時鐘(HSYNC):當顯示器顯示一行像素的時間;

3、場同步時鐘(VSYNC):顯示器顯示一幀內容的時間;

4、像素數據(data):每個像素點的原始RGB數據;

     找兩張圖來解釋下:

        就這樣吧,重點不在這裏。爲什麼要寫這麼點?我覺得恰到好處,不會的人可以得到提示去專門學一下顯示控制器的相關知識。會的人也不想看太多。同智的內容看起來舒服,但是不會有成長。

       PL部分的實現:

這是顯示控制器的IP核,可以在ADI官網找到。注意下輸入信號:

1、S_AXI是利用AXI_LITE對該控制器進行一些寄存器相關的配置。

2、hdmi_clk就是像素時鐘;

3、vdma_clk是和VDMA控制器同步的時鐘;

4、vdma_data是鏈接dma控制器輸出端,也是該模塊的原始數據輸入;

輸出信號就是之前講的顯示掃描時序,你可以在物理層接HDMI傳輸器,或者直接接RGB顯示器。

 

VDMA控制器:

先看信號含義:

1、S_AXI_LITE同樣是完成該控制器配置的;

2、mm2s_fsync:幀同步

3、M_AXI_MM2S:DMA數據來源;

4、M_AXI_MM2S:DMA數據流出;

 

以上是部分的連接圖,嘗試了好多次都沒有好辦法把矢量圖粘貼上來。有需要可以郵箱聯繫我 [email protected]  tcl腳本後再github發佈。

好了,到這一步,PL部分基本完成。來看下地址分配。這個很重要,之後無論是裸金屬操作還是搭載操作系統,中斷號和控制器地址永遠是最重要的,地址信息如下:

中斷號:

完成了PL部分設計以後,開始轉向PS設計。

PS會統籌所用PL以及硬件資源,最後實現內容的顯示。

以上連接在zynq上的ADV7511。

1、除了視頻控制信號以外,還需要一路IIC對該器件進行一些配置。因此PS代碼中應該有ADV7511的初始化代碼;

2、在PL總的連接圖可以看出,顯示控制器需要一路clk_gen,該信號受AXI總線控制;

3、視屏控制器以及VDMA,這部分代碼是顯卡驅動程序;

根據以上所分析的,來對設備樹進行修改:

/ {
	fpga_axi: fpga-axi@0 {
		compatible = "simple-bus";
		#address-cells = <0x1>;
		#size-cells = <0x1>;
		ranges;

		i2c@41600000 {
			compatible = "xlnx,axi-iic-1.02.a", "xlnx,xps-iic-2.00.a";
			reg = <0x41600000 0x10000>;
			interrupt-parent = <&intc>;
			interrupts = <0 58 4>;
			clocks = <&clkc 15>;
			clock-names = "pclk";

			#address-cells = <1>;
			#size-cells = <0>;

			i2c_mux: i2cswitch@74 {
				compatible = "nxp,pca9548";
				#address-cells = <1>;
				#size-cells = <0>;
				reg = <0x74>;

				i2c@0 {
					#address-cells = <1>;
					#size-cells = <0>;
					reg = <0>;
					osc@5d {
						compatible = "si570";
						temperature-stability = <50>;
						reg = <0x5d>;
						factory-fout = <156250000>;
						initial-fout = <148500000>;
					};
				};

				i2c@1 {
				    #address-cells = <1>;
				    #size-cells = <0>;
				    reg = <1>;

				    adv7511: adv7511 {
						compatible = "adi,adv7511";
						reg = <0x39>, <0x3f>;
						reg-names = "primary", "edid";

						adi,input-depth = <8>;
						adi,input-colorspace = "rgb";
						adi,input-clock = "1x";
						adi,clock-delay = <0>;

						#sound-dai-cells = <0>;

						ports {
							#address-cells = <1>;
							#size-cells = <0>;

							port@0 {
								reg = <0>;
								adv7511_in: endpoint {
									remote-endpoint = <&axi_hdmi_out>;
								};
							};

							port@1 {
								reg = <1>;
							};
						};
				    };
				};

				i2c@2 {
					#address-cells = <1>;
					#size-cells = <0>;
					reg = <2>;
					eeprom@54 {
						compatible = "at,24c08";
						reg = <0x54>;
					};
				};

				i2c@3 {
					#address-cells = <1>;
					#size-cells = <0>;
					reg = <3>;
					gpio@21 {
						compatible = "ti,tca6416";
						reg = <0x21>;
						gpio-controller;
						#gpio-cells = <2>;
					};
				};

				i2c@4 {
					#address-cells = <1>;
					#size-cells = <0>;
					reg = <4>;
					rtc@54 {
						compatible = "nxp,pcf8563";
						reg = <0x51>;
					};
				};
			};
		};

		axi_vdma_0: axivdma@43000000 {
			#address-cells = <1>;
			#size-cells = <1>;
			#dma-cells = <1>;
			compatible = "xlnx,axi-vdma-1.00.a";
			reg = <0x43000000 0x1000>;
			xlnx,num-fstores = <0x3>;
			dma-channel@43000000 {
				compatible = "xlnx,axi-vdma-mm2s-channel";
				interrupts = <0 59 0x4>;
				xlnx,datawidth = <0x40>;
				xlnx,genlock-mode = <0x0>;
				xlnx,include-dre = <0x0>;
			};
		};

		hdmi_clock: axi-clkgen@0x43C10000 {
			compatible = "adi,axi-clkgen-2.00.a";
			reg = <0x43C10000 0x10000>;
			#clock-cells = <0>;
			clocks = <&clkc 16>;
		};

		axi_hdmi@0x43C00000 {
			compatible = "adi,axi-hdmi-tx-1.00.a";
			reg = <0x43C00000 0x10000>;
			dmas = <&axi_vdma_0 0>;
			dma-names = "video";
			clocks = <&hdmi_clock>;
			adi,is-rgb;

			port {
				axi_hdmi_out: endpoint {
					remote-endpoint = <&adv7511_in>;
				};
			};
		};

	//	axi_spdif_tx_0: axi-spdif-tx@75c00000 {
	//		compatible = "adi,axi-spdif-tx-1.00.a";
	//		reg = <0x75c00000 0x1000>;
	//		dmas = <&dmac_s 0>;
	//		dma-names = "tx";
	//		clocks = <&clkc 15>, <&audio_clock>;
	//		clock-names = "axi", "ref";
 
	//		#sound-dai-cells = <0>;
		};
	};

	audio_clock: audio_clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <12288000>;
	};

	adv7511_hdmi_snd {
		compatible = "simple-audio-card";
		simple-audio-card,name = "HDMI monitor";
		simple-audio-card,widgets =
			"Speaker", "Speaker";
		simple-audio-card,routing =
			"Speaker", "TX";

		simple-audio-card,dai-link@0 {
			format = "spdif";
			cpu {
				sound-dai = <&axi_spdif_tx_0>;
				frame-master;
				bitclock-master;
			};
			codec {
				sound-dai = <&adv7511>;
			};
		};
	};
};

設備樹的修改比較容易,就是根據之前PL部分的地址已經中斷號。IIC控制器的設備樹要結合自己的硬件平臺來進行修改,我這裏使用的是軟核IIC控制器+IIC多路器來對adv7511進行控制。

       在調試的時候要首先關注這裏,CPU通過IIC控制器會讀取液晶顯示器的EDID,該驅動程序註冊了debugfs,可以直接查看到設備的edid以及時鐘等信息。debugfs使用如下:

1、配置內核,使其支持debugfs   Kernelhacking --->[*]Debug Filesystem;

2、mount -t debugfs none /mnt;

3、打開掛在的目錄;

HDMI識別顯示器的過程有必要囉嗦一下。當顯示器連接到HDMI connector 上時,已有一個hotplug信號。該信號表徵HDMI顯示器已經連接,硬件測試時候要關注該信號。當ADV7511拿到該信號以後,就開始讀取液晶顯示器的EDID,(EDID就是告訴顯示控制器自己的信息,比如分辨率,backsacn time等)。顯示控制器拿到這些信息以後,顯示控制器會發出與之匹配的信號。

如果這一步沒有問題,示波器就能夠測量到clk,hsync,vsync信號,顯示器就可以正常工作。

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章