読者です 読者をやめる 読者になる 読者になる

ZY-FGD1442701V1, ST7735

移転しました。

aitendoの液晶モジュールを買いました。
http://www.aitendo.co.jp/product/1621
http://www.aitendo.co.jp/product/1707(基盤実装済み)
データシート&サンプルプログラムが上記リンクからダウンロードできます!


128*128dots 1.44inch(~3x3cm)
色数 65k色 (RGB 5,6,5bits)
携帯電話用


LCDコントローラはST7735。
SPI制御も出来るコントローラだが、シリ/パラ切り替えのピンが外に出てないので、パラレル制御(8bit)をするしかない。高速書き換えの為にはこちらの方が有利ですし、シリアル転送したいなら74HC164を使えばいいでしょう。
このコントローラに表示用バッファRAMが入っており、液晶に絵を表示するにはRAMへデータを書き込むだけでよい。表示のリフレッシュなどはコントローラがやってくれる。そのため秋月300円液晶のように、"クロックを送り続けないと液晶が死ぬ"ということはない。


単電源3.0Vでよくて、制御しやすいコントローラ付きで、仕様が分かっていて(重要)、0.8mmという接続しやすいインタフェースで、900円(現在)というのはなかなかお買い得だと思います。128x128というサイズは小さいですが、趣味で使うにはお手頃でいいと思います(サイズが大きすぎるとメモリが足りなくなる関係で)。

ピン
pin (W-)FGD1442701V1 ST7735
9 RSTB RESX リセット
5 CS0 CSX チップ選択。low enable。(以下のピンの入力を受け付けるか否か)
6 CD D/CX データ表示/コマンド-選択
7 RD RDX 読み込み有効。使わない場合はVDDIかDGNDに固定
8 WR WRX ライト有効
24,22,20,18,16,14,12,10 D[8:0] D[8:0] データ

(P.12)


インタフェスピン電圧は3.3V max. 4.6Vが絶対定格。バックライト用LEDがあるのでmin電圧が3.0Vとして、実質3.0-3.3Vの間で選択することになる。
チップの消費電流は1mA以下。バックライトLEDと比べたら無視できる量か。
(P.18,20)

タイミング。

基本は、DCX 1/0 -> CSX 0 -> WRX 0 -> D[7:0] -> WRX 1-> CSX 1。
すなわち、

  • DCXでデータ1かコマンド0かを選ぶ。チップ選択CSXを有効0(low enable)にする。
  • WRX 0にし、D[7:0]に書き込み準備をする。WRX 1で書き込みをかける(立ち上がりで読まれる)。
  • CSXを1にして終了。

CSXはenable(0)にしっぱなしでもDCXの切り替えは有効であるので、継続してデータを送るときはenableのままでいい。
書き込みに限れば、各ピン切り替えには50ns以上かければ、タイミング特性を満たすか。5*10^-8sec = 20MHz。10MHz駆動のAVRだとwaitなしでいけそう。それでも書き換えレートはまともな値となりそう。(~10MHz/(128bits*128bits*100clock)=10Hz)。
(P.21)

色データの送り方。

Rnをnピクセル目のR(赤)データとする。これは仕様書P37,38のチャートを見ていただいた方がわかりやすそうな。

  • 12bit,RGB 4-4-4bit, 3AH="03h":

command"2C" -> data"R1[3:0]G1[3:0]" -> data"B1[3:0]R2[3:0]" -> data"G2[3:0]B2[3:0]" ->...

  • 16bit,RGB 5-6-5bit, 3AH="05h":

command"2C" -> data"R1[4:0]G1[5:3]" -> data"G1[2:0]B1[4:0]" -> data"R2[4:0]G2[5:3]" ->...

(P37,38)

リセット

RESX を10us以上0(low enable)にし、1に戻す。120ms以上待つ。
(P.71)

コマンドリスト

P76-78, 118-121

SWRESET 01h: Software reset
SLPOUT 11h: Sleep out & booster on(起動時スリープinなので、outせねばならない。)
RAMWR 2Ch: Memory write(データ書き込み)
COLMOD 3Ah: Interface pixel format(データ転送を16bitにするか12bitにするか)


実際の制御方法の理解にはaitendoさんのところで公開されているサンプルコードが役に立ちます。
http://aitendo2.sakura.ne.jp/aitendo_data/product_img2/product_img/panel/ZY-FGD1442701V1/demo/144demo.C
以下、自分が理解しやすいようこのコードに勝手にコメントをつけたものです。

#include <reg52.h>
#include <intrins.h>

#define uchar unsigned char
#define uint  unsigned int

sbit CS=P3^2;
sbit A0=P3^3;
sbit RDB=P3^4;
sbit WRB=P3^5;
sbit RES=P3^7;
sbit key=P3^0;

uchar code colorc[]=

{0xf8,0x00,0x07,0xe0,0x00,0x1f,0xff,0xe0,0x1f,0xff,0x00,0x00,0xff,0xff};

void delay20us()
{
   _nop_();_nop_();_nop_();
   _nop_();_nop_();_nop_();
   _nop_();_nop_();_nop_();
   _nop_();_nop_();_nop_();
   _nop_();_nop_();_nop_();
}

void WriteCOM(unsigned char a)
{
    CS=0;// CSX
    A0=0;// D/CX
    P1=a;// D[7:0]
    WRB=0;// WRX
    delay20us();
    WRB=1;// WRX
    CS=1;// CSX
}

void WriteDAT(unsigned char b)
{
    CS=0;
    A0=1;
    P1=b;
    WRB=0;
    delay20us();
    WRB=1;
    CS=1;
}

void delayms(uint ms)
{
   uint i;
   for(;ms!=0;ms--)
   {for(i=200;i!=0;i--);}
}

main()
{
        uchar i,j,k=0;

        //RESET
	RES=1;// RESX
        delayms(100);
	RES=0;
	delayms(100);
	RES=1;
	delayms(120);


	WriteCOM(0x01);//SOFTWARE RESET
	delayms(50);

	WriteCOM(0x11);//SLEEP OUT
	delayms(200);

	WriteCOM(0xFF);//VCOM4 level
	WriteDAT(0x40);//TC2=4, TC1=0 clock delay
	WriteDAT(0x03);//TC3=3 clock delay
	WriteDAT(0x1A);

	WriteCOM(0xd9);//EEPROM control status?
	WriteDAT(0x60);//30h?
	WriteCOM(0xc7);//Set VCOM offset control?
	WriteDAT(0x90);// vmf = vmh (same as 10h)
	delayms(200);

	WriteCOM(0xB1);//Frame Rate Control(In normal mode/ Full colors)
	//Frame rate= f_osc/((RTNA + 20)*(LINE+FPA+BPA))
	WriteDAT(0x04);//RTNA = 4h
	WriteDAT(0x25);//FPA=25h = 37
	WriteDAT(0x18);//BPA=18h = 24

	WriteCOM(0xB2);//Frame Rate Control (In Idle mode/ 8-colors)
	WriteDAT(0x04);
	WriteDAT(0x25);
	WriteDAT(0x18);

	WriteCOM(0xB3);//Frame Rate Control (In Partial mode/ full colors)
	//1st parameter to 3rd parameter are used in line inversion mode.
	WriteDAT(0x04);
	WriteDAT(0x25);
	WriteDAT(0x18);
	//4th parameter to 6th parameter are used in frame inversion mode.
	WriteDAT(0x04);
	WriteDAT(0x25);
	WriteDAT(0x18);

	WriteCOM(0xB4);//Display Inversion Control(0:line inversion, 1:frame 

inversion)
	//[3:0] in full colors normal mode, in idle mode, in full colors partial mode (Partial mode on / Idle mode off)
	WriteDAT(0x03);// 011

	WriteCOM(0xB6);//Display Function set 5
	WriteDAT(0x15);//NO=1,SDT=1,EQ=1 (default)
	WriteDAT(0x02);//PTG=0,PT=2

	WriteCOM(0xC0);// POWER CONTROL 1 GVDD&AVDD
	WriteDAT(0x02);//4.7V (default)
	WriteDAT(0x70);//1.0uA (default)

	WriteCOM(0xC1);// POWER CONTROL 2 VGHH&VCLL
	WriteDAT(0x07);// 14.7V, -12.25V

	WriteCOM(0xC2);// POWER CONTROL 3 (in Normal mode/ Full colors)
	WriteDAT(0x01);// (default)
	WriteDAT(0x01);// (default)

	WriteCOM(0xC3);// POWER CONTROL 4 (in Idle mode/ 8-colors)
	WriteDAT(0x02);// (default)
	WriteDAT(0x07);// (default)

	WriteCOM(0xC4);// POWER CONTROL 5 (in Partial mode/ full-colors)
	WriteDAT(0x02);// (default)
	WriteDAT(0x04);// (default)

	WriteCOM(0xFC);// POWER CONTROL 6 (in Partial mode + Idle mode)
	WriteDAT(0x11);// (default)
	WriteDAT(0x17);// 15h (default) -> 17h dcd

	WriteCOM(0xC5);// VCOMH&VCOML
	WriteDAT(0x3c);// 4V (default) 
	WriteDAT(0x4f);// 3a:-1.050V(default) -> 4f:-0.525V

	WriteCOM(0x36);//Memory data access control
	WriteDAT(0xC8);//MY-MX-MV-ML-RGB-MH-0-0 = 11001000 , (mirror xy, BGR)


	WriteCOM(0x3a);//Interface pixel format
	WriteDAT(0x05);//16bit mode

	//GAMMA SET BY REGISTER
	//***********************GAMMA*************************
	WriteCOM(0xE0);// + polarity
	WriteDAT(0x06);
	WriteDAT(0x0E);
	WriteDAT(0x05);
	WriteDAT(0x20);
	WriteDAT(0x27);
	WriteDAT(0x23);
	WriteDAT(0x1C);
	WriteDAT(0x21);
	WriteDAT(0x20);
	WriteDAT(0x1C);
	WriteDAT(0x26);
	WriteDAT(0x2F);
	WriteDAT(0x00);
	WriteDAT(0x03);
	WriteDAT(0x00);
	WriteDAT(0x24);

	WriteCOM(0xE1);// - polarity
	WriteDAT(0x06);
	WriteDAT(0x10);
	WriteDAT(0x05);
	WriteDAT(0x21);
	WriteDAT(0x27);
	WriteDAT(0x22);
	WriteDAT(0x1C);
	WriteDAT(0x21);
	WriteDAT(0x1F);
	WriteDAT(0x1D);
	WriteDAT(0x27);
	WriteDAT(0x2F);
	WriteDAT(0x05);
	WriteDAT(0x03);
	WriteDAT(0x00);
	WriteDAT(0x3F);

	//***************************RAM ADDRESS*******************
	WriteCOM(0x2A);//column address set
	WriteDAT(0x00);//xs = 02h = 2
	WriteDAT(0x02);
	WriteDAT(0x00);//xe = 81h = 129
	WriteDAT(0x81);

	WriteCOM(0x2B);//row address set
	WriteDAT(0x00);//ys = 03h = 3
	WriteDAT(0x03);
	WriteDAT(0x00);//ye = 82h = 130
	WriteDAT(0x82);

	WriteCOM(0x29);//display on
	delayms(100);

	WriteCOM(0x2C); //memory write
  while(1)
  {
   for (i=0;i<128;i++)
    {
    for (j=0;j<128;j++)
       {
           WriteDAT(colorc[k]);
	   WriteDAT(colorc[k+1]);  //display green
        }
     }
     delayms(2000);
     k+=2;
     if(k>14)
       k=0;
  }

}
表示テスト

試行錯誤ののち、色を表示出来るようになりました。

この砂嵐の絵は・・・っ。なんだか懐かしいです。


FT245RL + 74HC164でデータはシリアル転送しています。FT245RLが3.3Vを出力してくれるので、それでLCDのLEDもすべて駆動しています。USBバスパワーだけで駆動出来るので楽です。
が、一枚表示するのに5-10分かかるんじゃないかという速度で、どうしたものかというところです。HD74HC164はtpd(clock to Q) = 14.5ns typで、今後ネックになりそうですが、今の速度のネックではなさそう。FT245RLのbitbangモードの転送速度,スループットが問題かなあと思っています。
->いま書き込みを1バイトずつしているのですが、これをまとめたら(バッファリングしたら)数十倍に高速化出来ました。->128*128*2*27bytes=884kBをまとめて送っても初期化(~2sec)含めて24secかかります・・。データ量からするとこれが限界ぽい気が。データ量を減らさないと。シリアル転送なので1コマンド送るのに27bytes使うというのが原因。

左から、赤線の表示、ALICE・ぱれーど、カタハネ

16bitビットマップの扱いについて

絵を表示するために、gimpなどを使い16bit bitmapを作ります。コントローラが受け付けるのは、R-G-B = 5-6-5bitでGreenが一ビット多いのに対し、16bitビットマップはR,G,Bそれぞれ5bitですから、Greenの最上位ビットを0で埋めてやります。さらにbmpはリトルエンディアンなので、gggbbbbb 0rrrrrggという並びになっています(ネット上の情報では色々違いが有るようですがうちの場合はこれでした)。つまり、これをrrrrr0gg gggbbbbbrrrrrggg gg0bbbbbとして転送してやるわけです(Gの最大値が64なので、2倍してやります)。私は次のようにしているわけですが、ハッカーのなんとかという論理演算本を読むともっとトリッキーにかけると思われます。

//dat2 = ((dat2 & 0x7c) << 1) | (dat2 & 0x03);  wrong  
dat2 = (dat2 << 1) | (dat >> 7);
dat = ((dat & 0x60) << 1) | (dat & 0x1F);

なおヘッダは、パレット情報がない場合、35hまで詰まっているのでその部分はとばします。

コード

まだいろいろ書き換えていますが、現段階のコードを貼っておきます(gnu/linux+gcc)。上記のコードをそのまま移植したものです。ピン接続はdefineのところに。他のピンは、HC164-B=VCCIO,RESET=VCCIO, LCD-RDX=VCCIOです。VCCIO=3.3V。
(高速化といって書き換えたので、リセットコマンドが送れていませんが、とりあえず現段階のコードで・・。すみません)
-> LCDコントロラ初期化コマンドのところで、cで配列代入出来ないの忘れてて宣言のところで配列を初期化してひどいことに。まあ、うごくので、これでいいか・・。二枚の絵がぱたぱた入れ替わります。

完成?

表示速度が頭打ちですがこれ以上は、AVR+eeprom(2MB)とかでやるのがいいかなと思っています。

(んー?これは、、libftdi:ftdi.c
int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate);)

 ftdi_set_baudrate(ftdic, 921600);

を追記したら、1.5secでかけるようになったよー。

このあたりのことを含めあとはwikiを作ってまとめたいと思います。

#include <stdio.h>
#include <time.h> //nanosleep()
#include <unistd.h> //sleep()
#include <ftdi.h> //FTDI


#define DIN 0x01 // d0 HC164-A
#define DCLK 0x02 // d1 HC164-clock
// d2 nc 0x04
#define CSX 0x08 // d3 cs0
// d4 nc 0x10
#define RESX 0x20 // d5 lcd RESX
#define DCX 0x40 // d6 lcd DCX
#define WRX 0x80 // d7 lcd WRX

#define DATA_SIZE 128*128*2 //
#define CD_SIZE 27 //size of one command/data

int make_cd(unsigned char *stat, unsigned char dat,
                 unsigned char is_dat, unsigned char *buf);//buf > 27Bytes
int setb(unsigned char *stat, unsigned char pin, unsigned char enable);
int write_buf(struct ftdi_context *ftdic, unsigned char *buf, int size);
inline void nsleep(int nsec);
int lcd_init(struct ftdi_context *ftdic, unsigned char *stat);
struct timespec treq;

int colorc[] = {0x07,0x00,0x07,0xe0,0x00,0x1f,0xff,0xe0,0x1f,0xff,0x00,0x00,0xff,0xff};

int main(int argc, char **argv)
{
  struct ftdi_context ftdic[1];
  int f,i,j,k=0;
  int l = 0;
  FILE *fp;
  unsigned char dat, dat2;
  unsigned char stat[1]; //status buffer
  unsigned char dbuf[DATA_SIZE][CD_SIZE]; //data buffer
  unsigned char cbuf[CD_SIZE]; //one command buffer
  char* files[] = {"kat16.bmp", "img16.bmp"};

  ftdi_init(ftdic); //FTDI init
  f = ftdi_usb_open(ftdic, 0x0403, 0x6001); //FTDI open
  if(f < 0 && f != -5) { //5 is ftdi_sio error
    fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f,  ftdi_get_error_string(ftdic));
      exit(-1);
  }
  printf("ftdi open succeeded: %d\n",f);

  printf("enabling bitbang mode\n");
  ftdi_enable_bitbang(ftdic, 0xFF); //all bits are bitbang
  nsleep(200*1000*1000);


  lcd_init(ftdic, stat);//LCD init

  make_cd(stat, 0x2C, 0, cbuf); //memory write
  write_buf(ftdic, cbuf, CD_SIZE);


  while(1){
    l = 1 - l;
    if((fp = fopen(files[l], "rb")) == NULL){
    printf("file open error.\n");
    exit(EXIT_FAILURE);
  }

  for(i=0; i<0x36; i++){
    getc(fp);
  }

/*  while(1){
    for (i = 0; i < 128; i++){
      printf("i : %d\n", i);
      for (j = 0; j < 128; j++){
        write_cd(ftdic, stat, colorc[k], 1);
        write_cd(ftdic, stat, colorc[k+1], 1);
      }
    }
    nsleep(2000*1000*1000);
    k += 2;
    if(k > 14){
      k=0;
    }
  }*/
  //gggbbbbb 0rrrrrgg -> rrrrr0gg gggbbbbb?
  //rrrrrggg gg0bbbbb?

  for(i=0; i<DATA_SIZE/2; i++){
    dat = getc(fp);dat2 = getc(fp);
    //dat2 = ((dat2 & 0x7c) << 1) | (dat2 & 0x03) ;
    dat2 = (dat2 << 1) | (dat >> 7);
    dat = ((dat & 0x60) << 1) | (dat & 0x1F);
    make_cd(stat, dat2, 1, dbuf[2*i]);
    make_cd(stat, dat, 1, dbuf[2*i+1]);

  }
  write_buf(ftdic, (unsigned char*)dbuf, DATA_SIZE * CD_SIZE);
  fclose(fp);
/*  while(1){
    printf("end\n");
    sleep(60);
  }*/
  printf("end\n");
  }
  setb(stat, CSX, 1);//data pins disenable
  write_buf(ftdic, stat, 1);

  printf("disabling bitbang mode\n");
  ftdi_disable_bitbang(ftdic); //bitbang end

  ftdi_usb_close(ftdic); //close device
  ftdi_deinit(ftdic);

  return 0;
}


int make_cd(unsigned char *stat, unsigned char dat,
                 unsigned char is_dat, unsigned char *buf){ //buf > 27Bytes
  int i;

  //  setb(ftdic, stat, CSX, 0);
  setb(stat, DCX, is_dat);
  buf[0] = *stat;

  setb(stat, WRX, 0);
  buf[1] = *stat;

  //D[7:0]
  for(i=0; i<8; i++){
    setb(stat, DCLK, 0);
    buf[3*i+2] = *stat;

    setb(stat, DIN, ((dat >> (7-i)) % 2));
    buf[3*i+3] = *stat;

    setb(stat, DCLK, 1);
    buf[3*i+4] = *stat;
  }

  setb(stat, WRX, 1);
  buf[26] = *stat;
  //  setb(ftdic, stat, CSX, 1);

  return 0;
}


int setb(unsigned char *stat, unsigned char pin, unsigned char enable){
  if(enable == 1){
    *stat |= pin;
  }else{
    *stat &= ~pin;
  }

  return 0;
}


int write_buf(struct ftdi_context *ftdic, unsigned char *buf, int size){
  int f;
  f = ftdi_write_data(ftdic, buf, size);
  if(f < 0) {
      fprintf(stderr,"write failed for 0x%x, error %d (%s)\n",buf[0],f,  ftdi_get_error_string(ftdic));
      return 1;
  }

  //  nsleep(50);
  return 0;
}


inline void nsleep(int nsec){
  treq.tv_sec = (time_t)0;
  treq.tv_nsec = nsec;//200 * 1000 * 1000;//mun
  nanosleep(&treq, NULL);
}


int lcd_init(struct ftdi_context *ftdic, unsigned char *stat){

  unsigned char cbuf[27];
  unsigned char cbufs[100][27];
//  unsigned char cmd[100][2];
  int cmdsize, i;
  unsigned char vcomcmd[][2] = {
    {0xFF, 0},//VCOM4 level
    {0x40, 1},//TC2=4, TC1=0 clock delay
    {0x03, 1},//TC3=3 clock delay
    {0x1A, 1},

    {0xd9, 0},//EEPROM control status
    {0x30, 1},//30h
    {0xc7, 0},//Set VCOM offset control
    {0x10, 1},// vmf = vmh (same as 10h)
  };


  unsigned char cmd2[][2] = {
    {0xB1, 0},//Frame Rate Control(In normal mode/ Full colors)
    //Frame rate= f_osc/((RTNA + 20)*(LINE+FPA+BPA))
    {0x04, 1},//RTNA = 4h
    {0x25, 1},//FPA=25h = 37
    {0x18, 1},//BPA=18h = 24

    {0xB2, 0},//Frame Rate Control (In Idle mode/ 8-colors)
    {0x04, 1},
    {0x25, 1},
    {0x18, 1},

    {0xB3, 0},//Frame Rate Control (In Partial mode/ full colors)
    //1st parameter to 3rd parameter are used in line inversion mode.
    {0x04, 1},
    {0x25, 1},
    {0x18, 1},
    //4th parameter to 6th parameter are used in frame inversion mode.
    {0x04, 1},
    {0x25, 1},
    {0x18, 1},

    {0xB4, 0},//Display Inversion Control(0:line inversion, 1:frame inversion)
    //[3:0] in full colors normal mode, in idle mode, in full colors partial mode (Partial mode on / Idle mode off)
    {0x07, 1},// 011

    {0xB6, 0},//Display Function set 5
    {0x15, 1},//NO=1,SDT=1,EQ=1 (default)
    {0x02, 1},//PTG=0,PT=2

    {0xC0, 0},// POWER CONTROL 1 GVDD&AVDD
    {0x02, 1},//4.7V (default)
    {0x70, 1},//1.0uA (default)

    {0xC1, 0},// POWER CONTROL 2 VGHH&VCLL
    {0x07, 1},// 14.7V, -12.25V

    {0xC2, 0},// POWER CONTROL 3 (in Normal mode/ Full colors)
    {0x01, 1},// (default)
    {0x01, 1},// (default)

    {0xC3, 0},// POWER CONTROL 4 (in Idle mode/ 8-colors)
    {0x02, 1},// (default)
    {0x07, 1},// (default)

    {0xC4, 0},// POWER CONTROL 5 (in Partial mode/ full-colors)
    {0x02, 1},// (default)
    {0x04, 1},// (default)

    {0xFC, 0},// POWER CONTROL 6 (in Partial mode + Idle mode)
    {0x11, 1},// (default)
    {0x17, 1},// 15h (default) -> 17h dcd

    {0xC5, 0},// VCOMH&VCOML
    {0x3c, 1},// 4V (default) 
    {0x4f, 1},// 3a:-1.050V(default) -> 4f:-0.525V

    {0x36, 0},//Memory data access control
    {0x88, 1},//MY-MX-MV-ML-RGB-MH-0-0 = 11001000 , (mirror xy, BGR)

    {0x3a, 0},//Interface pixel format
    {0x05, 1},//16bit mode
  };

  unsigned char gamma[][2] = {// + polarity
    {0xE0, 0},
    {0x06, 1},
    {0x0E, 1},
    {0x05, 1},
    {0x20, 1},
    {0x27, 1},
    {0x23, 1},
    {0x1C, 1},
    {0x21, 1},
    {0x20, 1},
    {0x1C, 1},
    {0x26, 1},
    {0x2F, 1},
    {0x00, 1},
    {0x03, 1},
    {0x00, 1},
    {0x24, 1},//17

    {0xE1, 0},// - polarity
    {0x06, 1},
    {0x10, 1},
    {0x05, 1},
    {0x21, 1},
    {0x27, 1},
    {0x22, 1},
    {0x1C, 1},
    {0x21, 1},
    {0x1F, 1},
    {0x1D, 1},
    {0x27, 1},
    {0x2F, 1},
    {0x05, 1},
    {0x03, 1},
    {0x00, 1},
    {0x3F, 1},
  };
  unsigned char ramad[][2] = {
    {0x2A, 0},//column address set
    {0x00, 1},//xs = 02h = 2
    {0x02, 1},
    {0x00, 1},//xe = 81h = 129
    {0x81, 1},

    {0x2B, 0},//row address set
    {0x00, 1},//ys = 03h = 3
    {0x03, 1},
    {0x00, 1},//ye = 82h = 130
    {0x82, 1},
  };


  // init state (WRX=0,DCX=0,RESX=0,CSX=1,DCLK=0,DIN=0)
  printf("init WRX=0,DCX=0,RESX=0,CSX=1,DCLK=0,DIN=0\n");
  *stat = 0x00 | CSX;
  write_buf(ftdic, stat, 1);

  // reset
  printf("RESET...\n");
  setb(stat, RESX, 1);
  write_buf(ftdic, stat, 1);
  nsleep(50*1000*1000);

  setb(stat, RESX, 0);
  write_buf(ftdic, stat, 1);
  nsleep(50*1000*1000);

  setb(stat, RESX, 1);
  write_buf(ftdic, stat, 1);
  nsleep(120*1000*1000);// wait for more than 120ms

  //data pins enable
  setb(stat, CSX, 0);
  write_buf(ftdic, stat, 1);

  // software reset
  make_cd(stat, 0x01, 0, cbuf);
  write_buf(ftdic, cbuf, CD_SIZE);
  nsleep(100*1000*1000);

  //sleep out
  printf("sleep out\n");
  make_cd(stat, 0x11, 0, cbuf);
  write_buf(ftdic, cbuf, CD_SIZE);
  nsleep(100*1000*1000);

  make_cd(stat, 0x28, 0, cbuf);//display off
  write_buf(ftdic, cbuf, CD_SIZE);

  //vcom
  cmdsize = sizeof(vcomcmd)/sizeof(vcomcmd[0]);

  for(i=0; i<cmdsize; i++){
    make_cd(stat, vcomcmd[i][0], vcomcmd[i][1], cbufs[i]);
  }
  write_buf(ftdic, (unsigned char*)cbufs, cmdsize * CD_SIZE);
  nsleep(200*1000*1000);

  //cmd2
  cmdsize = sizeof(cmd2)/sizeof(cmd2[0]);

  for(i=0; i<cmdsize; i++){
    make_cd(stat, cmd2[i][0], cmd2[i][1], cbufs[i]);
  }
  write_buf(ftdic, (unsigned char*)cbufs, cmdsize * CD_SIZE);


  //GAMMA SET BY REGISTER
  //***********************GAMMA*************************
  printf("gamma set\n");
  cmdsize = sizeof(gamma)/sizeof(gamma[0]);

  for(i=0; i<cmdsize; i++){
    make_cd(stat, gamma[i][0], gamma[i][1], cbufs[i]);
  }
  write_buf(ftdic, (unsigned char*)cbufs, cmdsize * CD_SIZE);



  //***************************RAM ADDRESS*******************
  printf("set ram address\n");
  cmdsize = sizeof(ramad)/sizeof(ramad[0]);

  for(i=0; i<cmdsize; i++){
    make_cd(stat, ramad[i][0], ramad[i][1], cbufs[i]);
  }
  write_buf(ftdic, (unsigned char*)cbufs, cmdsize * CD_SIZE);


  printf("display on\n");
  make_cd(stat, 0x29, 0, cbuf);//display on
  write_buf(ftdic, cbuf, CD_SIZE);

  nsleep(50*1000*1000);
  return 0;
}