H8/36094:IRQ0の処理が起動しないことがある

はじめまして。よろしくお願い致します。

H8/36094を以下のクロック、割込を使用して動かしているのですが、IRQ0の処理がたまに(1,000回に1回くらい)起動しないことがあります。

これは、プログラムでIRQ0の処理の入り口でP81=L、出口でP81=Hとし、オシロでIRQ0とP81を観測することで確認しております。

試しにTimerAの割込周期を約50msecにしたところ、上記の現象は100,000回に1回程度になったのでTimerAが影響しているのだろうとは思いますが、どうしてこうなるのか分かりません。

プログラム中では初期設定以外でIENR1やIビットの操作はしていません。

解決のために何をチェックすればよろしいでしょうか。ご教示いただけるとありがたいです。

 

CPUクロック

・オンチップオシレータ 10MHzで動作

IRQ0

・割込周期:約50msec、立下りエッジ検出、Lowレベル:約2msec、処理時間:50usec以下

TimerA

・割込周期:819.2usec、処理時間:50usec以下

ADC

・割込周期:50msecごと、処理時間:50usec以下

WDT

・未使用

  • CPUによって割り込み要因のフラグをユーザがリセットするものが有ります。
     また、自動的にリセットしてくれる物も有ります。
     自分の過去のH8/3052 のプログラムには、次のように書いてありました。
     
    ISR.BIT.IRQ0F = 0 ; /* 割り込みフラグをクリア */
     
     C言語のビット操作命令を使えば良いんじゃないんですか。
  • こんにちは、

    以下の様なFAQを見つけました。
    support.renesas.com/.../217386268
    H8/300H Super Low Powerですが、ビット操作命令実行中に割り込みフラグがセットされてもクリアされない論理となっているようです。
    おそらくH8/36094も同様の論理となっているのではないでしょうか?
  • SAさん、チョコさん、ありがとうございます。(すみません。追記したら Content Under Review となる投稿になった為、追記を減らして再度投稿します。)

    H8/300H Super Low PowerのFAQにあったのですね。H8_300Hファミリ、H8_TINYファミリ、H8ファミリのFAQは見たのですが、まさに読み飛ばしたところにあったとは、、、

    ちなみに、H8/36094のハードウェアマニュアルや上記のFAQ、純正コンパイラでのアプリケーションノートで割り込みを使っていそうな幾つかの例、さらに、GCCでのウェブ上の入門記事、とか見てみたのですが、割り込み処理中というか正確には割り込みディセーブル中でも割り込み要求フラグのクリアにビット操作命令を使うように、とのアドバイスは見付けられなかったです。

    せっかく調べたので、あとで画面コピーとかURLとか追記しようかと思っています。 → 追記しました。

    [追記]

    RL78/G13のハードウェアマニュアルには以下の記載がありました。

    www.renesas.com/ja-jp/doc/products/mpumcu/doc/rl78/r01uh0146jj0330_rl78g13.pdf


    他方、H8/36094では先ほど書いたドキュメントには、そのような記載は見つけられなかったです。

    ハードウェアマニュアル

    H8/36094 グループ ハードウェアマニュアル
    ルネサス16ビットシングルチップマイクロコンピュータ H8ファミリ/ H8/300H Tiny シリーズ
    www.renesas.com/ja-jp/doc/products/mpumcu/002/rjj09b0278_h836094hm.pdf




    FAQ

    Content Under Reviewとなるのを避けるため略

    純正コンパイラでのアプリケーションノート例

    H8/300H Tiny シリーズ
    内部割り込みによる多重割り込み動作

    H8/300H Tiny シリーズ
    オートリロードタイマ機能による割り込み周期設定

    16ビットフリーランニング機能による
    割り込み回数のカウント

    GCCでのウェブ上での入門記事例

    Content Under Reviewとなるのを避けるためURLを略

    イチから作って丸ごと学ぶ! H8マイコン道 - MONOist

    H8で学ぶマイコン開発入門 - MONOist

  • みなさま
    ありがとうございます。
    大変参考になりました。
    割込要求フラグをBCLR命令1回でクリアするようにしてからは不具合は発生しておりません。
    RL78のようにハードウェアマニュアルに説明があれば・・・とも思いましたが甘えすぎでしょうか。
    今後ともよろしくお願い致します。
  • > ISR.BIT.IRQ0F = 0 ; /* 割り込みフラグをクリア */
    > 
    >  C言語のビット操作命令を使えば良いんじゃないんですか。

    High-performance Embedded Workshop Upgrade 4.09.01

    C/C++ compiler package for the H8, H8S, and H8SX family V.7.00 Release 00

    で確認してみましたが

    #include "iodefine.h"
    
    __interrupt(vect=19) void INT_TimerA(void)
    {
        IRR1.BIT.IRRTA = 0;
    }
    

    ↑ が

    最適化ありサイズ優先

    0802 7FF67260     _INT_TimerA      BCLR      #6,@H'FFFFF6:8
    0806 5670                          RTE       
    

    最適化なし(-optimize=0)

    0808 6DF6         _INT_TimerA      MOV.W     R6,@-ER7
    080A 0D76                          MOV.W     R7,R6
    080C 7FF67260                      BCLR      #6,@H'FFFFF6:8
    0810 6D76                          MOV.W     @ER7+,R6
    0812 5670                          RTE       
    

    というコードとなりました。純正のコンパイラだけあって効率の良いコードを出力するようで、割り込みフラグのクリアは最適なしの設定でも適切な 1命令で行われます。

    同様のことを GNUH8 v12.02 Windows Toolchain (ELF) で試したところ

    $ cat -n hoge.c
         1  #include "iodefine.h"
         2
         3  void INT_TimerA(void) __attribute__((interrupt_handler));
         4  void INT_TimerA(void)
         5  {
         6      IRR1.BIT.IRRTA = 0;
         7  }
    
    $ h8300-elf-gcc -Wall -W -mh -mn -O2 -fomit-frame-pointer -c hoge.c && h8300-elf-objdump -d hoge.o
    
    hoge.o:     file format elf32-h8300
    
    
    Disassembly of section .text:
    
    00000000 <_INT_TimerA>:
       0:   01 00 6d f2     mov.l   er2,@-er7
       4:   01 00 6d f3     mov.l   er3,@-er7
       8:   79 02 ff f6     mov.w   #0xfff6,r2
       c:   68 2b           mov.b   @er2,r3l
       e:   72 6b           bclr    #0x6,r3l
      10:   68 ab           mov.b   r3l,@er2
      12:   01 00 6d 73     mov.l   @er7+,er3
      16:   01 00 6d 72     mov.l   @er7+,er2
      1a:   56 70           rte
    
    $
    

    1命令で割り込みフラグをクリアしてくれず先の問題が出ると思われます。

    gcc の場合はインラインアセンブラを使う他ないのかな?

    $ cat -n hoge.c
         1  #define IRR1 ((volatile unsigned char*)0xfff6)
         2  #define IRRTA 0b01000000
         3
         4  void INT_TimerA(void) __attribute__((interrupt_handler));
         5  void INT_TimerA(void)
         6  {
         7      __asm __volatile(
         8          "bclr %0, @%a1:8 \n"
         9          :
        10          : "i"(__builtin_ctz(IRRTA)), "i"(IRR1)
        11      );
        12  }
    
    $ h8300-elf-gcc -Wall -W -mh -mn -O2 -fomit-frame-pointer -c hoge.c && h8300-elf-objdump -d hoge.o
    
    hoge.o:     file format elf32-h8300
    
    
    Disassembly of section .text:
    
    00000000 <_INT_TimerA>:
       0:   7f f6 72 60     bclr    #0x6,@0xf6:8
       4:   56 70           rte
    
    $
    
  • イチから作って丸ごと学ぶ! H8マイコン道(10):
    割り込みテクニックでタイマを使おう (2/3)

     IRRTAフラグは、タイマカウンタがオーバフローすると「1」にセットされますが、IRRTAフラグを解除するのはプログラムの仕事です。その方法はC言語で、
        IRR1 &= ~IRRTA; 
    
    です。

    イチから作って丸ごと学ぶ! H8マイコン道(11):
    周期イベントでLEDのダイナミック点灯を! (3/3)

    #include "h8tiny.h"
     
    void int_tima(void) __attribute__((interrupt_handler));
    void int_timv(void) __attribute__((interrupt_handler));
     
    extern int count1, count10;
     
    void int_tima(void)
    {
        IRR1 &= ~IRRTA;
        if (count1 < 9)
            count1++;
        else {
            count1 = 0;
            if (count10 < 9)
                count10++;
            else
                count10 = 0;
        }
    }
    

    他の割り込みで IRR1 の割り込みフラグをリセットすることがなければ問題にならないとは思いますが、応用の利かない方法を紹介するのは入門記事としては宜しくない感じですね。

  • 投稿したのに何度も失敗で書き直しです。だから簡単に書きます。
     
    なんだ、マニュアルを見れば簡単。
    IRR1レジスタの説明は次のようになっています。
    リセットしたいビットだけ0にして書き込めばよい。
     
    IRQ0 割り込み要求フラグ
    [セット条件]
    IRQ0 端子が割り込み入力に設定され、指定されたエッジを検出したとき
    [クリア条件]
    0 をライトしたとき
  • リカルドさんwrote: said:
    なんだ、マニュアルを見れば簡単。
    ...略...
    リセットしたいビットだけ0にして書き込めばよい。[引用終]

    ああ、なるほど!! 1は書かれないということですね。コロンブスの卵ですね。

  • > IRQ0 割り込み要求フラグ
    > [セット条件]
    > IRQ0 端子が割り込み入力に設定され、指定されたエッジを検出したとき
    > [クリア条件]
    > 0 をライトしたとき

    1 をライトしたときセットされないかは要確認と思いますが、大丈夫であれば 

    C/C++ compiler package for the H8, H8S, and H8SX family V.7.00 Release 00

    #include "iodefine.h"
    
    __interrupt(vect=19) void INT_TimerA(void)
    {
        union un_irr1 irr1 = {~0};
        irr1.BIT.IRRTA = 0;
        IRR1 = irr1;
    }

    最適化ありサイズ優先

    0802 6DF0         _INT_TimerA      MOV.W     R0,@-ER7
    0804 F8FF                          MOV.B     #H'FF,R0L
    0806 7268                          BCLR.B    #6,R0L
    0808 38F6                          MOV.B     R0L,@H'FFFFF6:8
    080A 6D70                          MOV.W     @ER7+,R0
    080C 5670                          RTE       
    

    最適化なし(-optimize=0)

    0808 6DF6         _INT_TimerA      MOV.W     R6,@-ER7
    080A 0D76                          MOV.W     R7,R6
    080C 6DF0                          MOV.W     R0,@-ER7
    080E 1B87                          SUBS.L    #2,ER7
    0810 F8FF                          MOV.B     #H'FF,R0L
    0812 6EE8FFFD                      MOV.B     R0L,@(H'FFFD:16,ER6)
    0816 0D60                          MOV.W     R6,R0
    0818 7910FFFD                      ADD.W     #H'FFFD,R0
    081C 7D007260                      BCLR      #6,@ER0
    0820 6E68FFFD                      MOV.B     @(H'FFFD:16,ER6),R0L
    0824 38F6                          MOV.B     R0L,@H'FFFFF6:8
    0826 0B87                          ADDS.L    #2,ER7
    0828 6D70                          MOV.W     @ER7+,R0
    082A 6D76                          MOV.W     @ER7+,R6
    082C 5670                          RTE       
    

    GNUH8 v12.02 Windows Toolchain (ELF) 

    $ cat -n hoge.c
         1  #include "iodefine.h"
         2
         3  void INT_TimerA(void) __attribute__((interrupt_handler));
         4  void INT_TimerA(void)
         5  {
         6      union un_irr1 irr1 = {~0};
         7      irr1.BIT.IRRTA = 0;
         8      IRR1 = irr1;
         9  }
    
    $ h8300-elf-gcc -Wall -W -mh -mn -O2 -x c -fomit-frame-pointer -c hoge.c && h8300-elf-objdump -d hoge.o
    
    hoge.o:     file format elf32-h8300
    
    
    Disassembly of section .text:
    
    00000000 <_INT_TimerA>:
       0:   01 00 6d f2     mov.l   er2,@-er7
       4:   fa bf           mov.b   #0xbf,r2l
       6:   3a f6           mov.b   r2l,@0xf6:8
       8:   01 00 6d 72     mov.l   @er7+,er2
       c:   56 70           rte
    
    $
    

    ちょっと記述は煩いものゝ共通の書き方ができて良い感じですね。

    GCC では C99 が使えるのでも少し簡潔な書き方もできるのですが純正のコンパイラは C99 の対応は無いようで残念。 

    $ cat -n hoge.c
         1  #include "iodefine.h"
         2
         3  void INT_TimerA(void) __attribute__((interrupt_handler));
         4  void INT_TimerA(void)
         5  {
         6      union un_irr1 irr1 = {.BIT.IRRTA = 1};
         7      IRR1.BYTE = ~irr1.BYTE;
         8  }
    
    $ h8300-elf-gcc -std=c99 -Wall -W -Wno-missing-field-initializers -mh -mn -O2 -x c -fomit-frame-pointer -c hoge.c && h8300-elf-objdump -d hoge.o
    
    hoge.o:     file format elf32-h8300
    
    
    Disassembly of section .text:
    
    00000000 <_INT_TimerA>:
       0:   01 00 6d f2     mov.l   er2,@-er7
       4:   fa bf           mov.b   #0xbf,r2l
       6:   3a f6           mov.b   r2l,@0xf6:8
       8:   01 00 6d 72     mov.l   @er7+,er2
       c:   56 70           rte
    
    $
    
  • > RL78のようにハードウェアマニュアルに説明があれば・・・とも思いましたが甘えすぎでしょうか。

    ハードウェアマニュアルにはレジスタに拠っては

    5.2.2 RCトリミングデータプロテクトレジスタ(RCTRMDPR)
    RCTRMDPRはRCTRMDPR自身とRCTRMDRの書き込み制御を行うレジスタです。本レジスタの書き換えはMOV命令で行ってください。ビット操作命令では設定値の変更ができません。

     

    13.2.1 タイマコントロール/ステータスレジスタWD(TCSRWD)
    TCSRWDはTCSRWD自身とTCWDの書き込み制御を行うレジスタです。また、ウォッチドッグタイマの動作制御と動作状態を示す機能も持っています。本レジスタの書き換えはMOV命令で行ってください。ビット操作命令では設定値の変更ができません。

    と注意書きがあるものもありますが、ビット操作命令で安全に書き換えができるかも明記して欲しい気はしますね。