PIC版シャッターテスタ (6) 正確な割込みクロック

前回の精度の話で、計測の分解能は8μsと記した。それでは、正確な8μsは、どのように実現すればよいのだろう。

ロジック上は、一定間隔毎に割込みをかけ、割込みの回数をカウントすることでシャッターの開時間を計測している。割込みが正確な間隔でかからなければ計測値の意味も損なわれることとなり、プログラムの心臓部と言える部分である。

PICのタイマ割込みは、タイマレジスタが満了して0に戻る際に割込みが発生する。前の割込みが発生してから次の割込みが発生するまでを正確に8μsに調整しなければならない。

タイマ割込みでは、タイマの初期値を設定し、そこから定間隔でカウントアップを開始する。カウントアップはプログラムで行うのではなく、設定条件に従ってCPUの中で自動的に実行される。そして、カウンタのビットがフルになり0に戻った瞬間に割込みが発生する。

warikomi01

タイマ初期値の設定は、プログラムに記述する処理内容に応じ前後に移動する。どのような場合でも、割込みが発生してからタイマ初期値設定処理の前にかかる時間(Xμs)だけ差し引いた(8-X)μsを計測する値をタイマの初期値として設定しなければならない。

ところが、CのプログラムソースではXμsを正確に知ることはできない。なぜなら、命令時間が明らかになっているのはアセンブラ命令についてであり、コンパイルする前のCのプログラムでは計算できないのである。

そこで、PICの開発環境であるMPLABXで、
プロジェクトディレクトリdistdefaultproduction
にある
プロジェクト名.lst
というファイルに含まれるアセンブルリストでコンパイル後のアセンブラプログラムから処理時間を計算しなければならない。

PICは、ほとんどの命令は、4クロック(=1サイクル)で実行される。たとえば、CPUクロックが4MHzの場合、1命令は1μsで実行される。例外として条件分岐やジャンプにかかわる命令は2サイクルが必要となる。

また、タイマに初期値がセットされると、書込み直後の2サイクルはカウントアップが停止する等、データシートを注意深く読まなければ正確な初期値を算出することができない。

机上で正しい初期値を計算するのは、実は、結構大変だ。そこで、割込みのサイクルに同期させてLEDを点滅するようなプログラムをテスト用に作り、オシロスコープでLEDの点滅周期を測定して初期値を調整するといったことが可能になる。しかし、オシロを所有していないとそういう離れ業が使えないため、地道にアセンブルコードを見ながら計算しなければならない。

例えば、シャッターテスタの割込み処理ルーチンを以下に示すが、赤字のところがチェック対象となる。

/*#################### 割込みハンドラ #######################
*/
void interrupt handler( void ){
if(IOCAF){                 // デジタルポート状態変化割込み
if(!TMR0IE){                  // 初めてのフォトトラ割込なら
TMR0=TMR0_INIT2;              // 次の割込まで8us(TMR0_INITより11クロック短く)
TMR0IE=1;                     // TMR0割込開始
}
}
if(TMR0IE&&TMR0IF) {            // 4,3TMR0割込み(This17+Aft7=Total24)
    TMR0=TMR0_INIT;                   // 次の割込まで8us
// LED点滅
if(RA0) RA0=0;
else RA0=1;
time_count++;                     // 4:計測カウンタアップ
if(time_count==0xFFFF){           // 6,5:タイムアウトカウンタ満了なら
TMR0IE=0;                       // 1:TMR0割込禁止
stage=FINISH;                   // 4:計測タイムアウト発生
}
TMR0IF=0;                         // 1:割込みフラグクリア
}                                   // 2:GOTO Return
GIE=1;                              // 1:割込み許可
}                                     // 6:return処理(レジスタ復帰等)

これに対応するコンパイル後のアセンブラプログラム

3393 ;; *************** function _handler *****************
3394 ;; Defined at:
3395 ;;  line 165 in file “main.c”
3396 ;; Parameters:    Size  Location     Type
3397 ;;  None
3398 ;; Auto vars:     Size  Location     Type
3399 ;;  None
3400 ;; Return value:  Size  Location     Type
3401 ;;  None               void
3402 ;; Registers used:
3403 ;;  wreg, fsr0l, fsr0h, fsr1l, fsr1h, status,2, status,0, pclath, cstack
3404 ;; Tracked objects:
3405 ;;  On entry : 0/0
3406 ;;  On exit  : 0/0
3407 ;;  Unchanged: 0/0
3408 ;; Data sizes:     COMMON   BANK0   BANK1
3409 ;;      Params:         0       0       0
3410 ;;      Locals:         0       0       0
3411 ;;      Temps:          0       3       0
3412 ;;      Totals:         0       3       0
3413 ;;Total ram usage:        3 bytes
3414 ;; Hardware stack levels used:    1
3415 ;; Hardware stack levels required when called:    5
3416 ;; This function calls:
3417 ;;  _to_sleep_mode
3418 ;; This function is called by:
3419 ;;  Interrupt level 1
3420 ;; This function uses a non-reentrant model
3421 ;;
3422
3423  0004                     _handler:
3424
3425                           ;incstack = 0
3426                           ; Regs used in _handler: [wreg-fsr1h+status,2+status,0+pclath+cstack]
3427  0004  147E                bsf 126,0 ;set compiler interrupt flag
3428  0005  3180                pagesel $
3429  0006  0020                movlb 0 ; select bank0
3430  0007  087F                movf 127,w
3431  0008  00A5                movwf ??_handler+2
3432
3433                           ;main.c: 171: if(IOCAF){
3434  0009  0027                movlb 7 ; select bank7
3435  000A  0813                movf 19,w ;volatile
3436  000B  1903                btfsc 3,2
3437  000C  28B4                goto i1l1825
3438
3439                           ;main.c: 172: if(!TMR0IE){
3440  000D  1A8B                btfsc 11,5 ;volatile
3441  000E  2813                goto i1l1747
3442
3443                           ;main.c: 173: TMR0=206;
  3444  000F  30CE                movlw 206
  3445  0010  0020                movlb 0 ; select bank0
  3446  0011  0095                movwf 21 ;volatile
3447
3448                           ;main.c: 174: TMR0IE=1;
3449  0012  168B                bsf 11,5 ;volatile
3450  0013                     i1l1747:
3451
3452                           ;main.c: 175: }

3737                           ;main.c: 236: if(TMR0IE&&TMR0IF) {
3738  00B4  1A8B                btfsc 11,5 ;volatile
3739  00B5  1D0B                btfss 11,2 ;volatile
3740  00B6  28C9                goto i1l1837
3741
3742                           ;main.c: 237: TMR0=206;
  3743  00B7  30CE                movlw 206
  3744  00B8  0020                movlb 0 ; select bank0
  3745  00B9  0095                movwf 21 ;volatile
3746
3747                           ;main.c: 238: time_count++;
3748  00BA  3001                movlw 1
3749  00BB  07D2                addwf _time_count,f
3750  00BC  3000                movlw 0
3751  00BD  3DD3                addwfc _time_count+1,f
3752
3753                           ;main.c: 239: if(time_count==0xFFFF){
3754  00BE  30FF                movlw 255
3755  00BF  0653                xorwf _time_count+1,w
3756  00C0  1D03                skipz
3757  00C1  28C4                goto u134_25
3758  00C2  30FF                movlw 255
3759  00C3  0652                xorwf _time_count,w
3760  00C4                     u134_25:
3761  00C4  1D03                skipz
3762  00C5  28C8                goto i1l1835
3763
3764                           ;main.c: 240: TMR0IE=0;
3765  00C6  128B                bcf 11,5 ;volatile
3766
3767                           ;main.c: 241: stage=0;
3768  00C7  01DF                clrf _stage
3769  00C8                     i1l1835:
3770
3771                           ;main.c: 242: }
3772                           ;main.c: 243: TMR0IF=0;
3773  00C8  110B                bcf 11,2 ;volatile
3774  00C9                     i1l1837:
3775
3776                           ;main.c: 244: }

3805                           ;main.c: 253: GIE=1;
3806  00D7  178B                bsf 11,7 ;volatile
3807  00D8  0825                movf ??_handler+2,w
3808  00D9  00FF                movwf 127
3809  00DA  107E                bcf 126,0 ;clear compiler interrupt flag
3810  00DB  0009                retfie
3811  00DC                     __end_of_handler:

今回は、ソフトの底辺の制御方法に関するさわりの解説となり、ハードルが高かったかもしれないが、厳密な精度を求めるような機器の開発の場合に必要となるテクニックとして紹介した。

前回へ  次回へ

(Visited 1,280 times, 1 visits today)
スポンサーリンク

シェアする

フォローする