前回マイコンでPC-8801エミュレータを動かしてみたら楽しかったので、他のエミュレータも動かしてみたくなりました。ESP32で動くエミュレータは沢山あるのですが、PSRAMを必要とするものが多いようです。せっかくなら、手持ちのPSRAMを搭載していないESP32マイコンボードでも動くような軽いエミュレータにしたいと考えました。探してみたところ、こことかこことかここにあるゲームボーイエミュレータが良さそうです。どちらも元のソースは同じですね。サウンド出力はありませんが、そのおかげでDACの無いマイコンボードでの利用も出来そうです。
これらのエミュレータの元となったSDL2ベースのエミュレータもコンパイルして試しましたが、最低限の機能しかない代わりに軽快に動作しました。若干、再現性に劣る感じもありましたが、ESP32で動かすにはこれくらいのもので十分でしょう。
これらを修正して手持ちのESP32マイコンボードで動くようにしたいと思います。昔、ゲームボーイの実機で様々な電子工作を行ったことがありました。それがマイコン単体で実現できてしまうかもと思うと中々考え深いものがあります。
今回使用するのは、前に秋月電子で購入したESP32-WROOM-32Eです。PSRAMはありませんが低価格でフラッシュメモリ16Mのコストパフォーマンスに優れたボードです。もう一つM5StampS3も使ってみようと思います。PSRAMやDACも無くとても小さなボードです。ピンを2.54mmピッチではんだ付けすると使用できるGPIOも少なくなってしまい、ゲーム機エミュレータにはあまり向いていないマイコンボードです。
ディスプレイにはESP32のミュレータ関連ではおなじみのILI9341タッチパネル付きTFT液晶を使ってみます。ちなみにこのディスプレイは3.3Vでしか使わないので、レベルコンバータを外すためにJ1をはんだ付けしています。このディスプレイ、ブレッドボードでは安定して動かないなどという記事をよく見かけますが、いままでそんなことはありませんでした。もしかするとJ1のジャンパを結線したのが関係あるかもしれません。
他に、LCDコントローラーST7789とキットになっている小型ディスプレイATM0130B3も使ってみようと思います。
ゲームコントローラーはGPIOにスイッチを接続する単純なものと、I2C接続するもの2種類を用意しました。GPIO接続には昔作ったゲームパッドを利用しました。
I2Cのコントローラーは今回の為に作成したもので、独自仕様です。PICを使用したI2Cスレーブデバイスですが、詳細については次回にでも説明します。
まずはESP32-WROOM-32Eから。ディスプレイにILI9341をつなげてみました。コントローラーはGPIO接続かI2Cどちらかをプログラム内で選択します。
配線は次のようにしました。
ILI9341との接続
コントローラーとの接続
プログラムはPlatformIOで開発しましたが、フレームワークにArduinoを使っていますのでArduinoIDEでコンパイルできます。ただし、コンパイルにはゲームボーイのカートリッジから吸い出したROMファイルが必要です。
ソースコードのダウンロードはこちらから。BOOTHをアップローダーとして使っていますが無料でダウンロードできます。
ダウンロードしたファイルを解凍したら、下記の手順にしたがってコンパイルしてください。
●ROMファイルをC言語のヘッダーファイルに変換する
PSRAMの無いESP32では500KB程度のSRAMしかないのでメモリ上にゲームボーイのROMデータを置いておくことはできません(試したところ最大128KのROMまでが限度でした)。そこでROMデータはプログラムに埋め込んでフラッシュメモリに置いておく必要があります。そのためのバイナリデータ→テキスト変換プログラムを用意しました。
ダウンロードしたファイルのbin2textフォルダにあるbin2text.exeを実行します。プログラム実行にはWindowsの.NET8.0が必要です。
ダイアログが表示されたらファイル選択ボタンを押して、あらかじめ用意しておいたゲームボーイのROMファイルを読み込みます。するとgbrom.hというファイルが作成されます。このファイルは下記の手順に従って使用してください。
●PlatformIOでコンパイルする場合
PlatformIOを起動してEspressif ESP32 Dev Moduleのプロジェクトを作成します。
いったんPlatformIOを終了し、ダウンロードしたファイルのWROOM32E_Gamaboy_ILI9341フォルダ内のファイルをプロジェクトフォルダの中に上書きします。
次に上記で作成したgbrom.hをプロジェクトフォルダの中のsrcフォルダにコピーします。
再びPlatformIOを起動するとライブラリのダウンロードが開始されますので、終了したらコンパイルとESP32-WROOM-32Eへの書き込みを行います。
●Arduino IDEでコンパイルする場合
ディスプレイのコントロールにLovyan GFXを使用しますので、ライブラリマネージャーからインストールしておいてください。
ダウンロードしたファイルのWROOM32E_Gamaboy_ILI9341フォルダのsrcの中にあるmain.cppを"任意の名前".inoにリネームします。srcのフォルダも同じ名前に変更しておくといいでしょう。
このフォルダに上記で作成したgbrom.hをコピーします。
Arduino IDEでリネームした.inoファイルを読み込みます。ツールメニューの「ボード」にはESP32 Dev Moduleを選んでください。「Partition Scheme」では必ずFATFSと書いてあるものを選びます。
準備できたらコンパイルとESP32-WROOM-32Eへの書き込みを行います。
二つのコントローラーがつながっていますが、使用できるのはどちらか一方です
プログラムファイルのsdl.cppで様々な設定を行えます。
16行目の #define USEI2CPAD をコメントのままにしておけばGPIOジョイパッドを使用するようになり、コメントを外すとI2Cジョイパッドを使用します。
GPIOジョイパッドの接続ポート番号は30行の padPin[] に記述します。I2CはGPIO21,22を使用します。設定は99行です。
ゲームボーイカートリッジ内にバッテリーバックアップSRAMがあるゲームにも対応していますが、ESP32-WROOM-32Eの電源を切ると内容は消えてしまいます。そのため手動でSRAMデータをフラッシュメモリのFAT領域に書き込む機能があります。上記の配線表の「セーブボタン」がそのための物で、押すとフラッシュメモリにバックアップを行います。次回のゲーム起動時にこのバックアップ内容をSRAM領域にコピーするようになっています。
ゲームデータを保存する必要があるときは、ゲーム終了前などにこのボタンを押しておくようにしましょう。ボタンのGPIO番号は12行目の #define SAVE_BUTTON で設定します。
画面表示にはLovyanGFXを使用しました。さまざまな表示デバイスに対応してくれるので移植が簡単にできるようになります。
ESP32-S3-BOX-Liteに移植してみました
ILI9341の設定は LGFX_ILI9341.h にあります。ここで使用するGPIOの番号を変更できます。解像度が同じ別のデバイスを使うときはこのファイルを差し替えるだけで済みます。デバイスによってはAUTODETECTで判別してくれるものもあるでしょう。
解像度が異なるデバイスを使うときは、sdl.cpp の187、188、200、202行辺りも修正する必要があります。95行で読み込んでいるゲームボーイの枠の画像も変更する必要があります。
バックライトの明るさは93行目です。
上記の設定が間違っていなければ、コンパイル・書き込み後にGAMEBOYのロゴが表示されゲームが起動します。
ゲームボーイと一緒に購入した、当時大ブームだったテトリスを起動してみました。
実はアメリカで購入しているのでカートリッジもUSA版です
懐かしいですねぇ。エミュレータではあの名曲が聴けないのが残念ですが、ちゃんと動作しました。当たり前ですが実機より見やすくて遊びやすいです。でもゲーム表示画面が小さくて長時間の利用だと目が疲れます。
そこでゲーム表示画面を液晶画面いっぱいに拡大する機能をつけました。
小さい文字もだいぶ読みやすくなりました。sdl.cppの15行目にある #define EXPAND_SCREEN のコメントを外すと拡大表示されるようになります。
次はM5StampS3で動かしてみます。StampS3は2.54mmピッチのピンをはんだ付けしているためGPIOゲームパッドにはピンが足りず、I2Cゲームパッドだけ試しました。1.27mmで使用すればGPIOゲームパッドを使うことが出来るでしょう。
ディスプレイはATM0130B3です。これで超小型のゲームボーイをつくることも可能ですね。
配線は次のようにしました。
ATM0130B3(ST7789)との接続
コントローラーとの接続
ダウンロードしたファイルのStampS3_Gamaboy_ST7789フォルダ内にプログラムがあります。コンパイルの手順は上記のESP32-WROOM-32Eと同じです。LavyanGFXの設定は LGFX_ST7789.h です。
バックライトが明るすぎて長時間の直視は目に悪そうです。ATM0130B3のマニュアルにも説明がありますが、バックライトコントロールのためにジャンパをカットしてPWMの端子と接続した方がいいかもしれません。文字も小さいので拡大表示にしないと読みにくいですね。
小さなマイコンボードでエミュレータを動かすのは楽しいですね。ゲームで遊ぶというよりは、様々なゲームが動くのを見て楽しむ感じです。よく自作のミニチュア筐体にマイコンボードを組み込んで昔のPCとかを再現している記事を見ますが、その気持ちが少しわかる気がしました。
※コメント投稿者のブログIDはブログ作成者のみに通知されます