« Arduino デューティー計測のためのインプットキャプチャータイミング | トップページ | Arduino PWM波形のデューティー比測定 妥協点 »

2020年8月19日 (水)

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が重なってもちゃんと計測できた時。
A21

もうちょいOVF1が遅れると失敗。
A22

↓エッジへの切替が間に合わなくって、H区間の測定
ができなかった例です。

入力パルス周期とCNT1周期(4.096ms=約244Hz)との
重なり具合でOVF1がじゃまをするのです。

頻繁に発生するもんじゃないんで、この波形は
オシロスコープの組み合わせトリガー機能を使って
記録しました。
  ※ch1信号のHとch3信号のHをANDゲートして
   トリガー源に。


「ISR_NAKED」で見えるようになった割り込みへの応答。
これまでは、push命令に隠れてしまって本当の応答が見
えなかったわけで。
A23 
ジッターの周波数がざっと8MHz。
中心±16MHzということなんでしょうね。

|

« Arduino デューティー計測のためのインプットキャプチャータイミング | トップページ | Arduino PWM波形のデューティー比測定 妥協点 »

Arduino」カテゴリの記事

割り込み処理」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« Arduino デューティー計測のためのインプットキャプチャータイミング | トップページ | Arduino PWM波形のデューティー比測定 妥協点 »