トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS

DIY/mbed/OLED

Last-modified: 2015-05-24 (日) 02:26:09 (936d)
Top / DIY / mbed / OLED

DIY/mbed

aitendo の OLED

mbed_oled1.jpg


部屋の隅に昔買った aitendo の OLED が転がってました。
型番は IFB-095BWNNJ9-SPI。
今日はこれを mbed で点灯させてみます。

接続

もう aitendo では売っていないシロモノらしく、商品ページはないのですが、
型番でググると PDF がありました。
"IFB-095BWNNJ9-SPI_aitendo.pdf"

これをざっと見ると

  • 96x64 の液晶ドライバ + OLED
  • SPI で制御

と言った感じのようですね。ざっとし過ぎかな?(^^;)

何はともあれまずは mbed と接続ですね。
このモジュールで接続すべきピンは全部で7本。

  • VDD : 3.3V を供給します。
  • /RES : リセット。負論理なので 0 にするとリセットが掛かる。
  • /CS1 : チップセレクト。負論理なので 0 の間 SPI でモジュールが制御可能になる。
  • CLK : SPI のクロックを供給します。
  • MOSI : Master In Slave Out。mbed からのデータはここからモジュールに入力される。
  • DC : Data/Command 制御ピン。DC が High の間は MOSI のデータはディスプレイデータとして扱われる。一方 DC が Low の間は MOSI のデータはディスプレイコントローラの制御コマンドとして扱われる。
  • GND : GND に接続します。

以上より以下のようにつないでみました。
PA_0、PA_1、PA_4 は他のピンにしても全然 OK。

  • VDD <-> 3V3
  • /RES <-> PA_0
  • /CS1 <-> PA_1
  • CLK <-> SPI_SCK (PA_5)
  • MOSI <-> SPI_MOSI (PA_7)
  • DC <-> PA_4

mbed_oled2.jpg


大仰になってしまってますねー。
モジュールにはピンヘッダ接続でなくピンソケット接続にしとけば良かったなーと。。

初期化

aitendo の PDF に AVR 用のサンプルコードが載っていたのでパクらせてもらいます。
やっぱりまずは動くところを見たいですよね。。

  1. #include "mbed.h"
  2.  
  3. SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK);
  4.  
  5. DigitalOut res(PA_0);
  6. DigitalOut cs(PA_1);
  7. DigitalOut dc(PA_4);
  8.  
  9. void OLED_Init(void)
  10. {
  11.     cs = 0;
  12.     dc = 0;
  13.  
  14.     spi.frequency(24000000); // 24MHz
  15.  
  16.     // reset
  17.     res = 0;   
  18.     wait_us(20);
  19.     res = 1;
  20.     wait_us(20);
  21.  
  22.     spi.write(0xae); // OLED display OFF
  23.  
  24.     spi.write(0x75); // Set Row Address
  25.     spi.write(0x00); // Start = 0
  26.     spi.write(0x3f); // End = 63
  27.  
  28.     spi.write(0x15); // Set Column Address
  29.     spi.write(0x00); // Start = 0
  30.     spi.write(0x5f); // End = 95
  31.  
  32.     // contrast
  33.     spi.write(0xa0); // Set remap & data format 0111 0000
  34.     spi.write(0x70);
  35.     spi.write(0xa1); // Set Display Start Line
  36.     spi.write(0x00);
  37.     spi.write(0xa2); // Set Display offset
  38.     spi.write(0x00);
  39.     spi.write(0xa4); // Set Display Mode
  40.     spi.write(0xa8); // Set Multiplex Ratio
  41.     spi.write(0x3f);
  42.     spi.write(0xad); // Set Master Configuration
  43.     spi.write(0x8f); // (External VCC Supply Selected)
  44.     spi.write(0xb0); // Set Power Saving Mode
  45.     spi.write(0x1a);
  46.     spi.write(0xb1); // Set Phase 1 & 2 Period Adjustment
  47.     spi.write(0x74);
  48.     spi.write(0xb3); // Set Display Clock Divide Ratio / Oscillator Frequency
  49.     spi.write(0xd0);
  50.     spi.write(0x8a); // Set Second Pre-charge Speed of Color A
  51.     spi.write(0x81);
  52.     spi.write(0x8b); // Set Second Pre-charge Speed of Color B
  53.     spi.write(0x82);
  54.     spi.write(0x8c); // Set Second Pre-charge Speed of Color C
  55.     spi.write(0x83);
  56.     spi.write(0xbb); // Set Pre-charge Level
  57.     spi.write(0x3e);
  58.  
  59.     spi.write(0xbe); // Set VCOMH
  60.     spi.write(0x3e);
  61.     spi.write(0x87); // Set Master Current Control
  62.     spi.write(0x0f);
  63.     spi.write(0x81); // Set Contrast Control for Color A
  64.     spi.write(0x80);
  65.     spi.write(0x82); // Set Contrast Control for Color B
  66.     spi.write(0x80);
  67.     spi.write(0x83); // Set Contrast Control for Color C
  68.     spi.write(0x80);
  69.     spi.write(0xaf); // OLED display ON
  70. }
  71.  
  72. int main()
  73. {
  74.     OLED_Init();
  75.  
  76.     while (1)
  77.     {
  78.         wait(0.016);
  79.     }
  80. }


PDF にあった OLED_Init をベタ移植です。
コードを見ると画面を消してその間に諸々設定、終わったら画面を付ける、と。
細かいところは全然分かりません(汗

mbed_oled3.jpg


結果、安心(?)の砂嵐が出てきました(^^)

単色塗りつぶし

初期化は上手く行っているようなので、
今度は画面を単色で塗りつぶしてみます。

  1. #include "mbed.h"
  2.  
  3. SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK);
  4.  
  5. DigitalOut res(PA_0);
  6. DigitalOut cs(PA_1);
  7. DigitalOut dc(PA_4);
  8.  
  9. InterruptIn myButton(USER_BUTTON);
  10.  
  11. enum Color
  12. {
  13.     Color_Red,
  14.     Color_Green,
  15.     Color_Blue
  16. };
  17. int desireColor;
  18.  
  19. int getColorValue(int color)
  20. {
  21.     switch (color)
  22.     {
  23.         case 0 : return 0x001f;
  24.         case 1 : return 0x07e0;
  25.         case 2 : return 0xf800;
  26.     }
  27.     return 0x0;
  28. }
  29.  
  30. void pressed()
  31. {
  32.     desireColor++;
  33.     if (desireColor > Color_Blue)
  34.     {
  35.         desireColor = Color_Red;
  36.     }
  37. }
  38.  
  39. void OLED_Init(void)
  40. {
  41.     // 省略
  42. }
  43.  
  44. void Full_OLED_Screen(unsigned int color)
  45. {
  46.     unsigned char x;
  47.     unsigned char y;
  48.  
  49.     dc = 1;
  50.  
  51.     for (y = 0; y < 64; y++)
  52.     {
  53.         for (x = 0; x < 96; x++)
  54.         {
  55.             spi.write((color >> 8) & 0xff);
  56.             spi.write(color & 0xff);
  57.         }
  58.     }
  59. }
  60.  
  61. int main()
  62. {
  63.     int nowColor = Color_Red;
  64.     desireColor = Color_Red;
  65.  
  66.     OLED_Init();
  67.  
  68.     Full_OLED_Screen(getColorValue(nowColor));   
  69.  
  70.     myButton.fall(&pressed);
  71.  
  72.     while (1)
  73.     {
  74.         if (nowColor != desireColor)
  75.         {
  76.             Full_OLED_Screen(getColorValue(desireColor));
  77.             nowColor = desireColor;
  78.         }
  79.         wait(0.016);
  80.     }
  81. }


上述したように DC を High にするとその間はディスプレイデータになるそうなので、
dc = 1 にして 16bit の RGB データを 8bit づつ SPI で流し込みます。

ボタンを押すたびに赤 -> 緑 -> 青 -> 赤 ... と切り替えていくプログラムです。


動画で見ると写りが荒いのもあって上手く行っているように見えるんですが、
拡大してみると・・・。

mbed_oled4.jpg


右下に青いピクセルがあるのが分かりますでしょうか?
そうなんです、前のピクセル(赤の時は青、緑の時は赤、青の時は緑)が残ってしまっているのです。
ちゃんと Full_OLED_Screen 関数で 96 x 64 回分ピクセルを描いているのに、です。

いろいろ試行錯誤してみたのですけれどどうも上手くいかない。
例えば最後のピクセルだけおかしなことになっているので、
追加で 1 ピクセル分(spi.write としては2回)描いてみると全部塗りつぶされるのですけど、
切り替えの時に左上(描画の始めですね)に一瞬前のピクセルがちらほら出てきてしまったり・・・。

SSD1132

そんなわけで aitendo の PDF をマジメに読み始めたのですが、
ディスプレイ制御のコマンドが全部リストアップされていないんですよね。
サンプルコードには出てきているコマンドの説明が無かったので。

IFB-095BWNNJ9-SPI モジュールはディスプレイコントローラに SSD1132 を使用しているようなので、このコントローラの仕様書を探してみました。
結果、"Treiber_IC-SSD1332_OLED_96x64_COLOR.pdf" という PDF をゲット。

Graphic Acceleration Command

こっちにはコマンドが全部書いてありました(^^)
その中に "Graphic Acceleration Command Set Table" という気になる表が!
どうも SSD1132 には線を描いたり矩形を描いたり、
といった描画を楽にするコマンド群があるようです。
使わない手は無いですね!

"Clear Window" というコマンドがその名の通り画面をクリアするものらしく、
今回の目的にピッタリだと思ったのですが、
これは色指定できず黒一色にするものでしたのでダメ。

結局、上手く行ったのは以下のようなコードになりました。
Full_OLED_Screen 関数だけ提示しますね。

  1. void Full_OLED_Screen(unsigned int color)
  2. {
  3.     unsigned char red, green, blue;
  4.  
  5.     red = (color & 0x001f) << 1;
  6.     green = (color & 0x07e0) >> 5;
  7.     blue = (color & 0xf800) >> 10;
  8.  
  9.     // command register mode
  10.     dc = 0;
  11.  
  12.     spi.write(0x26); // Fill Enable
  13.     spi.write(0x01);
  14.  
  15.     spi.write(0x22);    // Drawing Rectangle
  16.     spi.write(0);       // Column Address of Start
  17.     spi.write(0);       // Row Address of Start
  18.     spi.write(95);      // Column Address of End
  19.     spi.write(63);      // Row Address of End
  20.     spi.write(blue);    // Color C of the line
  21.     spi.write(green);   // Color B of the line
  22.     spi.write(red);     // Color A of the line
  23.     spi.write(blue);    // Color C of the fill area
  24.     spi.write(green);   // Color B of the fill area
  25.     spi.write(red);     // Color A of the fill area
  26. }


戦略としては、

  • Fill Enable コマンドで Drawing Rectangle コマンドの時に矩形内を塗りつぶすように設定
  • そのあと、Drawing Rectangle コマンドで OLED 全体を指定
  • Color A, B, C は赤、緑、青と対応しているので、ビット演算して 16bit カラーを RGB565 に分解

としてみました。
結果、

mbed_oled5.jpg


真っ青になりました~(いい意味で)

まとめ

初期化、単色塗りつぶしまでは上手く行きました。
小さいながらも OLED なので結構キレイです。

今のところは素直に動くデバイスだなあという印象です。

次は画像表示にチャレンジしてみたいですね。


2015/05/24 : 1st