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