1. はじめに
Platform Designer には、Nios® II processor の HAL API Driver に対応した IP である、Interval Timer Core が用意されています。
Interval Timer Core は、Nios® II 、Nios® V 等のプロセッサー・システム用の Timer であり、この IP は、Platform Designer 上でパラメーター設定を変更することにより、さまざまな機能を実装した Timer として使用することができます。
この記事では、Interval Timer Core で実現可能な下記機能に対して、サンプルデザイン、サンプル・ソフトウェアを作成し、Interval Timer Core の使用方法とともに紹介します。
- Alarm : Timer の周期ごとに割り込みを発生させる機能
- System CLK : Tick 数から時間測定を行う機能
- Time stamp : CLK 周波数で動作する内部カウンターを使用して時間測定を行う機能
- WDT : プロセッサーに対して Reset 信号をアサートし Watchdog Timerとして使用する機能
Interval Timer Core に関する 記事やサンプルは、他にも下記のようなものがあります。併せてご参照いただくことでより理解が深まります。
参考: Embedded Peripherals IP User Guide ⇒ 23. Interval Timer Core
参考: Nios® II はじめてガイド - Nios® II SBT を使用したマルチコア・システムの実装
参考: Nios® II はじめてガイド - Nios® II SBT によるソフトウェア開発
2. Interval Timer Core
2-1. レジスターマップ
Interval Timer Core のレジスターは設定した Counter size により構造が変わります。
この項では、32 bit のレジスターマップについて解説いたします。
64 bit のレジスターマップについては、後程解説する period_h 、period_l 、snap_h 、snap_l のレジスター数が増えるのみで、レジスターの解説としては同じであるためこの記事では割愛します。
詳細は下記のユーザーガイドをご参照ください。
参考: Embedded Peripherals IP User Guide ⇒ 23.4.3. Register Map
【図1】にレジスター構成を示します。
【図1】 Interval Timer Core Register Map
【表1】が Status Register の詳細です。
Bit | Bit 名 | R/W | 概要 |
0 |
TO |
Read |
内部カウンター = 0 で 1 となり、新たに Write しない限りクリアーされません |
1 | RUN | Read | 内部カウンターが動作中の時 1 となります |
【表2】が Control Register の詳細です。
Bit | Bit 名 | R/W | 概要 |
0 |
ITO (*1) |
Read |
ITO : 1 かつ TO : 1 の場合、IRQ 信号を出力します。 |
1 | CONT |
Read |
CONT : 1 の時、STOP bit に 1 を書き込み停止するまで、カウンターは継続的に動作します。 CONT : 0 の時、内部カウンター = 0で、内部カウンターが停止し、各種 period レジスターに格納されている値をカウンターの初期値として読み込みます。 |
2 |
START (*2) |
Write |
1 を 書き込むことで、内部カウンターを開始させます。 内部カウンターが停止している場合、内部カウンターの現在の値から Timer は開始します。 |
3 |
STOP (*2) |
Write |
No Start / Stop control bit を有効にしている場合のみ使用できます。 |
*1 : ITO : 1 かつ TO : 1 の場合割り込み信号が発生し続けるため、どちらかの Bit をクリアーすることで、割り込みをクリアーする必要があります( sys_clk_timer で登録されている Timer は Nios® II HAL API で TO をクリアーする処理を Tick 毎に実行される割り込みハンドラー内で行っています)。
*2 : 各 Bit 0を書き込んでも効果はありません。また、両方に同時に 1 を書き込んだ場合、結果は未定義となります。
【表3】にその他のレジスターについて紹介します。
レジスター名 | Bit | 概要 |
period_l (*1) | 15 - 0 |
初期値としてパラメーター設定時の Time out period の値の下位 16 bit 分を格納します。内部カウンターに、以下の時に値を格納します。 ・内部カウンターの値が 0 になる ・Fixed period = 1 の時 ・Fixed period = 0 の時 【表1】の No Start / Stop control bits が ON の場合、このレジスターに書き込むことによって、内部カウンターがリセットされ、Platform Designer で設定した Timer 周期でリスタートします。 |
period_h (*1) | 31 -16 | 上記 period_l が下位 16 bit であるのに対し、period_h は上位 16 bit が対象となり、その他は全て同じ動作をします。 |
snap_l | 15 - 0 | レジスターに任意の値を書き込むことにより、内部カウンターの現在の値の下位 16 bit が snap_l レジスターにコピーされ参照することができます(書き込んだ値は影響しません)。 |
snap_h | 31 -16 | 上記 snap_l が下位 16 bit であるのに対し、snap_h は上位 16 bit が対象となり、その他は全て同じ動作をします。 |
*1 : Timer の周期 = 0 はサポートしていません。Period レジスターにて設定する場合でも 0 より大きい値で設定してください。
2-2. Platform Designer における設定
Interval Timer の Platform Designer 上の各種設定について紹介します。
【図2】は Interval Timer の Parameter 設定画面です。
【図2】 Interval Timer Core Parameters
*1 : Time out Period は、Period で設定した値以上の最小クロックサイクル数となります。
例:CLK = 30ns、Period = 1 us の時、Time out period =1.02 us
*2 : カウンターサイズによりレジスターの実装数が変わります。詳細は『2-1. レジスターマップ』をご参照ください。
パラメーター名 | 概要 |
No Start / Stop control bits |
無効時 有効時 |
Fixed period |
無効時 有効時 |
Readable snapshot |
無効時 有効時 |
各種 レジスターの詳細は『2-1. レジスターマップ』よりご参照ください。
注記:
上記 Interval Timer Core のパラメーター設定の Registers ブロックについて、ユーザーガイドとPlatform Designer でパラメーター名が下記のように差分があります。
-
- Writeable period ⇒ Fixed period
- Start / Stop control bits ⇒ No Start / Stop control bits
これらの項目は、ユーザーガイドと Platform Designer でパラメータの意味が逆になっており、それに伴い有効時と無効時の実装される内容も逆になります。そのためパラメータ設定時は【表4】の概要欄に従ってください。
また、Platform Designer の IP Catalog から Interval Timer を選択したときに、Presets を使用することができます。
Presets を使用することで、ユーザーは実現したい Timer の構成を容易に設定することが可能です。
種類としては【表5】Presets 設定一覧をご参照ください。
設定名 / 概要 |
Platform Designer 設定画面 |
Full-featured |
【図3】Presets : Full-featured |
Simple periodic Interrupt |
【図4】Presets : Simple periodic interrupt |
Watchdog |
【図5】Presets : Watch dog |
2-3. Nios® II Hal API Driver の仕様
Interval Timer Core が提供している Driverとして、下記 2 種類を使用することができます。
Driver 名 | 概要 |
System Clock Driver |
sys_clk_timer として Timer を使用し、Time out period ごとに割り込みで加算される Tick 数で時間を測定します。 使用方法 【図6】BSP Editor sys_clk_timer |
Time Stamp Driver |
timestamp_timer として Timer を登録し、CLK に同期してカウントされる内部カウンターを使用して時間を測定します。 使用方法 Fixed period については『2-2. Platform Desiner における設定』をご参照ください。 【図7】BSP Editor timestamp_timer |
注記:
1 つの Timer に対して 2 つの Driver を使用することはできません。
Interval Timer Core 対応 API 使用方法を【表7】に示します。
関数名 | 概要 | Include |
System Clk Driver 用 API | ||
alt_nTicks (void) |
リセット後からの sys_clk_timer の Tick 数を取得します。 |
alt_alarm.h |
alt_Ticks_per_second (void) |
1 秒当たりの sys_clk_timer の Tick 数を取得します。 | alt_alarm.h |
alt_alarm_start |
sys_clk_timer を使用した、アラームの登録、アラーム終了時の Call back 関数の登録を行います。 |
alt_alarm.h |
alt_alarm_stop (alt_alarm* alarm) | 登録したアラームに対して、取り消しを行います。 | alt_alarm.h |
Timestamp Driver 用 API | ||
alt_timestamp_start (void) | 内部カウンターの動作を開始します。関数を呼び出すたびに、内部カウンターは 0 にリセットされます。 | alt_timestamp.h |
alt_timestamp (void) |
内部カウンターの現在の値を返します。 |
alt_timestamp.h |
alt_timestamp_freq (void) | Interval Timer Core の 周波数を取得します。(*1) | alt_timestamp.h |
*1 : 内部カウンターは、Interval Timer Core の周波数で動作するため、
Interval Timer Core の周波数 = 1 秒当たりの Tick 数となります。
3. サンプルデザイン & サンプル・ソフトウェアの概要
この記事で紹介するサンプルデザイン情報を下記に記載します。
- 使用 Kit : Cycloen V GX スターター開発キット( Qsys ファイルとソフトウェアを他の Kit に移植して再現可能)
- Tool バージョン: Quartus® Prime ver20.1_Standard
- 主な使用 IP : Nios® II 、On-Chip RAM 、JTAG UART 、PIO ( LED ) 、Interval Timer
- Nios® II/f(Gen2): 命令キャッシュ : 4 KB データキャッシュ : 2 KB
- On-Chip RAM: 100 KB(ワークメモリー)
- ソフトウェア容量の目安: program size ( code + initialized data ):
下記()内の数字は BSP Editor にて、enable small c library (*1) 有効時のサイズ- Alarm : 70 KB(16KB)
- System CLK: 73 KB(20KB)
- Time stamp: 73 KB(19KB)
- WDT : 29 KB(15KB)
*1 : enable small c library は、BSP Editor から設定を行う、ファイルサイズを縮小するオプションです。詳細は下記をご参照ください。
参考:
Nios II はじめてガイド Nios II SBT と BSP Editor オプション設定 ⇒ 3-3-1-4. enable_small_c_library
注記:
ソフトウェア容量に対して RAM の容量が少ない場合、スタック・オーバーフローが発生する可能性がありますので、RAM 容量は余裕をもって設定してください。
各ソフトウェアに実装されている制御の詳細については、この記事に添付されているソースファイルをご参照ください。
Platform Designer の接続図を【図8】に示します。
【図8】Platform Designer の接続図
今回ご紹介するソフトウェアでは、Timer の動作を確認するために、JTAG_UART コア、PIO コアを使用していますが、Timer Core を使用して実際に開発を行う場合は、これらは必須ではありません。
3-1. サンプル・ソフトウェア "Alarm"
このサンプル・ソフトウェアでは、sys_clk_timer として Timer を登録 & 設定して、周期ごとに呼び出される Call back 関数内で記述した処理を実行するソフトウェアです。
『2-3. Nios® II HAL API Driver の仕様』 で紹介した HAL API を使用して Alarm を登録します。
サンプル・ソフトウェアの動作としては以下のとおりです。
- アラームの登録
- 指定秒数ごとに、Call back 関数を呼び出し
- Call back 回数を出力
ソフトウェアの最初でアラーム登録用の変数を用意し、下記 HAL API より Alarm の登録を行います。
// アラームポインタの登録
static alt_alarm alarm;
アラームの登録時に、初回の Call back 関数の呼び出し周期と、Call back 関数を登録します。
このサンプルでは、#define LOOPSEC で任意の秒数を設定し、LOOPSEC * alt_Ticks_pre_second() と記載することで、Call back 関数の呼び出し周期を決定します。
#define LOOPSEC (5)
// アラームの登録
alt_alarm_start(&alarm, LOOPSEC * alt_ticks_per_second(),tim_callback,NULL);
Call back 関数の呼び出し2回目以降は、Call back 関数の戻り値が次回 Call back 関数の呼び出し周期となります。
// 戻り値により、次回 Alarm の周期を設定 (LOOPSEC 秒)
return LOOPSEC * alt_ticks_per_second();
}
ソフトウェア実行後は、下記のように Call backした回数が出力されます。
Hello from Nios II Alarm!
Callback count :1
Set Alarm 5 s
Callback count :2
Set Alarm 5 s
3-2. サンプル・ソフトウェア "System CLK"
このサンプル・ソフトウェアは Alarm と同様に sys_clk_timer として Timer を 登録し、Tick 数を取得する HAL API を使用して、時間測定を行うサンプル・ソフトウェアです。
このサンプル・ソフトウェアは下記の動作を行います。
- 時間測定対象の処理を記載した関数の全てで、 Tick を取得
- 取得した Tick 数の差分を出して、測定時間を算出
alt_nticks() は、【表7】Interval Timer Core 対応 API リスト でも説明した通り、リセット後からの Tick 回数を取得しています。Tick ベースでの経過時間から下記のように記述することで、測定対象の所要時間を計測することができます。
// 測定対象関数の前後のTick数を取得
start_time = alt_nticks();
func1();
end_time = alt_nticks();
// 所用時間計算
printf("total time = %d %s \n",(int)((end_time-start_time)/(float)alt_ticks_per_second()/ conv),units);
enable small c library 有効の場合、printf() に float を表示できないため、単位を変換し int で出力しています。
単位 ( units ) と単位変換用の変数 ( conv ) は、system.h に定義されており、これをアプリケーション・ソフトウェア内の #define により以下のように定義しています。
#define units (ALARM_PERIOD_UNITS)
#define conv (ALARM_MULT)
ソフトウェア実行後は、下記のように測定対象前の Tick 数(start)と測定対象後 Tick 数(end)の終了時間を 1秒間の Tick 数( Ticks / sec ) で割ることでトータルの所用時間を算出しています。
Hello from Nios II SystemCLK!
count Up ( 100000 )
start 1
end 31
Ticks/sec 1000
total time = 30 ms
3-3. サンプル・ソフトウェア "Time Stamp"
このサンプル・ソフトウェアは使用 Timer を timestamp_timer に登録し、sys_clk_timer と同様の処理の時間計測を行います。
このサンプル・ソフトウェアでは Time stamp Driver を使用しており、CLK の周波数でカウントアップする内部カウンターを使用しているため、sys_clk_timer に比べ ns 単位での高精度な時間計測を行えます。
下記スクリプト記載の alt_timestamp() ; を実行することにより、snap レジスターに内部カウンターの値が格納されるため、この値から所要時間を算出します。
// 測定対象関数の前後の内部カウンターを参照
start_time = alt_timestamp();
func1();
end_time = alt_timestamp();
// 所用時間計算
printf("total time = %d ns \n",(int)((end_time - start_time)/(float)alt_timestamp_freq() * conv));
このサンプルでも同様に enable small c library を有効にしているため、単位変換を行いますが、こちらのソフトウェアは ns 単位での測定となるため、単位変換も ns に固定しています。
// ns 変換用変数
#define conv (1000000000)
下記がソフトウェア実行後の出力です。測定対象処前のカウンター数(Start)と測定対象後(end) のカウンター数の差分を出し、1秒当たりの Ticks 数( Ticks / sec )を割ることで、所要時間が算出されます。 sys_clk_timer 使用時に比べて【表7】で解説した通り、Ticks / sec が動作周波数の値になっており、高分解能で測定していることがわかります。
Hello from Nios II TimeStamp!
count Up ( 100000 )
start 8808
end 1508976
Ticks/sec = 50000000
total time = 3003784 ns
3-4. サンプル・ソフトウェア "WDT"
このサンプル・ソフトウェアは、内部カウンターが 0 になると Nios® II processor に対する Reset 信号(以下、ソフトウェア・リセット)を出力する WDT としての機能を実現するサンプルです。
WDT を実際に使用した場合、ソフトウェア・リセットが出力されないように、ソフトウェアで WDT のカウンターをクリアすることが多いため、このサンプル・ソフトウェアでも、『3-1. サンプル・ソフトウェア "Alarm"』のアラーム機能を使用し、ソフトウェア制御により内部カウンターが 0 になる前に、内部カウンターの初期化を行います。
初期化回数をソフトウェア上で設定できるので、規定回数に達したらソフトウェア・リセットが出力される構成です。
アラームで呼び出す Call back 関数内では、内部カウンターの初期化処理を実施します。
これは、『2-2. Platform Desiner における設定 』で解説した、Fixed period を有効にすることにより、period register への Write のみで内部カウンターが初期化されます。
下記が Call back 関数の内部です。
Call back 関数の戻り値が次の Callback 関数呼び出しの周期となるため、内部カウンターの周期(WDT_PERIOD)から 1 秒早く呼び出すよう設定しています。
alt_u32 WDTKick_count(void * context)
{
if (kick_count < KICK_LIMIT)
{
// WDTの Timer をリセット
IOWR_ALTERA_AVALON_TIMER_PERIODL(WDT_ADR, WDT_BIT_MSK);
++kick_count;
}else if(kick_count == KICK_LIMIT){
kick_flag_not = 1;
}
// WDT Timer から -1 s 早くアラームを起動
return (WDT_PERIOD -1) * alt_Ticks_per_second();
}
下記は出力結果です。
WDT のソフトウェア・リセットを契機に、ソフトウェアの最初から再ロードされていることがわかります。
Hello from Nios II WDT!
Reset soon...
Hello from Nios II WDT!
4. おわりに
以上が Interval Timer Core を使用した、各種機能と WDT 構成のサンプルデザインとなります。
今回は、各種基本的な機能と実際の使用を想定した応用編として、WDT のサンプルをご紹介しましたが、Interval Timer Core は多くの Reference Design に組み込まれている IP であり、各デザインでさまざまな使い方をされているかと思いますので、この記事を参考に他のデザインを見ることにより、理解を深めていただければ幸いです。
この記事で紹介したサンプルデザインは、下記よりダウンロードいただけます。