はじめまして。よろしくお願い致します。
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
・未使用
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.pdfFAQContent Under Reviewとなるのを避けるため略純正コンパイラでのアプリケーションノート例H8/300H Tiny シリーズ内部割り込みによる多重割り込み動作H8/300H Tiny シリーズオートリロードタイマ機能による割り込み周期設定16ビットフリーランニング機能による割り込み回数のカウントGCCでのウェブ上での入門記事例Content Under Reviewとなるのを避けるためURLを略イチから作って丸ごと学ぶ! H8マイコン道 - MONOistH8で学ぶマイコン開発入門 - MONOist
> 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; です。
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 の割り込みフラグをリセットすることがなければ問題にならないとは思いますが、応用の利かない方法を紹介するのは入門記事としては宜しくない感じですね。
リカルドさんwrote: said:なんだ、マニュアルを見れば簡単。...略... リセットしたいビットだけ0にして書き込めばよい。[引用終]
> IRQ0 割り込み要求フラグ> [セット条件]> IRQ0 端子が割り込み入力に設定され、指定されたエッジを検出したとき> [クリア条件]> 0 をライトしたとき
1 をライトしたときセットされないかは要確認と思いますが、大丈夫であれば
#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
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命令で行ってください。ビット操作命令では設定値の変更ができません。
と注意書きがあるものもありますが、ビット操作命令で安全に書き換えができるかも明記して欲しい気はしますね。