KM-Z80 midi 進捗:液晶表示
2019年9月23日
KM-Z80 midi (MZ-80K 互換機)をバージョンアップし、2019年9月現在、ver 0.4としている。ver 0.1からの変更は、以下の通り。
・アプリケーションのロード機能を追加。
・緑LEDをRB0に繋がず、トランジスターなどを用いてRB1から制御するようにした。
・液晶(ILI9341・SPI接続)表示にも対応。
・RB5とRB15の機能を入れ替えた。
・CMT機能の呼び出しの際、002xhでなく04xxhを呼び出しているプログラムに対応。
・FORMなど、分割ファイルの読み込みを行なっているプログラムに対応。
・プログラムセーブ時の不具合を解消。
・ソースコードのコンパイルにおいて、XC32 ver 1.32だけでなく上位のバージョンの XC32 コンパイラーにも対応。
・回路図微修正(LCDのバックライト電圧を3.3vに)。
写真は、SPI接続のILI9341液晶(3.2 インチ)を繋いで実行している所。
現在の回路図は以下の通り(クリックで拡大表示)。
液晶対応
ver 0.1の回路図を見て頂いて分かるように、当初から液晶表示に対応する予定でいた。使用するのは、ILI9341を用いたSPI接続のインターフェースで、240x320ドットの表示ができるタイプ。これを横置き(320x240)とすれば、8x8ドットの文字が40x30文字表示可能なので、40x25文字が必要なMZ-80Kに使うのに、ちょうど良いサイズ。このタイプの液晶ディスプレイとしては、ILI9341を用いて、4-wire SPIのインターフェースのものが最も一般的で需要が高いようなので、それを選択した。
この液晶の使い方について色々調べてみたところ、次の様な理解になった。
・インターフェースとしては、最低限 CS, MOSI, CLK, DC の4本が必要で、液晶からのデーター読み込みもするなら、さらに MISO が1本、合計5本が必要。
・キャラクターディスプレイのように使う事はできず、グラフィックディスプレイとして機能する。
・1ドットの表示には、16 bitsでカラー指定する。
・データーシートにおける SPI の最高速度は、10 MHz。
5本の連絡線は当初から確保してあったが、当初LEDとDCと共通で使うつもりであったRB0を、DC専用として、安定動作を計った。最初の問題が、PICからの信号連絡の方式をどうするかであった。1ドット2バイトなので、8x8ドットの文字表示には 128 バイトのデーター送出が必要である。表示位置もデーター送出しないといけない事を考えると、40x25文字の全てのデーターを送出すると、合計で134125バイト必要である事が分かった。10 MHzのSPIでこれを行なうと、107ミリ秒以上が必要である。実際には連続して送出する事はできないだろうから、200ミリ秒ほど(5 frames per second; 5 fps)になると思われる。この速度では、スクロールゲームなどには対応できないと思われる。
NTSC等と違い、液晶表示の場合は画面を常にリフレッシュし続ける必要はない。MZ-80Kの中でVRAM領域に書き込みがあった時のみ、液晶側にもデーターを送出するだけで、事足りる。この方式をとった場合、ひと文字当り139バイト、1112ビットの送出になる。10 MHzのSPIを使った場合、2 MHzで動くZ80 CPUのクロック数としては、222クロック分になり、この間 Z80 CPU を待たせる事になってしまう。Z80 命令の LDIR 等を使った場合、21クロックで済む所であるから、明らかに遅すぎる。VRAM変更データーをどこかにキャッシュして時間に余裕のある時にSPI送出するにしても、キャッシュが一杯になると誤作動してしまう。やはり、VRAM領域全体をキャッシュのように扱い、これを定期的に液晶側にデーター送出するのが、一番安定した実装方法であろう。
色々調べると、「ESP8266用ILI9341ライブラリの高速化」というブログ記事を見つけた。次のような記述がある。
Adafruit_ILI9341のSPIのクロックの設定は24MH。しかし、問題無く動いていた。調べるとESP8266のSPIクロックは最大80MHz。試しに80MHzでプログラムを動かすと、問題無く動いているように見える。他のプログラムで試した時、80MHzでは書込みミスが発生したので、最終的に40MHzにした。
ILI9341のSPIは、40 MHzぐらいでも問題なく信号のやりとりができるようで、このオーバークロックで実装全体を考えてみた。PIC上でCPUは48 MHzで動いていて、SPI通信の最高速度としても、48 MHzが選択できる(REFOCONを使用)。この速度で使ってみると、確かにエラーはほとんど起らないようだ。定期的に画面データーを送出し続ける場合には、低頻度のエラーは許容できる。割り込みを用いて定期的にVRAMのデーターに基づきSPI送信する方式にして、15 fps の実装が実現できた。上記の写真ではスクロールゲームのBugFireを実行しているが、全く問題なく遊べる事が分かった。
アプリケーションロード機能
このプロジェクトは、MachiKaniaの一つのタイプとして考えている。MachiKaniaの特徴としては、ボタンを押しながら起動する事でブートローダーが立ち上がり、HEXファイルを選択する事でアプリケーションの切り替えができる事が挙げられる。この機能を是非とも実装したい。
KM-Z80 midiの特徴としては、SD/MMCカードではなくUSBメモリーを使っている事がある。この、USBホストのインターフェース部分のプログラムはかなり大きく、ブートローダーにこれを組み入れると大容量の領域を占有してしまう。MachiKaniaの他のタイプと同じメカニズムを採用すると、後にMachiKania BASIC用の容量が足りなくなってしまう事が分かった。方式を変えないといけない。
MachiKania type N/Z/Mの場合、ブートローダーを構築するフラッシュ領域は、アプリケーションを構築するフラッシュ領域と分けられている。従って、ブートローダー上のコードでアプリケーション用のフラッシュ領域を書き換える事ができる(その逆も理論的には可能)。KM-Z80 midiでは、上の段落で述べたように、ブートローダー領域をアプリケーション領域と分ける事ができない。アプリケーション用のフラッシュ領域を書き換えるためには、この領域以外でコード実行しなければならない。唯一の方法は、フラッシュ領域を書き換えるためのコードをRAM上で実行する事である。
この目的のために、RAM上で実行するフラッシュ書き換えプログラムを作成した。GitHubで公開している。このプログラムの特徴は以下の通り
1)RAM上で走るプログラム
2)USB host機能を持つ
3)ファイルシステムIOを持つ
4)Intel HEX ファイルを読み込み可能
5)フラッシュ書き込み機能を持つ
特徴は、リンカースクリプトの以下の記述に現れている。
使用する際は、このhexファイル(fwiter.hex)中の0xA0002000-0xA000FFFFの領域をRAMに書き込み、アプリケーションHEXファイルのファイル名を0xA000FFF0からの領域に書き込んで、0xA0003000からコードを実行すればよい。KM-Z80 midiのそれぞれのアプリケーション内で、ファイル選択してこのfwriteに処理を引き継ぐ用にすれば、PicKit無しでアプリケーションの切り替えができるようになった。
今後の予定
今後の予定としては、次のような事を考えている。
1)MZ-80Kミニチュア版のような格好いい筐体を作製
2)キーボード部のカバーを、紙から3Dプリンター製のものに変えて使いやすく
3)MachiKania BASICも使用出来るようにする
4)CP/Mも使用出来るようにする(ほぼ完成)
5)Fuzixも対応できたらいいなぁ(独り言)
バージョン 0.4 は、GitHubにてダウンロード出来ます。
・アプリケーションのロード機能を追加。
・緑LEDをRB0に繋がず、トランジスターなどを用いてRB1から制御するようにした。
・液晶(ILI9341・SPI接続)表示にも対応。
・RB5とRB15の機能を入れ替えた。
・CMT機能の呼び出しの際、002xhでなく04xxhを呼び出しているプログラムに対応。
・FORMなど、分割ファイルの読み込みを行なっているプログラムに対応。
・プログラムセーブ時の不具合を解消。
・ソースコードのコンパイルにおいて、XC32 ver 1.32だけでなく上位のバージョンの XC32 コンパイラーにも対応。
・回路図微修正(LCDのバックライト電圧を3.3vに)。
写真は、SPI接続のILI9341液晶(3.2 インチ)を繋いで実行している所。
現在の回路図は以下の通り(クリックで拡大表示)。
液晶対応
ver 0.1の回路図を見て頂いて分かるように、当初から液晶表示に対応する予定でいた。使用するのは、ILI9341を用いたSPI接続のインターフェースで、240x320ドットの表示ができるタイプ。これを横置き(320x240)とすれば、8x8ドットの文字が40x30文字表示可能なので、40x25文字が必要なMZ-80Kに使うのに、ちょうど良いサイズ。このタイプの液晶ディスプレイとしては、ILI9341を用いて、4-wire SPIのインターフェースのものが最も一般的で需要が高いようなので、それを選択した。
この液晶の使い方について色々調べてみたところ、次の様な理解になった。
・インターフェースとしては、最低限 CS, MOSI, CLK, DC の4本が必要で、液晶からのデーター読み込みもするなら、さらに MISO が1本、合計5本が必要。
・キャラクターディスプレイのように使う事はできず、グラフィックディスプレイとして機能する。
・1ドットの表示には、16 bitsでカラー指定する。
・データーシートにおける SPI の最高速度は、10 MHz。
5本の連絡線は当初から確保してあったが、当初LEDとDCと共通で使うつもりであったRB0を、DC専用として、安定動作を計った。最初の問題が、PICからの信号連絡の方式をどうするかであった。1ドット2バイトなので、8x8ドットの文字表示には 128 バイトのデーター送出が必要である。表示位置もデーター送出しないといけない事を考えると、40x25文字の全てのデーターを送出すると、合計で134125バイト必要である事が分かった。10 MHzのSPIでこれを行なうと、107ミリ秒以上が必要である。実際には連続して送出する事はできないだろうから、200ミリ秒ほど(5 frames per second; 5 fps)になると思われる。この速度では、スクロールゲームなどには対応できないと思われる。
NTSC等と違い、液晶表示の場合は画面を常にリフレッシュし続ける必要はない。MZ-80Kの中でVRAM領域に書き込みがあった時のみ、液晶側にもデーターを送出するだけで、事足りる。この方式をとった場合、ひと文字当り139バイト、1112ビットの送出になる。10 MHzのSPIを使った場合、2 MHzで動くZ80 CPUのクロック数としては、222クロック分になり、この間 Z80 CPU を待たせる事になってしまう。Z80 命令の LDIR 等を使った場合、21クロックで済む所であるから、明らかに遅すぎる。VRAM変更データーをどこかにキャッシュして時間に余裕のある時にSPI送出するにしても、キャッシュが一杯になると誤作動してしまう。やはり、VRAM領域全体をキャッシュのように扱い、これを定期的に液晶側にデーター送出するのが、一番安定した実装方法であろう。
色々調べると、「ESP8266用ILI9341ライブラリの高速化」というブログ記事を見つけた。次のような記述がある。
Adafruit_ILI9341のSPIのクロックの設定は24MH。しかし、問題無く動いていた。調べるとESP8266のSPIクロックは最大80MHz。試しに80MHzでプログラムを動かすと、問題無く動いているように見える。他のプログラムで試した時、80MHzでは書込みミスが発生したので、最終的に40MHzにした。
ILI9341のSPIは、40 MHzぐらいでも問題なく信号のやりとりができるようで、このオーバークロックで実装全体を考えてみた。PIC上でCPUは48 MHzで動いていて、SPI通信の最高速度としても、48 MHzが選択できる(REFOCONを使用)。この速度で使ってみると、確かにエラーはほとんど起らないようだ。定期的に画面データーを送出し続ける場合には、低頻度のエラーは許容できる。割り込みを用いて定期的にVRAMのデーターに基づきSPI送信する方式にして、15 fps の実装が実現できた。上記の写真ではスクロールゲームのBugFireを実行しているが、全く問題なく遊べる事が分かった。
アプリケーションロード機能
このプロジェクトは、MachiKaniaの一つのタイプとして考えている。MachiKaniaの特徴としては、ボタンを押しながら起動する事でブートローダーが立ち上がり、HEXファイルを選択する事でアプリケーションの切り替えができる事が挙げられる。この機能を是非とも実装したい。
KM-Z80 midiの特徴としては、SD/MMCカードではなくUSBメモリーを使っている事がある。この、USBホストのインターフェース部分のプログラムはかなり大きく、ブートローダーにこれを組み入れると大容量の領域を占有してしまう。MachiKaniaの他のタイプと同じメカニズムを採用すると、後にMachiKania BASIC用の容量が足りなくなってしまう事が分かった。方式を変えないといけない。
MachiKania type N/Z/Mの場合、ブートローダーを構築するフラッシュ領域は、アプリケーションを構築するフラッシュ領域と分けられている。従って、ブートローダー上のコードでアプリケーション用のフラッシュ領域を書き換える事ができる(その逆も理論的には可能)。KM-Z80 midiでは、上の段落で述べたように、ブートローダー領域をアプリケーション領域と分ける事ができない。アプリケーション用のフラッシュ領域を書き換えるためには、この領域以外でコード実行しなければならない。唯一の方法は、フラッシュ領域を書き換えるためのコードをRAM上で実行する事である。
この目的のために、RAM上で実行するフラッシュ書き換えプログラムを作成した。GitHubで公開している。このプログラムの特徴は以下の通り
1)RAM上で走るプログラム
2)USB host機能を持つ
3)ファイルシステムIOを持つ
4)Intel HEX ファイルを読み込み可能
5)フラッシュ書き込み機能を持つ
特徴は、リンカースクリプトの以下の記述に現れている。
MEMORY { kseg0_program_mem (rx) : ORIGIN = 0xA0003000+0x0490, LENGTH = (0xD000-0x0490) /* modified (ORIGIN = 0x9D001000, LENGTH = 0x1F000) */ exception_mem : ORIGIN = 0xA0002000, LENGTH = 0x1000 /* modified (ORIGIN = 0x9D01F000, LENGTH = 0x1000) */ debug_exec_mem : ORIGIN = 0x9FC00490, LENGTH = 0x0 /* dummy (LENGTH = 0x760) */ kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x0 kseg1_boot_mem : ORIGIN = 0xA0003000, LENGTH = 0x490 /* modified (ORIGIN = 0xBFC00000)*/ config3 : ORIGIN = 0xBFC00BF0, LENGTH = 0x4 config2 : ORIGIN = 0xBFC00BF4, LENGTH = 0x4 config1 : ORIGIN = 0xBFC00BF8, LENGTH = 0x4 config0 : ORIGIN = 0xBFC00BFC, LENGTH = 0x4 kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x2000 /* modified (LENGTH = 0x8000) */ sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000 configsfrs : ORIGIN = 0xBFC00BF0, LENGTH = 0x10 }0xA0000000-0xA0001FFF をRAM領域、0xA0002000-0xA0002FFF を割り込み領域、0xA0003000-0xA000348F をブート領域、0xA0003490-0xA000FFFF をメインプログラム領域とした。
使用する際は、このhexファイル(fwiter.hex)中の0xA0002000-0xA000FFFFの領域をRAMに書き込み、アプリケーションHEXファイルのファイル名を0xA000FFF0からの領域に書き込んで、0xA0003000からコードを実行すればよい。KM-Z80 midiのそれぞれのアプリケーション内で、ファイル選択してこのfwriteに処理を引き継ぐ用にすれば、PicKit無しでアプリケーションの切り替えができるようになった。
今後の予定
今後の予定としては、次のような事を考えている。
1)MZ-80Kミニチュア版のような格好いい筐体を作製
2)キーボード部のカバーを、紙から3Dプリンター製のものに変えて使いやすく
3)MachiKania BASICも使用出来るようにする
4)CP/Mも使用出来るようにする(ほぼ完成)
5)Fuzixも対応できたらいいなぁ(独り言)
バージョン 0.4 は、GitHubにてダウンロード出来ます。