Raspberry Pi 2 Model B + RaspyPlay4 で組んだ volumio サーバーに OLED キャラクタ液晶を接続してみた

2016-08-22 13.13.23

Raspberry Pi 2 Model B に PCM5122 の DAC を搭載したサウンドカード RaspyPlay4 を載せてミュージックサーバーなるものを作ってみました。今は Raspberry Pi 用に様々な DAC 搭載したボードが販売されていて、載せた例も多数 Web 公開されています。私もそういうのを見て、ちょっと組んでみようと思った次第。

今回購入したのは、たまたま RS の通販見ててみつけた RaspyPlay4 という MikroElektronika 製のボード。runeaudio 対応らしいです。

20160716-091455-0

ボードは完成品なので、Raspberry Pi のコネクタに差してしまえば使えます。今回は volumio を Raspberry Pi にインストールしました。volumio には RaspyPlay4 の設定はありませんが、おなじ PCM5122 搭載のボードを選択したら動いたので問題ないかと思います。

このままで使用しても問題ないのですが、基板中央部に LCD と書いたスルーホールがありましたのでやっぱりキャラク液晶付けてみようと設定開始。最終的には、CPU の平均負荷と、空きメモリを表示するようにしてみました。ボリウムの値は MPD, AirPlay, mixer などのボリュームが複数あって、整理出来てなかったためひとまず CPU 負荷とかを出すことに決定しました。

Raspberry Pi でキャラクタ液晶の制御というと、Python の RPi-GPIO モジュールを使うのが簡単らしいので、Python を使うことにしました。よそ様の Web とかに apt-get install python-rpi.gpio すればインストール出来るようなことが書いてあったので、やってみたところパッケージが見つかりません。あれこれ探しましたが見つけられなかったので、本家のソースからビルドすることにしました。

volumio を入れた Raspberry Pi に ssh ログインして作業開始。raspberry-gpio-python
のサイトから RPi.GPIO-0.6.2.tar.gz をダウンロードして、tar zxvf で展開。ビルドするパッケージもインストールして Rpi.GPIO をインストールします。

# wget https://pypi.python.org/packages/c1/a8/de92cf6d04376f541ce250de420f4fe7cbb2b32a7128929a600bc89aede5/RPi.GPI O-0.6.2.tar.gz
wget の URL は、ブラウザなどで確認したアドレスを wget に渡すか、
いったんブラウザで RPi.GPI O-0.6.2.tar.gz をダウンロードしてから Raspberry Pi にアップロードしてください。
# tar ztvf RPi.GPIO-0.6.2.tar.gz 
# cd RPi.GPIO-0.6.2
# python setup.py install
コンパイル環境が無いのでエラーになる
# apt-get install gcc
# apt-get install arm-linux-gnueabihf-gcc
# apt-get install python-dev
# python setup.py install
ワーニングメッセージが出力されるけど、ビルドは通ってライブラリのインストール成功

今回使用した液晶モジュールは共立で買ってきた OLEDディスプレイ キャラクタ表示タイプ 16文字x2行 黄文字 WEH001602A というものです。

で、付録の紙の初期化をやっても動かず、散々苦労した結果動いた Python ソースコードは以下のとおりであります。Adafrit のサンプルが無かったらマジ捨ててたと思う。

#!/usr/bin/env python
#
# WINSTAR OLED 16x2 CHARACTER DISPLAY
# +----+-----+--------------------|
# | No | Pin | Desc               |
# +----+-----+--------------------|
# |  1 | VSS | GND                |
# |  2 | VDD | 3.3V or 5V         |
# |  3 | NC  | Not Used           |
# |  4 | RS  | 0: Command 1: Data |
# |  5 | RW  | 0: Write   1: Read |
# |  6 | E   | Enable             |
# |  7 | D0  | Data bit 0         |
# |  8 | D1  | Data bit 1         |
# |  9 | D2  | Data bit 2         |
# | 10 | D3  | Data bit 3         |
# | 11 | D4  | Data bit 4         |
# | 12 | D5  | Data bit 5         |
# | 13 | D6  | Data bit 6         |
# | 14 | D7  | Data bit 7         |
# | 15 | NC  | Not Used           |
# | 16 | NC  | Not Used           |
# +----+-----+--------------------|

import RPi.GPIO as GPIO
import time
import subprocess

RS = 7
E  = 8
D4 = 25
D5 = 24
D6 = 23
D7 = 22

DATA = True
COMMAND = False

def main():

    i = 0

    setup()

    while True:

        vmstatout = subprocess.check_output(["vmstat"])
        cpuidle = int(vmstatout[233:236])
        cpubusy = 100 - cpuidle

        lcdSetPos(0,0)
        lcdPutStr("CPU{:>3d}%".format(cpubusy))

        lcdSetPos(1,0)
        memfree = int(vmstatout[174:181])
        lcdPutStr("FREE{:7d}KB".format(memfree))

        lcdSetPos(1,15)
        if i == 0:
            lcdPutStr("-")
        if i == 1:
            lcdPutStr("*")
        if i == 2:
            lcdPutStr("|")
        if i == 3:
            lcdPutStr("*")
        i = i + 1
        if i > 3:
            i = 0

        time.sleep(1)

def setup():

    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(E, GPIO.OUT)
    GPIO.setup(RS, GPIO.OUT)
    GPIO.setup(D4, GPIO.OUT)
    GPIO.setup(D5, GPIO.OUT)
    GPIO.setup(D6, GPIO.OUT)
    GPIO.setup(D7, GPIO.OUT)

    time.sleep(0.05)
    lcdPut4bit(0x03)
    time.sleep(0.005)
    lcdPut4bit(0x08)
    time.sleep(0.005)
    lcdPut4bit(0x02)
    time.sleep(0.005)
    lcdPut4bit(0x02)
    time.sleep(0.005)
    lcdPut4bit(0x08)
    time.sleep(0.005)
    lcdPutByte(0x08,COMMAND)
    time.sleep(0.005)
    lcdPutByte(0x01,COMMAND)
    time.sleep(0.005)
    lcdPutByte(0x06,COMMAND)
    time.sleep(0.005)
    lcdPutByte(0x02,COMMAND)
    time.sleep(0.005)
    lcdPutByte(0x0c,COMMAND)
    time.sleep(0.005)

def lcdPutByte(byte, mode):

    GPIO.output(RS, mode)
    time.sleep(0.0001)
    GPIO.output(D4, GPIO.LOW)
    GPIO.output(D5, GPIO.LOW)
    GPIO.output(D6, GPIO.LOW)
    GPIO.output(D7, GPIO.LOW)

    if byte & 0x10 == 0x10:
        GPIO.output(D4, GPIO.HIGH)
    if byte & 0x20 == 0x20:
        GPIO.output(D5, GPIO.HIGH)
    if byte & 0x40 == 0x40:
        GPIO.output(D6, GPIO.HIGH)
    if byte & 0x80 == 0x80:
        GPIO.output(D7, GPIO.HIGH)

    lcdE()

    GPIO.output(D4, GPIO.LOW)
    GPIO.output(D5, GPIO.LOW)
    GPIO.output(D6, GPIO.LOW)
    GPIO.output(D7, GPIO.LOW)

    if byte & 0x01 == 0x01:
        GPIO.output(D4, GPIO.HIGH)
    if byte & 0x02 == 0x02:
        GPIO.output(D5, GPIO.HIGH)
    if byte & 0x04 == 0x04:
        GPIO.output(D6, GPIO.HIGH)
    if byte & 0x08 == 0x08:
        GPIO.output(D7, GPIO.HIGH)

    lcdE()

def lcdPut4bit(byte):

    GPIO.output(RS, GPIO.LOW)
    time.sleep(0.0001)
    GPIO.output(D4, GPIO.LOW)
    GPIO.output(D5, GPIO.LOW)
    GPIO.output(D6, GPIO.LOW)
    GPIO.output(D7, GPIO.LOW)

    if byte & 0x01 == 0x01:
        GPIO.output(D4, GPIO.HIGH)
    if byte & 0x02 == 0x02:
        GPIO.output(D5, GPIO.HIGH)
    if byte & 0x04 == 0x04:
        GPIO.output(D6, GPIO.HIGH)
    if byte & 0x08 == 0x08:
        GPIO.output(D7, GPIO.HIGH)

    lcdE()

def lcdE():

    time.sleep(0.0001)
    GPIO.output(E, GPIO.HIGH)
    time.sleep(0.0001)
    GPIO.output(E, GPIO.LOW)
    time.sleep(0.0001)

def lcdSetPos(line, col):

    rowOffset = (0x80, 0xc0)
    lcdPutByte(rowOffset[line] | col, COMMAND)

def lcdPutStr(str):

    length = len(str)
    for i in range(length):
        lcdPutByte(ord(str[i]),DATA)

def lcdClear():

    lcdPutByte(0x01, COMMAND)

if __name__ == '__main__':

    try:
        main()
    except KeyboardInterrupt:
        pass
    finally:
        lcdClear()
        lcdSetPos(0,0)
        lcdPutStr("Goodbye!")
        GPIO.cleanup()

vmstat コマンドの結果を液晶に表示しているだけです。この部分を変更することで、表示する内容を変更できます。
Raspberry Pi 3 での動作確認は面倒なのでやっていません。もし動かない場合は def lcdE(): の sleep 時間を増やせば動く確率は上がるかと思います。

root@volumio0726:~# cat /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

/home/volumio/pythonスクリプト.py &

exit 0

Raspberry Pi を立ち上げたときに、自動起動するように rc.local に /home/volumio/pythonスクリプト.py & (pythonスクリプトは作成されたファイル名に置き換えてください)を記述します。