RaspberryPiで有機ELディスプレイSSD1306をPythonで制御する。

# はじめに
RaspberryPiで有機ELディスプレイ SSD1306を制御した方法をまとめる。

# 目次
+ [材料](#材料)
+ [接続方法](#接続方法)
+ [SSD1306制御方法](#ssd1306制御方法)
+ [Pythonでの制御例](#pythonでの制御例)
+ [参考サイト](#参考サイト)


## 材料
+ **SSD1306**
SSD1306は秋月やAmazonで数100円ぐらいで購入可能。128x64ドットのディスプレイでI2Cにより制御できる。
https://akizukidenshi.com/catalog/g/g115870/
　
+ **RaspberryPi4**
https://www.raspberrypi.com/products/raspberry-pi-4-model-b/
　
+ **ユニバーサル基板**
ラズパイとSSD1306を接続する用のユニバーサル基板。ブレッドボードでも接続できる。
https://akizukidenshi.com/catalog/g/g114031/

[戻る](#目次)

## 接続方法
SSD1306とラズパイとは、I2C(SDA/SCL)とGND,3.3Vを接続する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299802/8e8a2ff4-b56d-c186-dbfe-3a7096d2b264.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299802/34bb571e-96c9-a567-0f19-8eb5d80f533a.png)

[戻る](#目次)

## SSD1306制御方法
I2Cアドレスは0x3Cで、「Control」で後に続く値が決まる。
Control|意味
---|---
0x80|1byteのCOMMAND
0x00|複数ByteのCOMMAND
0x40|ディスプレイに出力するデータ列

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299802/33982a02-d34d-a61f-6999-f29166b103b7.png)

初期設定に必要なCOMMANDは下記の通り
COMMAND|意味
-------|-------
0xA8,0xXX|解像度(0xXX:0x00～0x3F)
0xD3,0xXX|縦方向のオフセット(0xXX:0x00～0x3F)
0x40 ～ 0x7F|描画開始位置(下位6bit 0～63)
0xA0/0xA1|描画方向(0xA0:→/0xA1:←)
0xC0/0xC8|描画方向(0xC0:↓/0xC8:↑)
0xDA,0xXX|表示モード(0xXX:0x02:Altenative/0x12:Sequential)
0x81,0xXX|コントラスト(0x00～FF)
0xA4/0xA5|画面書き換えON(0xA4:ON/0xA5:OFF)
0xA6/0xA7|白黒(0xA6:通常/0xA7:反転)
0xD5,0xXX|クロック設定(0xXX:0x00～0xFF)
0x8D,0x14|レギュレータON
0xAE/0xAF|表示ON/OFF(0xAE:OFF/0xAF/ON)
0x20,0xXX|データ設定モード(0xXX:0x00:水平モード/0x01:アドレスモード/0x02:ページモード)
0x21,0xXX,0xXX|アドレスモード横方向の開始終了アドレス(0xXX,0xXX:0～127)

データのドットは128x64になっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299802/bb7227f2-841a-d753-072d-851cc5d2a47b.png)


詳細はデータシート

https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf

[戻る](#目次)

## Pythonでの制御例
Pythonのライブラリ```pigpio```を使って制御する。pigpioの使い方については下記にまとめる。

https://qiita.com/tapitapi/items/db16b106c54a66c49606

```sample.py```を実行すると下図のように出力される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299802/982c951e-6e83-60cc-b4d3-9d3ba54eba59.png)


```python:sample.py
import pigpio

# pigpio初期化
pi = pigpio.pi()
# I2C Open Address=0x3C
h = pi.i2c_open(1, 0x3C)

# 初期設定=====================================================
# 0xA8:解像度(0x00～0x3F)
pi.i2c_write_device(h, b'\x00\xA8\x3F')
# 0xD3:縦方向のオフセット(0x00～0x3F)
pi.i2c_write_device(h, b'\x00\xD3\x00')
# 0x40～0x7F:描画開始位置(下位6bit 0～63)
pi.i2c_write_device(h, b'\x80\x40')
# 0xA0/0xA1:描画方向(0xA0:→/0xA1:←)
pi.i2c_write_device(h, b'\x80\xA1')
# 0xC0/0xC8:描画方向(0xC0:↓/0xC8:↑)
pi.i2c_write_device(h, b'\x80\xC8')
# 0xDA:表示モード(0x02:Altenative/0x12:Sequential)
pi.i2c_write_device(h, b'\x00\xDA\x12')
# 0x81:コントラスト(0x00～FF)
pi.i2c_write_device(h, b'\x00\x81\x7F')
# 0xA4/0xA5:画面書き換えON(0xA4:ON/0xA5:OFF)
pi.i2c_write_device(h, b'\x80\xA4')
# 0xA6/0xA7:白黒(0xA6:通常/0xA7:反転)
pi.i2c_write_device(h, b'\x80\xA6')
# 0xD5:クロック設定(0x00～0xFF)
pi.i2c_write_device(h, b'\x00\xD5\x80')
# 0x8D 0x14:レギュレータON
pi.i2c_write_device(h, b'\x00\x8D\x14')
# 0xAE/0xAF:表示ON/OFF(0xAE:OFF/0xAF/ON)
pi.i2c_write_device(h, b'\x80\xAF')
# 0x20:データ設定モード(0x00:水平モード/0x01:アドレスモード/0x02:ページモード)
pi.i2c_write_device(h, b'\x00\x20\x00')
# 0x21:アドレスモード横方向の開始終了アドレス(0～127)
pi.i2c_write_device(h, b'\x00\x21\x00\x7F')


# すべて0埋め(128列*8page)=====================================
pi.i2c_write_device(h, b'\x40' + bytearray(b'\x00'*128*8) )


# Data設定=====================================================
#page0
pi.i2c_write_device(h, b'\x40\x01\x01\x01\x01\x03\x03\x03\x03\x07\x07\x07\x07\x0F\x0F\x0F\x0F')
pi.i2c_write_device(h, b'\x40\x1F\x1F\x1F\x1F\x3F\x3F\x3F\x3F\x7F\x7F\x7F\x7F\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x01\x01\x01\x01\x03\x03\x03\x03\x07\x07\x07\x07\x0F\x0F\x0F\x0F')
pi.i2c_write_device(h, b'\x40\x1F\x1F\x1F\x1F\x3F\x3F\x3F\x3F\x7F\x7F\x7F\x7F\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x01\x01\x01\x01\x03\x03\x03\x03\x07\x07\x07\x07\x0F\x0F\x0F\x0F')
pi.i2c_write_device(h, b'\x40\x1F\x1F\x1F\x1F\x3F\x3F\x3F\x3F\x7F\x7F\x7F\x7F\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x01\x01\x01\x01\x03\x03\x03\x03\x07\x07\x07\x07\x0F\x0F\x0F\x0F')
pi.i2c_write_device(h, b'\x40\x1F\x1F\x1F\x1F\x3F\x3F\x3F\x3F\x7F\x7F\x7F\x7F\xFF\xFF\xFF\xFF')
#page1
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\x7F\x7F\x7F\x7F\x3F\x3F\x3F\x3F\x1F\x1F\x1F\x1F')
pi.i2c_write_device(h, b'\x40\x0F\x0F\x0F\x0F\x07\x07\x07\x07\x03\x03\x03\x03\x01\x01\x01\x01')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\x7F\x7F\x7F\x7F\x3F\x3F\x3F\x3F\x1F\x1F\x1F\x1F')
pi.i2c_write_device(h, b'\x40\x0F\x0F\x0F\x0F\x07\x07\x07\x07\x03\x03\x03\x03\x01\x01\x01\x01')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\x7F\x7F\x7F\x7F\x3F\x3F\x3F\x3F\x1F\x1F\x1F\x1F')
pi.i2c_write_device(h, b'\x40\x0F\x0F\x0F\x0F\x07\x07\x07\x07\x03\x03\x03\x03\x01\x01\x01\x01')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\x7F\x7F\x7F\x7F\x3F\x3F\x3F\x3F\x1F\x1F\x1F\x1F')
pi.i2c_write_device(h, b'\x40\x0F\x0F\x0F\x0F\x07\x07\x07\x07\x03\x03\x03\x03\x01\x01\x01\x01')
#page2
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
#page3
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
#page4
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
#page5
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
#page6
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
#page7
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
pi.i2c_write_device(h, b'\x40\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')


# I2C Close
pi.i2c_close(h)
```
[戻る](#目次)

## 参考サイト
http://try3dcg.world.coocan.jp/note/i2c/ssd1306.html

[戻る](#目次)