通信ポートで遊ぶ


img
GB の通信についてまとめてみました。

基礎的な技術なので、これ単体では役に立ちませんが、
今時のアレコレと組み合わせれば新しい試みにつながるはず。

本ページのプログラムは GBC で増設された機能を使っているため、半分以上 GBC 専用です。





■ 通常の GB 同士のケーブル通信について

GB の通信ポートのピン配置は以下のようになっています。



pin4 は GBC で増設されました。rRP($FF56) の bit4 でデータの入力を拾えます。

同じ入力なのに Serial In と Serial Data 2つあるのは何故なのかというと、
Serial In/Out は従来の GB 互換で、クロック信号に従って(トコロテン方式) 8bit を順次やりとりするピン、
Serial Data は 1bit 単位で生シリアルデータを入力できるピンという区別があるのです。

まずは実際に見た方が早いと思うので従来の通信方法をテストするプログラムを置いておきます。
有り難いことに通信環境を再現したエミュレータがあるので、PC 上で実験できます。

通信ポートテストlinkport_20140307.zip


B ボタンを押すとマスターになり、相手側にその旨を通知します。
どちらかがマスターになると反対側がスレーブに。

1) A,B どちらもスレーブ(外部クロック同期)に設定して割り込みを待機
2) 送信する必要があるホスト側 A を内部クロックに切り替えて 1 バイトを送信、同時に受信が行われる
3) スレーブ B は A の送信クロック信号に同期して 1 バイトを受信、同時に送信が行われる
4) 送り終わったら A は外部クロック同期に戻して送受信の必要があるまで待機

という手順です。送信・受信というより 1 バイトの交換が行われます。
送りたい側は、その都度内部クロックにしてホストになる要領。

外部クロック同期は「送られてくるまで待機、送られてきたら受け取った 1 バイトとこちらの送信 1 バイトを交換」
内部クロック同期は「こちらの設定したクロックで送信開始、1 バイト送信と同時に向こうから 1 バイト受け取る」

   8192Hz -  1KB/s - Bit.1 = 0, Normal
  16384Hz -  2KB/s - Bit.1 = 0, Double Speed Mode
 262144Hz - 32KB/s - Bit.1 = 1, Normal
 524288Hz - 64KB/s - Bit.1 = 1, Double Speed Mode

上記は $FF02(rSC) の bit0=1 内部クロックにしたときの速度です。
CPU クロックに依存するので CPUを 4MHz->8MHz と倍速モードにすることで通信速度も倍速になります。
また、同ポートの bit.1 は CGB でのみ使用可能で、さらに高速な通信が可能になります。
この結果、内部クロックは 4 通り選べることになります。
外部クロックの場合は通信相手のクロック依存なので、相手の速度に従います。外部クロックの相手は GB で無くても良いです。

送受信交換は 1対 のラインでクロックに従って 1 ビットずつ行われます。
クロックが働かないと送受信は全く行われません。
1 バイト(=8ビット)をやりとりするのに外部クロックで 8 クロックかかり、1 バイト送受信完了すると割り込みが発生します。

通信割り込みは設定した送信クロックに従って割り込みが発生するようで、CPU の実行速度と比べると若干遅れてかかります。
割り込みが発生する前に通信ポートへ書き込みしてしまうと、クロックがリセットされて割り込みがかからなくなってしまうようで、
さらに送信側でリセットしてしまうと受信側でも割り込みが発生しなくなる模様。つまり割り込みをトリガーとした受信処理ができなくなる、と。

これを回避するため、CPU 側では割り込みの発生を待ち合わせる処理が必要です。


さて、以上から「送信側は」相手側の準備が出来ていようがいまいが、とにかく内部クロックにすれば
1 バイトを送りつけることが可能ということが分かると思います。

と、ここで Serial Out のピンを PC 側で監視させておき、$00(=全ビットオフ) と $FF(=全ビットオン) を超高速に送りつけるとどう見えるかというと・・・


GB からは 1 バイト送ったつもりが、PC には 1 ビットずつ送っているように見えるのです。(もちろん bps は計算で合わせないといけませんが)
この仕組みを使うことで、Serial Out を Serial Data と同じように、1 ビット単位での生シリアルデータの送信に使うことが出来るというわけです。

↓に続く。


■ 通信ポートを RS232C 仕様にする

たとえば、9600bps であれば 1/9600秒毎に 1 ビット(=$00 か $FF) を送信すれば良いので、
そのタイミングを GB の CPU 側で厳密にコントロールします。GB の CPU はそれよりは高速なので大きな手間ではありません。

1/9600bps = 104.16us
1/4194304 = 0.2384us (GBの1動作クロック)  
104.16 / 0.2384 = 436.9 

GBは436クロック毎に1バイト(=PCにとっての1ビット)送信すれば良い

受信に関しても、rRP($FF56)の bit4 を適切なタイミングで読み取るようにすれば送られてきたビットを拾えます。

あとは、信号のレベルさえ RS-232C と合わせれば、めでたく PC と会話ができるようになるという寸法です。
ただし信号レベルだけはハードの増設が必要です。GBC は乾電池 2 本で動いてますからね。

RS232C テスト rs232test_20140307.zip

以下の回路を参考に組み立てます。
繰り返しますがGBC 専用です。モノクロ GB は pin4 が別の所につながっているので受信ができません。

IC 1 個 と 10uF電解コンデンサ*4 を使用しました。
丸数字 ABDは PC のシリアルポートが 9pin の時のものです。25pin の場合はAとBが逆、DはFになります。
オスメスでピン番号順は左右逆になります。Wikipedia にピン配置は載っています。
GB 側コネクタの配線の色は筆者の手持ちのパーツのもので、型番によっては違う場合もあります。テスター等で確認した方が良いでしょう。
MAX232 は互換品で Ok です。筆者は ADM3202AN を使いました。


以上は Ken Kaarvik 氏の作成された回路図とサンプルプログラムを少し手直しした程度で、ほぼ変わっていません。
この回路図で PC と接続するときは、RxD-TxD がお互い正対しているので、ストレートケーブルを用います。

PC と GB を前述のアダプタを介して接続し、PC側で適当なターミナルプログラムを起動します。
acknowrich が手軽。
9600 bps 送受信 8ビット、ストップビット1、ノンパリティ(N81)で設定します。

GB 側からはボタンを押す度に 1 バイト送信されます。チャタリングのせいでゴミが出ることがあります。
PC 側からは任意の 1 バイトを送信でき、GB 側では受信したデータを画面左上に 16 進数で表示します。
あくまでテストなのでこれだけ。


GB 電源投入時に 00 が送信されてしまうみたいです。
次の 83 は メモリ初期値のクリア忘れです。後の赤字は正常。押したボタンに対応するビットが立った数値が PC に送信されています。
青字は PC から GB への送信データ。GB の画面左上に表示されます。

なお、RS232C 仕様といっても、RTS や CTS 信号は無いのでフロー制御はできません。

■ GB で MIDI 出力してみる

RS232C 仕様(仮)の通信ポートが出来たので、今度は MIDI 信号を出力してみます。
実は GB の通信ポートを利用した、本来の MIDI ケーブルを流れる信号を出力するキットなどもあるのですが
(フォトカプラを挟んだ MIDI 仕様に準拠したもの)、シリアル MIDI として知られる今回の方法も全く遜色なく使えます。
音源には SC-88Pro など、シリアル入力ポートを備えた MIDI 機器が必要です。USB はダメ。

MIDI の通信は 38400bps の N,8,1 ですので、上の 9600bps の 4 倍速ということになります。
速度的に若干不安がありますが、画面にゴテゴテ表示するようなことをしなければ大丈夫でしょう。

MIDI 音源のポート設定は PC-2 など 38400bps の設定にしてください。
シリアルケーブルは↑の回路通りに作った場合、「リバースで」接続しないといけません。
MIDI 機器の内部でさらにリバースになっているので。

MIDI 出力テストgbmidi_20140307.zip



電源を入れて画面が出たら B ボタンを押すと演奏を開始します。
演奏が終わったら END と出ます。リプレイなどは無し。

サンプル曲(sample2.mid)は以下のサイトの
Bach > The Well-Tempered Clavier Part I, BWV 846-869 (1722) > Prelude and Fugue in C major BWV 846
を使用させていただきました。
SMF の Format.0 を Format.1 に、Timebase を 48 に変更しています。
>Copyright (c) 1996-2013 by Bernd Krueger
>Home: http://www.piano-midi.de

ライセンスが CC-BY-SA なので、同梱したものについてもそれに従います。


というわけで、問題なく MIDI 信号も送信できました。
プログラムの方は PC88 などで使ったものを改造しただけなので若干非効率で汚くなってしまいましたが
構造的には単純です。通信速度が速くなったくらいで、↑のテストプログラムと大した違いはありません。

■ GB に音源レジスタデータを送信する

今度は逆に、PC 側から GB にデータを送信してみます。

PC->GB 出力テスト instboy_20140307.zip



シリアルポートを選択して C 〜 B のボタンを押すと、GB 側で音が鳴ります。
このとき、「どのボタンが押されたか」という情報では無く、音源レジスタに書き込む値を直接送信しています。
レジスタ下位+データの 2byte を レジスタ 5 個分、合計 10byte を一度に送っています。

受信は 9600bps なのですが、スタートビットを検出した後、信号の立ち上がり(下がり)確定した状態を
うまく拾えなかったので若干のウェイトを置いています。やはりエッヂの部分は不安定なようです。

実は nezplug++ を改造して音源ログを送れるようにしようと思っっていたのですが、私の力では無理でした。
一応 38400bps での受信実験には成功しているのでなんとかなるかも、と思ったのですが・・・。

38400bps = 3840byte/秒 で、1/60秒につき 64byte。
音源ドライバが vsync 毎に波形メモリ含め全音源レジスタに書き込んだとすると 37レジスタ*2(アドレス+データ)。
少し工夫すればどうにかなりそうな案配なんですけどねぇ。

バッファリング再生も途中まで作りかけていました。
これも PC 側が色々大変で・・・。

PC との接続は RS-232C だけでなく、パラレルポート接続なども出来ます。
入力も pin4 でなく、クロック端子も使って GB に偽装して(?)やりとりする方法もあるようです。
外部クロックを PC 側で生成すれば 500KHz 辺りまで追従するんだとか。ハンドシェイクきちんとやらないと大変でしょうけれど。
pin4 を使わないやり方であれば、白黒 GB でも使えて良いと思います。

■ GB ヘッドホンジャックから送信

ちょっとカテゴリ違う気がするけど、書くところが無いのでここにくっつけておきます。

GB には音声出力端子があります。これを通信ポートに見立てて GB から外部にデータを送信することが出来ます。
原理としてはこれまで書いた他の方法と同じく、デジタルデータの 0 と 1 を音声の OFF/ON として出力するだけです。

音声の出力に関しては ch.3 波形メモリ音源を使います。
ch.1/2 の矩形波出力は、それ自体が 0/1 を繰り返していて使いづらいので。ch.4 のノイズ音源はいわずもがな。


波形メモリ音源は 16byte の波形設定領域を持っています。1byte を上下 4bit ずつに分けるので、全部で 32step。
4bit なので音量は 16 段階ということになります。
ここで設定した 32step は音源レジスタに設定した周波数値で自動的に再生され、最後まで行くと最初に戻ります。
たとえば音量を 0->15 になるように 32 step かけて上がっていくような感じの波形を設定すると「のこぎり波」として聞こえます。

今回は必要なのは 0 と 1 なので、波形は 16byte を全部 $FF にします。音量最大がずっと続く感じです。
この波形をずっと再生しっぱなしにして、on/off は ch.3 音源レジスタで再生/消音の切り替えで制御します。

改めて通信の説明。
データを出力する場合、受信側で「どこからどこまでが 8bit=1byte」なのかが分からないと都合が悪いです。
もしデータがずっと $00 だったり $FF だったりしたら、通信が始まったことすらわからないですからね。

というわけで、こういうときは「スタートビット」「ストップビット」というのを追加します。
最初は送信側はずっと 1 にしておき、受信側は 0 が来るのをずっと待ち続けます(あるいは 0->1 でも良い)。
0 が来たらそこから通信開始と認識して、続く 8 個のビットをデータの本体であると見なすのです。終端は 1 を立てて再びスタートビットを待ちます。
こういった送信側・受信側双方において、あらかじめ約束事(プロトコル)を取り決めておくことが大事です。


1byte = $CA = %11001010 を送るの図。
見て分かるとおり、1byte=8bit を送るのに計 11bit 必要になります。

今回はストップビットは 2bit ですが、場合によっては 1bit だったり、別にパリティビットが加わったりします。
受信に使う PC 側のツールに MSX 用のテープ音声変換ツールを使う予定なので、今回は以上のような設計にしています。

さらに 0/1 の部分は MSX テープのフォーマットに合わせて 2400Hz/4800Hz の周波数を刻むものとします。2400baud。
また、テープの場合は頭にヘッダという「ピー」音が入るので、これも併せて取り入れることにします。

こういうフォーマットにするのは、受信側ツールを新規に作るのが面倒という筆者の都合によるものなので
ツールから自作する場合は好きにするといいです。2byte ずつ送受信するとか。

GB 側のテストプログラムは以下。2400Hz/4800Hz はソフト的につくりだします。
クロックを数えてタイミングを合わせるのが少し大変です。

exporttest_20190407.zip


A ボタンを押すとピーガー鳴り出します。この音声を PC 側マイク端子で録音します。
今回は 44100Hz ステレオで録音しました。

wav からの変換には castools (http://home.kabelfoon.nl/~vincentd/)を使います。



wav ファイルをドラッグ&ドロップ。
phase shift signal にチェックを入れてから convert to .cas で変換。

できあがった .cas ファイルには MSX テープフォーマット由来のヘッダ情報がついているので先頭から 8byte は手動で削除します。
これもツールの流用が原因なので、完全に自前で作るならもっと便利にできるはず。




拡張子を .cas から .png に戻すと、、、
以下のように、GB から送った画像データが PC 上で復元できました。



出典:いらすとや『AI(人工知能)が搭載されたロボットがパソコンの操作(RPA)をしているイラスト』 50% 縮小・白黒化。
シュールですね。

この方式の利点はなんといっても簡便さにあります。
どこの家庭にもある(?)ミニプラグ音声ケーブル一本で PC に送信できるので、追加投資はほぼ必要ありません。
PC 側も特別なドライバをインストールしたりする手間は要らず、録音も標準の「サウンドレコーダー」で十分です。

▲ TOP