Arduino デューティー計測のためのインプットキャプチャータイミング
2020年8月16日:Arduino UNOのPWM出力を(ちょっと精密に)確かめる
2020年8月16日:Arduino UNOのPWM出力を(ちょっと精密に)確かめる
の中の、デューティー計測回路。
これはタイマー1のインプットキャプチャー機能(日本語訳だと捕獲入力)
を使って実現しています。
ICP1入力のパルスエッジ↑↓を捉えて、↑パルスを検出した時は
「L区間のタイマー1カウント値」、↓パルスを検出した時は「H区間の
カウント値」として、内部クロック16MHzを数えます。
16bitカウンタですので65535が最大。
周波数約244Hz以下のパルスになるとこれがオーバーフロ-します。
そこで、タイマー1のオーバーフロー割り込みを使って、32bit値の
上位桁をカウントアップ。
これで、10Hzや1Hzなどの低周波パルスでもそのデューティが測定でき
ます。
問題は、デューティーが「0%」や「100%」に近づいた時。
0%や100%ならLかHに固定しちゃうんで、「パルス無し」なんですが、
例えば「analogWrite」のval値を1や254にしたような時に、
「16MHz/64 = 4us」のHあるいはLのパルスが出てきます。
これの検出がギリギリなんです。
その様子。
上が入力パルス。(このくらいだと十分間に合う)
真ん中がPB2に出力したICP1割り込みの実行時間。
下がPB3に出しているオーバーフロー割り込みの処理時間。
ポートを観察して見えるICP1割り込みの実行時間は6usほど。
しかし・・・パルスの↑↓エッジからPB2が現れるまで、2~3us
の時間がかかっています。
また、オーバーフロー割り込みが↑↓エッジの直前に入ると、
ICP割り込みの起動が遅れている様子が見えます。
この短パルス、もっと短くするとこうなってしまいます。
↑↓エッジの切替処理が間に合わなくなり、デューティーの
測定ができなくなってしまいます。
この遅れの原因が「C言語」特有の「レジスタの待避処理」。
割り込み処理が始まると、割り込みで使うレジスタを全部
プッシュします。
この手順が遅れの原因。
「C」で書いている割り込み処理はこんなの。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/***** タイマー1インプットキャプチャー割込 *****/
// ICP1の↓↑エッジでキャプチャー
ISR(TIMER1_CAPT_vect)
{
uint32_t cnt_d; // 差の計算用
word cnt_r; // ICR1読み出し
PB2_H; // (!!!)
cnt_r = ICR1; // キャプチャー値 ★1
XCG_EDGE1; // 次にそなえて↑↓エッジをトグル ★1
// オーバーフロー有無
if(CK_OVF1){ // 割込処理中にOVF発生したか? ★2
if(cnt_r < 160){ // 10uS(160ck)未満なら未処理のOVFがある
cnt1_ovf += 1; // オーバーフローカウンタ+1
CLR_OVF1; // オーバーフローフラグをクリア
}
}
// カウント差を計算
cnt1_n = (uint32_t)cnt_r +
((uint32_t)cnt1_ovf << 16); // 32bitでカウント値
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
f_plsin2 = 1; // min,maxチェック用
// 次の↑↓パルスが来てるかどうかのチェック
if(CK_ICF1) f_plsovl = 1; // パルスがオーバーラップ
PB2_L; // (!!!)
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
★1の処理をできるだけ前に持ってきたいのですが、展開された
機械語はこうなってしまいます。
=============================
356 <__vector_10>:
356: 1f 92 push r1
358: 0f 92 push r0
35a: 0f b6 in r0, 0x3f ;sreg
35c: 0f 92 push r0
35e: 11 24 eor r1, r1 ;△
360: 2f 93 push r18 ;△
362: 3f 93 push r19 ;△
364: 4f 93 push r20 ;△
366: 5f 93 push r21 ;△
368: 6f 93 push r22 ;△
36a: 7f 93 push r23 ;△
36c: 8f 93 push r24 ;△
36e: 9f 93 push r25 ;△
370: af 93 push r26 ;△
372: bf 93 push r27 ;△
374: 2a 9a sbi 0x05, 2 ;PB2
376: 20 91 86 00 lds r18, 0x0086 ;cnt_r = ICR1 ★1
37a: 30 91 87 00 lds r19, 0x0087
37e: 90 91 81 00 lds r25, 0x0081
382: 80 e4 ldi r24, 0x40 ;XCG_EDGE1 ★1
384: 89 27 eor r24, r25
386: 80 93 81 00 sts 0x0081, r24
38a: b0 9b sbis 0x16, 0 ;if(CK_OVF1) ★2
38c: 0e c0 rjmp .+28 ; 0x3aa
38e: 20 3a cpi r18, 0xA0 ;if(cnt_r < 160)
※長いので以下省略
=============================
★1の処理をできるだけ前に持ってきたいのです。
そうすれば、短いパルスもちゃんと処理できるようになります。
10個ある△の「push命令」。
命令実行の手順としては、これを★1より後に下げても同じ。
先にpushしてるr0とr1でもって処理できます。
アセンブラで書けば自由になるんですが、「Arduino」の環境だと
如何とも・・・
↑
ここらがhelp!でっす。
※豆知識
AVRマイコンの割り込み優先順序(同時に割り込み要因が起動し
た時、どっちが先に処理されるか)、割り込みベクトルの若い方
(先頭に近い方)が優先されます。
タイマーではオーバーフローより、コンペアマッチと
インプットキャプチャ-が優先されます。
リストの★、もう一つが★2。
これがオーバーフローの処理。
ICP割り込み処理の前にオーバーフローが発生し、その割り込み
処理が遅れても32bitのカウント値は正しく読めます。
※参考図
しかし、ICP割り込みとOVF割り込みが同時、あるいは微妙な
タイミングならどうかというのを考えたのがこの図です。
ICP割り込みで、
・OVF割り込みフラグが無ければクリチカルな問題は無し。
・処理されてないOVF割り込みフラグが残っていても、
その時のキャプチャーカウント値が十分に大きければ
クリチカルな問題じゃ無い。
・OVF割り込みフラグがあって、キャプチャーカウント値
が小さい時は、微妙なタイミングが発生してる。
その時は、ICP割り込み内でもオーバーフローの処理が
必要。
こんな処理がICP割り込み内に必要です。
でもこれは↑↓エッジ検出から遅れても問題なし。
短パルスを捉えるため、ICP割り込みでまず優先しなくちゃ
ならないのはキャプチャーカウンタの読み出しと↑↓エッジ
検出の逆転処理です。
※Arduino環境で機械語命令をどう書く、というのが課題・・・
※調べてたらこんなのが・・・
これで、解決できそうな。
ISR(TIMER1_CAPT_vect, ISR_NAKED)
ISR_NAKEDを入れると、割り込みルーチンのpush、pop、reti、
それにsregのセーブとリストアのルーチンが全部無くなります。
ISR_NAKEDを入れる前と入れた後を比較して、抜けてる
処理を手で(インラインアセンブラで)入れ込めば
解決(★1処理をちょっとでも速く)できるかっと。
こりゃ面白い!
| 固定リンク
「Help me! (助けて!)」カテゴリの記事
- 2.0mmピッチの電線対電線接続用コネクタ(2024.12.11)
- この「テープ」は何という名前?(2024.10.01)
- シリコン樹脂とリミットスイッチの接点(2024.09.26)
- 電動シャッターが動かない リモコン操作も手動スイッチもアウト(2024.08.09)
- このネジをゆるめるには?(2024.06.28)
「Arduino」カテゴリの記事
- Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMの例(2025.03.22)
- パルスジェネレータをI2C液晶で動かす(2025.01.28)
- EEPROMを使ったシリアル受信バッファ 512kバイトに増設(2024.12.26)
- 1/nカウント方式とDDS方式の2相パルス発生回路(2024.10.13)
- おっと。map関数の計算桁に注意(2024.10.06)
「割り込み処理」カテゴリの記事
- 1クロックでも速くしたい 割込を「ISR_NAKED」で(2024.09.30)
- 1クロックでも速くしたい DDS方式の2相パルス発生器(2024.09.27)
- 最適化処理のせいで悩んだぞ 呪文volatile再び(2024.06.06)
- I2C液晶のアクセス、割り込みで処理しないようにすると(2024.04.12)
- I2C液晶のアクセス、割り込み処理で遅れる原因らしきもの(2024.04.07)
コメント
「ISR_NAKED」、解説はあれこれ出てきますが、
「具体例」が少ないようでっす。
ちゃんと動かすまで、ちょい待って。
投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年8月18日 (火) 20時28分