RL78マイコン基板(RL78/G10)|TOOL0端子へのシリアル出力を使ったgetch()関数もどきのコード
秋月電子さんで販売されているRL78/G10 10pin DIP基板に書き込む為にブレッドボード上に組んだ自作回路
(FT232RLと74HC125と抵抗2本の簡単なもの)をRL78/G10のTOOL0端子(書き込みに使う端子)に繋げたまま、
2つ前のエントリでRL78/G10のTOOL0端子からPC上にデバッグメッセージを表示させたり、1つ前のエントリで
PC側のキーが押されたことをTOOL0端子でRL78/G10に伝えたりしたのですが、ちょっと思い付いた(というか
割り切るやり方として気付いた)ことがあって、今回、PC側で押されたキーのキー入力コード(文字コード)を
TOOL0端子でRL78/G10に伝えるアセンブラコードを書いて試してみました。(我ながら怪しいコードですが。)
結局のところTOOL0端子に接続されたFT232RLからのシリアル出力をTOOL0端子の素朴なポート入力機能を
使って受信するソフトウェアシリアルなのですが、今までモヤモヤしていたことが幾らか晴れてきました。
(1) FT232RLを2Mbaudで動かすことに意地になっていますが、UARTの1ビット幅がRL78/G10の10クロック
相当なので、受信を始めたら割り込み禁止でTOOL0端子を監視しないとスタートビット検出に失敗する。
キー入力は人が行うことなので、割り込み処理が秒や分の単位で停止してしまう(保留される)ことになる。
その結果としては、例えばダイナミック点灯では点灯中のセグメントに流れる電流が過大になってしまう。
→スタートビットの検出に失敗すると受信データの最上位ビットは1になる。(あるいは受信データが
丸ごとすっぽ抜けて何も受信されないことになる。) デバッグ目的で人が行うキー入力であれば、
エラーを表示して再入力すれば事足りるような気がします。(あるいは受信データがすっぽ抜けた
ことにより何の応答も返って来ないような場合なら誰でも再入力するでしょうし。) そう考えれば
エラーを容認することにして割り込みを禁止しない手もありな気がします。
→または、割り込み処理が停止しても(保留されても)問題ない状態にしてから受信を始める(というか
受信処理を呼び出す)ようにする。例えば、前のエントリのkbhit()関数でキー押下があったかどうか
調べて、キー押下があれば問題が起きない安全な状態に設定してから次のキー入力を求めるような
メッセージを表示し、その後で割り込み禁止にしてから受信処理を呼び出すとか。
→追記 : もっとも、ICEを使ってデバッグする時もブレークした時には同様に割り込み処理が秒や分の
単位で停止してしまう(保留される)ので、何日か経った後で思い返してみると、デバッグ目的として
いた筈なのに何か思い込み過ぎ(だっただけ)のような気もして来ています。
(2) 上にも書いたことですがFT232RLを2Mbaudで動かすことに意地になっていますが、UARTの1ビット幅が
RL78/G10の10クロック相当なのに、アセンブラコードにしてもTOOL0端子の入力をポーリングする間隔
として5クロック掛かってしまう。あたかも量子力学の電子位置のごとくスタートビットの立下りエッジ
位置の存在確率が5クロック幅の中に不確実に広がっているわけで、当然ながらデータビット(10クロック
幅)の真ん中の位置を求める時の精度に関しても不確実なものになってしまう。
→10クロック幅の真ん中の位置がその半分の5クロック幅の精度でしか求まらないので、FT232RLと
RL78/G10の双方のボーレート偏差のマージンが通常の半分に減ることになりますが、逆に、通常は
2%とされているマージンが半分に減っても1%のマージンはあると考えることも出来ない訳ではない
気もします。マージンは大元の発振回路での周波数精度と分周回路(ボーレートジェネレータ)での
生成誤差の合計ですが、今回の場合は分周回路的にはぴったり2Mbaudとして生成されていると思い
ますので対象が発振回路での周波数精度だけになって、ちょっとは希望が持てるような気がします。
(もっとも、我ながら怪しい考えだとも思っていますが。)
そういうことで実際にアセンブラコードを書いて試してみたところ、うまく行きました。

作成したアセンブラコード(計87バイト)は以下の通りです。(前のエントリで作成したputchar()とkbhit()の
2つも含めています。ちなみに、我ながら怪しい考え方をしていると思っている箇所を紫字にしています。)
; This code is in the public domain. You may use, modify or distribute it freely.
PUBLIC _putchar
_putchar: ;X = data, A = ignored, void putchar( unsigned char )
SET1 PM4.0 ; 2 clk 3 byte always I do for robustness, P40 = TOOL0/KR0
CLR1 P4.0 ; 2 clk 3 byte same as above
MOV1 CY, KRM0.0 ; 1 clk 3 byte for kbhit(), get KR0 detection enable flag
CLR1 KRM0.0 ; 2 clk 3 byte for kbhit(), disable KR0 detection flag
PUSH PSW ; 2 clk 2 byte
_putchar_b: ;begin
ONEB A ; 1 clk 1 byte as a stop bit, shorter than "MOV A, #01H"
ADDW AX, AX ; 2 clk 1 byte for a start bit, shorter than "SHLW AX, 1"
DI ; 4 clk 3 byte
_putchar_l: ;loop (start bit = 0, b0, b1, b2, b3, b4, b5, b6, b7, stop bit = 1)
SHRW AX, 1 ; 2 clk 2 byte
MOV1 PM4.0, CY ; 2 clk 3 byte
CMPW AX, #0000H ; 2 clk 3 byte
BNZ $_putchar_l ; 2/4 clk 2 byte
_putchar_e: ;end
POP PSW ; 4 clk 2 byte
MOV1 KRM0.0, CY ; 2 clk 3 byte for kbhit(), restore KR0 detection enable flag
RET ; 7 clk 1 byte
PUBLIC _kbhit
_kbhit: ;char kbhit( void ), return value : 1=detected / 0=not detected
SET1 PM4.0 ;always I do for robustness, P40 = TOOL0/KR0
SET1 KRM0.0 ;enable KR0 detection flag
SET1 KRCTL.7 ;enable KRx detection flags
MOV A, KRF ;get KRx detection flgas
AND A, #01H ;check KR0 detecion flag
BZ $_kbhit_e ;Z=not detected / NZ=detected
MOV C, #20 ;set loop count (10 clk/bit * 10 bit = 100 clk = 5 clk * 20)
_kbhit_w: ;wait 100 clk (start bit, b0, b1, b2, b3, b4, b5, b6, b7, stop bit)
DEC C ; 1 clk 1 byte
BNZ $_kbhit_w ; 2/4 clk 2 byte
MOV KRF, #0FEH ;clear KR0 detection flag
_kbhit_e:
MOV C, A ;A = KR0 detecion flag (01H=detected / 00H=not detected)
RET ;C = return value (1=detected / 0=not detected)
PUBLIC _getch
_getch: ;unsigned char getch( void ), return value : character code
SET1 PM4.0 ; 2 clk 3 byte always I do for robustness, P40 = TOOL0/KR0
_getch_w: ;wait for a start bit
BT P4.0, $$ ; 3/5 clk 4 byte
_skip_10clk: ;MAYBE (as average of trials) ...
; ;falling edge of start bit is (5 / 2) + 3 = 5.5 clk before
; ;center of b0 is 9.5 clk later
BR $$+2 ; 3 clk 2 byte only for getting clocks
BR $$+2 ; 3 clk 2 byte only for getting clocks
BR $$+2 ; 3 clk 2 byte only for getting clocks
MOV C, #8 ; 1 clk 2 byte set loop count
_getch_l: ;loop (b0, b1, b2, b3, b4, b5, b6, b7)
MOV1 CY, P4.0 ; 1 clk 3 byte
RORC A, 1 ; 1 clk 2 byte
BR $$+2 ; 3 clk 2 byte only for getting clocks
DEC C ; 1 clk 1 byte
BNZ $_getch_l ; 2/4 clk 2 byte
_getch_e: ;end
MOV C, A ; 1 clk 1 byte A = data
RET ; 7 clk 1 byte C = return value (character code)
END
また、動作確認用に作成したCコードは以下の通りです。
void putchar( unsigned char );
char kbhit( void );
unsigned char getch( void );
void puts( char *p ) { while (*p) putchar( (unsigned char)*p++); }
途中省略
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
DI();
while (1U)
{
unsigned char c;
c = getch();
puts( " <-- input on TeraTerm & echo by 74HC125 : echo by RL78/G10 --> " );
if ( c < 0x80 )
{
putchar(c);
}
else
{
puts("ERROR");
}
puts( "\r\n" );
}
/* End user code. Do not edit comment generated here */
}

(FT232RLと74HC125と抵抗2本の簡単なもの)をRL78/G10のTOOL0端子(書き込みに使う端子)に繋げたまま、
2つ前のエントリでRL78/G10のTOOL0端子からPC上にデバッグメッセージを表示させたり、1つ前のエントリで
PC側のキーが押されたことをTOOL0端子でRL78/G10に伝えたりしたのですが、ちょっと思い付いた(というか
割り切るやり方として気付いた)ことがあって、今回、PC側で押されたキーのキー入力コード(文字コード)を
TOOL0端子でRL78/G10に伝えるアセンブラコードを書いて試してみました。(我ながら怪しいコードですが。)
結局のところTOOL0端子に接続されたFT232RLからのシリアル出力をTOOL0端子の素朴なポート入力機能を
使って受信するソフトウェアシリアルなのですが、今までモヤモヤしていたことが幾らか晴れてきました。
(1) FT232RLを2Mbaudで動かすことに意地になっていますが、UARTの1ビット幅がRL78/G10の10クロック
相当なので、受信を始めたら割り込み禁止でTOOL0端子を監視しないとスタートビット検出に失敗する。
キー入力は人が行うことなので、割り込み処理が秒や分の単位で停止してしまう(保留される)ことになる。
その結果としては、例えばダイナミック点灯では点灯中のセグメントに流れる電流が過大になってしまう。
→スタートビットの検出に失敗すると受信データの最上位ビットは1になる。(あるいは受信データが
丸ごとすっぽ抜けて何も受信されないことになる。) デバッグ目的で人が行うキー入力であれば、
エラーを表示して再入力すれば事足りるような気がします。(あるいは受信データがすっぽ抜けた
ことにより何の応答も返って来ないような場合なら誰でも再入力するでしょうし。) そう考えれば
エラーを容認することにして割り込みを禁止しない手もありな気がします。
→または、割り込み処理が停止しても(保留されても)問題ない状態にしてから受信を始める(というか
受信処理を呼び出す)ようにする。例えば、前のエントリのkbhit()関数でキー押下があったかどうか
調べて、キー押下があれば問題が起きない安全な状態に設定してから次のキー入力を求めるような
メッセージを表示し、その後で割り込み禁止にしてから受信処理を呼び出すとか。
→追記 : もっとも、ICEを使ってデバッグする時もブレークした時には同様に割り込み処理が秒や分の
単位で停止してしまう(保留される)ので、何日か経った後で思い返してみると、デバッグ目的として
いた筈なのに何か思い込み過ぎ(だっただけ)のような気もして来ています。
(2) 上にも書いたことですがFT232RLを2Mbaudで動かすことに意地になっていますが、UARTの1ビット幅が
RL78/G10の10クロック相当なのに、アセンブラコードにしてもTOOL0端子の入力をポーリングする間隔
として5クロック掛かってしまう。あたかも量子力学の電子位置のごとくスタートビットの立下りエッジ
位置の存在確率が5クロック幅の中に不確実に広がっているわけで、当然ながらデータビット(10クロック
幅)の真ん中の位置を求める時の精度に関しても不確実なものになってしまう。
→10クロック幅の真ん中の位置がその半分の5クロック幅の精度でしか求まらないので、FT232RLと
RL78/G10の双方のボーレート偏差のマージンが通常の半分に減ることになりますが、逆に、通常は
2%とされているマージンが半分に減っても1%のマージンはあると考えることも出来ない訳ではない
気もします。マージンは大元の発振回路での周波数精度と分周回路(ボーレートジェネレータ)での
生成誤差の合計ですが、今回の場合は分周回路的にはぴったり2Mbaudとして生成されていると思い
ますので対象が発振回路での周波数精度だけになって、ちょっとは希望が持てるような気がします。
(もっとも、我ながら怪しい考えだとも思っていますが。)
そういうことで実際にアセンブラコードを書いて試してみたところ、うまく行きました。

作成したアセンブラコード(計87バイト)は以下の通りです。(前のエントリで作成したputchar()とkbhit()の
2つも含めています。ちなみに、我ながら怪しい考え方をしていると思っている箇所を紫字にしています。)
; This code is in the public domain. You may use, modify or distribute it freely.
PUBLIC _putchar
_putchar: ;X = data, A = ignored, void putchar( unsigned char )
SET1 PM4.0 ; 2 clk 3 byte always I do for robustness, P40 = TOOL0/KR0
CLR1 P4.0 ; 2 clk 3 byte same as above
MOV1 CY, KRM0.0 ; 1 clk 3 byte for kbhit(), get KR0 detection enable flag
CLR1 KRM0.0 ; 2 clk 3 byte for kbhit(), disable KR0 detection flag
PUSH PSW ; 2 clk 2 byte
_putchar_b: ;begin
ONEB A ; 1 clk 1 byte as a stop bit, shorter than "MOV A, #01H"
ADDW AX, AX ; 2 clk 1 byte for a start bit, shorter than "SHLW AX, 1"
DI ; 4 clk 3 byte
_putchar_l: ;loop (start bit = 0, b0, b1, b2, b3, b4, b5, b6, b7, stop bit = 1)
SHRW AX, 1 ; 2 clk 2 byte
MOV1 PM4.0, CY ; 2 clk 3 byte
CMPW AX, #0000H ; 2 clk 3 byte
BNZ $_putchar_l ; 2/4 clk 2 byte
_putchar_e: ;end
POP PSW ; 4 clk 2 byte
MOV1 KRM0.0, CY ; 2 clk 3 byte for kbhit(), restore KR0 detection enable flag
RET ; 7 clk 1 byte
PUBLIC _kbhit
_kbhit: ;char kbhit( void ), return value : 1=detected / 0=not detected
SET1 PM4.0 ;always I do for robustness, P40 = TOOL0/KR0
SET1 KRM0.0 ;enable KR0 detection flag
SET1 KRCTL.7 ;enable KRx detection flags
MOV A, KRF ;get KRx detection flgas
AND A, #01H ;check KR0 detecion flag
BZ $_kbhit_e ;Z=not detected / NZ=detected
MOV C, #20 ;set loop count (10 clk/bit * 10 bit = 100 clk = 5 clk * 20)
_kbhit_w: ;wait 100 clk (start bit, b0, b1, b2, b3, b4, b5, b6, b7, stop bit)
DEC C ; 1 clk 1 byte
BNZ $_kbhit_w ; 2/4 clk 2 byte
MOV KRF, #0FEH ;clear KR0 detection flag
_kbhit_e:
MOV C, A ;A = KR0 detecion flag (01H=detected / 00H=not detected)
RET ;C = return value (1=detected / 0=not detected)
PUBLIC _getch
_getch: ;unsigned char getch( void ), return value : character code
SET1 PM4.0 ; 2 clk 3 byte always I do for robustness, P40 = TOOL0/KR0
_getch_w: ;wait for a start bit
BT P4.0, $$ ; 3/5 clk 4 byte
_skip_10clk: ;MAYBE (as average of trials) ...
; ;falling edge of start bit is (5 / 2) + 3 = 5.5 clk before
; ;center of b0 is 9.5 clk later
BR $$+2 ; 3 clk 2 byte only for getting clocks
BR $$+2 ; 3 clk 2 byte only for getting clocks
BR $$+2 ; 3 clk 2 byte only for getting clocks
MOV C, #8 ; 1 clk 2 byte set loop count
_getch_l: ;loop (b0, b1, b2, b3, b4, b5, b6, b7)
MOV1 CY, P4.0 ; 1 clk 3 byte
RORC A, 1 ; 1 clk 2 byte
BR $$+2 ; 3 clk 2 byte only for getting clocks
DEC C ; 1 clk 1 byte
BNZ $_getch_l ; 2/4 clk 2 byte
_getch_e: ;end
MOV C, A ; 1 clk 1 byte A = data
RET ; 7 clk 1 byte C = return value (character code)
END
また、動作確認用に作成したCコードは以下の通りです。
void putchar( unsigned char );
char kbhit( void );
unsigned char getch( void );
void puts( char *p ) { while (*p) putchar( (unsigned char)*p++); }
途中省略
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
DI();
while (1U)
{
unsigned char c;
c = getch();
puts( " <-- input on TeraTerm & echo by 74HC125 : echo by RL78/G10 --> " );
if ( c < 0x80 )
{
putchar(c);
}
else
{
puts("ERROR");
}
puts( "\r\n" );
}
/* End user code. Do not edit comment generated here */
}

- 関連記事
-
- RL78マイコン基板(RL78/G10)|CS+(CubeSuite+)で内蔵周辺機能シミュレーションを試す (3)
- RL78マイコン基板(RL78/G10)|CS+(CubeSuite+)で内蔵周辺機能シミュレーションを試す (2)
- RL78マイコン基板(RL78/G10)|CS+(CubeSuite+)で内蔵周辺機能シミュレーションを試す (1)
- RL78マイコン基板(RL78/G10)|e2studio同梱のPython 2.7.2+pySerial 2.7でシリアルポート操作
- RL78マイコン基板(RL78/G10)|CS+(CubeSuite+)のPythonコンソール上でシリアルポート操作 (3)
- RL78マイコン基板(RL78/G10)|CS+(CubeSuite+)のPythonコンソール上でシリアルポート操作 (2)
- RL78マイコン基板(RL78/G10)|CS+(CubeSuite+)のPythonコンソール上でシリアルポート操作 (1)
- RL78マイコン基板(RL78/G10)|TOOL0端子へのシリアル出力を使ったgetch()関数もどきのコード
- RL78マイコン基板(RL78/G10)|TOOL0端子へのシリアル出力を使ったkbhit()関数もどきのコード
- RL78マイコン基板(RL78/G10)|TOOL0端子から2Mbaudでソフトウェアシリアル出力するコード
- RL78マイコン基板(RL78/G10)|Renesas Flash Programmerのコマンドラインでフラッシュ書き込み
- RL78マイコン基板(RL78/G10)|秋月のRL78/G10 10pin DIP基板に自作回路でフラッシュ書き込み (2)
- RL78マイコン基板(RL78/G10)|秋月のRL78/G10 10pin DIP基板に自作回路でフラッシュ書き込み (1)
- RL78マイコン|10ピン0.65mmピッチSSOP→DIP変換基板が見当たらない
- RL78マイコン | 公開されている仕様ではRL78マイコン用GDBSTUBを作ることが出来ない
2015/01/11 blog-entry-548 category: RL78 /* 16bit,8bit CISC */
| h o m e |