LoginSignup
10
8

More than 5 years have passed since last update.

秋月のTFT液晶モジュールで画像を表示してみた

Last updated at Posted at 2016-06-11

秋月のTFT液晶モジュールで画像を簡単に表示出来たので記事を書いてみました。
今回はとりあえず画像を表示してみたかったので、出来るだけ簡単に妥協して作成しました。まず妥協点1は、TFT液晶のRGBデータがそれぞれ8bit分の配線が大変なのでTFT液晶のRGBのそれぞれ上位4bitと接続しました(表示出来ればあとからbit拡張すれば8bit出力も出来る)。妥協点2は、TFT液晶は画素数480x272であるがメモリブロック1つでは収まらないので240x136を拡大して出力する(dramかメモリブロックを4つにすれば改善可能だと思います)。

構成
20160602222332.png

ZYBOのClock Sourcesである125MHzからIP CatalogのClocking Wizardを用いて9MHzを生成します(dclkでありこれよりhsync,vsync生成)。IP CatalogのBlock Memory Generatorを用いて12bitの240x136wordsのブロックRAMを生成し、Memory Initializationで予め画像データを入力し、それを読み出しTFT液晶に表示しました。

TFT液晶モジュールのタイミングチャートよりdclkを用いてhsyncとvsyncを生成し、タイミングを合わせて画素データを読み出すように記述します。以下に動かした時のコードを載せます(動作は確認しましたがタイミングの正確性は保証しません)。

module display_test(
    input        reset,
    input        clk,
    output [3:0] r,
    output [3:0] g,
    output [3:0] b,
    output reg hsync,
    output reg vsync,
    output wire dclk
    );

    //125MHz to 9MHz
    clk_wiz_0 clk_wiz_0_inst(
       .clk_in1(clk),
       .clk_out1(dclk),
       .reset(1'b0)
    );

    //block RAM 240 x 136
    blk_mem_gen_0 blk_mem_gen_0_inst(
      .clka(dclk),    // input wire clka
      .wea(1'b0),      // input wire [0 : 0] wea
      .addra(16'h0),  // input wire [15 : 0] addra
      .dina(12'h0),    // input wire [11 : 0] dina
      .clkb(dclk),    // input wire clkb
      .enb(1'b1),      // input wire enb
      .addrb(addrb),  // input wire [15 : 0] addrb
      .doutb({r,g,b})  // output wire [11 : 0] doutb
    );

    //display parameter
    parameter H_PERIOD = 531;
    parameter H_BPORCH = 43;
    parameter V_PERIOD = 288;
    parameter V_BPORCH = 12;

    reg  [9:0]  hcnt;
    reg  [9:0]  pcnt;
    wire [15:0] addrb;
    wire [9:0] p_addr;
    wire [9:0] h_addr;

    always @(posedge dclk) begin
        if(pcnt == (H_PERIOD-1)) begin
            pcnt <= 0;
        end else begin
            pcnt <= pcnt + 1;
        end
    end

    always @(posedge dclk) begin
        if(pcnt < (H_BPORCH-1))begin
            hsync <= 0;        
        end else begin
            hsync <= 1;
        end
    end

    always @(posedge hsync) begin
        if((V_PERIOD-1) == hcnt) begin
            hcnt <= 0;            
        end else begin
            hcnt <= hcnt + 1;
        end
    end

    always @(posedge dclk) begin
        if((V_BPORCH-1) < hcnt) begin
            vsync <= 1;
        end else begin
            vsync <= 0;
        end
    end

    assign p_addr = (hsync == 1 && vsync == 1) ? pcnt - 43 : 10'h0;
    assign h_addr = (hsync == 1 && vsync == 1) ? hcnt - 12 : 10'h0;
    assign addrb  = (hsync == 1 && vsync == 1) ? p_addr[9:1] + h_addr[9:1] * 240 : 12'h0;

endmodule

ハード関連はこれで終了です。書いたコードもこれくらいなので簡単だと思います。
次にMemory Initializationのデータ生成について書きます。入力画像は240x136を用います。Visual Studio2013でOpenCV(2.4.10)を用いてjpgやpng画像からrawデータ(RGBを4bit化)を取り出しかつMemory Initializationのフォーマットに合わせてテキストを出力するコードを記述します。以下にコードを載せます(私の環境では上手く行きましたが動作保証出来ません)。

#include <opencv2/nonfree/nonfree.hpp>
#include <opencv/highgui.h>
void main()
{

    FILE *outputfile;         
    outputfile = fopen("d.txt", "w");  
    if (outputfile == NULL) {         
        printf("cannot open\n");         
        exit(1);                         
    }

    // 画像の読み込み
    cv::Mat srcImg = cv::imread("yamada.jpg");

    for (int y = 0; y < srcImg.rows; y++) {
        cv::Vec3b* ptr = srcImg.ptr(y);
        for (int x = 0; x < srcImg.cols; x++) {
            cv::Vec3b bgr = ptr[x];
            fprintf(outputfile, "%x%x%x,\n", bgr[2] >> 4, bgr[1] >> 4, bgr[0] >> 4); 
        }
    }
    fclose(outputfile);
}

プロジェクトの作り方は、説明していませんが上2つのコードでこんな感じで画像が出ました。
っねすごく簡単でしょ!?
DSC_0532.JPG
画像の通り今はジャンパ線で接続しているので、今度は基板にして遊びやすくしたいです。

参考URL
Memory Initializationのcoeフォーマット
Opencv 画素抽出
C言語ファイル出力

10
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8