
マイクロビットでSPIカラー電子ペーパーモジュールを使ってみます。
今回使用するモジュールはWaveShare 3インチ 400 × 168 電子ペーパーモジュール(G) 赤/黄/黒/白(以後、e-paperと略す)で、これから記載するコードは公式サイトで配布されているラズベリーパイ用のMicroPythonのコードをマイクロビット用に書き換えたものになります。
3インチ 400 × 168 電子ペーパーモジュール(G) 赤/黄/黒/白 — スイッチサイエンス
配線はマイクロビットに拡張ボードをかまし
| e-paper | microbit |
|---|---|
| VCC | 3.3V |
| GND | GND |
| DIN(MISO) | GPIO 15 |
| SCLK | GPIO 13 |
| DC | GPIO 2 |
| CS | GPIO 3 |
| RST | GPIO 0 |
| BUSY | GPIO 1 |
にします。
from microbit import *
# 画像データ
buf = []
# pin3 を使用できるようにする
display.off()
# Pin definition
RST_PIN = pin0
DC_PIN = pin2
CS_PIN = pin3
BUSY_PIN = pin1
# Display resolution
EPD_WIDTH = 168
EPD_HEIGHT = 400
class EPD:
def __init__(self):
spi.init()
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.BLACK = 0x000000 # 00 BGR
self.WHITE = 0xffffff # 01
self.YELLOW = 0x00ffff # 10
self.RED = 0x0000ff # 11
# Hardware reset
def reset(self):
RST_PIN.write_digital(1)
sleep(200)
RST_PIN.write_digital(0) # module reset
sleep(2)
RST_PIN.write_digital(1)
sleep(200)
def send_command(self, cmd):
DC_PIN.write_digital(0)
CS_PIN.write_digital(0)
spi.write(bytes([cmd]))
CS_PIN.write_digital(1)
def send_data(self, d):
DC_PIN.write_digital(1)
CS_PIN.write_digital(0)
spi.write(bytes([d]))
CS_PIN.write_digital(1)
def ReadBusyH(self):
print("e-Paper busy H")
while(BUSY_PIN.read_digital() == 0): # 0: idle, 1: busy
sleep(5)
print("e-Paper busy H release")
def ReadBusyL(self):
print("e-Paper busy L")
while(BUSY_PIN.read_digital() == 1): # 0: busy, 1: idle
sleep(5)
print("e-Paper busy L release")
def TurnOnDisplay(self):
self.send_command(0x12) # DISPLAY_REFRESH
self.send_data(0x01)
self.ReadBusyH()
self.send_command(0x02) # POWER_OFF
self.send_data(0X00)
self.ReadBusyH()
def init(self):
self.reset()
self.send_command(0x66)
self.send_data(0x49)
self.send_data(0x55)
self.send_data(0x13)
self.send_data(0x5D)
self.send_data(0x05)
self.send_data(0x10)
self.send_command(0xB0)
self.send_data(0x00) # 1 boost
self.send_command(0x01)
self.send_data(0x0F)
self.send_data(0x00)
self.send_command(0x00)
self.send_data(0x4F)
self.send_data(0x6B)
self.send_command(0x06)
self.send_data(0xD7)
self.send_data(0xDE)
self.send_data(0x12)
self.send_command(0x61)
self.send_data(0x00)
self.send_data(0xA8)
self.send_data(0x01)
self.send_data(0x90)
self.send_command(0x50)
self.send_data(0x37)
self.send_command(0x60)
self.send_data(0x0C)
self.send_data(0x05)
self.send_command(0xE3)
self.send_data(0xFF)
self.send_command(0x84)
self.send_data(0x00)
return 0
def display(self, l):
if self.width % 4 == 0 :
Width = self.width // 4
else :
Width = self.width // 4 + 1
Height = self.height
self.send_command(0x04)
self.ReadBusyH()
count = len(l)
for j in range(0, Height):
for i in range(0, Width):
idx = i + j * Width
if count > idx:
self.send_data(l[idx])
else:
# 足りない分はWHITEで埋める
self.send_data(0)
self.TurnOnDisplay()
def Clear(self, color=0x55):
if self.width % 4 == 0 :
Width = self.width // 4
else :
Width = self.width // 4 + 1
Height = self.height
self.send_command(0x04)
self.ReadBusyH()
self.send_command(0x10)
for j in range(0, Height):
for i in range(0, Width):
self.send_data(color)
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x02) # POWER_OFF
self.send_data(0x00)
self.send_command(0x07) # DEEP_SLEEP
self.send_data(0XA5)
sleep(2000)
print("epd3in0g Demo")
epd = EPD()
# Drawing on the image
epd.init()
print("Drawing on the image...")
epd.display(buf)
sleep(3000)
print("Goto Sleep...")
epd.sleep()
下記URL先のページでもMicroPythonのコードを確認できます。
https://github.com/inunosinsi/color-e-paper_on_microbit/blob/main/main.py
上記のコードは試しに実行してみますと、ディスプレイが真っ白になり何も表示されません。
# 画像データ buf = []
コードの冒頭にあるリスト型のbufに出力したいデータを格納する必要があるのですが、何も指定されていません。
今回のe-PaperではPythonのPILライブラリを用いて画像データを生成してディスプレイにデータを送信することでディスプレイに出力されますが、マイクロビットではPILライブラリが使用できないため、事前に画像データを作成する必要があります。
Python Imaging Library - Wikipedia
そこで事前にコード作成用のPCで画像のデータを作成しておいて、生成したデータをフラッシング用のコードに直接貼り付けることで試しています。
PILで画像を生成するコードは下記のディレクトリのように作成します。
. ├── d.txt └── generate.py
generate.py
from PIL import Image,ImageDraw,ImageFont
EPD_WIDTH = 168
#EPD_HEIGHT = 400
EPD_HEIGHT = 40
BLACK = 0x000000 # 00 BGR
WHITE = 0xffffff # 01
YELLOW = 0x00ffff # 10
RED = 0x0000ff # 11
def getbuffer(image):
# Create a pallette with the 4 colors supported by the panel
pal_image = Image.new("P", (1,1))
pal_image.putpalette( (0,0,0, 255,255,255, 255,255,0, 255,0,0) + (0,0,0)*252)
# Check if we need to rotate the image
imwidth, imheight = image.size
if(imwidth == EPD_WIDTH and imheight == EPD_HEIGHT):
image_temp = image
elif(imwidth == EPD_HEIGHT and imheight == EPD_WIDTH ):
image_temp = image.rotate(90, expand=True)
#else:
#logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, EPD_WIDTH , EPD_HEIGHT))
# Convert the soruce image to the 4 colors, dithering if needed
image_4color = image_temp.convert("RGB").quantize(palette=pal_image)
buf_4color = bytearray(image_4color.tobytes('raw'))
# into a single byte to transfer to the panel
buf = [0x00] * int(EPD_WIDTH * EPD_HEIGHT / 4)
idx = 0
for i in range(0, len(buf_4color), 4):
buf[idx] = str((buf_4color[i] << 6) + (buf_4color[i+1] << 4) + (buf_4color[i+2] << 2) + buf_4color[i+3]) + ","
idx += 1
return buf
img = Image.new('RGB', (EPD_WIDTH, EPD_HEIGHT), 0xffffff)
draw = ImageDraw.Draw(img)
draw.text((5, 0), 'hello world', fill = RED)
buf = getbuffer(img)
print(len(buf))
with open('d.txt','w') as f:
f.writelines((buf))
下記URL先のページでもPythonのコードを確認できます。
https://github.com/inunosinsi/color-e-paper_on_microbit/blob/main/generate.py
コードが出来ましたら、実行してみます。
作成したコードが
/path/to/dir/generate.py
にある場合、
sudo apt-get update sudo apt-get install python3-pip sudo apt-get install python3-pil python3 /path/to/dir/generate.py
の順にコマンドを実行して、画像データを生成します。
生成した画像のデータはd.txtに格納されていますので、d.txtの内容をフラッシングするコードの方の
# 画像データ buf = [85,85,85...]
のように数字の羅列を貼り付けます。
上記の処理を終えてコードをフラッシングしてみますと、フラッシング終了後に

のようにディスプレイに生成した画像データが出力されます。
generate.pyの方のパラメータで
EPD_WIDTH = 168 #EPD_HEIGHT = 400 EPD_HEIGHT = 40
の画像生成用の値があります。
マイクロビットのメモリの都合上、e-Paperに合わせた画像データを持つことが出来ません。
マイクロビット用にデータを小さくして生成する必要がありますが、この時に変更できる値はEPO_HEIGHTのみになります。
EPO_WIDTHを変更するとディスプレイ出力時に表示がずれてしまいます。
ここから今回利用したSPIというシリアル通信について触れていきます。
SPIはシリアル・ペリフェラル・インタフェース(serial peripheral interface)の略で、データの送受信を行うシリアル通信の一種です。

en:User:Cburnett - 投稿者自身による作品 このW3C-unspecified ベクター画像はInkscapeで作成されました ., CC 表示-継承 3.0, リンクによる
SPIでは、モジュールを操作する為のマイコン等のマスター(Master)と、操作される側のスレーブ(Slave)があります。
マスターとスレーブを繋ぐ時は、SCLK、MOSI、MISOとSSがあり、必要に応じて繋いでいきます。
各々のピンの役割ですが、
になります。

I, Cburnett, CC 表示-継承 3.0, リンクによる
SPIではMISOやMOSIでデータを送受信する際、SCLKがあり自身でクロックを発生させることで、マイクロビットでUARTを使ってみるで見たUARTのようにデータ送信側と受信側のボーレートを合わせるといった手続きが不要になります。

SSはどのマスターがどのスレーブとやりとりをするか?の合図を送る為に使用します。
※今回のコードではSPIデバイスに対して書き込みのみを行いましたが、SPIには読み込みの方のモジュールもあります。