首先來明確下設計結構,不管是用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信號,顯示器就可以正常工作。