製作物

PICでカラーLCDモジュールを動かしてみた話【ST7789】

投稿日:

今回は以前に Amazon で購入したまま積んでいた フルカラーグラフィックLCD を PIC で制御してみました。

激ムズというわけではありませんでしたが、いくつかつまずいたポイントがあったので備忘録がてら記事にしたいと思います。

 

今回使用した LCD はこちらです。

似たような商品は他にもいくらでもあると思いますが、制御チップがこれと同じ ST7789 であれば恐らく同じように使用できると思います。

 

付属資料の分析

Amazon の商品説明欄に ユーザーマニュアルのURL (Google Driveで共有するのね…) が記載されていたので、そこから zip ファイルをダウンロード、解凍するといろいろ資料が入っていました。

当然のごとく中国語か英語なので頑張って雰囲気で読んでいきます。

 

まずは基板から

いきなり前言撤回しますが、資料の前に基板の情報を見てみましょう。

表面

裏面

7ピンでピンアサインは基板表面に書かれているので分かりやすいですね。解像度は 240×240 、けっこう細かい画像が表示できそうです。

裏面を見ると、制御チップは ST7789 で、通信方法は SPI のようです。

SPI は I2C に比べるととっつきにくいイメージですが、画像のような大量のデータを送信するにはスピードが必要になるので仕方ないですね。

ところで PIC のデータシートとかにある用語では SCL, SDA は I2C の用語で、SPI だと SCK, SDI (, SDO) だったと思うけど、本当に SPI なんだよね?

ちなみに SPI については解説記事を書いているので知りたい方はこちらも合わせてご覧ください。

【PIC】SPI通信のやり方

 

付属資料にはピンアサインについて説明がついていました。中国語ですが雰囲気で読み取ります。

通信方法が 4線SPI と書かれているのでこれは有益な情報ですね。

配線図

基板に出ている 7ピンが制御チップのどのピンに繋がっているのか、どんな役割なのかを見ていきましょう。

資料が複数あるんですけど、どうやらこの液晶モジュールは 2重のモジュールになっているようです。

まず12ピン、極小ピッチのモジュールがあって(基板裏面橙色部分)、それを 7ピン、2.54 mm ピッチの基板にモジュール化しているようです。

2.54 mm ピッチなのは大変ありがたい限りですが、資料を眺めているとなんだか嫌な雰囲気が…

12ピンの中にある CS が 7ピンの中には含まれていなく GND に繋がっています。CS って SPI で通信相手を指定するときの Chip Select だよね?なんで外部から制御できるようになってないの?

 

ちょっと受け入れ難かったのでテスターで確かめてみたんですけど、ばっちり GND に繋がっていました。

まあここで悩んでてもしょうがないので先に進みましょう。

 

ST7789 データシート

次は一番大事な、制御チップ ST7789 のデータシートです。英語で書かれてて良かった、これが中国語だったらやる気がガタ落ちでした。

さて、初めに確認するべきはやっぱり通信方法ですかね。

この IC はパラレル、シリアルともに多くの通信方法に対応しているようです。

シリアルインターフェイスの説明を見てみましょう。

The serial interface is either 3-lines/9-bits or 4-lines/8-bits bi-directional interface for communication between the micro controller and the LCD driver. The 3-lines serial interface use: CSX (chip enable), SCL (serial clock) and SDA (serial data input/output), and the 4-lines serial interface use: CSX (chip enable), D/CX (data/ command flag), SCL (serial clock) and SDA (serial data input/output). Serial clock (SCL) is used for interface with MCU only, so it can be stopped when no communication is necessary.

うんうん、なるほど。4線というのは クロック、データ、D/C、CS の 4本のようです。私の知ってる 4線SPI とは違うけど、データは一方通行でいいのでそこは置いておきましょう。

DC というのは Data/Command の選択ピンのようです。パラレル接続のときにはよくあるやつですね。まあこれは大したことは無いでしょう。

 

でもやっぱり CS 要るよね??

まあ CS が常に GND になっているということは常に受信態勢にあるわけなのでなんとかなるのかな?

でもパケットの先頭を知る術がないので 1クロックでもずれたら崩壊しそうだけど大丈夫なのだろうか?

 

通信タイムチャートを見てみると、クロックは Idle Low で、データの送信は Idle to Active っぽいですね。(フラグ)

PIC の SPI の設定をこれに合わせましょう。

 

初期化

こういうデバイスで一番厄介なのが初期化のプロセスですね。初期化が出来ないと通信が出来ているのかすら分からないので、壊れているんじゃないかという不安と闘いながら手がかりもなく原因を探すことになります。

付属資料の中に初期化プログラムが入っていました。

 

最初のコマンド (0x36) をデータシートで調べてみると、ディスプレイの表示方向の設定のようです。

最後のコマンド (0x29) は表示を ON にするコマンドのようなので、全部は見てられないけどこれで適切に初期化が出来ると信じましょう。

コマンドとパラメータを送信する関数の中身は書いてないですけど、きっと DC を切り替えて 8bit を SPI で送信すれば大丈夫でしょう。

 

address() は X, Y のアドレスの範囲を指定して、データ書き込み準備をしているようです。

これも初期化の後に呼んでおきましょう。

 

通信プログラム

ここでようやく PIC の登場です。今回使用したのは PIC16F18326 です。SPI を使うための MSSPモジュールがあればいいと思います。

プログラムの全体は記事の最後に掲載するので、ここでは主要な部分だけ書きます。

 

データの形式は分からないですけど、とりあえず適当な値を送れば通信が出来ているかどうかは分かるでしょう。

いざ実験!

映らない!

 

まあいきなり上手くいくとは思ってませんよ。

とりあえず配線を間違えてないかを確認する。とここでふと電源電圧を確認していないことに気付く。何も考えずに 5V をかけていたけど大丈夫だろうか?

資料で電源について探してみると…

あ、3.3V だったわ。死んだわアイツ。(完)

 

でも今までの経験によると 3.3V のデバイスに 5V かけても案外死なないのでまだ生きてる可能性にかけて続けよう。

とりあえず電源を 3.3V に変更してもう一度チャレンジするも何も反応なし。

 

SPI のデバイスを他に持っていないので、そもそも SPI が正しく通信出来ているかが分からない。I2C は通信成功確認してるので多分大丈夫だと思うんだけど。

 

付属資料の中に他にもプログラムが入ってたんですが、そこでは SPI を GPIO によってソフトウェア的に実装していたので、いったんこれでやってみることにしました。

 

結果

生きてた!!

ということはおそらく SPI の通信に問題がありそうです。また私の経験によると、SPI の通信が上手くいかないときは大抵通信モードが間違っているので、総当たり作戦に行きます。

クロックの極性を Idle High に変更してみました。

結果

出来た!!

写真使いまわしてすみません。まあ表示されるもの同じなので許して。

ただしさっきのソフトウェア SPI に比べると何倍か速いです。やっぱりハードウェアで処理できるペリフェラルは速いんですねえ。

 

データ構造

先程はデータ構造も知らないまま適当なデータを送信して通信の成功を確認したわけですが、次はちゃんとした画像データを送信しましょう。

 

初期化コマンドの2つ目 (0x3A) を見てみると、これはデータの形式を設定するコマンドのようで、ここでは 16bit/pixel のモードになっているようです。

RGB interface についてはよく分かりません。

 

16bit/pixel のデータでは R, G, B がそれぞれ 5, 6, 5 bit ずつ割り当てられています。

ちなみに G に他よりも多くのビットが割り当てられているのは、人間の視覚特性として緑が最も感度が高いからです。

この 16 bit を 2回に分けて上位から送信します。

 

さて、データ形式も分かったところで表示させる画像を用意しましょう。

今回はひとまずこちらの私のアイコンを表示させてみることにしました。

この画像は 512×512 の png 画像なので、ひとまずペイントでサイズを 240×240 に変更します。

 

16bitビットマップ に変換すればいいのですが、それでもヘッダーのデータが含まれてたり上下が逆だったりして多少手を加えなければ、使えるデータにはなりません。

 

データ変換ツール作成

というわけで小見出しの通りデータ変換ツールを自作しました。

Visual Studio で C# を用いて作りました。

主なソースはこんな感じです。

17行目でそれぞれ 8bit の R, G, B の上位 5, 6, 5 ビットを取り出して 16bit の変数にまとめています。

ちなみに Windows はリトルエンディアンなので上位と下位を入れ替える必要があります。

 

PC は PIC と違って十分速いので、プログラムの効率とか考えずに適当に作ってます。

 

出来上がったデータは 240x240x2 = 115200 byte ある訳ですが、残念ながら PIC16F18326 はプログラムメモリでも 28 KB しかないので到底保存できません。

というわけで今回は PC から USART でデータを送信してそれをそのままディスプレイに流すという形にしたいと思います。

 

画像表示テスト

先程用意した画像データを TeraTerm を利用して送信します。

ウィンドウ左上の ファイル>ファイル送信 から送信するファイルを選択することができます。

このときオプションのバイナリにチェックを入れておきます。

PC と PIC の間には USB-シリアル変換モジュール を使用しています。このモジュールの出力は 3.3V なので PIC にそのまま接続できます。

 

プログラムはこんな感じです。USART で受信したデータを SPI で送信するだけです。

 

いざ実践!

なんか思ってたんと違う!

 

原因は割とすぐに見つかって、画像を変換するプログラムが間違ってました。(先程のプログラムは修正後のプログラムです。)

改めてデータ送信!

できた!大勝利!

 

ちなみに USART の速度は 115200 bps なので画像の描画には 8秒かかることになります。実測はおよそ10秒でした。

多少は描画速度を上げられると思いますが、動画を表示させたりするのは厳しいでしょうね。まあパラレルじゃなくてシリアルなのでそこは諦めるしかないでしょう。

 

ソースコード

ソースコードは こちら のページに載せてあります。一応ダウンロードも可能です。

 

エピローグ

というわけで無事に PIC でフルカラーLCD に画像を表示させることに成功しました。

本当はスッキリまとめた記事を書こうと思ってたんですけど、試行錯誤の過程を書いていたらすっかりいい文量になってしまったので、また別の記事にしたいと思います。

私自身電子工作でつまづいたときにどこかの誰かの電子工作日記に助けられたことが何度かあるので、この徒然なる記事もいつか誰かの役に立つと信じます。

 

それでは最後までご覧いただきありがとうございました。

-製作物

執筆者:


  1. STL より:

    STLと申します。
    現在、同じようなLCDを動作させようとしていて、こちらのサイトはとても参考にさせていただいています。
    データ変換ツール作成のプログラムについて、C#やVisual studioをあまり使ったことがなくプログラムの内容がいまいち理解できないのですが、プログラムの全体を見せていただくことは可能でしょうか?

    • きっちー より:

      記事の閲覧とコメントありがとうございます。
      すみませんが元のソースコードは見当たりませんでした。
      C#の機能以外に自分で定義した関数などは一切使用していないので調べれば情報は出てくるかと思います。
      どこが分からないのか教えてくれれば解説もしますが、今試したところChatGPTでこのコードの解説やほかの言語への変換をしてくれたので良かったら試してみてください。

  2. STL より:

    ご返信ありがとうございました。
    掲載されているコード以外の部分は、主にvisual studioが自動生成するコードでしょうか?
    コードの分からない箇所はChatGPTで調べてみたいと思います。

  3. STL より:

    もう一つお伺いしたいのですが、SPI通信のタイムチャートを見てみるとクロックは Idle Lowなのに、実際のクロックの設定をIdle Highにすると動作が上手くいったのでしょうか。私も同じドライバーICのLCDを使用していて、クロックの設定をIdle LowではなくIdle Highにすると動作したのですが、これがなぜなのか分かりますでしょうか?

    • きっちー より:

      >>掲載されているコード以外の部分は、主にvisual studioが自動生成するコードでしょうか?
      そういうことにはなりますが、せいぜいボタンを押したらこのコードを実行するようにしてるぐらいのものだったと思います。openFileDialog1.FileName, saveFileDialog1.FileNameの部分を何かしらの方法で読み込み・保存先のファイルのパスにすれば、大抵の言語で画像クラスなど同じような機能は提供されてると思います。ただし18行目のバイト列への変換はC#の独自色が強いと思います。
      uint8 rgb16_H = (c.R & 0xF8) | ((c.G >> 5) & 0x07);
      uint8 rgb16_L = ((c.G << 3) & 0xE0) | ((c.B >> 3) & 0x1F);
      のようにバイト単位で計算する方法ならどの言語でもできると思います。エンディアンも問題になりませんし。

      >>クロックの設定をIdle LowではなくIdle Highにすると動作したのですが、これがなぜなのか分かりますでしょうか?
      何故なのかはわかりません。当時は波形を見る手段がなかったのでデータシートのタイミングチャートと合っているかは確かめられていません。データシートが間違っている可能性があるかもしれませんね。

      • STL より:

        お答えいただきありがとうございました。
        画像変換のコードに関しては大分理解が進んできたので、自分でも書いてみます。

comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

USB給電の小型吸煙器を作ってみた

今回はUSB給電で動作する小型の吸煙器を作ってみました。 今まではんだ付けの際はヤニの煙を吸わないように気を付けながら行っていましたが、吸煙器を使うことでとても快適になりました。 もっと早く作ればよか …

オペアンプを使った積分型ADCを作ってみた

トランジスタ技術2022年4月号に掲載されていた積分型ADC (Analog to Digital Converter)の記事を見て、面白そうだったので実際にブレッドボードで作ってみました。 初めに言 …

1セル1基板のアナログライフゲーム作ってみた vol.1

普段は主に PIC を使って電子工作をしている私ですが、今回はマイコンを使わないでライフゲームを作ってみました。 ライフゲームを知らない人は恐らくこんな記事を読まないと思うので、ライフゲーム自体につい …

PICとグラフィックLCDでシンプルな卓上時計を作ってみた

今回はある程度実用的な卓上時計を作ってみました。日時の表示と温度、湿度、気圧の表示だけのシンプルな機能としました。   目次1 主な使用部品2 回路解説2.1 電源部2.2 RTC2.3 I …

1セル1基板のアナログライフゲーム作ってみた vol.3

前々回でライフゲーム基板、前回でクロックコントローラーを制作しました。 第3回の今回は関連アイテムを作って完成となります。 前々回、前回をまだご覧になっていない方は是非そちらを先にご覧ください。 1セ …