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

[复制链接]
856|1
 楼主| a976209770 发表于 2024-12-9 15:12 | 显示全部楼层 |阅读模式
1. 引言

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

2. 示例代码

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

  2. // DWT 和 Core Debug 基地址
  3. #define DWT_BASE       0xE0001000UL
  4. #define DWT            ((DWT_Type *)DWT_BASE)
  5. #define CoreDebug_BASE 0xE000EDF0UL
  6. #define CoreDebug      ((CoreDebug_Type *)CoreDebug_BASE)

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

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

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

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

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

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

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

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

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

  41.     // 执行目标函数
  42.     func();

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

  45.     // 返回周期数
  46.     return end - start;
  47. }

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

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

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

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

  60.         // 更新最大周期数
  61.         if (cycles > max_cycles) {
  62.             max_cycles = cycles;
  63.         }

  64.         // 更新最小周期数
  65.         if (cycles < min_cycles) {
  66.             min_cycles = cycles;
  67.         }
  68.     }

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

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

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

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

  86.     // 初始化 DWT
  87.     DWT_Init();

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

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

  • 初始化 DWT 模块

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

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

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

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


4. 总结

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





呐咯密密 发表于 2024-12-10 18:36 | 显示全部楼层
以前都是用一个IO的高低电平配合示波器测量的,这个挺好,调试的时候很方便
您需要登录后才可以回帖 登录 | 注册

本版积分规则

40

主题

43

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部