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

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

- 使用した環境
 - Vivado 2015.4
 - Visual Studio 2013

- 使用したもの
 - [ＴＦＴ液晶モジュールＡＴＭ０４３０Ｄ２５](http://akizukidenshi.com/catalog/g/gP-09250/)
 - [ＺＹＢＯ　Ｚｙｎｑ－７０００　評価ボード](http://akizukidenshi.com/catalog/g/gM-07740/)
 - [フレキコネクタＤＩＰ化基板](http://akizukidenshi.com/catalog/g/gP-10187/)

構成
![20160602222332.png](https://qiita-image-store.s3.amazonaws.com/0/97833/a846fe98-f901-2ede-a6cb-755da256cd0b.png)

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

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

```verilog
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のフォーマットに合わせてテキストを出力するコードを記述します。以下にコードを載せます(私の環境では上手く行きましたが動作保証出来ません)。

```cpp
#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);
}
```

プロジェクトの作り方は、説明していませんが上２つのコードでこんな感じで画像が出ました。
っねすごく簡単でしょ！？
![DSC_0532.JPG](https://qiita-image-store.s3.amazonaws.com/0/97833/4884e574-5d18-0c56-1e78-5736c2777155.jpeg)
画像の通り今はジャンパ線で接続しているので、今度は基板にして遊びやすくしたいです。

参考URL
Memory Initializationの[coeフォーマット](http://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx11/cgn_r_coe_file_syntax.htm)
[Opencv 画素抽出](http://d.akiroom.com/2012-06/opencv-pixel-read-write-get-set/)
[C言語ファイル出力](http://ylb.jp/2006b/proc/fileio/fileoutput.html)