[トップページへ戻る]

UG-2864HSWEG01/SSD1306 I2Cで動作テスト

2013年10月(製作)/2013年11月(記事公開)
OLEDをI2C接続で使ってみました。よくあるグラフィックLCDと使い方は同じだろう、サクッと表示テスト。…と思ったのですが、すんなりとは行きませんでした。
配線、文字データ作成、描画方法について、やったこと/分かったことをまとめました。


接続方法と配線図について

初めて動作したときの様子
ディスプレイデバイスを動かすにはディスプレイとコントローラ(ディスプレイドライバ)のデータシートを見ることになります。今回使用したOLEDのコントローラはSSD1306です。ディスプレイ部は乗せるディスプレイの仕様によりデータシートが異なるので、製品の型番で検索します。ここでは次の2つを参考にしました。
・SSD1306 / Rev 1.5 / Aug 2010
・UG-2864HSWEG01(Doc. No: SAS1-9046-B)

コントローラSSD1306とマイコンを接続する方法は、68系/80系パラレル接続、SPIの他、I2Cにも対応しています。ディスプレイ部に必要な電圧(ロジック部の電圧の3〜4倍)は内蔵DC/DC(チャージポンプ)で生成できるので、OLEDは単一電源で動かせます。

今回の工作ではこのOLEDを、I2C接続、内蔵DC/DC利用、3.3V単一電源で動かしています。
データシートの説明は基本的に、パラレル接続かSPI、かつ、ディスプレイ部の電源を外部供給するパターンで使うことを想定している感じです。I2Cかつ内蔵DC/DC利用のパターンで使うつもりでデータシートを読むと、説明が矛盾していたり分かりにくかったりする点があり、実際に動かせるようになるまで何カ所か勘違いしました。

データシートの図と端子の説明に不満があったので、まとめの意味でも自分で描いてみました。


手持ちの部品で間に合わせてよいか?と考えた場合… VCCのコンデンサ2.2uFはチャージポンプの最終段のはずなので、10uFくらいまでで適当に決めて構わないと思います。VCOMHを使わないなら、このコンデンサも適当な容量でいいと思います。※確定的な根拠はありません。自己責任で。
IREFの400kΩは、VCCの電圧(チャージポンプの電圧)を7.5Vとしたときの計算値です。近い値なら問題ないでしょう。外れた値でも輝度調整に影響が出るだけです。※計算式やこの抵抗が何なのかはデータシートに説明あり。
I2Cでは未使用のデータ線D3〜D7は、実は未配線のままでも動作しています。ですがデータシート通りGND接続が好ましいと思います。※ハンダ付けが辛くてサボった。
【協力】 @tomozhさん @T_colonさん (Twitter)

文字データ(フォント)を作る
グラフィックディスプレイはキャラクタLCDのように文字データを内蔵していないので、利用者が自前で用意し、「描画」します。グラフィックディスプレイに文字、記号、画像の区別はなく、表示するデータはすべて画像として扱います。

キャラクタLCDのフォントデータを作成する
電子工作でお馴染みのキャラクタLCDモジュールといえば、SC1602などHD44780互換コントローラ搭載のものです。これのフォントを使いたくてフォントデータを作成しました。LCDのハードから内蔵データを読み込むのではなく、データシートの文字コード表を画像処理してデータ化しています。半自動、人力OCRです。
pdf(dpi単位)をスクリーンキャプチャしてbmp(ドット単位)にする都合上、枠線、マス目、文字形のドットの大きさは微妙に不揃いとなります。bmp画像を整形したり、いびつなドットを読み取れるようプログラム側で対策します。

プログラム
フォントデータ作成アプリ ダウンロード
CharLCDFontCreator_and_imgsrc.zip
EXEファイル、C#のソース他、プロジェクトのファイル一式
画像ファイル、出力サンプルを含む
開発環境:Windows7/64bit, .NetFramework4, VisualStudio2010Exp./C#

表示例 (1)データシート (2)整形した画像 (3)出力されたフォントデータ

コンソールアプリです。
(1)HD44780のデータシートの文字コード表のページを、サイズ100%でスクリーンキャプチャします。
(2)行/列がところどころ1ドット広かったり狭かったりするので、同じ幅に修正します。
 マス内の字形自体は、どれも各マスの中で同じ位置関係にあるようなので、修正する必要はありません。
(3)プログラムに(2)の画像を読み込ませるとPC画面に結果が出力されます。リダイレクトしてファイルに保存します。
※リダイレクトするとキー入力待ちメッセージが表示されないのでプログラムが暴走したように見えます。何かキーを押せば正しく終了します。
※写真は表示例です。上記zipにhexファイルは含まれません。

フォントデータは「byte font[ ][ ]」の形(ジャグ配列)で利用することを想定した書式で出力されます。ただし変数の宣言部分はないので、プログラムに合わせて記述を付け足してください。不要なデータを削除して容量を削減したり、英数カナの種別で配列を分けたりしてもよいと思います。

グラフィックディスプレイの画像メモリについて
モノクロ・グラフィックディスプレイは、画面上では1ドット単位で画像を表現していますが、画像メモリ上は1ドット単位ではなく、その点を含む上下8ドット単位で処理されます。1ドットの情報は点灯(1)/消灯(0)なので1ビットで足ります。従ってデータの書き込みは8ビット(1バイト)単位となります。
画像メモリ(GDDRAM)は縦8ドットで区切られた「ページ」という単位で管理されています。さらに各ページは横1ドット単位の「セグメント」に区切られています。画像データの書き込みとは、セグメントに対する書き込みに他なりません。

ページ/セグメント

※SSD1306データシートより。
※リンク先画像 840x1160

画像データをセグメントに書き込むとき、0は透明色ではなく、黒(背景色)で塗ることを意味します
1を書くと「点灯」。0を書くと「現状のまま」ではなく「消灯」です。勘違いしないよう注意してください。

既に点灯しているドットに影響を与えず別のドットを点灯させるには、セグメントの現在の点灯状態に新しいドットの値を重ねて(論理OR)そのセグメントに書き込む、という手順になります。
図のように、2ドット描かれているセグメントに新規1ドットを追加するとき、新規1ドットだけのデータを書き込むと既存の2ドットは消えてしまいます。既存の2ドットとORを取ったデータを書き込むと、目的の形で描画されます。

フレームバッファを活用する
グラフィックディスプレイとマイコンの接続方法によっては、セグメントの状態をハードから読み込む方法がありません。そのため、セグメントの状態をソフト上に持っておく必要があります。その仕組みがフレームバッファです。
フレームバッファはマイコンのSRAM上のbyte配列です。1バイトを実画面の1セグメントに見立て、メモリ上に仮想画面を用意したものです。プログラム中の描画操作はフレームバッファに対して行い、適当なタイミングでフレームバッファの内容を実画面へ転送します。こうすることで実画面上の現在の描画状態を気にすることなく(上書きだのドットが消えるだの)、真の1ドット単位の描画処理ができるようになります。ページの区切りを意識する必要もありません。

グラフィックディスプレイの使い方によってはフレームバッファは必要ありません。例えばキャラクタLCDのように決まった形の文字やアイコン画像を常に上書き表示する場合です。ただし画像の大きさと描画位置に関して、縦は8ドット単位(ページの高さ単位)という制限が付きます。

【参考】
128x64ドットのモノクロ・グラフィックディスプレイで8ドットを1byteで表現すると、マイコンのSRAMは
128 x 64 / 8 = 1024byte(1KB) 必要です。
例えばATmega328PはSRAMが2KBあるので1KB分のフレームバッファを取るのは余裕です。
ATmega48/88/168はSRAMが1KBしかなく、全部をフレームバッファに使うとプログラムが動きません。実画面の半分だけフレームバッファ、残りはGDDRAMへ直接描画といった工夫が必要です。※さもなくば素直にATmega328Pを使います。

【参考】
GDDRAMへのデータ書き込み方向は、ページ単位、水平方向優先、垂直方向優先の3通りあります。
ページ単位モードは、1行(ページ)の末尾からその行の先頭へ戻ります。文字表示専用の1行といった使い方のときに便利だと思います。長い文字列を1ページ内でグルグルと上書き表示する動作です。
水平方向優先モードは、水平に1行表示し終わると、次の行の先頭(左端)へ戻ります。ほとんどの描画処理はこのモードを使うことになると思います。
垂直方向優先モードは、垂直に1列表示し終わると、次の列の先頭(上端)へ戻ります。この方法は文字(フォントデータ)を拡大表示するのに便利かもしれません。今回作成した文字データは1文字が5x7ドットで、幅1ドットごとに縦1byteの値で作られています。5byteで1文字です。2倍に拡大表示する場合、まずGDDRAMの描画範囲に縦2ページ分(16ドット)を指定します。文字データを1byte読んで縦2倍に拡大し(2byte)、GDDRAMへ2byte書き込めば自動的に縦方向に配置されます。同じ2byteをもう一度書き込むと隣の列に配置されます(横2倍の分)。これを文字データ5byte分繰り返すと2倍に拡大された文字が表示されます。…長々と説明しましたが、描画時に1文字分のデータ(5byte)全体を読み込まずとも1byteずつ読み捨てで処理できるということです。
※その程度のメモリ節約がナンボのもんだ!という話ですね。無理矢理考えました。正直なところ、使いどころがよく分かりません。

描画デモ
I2C-EEPROM使用 湿度温度ロガーお試し版」で予告したロガー第2弾に使うつもりで画面イメージを作りました。※グラフは画面作り用の偽データ。
ATmega88(SRAM:1KB)で動作しています。画像メモリ8ページ中、上下1ページは直接描画、中6ページはフレームバッファ適用で、SRAMは768byte使用しています。
描画関数は自作です。GDDRAM直接描画の他、フレームバッファに対応し、上記の通り同時利用できます。描画内容は、点、線、文字、文字列の描画。矩形領域の塗りつぶしと消去。装飾機能として白黒反転描画。

プログラム
ファームウェア
ダウンロード SSD1306_demo.zip
HEXファイル、Cのソース他、プロジェクトのファイル一式
開発環境:Windows7/64bit, AtmelStudio6
上記写真の画像を表示するプログラムです。I2C-SSD1306ライブラリ的なものを含みます。文字データの組み込み方/使い方も参考になるかもしれません。

部品について
OLEDはAliExpressで購入。aitendoで販売しているUG-2864HLBEG01と恐らく同一のものです。
モノクロ…ということは色による表現力は考えないので、白色にこだわらず青色のものを選んでみました。

基板にポリイミドテープを貼り、基板の穴をふさぎます。ハンダ付けしやすくするため。
そこに端子が乗るようにOLEDを置き、表示部のウラを両面テープで留めます。
端子はUEW(ポリウレタン銅線)でハンダ付け。
最後に保護と絶縁のため、ハンダ付けしたところをポリイミドテープで覆って完成。
マイコンとの接続用に、VCC、GND、リセット、SA0(スレーブアドレスの一部)、SCL、SDAをピンソケットで出しました。


◆ ◆ ◆
実は初めてモノクロ・グラフィックディスプレイを使いました。
知ってる人には今さらですが、ページ単位でメモリ管理していることを今回知りました。
描画ライブラリを作り込みたくなりつつも、最小限の単純な機能に抑えました。
でも洒落っ気を出して反転描画だけは取り入れました。
OLEDの端子のピッチが狭くてハンダ付けに苦労したので、専用基板を起こしたくなりました。


(C) 『昼夜逆転』工作室 [トップページへ戻る]
inserted by FC2 system