標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第583回]
●PICSTBがおかしい
前回、PIC18F14K50からZ80CPU側に232C受信データを渡しているところをロジアナで記録した波形を見まして、おかしいところがあることに気が付きました、と書きました。
まずはそのことについて説明をいたします。
これは前回最初にお見せした波形です。
16,17と続くデータの、 ,1 の部分を渡しているところです。
おかしなところというのは、図の矢印で示した@の立下り部分です。
この信号はPIC18F14K50がZ80にデータを渡すときに、そのデータをセットしたことをZ80に示すためのSTB信号です。
処理の流れから、このデータは232C受信データなのですが、ここでデータがセットされるのはあきらかに間違っています。
@の立ち下りは、その上の232Cセレクト信号が立ち上がったあとのタイミングになっています。
なぜ?
おかしいのはそこなのです。
PICSTB信号は、232Cセレクト信号の立ち下りを見て、出力されるべきなのです。
次のデータを受け取るために232Cセレクト信号が立ち下るのは、Aのタイミングですから、ほんとうはAのあとで、@の立ち下りが来なければいけないはずです。
もうひとつおかしいところがあります。
Bの立ち下りも、@と同じ理由でおかしいのです。
このときは、受信バッファにデータが残っていなかったらしく、受信バッファエンプティを返しているために、PICSTBは15μsec程度で立ち上がっています。
この受信バッファエンプティの信号も、本当はCのタイミングが正しいのです。
なぜかBで余計な応答をしてしまっています。
なぜか、と書きましたがもちろん今はその理由はわかっています。
●PIC18F14K50のデータ送出プログラムに甘いところがありました
PIC18F14K50のデータ送出ルーチン(dtoutsub)のソースリストです。
このリストは上で指摘した問題点を修正したあとのものです。
dtoutsub
movwf datawk
btfsc PORTC,4
iorlw 10;rc4=1 (232cerror none)
btfss PORTC,4
andlw 0f;rc=0 (232cerror)
dtoutsub1
btfss PORTC,5;wait till cpu READY
goto dtoutsub1
movwf PORTC;low 4bits out
bcf PORTB,4; STROBE out
dtoutsub2
btfsc PORTC,5; wait till cpu BUSY
goto dtoutsub2
bsf PORTB,4; STROBE off
; High 4 bits data out
rrncf datawk
rrncf datawk
rrncf datawk
rrncf datawk,w
btfsc PORTC,4
iorlw 10;rc4=1 (232cerror none)
btfss PORTC,4
andlw 0f;rc=0 (232cerror)
dtoutsub3
btfss PORTC,5; wait till cpu ready
goto dtoutsub3
movwf PORTC;high 4bits out
bcf PORTB,4; STROBE out
dtoutsub4
btfsc PORTC,5; wait till cpu BUSY
goto dtoutsub4
bsf PORTB,4; STROBE off
dtoutsub5
btfss PORTC,5;wait till cpu ready & 232c off
goto dtoutsub5
btfss PORTC,7
goto dtoutsub5
return
このことに気が付く前は、一番最後の
btfss PORTC,7
goto dtoutsub5
が無かったのです。
当初は、この部分が無かったために、232Cセレクト信号の立ち上がりを確認しないでリターンしていました。
232Cセレクト信号もじきに立ち上がるのですが、PIC18F14K50は何しろクロックが48MHzですから、実に速いのです。
前回お見せしたフローチャートをあっという間に一巡してしまって、まだ232Cセレクト信号が立ち上がる前に、次の232Cセレクト信号のチェックルーチンにエントリしてしまっていたのです。
Bの立ち下りが発生してしまったのもまったく同じ理由からでした。
そして、問題のデータの欠落部分です。

Dの立ち下りが誤りであることは上で説明した理由と全く同じなのですが、今度はまだ受信データが残っているために、Z80がそれを引き取るまでずっと待っています。
Z80CPU側は、かなり時間が経ってから、約120μsec後に、Z80BUSY信号をアクティブにして、データを引き取っています。
ところが良く見ますと、232Cセレクト信号は上がったままです。
ということはZ80CPUは、このときのデータは232C受信データではなくて、USB(HID)経由でWindowsパソコンから送られてきたデータとして受け取っているらしいことになります。
しかし、PIC18F14K50の側は、232C受信バッファのデータを渡しているのです。
なぜこのような食い違いが起きてしまったのでしょうか。
じつは、前回の出力データの説明にもありましたように、このときのコード[37]つまり文字’7’が、Z80BASICで232C受信データを格納していたA$に39バイト目のデータとして入れられたので、一旦READ #1命令が終了して、次の処理に移っていたのです。
Z80BASICは、実行中にWindowsパソコンのキーボードから[Ctrl][B]を入力することでブレイクさせて、実行を中止することができます。
その機能のために、Z80BASICでは、各行の先頭部分で毎回ブレイクキーの入力の有無をチェックしています。
上のロジアナの波形にあった、Windowsパソコンからのデータとして受け取っているのは、そこだったのです。
しかしブレイクチェックルーチンではブレイクコード(00)にしか反応しませんから、そこで受け取ったコード(2C)は結局捨てられてしまったのです。
ところで、前回お見せしましたように、A$に39バイトのデータが溜まる以前にも、ひんぱんにREAD #1が終了して次の処理に移っていたはずなのに、なぜ、39バイトのデータが溜まったときに限って、上で説明したようなデータの欠落が起きたのでしょうか。
これには、かなり悩みました。
なぜだろうか?
たまたま、とか偶然に、とかといって片付けるにはちょっと無理があります。
何か理由があるはず。
やっと、そのわけがわかりました。
その理由は、READ #1の処理ルーチンの仕組みにありました。
前回説明しましたように、READ #1命令は、そこで受信待ちでハングアップしてしまわないように、受信バッファエンプティを受け取ったときは、すぐにリターンします。
受信データがあるときは、文字変数にそのデータを追記していきますが、文字変数に39バイトのデータが格納されると、データの受け取り処理を中断して、READ #1を一旦終了してしまいます。
参考までに、Z80BASICのREAD #1部分のプログラムリストです。
;;;
3946 13 RDURA:INC DE
3947 CD262A CALL ICALC
394A 7D LD A,L
394B FE01 CP 01
394D C21F3A JP NZ,ER3E;=62
3950 CD0E3A CALL RDHNS
3953 C21F3A JP NZ,ER3E
3956 E5 PUSH HL
3957 CD0E3A CALL RDHNS
395A FEF2 CP F2
395C C21F3A JP NZ,ER3E
395F DDE1 POP IX
3961 DDE5 PUSH IX;A$
3963 E5 PUSH HL;A%
3964 4E LD C,(HL)
3965 23 INC HL
3966 46 LD B,(HL)
3967 DDE5 PUSH IX
3969 E1 POP HL
396A 03 INC BC
396B 79 LD A,C
396C B0 OR B
396D CA7D39 JP Z,SIN2;A%=-1
3970 0B DEC BC
3971 79 LD A,C
3972 B0 OR B
3973 CA7C39 JP Z,SIN1
3976 E1 POP HL
3977 DDE1 POP IX
3979 C3EE2F JP STEND
397C 77 SIN1:LD (HL),A
397D 7E SIN2:LD A,(HL)
397E FE27 CP 27
3980 D2A839 JP NC,SINFUL;A$=FULL
3983 23 INC HL
3984 D5 PUSH DE
3985 1600 LD D,00
3987 5F LD E,A
3988 19 ADD HL,DE
3989 47 LD B,A
398A 3E27 LD A,27
398C 90 SUB B
398D CDB439 CALL RDSB
3990 D1 POP DE
3991 E1 POP HL
3992 DDE1 POP IX
3994 DD7000 LD (IX+00),B
3997 CAAD39 JP Z,SINEND
399A 78 LD A,B
399B FE27 CP 27
399D CAAB39 JP Z,SINFUL2
39A0 3EFF LD A,FF
39A2 77 LD (HL),A
39A3 23 INC HL
39A4 77 LD (HL),A
39A5 C3EE2F JP STEND
39A8 E1 SINFUL:POP HL
39A9 DDE1 POP IX
39AB 0628 SINFUL2:LD B,28
39AD 70 SINEND:LD (HL),B
39AE 23 INC HL
39AF 3600 LD (HL),00
39B1 C3EE2F JP STEND
;
39B4 08 RDSB:EX AF,AF'
39B5 C5 RDSB2:PUSH BC
39B6 06EB LD B,EB
39B8 78 LD A,B
39B9 D398 OUT (98),A
39BB DB94 RDSB3:IN A,(94)
39BD E620 AND 20
39BF C2BB39 JP NZ,RDSB3
39C2 3E0A LD A,0A;WAIT ABOUT 20MICROS
39C4 3D RDSB32:DEC A;(4)
39C5 C2C439 JP NZ,RDSB32;(10)
39C8 DB94 IN A,(94)
39CA E620 AND 20
39CC C2F739 JP NZ,RDSB4
39CF DB94 IN A,(94)
39D1 E610 AND 10
39D3 F5 PUSH AF
39D4 CDA706 CALL RSIN
39D7 3EEF LD A,EF
39D9 D398 OUT (98),A
39DB F1 POP AF
39DC CAFD39 JP Z,SINER;=73
39DF 79 LD A,C
39E0 C1 POP BC
39E1 FE0A CP 0A
39E3 C8 RET Z
39E4 FE0D CP 0D
39E6 CAB539 JP Z,RDSB2
39E9 77 LD (HL),A
39EA 23 INC HL
39EB 04 INC B
39EC 08 EX AF,AF'
39ED 3D DEC A
39EE CAF539 JP Z,RDSB33
39F1 08 EX AF,AF'
39F2 C3B539 JP RDSB2
39F5 3C RDSB33:INC A;reset zf
39F6 C9 RET
39F7 3EEF RDSB4:LD A,EF
39F9 D398 OUT (98),A
39FB C1 POP BC
39FC C9 RET
;
39FD F1 SINER:POP AF;DUMMY
39FE F1 POP AF;DUMMY
39FF D1 POP DE
3A00 E1 POP HL
3A01 71 LD (HL),C
3A02 23 INC HL
3A03 3600 LD (HL),00
3A05 3EEF LD A,EF
3A07 D398 OUT (98),A
3A09 3E49 ER49:LD A,49
3A0B C33D31 JP ERRDP
[以下の説明部分を書き直しました(2010.8.15)]
文字変数に39バイトのデータが入れられると、それ以上はその文字変数にデータを入れることはできません(Z80BASICの文字変数は39バイトの固定長です)。
そこでその文字変数のデータを処理できるようにするために、一旦READ #1を終了します。
このことは、PIC18F14K50の232C受信バッファにデータが残っていても、残っていなくても、それとは関係なしにZ80BASIC側の事情(文字変数に39バイトのデータが格納されたこと)によって発生します。
もしまだ受信バッファにデータが残っている場合には、PIC18F14K50は続いて残っているデータを送出しようとすることになりますが、Z80BASIC側は、文字変数のデータを処理して、ふたたびREAD #1ルーチンにエントリしてくるまでの間は、その受信データを引き取ることはできません。
そこで、READ #1ルーチンでは、受信データを1バイト引き取るごとに、232Cセレクト信号をアクティブにするようにしているのです。
PIC18F14K50は、232Cセレクト信号が立ち下がったら、Z80側に受信データを1バイト送り出します。
READ #1ルーチンで、232Cセレクト信号をアクティブ(出力L)にしているところは、上のリストのアドレス39B9です。
I/Oアドレス98のビット2が、232Cセレクト信号です。
この出力ラインはPIC18F14K50のPORTCのビット7につながっています。
232CセレクトラインをOFF(出力H)にしているところは、アドレス39D9、39F9です。
このラインを1バイト受信するごとにアクティブにして、PIC18F14K50からのデータ送出をコントロールしていたつもりだったのですが、PIC18F14K50のプログラムで、232Cセレクト信号がOFF(H)になるのを確認しないで、Z80へのデータ送出ルーチンからリターンしていたために、Z80側が受け取った1バイトのデータの処理を完了して232CセレクトラインをHにするよりも前に、ふたたびPIC18F14K50のデータ送出ルーチンが実行されていました。
Z80BASICの側では、まだ文字変数に39バイトのデータが格納されるまでの間は、引き続きREAD #1ルーチンの中で、次のデータを受け取りますから、PIC18F14K50が、先にデータを送出するようにしていても、そこでは問題は発生することなく、データの受け渡しが行われます。
もしPIC18F14K50の232C受信バッファにデータが残っていない場合には、さきほどのロジアナ波形の矢印Bのように、受信バッファエンプティの誤出力になりますから、わずか15μsecの期間だけアクティブになるだけです。
PIC18F14K50のクロック48MHzは非常に高速ですが、Z80は6MHzですから、それに比べればかなりゆっくりしています。
矢印BのパルスはZ80BASICでは認識されることなくパスされてしまっているのですが、もしもZ80の処理がもう少し速くて、Bのパルスを認識していたとしても、その場合には、やっぱり受信バッファエンプティとして処理されますから、したがって、この場合にもなんの問題も発生しません。
結局、まだPIC18F14K50の受信バッファに、送出されていないデータが残っているときに、文字変数にデータが39バイト格納されて、そこでREAD #1が終了した時に限って、PIC18F14K50は次のデータをセットして、それをZ80側が引き取るまでスタンバイすることになり、そしてそのときには、Z80BASICではブレイクコードのチェックが行われるために、上で説明した「食い違い」によって、データの欠落が発生することになったのです。
文字変数データに39バイトのデータが格納されてREAD #1が終了したときに、たまたまPIC18F14K50の232C受信バッファが空になっていた場合には、矢印Bの受信バッファエンプティが出力されますが、これは既に説明しましたように、出力されるタイミングが速すぎてZ80側では認識できませんから、そのままパスされてしまいます。
したがって、このときには、文字変数が39バイトになっても、データの欠落はおこりません。
データの欠落は、文字変数にデータが39バイト入れられた直後に発生していましたが、しかし、文字変数にデータが39バイト入れられた直後でも、発生していないところもありましたが、そのときは、たまたま受信バッファが空になったときだったのです。
[ここまで2010.8.15書き直し]
プログラム修正後の波形です。

PICSTBの誤出力は無くなっています。
もちろん、データの欠落は発生しなくなりました。
>.
10 A%=0
20 READ #1,A$,A%
30 IF A%<1 GOTO 20
40 PRINT A$
50 GOTO 10
>r.
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1
6,17,18,19,20,21,22,23,24,25,26,27,28,2
9,30,31,32,33,34,35,36,37,38,39,40,41,4
2,43,44,45,46,47,48,49,50,51,52,53,54,5
5,56,57,58,59,60,61,62,63,64,65,66,67,6
8,69,70,71,72,73,74,75,76,77,78,79,80,8
1,82,83,84,85,86,87,88,89,90,91,92,93,9
4,95,96,97,98,99,100,101,102,103,104,10
5,106,107,108,109,110,111,112,113,114,1
15,116,117,118,119,120,121,122,123,124,
125,126,127,128,129,130,131,132,133,134
,135,136,137,138,139,140,141,142,143,14
4,145,146,147,148,149,150,151,152,153,1
54,155,156,157,158,159,160,161,162,163,
164,165,166,167,168,169,170,171,172,173
,174,175,176,177,178,179,180,181,182,18
3,184,185,186,187,188,189,190,191,192,1
93,194,195,196,197,198,199,200,201,202,
203,204,205,206,207,208,209,210,211,212
,213,214,215,216,217,218,219,220,221,22
2,223,224,225,226,227,228,229,230,231,2
32,233,234,235,236,237,238,239,240,241,
242,243,244,245,246,247,248,249,250,251
,252,253,254,255,end
2010.8.14upload
2010.8.15一部更新
前へ
次へ
ホームページトップへ戻る