激安QVGA液晶をESP8266で使う

esp826610.jpg

中国の通販サイトaliexpressで、QVGA(320×240)の2.2インチカラーLCDが送料込で5ドル少々だったので購入してみました。
インタフェースはSPIで、コントローラはILI9340Cということで、たぶん以下の記事で使われているのと同じものだと思います。

Cheap TFT 2.2 inch Display on Arduino (ILI9340C or ILI9341) – All

ちなみに購入したお店はこちらです。

New 2.2 inch 2.2 240×320 SPI TFT LCD Display Module ILI9341 PCB 5V/3.3V 51/AVR/STM32/ARM/PIC Free Shipping-in LCD Modules from Electronic Components & Supplies on Aliexpress.com | Alibaba Group

ピン配列は以下のようになっています。

1 : VCC
2 : GND
3 : CS
4 : RESET
5 : DC/RS
6 : SDI/MOSI
7 : SCK
8 : LED
9 : SDO/MISO

esp826610-01.jpg

SPIですので、基本的に接続方法はこれまで使っていたST7735のLCDと同じです(ピンの呼称が若干違いますが)。
ESP8266とは、以下のように接続しました。

LCD / ESP8266
CS / IO15
RST / IO5
DC / IO4
SDI / IO13
SCK / IO14
SDO / IO12

SDOはST7735では使っていませんでしたが、ILI9340ではLCDから情報を受け取るために使います。
他に、VCCとLEDを電源(3.3V)、GNDを電源のGNDに接続します。
LEDは抵抗が入っているかどうか怪しいので、5Vには直接接続しないほうが良いかもしれません。

ドライバはArduino IDE for ESP8266に最初から含まれています。
ただしILI9340ではなくILI9341用のものですが、問題なく動作しました。

Arduino/libraries/Adafruit_ILI9341 at esp8266 · esp8266/Arduino

2019/08/14追記:現在はこのファイルは
Basic/libraries/Adafruit_ILI9341 at master · esp8266/Basic
に移動したようです。】

また、スケッチ例として「graphicstest_esp8266」が含まれています。
ESP8266用のスケッチですので、結線情報など若干変更すれば動作しました。
ちなみに変更部分は以下の箇所です。

#include <Arduino.h>
#include <SPI.h>  //この行を追加
#include <Adafruit_GFX.h>  //この行を追加
#include <Adafruit_ILI9341.h>

// For the Adafruit shield, these are the default.
//結線を以下の通り変更
#define TFT_CS     15
#define TFT_RST    5
#define TFT_DC     4

私の環境では、上記の変更だけでは動作したりしなかったりという現象があったのですが、この記事のコメント欄を見ると、リセットはHighにしないと動作しない場合があるようです。

そこで、setupルーチンの冒頭に以下のコードも追加しています。

void setup() {
 pinMode(TFT_RST, OUTPUT);
 digitalWrite(TFT_RST, LOW);
 digitalWrite(TFT_RST, HIGH);

これでスケッチ例が動作するようになったので、前回のJPEG表示プログラムもILI9340用に書き換えて、320x240ピクセルの画像を表示させてみました。

動作結果がページ先頭の写真です。
表示させている画像は画像符号化の世界ではおなじみのレナさんです。

書き換えのポイントは以下の通りです。

・includeするファイルの変更

#include <Adafruit_ILI9341.h>

・TFT液晶のオブジェクト

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

・液晶のリセットコード追加(前述)
・TFT初期化

  tft.begin();

・色変換の関数名

            tft.drawPixel(x, y, tft.color565(

・LCDが動作しているかどうかの診断(スケッチ例graphicstest_sep8266からコピー)

表示に1秒以上かかりますが、現在は1ピクセルずつdrawPixelで書いている部分をsetAddrWindowとpushColorで書き直せば、もう少し高速化できると思います。

最後にこのスケッチの全体を掲載しておきます。
JPEGファイルは、ファイル名test1.jpgで、あらかじめSPIFFSへ格納しておいてください。

#include <arduino.h>
#include <SPI.h>
#include <FS.h>
#include <JPEGDecoder.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ILI9341.h> // Hardware-specific library

#define TFT_CS     15
#define TFT_RST    5
#define TFT_DC     4

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

void setup() {
 pinMode(TFT_RST, OUTPUT);
 digitalWrite(TFT_RST, LOW);
 digitalWrite(TFT_RST, HIGH);

 Serial.begin(115200);
 Serial.println("");
 delay(10);

 tft.begin();
 // read diagnostics (optional but can help debug problems)
 uint8_t x = tft.readcommand8(ILI9341_RDMODE);
 Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
 x = tft.readcommand8(ILI9341_RDMADCTL);
 Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
 x = tft.readcommand8(ILI9341_RDPIXFMT);
 Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
 x = tft.readcommand8(ILI9341_RDIMGFMT);
 Serial.print("Image Format: 0x"); Serial.println(x, HEX);
 x = tft.readcommand8(ILI9341_RDSELFDIAG);
 Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);

 tft.fillScreen(ILI9341_BLACK);

 SPIFFS.begin();
 jpegDraw("/test1.jpg");
}

void jpegDraw(char* filename) {
 char str[100];
 uint8 *pImg;
 int x,y,bx,by;
 
 // Decoding start
 JpegDec.decode(filename,0);

 // Image Information
 Serial.print("Width     :");
 Serial.println(JpegDec.width);
 Serial.print("Height    :");
 Serial.println(JpegDec.height);
 Serial.print("Components:");
 Serial.println(JpegDec.comps);
 Serial.print("MCU / row :");
 Serial.println(JpegDec.MCUSPerRow);
 Serial.print("MCU / col :");
 Serial.println(JpegDec.MCUSPerCol);
 Serial.print("Scan type :");
 Serial.println(JpegDec.scanType);
 Serial.print("MCU width :");
 Serial.println(JpegDec.MCUWidth);
 Serial.print("MCU height:");
 Serial.println(JpegDec.MCUHeight);
 Serial.println("");
 
 sprintf(str,"#SIZE,%d,%d",JpegDec.width,JpegDec.height);
 Serial.println(str);

 // Raw Image Data
 while(JpegDec.read()){
   pImg = JpegDec.pImage ;

   for(by=0; by<JpegDec.MCUHeight; by++){
     for(bx=0; bx<JpegDec.MCUWidth; bx++){
       
       x = JpegDec.MCUx * JpegDec.MCUWidth + bx;
       y = JpegDec.MCUy * JpegDec.MCUHeight + by;
       
       if(x<JpegDec.width && y<JpegDec.height){
         if(JpegDec.comps == 1){ // Grayscale          
           tft.drawPixel(x, y, tft.color565(pImg[0], pImg[0], pImg[0]));
         }else{ // RGB
           tft.drawPixel(x, y, tft.color565(pImg[0], pImg[1], pImg[2]));
         }
       }
       
       pImg += JpegDec.comps ;
     }
   }
 }
}
   
void loop() {
}

コメント