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 核心微控制器。
|