ある処理に掛かるサイクル数や時間を計測したい時に便利な方法をご紹介します。
ARM社のCortex-Mコア向けアプリケーションソフトウェア規格であるCMSIS(Cortex Micro-controller Software Interface Standard)を使うことで、超簡単に処理サイクルを計測できるんです。
そんなCMSISを使ったサイクル計測方法を紹介します。
CMSISインターフェース
Cortex-Mコアやデバイスのペリフェラル等を共通で一貫したソフトウェアインタフェースを規格したもので、7つのソフトウェアインタフェース規格があります。
- CMSIS-CORE
- CMSIS-Driver
- CMSIS-DSP
- CMSIS-RTOS
- CMSIS-Pack
- CMSIS-SVD
- CMSIS-DAP
このように、コアやペリフェラル、DSP命令、組み込み関数、デバッグアクセスに至るまで、一貫したインタフェースを規格しています。
このCMSISはランタイムシステムで、コア等へのアクセスが可能になるものです。
積極的にこのCMSISを使用することで、異なるベンダー間のMCUでもCortex-Mコアへのアクセスが一貫したインタフェースで共通化されているので、移植が容易になると言うものです。
CMSIS-CORE
今回は、この内のCMSIS-COREを使います。
CMSIS-COREは、ハードウェア抽象化レイヤ、システム例外や割り込みベクタ、システムの初期化と言ったいわば、システムの中心を担うハードウェアへのアクセスをするためのインタフェースです。
具体的には、
- HAL (Hardware Abstraction Layer)
- システム例外、割り込みベクタ
- ヘッダファイルの構成
- システムの初期化方法
- C/C++コンパイラでサポートされていない命令の組み込み関数
- SysTickタイマーの初期化、スタート
大きく分けると、6つに別れています。
今回は、6番目のSysTickタイマを使用する訳です。
SysTickタイマー
百聞は一見にしかず。早速使ってみましょう。
NXPのMCUXpresso SDK Builderで目的の評価ボードのSDKをダウンロードして、SDKからサンプルのコードをインポートすると自動的にCMSISが付いてきます。

今回は、SysTickタイマーを使用しますが、core_cm0plus.hにSysTick_Config()と言うインライン関数が定義されています。この関数は、コアクロックで動作しているシステムタイマーで、このカウントレジスタを設定しSysTickタイマーをスタートします。
使い方は、SysTick_Config()の引数にカウント値を入力するだけです。コアクロックでカウント値をカウントダウンしていき、0になると、SysTick_IRQnに割り込みが入ります。
今回は、サイクル数を計測するだけなので、このカウント値は適当な値を入力するだけでOKです。ただし、計測する時間以上のティック数を入力する必要があります。そうしないと、計測する時間未満でSysTick割り込みが発生してしまいます。
割込みを利用することで、OSのコンテキストスイッチなどにも利用可能です。
使い方は、以下のようになっています。
uint32_t SysTick_Config (uint32_t ticks )
パラメータ
[in] ticks 割り込みと割り込みの間のティック数
リターン
0 - 成功
1 - エラー
サイクルの計測
では、早速サイクルの計測をやってみます。 MCUXpresso SDKをインストール(SDKのzipファイルをそのままInstalled SDKsウィンドウにドラッグ&ドロップ)して、Hello Worldのサンプルプログラムをインポートします。
今回は、SDKのインポートなどの詳しい方法は、割愛します。他の記事を参考にしてください。
サイクルの測定には、簡単な次のようなコードを用意してみました。
Hello Worldのmain()内を以下に書き換えて実行してみてください。
int main(void)
{
uint32_t cnt=0;
volatile uint32_t i;
uint16_t ret;
/* Init board hardware. */
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
/* Cycle count start */
ret= SysTick_Config(16000000);/*<---- Here starts the cycle count */
if(ret){
PRINTF("SysTick configuration is failed.\n\r");
while(1);
}
for (i=0; i<1000;i++ );
cnt = 16000000 - SysTick->VAL;/*<--- Here stops the cycle counting */
PRINTF("Result : %d Cycles\n\r",cnt);
/* Cycle count ended */
while(1);
}
実行結果

実行すると、for文のループ回数に掛かるサイクル数が計測されます。もちろん、forループ回数を多くすれば、サイクル数も比例して大きくなります。 SysTick_Config()で、システムタイマーの設定とスタートを同時に行っています。タイマーのストップは行なっていませんが、SYsTick.CTRLレジスタのENABLEビットをクリアするとストップします。
番外編: SysTick割り込み
SysTick_Configに設定するティック数で、SysTick割り込みが発生するので、こちらの使い方もみて見ましょう。
サンプルコードがCMSISのドキュメントに記載されています。
#include "LPC17xx.h"
uint32_t msTicks = 0; /* Variable to store millisecond ticks */
void SysTick_Handler(void) { /* SysTick interrupt Handler.
msTicks++; See startup file startup_LPC17xx.s for SysTick vector */
}
int main (void) {
uint32_t returnCode;
returnCode = SysTick_Config(SystemCoreClock / 1000); /* Configure SysTick to generate an interrupt every millisecond */
if (returnCode != 0) { /* Check return code for errors */
// Error Handling
}
while(1);
}
まとめ
いかがでしたでしょうか。 CMSISを使って、簡単にサイクル数を計測できます。たま〜に、こう言ったサイクル数を計測したい時があるので、参考にして見てください。 Cortex-M4などでは、CYCLE count値のCPUレジスタがあるので、デバッガ上で確認できるのですが、Cortex-M0/M0+では、デバッガでは確認できないので、SysTickを使うと便利です。