web-dev-qa-db-ja.com

ARM Cortex M4(またはM3)のサイクルカウンター?

Cortex M4でC関数(割り込みから呼び出されますが、抽出して他の場所でプロファイルできます)をプロファイルしようとしています。

この関数で通常使用されるサイクル数をカウントする可能性は何ですか?関数は最大4000サイクルで実行されるため、RTCは私が推測するオプションではなく、分解からのサイクルを手動でカウントするのは面倒な場合があります。プロファイルを作成したいので平均した場合にのみ役立ちます。典型的なフラッシュ/メモリ使用パターンの典型的なストリーム。

サイクルカウンタレジスタとMRC命令について聞いたことがありますが、A8/11で使用できるようです。私はcortex-Mxマイクロでそのような指示を見たことがありません。

12
makapuf

定義されたDWT_CYCCNTレジスタを見てください ここ 。このレジスタは実装に依存することに注意してください。チップベンダーは誰ですか? STM32実装がこのレジスタのセットを提供していることを私は知っています。

この投稿 タイミングにDWTサイクルカウンタレジスタを使用するための手順を提供します。 (2009年12月11日午後6時29分に投稿フォームを参照)

このスタックオーバーフローの投稿 はDWT_CYCCNTの方法の例でもあります。

18
Throwback1986

パーツに CoreSight Embedded Trace Macrocell が組み込まれていて、適切なトレース対応のデバッガハードウェアとソフトウェアがある場合は、コードを直接プロファイリングできます。トレース対応のデバッグハードウェアはもちろん高価であり、デバッグヘッダーでトレースポートピンを使用できるようにボードを設計する必要があります。これらのピンは他の機能に多重化されることが多いため、常に可能または実用的であるとは限りません。

それ以外の場合、ツールチェーンにサイクル精度のシミュレーター( Keil uVision で利用可能なものなど)が含まれている場合は、それを使用してコードのタイミングを分析できます。シミュレーターは、チップ上で利用可能なものよりも一般的に強力で柔軟性のあるデバッグ、トレース、およびプロファイリング機能を提供するため、トレースハードウェアを使用している場合でも、シミュレーターの方が簡単なソリューションである可能性があります。

3
Clifford

mainのDWT_CYCCNTの例(STM32)で以前の回答を拡張します(私の 他の投稿 と同様)。

注:遅延メソッドも追加しました。 _stopwatch_delay_を呼び出して_STOPWATCH_START_を確認し、stopwatch_delay(ticks)を実行してから、_STOPWATCH_STOP_を呼び出し、CalcNanosecondsFromStopwatch(m_nStart, m_nStop)で確認できます。必要に応じてticksを調整します。

_uint32_t m_nStart;               //DEBUG Stopwatch start cycle counter value
uint32_t m_nStop;                //DEBUG Stopwatch stop cycle counter value

#define DEMCR_TRCENA    0x01000000

/* Core Debug registers */
#define DEMCR           (*((volatile uint32_t *)0xE000EDFC))
#define DWT_CTRL        (*(volatile uint32_t *)0xe0001000)
#define CYCCNTENA       (1<<0)
#define DWT_CYCCNT      ((volatile uint32_t *)0xE0001004)
#define CPU_CYCLES      *DWT_CYCCNT
#define CLK_SPEED         168000000 // EXAMPLE for CortexM4, EDIT as needed

#define STOPWATCH_START { m_nStart = *((volatile unsigned int *)0xE0001004);}
#define STOPWATCH_STOP  { m_nStop = *((volatile unsigned int *)0xE0001004);}


static inline void stopwatch_reset(void)
{
    /* Enable DWT */
    DEMCR |= DEMCR_TRCENA; 
    *DWT_CYCCNT = 0;             
    /* Enable CPU cycle counter */
    DWT_CTRL |= CYCCNTENA;
}

static inline uint32_t stopwatch_getticks()
{
    return CPU_CYCLES;
}

static inline void stopwatch_delay(uint32_t ticks)
{
    uint32_t end_ticks = ticks + stopwatch_getticks();
    while(1)
    {
            if (stopwatch_getticks() >= end_ticks)
                    break;
    }
}

uint32_t CalcNanosecondsFromStopwatch(uint32_t nStart, uint32_t nStop)
{
    uint32_t nDiffTicks;
    uint32_t nSystemCoreTicksPerMicrosec;

    // Convert (clk speed per sec) to (clk speed per microsec)
    nSystemCoreTicksPerMicrosec = CLK_SPEED / 1000000;

    // Elapsed ticks
    nDiffTicks = nStop - nStart;

    // Elapsed nanosec = 1000 * (ticks-elapsed / clock-ticks in a microsec)
    return 1000 * nDiffTicks / nSystemCoreTicksPerMicrosec;
} 

void main(void)
{
    int timeDiff = 0;
    stopwatch_reset();

    // =============================================
    // Example: use a delay, and measure how long it took
    STOPWATCH_START;
    stopwatch_delay(168000); // 168k ticks is 1ms for 168MHz core
    STOPWATCH_STOP;

    timeDiff = CalcNanosecondsFromStopwatch(m_nStart, m_nStop);
    printf("My delay measured to be %d nanoseconds\n", timeDiff);

    // =============================================
    // Example: measure function duration in nanosec
    STOPWATCH_START;
    // run_my_function() => do something here
    STOPWATCH_STOP;

    timeDiff = CalcNanosecondsFromStopwatch(m_nStart, m_nStop);
    printf("My function took %d nanoseconds\n", timeDiff);
}
_
1
bunkerdive

これは簡単です:

[コード]

#define start_timer()    *((volatile uint32_t*)0xE0001000) = 0x40000001  // Enable CYCCNT register
#define stop_timer()   *((volatile uint32_t*)0xE0001000) = 0x40000000  // Disable CYCCNT register
#define get_timer()   *((volatile uint32_t*)0xE0001004)               // Get value from CYCCNT register

/***********
* How to use:
*       uint32_t it1, it2;      // start and stop flag                                             

        start_timer();          // start the timer.
        it1 = get_timer();      // store current cycle-count in a local

        // do something

        it2 = get_timer() - it1;    // Derive the cycle-count difference
        stop_timer();               // If timer is not needed any more, stop

print_int(it2);                 // Display the difference
****/

[/コード]

Cortex M4:CJMCUボード上のSTM32F407VGTで動作し、必要なサイクルをカウントするだけです。

1
Shalec

これはあなたに依存しますARM実装。

Stm32F4コアでSysTick->VALレジスタを使用しました。これは正確なサイクルです。

結果を解釈するときは、次の点に注意してください。

  • ラッピングを考慮に入れてください。
  • カウントアップではなく、カウントダウンします。

制限:これは、単一のsystickよりも小さい間隔でのみ機能します。

0
harmv