自作関数のリエントラント性について

RL78/G14(R5F104LLAFB#V0)で、C言語の自作関数を使用しておりますが、この関数をメインルーチンと割り込みルーチンの両方で使用しております。

関数内ではグローバル変数を使用しておらず、リエントラントになっていると考えております。

 

void mmcopy( _UBYTE *d5, _UBYTE *s5, _UWORD n)
{ _UWORD i;
for(i=0;i<n;i++)
*(d5+i) = *(s5+i);
}

 

この関数がメインと割り込みで競合した場合、カウンタiはスタック退避されて戻れると認識しておりますが、E1エミュレータを接続し、連続運転していると

RESF=10hのリセットが発生します。OCDトレースを見るとこの関数で無限ループに陥っているように見えます。

RL78では上記のような関数はリエントラントにはならないのでしょうか?

  • > RL78では上記のような関数はリエントラントにはならないのでしょうか?

    RL78 がコード生成をするわけではないので問い合わせ内容が意味を持ちません。
    使用されてるコンパイラやコンパイルオプション、_UBYTE等の定義内容等明らかでないと明確な回答は不能です。該当部分の逆アセンブルリストがあれば判断は早いと思います。
  • > この関数がメインと割り込みで競合した場合、

    割り込み処理が正しく実装されてるかも疑われるべきでしょう。
  • fujita nozomuさん

    返信ありがとうございます。
    統合開発環境はCS+V8.02、コンパイラ(CC-RL)はV1.08を使用しております。
    コンパイラオプションは
    ------ ビルド・オプション一覧開始(VCD-30G14, DefaultBuild) ------
    [共通オプションの設定状況]
    iodefine.h : C:\Program Files\Renesas Electronics\CS+\CC\Utilities\IOHeaderGenerator\df2iodef.exe "-df=C:\Program Files\Renesas Electronics\CS+\CC\Device\RL78\Devicefile\DR5F104LL.DVF" -o=C:\Users\user\Documents\VCD-30\20190910A_VCD-30G14\VCD-30G14\iodefine.h -f
    r_main.c r_systeminit.c r_cg_cgc.c N_LIB.C r_cg_cgc_user.c r_cg_port.c r_cg_port_user.c r_cg_serial.c r_cg_serial_user.c r_cg_adc.c r_cg_adc_user.c r_cg_it.c r_cg_it_user.c r_cg_timer.c r_cg_timer_user.c r_cg_wdt.c r_cg_wdt_user.c : C:\Program Files\Renesas Electronics\CS+\CC\CC-RL\V1.08.00\Bin\ccrl.exe r_main.c r_systeminit.c r_cg_cgc.c N_LIB.C r_cg_cgc_user.c r_cg_port.c r_cg_port_user.c r_cg_serial.c r_cg_serial_user.c r_cg_adc.c r_cg_adc_user.c r_cg_it.c r_cg_it_user.c r_cg_timer.c r_cg_timer_user.c r_cg_wdt.c r_cg_wdt_user.c -cpu=S3 -obj_path=DefaultBuild "-dev=C:\Program Files\Renesas Electronics\CS+\CC\Device\RL78\Devicefile\DR5F104LL.DVF" -g -g_line -Onothing -I . -memory_model=medium -refs_without_declaration -pack -volatile -switch=ifelse -c -exec_time=C:\Users\user\AppData\Local\Temp\CSPlusBuildTool_ea78e13467b14c2d895258da58960d06oru2tent.jak -msg_lang=japanese
    cstart.asm stkinit.asm : C:\Program Files\Renesas Electronics\CS+\CC\CC-RL\V1.08.00\Bin\ccrl.exe cstart.asm stkinit.asm -cpu=S3 -obj_path=DefaultBuild "-dev=C:\Program Files\Renesas Electronics\CS+\CC\Device\RL78\Devicefile\DR5F104LL.DVF" -g -c -exec_time=C:\Users\user\AppData\Local\Temp\CSPlusBuildTool_2994b33ca58d418c8e27e914d2fca88agu14jvhc.iw4 -msg_lang=japanese
    DefaultBuild\VCD-30G14.abs ..\ROM\VCD-30G14.mot : C:\Program Files\Renesas Electronics\CS+\CC\CC-RL\V1.08.00\Bin\rlink.exe -subcommand=DefaultBuild\VCD-30G14.clnk
    ------ ビルド・オプション一覧終了(エラー:0個, 警告:0個)(VCD-30G14, DefaultBuild) ------
    ========== 終了しました(成功:1プロジェクト, 失敗:0プロジェクト)(2020年4月1日 13:24:03) ==========


    逆アセンブルリストは

    void mmcopy( _UBYTE *d5, _UBYTE *s5, _UWORD n)

    _mmcopy:
    2008 SUBW SP,#8H
    b802 MOVW [SP+2H],AX
    13 MOVW AX,BC
    b806 MOVW [SP+6H],AX
    15 MOVW AX,DE
    b804 MOVW [SP+4H],AX
    f6 CLRW AX
    for(i=0;i<n;i++)

    b800 MOVW [SP+0H],AX
    ef12 BR $_mmcopy+0x21
    *(d5+i) = *(s5+i);

    a800 MOVW AX,[SP+0H]
    12 MOVW BC,AX
    a802 MOVW AX,[SP+2H]
    03 ADDW AX,BC
    16 MOVW HL,AX
    a806 MOVW AX,[SP+6H]
    03 ADDW AX,BC
    14 MOVW DE,AX
    89 MOV A,[DE]
    9b MOV [HL],A
    a800 MOVW AX,[SP+0H]
    a1 INCW AX
    b800 MOVW [SP+0H],AX
    for(i=0;i<n;i++)

    a804 MOVW AX,[SP+4H]
    12 MOVW BC,AX
    a800 MOVW AX,[SP+0H]
    43 CMPW AX,BC
    dce6 BC $_mmcopy+0xf
    }

    1008 ADDW SP,#8H
    d7 RET

    となります。

    _UBYTEの定義は

    typedef unsigned char _UBYTE;

    です。
  • _UWORDの定義は

    typedef unsigned short _UWORD;

    です。
  • fujita nozomuさん

    コメントありがとうございます。
    割り込み処理はA/D変換の割り込みで、コード生成ツールにより作成されたr_cg_adc_user.c内のr_adc_interrupt()関数内でユーザー定義関数を呼び出しております。

    static void __near r_adc_interrupt(void)

    _r_adc_interrupt@1:
    c1 PUSH AX
    c3 PUSH BC
    c5 PUSH DE
    c7 PUSH HL
    8efd MOV A,ES
    70 MOV X,A
    8efc MOV A,CS
    c1 PUSH AX
    ADCint( );

    fc918c00 CALL !!_ADCint
    c0 POP AX
    9efc MOV CS,A
    60 MOV A,X
    9efd MOV ES,A
    c6 POP HL
    c4 POP DE
    c2 POP BC
    c0 POP AX
    61fc RETI


    ネストが深く、長くなるのでADCintの中までは記載しませんが、上記でスタック退避していることから問題ないと考えております。
  • リエントラント性について問題はなく、割り込み関数も正常にコード化されているようですが、

    > RESF=10hのリセットが発生します。

    RESF の bit4 がセットされるのはウォッチドッグタイマによる内部リセットなので其方を疑うべきと思います。
    mmcopy() は最適化なしでコンパイルされており 1バイトの転送に 20クロックくらい要する実行効率の良くないコードとなっており、割り込み処理の中でどのような用途で使用されているのか分かりませんが、例えば A/D 変換で入力された値をバッファに格納する際、過去に貯めた値をがばっとブロック転送している場合などではバッファのサイズにより結構な処理時間を要してしまう可能性があり、それによりウォッチドッグを叩くタイミングに遅れてしまいリセットが掛かる、というような状況は普通に考えられるのではないかと思います。割り込み処理では重い処理はさせずに先の想定ではブロック転送を止めてリングバッファを導入する等対策が必要でしょう。
    ウォッチドッグタイマの設定やウォッチドッグの叩き方、割り込み処理で行っていることの内容等詳しい説明があればもう少し具体的な話に踏み込めるのではないかと思います。
  • fujita nozomuさん

    ご回答ありがとうございます。

    割り込み処理中のmmcopyはUARTポートに”:”を出力するために1byteのコピーで使用しております。
    A/D割り込みではR_ADC_StopとR_ADC_Get_Result_8bitでADCRHからデータを取得する処理を行っております。
    ウォッチドッグを叩くタイミングはメインループの先頭および中間に適度に叩くようにちりばめております。
    発生頻度も低く、2/28以降本日までに3/4、3/12の2回のみの発生となっております。それ以外にRESF=02H(IAWRF)のリセットも3/6、3/19に発生しており、この時のOCDトレースではmmcopyが正常終了した直後4ステップ程度に起きております。症例が少ないので何とも言えませんが、付近で発生しているのでmmcopyが疑わしいと思いました。ノイズ等H/Wに起因するものとの複合的な事象と推測しております。
  • ウォッチドッグタイマのオーバーフロー時間は136.53ms(2^11/fIL=15kHz)です。
    メインループ一周は8~24μs(オシロスコープにて実測)、A/D割り込み処理は最長5μsです。
  • ヒューリステックに話の流れを聞いていると、ノイズというよりもソフトのバグの可能性が高い感触ですね。
    特定の条件で暴走していそうです。
    いい機会なので根本原因を追えるといいですね。

  • Kirinさん

    コメントありがとうございます。
    特定の条件が発生するような外的なイベント要因はありません。
    ちなみにRESF=10h(WDTRF)は、E1エミュレータを接続した状態でのみ発生しております。
    現場で発生しているのはRESF=02H(IAWRF)で、最長で28日、最短で1時間30分で発生しております。
    定常状態の処理で何らかの割り込みのタイミングが重なることはあると思いますが、メインループが24μsで回っているものに対して、最長で28日間起きなかったため、1千億分の1の確率で発生する条件というのが考えられるでしょうか?割り込みはタイマー、A/D変換、UART受信を使用しております。
    ちなみに、静電気試験でリセットが発生することがありましたが、10kVとかなり高い電圧で、発生したときのRESFは80H、04H、02Hでした。