本文為明德揚原創文章,轉載請注明出處!
1.1 總體設計
1.1.1 概述
液晶顯示器是一-種通過液晶和色彩過濾器過濾光源,在平面面板上產生圖像的數字顯示器。LCD 的構造是在兩片平行的玻璃基板當中放置液晶盒,下基板玻璃上設置薄膜晶體管,.上基板玻璃上設置彩色濾光片,通過薄膜晶體管上的信號與電壓改變來控制液晶分子的轉動方向,從而達到控制每個像素點偏振光出射與否而達到顯示目的。與傳統的陰極射線管相比,LCD具有占用空間小,低功耗,低輻射,無閃爍,降低視覺疲勞等優點。現在LCD已漸替代CRT成為主流,價格也已經下降了很多,并已充分的普及。1.1.2 設計目標在7寸LCD顯示屏上實現圖片顯示。其中,在顯示屏左上角顯示明德揚的LOGO圖標,在顯示屏的中間居中顯示字母“E”。1.1.3 系統結構框圖
系統結構框圖如下所示:
圖一1.1.4模塊功能
PLL模塊實現功能1. 將輸入的50MHz時鐘分頻輸出40MHz時鐘。
ROM模塊實現功能
2. e_rom存儲字母“E”的圖像數據。
LCD驅動模塊實現功能1、 產生驅動LCD屏顯示的時序2、 讀取ROM里存儲的數據并輸出顯示
1.1.5頂層信號
1.1.6參考代碼
- module top_mdyLcdPicOverlay(
- clk ,
- rst_n ,
- hys ,
- vys ,
- lcd_de ,
- lcd_rgb ,
- lcd_dclk
- );
-
- parameter PICTURE_W = 24 ;
-
- input clk ;
- input rst_n ;
- output hys ;
- output vys ;
- output lcd_de ;
- output [PICTURE_W-1:0] lcd_rgb ;
- output lcd_dclk ;
-
- wire clk_0 ;
- wire hys ;
- wire vys ;
- wire lcd_de ;
- wire [PICTURE_W-1:0] lcd_rgb ;
- wire lcd_dclk ;
-
-
- //40MHz
- pll_40m u_pll_40m(
- .areset (~rst_n ),
- .inclk0 (clk ),
- .c0 (clk_0 )
- );
-
-
- lcd_driver u2(
- .clk (clk_0 ),//40MHz
- .rst_n (rst_n ),
- .hys (hys ),
- .vys (vys ),
- .lcd_de (lcd_de ),
- .lcd_rgb (lcd_rgb ),
- .lcd_dclk (lcd_dclk )
- );
-
- endmodule
復制代碼
1.2 PLL模塊設計
1.2.1接口信號下面為PLL的接口信號:
1.2.2 設計思路本模塊主要用于產生LCD驅動時序所需要的時鐘,關于PLL的使用詳細介紹請看下方鏈接:
1.3 ROM模塊設計
1.3.1接口信號
1.3.2設計思路本模塊主要用于存儲需要顯示的圖像數據,關于ROM的使用詳細介紹請查看IP核右上角數據手冊“Documentation”。1.4 LCD驅動模塊設計
1.4.1接口信號
1.4.2設計思路產生驅動LCD顯示的行場時序信號,其計數器架構如下圖所示:
行計數器h_cnt:該計數器用來計算行同步信號的幀長。加一條件為1,表示一直在計數。結束條件為數1056個,也就是一行有1056個像素。場計數器v_cnt:該計數器用來計算場同步信號的幀長。加一條件為end_h_cnt,即行計數器的計數器的結束條件,表示每計數完一行像素就加一。結束條件為數525個,也就是一共有525行像素。其中,在從存儲圖像“E”的ROM里讀取數據的時候,有一個操作就是讀取的地址從第8位開始,也就是說18位數據地址,低三位不讀,讀取的是e_rom_addr[16:3]。有這樣一個操作的話就能實現對存儲的圖像進行8倍的放大顯示。
1.4.3參考代碼
- module lcd_driver(
- clk ,//40MHz
- rst_n ,
-
- hys ,
- vys ,
- lcd_de ,
- lcd_rgb ,
- lcd_dclk
- );
-
- input clk ;
- input rst_n ;
-
- output hys ;
- output vys ;
- output lcd_de ;
- output [23:0] lcd_rgb ;
- output lcd_dclk ;
-
- reg hys ;
- reg vys ;
- reg lcd_de ;
- reg [23:0] lcd_rgb ;
- wire lcd_dclk ;
-
- //1056
- parameter THPW = 20 ;
- parameter THB = 46 ;
- parameter THD = 800 ;
- parameter THFP = 210 ;
- //525
- parameter TVPW = 10 ;
- parameter TVB = 23 ;
- parameter TVD = 480 ;
- parameter TVFP = 22 ;
-
- parameter HDE_CENTRE = THD/2 ;//400
- parameter VDE_CENTRE = TVD/2 ;//240
-
- parameter LOGO_X0 = (0 + (THB-1)) ;
- parameter LOGO_X1 = (120 + (THB-1)) ;
- parameter LOGO_Y0 = (0 + (TVB-1)) ;
- parameter LOGO_Y1 = (55 + (TVB-1)) ;
-
- parameter E_X0 = ((HDE_CENTRE-200) + (THB-1)) ;
- parameter E_X1 = ((HDE_CENTRE+200) + (THB-1)) ;
- parameter E_Y0 = ((VDE_CENTRE-150) + (TVB-1)) ;
- parameter E_Y1 = ((VDE_CENTRE+150) + (TVB-1)) ;
-
- reg [ 10:0] h_cnt ;
- wire add_h_cnt ;
- wire end_h_cnt ;
- reg [ 9:0] v_cnt ;
- wire add_v_cnt ;
- wire end_v_cnt ;
-
-
- wire active_area ;
- reg logo_rom_area ;
- reg [15:0] logo_rom_addr ;
- wire [7:0] logo_rom_data ;
- reg e_rom_area ;
- reg [17:0] e_rom_addr ;
- wire [7:0] e_rom_data ;
- reg [2:0] e_rom_addr_low ;
- reg e_sel ;
-
-
- always @(posedge clk or negedge rst_n) begin
- if (rst_n==0) begin
- h_cnt <= 0;
- end
- else if(add_h_cnt) begin
- if(end_h_cnt)
- h_cnt <= 0;
- else
- h_cnt <= h_cnt+1 ;
- end
- end
- assign add_h_cnt = 1;
- assign end_h_cnt = add_h_cnt && h_cnt == (THB + THD + THFP)-1 ;
-
-
-
- always @(posedge clk or negedge rst_n) begin
- if (rst_n==0) begin
- v_cnt <= 0;
- end
- else if(add_v_cnt) begin
- if(end_v_cnt)
- v_cnt <= 0;
- else
- v_cnt <= v_cnt+1 ;
- end
- end
- assign add_v_cnt = end_h_cnt;
- assign end_v_cnt = add_v_cnt && v_cnt == (TVB + TVD + TVFP)-1 ;
-
- /*******************************************************/
- //dclk
- assign lcd_dclk = clk;
-
- //hsync
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- hys <= 0;
- end
- else if(add_h_cnt && h_cnt==THPW-1)begin
- hys <= 1;
- end
- else if(end_h_cnt)begin
- hys <= 0;
- end
- end
-
-
- //vsync
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- vys <= 0;
- end
- else if(add_v_cnt && v_cnt==TVPW-1)begin
- vys <= 1;
- end
- else if(end_v_cnt)begin
- vys <= 0;
- end
- end
-
- //lcd_de
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- lcd_de <= 0;
- end
- else if(active_area)begin
- lcd_de <= 1;
- end
- else begin
- lcd_de <= 0;
- end
- end
-
- /********************************************************************/
-
-
-
- assign active_area = h_cnt>=(THB-1) && h_cnt<(THB+THD-1) && v_cnt>=(TVB-1) && v_cnt<(TVB+TVD-1);
-
-
- always @(*)begin
- logo_rom_area = h_cnt >=LOGO_X0 && h_cnt < LOGO_X1 && v_cnt >= LOGO_Y0 && v_cnt < LOGO_Y1;
- end
-
- always @(*)begin
- e_rom_area = h_cnt >=E_X0 && h_cnt < E_X1 && v_cnt >= E_Y0 && v_cnt < E_Y1;
- end
-
-
-
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- lcd_rgb <= 0;
- end
- else if(active_area)begin
- if(logo_rom_area)
- lcd_rgb <= {logo_rom_data[7:5],5'b11111,logo_rom_data[4:2],5'b11111,logo_rom_data[1:0],6'b111111};
- else if(e_rom_area)
- lcd_rgb <= {24{e_sel}};
- else
- lcd_rgb <= {24{1'b1}};
- end
- else begin
- lcd_rgb <=0;
- end
- end
-
-
-
-
- always @(*)begin
- logo_rom_addr = (h_cnt-LOGO_X0) + 120*(v_cnt-LOGO_Y0);
- end
-
- always @(*)begin
- e_rom_addr = (h_cnt-E_X0) + 400*(v_cnt-E_Y0);
- end
-
-
-
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- e_rom_addr_low <= 0;
- end
- else begin
- e_rom_addr_low <= e_rom_addr[2:0];
- end
- end
-
-
- always @(*)begin
- e_sel = ~e_rom_data[7-e_rom_addr_low];
- end
-
-
- fpga_rom u_fpga_rom(
- .address (logo_rom_addr),
- .clock (clk ),
- .q (logo_rom_data));
-
- e_rom u_e_rom(
- .address (e_rom_addr[16:3] ),
- .clock (clk ),
- .q (e_rom_data ));
-
-
- endmodule
復制代碼
1.5 效果和總結以下為工程上板后的現象效果圖:mp801開發板
ms980試驗箱
設計視頻和源工程代碼請到論壇下載學習:http://www.fpgabbs.cn/thread-1162-1-1.html
訪問明德揚論壇(http://www.fpgabbs.cn/)進行更多FPGA相關工程設計學習。