16

我正在尝试在 Cortex M4 上分析 C 函数(从中断调用,但我可以将其提取并在其他地方分析)。

计算此函数中通常使用的周期数的可能性是什么?函数应在大约 4000 个周期内运行,因此我猜 RTC 不是一个选项,并且手动计算反汇编周期可能会很痛苦 - 并且只有在平均时才有用,因为我想用典型的闪存/内存在典型的流上进行分析使用模式。

我听说过循环计数器寄存器和 MRC 指令,但它们似乎可用于 A8/11。我还没有在 cortex-Mx micros 中看到这样的说明。

4

5 回答 5

23

看看这里定义的 DWT_CYCCNT 寄存器。请注意,此寄存器取决于实现。谁是芯片供应商?我知道 STM32 实现提供了这组寄存器。

这篇文章提供了使用 DWT 周期计数器寄存器进行计时的说明。(请参阅 2009 年 12 月 11 日 - 下午 6:29 的邮寄表格)

这个堆栈溢出帖子也是如何使用 DWT_CYCCNT 的示例。

于 2012-07-17T21:02:42.483 回答
3

如果您的部件包含CoreSight 嵌入式跟踪宏单元并且您有适当的支持跟踪的调试器硬件和软件,那么您可以直接分析代码。具有跟踪功能的调试硬件当然更昂贵,并且您的电路板需要设计为在调试头上提供跟踪端口引脚。由于这些引脚通常与其他功能复用,这可能并不总是可行或实用的。

否则,如果您的工具链包含一个周期精确的模拟器(例如Keil uVision中可用的模拟器),您可以使用它来分析代码时序。模拟器提供的调试、跟踪和分析功能通常比芯片上可用的功能更强大、更灵活,因此即使您确实有跟踪硬件,模拟器可能仍然是更简单的解决方案。

于 2012-07-18T05:02:30.573 回答
2

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);
}
于 2017-04-21T04:44:29.403 回答
2

这更容易:

[代码]

#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,只计算所需的周期。

于 2017-10-29T17:49:04.560 回答
0

这取决于您的 ARM 实现。

SysTick->VAL 在 stm32F4 内核上使用了寄存器。这是周期准确的。

在解释结果时,请注意:

  • 考虑到包装。
  • 它倒计时,而不是倒计时。

限制:这仅适用于小于单个 systick 的间隔。

于 2014-05-14T10:07:23.133 回答