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スクリプトは作成されたファイル名に置き換えてください)を記述します。

Raspberry Pi 2 Model B をやっと無線 LAN 対応にした

2015-06-19 12.33.01

今まで Raspbery Pi を使うときは LAN ケーブルを接続して使っていたのですが、さすがに毎回セットアップすんのも面倒になってきたので無線 LAN アダプタを付けることにしました。買ったのは動作実績がある Buffalo WLI-UC-GNM という子機です。アマゾンの販売価格 713 円なり。まよわず2個購入

2015-06-19 12.31.07

とりあえずセットアップするべくシリアルコンソールに USB シリアル変換を接続して TeraTerm 立ち上げるもコンソール端末が動きません。

2015-06-19 11.23.40

調査の結果

2015-06-19 11.20.49

まさかの圧着不良のケーブルでございました。本体壊れてなくてよかったです。

2015-06-19 12.34.49

気をとりなおして設定作業を続けます。USB のポートに無線 LAN アダプタを入れます。

kernel: [  223.298795] usb 1-1.5: new high-speed USB device number 4 using dwc_otg
kernel: [  223.414612] usb 1-1.5: New USB device found, idVendor=0411, idProduct=01a2
kernel: [  223.414637] usb 1-1.5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
kernel: [  223.414654] usb 1-1.5: Product: 802.11 n WLAN
kernel: [  223.414670] usb 1-1.5: Manufacturer: Ralink
kernel: [  223.414686] usb 1-1.5: SerialNumber: 1.0
kernel: [  223.525784] cfg80211: Calling CRDA to update world regulatory domain
kernel: [  223.708837] usb 1-1.5: reset high-speed USB device number 4 using dwc_otg
kernel: [  223.817845] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 3070, rev 0201 detected
kernel: [  223.840939] ieee80211 phy0: rt2x00_set_rf: Info - RF chipset 0005 detected
kernel: [  223.863206] ieee80211 phy0: Selected rate control algorithm 'minstrel_ht'
kernel: [  223.865320] usbcore: registered new interface driver rt2800usb
ifplugd(wlan0)[2085]: ifplugd 0.28 initializing.
kernel: [  223.926606] ieee80211 phy0: rt2x00lib_request_firmware: Info - Loading firmware file 'rt2870.bin'
kernel: [  223.930068] ieee80211 phy0: rt2x00lib_request_firmware: Info - Firmware detected - version: 0.29
ifplugd(wlan0)[2085]: Using interface wlan0/CC:E1:D5:3F:34:8A with driver <rt2800usb> (version: 3.18.7-v7+)
ifplugd(wlan0)[2085]: Using detection mode: SIOCETHTOOL
ifplugd(wlan0)[2085]: Initialization complete, link beat not detected.

さくっと認識します。

root@rasp2:/var/log# lsusb
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. 
Bus 001 Device 004: ID 0411:01a2 BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM Wireless LAN Adapter [Ralink RT8070]

lsusb コマンドも問題なし。使う無線 LAN が認識できるか wpa_passphrase コマンドを使って確認します

root@rasp2:/var/log# wpa_passphrase 無線LANのSSID パスフレーズ
network={
	ssid="無線LANのSSID"
	#psk="パスフレーズ"
	psk=70f16dae8c39c15a7f923e525edd84112bbf52525b92f6d7bb449be615b6943a
}

network= というのが表示されたら通信出来るようです。ここまでで確認作業は終り。続いて設定作業です。最初に、上記 wpa_passphrase コマンドで表示された結果を /etc/wpa_supplicant/wpa_supplicant.conf ファイルに追記します。エディタでコピペして追加してもいいですし、wpa_passphrase 無線LANのSSID パスフレーズ >> /etc/wpa_supplicant/wpa_supplicant.conf のような方法でもかまいません。追加できたらいいです。

root@raspberrypi:/etc/network# cat interfaces
auto lo

iface lo inet loopback

#iface eth0 inet dhcp
iface eth0 inet static
address 192.168.24.188
netmask 255.255.255.0
gateway 192.168.24.1
network 192.168.24.0
broadcast 192.168.24.255

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
#iface default inet dhcp
iface default inet static
address 192.168.24.186
netmask 255.255.255.0
gateway 192.168.24.1
network 192.168.24.0

/etc/network/interfaces に無線LANアダプタの設定を追加します。allow-hotplug wlan0 以下の行ですね。今回 IP アドレス固定で使う設定にしました。

dhcp 設定でもDNS 登録するようにしておいて、ホスト名で端末接続できるようにするほどでもないので設定はこれにて完了。

# ifdown wlan0
# ifup wlan0

接続確認は if コマンドでインタフェース起動か、OS reboot させてインタフェースを立ち上げます。ifconfig で wlan0 が上っていたら成功です。

ちなみに、この無線LANアダプタわりと発熱します。ケースに入れてる人は連続使用時の温度は確認したほうがいいと思います。

Raspberry Pi 2 購入

2015-02-13 22.17.23

最近発売になった Raspberry Pi 2 です。RSのサイトで頒布物のパーツ注文するついでに買おうと思っていたのですが、肝心のパーツは在庫切れ、Raspberry Pi 2 もクリック出来ない状態というやつで手配出来ない事態に。仕方ないので、大阪帰る前に秋月寄ったとき代替パーツと共に玄関先のワゴンに積まれてたRaspberry Pi 2 も 1個購入。まぁ、なんといいますか、PC 好きな人がハードディスク買うような感覚の買い物でしょうかねぇ。マイクロSDカード買い忘れてたのでカメラ屋さんでマイクロSDカードを購入。

本家のサイトから ARM 用 Linux のディストリをダウンロードして、マイクロSDカードに書き込みます。今回も Raspbian という Debain GNU Linux のイメージをマイクロSDカードにツールを使って書き込み。

2015-02-14 08.18.23

私の家には、USB キーボードが無いため、Raspberry Pi 2 の初期セットアップを HDMI 出力 + キーボードという組み合わせで行うことが出来ません。私の場合はシリアルコンソールから初期セットアップを行います。写真のように、ヘッダーピンには以前の Raspberry Pi 同様シリアル出力が出ていますので、ここに USB シリアル変換を差して PC の Teraterm から設定をします。このとき使用する USB シリアル変換の I/O は 3.3V 対応にしてください。

シリアルコンソールからログイン出来たら、必要最低限の設定を $ sudo raspi-config して行います。とりあえずファイルシステム設定でSDカード全体使うように設定するのと、ホスト名変更と、SSH サーバーが有効になっていることを確認。次に /etc/network/interfaces の有線LANの設定を固定IPに変更してリブート。

2015-02-14 08.17.59

LAN ケーブルをノートPCに接続。私のノート PC は無線 LAN でルータと繋っているので、Windows のコンパネから、無線 LAN と RaspberryPi 2 を繋いだ有線 LAN をブリッジさせます。このブリッジさせることで、ノート PC が HUB みたいな感じになります。Teraterm の ssh 接続で Raspberry Pi 2 にログインして、sudo apt-get install dnsutils を行い nslookup コマンドをインストール。
nslookup コマンドで 自宅以外のドメイン名入れてお返事出てくれば問題なし。駄目なら /etc/resolv.conf 確認したらいいと。ネットワークが動けばなんとかなるので、最初のセットアップはここまでやって終了。

あ、ちなみにストロボ焚いて誤動作するのを再現させるテストはやってませんよ