So-net無料ブログ作成

サイクルタイムを測定しよう (1) [PSoC]このエントリーを含むはてなブックマーク#

サイクルタイム測定キット

PSoC 4 にも CPU として Cortex-M0 が搭載されています。 普段は気にすることもないのですが、プログラムの実行時間をタイマを使って測定してみました。

実験回路

回路は、タイマと UART で構成されています。 タイマを16ビットのフリーランニングカウンタとして使用して、プログラムの実行前と実行後に読み出したカウンタの値の差を計算します。 この測定を何回か繰り返したら、まとめて UART から測定値を表示します。

実験では、 Internal Main Oscillator (IMO) の周波数を変更しながら、実行時間を測定します。 そのため、 UART の駆動クロックは、外部から与える構成にしました。

メイン関数

プログラムは、いくつかの部分で構成されています。 まずは、メイン関数から見ていきます。

int main(void) {
    // CyGlobalIntEnable; /* Enable global interrupts. */

    /* Place your initialization/startup code here (e.g. MyInst_Start()) */
    Timer_Start();
    UART_Start();
        
    loop(48);
    loop(24);
    loop(12);

    for(;;) {
        /* Place your application code here. */
    }
}

コンポーネント "Timer" と "UART" の初期化を行ったら、 loop() 関数で測定を三回行います。 loop() 関数の引数には、 IMO の周波数を MHz 単位で与えます。 この実験では、 48MHz, 24MHz, 12MHz の三種類の周波数について測定を行います。 測定が終わったら、無限ループに突入します。

測定ループ

loop() 関数は、三つの部分で構成されています。

// Measure the cycle time repeatedly
// The CPU frequency is set as specified in argument
void loop(uint32 freq) {
    uint32  i;
    char    sbuf[32];
    
    // Set CPU frequency
    setFreq(freq);
    
    // Measure the cycle time
    for (i = 0; i < N_DIFF; i++) {
        diffs[i] = measure() & Timer_16BIT_MASK;
    }

    // Show the measurement results
    sprintf(sbuf, "\r\nFreq:%ld\r\n", freq);
    UART_UartPutString(sbuf);
    for (i = 0; i < N_DIFF; i++) {
        sprintf(sbuf, "%04X", diffs[i]);
        UART_UartPutString(sbuf);
        if ((i & 7) < 7) {
            UART_UartPutChar(' ');
        } else {
            UART_UartPutCRLF(' ');
        }
    }

    // Wait for UART communication completed
    while (!(UART_GetTxInterruptSource() & UART_INTR_TX_UART_DONE));
}
IMO の設定
最初は、 IMO の周波数を設定するために setFreq() 関数を呼び出します。 中身は、のちほど。
サイクルタイムの測定
サイクルタイムの測定を measure() 関数で行い、 測定結果は diff[] 配列に格納していきます。 測定は、 N_DIFF で示される回数だけ繰り返されます。
測定結果の表示
測定結果は、 UART から出力されます。 出力形式は、16進数です。

IMO の設定関数

IMO の設定を変える時には、発振周波数の変更以外に、いくつかパラメータを調整する必要があります。

// Set the CPU clock frequency
void setFreq(uint32 freq) {
    // Select a longest wait cycle
    CySysFlashSetWaitCycles(48);
    
    // Change the IMO and related parameters
    CySysClkWriteImoFreq(freq);
    CySysFlashSetWaitCycles(freq);
    CyDelayFreq(freq * 1000000u);

    // Reconfigure the UART clock frequency
    Clock_UART_SetDivider(cydelayFreqHz/BAUDRATE/UART_UART_OVS_FACTOR-1);
}

まず、 CySysFlashSetWaitCycles(48) で、 Flash ROM のウエイトサイクル数を最大設定にします。 PSoC 4 に内蔵されている Flash ROM は、システムクロックが早い場合には、ウエイトサイクルを入れる必要があります。 この関数で、最大周波数 48MHz の時に使用されるウエイトサイクル、具体的には2サイクルのウエイトが挿入されます。

次に CySysClkWriteImo() 関数で IMO の周波数を変更します。 さらに、この周波数に適切なウエイトサイクルを Flash ROM に設定します。 引き続き、 CyDelayFreq() 関数を使って、サイクルタイムの測定で使用されている CyDelay() 関数などで使用される周波数パラメータを変更します。

最後に UART に使用されるクロックの周波数を変更します。 この時に、別途宣言されている BAUDRATE を使用して、 UART のボーレートを調整しています。 この実験では、 IMO を 12MHz まで落としているので、 UART のボーレートは 9600bps と低めの値に設定されています。

サイクルタイムの測定

プログラムのサイクルタイムを測定するには、プログラムの実行前と実行後にカウンタの値を読み出します。

// Measure the execution cycle time
uint32 measure(void) {
    uint32  s;
    uint32  e;
    
    s = Timer_COUNTER_REG;
    CyDelay(1);
    e = Timer_COUNTER_REG;
    
    return e - s;
}

実行前のカウンタ値を s に格納し、実行後のカウンタ値を e に格納します。 そして、これらの差分を関数の値として返します。

この実験では、 CyDelay(1) の実行時間(約1ミリ秒)を測定しています。

実行結果

この実験し使用した機材は、 CY8C4247AZI-M485 を搭載した CY8CKIT-044 です。 実行結果は、以下のようになりました。

Freq:48
BBB8 BBB8 BBB8 BBB8 BBB8 BBB8 BBB8 BBB8
BBB8 BBB8 BBB8 BBB8 BBB8 BBB8 BBB8 BBB8
BBB8 BBB8 BBB8 BBB8 BBB8 BBB8 BBB8 BBB8
BBB8 BBB8 BBB8 BBB8 BBB8 BBB8 BBB8 BBB8

Freq:24
5DF0 5DF0 5DF0 5DF0 5DF0 5DF0 5DF0 5DF0
5DF0 5DF0 5DF0 5DF0 5DF0 5DF0 5DF0 5DF0
5DF0 5DF0 5DF0 5DF0 5DF0 5DF0 5DF0 5DF0
5DF0 5DF0 5DF0 5DF0 5DF0 5DF0 5DF0 5DF0

Freq:12
2F0A 2F0A 2F0A 2F0A 2F0A 2F0A 2F0A 2F0A
2F0A 2F0A 2F0A 2F0A 2F0A 2F0A 2F0A 2F0A
2F0A 2F0A 2F0A 2F0A 2F0A 2F0A 2F0A 2F0A
2F0A 2F0A 2F0A 2F0A 2F0A 2F0A 2F0A 2F0A

48MHz のとき 0xBBB8 (48056) サイクル、 24MHz のとき 0x5DF0 (24048) サイクル、 12MHz のとき 0x2F0A (12042) サイクルを要しています。 CyDelay() 関数は、 CPU の実行時間を利用して遅延時間を作り出していますので、このくらいの精度が有れば十分でしょう。

プロジェクトアーカイブ

この記事で作成したプロジェクトは、このファイルの拡張子を "zip" に変更すると再現できます。


nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。