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! (助けて!)」カテゴリの記事
- 「アラルダイト」が無い!(2023.12.05)
- 2つあるワンショットマルチの時定数比を一定にしたい(2023.10.21)
- TRWの16pin DIP IC「8543」 これは何?(2023.10.06)
- 入力セレクタ+VR+トーンコントロール用IC、何かないかな?(2023.10.02)
- 電磁石の接触面の状態で保持力が変わるの?(2023.09.28)
「Arduino」カテゴリの記事
- Arduinoで「ボコスカハンマー」 あれれれれっ?!(2023.12.07)
- 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)
「割り込み処理」カテゴリの記事
- 初めて買ったArduino UNO・・・今は(2023.05.25)
- 8ビットマイコンの割り込み処理・・・1バイトに収まるなら1バイトに(2023.03.01)
- 8bitマイコンにも16bitのメモリ読み書き命令があった(2022.10.14)
- 何度も言うぞ! Arduino(8bitマイコン)の割り込みには気をつけろ!(2022.10.11)
- ロータリーエンコーダーのチャタリング波形(2022.09.11)
コメント
「ISR_NAKED」、解説はあれこれ出てきますが、
「具体例」が少ないようでっす。
ちゃんと動かすまで、ちょい待って。
投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年8月18日 (火) 20時28分