Raspberry Pi で電子ペーパーを点けてみる (e-Paper )


BN-880 と一緒に e-Paper を買っていたので、BN-880 の交換対応を頼んでいる間に点灯確認をやってみる。
この e-Paper は SPI で操作するので sudo raspi-config で SPI を ON にしておく。


商品 waveshare製 7.5inch e-Paper HAT (B)
この e-Paper は [白/黒](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT), [白/黒/赤](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT_(B)), [白/黒/黄](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT_(C)) の 3タイプあり、二番目の 白/黒/赤 を購入。

購入先 [banggood](https://www.banggood.com/Waveshare-7_5-Inch-E-ink-Screen-Module-e-Paper-Display-SPI-Type-B-For-Arduino-Raspberry-Pi-p-1365284.html) 6798円 (2019/3/21 時点) でした。他には[Amazon](https://amzn.to/2XfhH0B)、[せんごくネット](https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-58P6)、[aliexpress](https://waveshare-developmentkit.ja.aliexpress.com/store/group/7-5inch/216233_513211037.html) でも購入可能です。

ドキュメントの場所はメーカ (waveshare) の Wiki っぽいページ
[waveshare 7.5inch e-Paper HAT (B)](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT_(B)) から辿れます。

接続方法
HAT の写真
![PSX_20190412_184908.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/99badf19-50cd-54e2-e04f-7c7b87416a99.jpeg)
User Manual によると pin 接続は以下の通り

|Raspberry Pi|e-Paper (HAT) pin番号/ケーブルの色|
|:---:|:-----|
| 3.3V  | VCC (3.3～5V) pin1/赤|
| GND | GND pin2/黒|
|MOSI (GPIO10/pin19)|DIN pin3/青|
|SCLK (GPIO11/pin23)|CLK pin4/黄|
|CE0 (GPIO8/pin24) | CS  pin5/橙|
|- (GPIO 25/pin22) | DC  pin6/緑|
|- (GPIO 17/pin11) | RES pin7/白|
|- (GPIO 24/pin18) |BUSY pin8/紫|
|CE1 (GPIO7/pin26)| -NC-  |
|MISO (GPIO9/pin21)| -NC- |


GPIO の並びに並べてみると以下の通り。刺し間違えしにくいように 4x2 のピンと、3x1 をくっつけてしまうかな？

|pin番号|名前|名前|pin番号|
|--:|---|---|:--|
|11|RES|-|12|
|13|-|-|14|
|15|-|.|16|
|17|3.3V|BUSY|18|
|19|DIN|GND|20|
|21|-|DC|22|
|23|CLK|CS|24|

こんな感じで付属ケーブルの頭を挿げ替えた。
![PSX_20190412_185027.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/190def47-e646-2430-5415-1efb7854abfe.jpeg)
![PSX_20190412_184757.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/35dc7c64-917d-d670-46fa-998b6ec9c693.jpeg)

Raspberry Pi に刺したところはこんな感じ。
![IMG_20190412_192821.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/3a70480f-6503-35f9-bf00-825c435e9291.jpeg)
後ろにプー・ルイさんとか見えてません。

[BCM 2835 ライブラリ](http://www.airspayce.com/mikem/bcm2835/) をダウンロードしてインストール & ソースファイルは消す。

```tcsh:
Ras1:~/> mkdir e-paper && cd e-paper
Ras1:~/e-paper> wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.58.tar.gz                                                     --2019-04-12 19:35:26--  http://www.airspayce.com/mikem/bcm2835/bcm2835-1.58.tar.gz                                                 Resolving www.airspayce.com (www.airspayce.com)... 192.185.48.187                                                                   Connecting to www.airspayce.com (www.airspayce.com)|192.185.48.187|:80... connected.                                                HTTP request sent, awaiting response... 200 OK
Length: 264731 (259K) [application/x-gzip]
Saving to: 'bcm2835-1.58.tar.gz'

bcm2835-1.58.tar.gz              100%[==========================================================>] 258.53K   214KB/s    in 1.2s

2019-04-12 19:35:27 (214 KB/s) - 'bcm2835-1.58.tar.gz' saved [264731/264731]

Ras1:~/e-paper> tar xzf bcm2835-1.58.tar.gz
Ras1:~/e-paper> cd bcm2835-1.58
Ras1:~/e-paper/bcm2835-1.58> ./configure
...snip...
Ras1:~/e-paper/bcm2835-1.58> make
...
Ras1:~/e-paper/bcm2835-1.58> sudo make check
...
make[3]: Entering directory '/home/pi/e-paper/bcm2835-1.58/src'
PASS: test
============================================================================
Testsuite summary for bcm2835 1.58
============================================================================
# TOTAL: 1
# PASS:  1
# SKIP:  0
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================
make[3]: Leaving directory '/home/pi/e-paper/bcm2835-1.58/src'
...
Ras1:~/e-paper/bcm2835-1.58> sudo make install
...
make[2]: Entering directory '/home/pi/e-paper/bcm2835-1.58/src'
 /bin/mkdir -p '/usr/local/lib'
 /usr/bin/install -c -m 644  libbcm2835.a '/usr/local/lib'
 ( cd '/usr/local/lib' && ranlib libbcm2835.a )
 /bin/mkdir -p '/usr/local/include'
 /usr/bin/install -c -m 644 bcm2835.h '/usr/local/include'
make[2]: Leaving directory '/home/pi/e-paper/bcm2835-1.58/src'
...
Ras1:~/e-paper/bcm2835-1.58> cd ..
Ras1:~/e-paper> rm -rf bcm2835-1.58*
```
python のライブラリをインストール。

```tcsh:
Ras1:~> sudo apt install libopenjp2-7-dev
Ras1:~> sudo apt install python-rpi.gpio python-spidev python-pil python-tz
Ras1:~> sudo apt install python3-rpi.gpio python3-spidev
Ras1:~> sudo apt-get install python3-pip
Ras1:~> sudo pip3 install Pillow

```
デモコードをダウンロード & コンパイル

```tcsh:
Ras1:~/e-paper> wget https://www.waveshare.com/w/upload/0/01/7.5inch_e-paper_hat_b_code.7z
...
Ras1:~/e-paper> mkdir 7.5inch_e-paper_hat_b_code && cd 7.5inch_e-paper_hat_b_code
Ras1:~/e-paper/7.5inch_e-paper_hat_b_code> 7za x ../7.5inch_e-paper_hat_b_code.7z
Ras1:~/e-paper/7.5inch_e-paper_hat_b_code> cd RaspberryPi/bcm2835
Ras1:~/e-paper/7.5inch_e-paper_hat_b_code/RaspberryPi/bcm2835> make
gcc -g -O0 -Wall -D USE_DEBUG -c  obj/main.c -o bin/main.o -lbcm2835 -lm
gcc -g -O0 -Wall -D USE_DEBUG -c  obj/GUI_Paint.c -o bin/GUI_Paint.o -lbcm2835 -lm
gcc -g -O0 -Wall -D USE_DEBUG ./bin/font12CN.o ./bin/font12.o ./bin/font16.o ./bin/font24CN.o ./bin/font20.o ./bin/font8.o ./bin/fon
t24.o ./bin/GUI_BMPfile.o ./bin/main.o ./bin/EPD_7in5b.o ./bin/ImageData.o ./bin/GUI_Paint.o ./bin/DEV_Config.o -o epd -lbcm2835 -lm
```
できたデモを実行

```tcsh:
Ras1:~/e-paper/7.5inch_e-paper_hat_b_code/RaspberryPi/bcm2835> sudo ./epd
7.5inch e-Paper B(C) demo
bcm2835 init success !!!
clear...
Debug: e-Paper busy
Debug: e-Paper busy release
Debug: e-Paper busy
Debug: e-Paper busy release
...
```
画面の明滅の他、デモ表示がされました。
python3 のデモも実行。

```tcsh:
Ras1:~/e-paper/7.5inch_e-paper_hat_b_code/RaspberryPi/bcm2835> cd ../python3
Ras1:~/e-paper/7.5inch_e-paper_hat_b_code/RaspberryPi/python3> sudo python3 ./main.py
e-Paper busy
e-Paper busy release
Clear...
e-Paper busy
e-Paper busy release
Drawing
traceback.format_exc():
%s Traceback (most recent call last):
  File "./main.py", line 23, in <module>
    font24 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24)
  File "/usr/lib/python3/dist-packages/PIL/ImageFont.py", line 238, in truetype
    return FreeTypeFont(font, size, index, encoding)
  File "/usr/lib/python3/dist-packages/PIL/ImageFont.py", line 127, in __init__
    self.font = core.getfont(font, size, index, encoding)
OSError: cannot open resource

```
フォントが無いみたいですね。
フォントファイル 2か所を /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc に書き換えて実行し成功(^^)
python2 の方も同じくフォントファイルを書き換えて成功。

e-Paper を sleep させずに放置するとダメージがあるらしいので、とりあえずリセットするコマンドを作成。24時間以上表示したままだとゴーストが消えない可能性があるとか、太陽光の下でリフレッシュしたら駄目だとか。まだまだこれからのデバイスなんですね。

```python:init_clear.py
#!/usr/bin/python3
import epd7in5b

epd = epd7in5b.EPD()
epd.init()
epd.Clear(0xFF)
epd.sleep()
print("e-Paper clear & sleep done.")
```
ちょっとフォントを追加したりして

```tcsh:フォントを追加
> sudo apt install ttf-ancient-fonts-symbola
```
こんな感じに書き換えてみました。

```python:e-Paper_time.py
#!/usr/bin/python3 
# -*- coding:utf-8 -*-

import epd7in5b
import time
import datetime
from PIL import Image,ImageDraw,ImageFont
import traceback
import random

import re
from subprocess import check_output

def timestamp(mess):
        nowtime = datetime.datetime.now()
        print("{}: {}".format(mess,nowtime.strftime('%T.%f')))



def ntp_status():
    out = check_output(["ntpq", "-c", "sysinfo"])

    for line in out.splitlines():
        if "system peer: " in line.decode():
            peer = re.sub('^system peer: *', '', line.decode())

        if "stratum:" in line.decode():
            st = re.sub("^stratum: *", "", line.decode())

    return (int(st), peer)



font48 = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', 48)
font24 = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', 24)
Symb48 = ImageFont.truetype('/usr/share/fonts/truetype/ancient-scripts/Symbola_hint.ttf', 48)

try:
    (ntp_stratum, ntp_sys_peer) = ntp_status()

    epd = epd7in5b.EPD()
    timestamp("edp.init             ")
    epd.init()

    # 10分に一度 Clear する
    while 1:
      timestamp("edp.Clear            ")
      epd.Clear(0xFF)

      for i in range(0,10):
        timestamp("edp.init             ")
        epd.init()
        timestamp("edp.Clear skip       ")
        
        gps = int(random.random()*13)
        qzss = int(random.random()*3)
        glonass = int(random.random()*13)
        BeiDou = int(random.random()*13)
        Galileo = int(random.random()*13)


        timestamp("make image           ")
        # Drawing on the Horizontal image
        HBlackimage = Image.new('1', (epd7in5b.EPD_WIDTH, epd7in5b.EPD_HEIGHT), 255)  # 298*126
        HRedimage   = Image.new('1', (epd7in5b.EPD_WIDTH, epd7in5b.EPD_HEIGHT), 255)  # 298*126    
    
        # Horizontal
        timestamp("Drawing              ")
        drawblack = ImageDraw.Draw(HBlackimage)
        drawred   = ImageDraw.Draw(HRedimage)


        drawblack.text((  0,  0), u'ただ今の時刻', font = font48, fill = 0)
        drawblack.text((288, 14), u'⏰' ,font = Symb48, fill = 0)

        drawblack.text((  0,102), 'NTP stratum:{:2d}'.format(ntp_stratum), font = font24, fill = 0)
        drawblack.text(( 48,127),     'peer:{:s}'.format(ntp_sys_peer),    font = font24, fill = 0)

        drawblack.text((  0,164), u'🛰' ,font = Symb48, fill = 0)
        str = "GPS {:2d} / みちびき {:2d}".format(gps, qzss)
        drawblack.text(( 48,150), str, font = font48, fill = 0)
        str = "北斗 {:2d} / GLONASS {:2d}".format(BeiDou, glonass)
        drawblack.text(( 48,200), str, font = font48, fill = 0)
        str = "Galileo {:2d}".format(Galileo)
        drawblack.text(( 48,250), str, font = font48, fill = 0)

        nowtime = datetime.datetime.now()
        sleeptime = 60-nowtime.second - nowtime.microsecond/1000000
        time.sleep(sleeptime)
        timestamp("write date start     ")
        nowtime = datetime.datetime.now()
        drawblack.text(( 0, 50), nowtime.strftime('%T.%f'), font = font48, fill = 0)
        timestamp("epd.display          ")
        epd.display(epd.getbuffer(HBlackimage), epd.getbuffer(HRedimage))
        timestamp("epd.sleep            ")
        epd.sleep()

        (ntp_stratum, ntp_sys_peer) = ntp_status()

        timestamp("next update waiting..")
        nowtime = datetime.datetime.now()
        sleeptime = 60-nowtime.second - nowtime.microsecond/1000000 - 0.6
        print("sleep to {}sec".format(sleeptime))
        time.sleep(sleeptime)

except:
    print('traceback.format_exc():\n%s',traceback.format_exc())
    exit()
```
実行するとこんな感じで、完了するまでに40秒ぐらいかかってしまいます。

```tcsh:
Ras1:~/e-paper/7.5inch_e-paper_hat_b_code/RaspberryPi/python3> python3 test.py
edp.init             : 14:28:12.743321
e-Paper busy
e-Paper busy release
edp.Clear            : 14:28:13.245920
e-Paper busy
e-Paper busy release
edp.init             : 14:28:50.703835
e-Paper busy
e-Paper busy release
edp.Clear skip       : 14:28:51.206602
make image           : 14:28:51.207088
Drawing              : 14:28:51.209098
write date start     : 14:29:00.009041
epd.display          : 14:29:00.016917
Horizontal
Horizontal
e-Paper busy
e-Paper busy release
epd.sleep            : 14:29:38.776385
e-Paper busy
e-Paper busy release
next update waiting..: 14:29:38.924334
sleep to 20.475171sec
edp.init             : 14:29:59.420804
e-Paper busy
e-Paper busy release
edp.Clear skip       : 14:29:59.923895
make image           : 14:29:59.924366
Drawing              : 14:29:59.926296
write date start     : 14:30:00.000278
epd.display          : 14:30:00.007575
Horizontal
Horizontal
e-Paper busy
e-Paper busy release
epd.sleep            : 14:30:39.163830
e-Paper busy
e-Paper busy release
next update waiting..: 14:30:39.311694
sleep to 20.087804sec
edp.init             : 14:30:59.420422
e-Paper busy
e-Paper busy release
edp.Clear skip       : 14:30:59.923471
make image           : 14:30:59.923945
Drawing              : 14:30:59.925980
write date start     : 14:31:00.000285
epd.display          : 14:31:00.007451
Horizontal
Horizontal
e-Paper busy
e-Paper busy release
epd.sleep            : 14:31:39.175683
e-Paper busy
e-Paper busy release
next update waiting..: 14:31:39.321270
sleep to 20.078232sec
...snip...
```

表示はこんな感じ。とりあえず映ったなと。GPS 部分はダミー。
![PSX_20190413_144555.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306041/861cca18-4eae-c9da-05c7-26c576bfc621.jpeg)

更新中はこんな感じ。
https://www.youtube.com/watch?v=1haqmX0vacE
白バックから白黒反転して書き換わる、そしてゴーストが消えるまで点滅、再度白バックで表示。となってます。遅い...

続きはまた今度。更新にめっちゃ時間がかかるので時間表示は無理ですね。日付と天気予報表示ぐらいかな。時刻を表示するには普通の LCD 買わないといけませんね。

# リフレッシュの早い e-Ink ディスプレイ
改めて調べてみると、もっと大きくてもリフレッシュが 1秒以下のものがありますねぇ。高いけど。これらのインターフェイスは USB/SPI/I80/I2C 対応で、16諧調 (4bit)、部分リフレッシュもできるみたいですね。

- [6 インチ 800*600](https://ja.aliexpress.com/item/32969309942.html)
- [7.8 インチ 1872*1404](https://ja.aliexpress.com/item/4000033661088.html)
- [9.7 インチ 1200*825](https://ja.aliexpress.com/item/32948801639.html)
- [10.3 インチ 1872*1404](https://ja.aliexpress.com/item/33054424357.html)

7.8インチ、10.3インチはリフレッシュ速度は 0.45s だとか。
9.7インチは 1秒以下。 6インチは Refresh Rate 85Hz とありますが、0.45s 以下？
こいつらは電気を食うので、更新時には 1A 以上は見ておいたほうが良いみたいです。