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

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

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

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

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

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

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

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

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

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

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

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

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

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

【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 インターフェースレジスタを直接叩くプログラムが使われていました。
それはこんな感じのところです。

【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)

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 ライセンスだと思われます。

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

コメント

  1. マッキー より:

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

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

    • mgo-tec mgo-tec より:

      マッキーさん

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

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

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

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

  2. マッキー より:

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

    • mgo-tec mgo-tec より:

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

  3. あいむ より:

    こんにちは。

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

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

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

    では、では。

    • mgo-tec mgo-tec より:

      あいむさん

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

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

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

  4. あいむ より:

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

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

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

    • mgo-tec mgo-tec より:

      あいむさん

      ご報告ありがとうございます。
      私も、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インチのタッチパネル付きを購入したので、届いたらこちらも動作確認してみます。

    • mgo-tec mgo-tec より:

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

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

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

  6. kazu より:

    こんばんは
    Atom Liteに書き込みをしてみました。ILI9341の接続をどうしたらいいのかわかりません。
    といっても元々無理なことをしているのかもしれません。

    • mgo-tec mgo-tec より:

      kazuさん

      記事をご覧いただきありがとうございます。
      残念ながら、私はAtom Liteを持ち合わせていませんので、動くかどうか私には分かりません。

      ところで、M5StackやESP32でディスプレイを高速表示させるライブラリを作っているらびやんさんという方がおられます。私が尊敬するお方です。
      その方は超プロフェッショナルなので、恐らく、Atom LiteとILI9341に関しては熟知していると思います。
      TwitterかGitHubで質問してみるという手もあるかもです。

      というわけで、お役に立てず、すみません。

  7. haiga より:

    mgo-tecさま

    いつも有用な記事を拝見させて頂き、当方のCMに関連するツールに様々に使用させて頂いております。ありがとうございます。

    さて、最近、Amazon等でILI9341ドライバー仕様で320×480解像度の3.5インチLCDが売られておりますが、240×320のLCDをこれに変更できれば、エリアが2倍に広がります。

    mgo-tecさまのLCDドライバーの何処を変更すれば、このLCDに対応できるか((319,239)と記述している部分?)が知りたいと思い書込みした次第です。

    /haiga

    • mgo-tec mgo-tec より:

      haigaさん

      記事をご覧いただき、ありがとうございます。

      ILI9341の倍画面ですか~…。
      実機で確かめてみないと何とも言えませんが、今の私には実験する時間がまったく無く、最近はしばらくESP32もM5Stackも触っていないので、あまりお役に立てないかも知れません。
      この記事のソースコードならば、319, 239 のところを書き換えれば、もしかしたら動くかもしれませんが、何とも言えません。

      また、この記事は古く、未熟なプログラムで、他の私の自作ライブラリのドライバーも素人コードで動作が遅いです。

      お勧めなのは、「らびやん」さんのESP32, M5Stack用LCDドライバーが遙かに高速で、様々なLCDに対応していて、今やM5Stackの標準ライブラリになっています。
      LovyanGFXというものです。
      Arduino IDEからでもライブラリマネージャでインストールできると思います。
      使い方は私には解りませんが、ネットでもかなり情報が出ているので、是非試してみて下さい。
      おそらく、倍角のILI9341ドライバーにも対応していると思います。

タイトルとURLをコピーしました