なんとかなるさね

マイコンをネタにブログを始めてみました


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 */
}




関連記事

2015/01/11   blog-entry-548   category: RL78 /* 16bit,8bit CISC */

go page top