- 新增性能监控模块(performance_monitor),用于实时跟踪系统性能指标 - 添加串口调试输出功能,支持系统状态和性能统计的定期输出 - 实现双缓冲机制,提升ADC数据采集和存储的实时性 - 优化数据存储模块,支持校正后数据的存储和双缓冲管理 - 增强错误处理机制,完善中断回调函数和系统错误恢复 ♻️ refactor(ltc2508): 重构ADC驱动支持双缓冲 - 将ADC数据存储从单缓冲区重构为双缓冲区结构 - 新增缓冲区状态管理和自动切换机制 - 优化DMA传输完成回调,支持多缓冲区处理 - 提供缓冲区获取和释放的API接口 📝 docs(performance): 新增性能评估报告和使用指南 - 创建STM32F405性能评估报告,详细分析系统性能指标 - 编写双缓冲机制使用指南,说明实现原理和使用方法 - 添加LTC2508驱动使用示例代码 🐛 fix(dma): 调整DMA中断优先级 - 将DMA2_Stream7中断优先级从9调整为6,优化中断响应 - 更新STM32CubeMX配置文件中的中断优先级设置 🔧 chore(config): 优化系统配置和代码结构 - 添加串口调试输出控制开关和间隔配置 - 清理中断处理文件,移除重复的回调函数定义 - 增强错误处理函数,添加系统状态恢复机制
193 lines
5.3 KiB
C
193 lines
5.3 KiB
C
#include "performance_monitor.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
// 静态变量
|
|
static SystemPerfStats_t g_perf_stats = {0};
|
|
static uint32_t g_task_start_time[PERF_MON_MAX_TASKS] = {0};
|
|
static uint8_t g_task_active[PERF_MON_MAX_TASKS] = {0};
|
|
|
|
// 外部符号声明 (用于堆栈监控)
|
|
extern uint32_t _estack;
|
|
extern uint32_t _Min_Stack_Size;
|
|
|
|
/**
|
|
* @brief 初始化性能监控模块
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void PerformanceMonitor_Init(void)
|
|
{
|
|
memset(&g_perf_stats, 0, sizeof(SystemPerfStats_t));
|
|
memset(g_task_start_time, 0, sizeof(g_task_start_time));
|
|
memset(g_task_active, 0, sizeof(g_task_active));
|
|
|
|
g_perf_stats.sample_period_ms = PERF_MON_SAMPLE_PERIOD_MS;
|
|
g_perf_stats.last_update_tick = HAL_GetTick();
|
|
|
|
// 初始化最小执行时间为最大值
|
|
for (int i = 0; i < PERF_MON_MAX_TASKS; i++) {
|
|
g_perf_stats.tasks[i].min_time_us = UINT32_MAX;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief 开始任务性能监控
|
|
* @param task_id: 任务ID
|
|
* @retval None
|
|
*/
|
|
void PerformanceMonitor_TaskStart(PerfTaskID_t task_id)
|
|
{
|
|
if (task_id >= PERF_MON_MAX_TASKS) return;
|
|
|
|
g_task_start_time[task_id] = HAL_GetTick() * 1000; // 转换为微秒
|
|
g_task_active[task_id] = 1;
|
|
}
|
|
|
|
/**
|
|
* @brief 结束任务性能监控
|
|
* @param task_id: 任务ID
|
|
* @retval None
|
|
*/
|
|
void PerformanceMonitor_TaskEnd(PerfTaskID_t task_id)
|
|
{
|
|
if (task_id >= PERF_MON_MAX_TASKS || !g_task_active[task_id]) return;
|
|
|
|
uint32_t end_time = HAL_GetTick() * 1000; // 转换为微秒
|
|
uint32_t execution_time = end_time - g_task_start_time[task_id];
|
|
|
|
TaskPerfStats_t *task_stats = &g_perf_stats.tasks[task_id];
|
|
|
|
// 更新统计信息
|
|
task_stats->total_time_us += execution_time;
|
|
task_stats->call_count++;
|
|
|
|
// 更新最大最小时间
|
|
if (execution_time > task_stats->max_time_us) {
|
|
task_stats->max_time_us = execution_time;
|
|
}
|
|
if (execution_time < task_stats->min_time_us) {
|
|
task_stats->min_time_us = execution_time;
|
|
}
|
|
|
|
// 计算平均时间
|
|
task_stats->avg_time_us = task_stats->total_time_us / task_stats->call_count;
|
|
|
|
g_task_active[task_id] = 0;
|
|
}
|
|
|
|
/**
|
|
* @brief 更新性能监控统计
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void PerformanceMonitor_Update(void)
|
|
{
|
|
uint32_t current_tick = HAL_GetTick();
|
|
|
|
// 检查是否到了更新周期
|
|
if (current_tick - g_perf_stats.last_update_tick < g_perf_stats.sample_period_ms) {
|
|
return;
|
|
}
|
|
|
|
// 计算CPU使用率
|
|
uint32_t total_cpu_time = 0;
|
|
for (int i = 0; i < PERF_MON_MAX_TASKS; i++) {
|
|
if (g_perf_stats.tasks[i].call_count > 0) {
|
|
// 计算每个任务的CPU使用率
|
|
uint32_t task_time_per_period = g_perf_stats.tasks[i].avg_time_us *
|
|
(1000 / g_perf_stats.sample_period_ms);
|
|
g_perf_stats.tasks[i].cpu_usage_percent =
|
|
(float)task_time_per_period / 10000.0f; // 转换为百分比
|
|
|
|
total_cpu_time += task_time_per_period;
|
|
}
|
|
}
|
|
|
|
// 更新总CPU使用率
|
|
g_perf_stats.total_cpu_usage_percent = total_cpu_time / 100;
|
|
|
|
// 更新内存使用情况
|
|
g_perf_stats.free_heap_size = PerformanceMonitor_GetFreeHeapSize();
|
|
if (g_perf_stats.min_free_heap_size == 0 ||
|
|
g_perf_stats.free_heap_size < g_perf_stats.min_free_heap_size) {
|
|
g_perf_stats.min_free_heap_size = g_perf_stats.free_heap_size;
|
|
}
|
|
|
|
// 更新栈使用率
|
|
g_perf_stats.stack_usage_percent = PerformanceMonitor_GetStackUsage();
|
|
|
|
g_perf_stats.last_update_tick = current_tick;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取性能统计信息
|
|
* @param stats: 统计信息结构体指针
|
|
* @retval None
|
|
*/
|
|
void PerformanceMonitor_GetStats(SystemPerfStats_t *stats)
|
|
{
|
|
if (stats != NULL) {
|
|
memcpy(stats, &g_perf_stats, sizeof(SystemPerfStats_t));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 重置性能统计
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void PerformanceMonitor_ResetStats(void)
|
|
{
|
|
memset(&g_perf_stats, 0, sizeof(SystemPerfStats_t));
|
|
g_perf_stats.sample_period_ms = PERF_MON_SAMPLE_PERIOD_MS;
|
|
g_perf_stats.last_update_tick = HAL_GetTick();
|
|
|
|
// 重新初始化最小执行时间
|
|
for (int i = 0; i < PERF_MON_MAX_TASKS; i++) {
|
|
g_perf_stats.tasks[i].min_time_us = UINT32_MAX;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 获取空闲堆内存大小
|
|
* @param None
|
|
* @retval 空闲堆内存大小(字节)
|
|
*/
|
|
uint32_t PerformanceMonitor_GetFreeHeapSize(void)
|
|
{
|
|
// 简单的堆内存检测方法
|
|
// 在实际应用中,可能需要更复杂的内存管理
|
|
void *ptr = malloc(1);
|
|
if (ptr != NULL) {
|
|
free(ptr);
|
|
// 这里返回一个估算值,实际项目中需要更精确的实现
|
|
return 32768; // 假设有32KB空闲堆内存
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取栈使用率
|
|
* @param None
|
|
* @retval 栈使用率百分比
|
|
*/
|
|
uint32_t PerformanceMonitor_GetStackUsage(void)
|
|
{
|
|
// 获取当前栈指针
|
|
uint32_t current_sp;
|
|
__asm volatile ("mov %0, sp" : "=r" (current_sp));
|
|
|
|
// 计算栈使用量
|
|
uint32_t stack_top = (uint32_t)&_estack;
|
|
uint32_t min_stack_size = (uint32_t)&_Min_Stack_Size;
|
|
uint32_t stack_used = stack_top - current_sp;
|
|
|
|
// 计算使用率百分比
|
|
if (min_stack_size > 0) {
|
|
return (stack_used * 100) / min_stack_size;
|
|
}
|
|
|
|
return 0;
|
|
} |