概要
NanoPi-NEOでLCDやOLEDなどいろいろ繋いで表示させてみます。
今回のターゲットは下記の通り。
既存の表示ライブラリ等は一切使わず、画像(Gray/BGRA)表示のみに特化し、C++でフルスクラッチで作ってみた。
つまり、gpio,spi,i2cすべてLinux直叩きである。
コントローラ | IF | パネルサイズ | 解像度 | タイプ |
---|---|---|---|---|
SSD1306 (NanoHatOLED) | I2C | 0.96 inch | 128x64 | OLED (2値) |
SH1106 | I2C | 1.3 inch | 128x64 (132x64) | OLED (2値) |
ILI9341 (2.2") | 4wire SPI | 2.2 inch | 240x320 | TFT LCD |
ILI9341 (2.4", TouchPanel) | 4wire SPI | 2.4 inch | 240x320 | TFT LCD |
ILI9328 | 3wire SPI ?? | 2.2 inch | 240x320 | TFT LCD |
ILI9225 | 4wire SPI | 2.2 inch | 176x220 | TFT LCD |
ST7735 | 4wire SPI | 1.8 inch | 128x160 | TFT LCD |
また、一般的にLCDやOLEDと呼ばれるのは以下の集合体のことである。
- コントローラIC
- OLED/LCDパネル
- 通信信号以外の配線部
つまり、通信して表示させようとした場合、コントローラ以外の部分の仕様も影響してくる。
よくあるのが、RGB/BGRフォーマット、上下反転、左右反転、左端が欠落する。など、配線部により決定する部分である。
この場合は必要に応じソフトウェア的に対処する。
ソースコード
ソースは、こちら。
https://github.com/blue777/NanoPi-NEO
g++ -O3 -pthread -std=c++11 Test_display.cpp `pkg-config --cflags opencv` `pkg-config --libs opencv`
今回関連するファイルは以下の通り。
File | Description |
---|---|
Test_display.cpp | テスト用アプリ |
common/ctrl_gpio.h | GPIO制御用クラス |
common/ctrl_i2c.h | I2C制御用クラス |
common/ctrl_spi.h | SPI制御用クラス |
common/display_if.h | ディスプレイ統一IFクラス |
common/display_ssd1306_i2c.h | SSD1306(i2c接続版) |
common/display_rgb565_spi.h | SPI接続ディスプレイ用ベースクラス |
common/display_ili9225_spi.h | ILI9225用 |
common/display_ili9328_spi.h | ILI9328用 |
common/display_ili9341_spi.h | ILI9341用 |
common/display_st7735_spi.h | ST7735用 |
common/img_conv.h | 画像フォーマット変換用 |
common/img_halftone.h | 誤差拡散2値化処理用 |
表示系IFは、display_if.hを継承使用し、統一している。
配線・デバイス依存部は、コンストラクタへ集約。
ディスプレイ統一IFのメソッドは下記の人たち。
関数名 | 概要 |
---|---|
Init() | デバイス初期化。表示はまだされない |
GetSize() | ディスプレイサイズの取得。Init()~Quit()間で有効 |
DispClear() | 黒で全面初期化する |
WriteImageGRAY(x,y,data,stride,width,height) | グレー(8bit)画像の転送。x,yが転送先の位置 |
WriteImageBGRA(x,y,data,stride,width,height) | カラー(8bit x4)画像の転送。x,yが転送先の位置 |
DispOn() | 表示の開始 |
DispOff() | 表示の終了 |
Quit() | デバイスの終了 |
NanoPi-NEO(2)のGPIO PinLayout
本家:
http://wiki.friendlyarm.com/wiki/index.php/NanoPi_NEO
http://wiki.friendlyarm.com/wiki/index.php/NanoPi_NEO2
以下の通りである。詳細は本家を参照してください。
Linux gpio | Name | Pin# | Pin# | Name | Linux gpio |
---|---|---|---|---|---|
SYS_3.3V | 1 | 2 | VDD_5V | ||
I2C0_SDA | 3 | 4 | VDD_5V | ||
I2C0_SCL | 5 | 6 | GND | ||
203 | GPIOG11 | 7 | 8 | UART1_TX/GPIOG6 | 198 |
GND | 9 | 10 | UART1_RX/GPIOG7 | 199 | |
0 | UART2_TX/GPIOA0 | 11 | 12 | GPIOA6 | 6 |
2 | UART2_RTS/GPIOA2 | 13 | 14 | GND | |
3 | UART2_CTS/GPIOA3 | 15 | 16 | UART1_RTS/GPIOG8 | 200 |
SYS_3.3V | 17 | 18 | UART1_CTS/GPIOG9 | 201 | |
64 | SPI0_MOSI/GPIOC0 | 19 | 20 | GND | |
65 | SPI0_MISO/GPIOC1 | 21 | 22 | UART2_RX/GPIOA1 | 1 |
66 | SPI0_CLK/GPIOC2 | 23 | 24 | SPI0_CS/GPIOC3 | 67 |
OLED系
今回はSSD1306とSH1106の2種。
コマンドは、ほぼ共通でSSD1306の方が高機能になっており、描画コマンドも多い。
SSD1306 (NanoHatOLED - i2c 接続)
概要
入手元:
http://www.friendlyarm.com/index.php?route=product/product&product_id=191
$6.99
インスタンス生成:
Display_SSD1306_i2c(180); // for SSD1306
配線
NanoHatOLEDなので、NanoPi-NEO(2)に載せるだけ。
回路図は以下にあるが、制御に必要となる信号線は4本のみである。
http://wiki.friendlyarm.com/wiki/images/c/c3/SCHEMATIC_NanoHat_OLED-1703_v1.0.pdf
SH1106 (i2c接続)
概要
入手元:
https://www.amazon.co.jp/gp/product/B01MF97E87/ref=oh_aui_detailpage_o05_s00?ie=UTF8&psc=1
¥720
ソースコードもSSD1306と共通で、Display_SSD1306_i2c(rotate,xoffset) の、xoffset=2を設定すれば問題なく動く
インスタンス生成:
Display_SSD1306_i2c(180,2); // for SH1106
配線
SPI版もあるが今回はi2c接続版のため下記の通り接続すればOK
SH1106 (i2c) | NanoPi-NEO(2) PinName | NanoPi-NEO(2) Pin# |
---|---|---|
VCC | SYS_3.3V | 1 |
GND | GND | 9 |
SCL | I2C0_SCL | 5 |
SDA | I2C0_SDA | 3 |
LCD系
一般的な4wire SPI接続であれば、以下の7本が必要となる。
(LCDコントローラチップからのデータ読み出し行う場合は+1本)
- VCC
- GND
- D/C (Data/Command select。GPIOで個別制御)
- RESET (リセット信号。GPIOで個別制御)
- SPI0_CLK (クロック)
- SPI0_MOSI (データ)
- SPI0_CS (Chip select)
ソースコードでは、上記に加えバックライトOn/Off制御用に1本追加となる。
SPI0_MISO/GPIOC1はSPI通信のデータ受信用だが、データ受信しないため、バックライト制御用GPIOとして使用する。
NanoPi-NEO(2)のGPIO PinLayoutを元に、配線を集中させるよう検討した結果、下側の8本(Pin#17~24)に完結できた。(笑
バックライト制御
上記ソースコードでは、DispOn/DispOff でバックライト制御もできるようにGPIO出力している。
通常、バックライトは WhiteLED のため、3.3vの電源でそのまま使用できる(ことが多い)。
接続例に分けて4種類記載してみる。
工作といえど、バックライトOn/Off制御は見栄えが良い(笑
そもそも制御しない
ソースコードでは、GPIOポートに-1を設定すればGPIO制御が無効化できるようにしています。
バックライトのLEDは直接電源に接続すればOK。
GPIO直接制御版
GPIOの出力電流で十分賄える場合である。
例えば、NanoPi-NEO(2)の場合、最大20mA出力できる模様。
20mAに収まるLCDパネルのバックライトであれば、そのまま接続でOK.
LEDのカソード(-)側で制御
100mA未満であれば、希少品の2SC1815で十分かな。
回路図は一般的な工作例なので、本気組の方はLTSpice等でちゃんと設計しましょう。
LEDのアノード(+)側で制御
100mA未満であれば、希少品の2SC1815と2SA1015で十分かな。
回路図は一般的な工作例なので、本気組の方はLTSpice等でちゃんと設計しましょう。
ILI9341 (240x320, 2.2inch)
概要
入手元:
https://www.amazon.co.jp/gp/product/B01CZL6QIQ/ref=oh_aui_detailpage_o03_s00?ie=UTF8&psc=1
¥980
軽く見てみた限り、割と有名なチップ。
QVGA対応なので、ほぼ標準品的な位置づけであるとも言えるかもしれない。
また、液晶パネルサイズも、2.2inch, 2.4inch, 2.8inch, 3.2inchとバリエーション豊かである。
インスタンス生成:
Display_ILI9341_spi_TM22(0); // for Tianma2.2" Panel
配線
バックライトLEDをGPIOでOn/Offする場合の結線方法である。
SPI0_MISO/GPIOC1はSPI通信のデータ受信側だが、データ受信しないため、GPIOとして使用する。
On/Off制御が不要な場合は、LEDをSYS_3.3Vへ繋げば良い。
ILI9341 | NanoPi-NEO(2) PinName | NanoPi-NEO(2) Pin# | 備考 |
---|---|---|---|
SDO/MISO | - | - | LCDのデータ読むときに必要 |
LED | LEDのアノード(+)側で制御 | 21 | SPI0_MISO/GPIOC1 (gpio65) Pin#21で制御 |
SCK | SPI0_CLK/GPIOC2 | 23 | |
SDI/MOSI | SPI0_MOSI/GPIOC0 | 19 | |
DC/RS | UART2_RX/GPIOA1 | 22 | D/C制御用GPIO (gpio1) |
RESET | UART1_CTS/GPIOG9 | 18 | Reset制御用GPIO (gpio201) |
CS | SPI0_CS/GPIOC3 | 24 | |
GND | GND | 20 | |
VCC | SYS_3.3V | 17 |
バックライトについて
バックライトの消費電流 : 2.45mA @ 3.3v
SYS_3.3Vに接続ででOnになる。
消費電流的に制御回路入っている模様なので、GPIO直接ドライブでもOK.
ただし、知らぬ間に仕様変更されることもあるので、基本的には、LEDのアノード(+)側で制御 で制御するのが無難
ILI9341 (240x320, 2.4inch, TouchPanel)
概要
入手元:
https://www.amazon.co.jp/gp/product/B071KBS7MD/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1
¥890
タッチパネル付きだけど、今回タッチパネルは使用しない。
そして、タッチパネルICの仕様もまったくもって不明である。
インスタンス生成:
Display_ILI9341_spi_TM24(180); // for Tianma2.4" Panel
配線
ILI9341 2.4" Touch | NanoPi-NEO(2) PinName | NanoPi-NEO(2) Pin# | 備考 |
---|---|---|---|
T-IRQ | - | - | TouchPanel関係 |
T-DO | - | - | TouchPanel関係 |
T-DIN | - | - | TouchPanel関係 |
T-CS | - | - | TouchPanel関係 |
T-CLK | - | - | TouchPanel関係 |
SDO | - | - | LCDのデータ読むときに必要 |
LED | LEDのアノード(+)側で制御 | SPI0_MISO/GPIOC1 (gpio65) Pin#21で制御 | |
SCK | SPI0_CLK/GPIOC2 | 23 | |
SDI(MOSI) | SPI0_MOSI/GPIOC0 | 19 | |
D/C | UART2_RX/GPIOA1 | 22 | D/C制御用GPIO (gpio1) |
RESET | UART1_CTS/GPIOG9 | 18 | Reset制御用GPIO (gpio201) |
CS | SPI0_CS/GPIOC3 | 24 | |
GND | GND | 20 | |
VCC | SYS_3.3V | 17 |
バックライトについて
バックライトの消費電流 : 63.3mA @ 3.3v
SYS_3.3Vに接続ででOnになる。
Gpio制御する場合は「LEDのアノード(+)側で制御」が必要。
ILI9328 (240x320, 2.4inch)
概要
入手元:
http://www.aitendo.com/product/10943
¥1750
制御コマンド系は、ILI9341,ST7335系(8bit系)とは異なる。
また、ILI9225(16bit系)とも異なる。
4wireSPIではなく、3wire接続タイプとなる。
D/Cが無い代わりに、StartCodeを1byteつけて送る必要がある。
インスタンス生成:
Display_ILI9328_spi_TM22(0);
配線
ILI9328 | NanoPi-NEO(2) PinName | NanoPi-NEO(2) Pin# | 備考 |
---|---|---|---|
D_SDO | - | - | LCDのデータ読むときに必要 |
D_LED | LEDのカソード(-)側で制御 | SPI0_MISO/GPIOC1 (gpio65) Pin#21で制御 | |
D_SCK | SPI0_CLK/GPIOC2 | 23 | |
D_SDI | SPI0_MOSI/GPIOC0 | 19 | |
D_RS | UART2_RX/GPIOA1 | 22 | D/C制御用GPIO (gpio1) |
D_/RST | UART1_CTS/GPIOG9 | 18 | Reset制御用GPIO (gpio201) |
D_CS | SPI0_CS/GPIOC3 | 24 | |
D_GND | GND | 20 | |
VCC_IN | SYS_3.3V | 17 |
D_LEDをGPIO制御しない場合は、GNDに落とすと常時Onになる。
バックライトについて
バックライトの消費電流 : 53.9mA @ 3.3v
GND接地でOnになる。
Gpio制御する場合は「LEDのカソード(-)側で制御」が必要。
ILI9225 (176x240, 2.2inch)
概要
入手元:
https://www.amazon.co.jp/gp/product/B010SHM2E6/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1
¥750
制御コマンド系は、ILI9341,ST7335系(8bit系)とは異なる。
また、ILI9328(16bit系)とも異なる。
インスタンス生成:
Display_ILI9225_spi(180); // for basic ILI9225
配線
ILI9225 | NanoPi-NEO(2) PinName | NanoPi-NEO(2) Pin# | 備考 |
---|---|---|---|
VCC | SYS_3.3V | 17 | |
GND | GND | 20 | |
GND | |||
NC | |||
NC | |||
LED | LEDのアノード(+)側で制御 | 21 | SPI0_MISO/GPIOC1 (gpio65) Pin#21で制御 |
CLK | SPI0_CLK/GPIOC2 | 23 | |
SDI | SPI0_MOSI/GPIOC0 | 19 | |
RS | UART2_RX/GPIOA1 | 22 | D/C制御用GPIO (gpio1) |
RST | UART1_CTS/GPIOG9 | 18 | Reset制御用GPIO (gpio201) |
CS | SPI0_CS/GPIOC3 | 24 |
バックライトについて
消費電力は、0.01mA未満。測定限界以下。
SYS_3.3Vに接続ででOnになる。
消費電流の少なさは、FET入力か何かなのでしょう。
なお、バックライト点灯させた状態におけるLCD全体の消費電流は、44mA @ 3.3v であった。
ST7735 (128x160, 1.8inch)
概要
入手元:
https://www.amazon.co.jp/gp/product/B010SHK0Y0/ref=oh_aui_detailpage_o04_s00?ie=UTF8&psc=1
¥480
インスタンス生成:
Display_ST7735_spi(180); // for KMR1.8
配線
ST7735 | NanoPi-NEO(2) PinName | NanoPi-NEO(2) Pin# | 備考 |
---|---|---|---|
LED- | - | - | 実はGNDに繋がっている。 |
LED+ | LEDのアノード(+)側で制御 | - | SPI0_MISO/GPIOC1 (gpio65) Pin#21で制御 |
SD_CS | - | - | |
MOSI | - | - | |
MISO | - | - | LCDのデータ読むときに必要 |
SCK | - | - | |
CS | SPI0_CS/GPIOC3 | 24 | |
SCL | SPI0_CLK/GPIOC2 | 23 | |
SDA | SPI0_MOSI/GPIOC0 | 19 | |
AO | UART2_RX/GPIOA1 | 22 | D/C制御用GPIO (gpio1) |
RESET | UART1_CTS/GPIOG9 | 18 | Reset制御用GPIO (gpio201) |
NC | - | ||
NC | - | ||
NC | - | ||
VCC | SYS_3.3V | 17 | |
GND | GND | 20 |
バックライトについて
バックライトの消費電流 : 35.00mA @ 3.3v
SYS_3.3Vに接続ででOnになる。
Gpio制御する場合は「LEDのアノード(+)側で制御」が必要。
LED-をGNDに、LED+をGPIOに繋ぎ直ドライブすると、かなり暗く、
消費電力を測ってみたところ、7.18 [mA] であった。
かなりな電力不足である。
(過電流でCPU側が壊れるかもしれないので、あまりやらないように)
まとめ
-
ST7735, ILI9341 はCommand長が8bitであり、基本コマンドはかなり共通している。
-
ILI9225, ILI9328 は、Command長が16bitであり、ILI9325とも比較してみたが、共通コマンドはあるものの、ほとんどが不統一の状態。チップ毎に制御コード書かないとイケナイ。
-
各種LCDパネルには、パネル固有値(ガンマテーブル、制御電圧値)があるが、そもそもパネルの素性がメーカー名すらも不明な状態のため、何が正しいデータなのかもわからない。
-
上記4つの赤基板LCDパネルの視野角は、かなり狭い。。。ちゃんとした物が欲しい場合は、数打たなければいけない。
-
LCDパネルには、バックライトが直接GPIO制御できるよう増幅回路が入っているものもあり、非常に便利!
-
SPI通信速度はパネルによっては、仕様の10MHz以上に設定できるものもあり、表示フレームレートを稼ぐことができる。
-
例えば、240x320 で40MHz駆動の場合 $40[MHz] / (320[pix]*240[pix]*16[bit]) = 32.55 [fps]$ が理論値。
-
しかし実測は、主にSPIドライバのオーバヘッドで、9fps程度しか出ない
-
80MHz(表示は崩れるが)で駆動しても、11.5fps 程度。誰かSleepしてる?あるいはioctlがネック?
-
Aitendo購入のILI9328コントローラの液晶、これらLCDの中では一番視野角が広く、左右80度、上下30度程度内で色変化がほぼ無い。
-
しかしNanoPi-NEOでは、なぜか動かせなかった。(NEO2はすんなり動いた。NEOで深い追いはしていないので、再度実施すれば、動くかもしれないし、動かないかもしれない)
-
たまに、コマンドあるいはStartCodeの取りこぼしするときがある。その結果、描画されないなどの現象が稀に発生している。SCLクロックが速すぎ。というわけでも無さそうなので、CSタイミングの問題かも。