FT245という、PCにUSBで接続する8Bitパラレル出力ICがあります。USBに接続されたFT245は、仮想COMポートとして扱われ、1バイトのデータを出力すると、そのデータ1バイト(8Bit)がFT245の端子にパラレルに出力されます。
ここのページは、FT245をPC-6001のジョイスティックポートにつないで、PCからPC-6001へとデータを送ってみようという実験の記録です。
FT245単体では扱いにくいので、キットを利用します。秋月電子には「FT245RL USBパラレル変換モジュール」という製品があります。 今回は、Amazonで入手可能なFT245モジュールを使ってみました。
これを選んだ理由は、端子部分が横向きのピンヘッダになっているから・・・だけなので、FT245を使った製品であれば、どれでもいいと思います。
FT245は多機能なのですが、難しいことは抜きにしたいので、単純にUSB接続できるCOMポートとして扱います。COMポートから1バイトのデータを送ると、FT245の8本の端子に信号が現れますが、それだけでは困ったことになります。 というのも、PC側は、次のデータをいつ送ればいいのかわかりませんし、受信側はどのタイミングでデータを読み取ればいいのかわからないのです。そのための制御用の信号が用意されています。
また、FT245は双方向通信が可能なのですが、今回はPC → USB → FT245 → PC-6001ジョイスティックポートという一方向通信とします。その為の信号線は2本あります。信号線の制御は、データの受け側、つまり、今回はPC-6001が担当します。その他の面倒なところはFT245が取り持ってくれるので、PC側では何も気にせずにデータを送るだけで済みます。
2本の制御線である、RDとRXF#の扱い方は以下の流れになります。
PC-6001側はRDをHighにすることで受信の準備が出来ていない事を相手に伝え、FT245はデータが準備できたことをRXF#をLOWにすることで伝えます。PC-6001側でデータを受信できる準備ができたらRDをLOWにしてデータを要求してからデータを読み取ります。読み取り後にRDをHIGHにして次に備えます。
PC側では、COMポートのフロー制御をFT245がいい感じに処理してくれるので、何もすることはありません。
PC-6001のジョイスティックポートは9ピンで、その内訳は以下の通りです。(ジョイスティックポートの1と2のどちらも同じ使い方です)
PIN番号 | PC-6001から見た入出力と用途 |
---|---|
1 | 入力 |
2 | 入力 |
3 | 入力 |
4 | 入力 |
5 | +5V出力 |
6 | 入出力切り替え可 |
7 | 入出力切り替え可 |
8 | 出力 |
9 | GND |
PC-6001のジョイスティックポートは、音源ICのAY-3-8910の8bit ×2つのI/O端子に接続されていますが、AY-3-8910の2つのI/O端子は8bit単位でしか入力と出力を切り替えられません。そこで、PC-6001の内部で別の制御回路が組まれています。そのため、6,7番ピンの入出力切り替えや、ジョイスティックポートの1と2のどちらから読むのかを指定する処理が必要になります。
具体的には、AY-3-8910のPORT-BのBit7をHighにするとジョイスティックポートの6,7ピンが入力に、Lowにすると出力になります。また、PORT-BのBit6をHighにするとジョイスティックポート1からの入力に、Lowにするとジョイスティックポート2からの入力になります。
FT245とPC-6001を、8bit分のデータと2本の制御線で繋げられたらよかったのですが、残念なことに端子の数の都合から、PC-6001側では8bitのデータを受け取ることが出来ません。そこで、今回は4Bitのデータ受信とします。1バイト単位でのデータのやり取りをするには、送り側でも8Bitを4Bitに分けて送る必要があります。回避方法としては、ジョイスティックポート2の入力端子を使うという手がありますが、ケーブル工作が増えるので、今回は4Bit単位にしておきます。
FT245とPC-6001は2本の制御線を使って互いの状態を確認しながらデータの受け渡しをするので、順序さえ守っていれば、タイミングは気にせずにすみます。以前に作成したPC-6001のジョイスティックポートを使ったシリアル通信プログラムでは、Z80のクロックを数えながら通信を行いましたが、今回はそういった細かな制御はまったく必要ありません。つまり、PC-6001mkIISR(6601SR)でも動くはずですし、マシン語を使わずにBASICでもやり取りが可能です。
ピンヘッダとPC-6001のジョイスティックポートの接続には、QIコネクタというものを使います。私は、マルツで10PIN×2列のコネクタを買いました。
ピンヘッダを使うと、ハンダ付けをしないで済みますが、圧着ペンチが必要になります。専用のペンチはちょっと高いですね。普通のラジオペンチでも固定できなくはないです。
つなぐ端子は、データ信号線4本、制御線2本、GND1本の合計7本です。
番号 | PC-6001からみた入出力 | FT245への接続先 |
---|---|---|
1 | 入力 | D0 |
2 | 入力 | D1 |
3 | 入力 | D2 |
4 | 入力 | D3 |
5 | 今回は未使用(+5V出力) | × |
6 | 入力 | RXF# |
7 | 今回は未使用 | × |
8 | 出力 | RD |
9 | GND | GND |
ジョイスティックポートの番号は、PC-6001を横から見た時の並びです。(PC-6001のマニュアルに記載されている順)
挿し込む側からみると、このような並びになります。
PC-6001のジョイスティックポートはD-SUB 9pinですが、一点だけ注意しなければならない事があります。接続口をみるとわかるのですが、コネクタ部が本体の奥まったところにあるので、電子パーツ店で売られている一般的なD-SUBコネクタではネジ止めの板があり、接続できないのです。少々心苦しいのですが、 MSXやメガドライブなどのジョイスティックやパッドを分解して利用するのがよいでしょう・・・というのがこれまでのやり方だったのですが、今ではレトロPC/ゲーム機のコントローラが高価品になってしまいましたので、BEEPで取り扱いのある、AMP9ピンケーブルを購入するのがよいかと思います。
FT245の基板には端子名が書かれているので、そのまま接続します。
AY-3-8910は、Z80 I/OのA0h - A2hに接続されています。AY-3-8910レジスタ制御方法はググってください。
I/Oアドレス | 用途 |
---|---|
A0 | AY-3-8910 / レジスタ選択 |
A1 | AY-3-8910 / 出力 |
A2 | AY-3-8910 / 入力 |
PC-6001 BASICのようなそうでないようなプログラムがこちらです。
CONSOLE,,,0
REM AY-3-8910のPORT-A(REG14)を入力、PORT-B(REG15)を出力に設定
OUT &HA0,7
OUT &HA1,&HBF
REM PORT-BのBit7をHighにすると、JOYSTICK端子の6,7ピンが入力用になります
REM PORT-BのBit6をHighにすると、JOYSTICK端子1からの4bit(ピン0-3)入力になります
REM PORT-BのBit5をHigh/Lowして、FT245とやりとりします(RD端子)
REM 1110_0000 (&HE0) / RD High
REM 1100_0000 (&HC0) / RD Low
[REPEAT]
REM FT245のRDをHIGHにします
OUT &HA0,15
OUT &HA1,&HE0
REM FT245からデータが送られてくるまで待ちます
REM FT245がデータを用意すると、RXF#がLOWになります
REM RXF#は、PORT-AのBit4につながっています
OUT &HA0,14
[LOOP]
A=INP(&HA2)
if (a and &H10)<>0 then [LOOP]
REM RDをLOWにしてデータ要求します
OUT&HA0,15
OUT&HA1,&HC0
REM PORT-Aから4bitデータを読み取ります
OUT &HA0,14
A=INP(&HA2)
PRINT HEX$(A AND &H0F)
GOTO [REPEAT]
PC側となるWindows10に、FT245モジュールをUSB接続したところ、特に何のドライバ要求もなくCOMポートが追加されましたので、通信ソフトのacknowrichを使って、データの00から0Fを送ります。上位4Bitは読み捨てられるのでなんでもOKです。
PC-6001mkII実機でプログラムを実行して、0からFまでの4Bitを受信出来ました。上位4Bitには余計なデータが入るので0Fhでマスクしてください
4Bitを2回送受信して1バイトを組みたてるというのが王道ですが、4bitで出来ることを考えてみたところ、PC-6001mkIIのカラーコードがちょうど16色4Bitなので、受信した4BitをそのままPSET命令で画面に表示するテストをしてみました。こんなPSETの色指定を書いたのは初めてです。
SCREEN MODE3では1行が160ドットですので、まずは160回のデータ受信を行ってみたところ、約23秒かかりました。1画面は200行ですから、1画面相当だと約76分かかりますと。さすがにこのままでは実用性はなさそうです。
PC-6001mkIIとWindowsを接続して、VRAMへの画像転送をしてみました。
;
; 4bit転送版
;
relaxed on
; [BASIC]
; 10 SCREEN 3,4,4:CLS
; 20 CONSOLE ,,,0
; 30 EXEC &Hc827
org $c827
di
; ram write area(ALL RAM)
ld a,$dd
out ($F0),a
;FT245のRDをHIGHに
ld a,15 ; PORT-B指定
out ($A0),a
ld a,%11100000 ; RD High
out ($A1),a
; AY3-8910入出力設定(AY-3-8910のPORT-A(REG14)を入力、PORT-B(REG15)を出力に設定)
ld a,7
out ($A0),a
ld a,%10000000
out ($A1),a
; レジスタ操作用
ld d,14
ld e,15
ld hl,$0000 ; 受信データの書き込み先頭アドレス
ld bc,$4000 ; 受信データバイト数
MAIN_LOOP:
; FT245からデータが送られてくるまで待ちます
; FT245がデータを用意すると、RXF#がLowになります
ld a,d ; PORT-A指定
out ($A0),a
$$loop1:
in a,$A2
and %00010000 ; RXF#はPORT-AのBit4につながっています
jr nz,$$loop1 ; RXF#がLowになるまでループ
; RDをLOWにしてデータ要求します
ld a,e ; PORT-B指定
out ($A0),a
ld a,%11000000 ; RD Low
out ($A1),a
; PORT-Aから4bitデータを読み取ります(上位)
ld a,d ; PORT-A指定
out ($A0),a
in a,$A2
; 受信データの上位4bit転送(HL)
rld
;FT245のRDをHIGHに
ld a,e ; PORT-B指定
out ($A0),a
ld a,%11100000 ; RD High
out ($A1),a
; FT245からデータが送られてくるまで待ちます
; FT245がデータを用意すると、RXF#がLowになります
ld a,d ; PORT-A指定
out ($A0),a
$$loop2:
in a,$A2
and %00010000 ; RXF#はPORT-AのBit4につながっています
jr nz,$$loop2 ; RXF#がLowになるまでループ
; RDをLOWにしてデータ要求します
ld a,e ; PORT-B指定
out ($A0),a
ld a,%11000000 ; RD Low
out ($A1),a
; PORT-Aから4bitデータを読み取ります(下位)
ld a,d ; PORT-A指定
out ($A0),a
in a,$A2
; 受信データの下位4bit転送(HL)
rld
;FT245のRDをHIGHに
ld a,e ; PORT-B指定
out ($A0),a
ld a,%11100000 ; RD High
out ($A1),a
; HL=HL+1, BC=BC-1
cpi
jp pe,MAIN_LOOP
; ram write area
ld a,$11
out ($F0),a
ei
ret
1バイトを4bit+4bitとして分解する必要があるため、転送量自体は2倍になります。上位4bit/下位4bitの順で送って合成して1バイトをVRAMに書き込んでいます。
PAGE4のVRAMアドレスは0000hでBASIC ROM領域と重なっていますが、ここへの書き込み先はVRAMになります。ただしRLD命令を使っている都合上、メモリからの読込が発生するので、読込先もVRAMにしておく必要があります。これはI/OポートのF0hで操作しています。
AY-3-8910の入出力設定を切り替えてから出力データを設定する、という処理順にすると、最初のデータを取りこぼしてしまいました。そのため、「あらかじめ出力データを設定しておいてからAY-3-8910の入出力設定を変える」という処理順にしています。
転送時間は約4秒です。BUSREQをOFFにすると2秒弱まで速くなります。
いくつかの課題が残っていますが、これらはそのうちチャレンジしたいです。