PICでUSBを!(知識ゼロからのスタートです)
PIC18F14K50のUSB機能を100%自前のソフトで制御する試みです。しかもアセンブラで!
当記事は2009年12月から「TTLでCPUをつくろう!」というタイトルの もとにほとんど毎日連載をしてきたものを再編集したものです。 2011.7.12

前へ
次へ
目次へ戻る
ホームページトップへ戻る
☆PIC18F14K50

PIC18F2550では大きすぎて、計画中のTK80互換マイコンボードND80ZVには組み込めそうにないことがわかりました。
USB機能内蔵のPICにはPIC18F4550、PIC18F2550のほかに20pinのPIC18F14K50があることはちょっと前から知っていました。しかしUSBに関する部分がPIC18F2550とはかなり異なっているようです。
案の定しっかり泥沼にはまってしまいました。

[第74回]

●8ビットパラレルデータ伝送(TK80モニタプログラム

前回はPIC18F2550とZ80CPUとの間での8ビットパラレルデータ伝送について説明をいたしました。
というか、過去記事へのリンクで逃げてしまいました。
今回はその部分のプログラムをお見せすることにいたします。

まずは、Z80版TK80ボード(ND80ZH)の「TK80」モニタプログラムです。
オリジナルのTK80モニタプログラムでは、ここのところは、カセットテープレコーダインターフェイスになっていました。
もちろんいまどきカセットテープではお話しになりませんから、Z80版TK80ボード(ND80ZH)ではそれをPIC16F88を使ってRS232Cインターフェイスにしています。

今回はそこのところを、さらに変更してPIC16F88の代わりにPIC18F2550を使って、RS232Cだけではなくて、USB(HID)での送受信機能が使えるようにしました。
USB(HID)を使うと言っても、実際にその通信部分は全てPIC18F2550がやってくれますから、Z80版TK80ボード(今回の試作ボード)のモニタプログラムは、PIC18F2550との間で、8本のデータラインと4本の制御線を使ってデータをパラレルに送受信すればよく、その方法はPIC16F88でもPIC18F2550でも全く同じです。

そのデータのやり取りの部分をまずZ80版TK80ボード(試作版)の側のプログラムで見てみます。
プログラムサブルーチンの名前はSERIALになっていますが、シリアル送受信を行うのはPIC18F2550ですから、ここのところのPIC18F2550との間でのデータのやり取りはシリアルではなくてパラレルです。

              ;
              ;SERIAL OUTPUT ROUTINE
              ;
027C 4F       SOUT:MOV C,A
027D DB98     SOUT2:IN 98
027F E602       ANI 02
0281 CA7D02     JZ SOUT2
0284 79         MOV A,C
0285 D394       OUT 94
0287 3EF9       MVI A,F9; I/Oaddress 94 "out" & STROBE ON
0289 D398       OUT 98
028B DB98     SOUT3:IN 98
028D E602       ANI 02
028F C28B02     JNZ SOUT3
0292 3EFB       MVI A,FB; I/Oaddress 94 "out" & STROBE OFF
0294 D398       OUT 98
0296 C9         RET
              ;
              ;SERIAL INPUT ROUTINE
              ;
                ORG $02A0
              ;
02A0 DB98     SIN:IN 98
02A2 0F         RRC
02A3 DAA002     JC SIN
02A6 3EFE       MVI A,FE;BUSY
02A8 D398       OUT 98
02AA DB94       IN 94
02AC 4F         MOV C,A
02AD 3EFF       MVI A,FF;READY
02AF D398       OUT 98
02B1 79         MOV A,C
02B2 C9         RET
              ;

8ビットのデータは8本のデータ線を使って一度に送信、または受信されます。
Z80版TK80ボード(試作版)は、8ビットのデータをI/Oアドレス94にOUT(PICに送信)、またはI/Oアドレス94からIN(PICから受信)します。
このとき送信、受信のそれぞれに、2組のSTROBE信号とREADY/BUSY信号を使います。

Z80CPUからPICへ送信する場合には、Z80側がSTROBE信号を出力します。これはI/Oアドレス98のビット1を0にすることで行われます。
実はZ80版TK80ボード(試作版)がデータをPICに出力するときは、このSTROBEとは別にもう1本、I/Oアドレス98のビット2も0にしなければなりません。
I/Oアドレス98のビット2は、データ出力用レジスタ74HC373(IC4)をアクティブにする信号として使われています([第69回]PIC18F2550回路図)。

PIC18F2550が受信可のときは(通常はこの状態です)、I/Oアドレス98のビット1入力がH(1)になります。
STROBEと同じI/Oアドレスですが、STROBEはOUTで、こちらはINです。回路は別になっていますから、信号がぶつかることはありません。
このラインが1(READY)の時にI/Oアドレス98にデータをOUTしてから、STROBEをL(0)にします。

PIC18F2550は、STROBEラインを監視していて、このラインがLになると、データを読み込んで、処理をする間、READY線をL(0)にします。BUSYです。
Z80CPU側は、PIC18F2550がBUSYを送ってきたことを確認してからSTROBEをOFFにします。
PIC18F2550はデータを読み込んだあと、STROBE信号がOFFになったのを確認してからREADY出力にします。

以上はZ80CPUからPIC18F2550へデータを送る(OUTPUT)プログラムの説明ですが、逆にPIC18F2550からZ80CPUにデータが送られてくるとき(INPUT)も、考え方は全く同じです。
データの読み込みもI/Oアドレス94からのINで行われます。
このときにアドレス94の出力(IC4、74HC373)がアクティブになっていると、PIC18F2550からのデータ出力とぶつかってしまいますから、出力禁止にしておかなければなりません。I/Oアドレス98のビット2出力をHにしておきます。

PIC18F2550からのSTROBE信号は、I/Oアドレス98のビット0からの入力で確認されます。
このラインがL(0)になったら、I/Oアドレス94からデータを読み込みます。
READY/BUSY信号はI/Oアドレス98のビット0出力です。
PIC18F2550からのデータ読み込み動作に入る前に、I/Oアドレス98から’FF’を出力して、IC4の出力禁止とREADY出力にしてあります。

データを読み込むよりも前に、BUSY(アドレス98のビット0=0)を出力しているのは、Aレジスタにデータを読み込まなくてはいけないからです。
とはいえ、結局READYを出力するのにAレジスタが必要になりますから、受信したデータは一時Cレジスタに退避させます。

●8ビットパラレルデータ伝送(PIC18F2550プログラム

こちらはPIC18F2550のプログラムです。
Z80のプログラムと同じことをやっているのですが、PIC18F2550のほうがはるかに短いプログラムで済んでいます。
PICのアセンブラ(機械語の命令)はかなり評判が悪いようですが、こうやって比べてみると、I/O制御に適した命令機能をもっていることがわかります。

;
;data out to cpu
;
dtoutsub
        btfss PORTA,1
        goto dtoutsub
        movwf PORTB
        bcf PORTA,0
dtoutsub2
        btfsc PORTA,1
        goto dtoutsub2
        bsf PORTA,0
        return
;
;data in from CPU to READBF
;
dtin
        movf PORTB,w
        bcf PORTA,2;set busy
        movwf INDF2
dtin3
        btfss PORTA,3;if strobe off
        goto dtin3
        bsf PORTA,2;set ready
        return
;

PIC18F2550の側は、パラレルデータの入力、出力にPORTBを使います。
PIC18F2550からZ80の側にパラレルデータを出力する(data out)場合には、PORTAのビット0をSTROBE出力に使います。
bcf PORTA,0でSTROBE on、bsf PORTA,0でSTROBE offです。
bcfはビットクリア、bsfはビットセット命令です。
Z80からのREADY/BUSYはPORTAのビット1に入力されます。
btfssは指定したビットがセットされていたら、次の命令(多くはgotoが使われる)をスキップする命令です。
btfscはその逆に、指定したビットがクリアされていたら、次の命令をスキップする命令です。

movwf PORTBは、wレジスタの値をPORTBにmoveする(wレジスタの値がPORTBから出力される)ために使われています。
PICにはOUT命令、IN命令はありません。
I/Oポートもレジスタとして扱われます。
出力の向きに設定したポートレジスタに値をmoveすることで出力が行われます。

逆に入力の向きに設定したポートレジスタからwレジスタに値をmoveすることで、INと同様の働きになります。
movf PORTB,wは、PORTBからwレジスタに入力値を読み込むために使われています。
PIC18F2550がZ80からのデータを受け取る(data in)場合には、PORTAのビット2をREADY/BUSY出力に使います。
PORTAのビット3には、Z80からのSTROBE信号が入力されます。

data in プログラムには、Z80CPU側からのSTROBEを確認するところがなくて、いきなりデータを読み込んでいますが、STROBEを確認していないのではなくて、このサブルーチンをCALLしている親プログラムで確認しています。

●4ビットパラレルデータ伝送(TK80モニタプログラム

さていよいよ8ビットデータ伝送を4ビット×2データ伝送に直しての動作テストです。
といってもそれほどむつかしいことではありません。
ただすこし面倒なだけです。
4ビットで送受信しますからデータのビット0〜ビット3だけを使います。ビット4〜7は使いません。

              ;
              ;SERIAL OUTPUT ROUTINE
              ;
027C 4F       SOUT:MOV C,A
027D DB98     SOUT2:IN 98
027F E602       ANI 02
0281 CA7D02     JZ SOUT2
0284 CD2603     CALL SOUTSB
0287 3EF9       MVI A,F9; I/Oaddress 94 "out" & STROBE ON
0289 D398       OUT 98
028B DB98     SOUT3:IN 98
028D E602       ANI 02
028F C28B02     JNZ SOUT3
0292 3EFB       MVI A,FB; I/Oaddress 94 "out" & STROBE OFF
0294 D398       OUT 98
0296 C9         RET
              ;
              ;SERIAL INPUT ROUTINE
              ;
                ORG $02A0
              ;
02A0 DB98     SIN:IN 98
02A2 0F         RRC
02A3 DAA002     JC SIN
02A6 3EFE       MVI A,FE;BUSY
02A8 D398       OUT 98
02AA DB94       IN 94
02AC E60F       ANI 0F
02AE 4F         MOV C,A
02AF 3EFF       MVI A,FF;READY
02B1 D398       OUT 98
02B3 DB98     SIN1:IN 98
02B5 0F         RRC
02B6 DAB302     JC SIN1
02B9 3EFE       MVI A,FE
02BB D398       OUT 98
02BD DB94       IN 94
02BF 07         RLC
02C0 07         RLC
02C1 07         RLC
02C2 07         RLC
02C3 E6F0       ANI F0
02C5 B1         ORA C
02C6 4F         MOV C,A
02C7 3EFF       MVI A,FF
02C9 D398       OUT 98
02CB 79         MOV A,C
02CC C9         RET
              ;
              ;
0326 79       SOUTSB:MOV A,C
0327 D394       OUT 94
0329 3EF9       MVI A,F9
032B D398       OUT 98
032D DB98     SOUTSB2:IN 98
032F E602       ANI 02
0331 C22D03     JNZ SOUTSB2
0334 3EFB       MVI A,FB
0336 D398       OUT 98
0338 DB98     SOUTSB3:IN 98
033A E602       ANI 02
033C CA3803     JZ SOUTSB3
033F 79         MOV A,C
0340 0F         RRC
0341 0F         RRC
0342 0F         RRC
0343 0F         RRC
0344 D394       OUT 94
0346 C9         RET

8ビットデータを1回で送信していたところを、2回の繰り返しに変更します。
TK80モニタプログラムをそのまま書き直すと、入力ルーチン(SIN)の開始アドレスがオリジナルと違ってきてしまいますから、一部をサブルーチンにしています(SOUTSB)。

最初は下位4ビットを送ります。
送信する場合はそのまま出力するだけです。
次に上位4ビットを出力するために、RRC命令(右ローテイト)を4回繰り返して上位4ビットのデータを下位4ビットに移動します。
そのようにしておいてから、データを出力します。

データを受信する場合は、8ビットで受け取ることになります(ただし上位4ビットは無意味です)から、受け取ったあと、上位4ビットを捨てるためにANI 0Fを使って、上位4ビットを’0’にしてからワークレジスタに保存します。
次に上位4ビットのデータがやはり下位4ビットのデータとして送られてきますから、RLC命令(左ローテイト)を4回使って、下位4ビットのデータを上位4ビットに移動します。
そのあとで、ANI F0で下位4ビットを’0’にしてから、先に受信した下位4ビットデータとOR命令で合成して、もとの8ビットデータに戻します。

●4ビットパラレルデータ伝送(PIC18F2550プログラム

今回8ビットパラレルデータ伝送を4ビットデータ伝送に変更する目的はPIC18F14K50を使うためです。
しかしいきなりPIC18F14K50のためのプログラムを書いてしまって、それでテストをする、というのは余りに乱暴です。
なにしろPIC18F14K50はまだ使ったことがありません。
今回使ってみるのがはじめてですから、いきなりぶっつけ本番で試したりしたら、どんなトラップにはまってしまうかわかったものではありません。

おお。神よ。
なんと賢明な判断であったことか。
そのように慎重にことを運んでさえ、見事に底無し沼のトラップにはまってしまったのですから。

それはともかく、PIC18F2550では8ビットデータ伝送は動作を確認済みです。
ここはまず、回路もそのまま使うことにして、データ伝送部の上位4ビットも配線済みのまま、プログラムだけ上位4ビットを使わない、ということで動作テストを行いました。
そのようにすれば、プログラム変更の結果、うまく動作しなかった場合でも、もとの8ビットに戻して再確認などをすることもできます。

という考えから、まずはPIC18F2550を使って4ビットデータ伝送のテストをしてみることにしました。

これがPIC18F2550の4ビット出力および入力プログラムです。
考え方はTK80モニタプログラムの変更についての考え方と全く同じです。

;
;data out to CPU
;
dtoutsub
	btfss PORTA,1
	goto dtoutsub
	movwf datawk
	movwf PORTB;low 4bits out
	bcf PORTA,0
dtoutsub2
	btfsc PORTA,1
	goto dtoutsub2
	bsf PORTA,0
dtoutsub3
	btfss PORTA,1
	goto dtoutsub3
	rrncf datawk
	rrncf datawk
	rrncf datawk
	rrncf datawk,w
	movwf PORTB;high 4bits
	bcf PORTA,0
dtoutsub5
	btfsc PORTA,1
	goto dtoutsub5
	bsf PORTA,0
	return
;
;data in from CPU to READBF
;
;
dtinsub
	movf PORTB,w
	andlw 0f
	movwf datawk
	bcf PORTA,2
dtinsub1
	btfss PORTA,3
	goto dtinsub1
	bsf PORTA,2
dtinsub2
	btfsc PORTA,3
	goto dtinsub2
	movf PORTB,w
	bcf PORTA,2
	movwf datawkh4
	rlncf datawkh4
	rlncf datawkh4
	rlncf datawkh4
	rlncf datawkh4,w
	andlw 0f0
	iorwf datawk,w
dtinsub3
	btfss PORTA,3
	goto dtinsub3
	bsf PORTA,2
	return		

このようにして、TK80モニタプログラムとPIC18F2550のプログラムの両方を4ビットデータ伝送に書き直して動作テストを行って、8ビットの場合と同じように動作することを確認いたしました。

すると、次はいよいよ、PIC18F2550のプログラムを、PIC18F14K50に移植しての動作テストです。
CPUをつくろう!第501回(2010.5.17upload)を再編集

PICでUSBを![第74回]
2011.7.12upload

前へ
次へ
目次へ戻る
ホームページトップへ戻る