打印
[APM32F4]

基于APM32F407的DWT周期计数器实现精准代码性能分析

[复制链接]
268|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
a976209770|  楼主 | 2024-12-9 15:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1. 引言

在嵌入式系统开发中,性能分析是优化代码的重要环节。APM32F407提供的DWT(Data Watchpoint and Trace)模块可以利用其周期计数器(CYCCNT)功能,精准记录代码执行的时钟周期数。结合多次统计功能,我们可以更全面地分析代码性能,包括平均执行时间、最长时间和最短时间。

2. 示例代码

以下是具有统计功能的完整代码:
#include <stdint.h>

// DWT 和 Core Debug 基地址
#define DWT_BASE       0xE0001000UL
#define DWT            ((DWT_Type *)DWT_BASE)
#define CoreDebug_BASE 0xE000EDF0UL
#define CoreDebug      ((CoreDebug_Type *)CoreDebug_BASE)

// DWT 寄存器结构
typedef struct {
    volatile uint32_t CTRL;      // 控制寄存器
    volatile uint32_t CYCCNT;    // 周期计数器
    uint32_t RESERVED[6];        // 保留区域
    volatile uint32_t LSR;       // 锁存状态寄存器
} DWT_Type;

// Core Debug 寄存器结构
typedef struct {
    volatile uint32_t DHCSR;     // 调试主机控制和状态寄存器
    volatile uint32_t DCRSR;     // 调试核心寄存器选择器寄存器
    volatile uint32_t DCRDR;     // 调试核心寄存器数据寄存器
    volatile uint32_t DEMCR;     // 调试异常和监控控制寄存器
} CoreDebug_Type;

// Core Debug DEMCR 寄存器中的 TRCENA 位定义
#define CoreDebug_DEMCR_TRCENA_Pos 24
#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos)

// DWT CTRL 寄存器中的 CYCCNTENA 位定义
#define DWT_CTRL_CYCCNTENA_Pos 0
#define DWT_CTRL_CYCCNTENA_Msk (1UL << DWT_CTRL_CYCCNTENA_Pos)

// 初始化 DWT 周期计数器
void DWT_Init(void) {
    // 启用 DWT 和跟踪功能
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;

    // 重置周期计数器
    DWT->CYCCNT = 0;

    // 启用周期计数器
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}

// 测量函数执行时间
uint32_t Measure_Execution_Time(void (*func)(void)) {
    uint32_t start, end;

    // 记录起始时间
    start = DWT->CYCCNT;

    // 执行目标函数
    func();

    // 记录结束时间
    end = DWT->CYCCNT;

    // 返回周期数
    return end - start;
}

// 周期数转换为时间(单位:微秒)
float CyclesToTime_us(uint32_t cycles, uint32_t cpu_freq) {
    return (float)cycles / (float)cpu_freq * 1e6;
}

// 多次执行统计
void Measure_Statistics(void (*func)(void), uint32_t iterations, uint32_t cpu_freq) {
    uint32_t cycles, total_cycles = 0, max_cycles = 0, min_cycles = UINT32_MAX;
    float average_time_us, max_time_us, min_time_us;

    for (uint32_t i = 0; i < iterations; i++) {
        cycles = Measure_Execution_Time(func);

        // 更新总计周期数
        total_cycles += cycles;

        // 更新最大周期数
        if (cycles > max_cycles) {
            max_cycles = cycles;
        }

        // 更新最小周期数
        if (cycles < min_cycles) {
            min_cycles = cycles;
        }
    }

    // 计算平均时间
    average_time_us = CyclesToTime_us(total_cycles / iterations, cpu_freq);
    max_time_us = CyclesToTime_us(max_cycles, cpu_freq);
    min_time_us = CyclesToTime_us(min_cycles, cpu_freq);

    // 打印统计结果
    printf("执行次数: %lu\n", iterations);
    printf("平均时间: %.2f us\n", average_time_us);
    printf("最长时间: %.2f us\n", max_time_us);
    printf("最短时间: %.2f us\n", min_time_us);
}

// 示例目标函数
void Sample_Function(void) {
    for (volatile int i = 0; i < 1000; i++);
}

int main(void) {
    uint32_t cpu_freq = 84000000; // 假设 CPU 频率为 84 MHz
    uint32_t iterations = 100;   // 测试运行 100 次

    // 初始化 DWT
    DWT_Init();

    // 统计 Sample_Function 的执行时间
    Measure_Statistics(Sample_Function, iterations, cpu_freq);

    while (1);
}
3. 功能解释

  • 初始化 DWT 模块

    • 通过寄存器直接操作,启用周期计数器。
    • 清零 CYCCNT 寄存器。
  • 测量单次执行时间

    • 使用 Measure_Execution_Time 函数记录代码片段的开始和结束时钟周期数。
  • 统计多次执行结果

    • 在 Measure_Statistics 中进行多次测试,记录总周期数、最大周期数和最小周期数。
    • 根据 CPU 时钟频率,将周期数转换为时间。
  • 显示统计结果

    • 打印平均时间、最长时间和最短时间,帮助用户全面评估代码性能。


4. 总结

通过 DWT 的周期计数器,可以实现高精度的代码性能分析。结合多次统计功能,开发者可以更全面地评估代码效率,为优化提供依据。本文提供的实现方案基于寄存器操作,适用于所有支持 DWT 的 ARM Cortex-M4 核心微控制器。





使用特权

评论回复
沙发
呐咯密密| | 2024-12-10 18:36 | 只看该作者
以前都是用一个IO的高低电平配合示波器测量的,这个挺好,调试的时候很方便

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

37

主题

40

帖子

0

粉丝