【小梅哥FPGA進階教程】第十四章 TFT屏顯示圖片


十四、TFT屏顯示圖片

本文由杭電網友曾凱峰貢獻,特此感謝

學習了小梅哥的TFT顯示屏驅動設計后,想着在此基礎上通過TFT屏顯示一張圖片,有了這個想法就開始動工了。首先想到是利用FPGA內部ROM存儲圖片數據,然后通過控制讀取數據地址將圖片數據傳給TFT驅動模塊,從而將每個圖片數據顯示在對應的像素點上。整個設計的框圖如下:

圖片1

主要是在小梅哥TFT驅動設計基礎上增加了圖片數據發送控制模塊Imgdata_send,該模塊包括存儲圖片數據的rom,和一些簡單的邏輯控制。具體的rom IP核的建立我這里就不說了,不懂的可以參看小梅哥的相關內容的視頻,我這里主要講如何將圖片轉換成mif文件。這里有兩種方法,可以作為參考,主要用到如下軟件:

圖片2

步驟1:利用Img2Lcd將圖片轉化為BMP格式的(當然圖片本身為BMP格式就不需要轉了,直接進入步驟2);

步驟2:利用BMP2Mif可將圖片轉化為mif文件。

具體實現如下:

步驟1:先打開Img2Lcd打開一張圖片,選擇輸出格式為BMP格式,輸出灰度選擇24位真彩色(由於BMP2Mif軟件只能載入24位或8位的,所以這里就沒有直接選16位的真彩色),最大寬度和高度根據圖片實際的大小進行選擇的,由於內部rom能存儲的數據量有限,我選擇了一張像素為160*120的圖片如果想顯示大的圖片,如480*272圖片,用這種方法就不能實現(看到這里有人想,如果想顯示大點的圖片那應該怎么解決,后面我會有其他方法來實現TFT屏保顯示)。

圖片3

步驟2:打開BMP2Mif軟件,加載剛轉換輸出的24位BMP格式圖片,選擇輸出圖像格式和文件類型,點擊一鍵轉換便將圖片轉換為了mif文件了,可以將mif文件名更改下以區別不同圖片mif文件。

圖片4

可以用Notepad++將轉化的mif文件打開看看,截取部分圖如下:

圖片5

rom IP核設置完成后就是數據發送控制模塊Imgdata_send中控制邏輯的編寫,主要是讓圖片顯示在屏幕指定的地方,這就需要根據TFT_CTRL模塊的TFT行和場掃描計數器輸出信號來控制rom的數據地址,從而控制TFT_CTRL的待顯示數據data_in。具體代碼如下:

1   module Imgdata_send(
2       clk50M,
3       rst_n,
4       tft_de,
5       hcount,
6       vcount,
7       data_in
8   );
9 
10      input clk50M;           //系統時鍾,默認50M
11      input rst_n;            //復位信號,低電平有效
12      input tft_de;           //TFT數據使能
13      input [9:0]hcount;     //TFT行掃描計數器
14      input [9:0]vcount;     //TFT場掃描計數器
15      output [15:0]data_in; //待顯示圖片數據
16      
17      wire img_ack;              //圖片數據使能
18      
19      localparam IMG_H = 160,  //圖片行像素點個數
20                   IMG_V = 120;  //圖片場像素點個數
21                    
22      localparam TFT_H = 480,  //TFT屏行像素點個數
23                   TFT_V = 272;  //TFT屏場像素點個數
24                    
25      localparam IMG_HM = TFT_H - IMG_H,  //圖片行方向可移動像素點個數
26                 IMG_VM = TFT_V - IMG_V;    //圖片場方向可移動像素點個數
27                    
28      reg [9:0]img_hbegin = 0;   //圖片左上角第一個像素點在TFT屏的行向坐標
29      reg [9:0]img_vbegin = 0;   //圖片左上角第一個像素點在TFT屏的場向坐標
30      
31      reg [14:0]addr;             //讀圖片數據rom地址                  
32      wire [15:0]img_data;       //讀出圖片數據
33      
34      rom u4_rom(
35          .address(addr),
36          .clock(clk50M),
37          .q(img_data)
38      );
39      
40      assign img_ack = tft_de && (hcount >= img_hbegin && hcount < img_hbegin + IMG_H) &&
41                            (vcount >= img_vbegin && vcount < img_vbegin + IMG_V)?1'b1:1'b0;
42      
43      always@(posedge clk50M or negedge rst_n)
44      begin
45          if(!rst_n)
46              addr <= 15'd0;
47          else if(img_ack)
48              addr <= (hcount - img_hbegin) + (vcount - img_vbegin)*IMG_H;
49          else
50              addr <= 15'd0;  
51      end
52      
53      assign data_in = img_ack ? img_data : 16'h0;
54      
55  endmodule 

接下來就是仿真驗證,利用已有的TFT_CTRL模塊的hcount、vcount、tft_de作為Imgdata_send模塊的輸出進行仿真驗證,代碼如下:

1   `timescale 1ns/1ns
2   `define PERIOD_CLK 20
3 
4   module Imgdata_send_tb;
5 
6       reg clk50M;
7       reg rst_n;
8       wire tft_de;
9       wire [9:0]hcount;
10      wire [9:0]vcount;
11      wire [15:0]data_in;
12      
13      wire clk9M;
14
15      Imgdata_send u0_Imgdata_send(
16          .clk50M(clk50M),
17          .rst_n(rst_n),
18          .tft_de(tft_de),
19          .hcount(hcount),
20          .vcount(vcount),
21          .data_in(data_in)
22      );
23      
24      pll u1_pll(
25          .areset(!rst_n),
26          .inclk0(clk50M),
27          .c0(clk9M)
28      );
29      
30      TFT_CTRL u2_TFT_CTRL(
31          .clk9M(clk9M),
32          .rst_n(rst_n),
33          .data_in(),
34          .hcount(hcount),
35          .vcount(vcount),
36          .tft_rgb(),
37          .tft_hs(),
38          .tft_vs(),
39          .tft_clk(),
40          .tft_de(tft_de),
41          .tft_pwm()
42      );
43      
44      initial clk50M = 1'b1;
45      always #(`PERIOD_CLK/2) clk50M = ~clk50M;
46      
47      initial 
48      begin
49          rst_n = 1'b0;
50          #(`PERIOD_CLK*200+1)
51          rst_n = 1'b1;   
52      end
53
54  endmodule 

仿真驗證的波形圖如下:

圖片8圖片9

從仿真結果可以看出,圖片數據是在我們指定的區域輸出的。該模塊仿真驗證正確后,進行頂層電路文件的設計。頂層文件編寫如下:

1   module rom_tft_img(
2 
3       clk50M,
4       rst_n,  
5       
6       tft_rgb,
7       tft_hs,
8       tft_vs,
9       tft_clk,
10      tft_de,
11      tft_pwm
12  );
13
14      input clk50M;
15      input rst_n;    
16      
17      output [15:0]tft_rgb;
18      output tft_hs;
19      output tft_vs;
20      output tft_clk;
21      output tft_de;
22      output tft_pwm;
23      
24      wire [15:0]data_in;
25      wire [9:0]hcount;
26      wire [9:0]vcount;
27      wire clk9M;
28      
29      Imgdata_send u0_Imgdata_send(
30          .clk50M(clk50M),
31          .rst_n(rst_n),
32          .tft_de(tft_de),
33          .hcount(hcount),
34          .vcount(vcount),
35          .data_in(data_in)
36      );
37      
38      pll u1_pll(
39          .areset(!rst_n),
40          .inclk0(clk50M),
41          .c0(clk9M)
42      );
43      
44      TFT_CTRL u2_TFT_CTRL(
45          .clk9M(clk9M),
46          .rst_n(rst_n),
47          .data_in(data_in),
48          .hcount(hcount),
49          .vcount(vcount),
50          .tft_rgb(tft_rgb),
51          .tft_hs(tft_hs),
52          .tft_vs(tft_vs),
53          .tft_clk(tft_clk),
54          .tft_de(tft_de),
55          .tft_pwm(tft_pwm)
56      );
57
58  endmodule 

生成的頂層電路圖如下:

圖片11

接下來就是仿真驗證,仿真驗證程序如下:

1   `timescale 1ns/1ps
2   `define PERIOD_CLK 20
3 
4   module rom_tft_img_tb;
5       //模塊輸入端口
6       reg clk50M;
7       reg rst_n;
8       
9       //模塊輸出端口
10      wire [15:0]tft_rgb;
11      wire tft_hs;
12      wire tft_vs;
13      wire tft_clk;
14      wire tft_de;
15      wire tft_pwm;
16      
17      reg [7:0]v_cnt = 0; //掃描幀數統計計數器
18
19      rom_tft_img rom_tft_img( 
20
21          .clk50M(clk50M),
22          .rst_n(rst_n),  
23          
24          .tft_rgb(tft_rgb),
25          .tft_hs(tft_hs),
26          .tft_vs(tft_vs),
27          .tft_clk(tft_clk),
28          .tft_de(tft_de),
29          .tft_pwm(tft_pwm)
30      );
31      
32      initial clk50M = 1'b1;
33      always #(`PERIOD_CLK/2) clk50M = ~clk50M;
34      
35      initial
36      begin
37          rst_n = 1'b0;
38          #(`PERIOD_CLK*200 + 1);
39          rst_n = 1'b1;
40      end
41      
42      initial 
43      begin
44          wait(v_cnt == 3);  //等待掃描2幀后結束仿真
45          $stop;
46      end
47      
48      always@(posedge tft_vs)   //統計總掃描幀數
49          v_cnt = v_cnt + 1'b1;
50
51  endmodule 

仿真波形如下:

圖片13圖片14

從波形可以看出,圖片數據在指定區域顯示。接下來就是板級驗證,引腳分配參照芯航線FPGA學習套件引腳分配表進行分配,然后布局布線,板級程序下載最后實現的效果圖如下:

圖片15

我們設置的是顯示在屏幕的左上角,與預期效果是一致的,想要改變圖片的位置,可以更改Imgdata_send模塊的28、29行代碼:

28      reg [9:0]img_hbegin = 0;   //圖片左上角第一個像素點在TFT屏的行向坐標
29      reg [9:0]img_vbegin = 0;   //圖片左上角第一個像素點在TFT屏的場向坐標

將上面的(0、0)更改為其他的數,圖片位置就會改變,如果想讓圖片在屏幕上自動的移動,可以自己設置一種路徑讓img_hbegin、img_vbegin的值按你的路徑變化就可實現圖片的自動移動,讀者可以自己改進學習。

如有更多問題,歡迎加入芯航線 FPGA 技術支持群交流學習:472607506

小梅哥

芯航線電子工作室

關於學習資料,小梅哥系列所有能夠開放的資料和更新(包括視頻教程,程序代碼,教程文檔,工具軟件,開發板資料)都會發布在我的雲分享。(記得訂閱)鏈接:http://yun.baidu.com/share/home?uk=402885837&view=share#category/type=0

贈送芯航線AC6102型開發板配套資料預覽版下載鏈接:鏈接:http://pan.baidu.com/s/1slW2Ojj 密碼:9fn3

贈送SOPC公開課鏈接和FPGA進階視頻教程。鏈接:http://pan.baidu.com/s/1bEzaFW 密碼:rsyh


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM