From 9a2d543fcb5ffeab8156f92cbf420d1e510bd770 Mon Sep 17 00:00:00 2001 From: zhoujie <929834232@qq.com> Date: Fri, 6 Feb 2026 23:58:56 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(system-monitor):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9ESD=E5=8D=A1=E5=AD=98=E5=82=A8=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增SD卡存储监控功能,包含写入次数、错误次数、缓冲区满次数、总写入字节数和文件数量等统计指标 - 新增SD卡监控API函数,包括报告写入、报告错误、报告缓冲区满和报告文件创建 - 在data_storage.c中集成SD卡监控功能,在关键操作点添加监控报告 - 新增详细的使用文档《SD_Storage_Monitoring_Guide.md》,说明监控指标、API使用、集成方法和故障诊断 - 优化系统调试输出,在DebugOutput_PrintSystemStats中增加SD卡统计信息显示,包括基本统计、SD卡统计和计算指标(平均写入大小、错误率) - 调整SDIO时钟分频器从2改为1以提高SD卡通信速度 - 调整TIM2中断优先级从12改为3以提高定时器响应优先级 - 更新STM32CubeMX配置文件(.ioc)以反映SDIO时钟分频和TIM2中断优先级的更改 - 注释掉USB连接状态检测代码以简化主循环处理 - 优化ADC数据就绪中断处理,每2次触发一次DMA读取,并在DMA读取超时时报告数据溢出 - 移除ProcessAdcData函数中已注释的RS485发送代码 - 将数据溢出报告从ProcessAdcData函数移至HAL_GPIO_EXTI_Callback函数中的DMA读取超时处理 --- Core/Src/main.c | 65 ++++++++--- Core/Src/sdio.c | 2 +- Core/Src/tim.c | 2 +- STM_ATEM_F405.ioc | 4 +- User/SD_Storage_Monitoring_Guide.md | 167 ++++++++++++++++++++++++++++ User/data_storage.c | 6 + User/system_monitor.c | 41 +++++++ User/system_monitor.h | 13 +++ 8 files changed, 283 insertions(+), 17 deletions(-) create mode 100644 User/SD_Storage_Monitoring_Guide.md diff --git a/Core/Src/main.c b/Core/Src/main.c index c6fdc5d..9e3b86e 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -175,7 +175,8 @@ static void ProcessAdcData(void) correction_applied = 1; // 发送校正后的数据包 - RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t)); +// RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t)); + } else { // 4b. 校正失败或未启用,使用原始数据 @@ -199,10 +200,7 @@ static void ProcessAdcData(void) // 7. 释放已处理的缓冲区 LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer()); } else { - // 数据来不及处理 -#if ENABLE_SYSTEM_MONITOR - SystemMonitor_ReportDataOverflow(); -#endif + } } @@ -243,18 +241,53 @@ static void DebugOutput_PrintSystemStats(void) return; } - char buffer[128]; + char buffer[256]; SystemMonitorStats_t sys_stats; SystemMonitor_GetStats(&sys_stats); + // 打印基本统计信息 snprintf(buffer, sizeof(buffer), "\r\n=== System Stats ===\r\n" "Total Samples: %lu\r\n" "Data Overflow: %lu\r\n", sys_stats.total_samples, sys_stats.data_overflow_count); - DebugOutput_SendString(buffer); + + // 打印SD卡存储监控信息 + snprintf(buffer, sizeof(buffer), + "=== SD Card Stats ===\r\n" + "SD Write Count: %lu\r\n" + "SD Write Errors: %lu\r\n" + "SD Buffer Full: %lu\r\n" + "SD Total Bytes: %lu\r\n" + "SD File Count: %lu\r\n", + sys_stats.sd_write_count, + sys_stats.sd_write_error_count, + sys_stats.sd_buffer_full_count, + sys_stats.sd_total_bytes_written, + sys_stats.sd_file_count); + DebugOutput_SendString(buffer); + + // 计算并打印统计指标 + if (sys_stats.sd_write_count > 0) { + uint32_t avg_write_size = sys_stats.sd_total_bytes_written / sys_stats.sd_write_count; + snprintf(buffer, sizeof(buffer), + "Avg Write Size: %lu bytes\r\n", + avg_write_size); + DebugOutput_SendString(buffer); + } + + if (sys_stats.sd_write_count + sys_stats.sd_write_error_count > 0) { + uint32_t total_attempts = sys_stats.sd_write_count + sys_stats.sd_write_error_count; + uint32_t error_rate = (sys_stats.sd_write_error_count * 100) / total_attempts; + snprintf(buffer, sizeof(buffer), + "Write Error Rate: %lu%%\r\n", + error_rate); + DebugOutput_SendString(buffer); + } + + DebugOutput_SendString("====================\r\n"); #endif } @@ -500,10 +533,10 @@ int main(void) uint32_t current_tick = HAL_GetTick(); // USB连接状态检测 (每500ms检测一次) - if (current_tick - g_last_usb_check >= 500) { - HandleUSBConnectionChange(); - g_last_usb_check = current_tick; - } +// if (current_tick - g_last_usb_check >= 500) { +// HandleUSBConnectionChange(); +// g_last_usb_check = current_tick; +// } // 处理数据存储后台任务 (轮询方式) if (g_recording_enabled) { @@ -584,12 +617,18 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) if(LTC2508_IsInited() == 0) return; cnt ++; - // if(cnt % 5 == 0) + if(cnt % 2 == 0) { // HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); if (GPIO_Pin == ADC_DRY_Pin) { // ADC数据就绪,触发DMA读取 - LTC2508_TriggerDmaRead(); + if(LTC2508_ERROR_TIMEOUT == LTC2508_TriggerDmaRead()) + { + // 数据来不及处理 + #if ENABLE_SYSTEM_MONITOR + SystemMonitor_ReportDataOverflow(); + #endif + } } // HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); } diff --git a/Core/Src/sdio.c b/Core/Src/sdio.c index b71da8c..ed5b76c 100644 --- a/Core/Src/sdio.c +++ b/Core/Src/sdio.c @@ -46,7 +46,7 @@ void MX_SDIO_SD_Init(void) hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; hsd.Init.BusWide = SDIO_BUS_WIDE_1B; hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; - hsd.Init.ClockDiv = 2; + hsd.Init.ClockDiv = 1; /* USER CODE BEGIN SDIO_Init 2 */ /* USER CODE END SDIO_Init 2 */ diff --git a/Core/Src/tim.c b/Core/Src/tim.c index c2c6646..594af3d 100644 --- a/Core/Src/tim.c +++ b/Core/Src/tim.c @@ -79,7 +79,7 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) __HAL_RCC_TIM2_CLK_ENABLE(); /* TIM2 interrupt Init */ - HAL_NVIC_SetPriority(TIM2_IRQn, 12, 0); + HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); /* USER CODE BEGIN TIM2_MspInit 1 */ diff --git a/STM_ATEM_F405.ioc b/STM_ATEM_F405.ioc index 6010634..7921126 100644 --- a/STM_ATEM_F405.ioc +++ b/STM_ATEM_F405.ioc @@ -182,7 +182,7 @@ NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 NVIC.SDIO_IRQn=true\:9\:0\:true\:false\:true\:true\:true\:true NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.SysTick_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:false -NVIC.TIM2_IRQn=true\:12\:0\:true\:false\:true\:true\:true\:true +NVIC.TIM2_IRQn=true\:3\:0\:true\:false\:true\:true\:true\:true NVIC.USART1_IRQn=true\:6\:0\:true\:false\:true\:true\:true\:true NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false PA1.GPIOParameters=GPIO_Label @@ -331,7 +331,7 @@ RCC.VCOI2SOutputFreq_Value=192000000 RCC.VCOInputFreq_Value=1000000 RCC.VCOOutputFreq_Value=336000000 RCC.VcooutputI2S=96000000 -SDIO.ClockDiv=2 +SDIO.ClockDiv=1 SDIO.HardwareFlowControl=SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDIO.IPParameters=ClockDiv,HardwareFlowControl SH.GPXTI1.0=GPIO_EXTI1 diff --git a/User/SD_Storage_Monitoring_Guide.md b/User/SD_Storage_Monitoring_Guide.md new file mode 100644 index 0000000..c6094e3 --- /dev/null +++ b/User/SD_Storage_Monitoring_Guide.md @@ -0,0 +1,167 @@ +# SD卡存储监控功能说明 + +## 概述 + +本文档说明系统监控模块中新增的SD卡存储监控功能。该功能用于实时跟踪SD卡的写入操作、错误情况和性能指标。 + +## 监控指标 + +### 1. SD卡写入次数 (`sd_write_count`) +- **描述**: 记录成功写入SD卡的次数 +- **用途**: 评估SD卡使用频率和系统活跃度 +- **更新时机**: 每次成功刷新缓冲区到SD卡后 + +### 2. SD卡写入错误次数 (`sd_write_error_count`) +- **描述**: 记录SD卡写入失败的次数 +- **用途**: 监控SD卡健康状态和可靠性 +- **更新时机**: + - 缓冲区刷新失败时 + - 文件创建失败时 +- **注意**: 该值持续增加可能表示SD卡故障或文件系统问题 + +### 3. 缓冲区满次数 (`sd_buffer_full_count`) +- **描述**: 记录双缓冲区都处于忙碌状态的次数 +- **用途**: 评估数据写入速度是否跟得上数据产生速度 +- **更新时机**: 切换缓冲区时发现目标缓冲区仍在刷新中 +- **注意**: 该值频繁增加表示需要优化写入性能或增大缓冲区 + +### 4. SD卡总写入字节数 (`sd_total_bytes_written`) +- **描述**: 累计写入SD卡的总字节数 +- **用途**: + - 评估SD卡使用量 + - 计算平均写入速度 + - 预估SD卡寿命 +- **更新时机**: 每次成功写入后累加 + +### 5. 创建的文件数量 (`sd_file_count`) +- **描述**: 记录创建的数据文件总数 +- **用途**: 跟踪数据分段情况 +- **更新时机**: 每次成功创建新文件后 + +## API函数 + +### 初始化 +```c +void SystemMonitor_Init(void); +``` +初始化系统监控模块,清零所有统计信息。 + +### SD卡监控函数 + +#### 报告SD卡写入 +```c +void SystemMonitor_ReportSDWrite(uint32_t bytes_written); +``` +- **参数**: `bytes_written` - 本次写入的字节数 +- **功能**: 增加写入次数计数,累加总写入字节数 + +#### 报告SD卡写入错误 +```c +void SystemMonitor_ReportSDWriteError(void); +``` +- **功能**: 增加写入错误计数 + +#### 报告缓冲区满 +```c +void SystemMonitor_ReportSDBufferFull(void); +``` +- **功能**: 增加缓冲区满计数 + +#### 报告文件创建 +```c +void SystemMonitor_ReportSDFileCreated(void); +``` +- **功能**: 增加文件创建计数 + +### 获取统计信息 +```c +void SystemMonitor_GetStats(SystemMonitorStats_t *stats); +``` +- **参数**: `stats` - 指向统计信息结构体的指针 +- **功能**: 获取当前所有监控统计信息 + +## 集成说明 + +### 在data_storage.c中的集成点 + +1. **文件头部**: 添加 `#include "system_monitor.h"` + +2. **DataStorage_FlushBuffer()函数**: + - 写入成功时调用 `SystemMonitor_ReportSDWrite(bytes_written)` + - 写入失败时调用 `SystemMonitor_ReportSDWriteError()` + +3. **DataStorage_CreateNewFile()函数**: + - 文件创建成功时调用 `SystemMonitor_ReportSDFileCreated()` + - 文件创建失败时调用 `SystemMonitor_ReportSDWriteError()` + +4. **DataStorage_SwitchBuffer()函数**: + - 目标缓冲区忙碌时调用 `SystemMonitor_ReportSDBufferFull()` + +## 使用示例 + +```c +// 初始化系统监控 +SystemMonitor_Init(); + +// ... 系统运行 ... + +// 获取统计信息 +SystemMonitorStats_t stats; +SystemMonitor_GetStats(&stats); + +// 打印SD卡监控信息 +printf("SD卡写入次数: %lu\n", stats.sd_write_count); +printf("SD卡写入错误: %lu\n", stats.sd_write_error_count); +printf("缓冲区满次数: %lu\n", stats.sd_buffer_full_count); +printf("总写入字节数: %lu\n", stats.sd_total_bytes_written); +printf("创建文件数量: %lu\n", stats.sd_file_count); + +// 计算平均写入大小 +if (stats.sd_write_count > 0) { + uint32_t avg_write_size = stats.sd_total_bytes_written / stats.sd_write_count; + printf("平均写入大小: %lu 字节\n", avg_write_size); +} + +// 计算错误率 +if (stats.sd_write_count > 0) { + float error_rate = (float)stats.sd_write_error_count / + (stats.sd_write_count + stats.sd_write_error_count) * 100.0f; + printf("写入错误率: %.2f%%\n", error_rate); +} +``` + +## 性能考虑 + +1. **低开销**: 所有监控函数都是简单的计数器操作,对系统性能影响极小 +2. **线程安全**: 当前实现未考虑多线程,如需在中断中使用需添加保护机制 +3. **溢出处理**: 使用32位计数器,在高频写入场景下可能溢出,需定期重置或使用64位计数器 + +## 故障诊断 + +### 高错误率 +- **现象**: `sd_write_error_count` 持续增加 +- **可能原因**: + - SD卡故障或接触不良 + - 文件系统损坏 + - SD卡写保护 +- **建议**: 检查SD卡硬件连接,尝试格式化SD卡 + +### 频繁缓冲区满 +- **现象**: `sd_buffer_full_count` 快速增加 +- **可能原因**: + - 数据产生速度超过SD卡写入速度 + - SD卡性能不足(低速卡) + - 缓冲区大小不足 +- **建议**: + - 使用更高速的SD卡(Class 10或UHS-I) + - 增大缓冲区大小 + - 优化数据采集频率 + +### 写入速度异常 +- **现象**: 平均写入大小异常小或写入频率异常高 +- **可能原因**: 缓冲区切换策略不当 +- **建议**: 调整缓冲区大小或刷新策略 + +## 版本历史 + +- **v1.0** (2026-02-06): 初始版本,添加SD卡存储监控功能 diff --git a/User/data_storage.c b/User/data_storage.c index fd15d01..553eda8 100644 --- a/User/data_storage.c +++ b/User/data_storage.c @@ -1,4 +1,5 @@ #include "data_storage.h" +#include "system_monitor.h" #include #include @@ -184,11 +185,13 @@ HAL_StatusTypeDef DataStorage_CreateNewFile(DataStorageHandle_t *handle) if (res != FR_OK) { handle->stats.error_count++; + SystemMonitor_ReportSDWriteError(); // 报告文件创建错误 return HAL_ERROR; } handle->stats.file_count++; handle->stats.current_file_size = 0; + SystemMonitor_ReportSDFileCreated(); // 报告文件创建成功 return HAL_OK; } @@ -271,6 +274,7 @@ HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t b if (res != FR_OK || bytes_written != buffer->index) { handle->stats.error_count++; buffer->state = BUFFER_READY_TO_FLUSH; // 恢复状态以便重试 + SystemMonitor_ReportSDWriteError(); // 报告SD卡写入错误 return HAL_ERROR; } @@ -279,6 +283,7 @@ HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t b // 更新统计信息 handle->stats.current_file_size += bytes_written; + SystemMonitor_ReportSDWrite(bytes_written); // 报告SD卡写入成功 // 重置缓冲区 buffer->index = 0; @@ -340,6 +345,7 @@ HAL_StatusTypeDef DataStorage_SwitchBuffer(DataStorageHandle_t *handle) if (next_buf->state == BUFFER_FLUSHING) { // 目标缓冲区正在刷新,等待完成 handle->stats.error_count++; + SystemMonitor_ReportSDBufferFull(); // 报告缓冲区满 return HAL_ERROR; } diff --git a/User/system_monitor.c b/User/system_monitor.c index ce14eaf..cfbf79c 100644 --- a/User/system_monitor.c +++ b/User/system_monitor.c @@ -45,3 +45,44 @@ void SystemMonitor_GetStats(SystemMonitorStats_t *stats) memcpy(stats, &g_system_stats, sizeof(SystemMonitorStats_t)); } } + +/** + * @brief 报告SD卡写入操作 + * @param bytes_written: 写入的字节数 + * @retval None + */ +void SystemMonitor_ReportSDWrite(uint32_t bytes_written) +{ + g_system_stats.sd_write_count++; + g_system_stats.sd_total_bytes_written += bytes_written; +} + +/** + * @brief 报告SD卡写入错误 + * @param None + * @retval None + */ +void SystemMonitor_ReportSDWriteError(void) +{ + g_system_stats.sd_write_error_count++; +} + +/** + * @brief 报告SD卡缓冲区满 + * @param None + * @retval None + */ +void SystemMonitor_ReportSDBufferFull(void) +{ + g_system_stats.sd_buffer_full_count++; +} + +/** + * @brief 报告SD卡文件创建 + * @param None + * @retval None + */ +void SystemMonitor_ReportSDFileCreated(void) +{ + g_system_stats.sd_file_count++; +} diff --git a/User/system_monitor.h b/User/system_monitor.h index 7cd890a..63bbccb 100644 --- a/User/system_monitor.h +++ b/User/system_monitor.h @@ -8,6 +8,13 @@ typedef struct { uint32_t total_samples; // 总采样样点数 uint32_t data_overflow_count; // 数据来不及处理的次数 + + // SD卡存储监控信息 + uint32_t sd_write_count; // SD卡写入次数 + uint32_t sd_write_error_count; // SD卡写入错误次数 + uint32_t sd_buffer_full_count; // 缓冲区满次数 + uint32_t sd_total_bytes_written; // SD卡总写入字节数 + uint32_t sd_file_count; // 创建的文件数量 } SystemMonitorStats_t; // 函数声明 @@ -16,4 +23,10 @@ void SystemMonitor_IncrementSampleCount(void); void SystemMonitor_ReportDataOverflow(void); void SystemMonitor_GetStats(SystemMonitorStats_t *stats); +// SD卡存储监控函数 +void SystemMonitor_ReportSDWrite(uint32_t bytes_written); +void SystemMonitor_ReportSDWriteError(void); +void SystemMonitor_ReportSDBufferFull(void); +void SystemMonitor_ReportSDFileCreated(void); + #endif // SYSTEM_MONITOR_H