1.77インチ カラー液晶の表示テスト

f:id:nicotakuya:20210305012358j:plain
TFT液晶表示

とりあえず動きましたというレベルですが、マイコン(Arduino)を使って1.77インチ カラー液晶に表示してみました。
16bitモードで、RGB+グレースケールを32諧調グラデーション表示します。
使用した部品は以下のとおりです。
マイコン「Seeeduino XIAO」580円。
・1.77インチ カラーグラフィックTFT LCD 評価キット「AE-ATM0177B3A」1200円。
昔は32bitマイコンもカラー液晶も高くて手が出なかったのですが、今だと手軽に買えてしまいます。便利な世の中になりました。
Arduino IDEでSeeeduino XIAOを使う方法については、こちらのページで紹介されています。
https://wiki.seeedstudio.com/Seeeduino-XIAO/#software
接続図は以下の通りです。3.3Vで動かします。

f:id:nicotakuya:20210305131928p:plain
接続方法

プログラム(Arduino IDE用)は以下の通りです。「TFTCS」「TFTCD」「SPICLK」「SPIDAT」「TFTRST」のGPIO番号を書き換えれば、他のマイコンでも動くと思います。

// TFT test program by takuya matsubara

// 初期設定は Max MC Costa(sumotoy)さんの「TFT_ILI9163C」を参考にしています。
//https://github.com/sumotoy/TFT_ILI9163C

// Akizuki AE-ATM0177B3A
// 1.77inch ZETTLER COLOR TFT LCD(ILI9163V / 128x160 pixel)
//https://akizukidenshi.com/catalog/g/gK-14032/

// pin assign
//1: NC
//2: NC
//3: NC
//4: NC
//5: LED Anode
//6: NC
//7: NC
//8: GND
//9: VCC
//10: SDA
//11: SCK
//12: CD(H=Data/L=Command)
//13: RESET
//14: LED Cathode
//15: CS(L=active)

//Seeeduino XIAO - Arduino Microcontroller
//CPU:Arm Cortex M0+ 32bit 48 MHz(SAMD21)
//Flash:256 KB 
//SRAM:32 KB

// pin assign
//    [USB]
//D0         5V
//D1(RST)    GND
//D2(CS)     3V3
//D3(CD)     D10(MOSI)
//D4         D9(MISO)
//D5         D8(SCK)
//D6(TX)     D7(RX)

#define TFTCS     2   // chip select
#define TFTCD     3   // command/data
#define SPICLK    8   // clock
#define SPIDAT   10   // data
#define TFTRST    1   // reset

#define SOFTWARE_RESET            0x01
#define SLEEP_OUT                 0x11
#define PARTIAL_MODE_ON           0x12
#define NORMAL_DISPLAY_MODE_ON    0x13
#define DISPLAY_INVERSION_OFF     0x20
#define DISPLAY_INVERSION_ON      0x21
#define GAMMA_SET                 0x26
#define DISPLAY_OFF               0x28
#define DISPLAY_ON                0x29
#define COLUMN_ADDRESS_SET        0x2A
#define PAGE_ADDRESS_SET          0x2B
#define MEMORY_WRITE              0x2C
#define V_SCROLL_DEFINITION       0x33
#define MEMORY_ACCESS_CONTROL     0x36
#define V_SCROLL_START_ADDRESS    0x37
#define INTERFACE_PIXEL_FORMAT    0x3A
#define FRAME_RATE_CONTROL_1      0xB1
#define DISPLAY_INVERSION_CONTROL 0xB4
#define DISPLAY_FUCTION_SET       0xb6
#define POWER_CONTROL_1           0xC0
#define POWER_CONTROL_2           0xC1
#define VCOM_CONTROL_1            0xC5
#define VCOM_OFFSET_CONTROL       0xC7
#define POSITIVE_GAMMA            0xE0
#define NEGATIVE_GAMMA            0xE1
#define GAM_R_SEL                 0xF2

#define GRAMWIDTH        128  // width[pixel]
#define GRAMHEIGHT       160  // height[pixel]

#define SPIWAIT 5

void waitloop(long count){
  while(count--);
}

void spi_sendbyte(unsigned char data){
  unsigned char bitmask;
  waitloop(SPIWAIT);
  digitalWrite(TFTCS,LOW);
  digitalWrite(SPICLK, LOW);
  waitloop(SPIWAIT);
  bitmask = 0x80;
  while(bitmask){
    if(bitmask & data){
      digitalWrite(SPIDAT, HIGH);
    }else{
      digitalWrite(SPIDAT, LOW);
    }    
    waitloop(SPIWAIT);
    digitalWrite(SPICLK, HIGH);
    waitloop(SPIWAIT);
    digitalWrite(SPICLK, LOW);
    bitmask >>= 1;
  }
  waitloop(SPIWAIT);
  digitalWrite(TFTCS,HIGH);
  waitloop(SPIWAIT);
}

void tft_sendcmd(unsigned char data){
  delay(1);
  digitalWrite(TFTCD,LOW);
  spi_sendbyte(data);
  digitalWrite(TFTCD,HIGH);
}

void tft_send_data(unsigned char data){
  digitalWrite(TFTCD,HIGH);
  spi_sendbyte(data);
}

void tft_sendcmd_15byte(unsigned char cmd,unsigned char *data){
  int cnt;
  tft_sendcmd(cmd);
  cnt=15;
  while(cnt--){
    tft_send_data(*data++);
  }
}

void tft_sendcmd_byte(unsigned char cmd,unsigned char data){
  tft_sendcmd(cmd);
  tft_send_data(data);
}

void tft_sendcmd_word(unsigned char cmd,unsigned int data){
  tft_sendcmd(cmd);
  tft_send_data((unsigned char)(data >> 8));
  tft_send_data((unsigned char)(data & 0xff));
}

void tft_sendcmd_long(unsigned char cmd,unsigned long data){
  tft_sendcmd(cmd);
  tft_send_data((unsigned char)(data >> 24));
  tft_send_data((unsigned char)((data >> 16)& 0xff));
  tft_send_data((unsigned char)((data >> 8)& 0xff));
  tft_send_data((unsigned char)(data & 0xff));
}

// test pattern
void tft_display_test(void){
  int x,y;
  char mode;
  unsigned int r,g,b,color;
  tft_sendcmd(MEMORY_WRITE);
  delay(150);  
  color=0;
  for(y=0; y<160; y++){
    for(x=0; x<128; x++){
      mode = (y / 40);
      if(mode==0) color = ((y % 40)*0x1f/39);     //blue
      if(mode==1) color = ((y % 40)*0x1f/39)<<6;  //green
      if(mode==2) color = ((y % 40)*0x1f/39)<<11; //red
      if(mode==3){ //grayscale
        b=(y % 40)*0x1f/39;
        r=b;
        g=b;
        color = (r<<11)+(g<<6)+b; 
      }
      tft_send_data(color >> 8);
      tft_send_data(color & 0xff);
    }
  }
}

void setup(void) {
  pinMode(SPIDAT, OUTPUT);
  pinMode(SPICLK, OUTPUT);
  pinMode(TFTCD, OUTPUT);
  pinMode(TFTCS, OUTPUT);
  pinMode(TFTRST, OUTPUT);
  digitalWrite(SPIDAT, HIGH);
  digitalWrite(SPICLK, LOW);
  digitalWrite(TFTCD, HIGH);
  digitalWrite(TFTCS, HIGH);
  digitalWrite(TFTRST, HIGH);
  delay(500);
  tft_sendcmd(SOFTWARE_RESET);
  delay(500);
  tft_sendcmd(SLEEP_OUT);
  delay(5);
  tft_sendcmd_byte(INTERFACE_PIXEL_FORMAT, 0x05);  //16bit
  tft_sendcmd_byte(GAMMA_SET,0x04);
  tft_sendcmd_byte(GAM_R_SEL,0x01);
  tft_sendcmd(NORMAL_DISPLAY_MODE_ON);
  tft_sendcmd_word(DISPLAY_FUCTION_SET,0xff06);
  tft_sendcmd_word(FRAME_RATE_CONTROL_1,0x0802);
  tft_sendcmd_byte(DISPLAY_INVERSION_CONTROL,0x07);
  tft_sendcmd_word(POWER_CONTROL_1,0x0A02);
  tft_sendcmd_byte(POWER_CONTROL_2,0x02);
  tft_sendcmd_word(VCOM_CONTROL_1,0x5063);
  tft_sendcmd_byte(VCOM_OFFSET_CONTROL,0x00);
  tft_sendcmd_long(COLUMN_ADDRESS_SET,GRAMWIDTH-1); 
  tft_sendcmd_long(PAGE_ADDRESS_SET,GRAMHEIGHT-1); 
  tft_sendcmd(DISPLAY_ON);
}
 
void loop() {
  delay(500);  
  tft_display_test();
}

液晶の初期設定のパラメータはMax MC Costa(sumotoy)さんの「TFT_ILI9163C」を使わせて頂きました。ガンマの設定はよくわからないので削っています。

プログラムには間違いがある可能性があります。間違いを見つけた場合は直して使ってみてください。