有機EL ( OLED ) SSD1306 を再検証してみました ( I2C 通信用 )

記事公開日:2017年10月16日
最終修正日:2017年10月17日

スポンサーリンク

こんばんは。

今回は、しばらく放置していた、I2C通信 OLED ( 有機EL ) SSD1306 を再検証してみました。
当ブログにちょくちょく質問やコメント、ご指摘をいただいたので、それもまとめてみたいと思います。

因みに、Adafruit さんや、その他の外部ライブラリは一切使いません。
Arduino core for ESP32 および ESP8266標準の Wire ライブラリのみを使います。
それだけで OLED SSD1306 を制御すると、ディスプレイドライブの仕組みが良く分かり、更にプログラミングを工夫すれば、 Adafruit さんのライブラリよりも軽い動作でサクサク動くと思われますので、皆さんも是非試してみてはいかがでしょうか。

I2C通信 OLED SSD1306 モジュール は、私の個人的意見ですが、通信速度が SPI より遙かに遅いし、グラフィック表示は極端にやりにくいし、とても使い辛いデバイスだと思っています。

個人的にはSSD1306よりも、同じくらいのサイズのOLEDでは、フルカラーで圧倒的に使いやすい SPI 通信の OLED SSD1331 が断然お勧めですね。

でも、日本の信頼できる販売店では(ちょっと割高ですが)秋月電子通商さんの Pmod OLED のみで、あとは中国販売店しかなく、到着までに10日~2週間くらいかかって、なかなか普及しないのが残念です。

それなのに、SSD1306の方はというと、いろいろなボードが発売されてきて、当方のブログでもSSD1306関連記事のアクセスが多く、質問やご指摘が多くなってきたので、私自身も無視できなくなってきました。

というわけで、今回は過去の以下の記事のプログラムを修正しつつ、更に一歩踏み込んで、I2C OLED SSD1306 を解明してみたいと思います。

I2C極小OLED(有機EL)SSD1306をArduinoでライブラリを使わずに動作させてみました

I2C極小OLED(有機EL)SSD1306をスクロールさせたり、もうちょっと深堀りしてみました

SPI通信用のものは、後日記事にしようと思っていますので、しばらくお待ちください。

使うもの

I2C通信用 OLED SSD1396 ディスプレイモジュール


この他にも以下の物がありますが、ここで買ったことはありません。

ESP-WROOM-32 ( ESP32 )開発ボード

ESP-WROOM-02 ( ESP8266 ) 開発ボード

ブレッドボード 及び ジャンパーワイヤー等

Arduino core for ESP32 および ESP8266 の設定

Arduino IDE は 1.8.5 で動作確認しております。

ESP-WROOM-32 ( ESP32 )の場合は、Arduino core for ESP32 を予めインストールしておいてください。
Arduino core for ESP32 は必ず最新版を使用してください。
インストール方法は以下の記事を参照してください。

Arduino core for the ESP32 のインストール方法

ESP-WROOM-02 ( ESP8266 )の場合は、Arduino core for the ESP8266 をインストールしておいてください。
インストール方法は以下の記事を参照してください。

Arduino IDE に Stable ( Staging )版 ESP8266 ボードをインストールする方法

有機EL ( OLED ) SSD1306 モジュールについて

有機EL ( OLED ) にディスプレイドライバ SSD1306 が組み込まれたモジュールです。
I2Cインターフェース用と、SPIインターフェース用が販売されています。
残念ながら、パラレル通信のものは見かけません。
ここで説明するのは、I2C通信用 128×96 pixel のものです。

I2C は通信線が2線で済み、モジュールにプルアップ抵抗が内蔵されているものが殆どなので、接続は簡単です。
ただ、通信周波数が最大 400kHz なので、SPI 通信より遙かに遅いです。

先ほども述べましたが、日本の販売店は今のところあまり見当たりません。
ただ、Amazon ではプライム対応のもの数店舗あり、種類も多く、入手しやすいです。

コマンドとデータの送信方法( I2C 通信 )

では、SSD1306 のデータシートに書かれている、コマンドとデータの送信方法を解明してみたいと思います。

実はこれ、2年くらい前に私がこのデバイスを使った時の以下の記事では、エライ勘違いをしていたんです。

I2C極小OLED(有機EL)SSD1306をArduinoでライブラリを使わずに動作させてみました

そして、以下の記事のコメント投稿欄で、MKさんから教えていただきました。

I2C極小OLED(有機EL)SSD1306をスクロールさせたり、もうちょっと深堀りしてみました

2年前はこのデバイスを使い始めたばかりで、しかもプログラミングを独学で始めたばかりだったので、何が悪いのかも良く分からず、とりあえず動いたので何となく使っていました。
I2C についてもあまり勉強せずに動かしていて、特に問題無かったのでそのまま使っていました。
その後、SPI通信のデバイスが高速なので、そちらに乗り換え、I2C を手放し放置状態にしていました。

それが、今頃になって、ようやくある程度正しい使い方が分ってきました。
やっぱり独学っていうのは穴だらけで、他の方やその道のプロの方々からご指摘を頂かないと、自分自身では間違いを発見できないですね。
今まで、当記事をご覧になって工作をしていただいた方々、大変失礼いたしました。
いずれにせよ、私は独学アマチュアなので、ご容赦いただきたいと思います。

では、まず、SSD1306 のデータシート内の下図の様な、I2C-bus data format を見てください。

ESP32_SSD1306_10

私はI2C通信についてはあまり詳しくありませんが、2年前はザッと見て理解したつもりになっていました。

これ、サラッと流して見て、理解した気になってプログラミングしてしまうと、実はエライ勘違いしてしまうんです。
正直言って、非常に分かりにくいです。
(ただ、実は後の英文で詳しく説明されていました・・・)

2年前、これを見た時、スレーブアドレスを送信した後、コマンドを連続で送り、その後データバイトを送っていました。
つまり、こんな感じです。

ESP32_SSD1306_11

当時はこれでも動いたんです!

ですが、何か変なノイズが出たり、思うように動作しないこともありました。
それは当時はあまり気にしていませんでした。

でも、コメント投稿欄で MKさんからご指摘を頂いて、初めて分かりました。

それに、実は、データシートのその後の英文で詳しく説明されていたんです。
Google 翻訳のお力を頂戴して、訳してみるとこんな感じです。

1)マスタ装置は、Start Condition  によりデータ通信を開始する。
Start Condition の定義を図8-8に示します。
Start Condition は、SCLがHIGHの間、SDAをHIGHからLOWに引き下げることによって確立されます。
(これは、シリアル通信のいわゆるスタートビット)

2)スレーブアドレスは Start Condition  の後に続きます。
SSD1306の場合、スレーブアドレスはSA0をLOWまたはHIGH(D / CピンがSA0として機能する)に変更することにより、 "b0111100"または "b0111101"のいずれかになります。

3)R/W# ビットを論理 "0"にすることにより、書き込みモードになります。

4)スレーブアドレスと R/W# ビットを含む1バイトのデータを受信した後、確認応答信号( ACK )が生成されます。
アクノリッジ信号( ACK )の図式表示については、図8-9を参照してください。
アクノリッジビット( ACK )は、アクノリッジ関連のクロックパルスのHIGH期間中にSDAラインがプルダウンされると定義されます。

5)スレーブアドレスの送信後、制御バイトまたはデータバイトのいずれかをSDAを介して送信することができる。
制御バイトは主に6つの "0"に続くCoビットと D/C# ビットで構成されます。
a. Coビットが論理「0」として設定されている場合、以下の情報の送信にはデータバイトのみが含まれます。
b. D/C# ビットは、次のデータバイトがコマンドまたはデータとして作用することを決定する。
D/C# ビットが論理「0」にセットされている場合、それは次のデータバイトをコマンドとして定義する。
D/C# ビットが論理「1」にセットされている場合、それは GDDRAM に記憶されるデータとして次のデータバイトを定義する。
GDDRAM 列アドレスポインタは、各データ書き込み後に自動的に1ずつ増加します。

6)アクノリッジビット ( ACK )は、各制御バイトまたはデータバイトを受信した後に生成されます。

7)Stop Conditionが適用されると書き込みモードが終了します。
停止条件は図8-8でも定義されています。
停止条件は、 "SCL"が "H"の間に "SDA in"をLOWからHIGHに引き上げることによって設定されます。
(これは、シリアル通信のいわゆるストップビット)

これをちゃんとじっくり読むとやっぱり理解できますね。
記事を書きながら、改めて「そうだったのか・・・」と気付いたりしています。

要するに、データシートはサラッと読み飛ばすのではなく、じっくり読み込むということがとても大事だということが分かりますね。
いゃぁ~・・・、反省しました。
でも、プログラミングを初めて間もない時だったので、ご容赦くださいませ。
m(_ _)m

I2C の アクノリッジ ( ACK ) については、須津技術研究所さんの、以下の記事が大変参考になります。

I2C ACK のはなし

要するに、データバイト等をスレーブデバイスの SSD1306 が受信したら、SSD1306自身が ACKビットを生成するということです。
それをマスターデバイス側であるESP32 が認識すれば、そのデータは有効ということになります。

Arduino IDE の場合、Wire ライブラリがあるので、あまり ACKビットとか気にしないでプログラミングしてしまいますね。
Arduino IDE は使いやすい分、正しい通信方法やプログラミング知識をスルーしてしまいがちなので、十分注意していかねばなりませんね。

以上を踏まえると、私が解釈した、I2C コマンドとデータの正しい送信手順はこんな感じです。

ESP32_SSD1306_12

これのポイントは、まず、コントロールバイトというものを必ず送るということです。
そして、データシートの m>=0 words というところで勘違いし易く、制御コマンドの場合は、コントロールバイトの後に1つの制御コマンドを送るということです。

制御コマンドの後に複数のコマンドを連続して送ることができません

これをつい最近まで気付かず、複数連続して送っていました。
それでも凝ったことをしなければ、動いてしまうところが勘違いの起きやすい点です。

制御コマンドを複数送る場合は、コントロールバイトと1つの制御コマンドを一組として、それを複数回送るということです。

そして、GDDRAM、いわゆるOLED に表示させる実ビットを書き込むデータの場合は、データ書き込み用コントロールバイトを送った後、連続してデータを送ることができます。

コントロールバイトはデータシートに書いてあるとおりで、特に難しいことはありません。
Co ビットは 0 にして、C/D# ビットが 0 の場合は制御コマンド、1 の場合はデータということです。
その後 6 ビットは全て 0 です。

制御コマンド用コントロールバイト→ 00000000
ディスプレイ表示データ用コントロールバイト→ 01000000

このコントロールバイトを適切に設定しないと、変に画面のオフセットがかかったり、変なノイズが画面に出たりします。
ということで、このコントロールバイトは極めて重要でしたね。
MKさんに教えていただいて、これに気付いたのがつい最近です。
MKさん、ホントにありがとうございました。
そして、皆さま、今まで勘違いしていてスミマセン・・・。
m(_ _)m

そもそも英語力が無いのも原因でした・・・。
Google翻訳に感謝!

スレーブアドレスについては次で説明します。

スポンサーリンク


mgo-tec電子工作 関連コンテンツ ( 広告含む )

投稿者:

mgo-tec

Arduino , ESP32 ( ESP-WROOM-32 ) , ESP8266 ( ESP-WROOM-02 )等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってますので、動作保証はしません。
電子回路やプログラミングの専門家ではありません。
畑違いの仕事をしてます。
でも、少しだけ電気の知識が必要な仕事なので、電気工事士や工事担任者等の資格は持ってます。

コメントを残す

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

*画像の文字を入力してください。(スパム防止の為)