2020年04月03日

ジョイスティックポートでRS-232C通信(2)

  ジョイスティックポートを使ったRS-232C通信の続き


  普通、今時のパソコンとP6間でRS-232Cを使う際は、

  USB <=> RS-232C変換(±12V)<=> 5Vレベル変換 <=> P6

  となるんですが、最近のRS-232Cは、5V/3.3Vで入出力するものがあります。
 (注意:±12Vとは限っていないようです。+Vと-Vで、V=3〜15だそうです)


  この場合、

  USB <=> RS-232C変換(5V)<=> P6

  となって、作る回路が少なくて済みます。


  先に紹介したTINY野郎さんが使っているのが、まさにその5Vで入出力するものです。


  AMAZONなどでも多数の種類があるのですが、232Cの処理をするチップが偽物で、
 ドライバをインストールしても動作しない事があるので、注意が必要です。


  私は秋月電子で↓を買いました。

http://akizukidenshi.com/catalog/g/gK-14745/

200403_01_写真1.jpg

  右下の緑色の基板がモジュール本体です。

  チップが中華製ですが...ドライバも秋月のホームページにリンクが張っています。

  また、USB側がTYPE-Cです。持ってなかったので、変換ケーブルをダイソーで買いました。


  ハードウエアを作るとき、RxD/TxD、RTS/CTS を逆にしがちなので注意が必要です。

  モジュールに記載している、RxD/TxD、RTS/CTSは、モジュールから見た端子名なので、
 P6と接続する時には、逆にして接続します。クロスケーブルで繋ぐイメージです。

  MORIYAさんのページの回路を実現する時は、

  モジュールTxD:ジョイスティックピン1
  モジュールRxD:ジョイスティックピン8
  モジュールRTS:ジョイスティックピン2
  モジュールCTS:ジョイスティックピン7
  モジュールGND:ジョイスティックピン9

 になります。


  実際に組み立てたものが↓です。

200403_01_写真2.jpg
200403_01_写真3.jpg

  むき出しはアレなので、熱収縮チューブを使って、コーティングしてみました。

200403_01_写真4.jpg

posted by えすび at 23:01| Comment(0) | P6解析:ジョイスティックポート | このブログの読者になる | 更新情報をチェックする

2020年03月31日

ジョイスティックポートでRS-232C通信

  最近ツイッターで、ジョイスティックポートを使った、RS-232C通信が流行っている(?)ので、流行に乗ってみました。


  P6のジョイスティック入出力ポートを使って、RS-232C通信を行うためのハードウエアなどは、MORIYAさんのページに詳しく書かれています。
http://p6ers.net/mm/pc-6001/dev/joy2rs232c/


  また、MSXでは、TINY野郎さんのページにも書かれています。
http://www.tiny-yarou.com/joyjoy_fs.html


  同じ事をやっても面白くないので、限界に挑戦してみることにしました。
  PC -> P6 のデータレートは、57600bps で動いているのが最速なようですが、115200bps が動きました。

  PC -> P6 への転送のみのプログラムです。プログラムは、MODE1-5、PAGE1-4で動作しますが、mk2SR/66SRではCPUクロックが違うために動作しません。

joy232c.zip


  ハードウエアは、上記のどちらのものを使っても動作します(RTS/CTSを使っていないため)。
  PC側の送信の設定は、57600bps or 115200bps、ストップビット1ビット、パリティなし、データ8ビットにして下さい。


  アセンブラソースは以下の通りです。


======================================================================
relaxed on

org $d000

jp WRITEDT_115K2 ; 0xD000:データ書き込み(115200bps)
jp WRITEDT_57K6 ; 0xD003:データ書き込み(57600bps)

org $d010

WRSTART: dw $0000 ; 書き込み先頭
WRSIZE: dw $0000 ; 書き込みサイズ

;
; データ書き込み
;
WRITEDT_115K2:
call INIT ; 初期化
ld hl,(WRSTART)
ld bc,(WRSIZE)
call RCVDT_115K2 ; データ受信&書き込み(115200bps)
call PS_PRO ; 後処理
ret

;
; データ書き込み
;
WRITEDT_57K6:
call INIT ; 初期化
ld hl,(WRSTART)
ld bc,(WRSIZE)
call RCVDT_57K6 ; データ受信&書き込み(57600bps)
call PS_PRO ; 後処理
ret

;
; データ受信&書き込み
; ・エラーチェックなし
; ・スタート、ストップ1ビット
; ・パリティなし
; ・ボーレート 115200bps(1ビット34.67clk@3.9936MHz)
; ・ボーレート 115200bps(1ビット34.72clk@4.0000MHz)
;
;
; 設計思想
; ・スタート、ストップとも1ビットのため、全体で10ビット
;
; ・1ビットのデータは、35クロック弱
;
; ・10ビット全体
;   スタートビットをすぐに見つける
;   8ビットデータを取り込む
;   データ格納、サイズチェックをして最初に戻る
;  までを、346クロック以内に終了させる(10ビットでデータ全体が346.7/347.2clkのため)
;
; ・スタートビット検出と、最初のデータ取り込みのタイミングは
;  36クロック以上にする
;  (35クロックにした場合、スタートビットがぎりぎり取れた時に
;   最初のビットを取り損なう可能性があるため)
;
;
; BC:データサイズ
; HL:書き込みアドレス
;
RCVDT_115K2:


ld (.sppt+1),sp ; ダミー命令を使うために、SPを退避する

.lp1:
in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
jp c,.lp1 ; 10+1 / 29 スタートビットを待つ


ld d,$00 ; 7+1 / 37

; 37 / 37


in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
ret c ; 5+1 / 34 時間調整用

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
ld sp,hl ; 6+1 / 35 時間調整用

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
ld sp,hl ; 6+1 / 35 時間調整用

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
ret c ; 5+1 / 34 時間調整用

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
ld sp,hl ; 6+1 / 35 時間調整用

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
ld sp,hl ; 6+1 / 35 時間調整用

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
ret c ; 5+1 / 34 時間調整用

; 242 / 279

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
ld (hl),d ; 7+1 / 36
cpi ; 16+2 / 54 HL<=HL+1 / BC<=BC-1 で、BC=0の時、P/V=0
jp pe,.lp1 ; 10+1 / 65

;
; ↑ストップビットの間に処理を済ませる

; 65 / 344

.sppt: ld sp,$0000
ret


;
; データ受信&書き込み
; ・エラーチェックなし
; ・スタート、ストップ1ビット
; ・パリティなし
; ・ボーレート 57600bps(1ビット69.33clk@3.9936MHz)
; ・ボーレート 57600bps(1ビット69.44clk@4.0000MHz)
;
; BC:データサイズ
; HL:書き込みアドレス
;
RCVDT_57K6:

ld (.sppt+1),sp ; ダミー命令を使うために、SPを退避する

.lp1:
in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
jp c,.lp1 ; 10+1 / 29 スタートビットを待つ

; ここで、本来はデータの中心まで待つ必要があるのだが、
; データ幅(=69)に対して、サンプリング間隔(=29)が大きいので、
; 適当にウエイトを入れる
; ↓

ld a,b ; 4+1 / 34 時間調整用のダミー命令

; スタートビット分待つ

in a,($a2) ; 11+2 / 13 時間調整用のダミー命令
inc hl ; 6+1 / 20 時間調整用のダミー命令
dec hl ; 6+1 / 27 時間調整用のダミー命令
inc hl ; 6+1 / 34 時間調整用のダミー命令
dec hl ; 6+1 / 41 時間調整用のダミー命令
inc hl ; 6+1 / 48 時間調整用のダミー命令
dec hl ; 6+1 / 55 時間調整用のダミー命令
inc hl ; 6+1 / 62 時間調整用のダミー命令
dec hl ; 6+1 / 69 時間調整用のダミー命令

REPT 7

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28
in a,($a2) ; 11+2 / 41 時間調整用のダミー命令
inc hl ; 6+1 / 48 時間調整用のダミー命令
dec hl ; 6+1 / 55 時間調整用のダミー命令
inc hl ; 6+1 / 62 時間調整用のダミー命令
dec hl ; 6+1 / 69 時間調整用のダミー命令

ENDM

in a,($a2) ; 11+2 / 13 受信ビット(bit0)(PSGは+1waitされる)
rrca ; 4+1 / 18
rr d ; 8+2 / 28

ld (hl),d ; 7+1 / 8
cpi ; 16+2 / 26 HL<=HL+1 / BC<=BC-1 で、BC=0の時、P/V=0
jp pe,.lp1 ; 10+1 / 37

;
; ↑ストップビットの間に処理を済ませる

.sppt: ld sp,$0000
ret

;
; 初期化
;
INIT:
di
ld a,$02
out ($93),a ; BUSRQ停止

ld a,$07
out ($a0),a
ld a,$bf
out ($a1),a ; ミキサー初期化

ld a,$0f
out ($a0),a
ld a,$7f ; bit7=L:6,7pinを出力に設定(#1、#2とも)
; bit6=H:JOYSTICK#1を選択する(入力のみ)
; bit5=H:8pin(#1)に出力する値
; bit4=H:8pin(#2)に出力する値
; bit3=H:7pin(#1)に出力する値
; bit2=H:6pin(#1)に出力する値
; bit1=H:7pin(#2)に出力する値
; bit0=H:6pin(#2)に出力する値
out ($a1),a

ld a,$0e
out ($a0),a ; ポートAから入力する状態にしておく

ret
;
; 後処理
;
PS_PRO:
ld a,$03
out ($93),a ; BUSRQを戻す
ei
ret

end

======================================================================



  マシンサイクルをいちいち書いている所が、タイミングを合わせる必要があって、なおかつ高速にする必要がある部分です。

  今回コードを書いていての新しい発見は、「 cpi 」です。

  cpi は、本来 Areg とメモリ内容の比較なのですが、ここでは

 ・HL ++
 ・BC --
 ・BC が 0かどうかの判定

  の3つの事を1命令で済ませています。


  これは他でも応用できます。

  例えば、特定の範囲のメモリを0にする場合、


======================================================================

ld hl,$e200
ld bc,$1800
ld d,$00
.lp1:
ld (hl),d
inc hl
dec bc
ld a,b
or c
jr nz,.lp1
ret

======================================================================


  とするのが普通だと思います(LDIRを使わない場合)。

  これを


======================================================================

ld hl,$e200
ld bc,$1800
ld d,$00
.lp1:
ld (hl),d
cpi
jp pe,.lp1
ret

======================================================================


  と、すっきり書けるのでなかなか便利だと思います。


  また、マシンサイクルを調整するために、いろいろ命令を駆使する必要があります。

  データブックを見ながら適切な命令を探しますが、以下を使う事が多いです。


NOP ; 5 (=4+1)
OR A ; 5 (=4+1)
RET C ; 6 (=5+1) (条件が不成立になるようにする)
RET NZ ; 6 (=5+1) (条件が不成立になるようにする)
INC HL ; 7 (=6+1)
LD SP,HL ; 7 (=6+1)
LD A,$00 ; 8 (=7+1)
AND $00 ; 8 (=7+1)
DJNZ $00 ; 9 (=8+1) (Breg=1にしておく)


  マシンサイクルが10以上は、上の組み合わせで全部網羅できます。

  もっとマシンサイクルを稼ぎたい場合は、PUSH-POP(11+1,10+1)や、EX (SP),HL を2回使う(19+1、19+1)と、バイト数が少なくてマシンサイクルを稼ぐ事ができます。


posted by えすび at 00:20| Comment(0) | P6解析:ジョイスティックポート | このブログの読者になる | 更新情報をチェックする

2012年11月21日

マウスを動かす(2)

  書き忘れです。

  MSX用、PC-8801用、FM-TOWNS用のマウスですが、ジョイスティックモードというのがあります。

  電源を入れる時(マウスを挿す時)に、左クリックを押しながら電源を入れると、ジョイスティックモードになります。


  このモードになると、マウスをジョイスティックの代わりに使う事が出来ます。

  マウスを上下左右に動かすと、パッドの上下左右を押したのと、同じ動きをします。


  あまり使いそうにありませんが(^^;




posted by えすび at 21:42| Comment(0) | P6解析:ジョイスティックポート | このブログの読者になる | 更新情報をチェックする

マウスを動かす(1)

  P6でも、マウスが一応使えます。

  MSX用、PC-8801用、FM-TOWNS用のマウスが使用可能で、ジョイスティック端子に挿して使う事が出来ます。
  仕様的には、上記3つは殆ど同じようです。

  データの受け渡し方法ですが、pin8 がSTROBE 信号で、特定のタイミングで変化させると、pin1-4 にマウスの座標が返ってきます。
  また、マウスのボタンは、pin6、7 に返ってきます(これは、通常のトリガボタンと同じです)。


  入出力タイミングは以下の通りです。

マウスタイミング


  最初に STROBE 信号を L → H にすると、X方向の移動量(上位)が返ってきます。
  次に STROBE 信号を H → L にすると、X方向の移動量(下位)が返ってきます。
  次に STROBE 信号を L → H にすると、Y方向の移動量(上位)が返ってきます。
  次に STROBE 信号を H → L にすると、Y方向の移動量(下位)が返ってきます。


  一度に返って来るデータは4ビットで、4回掛けてX方向の移動量8ビットとY方向の移動量8ビットを受信する事になります。

  返って来るのは移動量で、符号付き8ビットのデータになります。


  タイミングチャート内の、TA はデータが確定するまでに 最大80μs掛かるという意味です。
  同様に、TB はデータが確定するまでに 最大30μs掛かるという意味です。
  TC は、180 μs 以内にしなさい、という意味です。
  TD は、少なくとも 300 μs は空けてアクセスしなさい、という意味です(PC-8801用は80μsになっているようです)。

  TD の最大値が記載していませんが、あまり遅いと移動量がオーバーフローするので、適当なタイミングで読みにいく必要があります。


  上記の仕様の出典は、Panasonic のマウスの説明書、及びPC-8801マスターバイブルからです。


  また、これは未確認ですが、STROBE 信号が反転している仕様もあるみたいです。



  上記のような仕様なんですが、P6 で動かすには、TC の180μs以内にアクセスする必要があるのが、結構大変です。

  画面を表示している最中は CPU が停止しているために、時間を正確に計測できません。
  バスリクエストを OFF にすれば問題ないんですが、画面を表示させて使えない事を意味しますので、この案は却下です。


  幸い、mk2以降では、垂直同期が検出できますので、それを使用します。
 (初代 P6 でも検出が多分可能なんですが、まだ確立できていません)


  垂直同期のタイミングと、CPU が停止するタイミングですが、以下の通りです。


  画面行数:垂直同期:CPU の順です。

 ・MODE 1〜4
    0〜  2:L:通常
    3〜 36:H:通常
   37〜228:H:停止
  229〜261:H:通常

 ・MODE 5
    0〜  2:L:通常
    3〜 32:H:通常
   33〜232:H:停止
  233〜261:H:通常


  CPU 停止期間は、実際はずっと停止するわけではないんですが、70%程度停止しています。

  1/30 秒かけて、262行を描画します。ですので、1行は 大体 127μs に相当します。
  垂直同期を検出してから30行程度、つまり 3ms 程度は、CPU が停止しない期間になります。

  これを使えば、時間を正確に計測する事ができます。


  実際のプログラムがこれになります。mk2、66 用で、MODE2、PAGE4 です。

mouse.zip


  P6 では、垂直同期が検出できないため使用できません。
  SR 以降では、CPUクロックの周波数が違うために、手直しが必要です。また、バスリクエストをOFF にして実行する方が簡単かと思います。

  実行すると、画面右上に数字が出ます。
  上から、ポート1のマウスのX増分/Y増分/ボタンの状態、ポート2のマウスのX増分/Y増分/ボタンの状態、になります。


  アクセス時間が比較的短いため、増分が小さな数字になっています。

  また符号付きの数値なので、マウスをちょっとだけ動かすと、00000000/11111111 の値でパラパラと表示が変わると思います。



  もう一つ、サンプルプログラムです。MODE5、PAGE4 です。

mouse2.zip


  起動すると画面にカーソルが出て、マウスで移動させる事ができます。
  左右のトリガを両方押すと、終了します。


  ただ、マウスのデータに従って動かすだけの事なんですが、P6系では結構大変です。


posted by えすび at 21:29| Comment(1) | P6解析:ジョイスティックポート | このブログの読者になる | 更新情報をチェックする

2012年08月22日

mk2設計(8)

  いろいろな理由で、mk2を調べ直しています。

  で、ジョイスティックポートの回路のミスが見つかりました...
  通常のパッドは問題ないんですが、8pin から信号を出力するものは、ちゃんと動きません。

  電圧の問題もあるので、ジョイスティックポートはあんまり使えないようにはなっていますので、5V対応の回路を作ってみようかなと思っています。


  また、WAIT 関連(I/Oポート0xF3)も調べ直していますが、どうもFPGAの実装が実機と違うようです。
  さらに、実機の回路にもバグがあるような感じです。


  これも、殆ど変更しているソフトはないと思うので、実害は無さそうです。

posted by えすび at 20:25| Comment(0) | P6解析:ジョイスティックポート | このブログの読者になる | 更新情報をチェックする