Arduino インプットキャプチャー割り込みを「ISR_NAKED」で (デューティー比測定)
2020年8月18日:Arduino デューティー計測のためのインプットキャプチャータイミング
これの「ISR_NAKED」による高速化、こんなコードでやってみました。
SBI、CBI命令を先頭と尻尾に持ってこれたので、
割り込みタイミングが鮮明になりました。 ★1
※これまではpush、popに隠れていた。
で、結果ですが↑↓エッジ間が42クロックくらいまでは
ミスなく取り込めるようになりました。 ★2、★3
これまで、64クロックがギリギリだったのを思えば、
ちょいと進歩です。
※タイミングなどはまた今度に
/***** タイマー1インプットキャプチャー割込 *****/
// ICP1の↓↑エッジでキャプチャー
// "ISR_NAKED"指定でpush,pop,reti,sreg処理を無しに
ISR(TIMER1_CAPT_vect, ISR_NAKED)
{
// PB2_H; // (!!!)
// cnt_r = ICR1; // キャプチャー値
// XCG_EDGE1; // 次にそなえて↑↓エッジをトグル
asm volatile(
" sbi 0x05, 2 \n" // PB2 H ★1
" push r18 \n"
" push r19 \n"
" lds r18, 0x0086 \n" // ICR1 ★2
" lds r19, 0x0087 \n"
" sts cnt_r , r18 \n"
" sts cnt_r + 1 , r19 \n"
" in r18, __SREG__ \n"
" push r18 \n"
" lds r19, 0x0081 \n" // TCCR1B ★3
" ldi r18, 0x40 \n"
" eor r18, r19 \n"
" sts 0x0081, r18 \n"
" push r0 \n"
" push r1 \n"
" eor r1, r1 \n"
" push r20 \n"
" push r21 \n"
" push r22 \n"
" push r23 \n"
" push r24 \n"
" push r25 \n"
" push r26 \n"
" push r27 \n"
);
// オーバーフロー有無
if(CK_OVF1){ // 割込処理中にOVF発生したか?
if(cnt_r < 160){ // 10uS(160ck)未満なら未処理のOVFがある
cnt1_ovf += 1; // オーバーフローカウンタ+1
CLR_OVF1; // オーバーフローフラグをクリア
}
}
// カウント差を計算
cnt1_n = (uint32_t)cnt_r + // 32bitでカウント値
((uint32_t)cnt1_ovf << 16);
cnt_d = cnt1_n - cnt1_x; // 前回値との差分
cnt1_x = cnt1_n; // 次回用に残す
// ↑↓エッジをチェック
if(CK_EDGE1){ // ↑になった H区間
cnt1_caph = cnt_d;
}
else{ // ↓になった L区間
cnt1_capl = cnt_d;
}
f_plsin = 1; // パルス有フラグをon
// PB2_L; // (!!!)
// "ISR_NAKED"復元
asm volatile(
" pop r27 \n"
" pop r26 \n"
" pop r25 \n"
" pop r24 \n"
" pop r23 \n"
" pop r22 \n"
" pop r21 \n"
" pop r20 \n"
" pop r1 \n"
" pop r0 \n"
" pop r18 \n"
" out __SREG__, r18 \n"
" pop r19 \n"
" pop r18 \n"
" cbi 0x05, 2 \n" // PB2 L ★1
" reti \n"
);
}
※豆知識
・I/Oポートをビット操作するSBI、CBI命令ではフラグは変化しない。
だもんでsregは変化しない。
・AVRマイコンには8bitレジスターが32個あるんだけれど、
レジスターr0~r15はイミディエート命令が使えないのだ。
LDIやANDI、ORIのような即値が扱えるのはr16~r31の
16個だけ。
※追実験
ICR1レジスタ(インプットキャプチャー)を先に読むより、
↑↓クロックエッジを切り替える処理を先に持ってくる方が
良さそうです。★4
こんな具合。
※「asm volatile(」も「__asm__ volatile(」にしました。
ISR(TIMER1_CAPT_vect, ISR_NAKED)
{
// PB2_H; // (!!!)
// XCG_EDGE1; //★4 次にそなえて↑↓エッジをトグル
// cnt_r = ICR1; // キャプチャー値
__asm__ volatile(
" sbi 0x05, 2 \n" // PB2 H
" push r18 \n"
" push r19 \n"
" in r18, __SREG__ \n"
" push r18 \n"
" lds r19, 0x0081 \n" // TCCR1B ★4
" ldi r18, 0x40 \n"
" eor r18, r19 \n"
" sts 0x0081, r18 \n"
" lds r18, 0x0086 \n" // ICR1
" lds r19, 0x0087 \n"
" sts cnt_r , r18 \n"
" sts cnt_r + 1 , r19 \n"
" push r0 \n"
" push r1 \n"
" eor r1, r1 \n"
" push r20 \n"
" push r21 \n"
これで「32クロック = 2us」のパルスを読めています。
読みが遅れても、直前の↑↓でキャプチャされた値が出て
くるので、うまく行ってる感じかなぁ。
※オーバーフロー割り込みと重なると・・・
やっぱ、カウントミスが出ます。
クロックが短くなり、ミスカウントし出すとデューティが
ほぼ50%の値になり周波数が半分になってしまいます。
短クロックは検出しているんですが、
「倍の周期でH/Lする方形波」
としてとらえているのでしょう。
※ICP1割り込みをOVF1割り込みがじゃまする様子
OVF1が重なってもちゃんと計測できた時。
もうちょいOVF1が遅れると失敗。
↓エッジへの切替が間に合わなくって、H区間の測定
ができなかった例です。
入力パルス周期とCNT1周期(4.096ms=約244Hz)との
重なり具合でOVF1がじゃまをするのです。
頻繁に発生するもんじゃないんで、この波形は
オシロスコープの組み合わせトリガー機能を使って
記録しました。
※ch1信号のHとch3信号のHをANDゲートして
トリガー源に。
「ISR_NAKED」で見えるようになった割り込みへの応答。
これまでは、push命令に隠れてしまって本当の応答が見
えなかったわけで。
ジッターの周波数がざっと8MHz。
中心±16MHzということなんでしょうね。
| 固定リンク
「Arduino」カテゴリの記事
- Arduino UNO R3で±19.9V表示電圧計(2023.10.14)
- 「御詠歌プレーヤー」の製作 (MP3-TF-16Pモジュールの使用例)(2023.08.10)
- Arduino UNO R3のソケット・・思えば違和感がぁ(2023.07.07)
- 初めて買ったArduino UNO・・・今は(2023.05.25)
- 液晶表示コントローラ HD44780で迎撃(2023.05.16)
「割り込み処理」カテゴリの記事
- 初めて買ったArduino UNO・・・今は(2023.05.25)
- 8ビットマイコンの割り込み処理・・・1バイトに収まるなら1バイトに(2023.03.01)
- 8bitマイコンにも16bitのメモリ読み書き命令があった(2022.10.14)
- 何度も言うぞ! Arduino(8bitマイコン)の割り込みには気をつけろ!(2022.10.11)
- ロータリーエンコーダーのチャタリング波形(2022.09.11)
コメント