ArduinoでaitendoのTFT液晶(M-Z18SPI-2PB)を制御するライブラリを作成するための調査(1)

投稿者: | ↻ : 2019年6月23日

aitendoのTFT液晶モジュール(M-Z18SPI-2PB)向けの専用ライブラリを作成することを目的に、Arduinoで動かしながら制御方法の詳細を調べていきます。

TFT液晶with基板 [M-Z18SPI-2PB]

商品サイトの記載から、このTFT液晶モジュールは制御チップにSitronixのST7735Sを使用していることが分かります。aitendoでは動作の確認にAdafruitがGithubで公開しているST7735Sに対応したライブラリを使用しています。

このライブラリはAdafruitが販売している液晶モジュール向けに作成されているため、ライブラリに変更が必要でした。

調査環境の準備から、ライブラリの変更までを以下にまとめます。

2019年6月22日
公開されているAdafruitライブラリの変更に合わせて、ライブラリの変更箇所を修正しました。(※ 追加するコードは同じ)

基本の環境

Arduino Uno Rev3にプログラムを書き込んでLチカが出来る環境を前提とします。

  • macOS Sierra 10.12.6
  • Arduino IDE 1.8.3
  • Arduino Uno Rev 3
  • TFT液晶モジュール(1.8/SPI) [Z180SN009]

調査環境の準備

調査を行うためAdafruitのライブラリを使用してTFT液晶モジュールが動作する環境を作成します。

ライブラリのインストール

Githubから二つのライブラリをZIP形式でダウンロード

adafruit/Adafruit-GFX-Library
adafruit/Adafruit-ST7735-Library

Arduino IDEにライブラリをインストール

Arduino IDEのメニューから「スケッチ」>「ライブラリをインクルード」>「.ZIP形式のライブラリをインストール」からダウンロードしたファイルをインストールします。

「Adafruit GFX Library」と「Adafruit ST7735 Library」がリストに追加されます。

ライブラリが参照できるか確認

3つのヘッダファイルをインクルードしてコンパイルできるか確認します。


#include <gfxfont.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
}

TFT液晶モジュールの動作を確認

ArduinoとTFT液晶モジュールの接続

Arduino側とTFT液晶モジュール側のピンを以下の通りに接続します。

TFT液晶側Arduino側
GNDGND
CS10
VCC3.3V
SCK13
SDA11
A08
RST9
VLED5V
接続イメージ

Arduinoに動作確認のプログラムを書き込む

以下のプログラムをArduinoに書き込みます。


#include <gfxfont.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

#define TFT_CS  (10)  // SPI接続で制御するデバイスを選択するピン番号
#define TFT_RST (9)   // ハードウェアリセットを行うピン番号
#define TFT_DC  (8)   // 送信するデータがコマンドかデータかを決めるピン番号

/*
 * SCL(serial clock)とSDA(serial data input/output)のピンは初期値で
 * オブジェクトを生成する。(SCL=13/SDA=11)
 */
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

void setup() {
  /*
   * 各メソッドを呼び出す前に必ず、initR()を飛び出す。
   * initR()によりTFT液晶の内部コントローラチップの初期設定が行われる。
   */
  tft.initR(INITR_BLACKTAB);

  /*
   * Hello Worldの表示
   */
  tft.setTextWrap(false);
  tft.fillScreen(ST7735_BLACK);
  tft.setCursor(0, 30);
  tft.setTextColor(ST7735_YELLOW);
  tft.setTextSize(3);
  tft.println("Hello");
  tft.println("World");
}

void loop() {
}

実行結果の確認

液晶画面に黄色い文字で”Hello World”が表示されます。ただし、画面の右端と下部にゴミが残り、”Hello World”の左端が見切れています。

なぜ、画面の右端と下部にゴミが残るのか?

原因

これは品質の差などではなく、AdafruitとaitendoのTFT液晶モジュールで必要な設定値が異なるためです。

ST7735Sは表示する画像データを記憶するDisplay data RAMを持っています。このRAMは、132x162x18bit(384,912bit)の容量がありますが、液晶パネルは128×160の解像度なので一部を切り出して表示されます。
この切り出しの基準となる位置が、AdafruitとaitendoのTFT液晶モジュールで異なるために、左側の表示が見切れたり、画像データが転送されていない領域が表示されゴミとなります。

Display data RAMから液晶パネルへの切り出しの基準となる位置は固定なので、プログラム側でDisplay data RAMへ画像データを書き込む位置を調整して対応します。この位置の設定は、ライブラリのAdafruit_ST7735::initR()に実装されています。

Display data RAMについては、ST7735Sのデータシートの9.9 Display Data RAMあたりを参照。

Adafruit_ST7735.cppから抜粋

void Adafruit_ST7735::initR(uint8_t options) {
  commonInit(Rcmd1);
  if(options == INITR_GREENTAB) {
    displayInit(Rcmd2green);
    _colstart = 2;
    _rowstart = 1;
  } else if((options == INITR_144GREENTAB) || (options == INITR_HALLOWING)) {
    _height   = ST7735_TFTHEIGHT_128;
    _width    = ST7735_TFTWIDTH_128;
    displayInit(Rcmd2green144);
    _colstart = 2;
    _rowstart = 3; // For default rotation 0
  } else if(options == INITR_MINI160x80) {
    _height   = ST7735_TFTHEIGHT_160;
    _width    = ST7735_TFTWIDTH_80;
    displayInit(Rcmd2green160x80);
    _colstart = 24;
    _rowstart = 0;
  } else {
    // colstart, rowstart left at default '0' values
    displayInit(Rcmd2red);
  }
  displayInit(Rcmd3);

  // Black tab, change MADCTL color filter
  if((options == INITR_BLACKTAB) || (options == INITR_MINI160x80)) {
    uint8_t data = 0xC0;
    sendCommand(ST77XX_MADCTL, &data, 1);
  }

  if(options == INITR_HALLOWING) {
    // Hallowing is simply a 1.44" green tab upside-down:
    tabcolor = INITR_144GREENTAB;
    setRotation(2);
  } else {
    tabcolor = options;
    setRotation(0);
  }
}

AdafruitのライブラリはST7735系の複数のチップに対応していて、オプションで処理を分けています。オプションに指定する定数は、液晶パネルの保護シートに付いているタブの色を元に定数名が付けられており、制御チップがST7735Sの場合は黒なので、INITR_BLACKTABを指定します。
(Adafruitで使用している液晶パネルには黒っぽいラベルが付いているらしい。aitendoのは深緑くらい)

この処理で設定しているcolstartとrowstartがDisplay data RAMへ書き込みを行う時の基準となる位置です。optionsにINITR_BLACKTABを指定して呼び出した場合、colstartとrowstartが設定されないように見えますが、必ず呼び出されるcommonInit()内で、0に初期化されています。

そして、われわれが動かしたいaitendoのTFT液晶モジュールの基準となる位置は、0では無いのです。しくしく(ノД`)…

対応策

colstartとrowstartは、privateなメンバー変数なので外部から変更できません。AdafruitのTFT液晶モジュールが使えなくなりますが、専用ライブラリを作成するまでの仮なので、無視してライブラリのコードを変更します。(なので、変更の位置も適当です)
設定したい値は、colstart=2、rowstart=1となります。

macOSの場合、インストールしたライブラリのソースコードは以下のディレクトリに格納されています。
~/Documents/Arduino/libraries/Adafruit-ST7735-Library-master/Adafruit_ST7735.cpp

ライブラリの変更箇所(抜粋)


void Adafruit_ST7735::initR(uint8_t options) {
  commonInit(Rcmd1);

  ... 省略

  // Black tab, change MADCTL color filter
  if((options == INITR_BLACKTAB) || (options == INITR_MINI160x80)) {
    uint8_t data = 0xC0;
    sendCommand(ST77XX_MADCTL, &data, 1);
  }

  // 以下の2行を追加する
  _colstart = 2;
  _rowstart = 1;

  if(options == INITR_HALLOWING) {
    // Hallowing is simply a 1.44" green tab upside-down:
    tabcolor = INITR_144GREENTAB;
    setRotation(2);
  } else {
    tabcolor = options;
    setRotation(0);
  }
}

まとめ

これで、動作を確認できる環境ができました。ここから、ライブラリのコードの解析して必要な部分を頂きます。