レトロでハードな物語

レトロなゲーム機・マイコン・中古デバイスなどをArduinoやAVRで再活用する方法を模索しています。

ゲームボーイでSDメモリカードの読み書き

2019年03月23日 | ゲーム機

これまでゲームボーイとArduinoのシリアル接続を行ってきました。そこで今度はゲームボーイにArduino経由で何かデバイスをつないでみようと思います。まず思いついたのがSDメモリカードです。自作のプログラムに限られますが、ゲームボーイでデータの読み書きができたら、これはもうちょっとしたPDAですね。

ArduinoにはSDカードの読み書きのためのライブラリがあるので、スケッチの作成は難しくはなさそうです。ただ問題なのはSDカードが3.3V(2.7~3.6V)動作だということです。3.3V動作のArduinoなら簡単なのですが、ゲームボーイのシリアル端子は5VなのでArduinoも5V動作のものを使用したいところです。そこで電圧を変換する必要が出てきます。

方法は色々あると思いますが、抵抗による分圧で電圧を下げるのが一般的のようです。Arduinoで使えるSDメモリカード・シールドなどもそうなっているものが多いみたいです。今回は以前も利用したロジックレベル変換モジュールMM-TXS01を使うことにしました。ただ、このモジュールを使うときは5Vと3.3Vと2つの電圧を入力しなければならないので、配線をすっきりさせるため今回使用するArduinoはどちらの出力も持っているLeonardoにします。

さて、肝心なSDメモリカードをArduinoにつなぐコネクタですが、SDHCとかに対応していない古いSDメモリカードリーダーから剥ぎ取りました。miniSDを使うだけなら付属してくるSDカードのアダプタなんかを利用してもいいかもしれませんね。

プログラムについてですが、これまではゲームボーイに外部クロックを与えてデータ送信させていました。今回はゲームボーイからSDカードの読み書きを行うので、送信タイミングをゲームボーイの内部クロックで制御します。そのためLeonardo側でデータを取りこぼさないように、割り込みによるデータ受信を行うようにしました。ところがゲームボーイは1クロックごとに送受信を同時に行う仕様なので、ゲームボーイの内部クロックでLeonardo側からデータ送信を行うときにも割り込みが発生して余計なデータを拾うことになってしまいます。
このときLeonardo側の割り込みを禁止すると、delay()が正常動作しないなどの問題が発生したりしてスケッチ作成がなかなか思い道理に行きませんでした。 それでも試行錯誤してなんとか完成したのがこちらです。

BufferClass.h

GBSD.ino

ゲームボーイのプログラムはこちらです。コンパイル済のバイナリもアップしておきます。

sender.c

sender.gb

ピンアサインは次のようになります。(変換モジュールの部分は省略)

ゲームボーイ端子 → Leonardoピン
2 TXD → 4
3 RXD → 3
5 CLK → 2
6 GND → GND

Leonardoピン → SDカード端子
MOSI(ICSPピン)→ 2 CMD/DI
MISO(ICSPピン)→ 7 DAT0/DO
SCK (ICSPピン)→ 5 CLK
10ピン        → 1 DAT3/CS
3.3V        → 4 VDD
GND         → 3、6 GND



使用方法ですが、上記プログラムを書き込んだゲームボーイとLeonardoを接続したら、まずLeonardoにSDメモリカードをつないで電源を入れます。次にゲームボーイの電源を入れると画面にボタン操作のメッセージが表示されます。AボタンはSDカードへの書き込みで、BボタンはSDカードからの読み込みとなります。

SDカードに書き出すのはプログラムを書き込んだGB USB SMART CARD 64Mが内蔵しているRAM領域A000(MSC1やMBC3のゲームカートリッジに対応していれば他社の製品でも使えるはず)から8Kバイトで、プログラム実行直後に値0〜0xFFが繰り返し書き込まれます。FAT16かFAT32でフォーマットされたSDメモリカードを入れて実行すると、このRAM内容がBINARYW.DATというファイルに出力されているはずですので、バイナリエディタなどで中身を確認してみて下さい。

SDカードからの読み込みは、あらかじめSDカードに保存してあるBINARYR.DATというファイルの中身をゲームボーイのA000番地に書き込みます。ファイルのサイズと中身については任意です。サンプルとして0xAAだけを8Kバイト書き込んだファイルをアップします。

BINARYR.DAT

RAMに書き込まれた内容を確認するときは、再度AボタンでRAM領域をBINARYW.DATに書き出してファイルの中身を見ればRAM内容が分かります。

ちなみに今回のプログラムはエラー処理を一切行っていませんので、ご利用の際にはご注意下さい。

ところで、データ読み書き中にゲームボーイの画面に表示されるインジケータを見ると、書き込みと読み込みのスピードが全然違うことに気がつくと思います。

上記でも少し触れたように、ゲームボーイから書き込みデータが送られてくる時のクロックをLeonardoは割り込みで受けて、受け取ったデータをバッファに入れるようにしていますのでデータ受け渡しが効率良く行われています。

ゲームボーイにデータを送るときも同様にクロックによる割り込みと送信バッファで実現しようとしたのですが、処理が複雑になってビットずれやバッファに余計なデータが入ったりと不具合が頻発したためこの方法は諦めました。かわりにデータ送信時はLeonardo側でクロックを生成するようにしています。このときゲームボーイがデータを取りこぼさないようにdelay()によるウェイトを入れているので、その分のオーバーヘッドで送信が遅くなっているようです。ゲームボーイ側でも割り込みを活用してデータ受信するようにすればいいのですが、処理が複雑になって面倒くさいので作成しませんでした。

もう一点、クロックによる割り込み処理をプログラムしていて気がついたのですが、前回までのシリアル通信のスケッチではゲームボーイのクロックがHIGHのときにデータ取得していましたが、実際はLOWで取得するべきでした。道理でデータ送受信開始時に1ビットずれていたわけです。ゲームボーイ向けではありませんが過去に書いたスケッチでクロック取得はLOWで行っていたのに、なんで気が付かなかったんでしょう。今後は気を付けましょう。

ところでゲームボーイはメモリのバンク切り替えやV-Sync割り込み、サウンドレジスタなどハードウェアを意識したプログラム作成をする必要があるところが昔のパソコンのようで懐かしい感じですね。
開発に使うGBDKはよく出来ていて、ほとんどの処理をアセンブラを使わずにCで書けるのでとても快適です。

ゲームボーイのプログラミングにも慣れてきたので、そろそろ実用的なソフト製作も考えてみましょう。



最新の画像もっと見る

コメントを投稿