マイクロビットで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には読み込みの方のモジュールもあります。