一連の工作が終わったところで接続テストを行います。
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 側でスクリプトを実行してください。
GB の A/B ボタンを押すと、それぞれ $AA,$55 を送信します。
RPi 側は MISO ポートを 0.5秒毎に監視し続けており、入力が入ってきたらその数値を表示します。
CTRL+C で停止します。
見て分かる通り、送信していない時でも 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 が使えないままというのも痛いですよね。
さて、受信側は、いつ受信があるか分からないので、常に何かしらのデータを受信し続けています。
データが無い時でも受信バッファを空読みしています。
そのため、送信側がデータの最上位ビットを送った時に、受信側が受信バッファの途中を読んでいる最中だったりとすると、
データが丸々化けてしまうことになります。送信データの前半分が受信データの後ろ半分になったりするわけですね。
これを避けるために、送信側と受信側で「今から送る」という合図を決めておく必要があります。
具体的には、
- 受信側は常に 0x93 を待機すると同時に 0x39 を送信し続けておく(交換なので受信=送信)。
- 送信側は本データを送信する前に、合図として 0x93 を送信する。
- 送信側は 0x93 を送った結果 0x39 が受信できたら本データを送信する。0x39 でなければ 2. を繰り返す。
- 受信側は 0x93 が来たら、次のデータを本データとして扱う。
前述の通りデータは化ける可能性があるので、合図そのものが正確に伝わるとは限りません。
そこで、合図が正確に伝わるまで繰り返して(何が正確な合図かはお互いが知っているので)
送受信タイミングが合ったところで本データを送ります。
合図が正確に受信できた=正常に送れる状態、とみなすわけです。
100% 大丈夫と言うわけでもないのですが、とりあえず通信失敗は激減しました。
副産物として、合図の後は必ずデータ(空読みでは無い)と決まっているので 0x00 や 0xFF を送っても大丈夫になりました。
ただ、この方式だと実質ビットレートがどのくらいになるのか正確なところは分かりません。
タイミングが合うまで試行を繰り返すので、1byte を送るのに必要な時間はそれなりにかかるかも。
なお 0x93,0x39 という値そのものに特に意味はありません。
この方式のテストプログラムは掲示しませんが、↓の「ポケミクと繋ぐ」にて同方式を採用しています。
今回は使いませんでしたが、GB 側には「シリアル通信割り込み」というものがあり、
シリアル通信完了時に割り込みを入れることが出来ます。
これを使えば、マスター側から通信のリクエストが出来そうなのですが、GB の負荷を増やしたくなかったので見送りました。
512÷8=64KHz で割り込みがかかるのはちょっと重いかなと。。。
GB を SPI マスターとして使うのであれば、使い道は色々ありそうです。