NanoPi-NEOと5種のLCDと2種のOLED


# 概要

NanoPi-NEOでLCDやOLEDなどいろいろ繋いで表示させてみます。
今回のターゲットは下記の通り。
既存の表示ライブラリ等は一切使わず、画像(Gray/BGRA)表示のみに特化し、C++でフルスクラッチで作ってみた。
つまり、gpio,spi,i2cすべてLinux直叩きである。


<img width="960" alt="_72D0257.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/187531/a98d8115-3a74-2e21-1142-707f8c4c169e.png">


|コントローラ|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

```console:コンパイル
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|誤差拡散２値化処理用|

表示系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`

![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/31fc32b0-d089-ffad-fabc-91a4859e0461.png)


### 配線

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`


![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/f2f8781f-dfb8-9a5b-af0b-7d0c6b97dc0c.png)


### 配線

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コントローラチップからのデータ読み出し行う場合は＋１本)

- 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の電源でそのまま使用できる(ことが多い)。
接続例に分けて４種類記載してみる。
工作といえど、バックライトOn/Off制御は見栄えが良い(笑

### そもそも制御しない

ソースコードでは、GPIOポートに－１を設定すればGPIO制御が無効化できるようにしています。
バックライトのLEDは直接電源に接続すればOK。

### GPIO直接制御版

GPIOの出力電流で十分賄える場合である。
例えば、NanoPi-NEO(2)の場合、最大20mA出力できる模様。
20mAに収まるLCDパネルのバックライトであれば、そのまま接続でOK.

### LEDのカソード(-)側で制御

100mA未満であれば、希少品の2SC1815で十分かな。
回路図は一般的な工作例なので、本気組の方はLTSpice等でちゃんと設計しましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/df5a3ab7-da7c-e53e-e42c-698acc024278.png)

### LEDのアノード(+)側で制御

100mA未満であれば、希少品の2SC1815と2SA1015で十分かな。
回路図は一般的な工作例なので、本気組の方はLTSpice等でちゃんと設計しましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/4d85498b-2602-e944-a94d-776e1420eb50.png)

## 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`


![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/0cf5c209-ffa4-4cd6-1f2f-01827b584c58.png)


### 配線

バックライト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`


![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/190dcfab-a35b-ba66-c8b6-cdb6e5d4dfb5.png)


### 配線

|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<MISO>|-|-|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);`


![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/758454fc-1fe7-6955-eda2-c108fd04b4e9.png)


### 配線

|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`


![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/ec0cf78d-ecbb-b058-95cb-20fde55ee9e0.png)


### 配線

|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`


![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/74187003-5029-b250-a782-1a98334409a1.png)


### 配線

|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パネルには、パネル固有値(ガンマテーブル、制御電圧値)があるが、そもそもパネルの素性がメーカー名すらも不明な状態のため、何が正しいデータなのかもわからない。
- 上記４つの赤基板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タイミングの問題かも。