みかんのゆるふわ技術ブログ

Raspberry PiやIoT関係のことを書き残していきます

Raspberry Piに7ドルの2.4インチQVGA液晶ディスプレイをつなぐ

中国のお店が中国国外に売る通販モールAliExpressで小型液晶ディスプレイを買いました。

www.aliexpress.com

サイズは2.4インチ、解像度は320x240px(QVGA)、65万色対応だそうです。液晶コントローラとしてILI9341というLSIが搭載されており、SPIで制御できます。

小型でちょっとした情報を表示するのに便利そうですね🥰

おそらく、Amazon.co.jpで売られているこちらのものと類似品だと思います。画面サイズが微妙に違いますが、ピン配置や解像度は同じで、同じように使えるものだと思います。

AliExpressでの私が購入時の値段は、なんと$6.94でした!1000円しないのでお買い得ですね。

このディスプレイもPythonから簡単にアクセスできるライブラリを公開されている方がいて、ドライバを書かずとも簡単に好きなものが表示できます。 とても便利ですね🥰早速Raspberry Piにつないでみましょう。

Raspberry Piに接続

購入した小型液晶ディスプレイ

f:id:kimura_khs:20210809181103j:plain

こんなものが届きました。画面についていた保護シールははがしています。 ピンヘッダも搭載されていて、はんだ付けなしでジャンパワイヤーなどを使って簡単にRaspberry Piに接続できます。

f:id:kimura_khs:20210809181151j:plain

裏面はこのようになっています。なぜかSDカードスロットがついています。写真右側の4つのスルーホールにピンヘッダをはんだ付けすると、SDカードにもアクセスできます。何のためについているんでしょうね🤔

今回は液晶だけ使うので、SDカードスロットは無視します。

左側の黄色いピンヘッダですが、上5本のT_***というピンはタッチパネル制御のためのピンです。私が購入したのはタッチパネルなしモデルなので使いません。同じシリーズにタッチパネルつきのモデルもあり、それらはこのピンが使えます。

Raspberry Piにつないでみよう

f:id:kimura_khs:20200922113215p:plain
画像出典: raspberrypi.org

Raspberry Piのピンヘッダは上図のように機能が割り当てられています。 このモジュールはSPIで通信しますが、そのほかにも制御線をつなぐ必要があります。 SPI以外はどのGPIOでも良い(Pythonプログラムで指定可)のですが、以下のようにしてみました。

RasPiピン番号 RasPi 機能 液晶ディスプレイ 説明
1 3V3 power LED LEDバックライトON/OFF
17 3V3 power VCC 電源(3.3V)
18 GPIO24 RESET 液晶リセット信号
19 MOSI SDI(MOSI) SPIデータ(Raspi→液晶)
21 MISO SDO(MISO) SPIデータ(液晶→Raspi)
22 GPIO25 DC 液晶データ・コマンド選択
23 SCLK SCK SPIクロック
24 CS GPIO8 SPIチップセレクト
25 GND GND グランド(基準電圧0V)

バックライトON/OFF信号はHIGHでONになるようです。GPIOで制御しても良いですが、今回は3.3Vに接続して常時ONとしました。

これらをジャンプワイヤーで接続すると、次のようになりました。

f:id:kimura_khs:20210809181134j:plain

Raspberry Piの準備

SPIの有効化

Raspberry Pi OSのインストール直後はSPIが無効になっていて、そのままでは使えません🙅‍♀️

有効化するには、raspi-configのメニューから設定できます。

$ sudo raspi-config

で設定画面を起動し、"5 Interfacing Options" → "P4 SPI" → "Yes" を選択してください。

スポンサーリンク

Pythonで表示させてみよう

Pythonライブラリーのインストール

アメリカのオープンソースハードウェアベンダーのAdafruitがPythonライブラリを開発しています。

github.com

このライブラリは今回の液晶に搭載されているILI9341という液晶コントローラLSIの他に、ST7789など複数の液晶コントローラLSIに対応しています。SPIで制御できる液晶画面を幅広くサポートしていて便利です☺️

過去記事で紹介したST7789搭載液晶画面でもこのライブラリが使えます。

www.mikan-tech.net

早速インストールしてみましょう。インストールは次のようにします。

$ sudo apt-get install python3-rpi.gpio python3-spidev python3-pip python3-pil python3-numpy
$ pip3 install adafruit-circuitpython-rgb-display

依存ライブラリをaptでインストールして、最後にpip3でこのライブラリをインストールします。 2021年8月現在、numpyやPillow (PIL)はaptから入れた方がいいみたいです。

基本的な使い方

早速ですが、いちばん基本的なサンプルプログラムを載せます。

from adafruit_rgb_display.rgb import color565
from adafruit_rgb_display.ili9341 import ILI9341

from busio import SPI
from digitalio import DigitalInOut
import board

# Pin Configuration
cs_pin = DigitalInOut(board.D8)
dc_pin = DigitalInOut(board.D25)
rst_pin = DigitalInOut(board.D24)

# Set up SPI bus
spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)

# Create the ILI9341 display:
display = ILI9341(
    spi,
    cs=cs_pin, dc=dc_pin, rst=rst_pin,
    width=240, height=320,
    rotation=90,
    baudrate=24000000
)

# Define color
COLOR_ORANGE = color565((245, 124, 0))

# Fill display with one color
display.fill(COLOR_ORANGE)

このプログラムを実行すると、画面がオレンジ色で塗りつぶされます。

f:id:kimura_khs:20210809181354j:plain

簡単にプログラムの中を見ていきましょう。

spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)

この部分でSPIバスの設定をします。Raspberry PiのピンヘッダはSPIバスは1つだけなので、この通りにすれば大丈夫です。

display = ILI9341(
    spi,
    cs=cs_pin, dc=dc_pin, rst=rst_pin,
    width=240, height=320,
    rotation=90,
    baudrate=24000000
)

続いて、この部分でILI9341コントローラのディスプレイインスタンスを作成します。引数がたくさんありますね。 第1引数で先ほど作成したSPIバスのインスタンスを指定します。

続いてcsdcrstという引数でチップセレクト(CS)、データ制御(DC)、リセット(RST)ピンを指定します。 これらはDigitalInOutのインスタンスでDigitalInOut(board.D8)のように指定します。D8というのはRaspberry PiのGPIO8を表しています。 GPIOはどのピンでも良いので、自分の接続に合わせて指定してください。

さらにwidthheightで液晶画面の解像度を指定します。実はこの液晶は240x320pxの縦長が本来の姿なので、このように指定します。

横長にして使いたいときは、rotation=90とすると90度回転で表示できます(180、270も指定可)。 rotationを指定しなければ240x320pxの縦長のままとなります。今回は横長で使用します。

最後にbaudrateでSPIのクロックレートを指定します。この液晶の場合、24MHzまで使えるようです、

私の場合はこれで問題なく表示できました。

スポンサーリンク

いろいろ表示させてみよう

せっかくなので、いろんなものを表示させてみましょう。 Pillowを使って描画できれば、何でも表示できます。

画像の表示

やっぱり液晶があると、美しい画像を表示させたいですね。 このライブラリはPythonの画像処理ライブラリとして有名なPillow (PIL)と連携して、Pillowで作成した画像を表示できます。

試しに、ネットにある美しい画像を拾ってきましょう。

$ wget https://cdn-ak.f.st-hatena.com/images/fotolife/k/kimura_khs/20210110/20210110170457.jpg

次のようにして簡単に表示させられます。

from adafruit_rgb_display.rgb import color565
from adafruit_rgb_display.ili9341 import ILI9341

from busio import SPI
from digitalio import DigitalInOut
import board

from PIL import Image, ImageDraw

# Pin Configuration
cs_pin = DigitalInOut(board.D8)
dc_pin = DigitalInOut(board.D25)
rst_pin = DigitalInOut(board.D24)

# Set up SPI bus
spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)

# Create the ILI9341 display:
disp = ILI9341(
    spi,
    cs=cs_pin, dc=dc_pin, rst=rst_pin,
    width=240, height=320,
    rotation=90,
    baudrate=24000000
)

# Define image size (320x240, rotated)
IMAGE_SIZE = (disp.height, disp.width)

# Open image
image = Image.open("20210110170457.jpg")

# Resize to screen size
image = image.resize(IMAGE_SIZE, resample=Image.LANCZOS)

# Display image
disp.image(image)

dispインスタンス作成までは先ほどと全く同じです。 その後、Pillowの機能を使って画像を開き、画面サイズにあわせてリサイズしています。 注意点としては、90度回転を指定して液晶を横長で使っているので、Pillowの画像も320x240pxで作成します。

最後にdisp.image()でPillowの画像が表示できます。

これをファイルに保存し、実行すると次のようになりました。

f:id:kimura_khs:20210809181412j:plain

奈良にある東大寺 二月堂【国宝】の写真が映し出されました。

ちなみに、この写真は私が撮影した写真です😆

文字の表示

Pillowがあれば、OpenType/TrueTypeフォントで文字も書けます。 フォントをダウンロードしてみましょう。

$ sudo apt install fonts-noto-cjk fonts-roboto

プログラムは以下のようになります。

from adafruit_rgb_display.rgb import color565
from adafruit_rgb_display.ili9341 import ILI9341

from busio import SPI
from digitalio import DigitalInOut
import board

from PIL import Image, ImageDraw, ImageFont

# Pin Configuration
cs_pin = DigitalInOut(board.D8)
dc_pin = DigitalInOut(board.D25)
rst_pin = DigitalInOut(board.D24)

# Set up SPI bus
spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)

# Create the ILI9341 display:
disp = ILI9341(
    spi,
    cs=cs_pin, dc=dc_pin, rst=rst_pin,
    width=240, height=320,
    rotation=90,
    baudrate=24000000
)

# Define image size (320x240, rotated)
IMAGE_SIZE = (disp.height, disp.width)

# Define fonts
FONT_ROBOTO = ImageFont.truetype("Roboto-Medium.ttf", 12)
FONT_NOTO = ImageFont.truetype("NotoSansCJK-Regular.ttc", 18)
FONT_NOTO_SMALL = ImageFont.truetype("NotoSansCJK-Regular.ttc", 12)

# Define colors
COLOR_WHITE = (236, 239, 241)
COLOR_PURPLE = (239, 154, 154)

# Create an image with black background
image = Image.new("RGB", IMAGE_SIZE, (0, 0, 0))

# Draw some text
draw = ImageDraw.Draw(image)
text = """\
祇園精舎の鐘の声
諸行無常の響きあり
沙羅双樹の花の色
盛者必衰の理をあらはす
奢れる人も久からず
ただ春の夜の夢のごとし
猛き者も遂には滅びぬ
偏に風の前の塵におなじ
"""
for i, line in enumerate(text.split("\n")):
    draw.text((0, 24*i), line, font=FONT_NOTO, fill=COLOR_WHITE)

draw.text((200, 185), "「平家物語」冒頭より", font=FONT_NOTO_SMALL, fill=COLOR_WHITE)
draw.text((40, 200), "みかんのゆるふわ技術ブログ", font=FONT_NOTO, fill=COLOR_PURPLE)
draw.text((100, 222), "www.mikan-tech.net", font=FONT_ROBOTO, fill=COLOR_PURPLE)

# Show it on display
disp.image(image)

これを実行すると、次のようになります。

f:id:kimura_khs:20210809181425j:plain

これで、文字も表示できるようになりました。 QVGAなので近づいてみると多少ギザギザが見えて今時のスマホに少し劣りますが、12ptのフォントでも視認性は十分です👌

文字や画像を組み合わせて、ちょっとした情報をカッコよく表示できるので、皆様もぜひDIYなどにお使いください!