1)實驗平台:正點原子領航者ZYNQ開發闆
2)平台購買位址:https://item.taobao.com/item.htm?&id=606160108761
3)全套實驗源碼+手冊+視訊下載下傳位址:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
4)對正點原子FPGA感興趣的同學可以加群讨論:876744900
5)關注正點原子公衆号,擷取最新資料
http://weixin.qq.com/r/hEhUTLbEdesKrfIv9x2W (二維碼自動識别)
第二十章SD卡讀BMP圖檔HDMI顯示實驗
我們在“SD卡讀BMP圖檔LCD顯示實驗”中,成功地将SD卡中的BMP圖檔讀出,并将其顯示在了LCD屏上。本章我們将學習如何SD卡中的BMP圖檔顯示在HDMI顯示器上。
本章包括以下幾個部分:
2020.1簡介
20.2實驗任務
20.3硬體設計
20.4軟體設計
20.5下載下傳驗證
20.1簡介
在“SD卡讀BMP圖檔LCD顯示實驗”的簡介部分,我們詳細介紹了BMP圖檔的資料格式;另外在《領航者FPGA開發指南》中的“HDMI彩條顯示實驗”一章,我們介紹了HDMI接口。如果大家對這兩部分的内容不熟悉的話,可以參考相應的章節,此處就不再贅述了。
20.2實驗任務
本章的實驗任務是使用領航者ZYNQ開發闆讀取SD卡中存放的BMP格式圖檔,分辨率為1920*1080,并将其顯示在HDMI顯示器上。
20.3硬體設計
根據實驗任務我們可以畫出本次實驗的系統框圖,如下圖所示:
圖 20.3.1 系統框圖
圖 5.3.1與“SD卡讀BMP圖檔LCD顯示實驗”中的系統框圖基本相同,隻是将驅動LCD顯示的rgb2lcd子產品替換成了本次實驗中的DVI Transmitter,用于驅動HDMI接口;另外還删除了用于讀取LCD ID資訊的AXI GPIO子產品。是以本次實驗的硬體設計部分在“SD卡讀BMP圖檔LCD顯示實驗”的基礎上稍作修改即可。
首先要删除《SD卡讀BMP圖檔LCD顯示實驗》工程中的rgb to lcd和AXI GPIO兩個子產品,以及LCD相關的接口。如圖 20.3.2所示,我們要删除圖中橙色高亮的兩個子產品和3個接口:
圖 20.3.2 删除LCD相關子產品
接下來添加DVI Transmitter IP核。該IP核位于工程目錄下的ip_repo檔案夾中,名為“DVI_TX”。我們需要将其添加到工程的IP庫中,添加IP核的方法請大家參考“自定義IP核-呼吸燈實驗”。添加完成後,我們要在Block Design中連接配接DVI Transmitter子產品的接口信号,并引出外部端口,具體的連接配接方式如圖 20.3.3所示:
圖 20.3.3 添加并連接配接DVI_Transmitter IP核
至此本次實驗的硬體框圖已經搭建好了。需要說明的是,本次實驗的硬體框圖是基于《SD卡讀BMP圖檔LCD顯示實驗》搭建的,VDMA的AXI Stream格式資料流和Memory Map格式資料流的時鐘頻率設定的較低,為100Mhz,是以VDMA和DDR3的資料互動速率會受到限制,即支援的HDMI顯示分辨率無法達到很高,實測最大能達到的分辨率為1280x800。
對于LCD屏的顯示實驗來說,達到1280x800的分辨率已經夠用了,但是考慮到目前大多數的HDMI顯示器支援1080P(1920x1080)的分辨率,我們需要對底層搭建的硬體環境做修改,才能支援1080P分辨率。考慮到本手冊HDMI顯示相關的例程不需要1080P分辨率,且大多數HDMI顯示例程是基于LCD例程修改而來,如果每次都為了相容1080P分辨率而修改底層硬體環境比較麻煩,是以本手冊僅本章實驗的底層硬體環境支援1080P分辨率,其它HDMI實驗大家如果有1080P分辨率的顯示需求,可以按照本章實驗進行修改。
底層硬體修改的方法是将VDMA的AXI Stream格式資料流和Memory Map格式資料流的時鐘頻率改為150Mhz,而VDMA的配置端口不需要太高的頻率,可以仍然保持100Mhz。
首先輕按兩下打開“ZYNQ7 Processing System”框圖,點選“Clock Configuration”,在“PL Fabric Clocks”一欄下勾選FCLK_CLK1,時鐘頻率設定為150Mhz。設定完成後,點選“OK”按鈕,如下圖所示:
圖 20.3.4 添加“FCLK_CLK1”時鐘
修改完成後,可以發現“ZYNQ7 Processing System”框圖多了一個FCLK_CLK1端口。接下來删除FCLK_CLK0連線,首先選中FCLK_CLK0的連線使其高亮,然後按下鍵盤的“Delete”進行删除,如圖 20.3.5和圖 20.3.6所示:
圖 20.3.5 選中FCLK_CLK0連線
圖 20.3.6 删除FCLK_CLK0連線
然後删除框圖中的AXI Interconnect IP核(ps7_0_axi_periph)、AXI SmartConnect IP核(axi_smc)和Processor System Reset IP核(rst_ps7_0_100M),框圖删除後,如下圖所示。
圖 20.3.7 删除IP核
接下來連接配接FCLK_CLK1的時鐘,如下圖所示。
然後點選“Run Connnection Automation”,下面列出了會自動連接配接的子產品及其接口,勾選“All Automation”,然後點選“OK”按鈕。
此時系統會自動生成 AXI Interconnect 和 AXI Smartconnect。AXI Interconnect(ps7_0_axi_periph)用于橋接ZYNQ處理器M_AXI_GP0總線和外部低速外設的AXI_LITE總線;AXI Smartconnect(axi_smc)用于連接配接ZYNQ處理器的HP0接口和VDMA的M_AXI_MM2S總線。另外系統也自動生成了兩個 reset子產品(rst_ps7_0_100M和rst_ps7_0_150M),用于複位總線上的外設。
整體系統架構圖如下:
圖 20.3.8 整體系統架構連接配接圖
block design修改完成後儲存,然後重新Generate Output Products和“Create HDL Wrapper”。接下來我們還要修改限制檔案,為HDMI接口配置設定引腳。打開工程中名為“system_wrapper.xdc”的限制檔案,并将原先LCD相關的限制語句删除,替換成以下内容:
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports tmds_oen_0]
set_property PACKAGE_PIN L16 [get_ports {TMDS_0_tmds_data_p[2]}]
set_property PACKAGE_PIN M14 [get_ports {TMDS_0_tmds_data_p[1]}]
set_property PACKAGE_PIN K19 [get_ports {TMDS_0_tmds_data_p[0]}]
set_property PACKAGE_PIN L14 [get_ports TMDS_0_tmds_clk_p]
儲存限制檔案,然後選擇“Generate Bitstream”重新生成BIT檔案。
20.4軟體設計
本次實驗的軟體工程與“SD卡讀BMP圖檔LCD顯示實驗”略有不同,如下圖所示:
圖 20.4.1 軟體工程
圖 20.4.1左側紅色方框中的檔案夾名為“display_ctrl_hdmi”,它在前面實驗中“display_ctrl”的基礎上删除了GPIO相關的函數及變量。在本次實驗中删除了AXI GPIO子產品,是以要删除這些函數和變量,否則會報錯。
本次實驗的代碼如下所示:
- 1 #include <stdio.h>
- 2 #include <stdlib.h>
- 3 #include <string.h>
- 4 #include "xil_types.h"
- 5 #include "xil_cache.h"
- 6 #include "xparameters.h"
- 7 #include "xaxivdma.h"
- 8 #include "xaxivdma_i.h"
- 9 #include "display_ctrl_hdmi/display_ctrl.h"
- 10 #include "vdma_api/vdma_api.h"
- 11 #include "ff.h"
- 12
- 13 //宏定義
- 14 #define BYTES_PIXEL 3 //像素位元組數,RGB888占3個位元組
- 15 #define DYNCLK_BASEADDR XPAR_AXI_DYNCLK_0_BASEADDR //動态時鐘基位址
- 16 #define VDMA_ID XPAR_AXIVDMA_0_DEVICE_ID //VDMA器件ID
- 17 #define DISP_VTC_ID XPAR_VTC_0_DEVICE_ID //VTC器件ID
- 18
- 19 //函數聲明
- 20 void load_sd_bmp(u8 *frame);
- 21
- 22 //全局變量
- 23 XAxiVdma vdma;
- 24 DisplayCtrl dispCtrl;
- 25 VideoMode vd_mode;
- 26 //frame buffer的起始位址
- 27 unsigned int const frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x1000000);
- 28 unsigned int lcd_id=0; //LCD ID
- 29
- 30 int main(void)
- 31 {
- 32 xil_printf("HDMI Display 1920*1080 rn");
- 33
- 34 //設定video參數,分辨率:1920*1080
- 35 vd_mode = VMODE_1920x1080;
- 36
- 37 //配置VDMA
- 38 run_vdma_frame_buffer(&vdma, VDMA_ID, vd_mode.width, vd_mode.height,
- 39 frame_buffer_addr,0, 0,ONLY_READ);
- 40
- 41 //初始化Display controller
- 42 DisplayInitialize(&dispCtrl, DISP_VTC_ID, DYNCLK_BASEADDR);
- 43 //設定VideoMode
- 44 DisplaySetMode(&dispCtrl, &vd_mode);
- 45 DisplayStart(&dispCtrl);
- 46
- 47 //讀取SD卡圖檔并顯示
- 48 load_sd_bmp((u8*)frame_buffer_addr);
- 49
- 50 return 0;
- 51 }
- 52
- 53 //從SD卡中讀取BMP圖檔
- 54 void load_sd_bmp(u8 *frame)
- 55 {
- 56 static FATFS fatfs;
- 57 FIL fil;
- 58 u8 bmp_head[54];
- 59 UINT *bmp_width,*bmp_height,*bmp_size;
- 60 UINT br;
- 61 int i;
- 62
- 63 //挂載檔案系統
- 64 f_mount(&fatfs,"",1);
- 65
- 66 //打開檔案
- 67 f_open(&fil,"fengjing.bmp",FA_READ);
- 68
- 69 //移動檔案讀寫指針到檔案開頭
- 70 f_lseek(&fil,0);
- 71
- 72 //讀取BMP檔案頭
- 73 f_read(&fil,bmp_head,54,&br);
- 74 xil_printf("fengjing.bmp head: nr");
- 75 for(i=0;i<54;i++)
- 76 xil_printf(" %x",bmp_head);
- 77
- 78 //列印BMP圖檔分辨率和大小
- 79 bmp_width = (UINT *)(bmp_head + 0x12);
- 80 bmp_height = (UINT *)(bmp_head + 0x16);
- 81 bmp_size = (UINT *)(bmp_head + 0x22);
- 82 xil_printf("n width = %d, height = %d, size = %d bytes nr",
- 83 *bmp_width,*bmp_height,*bmp_size);
- 84
- 85 //讀出圖檔,寫入DDR
- 86 for(i=*bmp_height-1;i>=0;i--){
- 87 f_read(&fil,frame+i*(*bmp_width)*3,(*bmp_width)*3,&br);
- 88 }
- 89
- 90 //關閉檔案
- 91 f_close(&fil);
- 92
- 93 Xil_DCacheFlush(); //重新整理Cache,資料更新至DDR3中
- 94 xil_printf("show bmpnr");
- 95 }
可以看出,本次實驗的程式與“SD卡讀BMP圖檔LCD顯示實驗”非常相似,隻是删除了讀取LCD ID相關的内容。有關這部分代碼的詳細介紹請大家參考“SD卡讀BMP圖檔LCD顯示實驗”,此處不再贅述。需要注意的是,本次實驗在SD卡中放置的圖檔分辨率為1920*1080,是以在程式的第35行,視訊參數設定成VMODE_1920x1080。
20.5下載下傳驗證
首先我們将下載下傳器與領航者底闆上的JTAG接口連接配接,下載下傳器另外一端與電腦連接配接。然後使用Mini USB連接配接線将開發闆左側的USB_UART接口與電腦連接配接,用于序列槽通信。
我們在工程目錄下建立了一個名為“風景圖檔”的檔案夾,把其中名為“fengjing.bmp”的圖檔拷貝到SD卡的根目錄下,然後将SD卡插入領航者底闆背面的卡槽中。另外還需要使用HDMI連接配接線将HDMI顯示器連接配接到領航者底闆上的HDMI接口。最後連接配接開發闆的電源,并打開電源開關。
在SDK軟體下方的SDK Terminal視窗中點選右上角的加号來設定并連接配接序列槽。然後下載下傳本次實驗硬體設計過程中所生成的BIT檔案,來對PL進行配置。最後下載下傳軟體程式,下載下傳完成後,在下方的SDK Terminal中可以看到應用程式列印的資訊,如下圖所示:
圖 20.5.1 序列槽列印資訊
圖 20.5.1中列印出了BMP檔案的檔案頭和資訊頭等資訊,同時從資料中計算出BMP圖檔的寬度為1920,高度為1080,與我們存入SD卡中的BMP圖檔一緻。
同時HDMI顯示器上顯示存入SD卡中的示例圖檔,如圖 20.5.2所示,說明本次實驗在領航者ZYNQ開發闆上面下載下傳驗證成功。
圖 20.5.2 下載下傳驗證