GB 通信 - Raspberry Pi との接続およびポケットミク(NSX-39)の制御 -


img
GB の通信についての応用編です。
今度は GB の通信ポートと Raspberry Pi の SPI ポートを接続します。
SPI は GB のネイティブな通信方式と似ており、高速な通信が可能で様々な応用が考えられます。

今回の目標は Raspberry Pi を USB ホストにして、学研大人の科学の「ポケットミク(USB MIDI音源)」を接続し、
GB から間接的にコントロールすることです。

8bit 携帯ゲーム機が何倍もの性能のマシンや楽器を制御するというのも面白い所だと思います。




■ お さ ら い

筆者は嘘でも誇張でも無く真性ド素人なので、間違ったことを書いている可能性が大いにあります。
以下の記事の取り扱いには十分注意してください。

さて、基礎編「通信ポートで遊ぶ」では RS-232C 方式で他の機器とやりとりできるようになったわけですが、
信号タイミングを作っている間は CPU は何もできませんし、通信用のハードもちょっとゴツいですよね。
やはり I/O ポートに 1 byte ポンと書き込んで「コレ送っといて」と指示したら、後はハードが勝手に通信しておいてくれるのが理想です。

というわけで、GB ネイティブ通信の基本に立ち返ってなんとか出来ないか考えてみることにします。



図の通り、GB では 送信、受信、クロックの 3 本のラインで接続します。
送受信はクロック信号に従って 1bit ずつ同時に行います。8 クロックで 1byte 分の送受信が完了。
一連の作業はハードがやってくれるので CPU は「コレ送っといて」と指示するだけで Ok です。

で、SPI(=Serial Periferal Interface) という通信方式もこれとほとんど同じだったりするのです。
複数の機器を同時に使えるように CE(=Chip Enable) 線があったり、クロックの立ち上がり/下がりタイミングを設定できたり
最上位ビットからでなく最下位ビットから送るように出来たりと、細かい違いはありますが基本的には同じ 3 本のラインでの通信。

他に I2C という通信方式もあります。これはデータ+クロックの2本だけでやりとりするようです。詳細は割愛。

今回は GB の相手となる SPI 搭載マシンとして Raspberry Pi を選択します。なんといっても資料多いですしねー。


そうそう、SPI に関していくつか注意点があります。

■ OS の設定

分かる人は飛ばしてください。筆者は分からないサイドの人なので備忘録代わりに書いておきます。

RPi の OS は Raspbian Wheezy を使います。バージョンは忘れた・・・。
一応、最新の状態にしておきます。時間がかかるかも。
$ sudo apt-get update
$ sudo apt-get upgrade

SPI が無効化されているのを解除。
$ nano /etc/modprobe.d/raspi-blacklist.conf

頭に # を付けてコメント化します。これで SPI が有効に。ctrl+O,ctrl+X で上書き保存。
#blacklist spi-bcm2708
仲良くブラックリスト入りしている I2C の方も使う予定があるなら同様に有効化しておいても良いでしょう。

SPI ドライバも組み込まないといけません。起動時に自動的に組み込まれるように modules を編集。
$ nano /etc/modules 

最後尾に以下を追加して上書き保存。
spidev              

おもむろに再起動。
$ sudo reboot       

デバイスかくにん! よかった。
$ ls /dev/spi*      
/dev/spidev0.0  /dev/spidev0.1
黄文字のメッセージが出れば Ok です。入出力 2 系統あるのでデバイスも 2 つなんですね。

今回、RPi 側は python で制御するので、SPI を扱えるようにするための py-spidev を組み込みます。
の前に python-dev と git もインストールしないと。
だんだんダルくなってきました。
$ sudo apt-get install git-core
$ sudo apt-get install python-dev
$ cd /usr/src
$ sudo git clone git://github.com/doceme/py-spidev  
$ cd py-spidev
$ sudo python setup.py install
なにやら一杯文字列が出ますがこれにて OS の設定は終了。

http://elinux.org/RPi_SPI RPi の SPI 仕様はこちら。
py-spidevの説明(PDF) はコレでいいと思う。
できれば信号タイミングなども知りたいところ。


■ GB <-> Raspberry Pi 通信ケーブルを作る

前述の通り、GB 側通信ポートは信号レベルが 5V、対する RPi 側 SPI は 3.3V なので、変換器を挟む必要があります。
挟まずに直結すると機器が壊れる危険性があるとのこと。面倒だけど仕方ないですね。

電子工作の世界では 5V<->3.3V は定番の「あるあるネタ」らしいので、それ専用のキットや回路図がたくさん出回っています。
筆者は Sunhayayo の MM-TXS01 というロジックレベル変換モジュールを使いました。

赤裸々な配線例。
RPi側の CE (Chip Enable)端子は使いません。GB側 pin4 に接続しておく手もありそうですが使い道が無いような・・・。


MISO = Master In Slave Out (GPIO 9)
MOSI = Master Out Slave In (GPIO 10)
SCLK = Serial Clock

Q. どうして飛び飛びに配線しているの? A. 不器用なので。
Q. A3-B3/A5-B5 は逆が良くなかった? A. 入力イラネ → やっぱいるわ、の結果。

以上ブレッドボード使えで終わる話でした。

この手のモジュールは他にも色々あると思うので目的に沿っていれば好きにして良いと思います。
今回は、GB(5V)->RPi(3.3V) だけでなくその逆(3.3V->5V)も使うので「双方向」である必要があります。
GB のピン配置は基礎編の方をご覧ください。GB 通信ケーブルは反対側を D-Sub コネクタ等にしておくと使い回せて便利。

おっと、そういえば筆者の Raspberry Pi は Model-B rev.2 です。
Model-A とか rev.1 でも大きくは違わないはずですが、今一度ピン番号の確認を。
最近 SO-DIMM っぽい新型とか Model-B+ とか発表されましたね。

■ テ ス ト

一連の工作が終わったところで接続テストを行います。
8bit 携帯ゲーム機とつながるのが、何倍もパワフルなのに GB より一回り小さいシングルボードマシンというのも妙な感じですね。


接続図。何故画像を縦にしなかった・・・。
新しく出た Type-B+ はピンが増設されてるんでしたっけ。資料を見てよく確認しましょう。

gbspi.zip
GB 用のテスト ROM と Raspberry Pi 用の Python スクリプトを置いておきます。

 #!/usr/bin/python
 import spidev
 import time
 
 spi = spidev.SpiDev()
 spi.open(0, 1)
 spi.max_speed_hz = 524288
 
 try:
         while   True:
                 r = spi.readbytes(1)  
                 print '%02X' % r[0]
                 time.sleep(0.5)
 except	 KeyboardInterrupt:
         spi.close()
 #end

python スクリプトも短いので載せておきます。
GB の ROM はエミュレータで動かしても意味は無いのであしからず。

GB が起動して「PRESS BUTTON」画面が出たら、RPi 側でスクリプトを実行してください。
$ python spitest1.py       

GB の A/B ボタンを押すと、それぞれ $AA,$55 を送信します。
RPi 側は MISO ポートを 0.5秒毎に監視し続けており、入力が入ってきたらその数値を表示します。
CTRL+C で停止します。

 00		
 00		
 55		
 FF		
 FF		
 AA		
 00		
 00		

見て分かる通り、送信していない時でも 0xFF や 0x00 を「受信」しています。
これは受信バッファに残された直近のビットを拾ってしまうために起こる現象で、0x55(01010101)の後は 1、0xAA(10101010) の後は 0 が
拾われて、8回繰り返されることで 0xFF や 0x00 になってしまうのです。
この方式で受信をするのであれば、0xFF や 0x00 を使わない(意味のあるデータと見なさない)などの対策が必要になります。

速度は、上記のスクリプトでは 524288Hz で実行しています。
SPI 通信においてクロックを駆動するのはマスター側であり、
今回のマスターである Raspberry Pi では、32MHz あたりまで上げられるそうです。
気になるのは、GB 側がどこまで高速化に耐えられるか(追従できるか)です。
524288Hz というのは「それくらいまで大丈夫だった」という記述が、とある技術資料にあったからなのですが、もう少し頑張ってみます。

2倍速の 1,048,576Hz(1Mbps)でも OK でした。
4倍速の 2,097,152Hz(2Mbps)でも OK でした。
8倍速の 4,194,304Hz(4Mbps)でも OK でした。
12倍速の 6,291,456Hz(6Mbps)でも OK でした。
16倍速の 8,388,608Hz(8Mbps)は NG でした。

ということで、6Mbps 近辺が限界ではないかと思われます。これは正直驚きました。
GB の CPU クロックが倍速モードで 8,388,608 Hz なので、これを超えるのは無理だろうとは思っていましたが思いのほか好成績。

ただし、継続して検証した訳でも無いので安定して送れているかどうかは分かりません。
また RPi 側のマスタークロック設定をそのまま鵜呑みにしていいのかどうかも筆者にはよく分かりません。
なので、今回は安全策として 524288Hz を採用することにしました。
追記:間に挟んである 5V-3.3V 変換モジュールの性能も影響があるらしいです。

・・・
・・・
・・・
と、ここまでは最も基本的な通信の話。
データをもっと確実に送るためには、もう少しマシなハンドシェイクが必要になります。
0.5 秒毎に送受信というのも今ひとつ遅いですし、0x00 や 0xFF が使えないままというのも痛いですよね。

さて、受信側は、いつ受信があるか分からないので、常に何かしらのデータを受信し続けています。
データが無い時でも受信バッファを空読みしています。
そのため、送信側がデータの最上位ビットを送った時に、受信側が受信バッファの途中を読んでいる最中だったりとすると、
データが丸々化けてしまうことになります。送信データの前半分が受信データの後ろ半分になったりするわけですね。

これを避けるために、送信側と受信側で「今から送る」という合図を決めておく必要があります。
具体的には、
  1. 受信側は常に 0x93 を待機すると同時に 0x39 を送信し続けておく(交換なので受信=送信)。
  2. 送信側は本データを送信する前に、合図として 0x93 を送信する。
  3. 送信側は 0x93 を送った結果 0x39 が受信できたら本データを送信する。0x39 でなければ 2. を繰り返す。
  4. 受信側は 0x93 が来たら、次のデータを本データとして扱う。
前述の通りデータは化ける可能性があるので、合図そのものが正確に伝わるとは限りません。
そこで、合図が正確に伝わるまで繰り返して(何が正確な合図かはお互いが知っているので)
送受信タイミングが合ったところで本データを送ります。
合図が正確に受信できた=正常に送れる状態、とみなすわけです。
100% 大丈夫と言うわけでもないのですが、とりあえず通信失敗は激減しました。
副産物として、合図の後は必ずデータ(空読みでは無い)と決まっているので 0x00 や 0xFF を送っても大丈夫になりました。

ただ、この方式だと実質ビットレートがどのくらいになるのか正確なところは分かりません。
タイミングが合うまで試行を繰り返すので、1byte を送るのに必要な時間はそれなりにかかるかも。
なお 0x93,0x39 という値そのものに特に意味はありません。
この方式のテストプログラムは掲示しませんが、↓の「ポケミクと繋ぐ」にて同方式を採用しています。


今回は使いませんでしたが、GB 側には「シリアル通信割り込み」というものがあり、
シリアル通信完了時に割り込みを入れることが出来ます。
これを使えば、マスター側から通信のリクエストが出来そうなのですが、GB の負荷を増やしたくなかったので見送りました。
512÷8=64KHz で割り込みがかかるのはちょっと重いかなと。。。
GB を SPI マスターとして使うのであれば、使い道は色々ありそうです。


■ ポケットミク(NSX-39)と繋ぐ

「ポケットミク」とは、学研社「大人の科学マガジン」シリーズの特別編集「ふろく」として 2014年4月に発売された USB-MIDI 楽器です。
ソフト音源一辺倒の時代に、その極北ともいえるボーカロイドがハード音源となって帰ってくるというのも中々面白いですね。
実は中身はソフトウェア実装という話もありますが。

仕様書を読んで実際使ってみて、MIDI 楽器としてはそれほど難しく無さそうだったので GB で動かしてみることにしました。
Raspberry Pi の USB 端子にポケミクを繋いで、SPI 経由で GB からコントロール、という寸法です。
で、GB でピアノロール風のボーカロイドエディタを作るのがいいかなーと思っていたのですが、
それってスマホやタブレットに繋いで鳴らすのと出音の面では変わらないし、面白いのは見た目だけで運用面でいえばむしろ劣ってますよね。


GB の画面デザインもちょろっと考えてみたのですが見るからに使えなさそうなのでボツ。

というわけでこの案はさっくり捨てて、GBとポケミクで同期演奏をすることにしました。ありがちー。
『たしかに誰もやっていないけれど、作る方も見る方も一度で充分』という案件ですな。実にしょっぱい。

一応ポイントとしては、USB 機器を USB 端子の付いていない GB から間接的に制御出来るよ!という話です。
ただの MIDI 楽器のコントロールなら基礎編で既に経験済みなので、目新しい点としてはそこだけ。

MIDI の取扱いには pygame ライブラリを使います。これは特にインストールしなくても最初から入っているはず。
元々は RPi で手軽にゲームを作れるように準備されているものらしく、USB で接続された MIDI 機器やソフトシンセを使って
曲を演奏したりできるようになっています。
pygame.midi の解説はこちら。

これを使って、先の SPI 受信スクリプトに少々付け足して MIDI メッセージとして横流しするようにすれば Ok.

ただし、pygame は MIDI メッセージを 1byte 単位で出力する機能は無いようで、
ある程度整形してから出力しなければなりません。
pygame でない他の手段、他の言語であれば可能だろうとは思いますが、おそらく次は無いのでこれでいきます。

1)システムエクスクルーシブは可変長 [F0] ... [F7]
2)それ以外は 3byte 決めうち [Status] [data] [data]

として MIDI メッセージを垂れ流すことにしました。うわー。

たったこれだけの仕組みなので、別に Raspberry Pi でなくてもかまいません。
RPi はポケミクに対する USB ホストとしてしか使っていないので Arduino や Beagle Board はたまた PIC でも
USB-MIDI 機器として認識できてメッセージ横流しプログラムが用意できれば問題ないはずです。バッファリングあるとなお良し。

一番いいのは GB とポケミクを直結できることだったんですけどねー。
そういえば USB ホスト専用のアダプタみたいな MIDI 機器があるのですが \20,000 くらいするんですよね。高杉。

ポケミクで使う歌唱データは domino で編集して SMF に変換しておきます。
まともに歌わせるのが非常に難しくて大変でした。完璧とは言いがたい出来ですが、正直もうやりたくない・・・。
できあがったデータは歌唱用のトラックしか使わないので、SMF を編集して余計なデータはカットしてあります。

再生に使う GB 用 SMF プレイヤーも pygame.midi に渡すことを前提に、基礎編で使ったものを改造しました。
ランニングステータスを使わないようにしたり、2byteイベントでも3byte渡すようにしたり・・・。

GB 音源側も自作のドライバを使っています。
これも今回の用途に合わせて多少カスタマイズしてあります。
曲は MML で書きました。ボーカルと別編集なのでこれまた大変。



ミキシングスキルの無さが恨めしい。

ニコニコ動画のアカウントが無い人用 その1
ニコニコ動画のアカウントが無い人用 その2

gb_pocketmiku_demo.zip
ソースコードを置いておきます・・・が、大人の事情により曲データを抜いてあるのでコンパイルは失敗します。
今回は使っていませんが、GB からリアルタイムで NSX-39 をコントロールする nsx39.z80 も添付しておきました。


なんだかよく分からないデモ画面。

■ あ と が き

ここに置いたプログラムは GBC 専用ですが、改造すればモノクロ GB でも原理的には動くはず。
また、GBA は通信ポートに互換性が無いので GB モードで動かしても事実上使えません。
GBA は GBA ネイティブでやったほうが良いと思います。

今回の意義としては
1)GB 側をマスターとした SPI 通信で各種センサとつながるかも
2)RPi 等と繋いで、マスター側のストレージ・LAN・Bluetooth・USB・計算資源・その他リソースを物理的に使えるかも
3)RPi 等のマスターから GB 側のハードウェア資源を使えるかも

といった所だと思います。ポケミクと繋ぐのは 2 番目のカテゴリですかね。
ただ、筆者としては携帯ゲーム機のアイデンティティであるモビリティが薄まってしまうのが、少しばかり残念です。
通信に関してもエラー検知→再送みたいな仕組みが無いので、安心して取り回しができません。GB ほぼ置物化。

さらに言うと、今のところ単に繋いだだけであって、ここからの一歩がいつも大変なんですよね。
SNS に投稿する BOT を作るのもいいし Kinnect や GIMIC を繋ぐのもアリかもしれませんが、形にするにはまだまだハードルが高いです。

こういう研究は大抵 NES/FC に先行されてしまうのでその点(だけ)は良かったかなw

余談ですが、工学社 I/O Books の「ラズベリー・パイでつくる電子工作」という本が良書でした。
薄くて少し高いけれど、同ジャンルの中では初心者のツボを突いていて最もよくまとまっていると思います。
Arduino 向けの本も出ているようです。

▲ TOP