目次
前
次
タイマー割込み
タイマー割込みを利用する場合、4つあるタイマーが
どういう動きをするのかを理解しなくてはなりません。
アドレスマップを見て、各タイマーの動作を
レジスタから理解します。
リセット時の16進コードから、各タイマーの
ビットサイズは、次のようになります。
- timer0 16 bits
- timer1 32 bits
- timer2 32 bits
- timer3 16 bits
3つのタイマーには、汎用のタイマーの他に
AnalogDevicesが決めた使ってほしい機能の
名称が付けられています。
- timer0 (RTOS) timer
- timer2 (Wake-up) timer
- timer3 (Watchdog) timer
各タイマーのレジスタには、LD、VAL、CON、CLRIが
共通であります。
これらのレジスタの機能は以下です。
- LD 再設定カウント値
- VAL カウント値
- CON 動作設定
- CLRI 割込フラグ
レジスタCONに、動作モードを設定します。
CONに設定する内容は、以下です。
- 利用クロックの選択
- プリスケーラ分周比設定
- 割込み動作
CONで指定する動作は、どういうことを
やりたいかで決まりますが、次の原則は
忘れてはいけないでしょう。
タイマーは、通常はダウンカウンタ処理。
VALの値を参照することで、経過時間を知る
ことができますが、ポーリングでは、値参照
にかかり切りになるので、割込みを使って
通知してもらうように設定するのが定石です。
各タイマーの動作を見てみます。
timer0(RTOS)動作
timer0のブロック図は、以下。
ブロック図から読み取れることをリスト。
- timer0(RTOS)のクロックは、HCLKのみ利用可能
- プリスケーラ分周比は、1:1、1:16、1:256
- タイマーとしての割込みはTIMER0 IRQ
- A/Dコンバータに関連した割込みも兼用
これらの動作モードを設定するには、T0CONレジスタ
に与えるパラメータを組合わせます。
レジスタのビット構成から、次の内容を読み取れます。
- timer0モジュールを使うには、7ビット目を1に設定する
- 周期動作をさせるとき、6ビット目を1に設定する
- プリスケーラ分周比は、3ビット目と2ビット目の組合せで設定
周期動作は、ダウンカウントして値が0になった時
レジスタLDの設定値を、カウンタにロードさせて
ダウンカウントを継続すると設定可能。
カウント値が0になったことを、割込みで通知して
もらうと、様々な処理を1つのコンピュータで実現
できます。割込み指定は、タイマーカウンタでは
なく、IRQモジュールのレジスタに設定です。
IRQENレジスタのTimer0ビットに1を設定すると
timer0割込みが発生。
AnalogDevicesのデータシートでは、ビット割当て
を確認できます。
Keilの開発環境では、次のようにレジスタに設定できます。
/* enable timer 0 */
IRQEN = RTOS_TIMER_BIT ;
Keilの開発環境では、AnalogDevicesのデータシートで
規定した、RTOSというtimer0の機能を考えた、ラベル名
を使っています。
T0LD、T0CONレジスタへのパラメータ設定は、次の
ようなコードにします。
/* initialize timer 0 */
{
T0LD = 26112 ;
/* select cyclic , HCLK / 256 */
T0CON = 0xc4 ;
}
割込みが発生したときは、T0CLRIレジスタに
値を書き込み、割込み発生フラグをリセット
します。
具体的な関数は、次のように記述し。
void IRQ_Handler(void) __irq
{
/* clear timer 0 interrupt flag */
if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) {
T0CLRI = 0xff ;
}
}
すべての割り込みは、ひとつの関数で扱います。
関数内部で、どの割込みが発生したのかを判断し
必要な設定をします。
timer1動作
timer1のブロック図は、以下。
ブロック図から読み取れることをリスト。
- timer1のクロックは、32.768kHz、HCLK、P0.6、P1.0と選択できる
- プリスケーラ分周比は、1:1、1:16、1:256、1:32768
- タイマーとしての割込みはTIMER1 IRQ
- A/Dコンバータに関連した割込みも兼用
リスト内容から初期設定には、次の2点を最初に検討すれば充分。
レジスタでは、T1CONの各ビットの組み合わせで設定。
32ビット中の11から9で、利用クロックを指定。
32ビット中の3から0で、プリスケーラ分周比を指定。
レジスタT1CONの利用クロック、プリスケーラ分周比指定は
次のようなコードにすればよいでしょう。
T1CON = (1 << 9) | 15 ;
外部の32.768kHzを入力し、プリスケーラの分周比を1:32768に
設定します。
timer1を使わないのが、デフォルトになっているので
動かす場合は、T1CONレジスタの該当ビットを、セット
します。
初期設定と同時にtimer1を動かす場合、レジスタへの設定は
次のようになります。
T1CON = (1 << 9) | (1 << 7) |15 ;
timer1のカウンタは、アップあるいはダウンできるように
設計されています。
カウンタをアップで使うかダウンで使うかは、T1CONレジスタ
のビット8に設定する値で指定します。
カウンタ値がT1LDと一致すると、対応する割込みフラグが設定
されるので、割込みハンドラは次のように記述できます。
void IRQ_Handler(void) __irq
{
/* clear timer 1 interrupt flag */
if ( (IRQSTA & GP_TIMER_BIT) == GP_TIMER_BIT ) {
/* clear flag */
T1CLRI = 0xff ;
/* ??? */
}
}
利用クロックに32.768kHzがあり、プリスケーラ分周比に1:32768を
指定できることから、リアルタイムクロックを構成できると読取れ
ます。
timer1をリアルタイムクロックで使う場合、時、分、秒、1/100秒の
扱いを、カウンタの中でBCDとするのか2進とするかを指定できます。
ビットの組み合わせで、時計として利用するのか、カウンタとして
使うのかを指定できます。
- 00 2進
- 01 予約(使ってはいけない)
- 10 24時間制
- 11 256時間制
この他に、IRQの発生を0から31のいずれかを対象にして
補足できるようになっています。
対象となるIRQを指定し、IRQ発生時にカウンタ値をT1CAP
レジスタに格納する仕様になっています。
イベントキャプチャと呼ばれる動作で、指定IRQが発生する都度
カウンタ値を格納するので、周期や発生頻度を解析するのに利用
できます。
timer1は、A/D変換器でアナログ→デジタルの変換に利用する
クロックを生成しているので、A/D変換器を使う場合には注意
しなければ、希望する特性が得られない場面に遭遇します。
timer2(Wake-up)動作
timer2のブロック図は、以下。
ブロック図から読み取れることをリスト。
- 入力クロックは、内部クロック、外部クロック、HCLKと選択できる
- HCLK以外の周波数は、32.768kHz
- HCLKの周波数は、POWCONレジスタの設定値に依存
- プリスケーラ分周比は、1:1、1:16、1:256、1:32768
- タイマーとしての割込みはTIMER2 IRQ
クロック関係は、上記の通りですが、ロードレジスタと
カウンタのビットサイズが32ビットなので、非常に長い
周期を選択できます。(timer2の別名はWake-up Timer)
timer2に、どんな機能があるのかを、T2CONレジスタの
記述から読み取ってみます。
クロックソースは、内部、外部、HCLKを選択可能。
外部クロックは、2つの方法で選択できます。
分周比は、1:1、1:16、1:256、1:32768ですが
256分周の場合、時間をhh:mm:ssでカウントし
23時から0時あるいは255時から0時に戻る時
割込みが発生するように指定するモードと関連
します。
クロックによるカウントは、ダウンカウント、アップ
カウントのどちらかを指定可能です。
周期モードかフリーランモードで使えますが
やはり周期モードで使うのが簡単なようです。
timer3(Watch_dog)動作
timer3のブロック図は、以下。
周期モードに設定すると、動作はtimer0と同じに
なりますが、クロックは32.768kHz固定です。
クロック固定なので、プリスケーラから出力できる
クロック周波数は、以下の3種だけになります。
1Hzのクロックが必要な場合、T3LDレジスタに
次の値を設定します。
- 32768Hz : T3LD = 32768
- 2048Hz : T3LD = 2048
- 128Hz : T3LD = 128
時計を利用したい場合には、使えるタイマーでしょう。
割込みを使う場合、T3LDの値との兼ね合いで
次の図を参照してパラメータを設定します。
割込み処理
タイマーは4モジュールあり、0〜3と番号が
振られています。
これらのタイマーは、ダウンカウント処理で
動かすので、カウント値が0になったときに
割込みを発生させるようにします。
timer0からtimer3の割込みを発生させるため
には、該当ビットを1にします。
Keilの開発環境では、ヘッダファイルにラベル定義
されているので、それを使います。
#define RTOS_TIMER_BIT 0x00000004
#define GP_TIMER_BIT 0x00000008
#define WAKEUP_TIMER_BIT 0x00000010
#define WATCHDOG_TIMER_BIT 0x00000020
該当するヘッダファイルは、irq.hです。
対応するタイマとラベルは、以下です。
- timer0 => RTOS_TIMER_BIT
- timer1 => GP_TIMER_BIT
- timer2 => WAKEUP_TIMER_BIT
- timer3 => WATCHDOG_TIMER_BIT
timer0からtimer3の割込みを使う場合、次のように
論理和で設定します。
IRQEN = RTOS_TIMER_BIT | GP_TIMER_BIT | WAKEUP_TIMER_BIT | WATCHDOG_TIMER_BIT ;
割込みハンドラは、関数IRQ_Handlerの中に記述します。
void IRQ_Handler(void) __irq
{
/* judge timer0 interruption */
if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) {
/* clear flag */
T0CLRI = 0xff ;
/* set event flag */
t0flag = ON ;
/* ??? */
}
/* judge timer1 interruption */
if ( (IRQSTA & GP_TIMER_BIT) == GP_TIMER_BIT ) {
/* clear flag */
T1CLRI = 0xff ;
/* set event flag */
t1flag = ON ;
/* ??? */
}
/* judge timer2 interruption */
if ( (IRQSTA & WAKEUP_TIMER_BIT) == WAKEUP_TIMER_BIT ) {
/* clear flag */
T2CLRI = 0xff ;
/* set event flag */
t2flag = ON ;
/* ??? */
}
/* judge timer3 interruption */
if ( (IRQSTA & WATCHDOG_TIMER_BIT) == WATCHDOG_TIMER_BIT ) {
/* clear flag */
T3CLRI = 0xff ;
/* set event flag */
t3flag = ON ;
/* ??? */
}
}
目次
前
次