Timer
16bit カウンタを用いるハードウェアタイマー(TIMER0 .. 4) を利用可能です。
このタイマーは、PWM 出力などのペリフェラルとして利用することもできますし、ソフトウェア処理を行うハードウェアタイマーとして利用することも可能です。

ポートの割り当て

タイマー番号
副2
解説
TIMER0
8, 9, 10
2,3,4
汎用タイマー機能利用可能
TIMER1
11
5
PWM 出力専用
TIMER2
12
6
DO0*
PWM 出力専用
TIMER3
13
7
DO1*
PWM 出力専用
TIMER4
17
8
PWM 出力専用
ペリフェラル API vAHI_TimerSetLocation() により、副割り当てに変更できます。
* TIMER2と3 は DO0,1 に割り当てを変更できます。ただし、これらのポートについては、電源投入時に Vcc レベルになっていないと TWELITE 無線マイコンが正常起動しないことがあります。
TWELITE RED ではさらにPWM出力系統が増えていますが、TWELITE NET での標準的な対応は TIMER0..4 とします。

初期化と開始、終了

事前にペリフェラルマニュアルを参照の上、Timer で利用しないポートを宣言します。この宣言をしないと、Timer の初期化後、該当ポートは汎用のIOポートとして利用できなくなります。
以下の例では bit0,1,2 をセットします。これは TIMER0 で使用する PWM 用のピンを全て汎用IO向けに解放します。
1
vAHI_TimerFineGrainDIOControl(0x7);
Copied!

tsTimerContext() のパラメータ

Bit
Timer Input/Output
0
TIMER 0 ゲート/イベント入力
1
TIMER 0 キャプチャー入力
2
TIMER 0 PWM 出力
3
TIMER 1 PWM 出力
4
TIMER 2 PWM 出力
5
TIMER 3 PWM 出力
6
TIMER 4 PWM 出力
7
予約
次に Timer ライブラリ用の初期化構造体 tsTimerContext を静的に確保し、設定を行います。
必要なタイマーの周波数に対して適切な PreScale を選択するようにします。
プリスケール(u8PreScale) は、要求する周期(周波数)に対して、多くの場合はより小さい値を選択します。
Timer は 16Mhz のカウンター値をプリスケールしており、1周期のカウント値(Ct)は以下の式で与えられます。
1
Ct = 16,000,000 / 2^p / hz
2
p : プリスケール値
3
hz : Timer 周期
Copied!
この Ct 値が 16bit の最大数(65535)を超えないように設定します。例えば64Hzのタイマーが欲しい場合は p=2 で Ct = 62500, p=4 で Ct = 15625 となります。 より正確なDuty比のPWM出力が必要な場合は、少しでも小さな p=2 を選択しますが、単純にソフトウェア用のタイマーが必要な場合は p=4 でも違いはありません。
1
tsTimerContext sTimerApp; // global or static allocation
2
3
// set 64ticks/sec
4
memset(&sTimerApp, 0, sizeof(tsTimerContext));
5
sTimerApp.u8Device = E_AHI_DEVICE_TIMER0;
6
sTimerApp.u16Hz = 64;
7
sTimerApp.u8PreScale = 4; // [email protected]^4
Copied!
最後に、Timer を開始します。
1
vTimerConfig(&sTimerApp); // initialize
2
vTimerStart(&sTimerApp); // start timer
Copied!
Timer を一時的に停止させるには、vTimerStop() を呼び出します。完全に無効化するには vTimerDisable() を呼び出します。
1
// just stop the timer
2
vTimerStop(&sTimerApp);
3
...
4
// restart
5
vTimerStart(&sTimerApp);
6
...
7
// now, disable timer completely
8
vTimerStop(&sTimerApp);
9
vTimerDisable(&sTimerApp);
Copied!

タイマー割り込み

ToCoNet_u8HwInt() ToCoNet_vHwEvent() の u8DeviceID パラメータが E_AHI_DEVICE_TIMER0 から E_AHI_DEVICE_TIMER4 をとります。
割り込み周波数が高くなるとハード割り込みやイベントの処理が無視できなくなります。
  • 不要なタイマーの割り込みは無効にしておく
    • tsTimerContext の bDisableInt を TRUE に設定する
  • 割り込み処理のみで対応し、ハードイベントは発生させない
    • 割り込みハンドラを TRUE で return する
1
// hardware interrupt (return quickly!)
2
uint8 cbToCoNet_u8HwInt(
3
uint32 u32DeviceId,
4
uint32 u32ItemBitmap) {
5
uint8 u8handled = FALSE;
6
7
switch (u32DeviceId) {
8
case E_AHI_DEVICE_TIMER0:
9
_C {
10
static bool_t b;
11
b = !b;
12
vPortSet_TrueAsLo(PORT_DO1, b);
13
14
u8handled = FALSE; // if TRUE, no HwEvent follows.
15
}
16
break;
17
}
18
}
19
20
// hardware event (in the application loop)
21
// where we can make a bigger job, like RF transmit.
22
void cbToCoNet_vHwEvent(
23
uint32 u32DeviceId,
24
uint32 u32ItemBitmap) {
25
26
switch (u32DeviceId) {
27
case E_AHI_DEVICE_TIMER0:
28
vPutChar(&sSerStream, 'x'); // put x every tick
29
if (...) {
30
...
31
ToCoNet_bMacTxReq(...); // send a packt
32
}
33
break;
34
}
35
36
}
Copied!

PWM 出力

Timerの出力として PWM 出力を設定することが可能です。
Duty比の精度を向上させるため、上述のプリスケール値を十分小さい値にしておくことを推奨します。
PWM出力を得るためには以下の設定が必要です。
  • tsTimerContext の bPWMOut を TRUE に設定する
  • tsTimerContext の u16duty を 0..1024 の値に設定する
  • vAHI_TimerFineGrainDIOControl() で出力を無効にしていない
1
tsTimerContext sTimerPWM; // global or static allocation
2
3
// initialize
4
memset(&sTimerPWM, 0, sizeof(tsTimerContext));
5
sTimerPWM.u8Device = E_AHI_DEVICE_TIMER1;
6
sTimerPWM.u16Hz = 1000; // 1Khz
7
sTimerPWM.u8PreScale = 0;
8
sTimerPWM.u16duty = 512; // 50%
9
sTimerPWM.bPWMout = TRUE; // PWM out
10
sTimerPWM.bDisableInt = TRUE; // no interrupt (for CPU save)
11
// start
12
vTimerConfig(&sTimerPWM);
13
vTimerStart(&sTimerPWM);
14
15
...
16
// change duty
17
sTimerPWM.u16Duty = 256; // set new duty ratio
18
vTimerStart(&sTimerPWM); // just start again to change duty
Copied!
最終更新 1mo ago