M5stack ライブラリに頼らずに、TFT LCD ILI9341 をちょっと解明

M5Stack の液晶ディスプレイ ILI9341 をちょっと解明してみた

記事公開日:2018年4月11日


スポンサーリンク

TFT LCD ILI9341 の Pixel ( Dot )並びについて

では、ILI9341 の Pixel の並び方を見てみたいと思います。

このディスプレイは、赤(red)、緑(green)、青(blue)を混ぜて色を作る、RGBタイプです。
RGBの色素子まとめた1つが 1 pixel ( dot )になります。

M5Stack のボタンをディスプレイの下側とすると、デフォルト設定では、画面の左上端が描画の始点となります。

m5stack_lcd_mydemo03.jpg


ディスプレイを拡大鏡で 1 pixel を見てみると下図のような配置になっているのが分かると思います。
ILI9341 では、横に 320 pixel 、縦に 240 pixel 並んでいます。

m5stack_lcd_mydemo02.jpg


ILI9341 のデータシートによれば、横は Column という単位で、縦は Page という単位です。

Column も Page もゼロが始点です。
最大値は以下のようになります。

Column 最大値 = 319
Page 最大値 = 239

間違えないようにしてください。

また、四角形を描く場合は、下図の様に始点と終点を指定して範囲を設定すれば、あとは指定の数だけRGBビットを送れば四角形が描画できます。

m5stack_lcd_mydemo05.jpg


SPI コマンド及びデータ送信について

ILI9341 のデータシートを見てみると、1 pixel の色の指定方法およびデータ送信方法は以下のようにタイミングチャートで書かれています。

m5stack_lcd_mydemo04.jpg


【4wire SPI 65kカラーの場合】

65k色の場合、赤色の最大値は
00011111
( 10進数で31 )

緑色の最大値は
00111111
( 10進数で63 )

青色の最大値は
00011111
( 10進数で31 )

となります。
緑だけ値が大きいので、プログラミングする場合は注意が必要です。

また、これから分かる通り、デフォルトでは、赤(red)、緑(green)、青(blue) という順番でそのビットを送れば良いと思いますよね。

でも、実はこの通りにビットを配置しても、デフォルトでは赤と青が逆に表示されてしまいます。
この図では、赤が左側にありますが、ディスプレイを拡大鏡で見てみると青が左側にありました。

ということは、初期設定で RGB と BGR を逆にしなければなりません。
これは後述しますが、コマンドレジスタ 0x36 の Memory Access Control で設定できます。

また、このタイミングチャートを見て分かる通り、SPI モードはゼロですね。
そして、MSB First でデータを送信します。
SPI mode の波形については以下の記事を参照してください。
https://www.mgo-tec.com/blog-entry-esp8266-wroom-spi-speed-up-02.html

DC ( Data or Command )信号レベルについては、ちょっと難しく見えるかも知れません。
でも、これは基本的に、コマンドを送信する場合、 DC は Lowレベル、データを送信する場合は High レベルにすれば問題無く送信できました。

この他、262k カラーの場合もありますが、その場合はビット列が多くなります。
すると、転送速度も遅くなります。
私個人的には 65k色で十分なので、ここでは省略します。
いつか262kカラーには挑戦してみたいと思います。

これは、SSD1306 よりも簡単で設定しやすいですね。

SPI レジスタ直たたきプログラムについて

スケッチをプログラムする前に、説明しておかねばならないことがあります。

まず、Arduino – ESP32 用の M5Stack ライブラリを使ってみましたが、素晴らしく描画が速いんですね。
自分でもこれくらいできそうだと思っていましたが、実際に Arduino IDE でプログラミングしても速くなりませんでした。

M5Stack ライブラリは、Adafruit GFX ライブラリを改変しているようですが、それよりも速い気がしました。

そこで、 Display.cpp を調べてみると、ESP32 のSPI インターフェースレジスタを直接叩くプログラムが使われていました。
それはこんな感じのところです。

void spiWriteBlock(uint16_t color, uint32_t repeat) {
  uint16_t color16 = (color >> 8) | (color << 8);
  uint32_t color32 = color16 | color16 << 16;

  if (repeat > 15) {
    SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_NUM), SPI_USR_MOSI_DBITLEN, 255,
                      SPI_USR_MOSI_DBITLEN_S);

    while (repeat > 15) {
      while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM)) & SPI_USR)
        ;
      for (uint32_t i = 0; i < 16; i++)
        WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + (i << 2)), color32);
      SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR);
      repeat -= 16;
    }
    while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM)) & SPI_USR)
      ;
  }

  if (repeat) {
    repeat = (repeat << 4) - 1;
    SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_NUM), SPI_USR_MOSI_DBITLEN, repeat,
                      SPI_USR_MOSI_DBITLEN_S);
    for (uint32_t i = 0; i < 16; i++)
      WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + (i << 2)), color32);
    SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR);
    while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM)) & SPI_USR)
      ;
  }
}

これ、自分も使ってみたら、恐ろしく描画が速いのです。
これは、四角形範囲内を単色で塗りつぶす関数ですが、使い方によっては線も円も描けます。

私はこのレジスタコマンド群について、正直全く分かりません。
ですから解説も出来ません。
勉強不足です。

SPI 通信については、CS ピンの LOW-HIGH レベル変換の他、D/Cピンの LOW-HIGH レベル変換が必要で、その通信速度が描画に影響してきます。
ただ、四角形の中を単色のドットで埋め尽くす場合は、CS や DC のレベル変換は最初と最後の2回のみで、データ送信中は変換不要で固定です。

とすると、描画速度に関係するのは、クロック周波数と、クロック信号が描画中に中断なく持続してくれることです。
それと、それに合わせてMOSI 信号も中断なく持続して送ってくれることです。

クロック速度設定は初期化する時に実行しているので、中断の無い信号を出してくれるかどうかがカギになります。

Arduino – ESP32 の関数を使うと、どうしても途中で信号が中断してしまうんですね。
四角形を描くだけの短い間だけでも、中断せずに持続してパルスを出してほしいわけです。

それを可能にしてくれたのが、この SPI レジスタ直叩きプログラムです。

これはあまりにもスバラシイので、この関数はそのまま使わせて頂きます。
M5Stack ライブラリは MIT ライセンスですが、Display.cpp にはライセンスは書かれていませんでした。
でも、M5Stack ライブラリの中のものなので、MIT ライセンスだと思われます。

これを次のスケッチに入れてみます。


スポンサーリンク


「M5Stack の液晶ディスプレイ ILI9341 をちょっと解明してみた」への10件のフィードバック

  1. お久しぶりです。
    私も昨年末M5を入手しテストしてます。
    2月のコメントでILI9341をと書いたのはこのためでした。
    情報が少なく困ってました。
    wifi接続、SSL通信非常に参考のなりました。
    M5はアリエクスプレスで入手しましたが、アマゾンあたりは欠品してるみたいです。
    余談ですが、ESP32の試作ケースは3Dプリンターで作ってます。
    FreeCADっていうソフトですがなかなか良いです。無料ですし、オープンソースでパイソンで動いてます。
    画像が添付できればお見せしたいところです。

    今後ともご活躍ください。

    1. マッキーさん

      ご無沙汰しております。
      再度ブログにお越しいただき、そしてコメントいただき、ありがとうございます。

      そうだったんですね。
      M5stackを既に試されていたんですね。
      今はネットではESP32開発ボードよりも情報が多いくらいになっていて、M5stckを動かすには苦労しなくなっていますね。
      しばらくこのブームは続きそうです。

      3Dプリンターでケース作っているとはスゴイですね。
      私はしばらく使っておらず、使い方を忘れてしまいました。
      いつか挑戦してみようとは思っています。
      今後、M5stack用のライブラリを作ったりしていこうと思っています。

      マッキーさんも今後いろいろオモシロイ物を作って、ご活躍なさってください。

  2. ありがとうございます。
    ILI9341で通常の動作はさせましたが、前回お願いしたのは、漢字表示をさせたいためSSD1331のような漢字表示ライブラリーが欲しかったのです。
    中華製の漢字ROM、GT20L16J1Yを使って表示しましたがいまいちでした。
    余談ですが、M5stackでオシロスコープもすんなり動きました。
    無理ばっかり言ってすみません。(._.)

    1. 私自身も漢字表示ライブラリーが欲しいと思っています。
      今、取組中作業があるので、それが終わってから作成しようと思っています。
      もうちょっと時間がかかりますので、しばらくお待ちください。

  3. こんにちは。

    私も前々から気になっていたM5Stackをようやく購入できたので、色々なサンプルを動かしてどんなものか確認しています。今日は、このページのスケッチを動かしてみました。問題なく動作していましたが、まだ、ソースコードは全く見ていませんので、後でじっくり読んでみようと思っています。

    私はiPhoneのプログラマーなので、iPhoneとESP32をBLEで通信させた物を作っています。M5Stackがあると開発がスムーズに進められるようなので、うまくいったらESP32のプリント基板を自作してみようと思っています。

    私もM5Stackで、日本語表示してみたいです。

    では、では。

    1. あいむさん

      記事をご覧いただき、サンプルスケッチを試していただき、ありがとうございます。

      iPhone と BLE通信はイイですね!
      私はまだ BLE は試していません。
      Wi-Fiすら把握し切れていない状態です。

      確かに、M5stack を使うと開発がスムースになりそうですよね。
      何かオモシロイものができるとイイですね。

  4. アマゾンで購入しておいた1,186円のILI9341のLCDディスプレーモジュール基板が今日到着したので、このページのTFT LCD ILI9341 と ESP32の配線を参考に配線して、このスケッチを動作を確認したので報告します。

    M5Stackと同じように表示しました。が、XとYが逆になっていて、一部が表示されませんでした。たぶん日本語のスケッチも動くと思います。

    これから作る予定のESP32のプリント基板は、このILI9341のLCDが使えることが分かったので、表示装置はこれを使おうと思います。まだ、ライブラリーのソースコード見ていませんが、あとで修正できるか検討してみようと思います。

    1. あいむさん

      ご報告ありがとうございます。
      私も、2~3日前、Amazon で購入した サインスマート販売の 2.2 インチ ILI9341 は動作確認しました。
      ライブラリの
      ESP32_LCD_ILI9341_SPI.cpp
      91行目をコメントアウトして、92行目のコメントを解除すると XY 正しく表示されました。

      ただ、Hiletgo の 2.4インチのものはピン配列が謎で断念しました。

  5. もう修正してあったのですね。

    教えていただいたESP32_LCD_ILI9341_SPI.cppを修正したらXYが正しく表示されました。ただ、Yahooニュースをスクロールするスケッチを動かして見たのですが、今度はスクロールする文字列が横に長くて2文字くらいしか表示しなかったです。

    同じILI9341のLCDでも色々とありそうですね。
    今度は、1,490円のILI9341の2.8インチのタッチパネル付きを購入したので、届いたらこちらも動作確認してみます。

    1. あ、そうなんですね。
      サインスマートの ILI9341 は問題無く表示されましたけどね。

      ILI9341_Init関数は最小限の初期化コマンドしか使っていないので、やっぱり M5stack 標準ライブラリにあるように、ズラーッと初期化コマンドを使った方が正常に動作されるかも知れません。
      まだ使いこなせていないコマンドが多いです。

      今後、気付いたところは改良していきたいと思っています。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください