feat(monitor): 增强系统监控与数据存储功能

- 新增数据存储缓冲区可用性检查,防止缓冲区满时数据丢失
- 新增会话文件夹管理功能,每次上电自动创建新的数据存储文件夹
- 新增监控状态定期保存功能,将系统统计信息写入MONITOR.TXT文件
- 新增数据丢弃统计,记录因缓冲区满而未存储的数据包数量
- 优化数据输出模式配置,支持串口输出和存储到卡的独立控制
- 优化USB连接处理逻辑,增加系统稳定性检查

🐛 fix(interrupt): 调整中断优先级配置

- 提高USART1中断优先级(从6调整为2),确保串口通信及时响应
- 调整DMA2_Stream5中断优先级(从0调整为5),优化数据传输调度
- 修复RS485驱动中的忙标志逻辑,改为阻塞式传输以提高可靠性

♻️ refactor(config): 优化系统配置和存储设置

- 重构宏定义配置,统一系统监控开关,分离数据输出模式控制
- 将SD卡最大扇区大小从512调整为4096,优化大文件存储性能
- 增加堆栈大小配置(从0x800调整为0x1000),提高系统稳定性
- 优化USB存储读写超时设置,使用最大超时值确保操作完成

📝 docs(comments): 更新代码注释和文档

- 更新数据存储模块的注释,说明新的会话文件夹管理机制
- 在main.c中添加数据输出模式选择的详细说明注释
- 更新系统监控统计输出格式,包含新增的数据丢弃统计项
This commit is contained in:
zhoujie 2026-02-07 13:02:59 +08:00
parent 8a928032dd
commit 5419e33397
12 changed files with 577 additions and 217 deletions

View File

@ -57,7 +57,7 @@ void MX_DMA_Init(void)
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 10, 0); HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 10, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
/* DMA2_Stream5_IRQn interrupt configuration */ /* DMA2_Stream5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0); HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn); HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
/* DMA2_Stream6_IRQn interrupt configuration */ /* DMA2_Stream6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 10, 0); HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 10, 0);

View File

@ -46,12 +46,15 @@
/* Private define ------------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */ /* USER CODE BEGIN PD */
// 串口输出控制开关 // 监控功能宏开关(统一控制串口输出和文件存储)
#define ENABLE_UART_DEBUG_OUTPUT 1
#define DEBUG_OUTPUT_INTERVAL_MS 1000 // 调试输出间隔(毫秒)
// 监控功能宏开关
#define ENABLE_SYSTEM_MONITOR 1 // 系统监控开关 #define ENABLE_SYSTEM_MONITOR 1 // 系统监控开关
#define DEBUG_OUTPUT_INTERVAL_MS 1000 // 调试输出间隔(毫秒)
#define MONITOR_SAVE_INTERVAL_MS 10000 // 监控状态保存间隔(毫秒) - 10秒
// 数据输出模式选择(可以同时启用)
#define DATA_OUTPUT_MODE_UART 0 // 0=禁用, 1=启用串口输出数据
#define DATA_OUTPUT_MODE_STORAGE 1 // 0=禁用, 1=启用存储到卡
// 注意:两个模式可以同时启用,但会增加系统负载
/* USER CODE END PD */ /* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/
@ -87,7 +90,9 @@ static uint32_t g_last_usb_check = 0;
// 性能监控和调试输出 // 性能监控和调试输出
static uint32_t g_last_debug_output = 0; static uint32_t g_last_debug_output = 0;
static uint8_t g_debug_output_enabled = ENABLE_UART_DEBUG_OUTPUT;
// 监控状态保存
static uint32_t g_last_monitor_save = 0;
/* USER CODE END PV */ /* USER CODE END PV */
@ -147,6 +152,13 @@ static void ProcessAdcData(void)
LTC2508_BufferTypeDef *ready_buffer = NULL; LTC2508_BufferTypeDef *ready_buffer = NULL;
if (LTC2508_GetReadyBuffer(&ready_buffer) == LTC2508_OK && ready_buffer != NULL) if (LTC2508_GetReadyBuffer(&ready_buffer) == LTC2508_OK && ready_buffer != NULL)
{ {
// 检查存储缓冲区是否可用(用于决定是否存储数据)
uint8_t can_store_data = 0;
if (g_recording_enabled) {
uint32_t max_packet_size = sizeof(CorrectedDataPacket_t);
can_store_data = DataStorage_IsBufferAvailable(&g_data_storage, max_packet_size);
}
#if ENABLE_SYSTEM_MONITOR #if ENABLE_SYSTEM_MONITOR
SystemMonitor_IncrementSampleCount(); SystemMonitor_IncrementSampleCount();
#endif #endif
@ -174,28 +186,41 @@ static void ProcessAdcData(void)
correction_applied = 1; correction_applied = 1;
// 发送校正后的数据包 #if DATA_OUTPUT_MODE_UART
// RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t)); // 发送校正后的数据包到串口
RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t));
#endif
} else { } else {
// 4b. 校正失败或未启用,使用原始数据 // 4b. 校正失败或未启用,使用原始数据
PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2]); PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2]);
// 发送原始数据包 #if DATA_OUTPUT_MODE_UART
// 发送原始数据包到串口
RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t)); RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t));
#endif
} }
// 6. 存储数据到SD卡 (如果启用记录) // 6. 存储数据到SD卡 (如果启用记录且缓冲区可用)
#if DATA_OUTPUT_MODE_STORAGE
if (g_recording_enabled) { if (g_recording_enabled) {
if (correction_applied) { if (can_store_data) {
// 存储校正后的数据 if (correction_applied) {
DataStorage_WriteCorrectedData(&g_data_storage, &g_corrected_packet); // 存储校正后的数据
DataStorage_WriteCorrectedData(&g_data_storage, &g_corrected_packet);
} else {
// 存储原始数据
DataStorage_WriteData(&g_data_storage, &g_data_packet);
}
} else { } else {
// 存储原始数据 // 缓冲区满,数据被丢弃
DataStorage_WriteData(&g_data_storage, &g_data_packet); #if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportDataDropped();
#endif
} }
} }
#endif
// 7. 释放已处理的缓冲区 // 7. 释放已处理的缓冲区
LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer()); LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer());
@ -211,9 +236,9 @@ static void ProcessAdcData(void)
static void DebugOutput_Init(void) static void DebugOutput_Init(void)
{ {
// USART3已在MX_USART3_UART_Init()中初始化 // USART3已在MX_USART3_UART_Init()中初始化
if (g_debug_output_enabled) { #if ENABLE_SYSTEM_MONITOR
DebugOutput_SendString("\r\n=== System Debug Output Initialized ===\r\n"); DebugOutput_SendString("\r\n=== System Debug Output Initialized ===\r\n");
} #endif
} }
/** /**
@ -223,11 +248,13 @@ static void DebugOutput_Init(void)
*/ */
static void DebugOutput_SendString(const char* str) static void DebugOutput_SendString(const char* str)
{ {
if (!g_debug_output_enabled || str == NULL) { #if ENABLE_SYSTEM_MONITOR
if (str == NULL) {
return; return;
} }
HAL_UART_Transmit(&huart3, (uint8_t*)str, strlen(str), 100); HAL_UART_Transmit(&huart3, (uint8_t*)str, strlen(str), 100);
#endif
} }
/** /**
@ -237,10 +264,6 @@ static void DebugOutput_SendString(const char* str)
static void DebugOutput_PrintSystemStats(void) static void DebugOutput_PrintSystemStats(void)
{ {
#if ENABLE_SYSTEM_MONITOR #if ENABLE_SYSTEM_MONITOR
if (!g_debug_output_enabled) {
return;
}
char buffer[256]; char buffer[256];
SystemMonitorStats_t sys_stats; SystemMonitorStats_t sys_stats;
SystemMonitor_GetStats(&sys_stats); SystemMonitor_GetStats(&sys_stats);
@ -261,12 +284,14 @@ static void DebugOutput_PrintSystemStats(void)
"SD Write Errors: %lu\r\n" "SD Write Errors: %lu\r\n"
"SD Buffer Full: %lu\r\n" "SD Buffer Full: %lu\r\n"
"SD Total Bytes: %lu\r\n" "SD Total Bytes: %lu\r\n"
"SD File Count: %lu\r\n", "SD File Count: %lu\r\n"
"SD Data Dropped: %lu\r\n",
sys_stats.sd_write_count, sys_stats.sd_write_count,
sys_stats.sd_write_error_count, sys_stats.sd_write_error_count,
sys_stats.sd_buffer_full_count, sys_stats.sd_buffer_full_count,
sys_stats.sd_total_bytes_written, sys_stats.sd_total_bytes_written,
sys_stats.sd_file_count); sys_stats.sd_file_count,
sys_stats.sd_data_dropped_count);
DebugOutput_SendString(buffer); DebugOutput_SendString(buffer);
// 计算并打印统计指标 // 计算并打印统计指标
@ -328,6 +353,12 @@ static void HandleUSBConnectionChange(void)
// 卸载用于采样的文件系统 // 卸载用于采样的文件系统
UnmountFileSystemForSampling(); UnmountFileSystemForSampling();
while(1)
{
;
}
} else { } else {
// USB断开重新挂载文件系统开始数据采集 // USB断开重新挂载文件系统开始数据采集
DebugOutput_SendString("USB Disconnected: Starting data acquisition\r\n"); DebugOutput_SendString("USB Disconnected: Starting data acquisition\r\n");
@ -461,10 +492,6 @@ int main(void)
MX_TIM2_Init(); MX_TIM2_Init();
/* USER CODE BEGIN 2 */ /* USER CODE BEGIN 2 */
// SD_NAND_Init_And_Mount();
// SD_Test_Write();
// SD_Test_Read();
// 初始化系统监控 // 初始化系统监控
#if ENABLE_SYSTEM_MONITOR #if ENABLE_SYSTEM_MONITOR
SystemMonitor_Init(); SystemMonitor_Init();
@ -489,7 +516,7 @@ int main(void)
// 初始化数据存储 // 初始化数据存储
if (DataStorage_Init(&g_data_storage) == HAL_OK) { if (DataStorage_Init(&g_data_storage) == HAL_OK) {
// 开始数据记录 // 开始数据记录
StartRecording(); StartRecording();
} }
} }
} else { } else {
@ -502,6 +529,16 @@ int main(void)
} }
} }
#ifdef NEED_FORMAT_SD
// Raw_Hardware_Test();
// SDNAND_ForceFormat_and_Mount();
Run_SDNAND_SpeedTest_V2();
while(1)
{
;
}
#endif
// 启动TIM2定时器用于1ms周期的ADC数据处理 // 启动TIM2定时器用于1ms周期的ADC数据处理
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) { if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) {
Error_Handler(); Error_Handler();
@ -533,21 +570,34 @@ int main(void)
uint32_t current_tick = HAL_GetTick(); uint32_t current_tick = HAL_GetTick();
// USB连接状态检测 (每500ms检测一次) // USB连接状态检测 (每500ms检测一次)
// if (current_tick - g_last_usb_check >= 500) { if (current_tick - g_last_usb_check >= 500) {
// HandleUSBConnectionChange(); HandleUSBConnectionChange();
// g_last_usb_check = current_tick; g_last_usb_check = current_tick;
// } }
// 处理数据存储后台任务 (轮询方式) // 处理数据存储后台任务 (轮询方式)
// 优化连续处理3次加快缓冲区刷新速度
if (g_recording_enabled) { if (g_recording_enabled) {
DataStorage_ProcessBackgroundTasks(&g_data_storage); // for (int i = 0; i < 3; i++) {
DataStorage_ProcessBackgroundTasks(&g_data_storage);
// }
} }
// 定期输出调试信息 (每1秒输出一次) // 定期输出调试信息 (每1秒输出一次)
if (g_debug_output_enabled && (current_tick - g_last_debug_output >= DEBUG_OUTPUT_INTERVAL_MS)) { #if ENABLE_SYSTEM_MONITOR
if (current_tick - g_last_debug_output >= DEBUG_OUTPUT_INTERVAL_MS) {
DebugOutput_PrintSystemStats(); DebugOutput_PrintSystemStats();
g_last_debug_output = current_tick; g_last_debug_output = current_tick;
} }
#endif
// 定期保存监控状态 (每1分钟保存一次)
#if ENABLE_SYSTEM_MONITOR
if (current_tick - g_last_monitor_save >= MONITOR_SAVE_INTERVAL_MS) {
SystemMonitor_SaveStatus();
g_last_monitor_save = current_tick;
}
#endif
// ADC采样由PA1外部中断触发不在主循环中触发 // ADC采样由PA1外部中断触发不在主循环中触发
// 可以在这里添加其他低优先级任务 // 可以在这里添加其他低优先级任务
@ -617,7 +667,7 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
if(LTC2508_IsInited() == 0) return; if(LTC2508_IsInited() == 0) return;
cnt ++; cnt ++;
// if(cnt % 2 == 0) // if(cnt % 5 == 0)
{ {
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); // HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
if (GPIO_Pin == ADC_DRY_Pin) { if (GPIO_Pin == ADC_DRY_Pin) {

View File

@ -131,7 +131,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx); __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
/* USART1 interrupt Init */ /* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 6, 0); HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn); HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE BEGIN USART1_MspInit 1 */

View File

@ -175,7 +175,7 @@
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ function will be available. */ / function will be available. */
#define _MIN_SS 512 /* 512, 1024, 2048 or 4096 */ #define _MIN_SS 512 /* 512, 1024, 2048 or 4096 */
#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ #define _MAX_SS 4096 /* 512, 1024, 2048 or 4096 */
/* These options configure the range of sector size to be supported. (512, 1024, /* These options configure the range of sector size to be supported. (512, 1024,
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and / 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
/ harddisk. But a larger value may be required for on-board flash memory and some / harddisk. But a larger value may be required for on-board flash memory and some

View File

@ -89,7 +89,7 @@ Dma.USART1_TX.5.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphData
FATFS.BSP.number=1 FATFS.BSP.number=1
FATFS.IPParameters=_USE_LFN,USE_DMA_CODE_SD,_MAX_SS,_MIN_SS FATFS.IPParameters=_USE_LFN,USE_DMA_CODE_SD,_MAX_SS,_MIN_SS
FATFS.USE_DMA_CODE_SD=1 FATFS.USE_DMA_CODE_SD=1
FATFS._MAX_SS=512 FATFS._MAX_SS=4096
FATFS._MIN_SS=512 FATFS._MIN_SS=512
FATFS._USE_LFN=2 FATFS._USE_LFN=2
FATFS0.BSP.STBoard=false FATFS0.BSP.STBoard=false
@ -167,7 +167,7 @@ NVIC.DMA1_Stream0_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
NVIC.DMA1_Stream3_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true NVIC.DMA1_Stream3_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
NVIC.DMA2_Stream0_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream0_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
NVIC.DMA2_Stream3_IRQn=true\:10\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream3_IRQn=true\:10\:0\:true\:false\:true\:false\:true\:true
NVIC.DMA2_Stream5_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true NVIC.DMA2_Stream5_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
NVIC.DMA2_Stream6_IRQn=true\:10\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream6_IRQn=true\:10\:0\:true\:false\:true\:false\:true\:true
NVIC.DMA2_Stream7_IRQn=true\:12\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream7_IRQn=true\:12\:0\:true\:false\:true\:false\:true\:true
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
@ -183,7 +183,7 @@ 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.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SysTick_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:false NVIC.SysTick_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:false
NVIC.TIM2_IRQn=true\:3\: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.USART1_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
PA1.GPIOParameters=GPIO_Label PA1.GPIOParameters=GPIO_Label
PA1.GPIO_Label=ADC_DRY PA1.GPIO_Label=ADC_DRY
@ -291,7 +291,7 @@ ProjectManager.ProjectFileName=STM_ATEM_F405.ioc
ProjectManager.ProjectName=STM_ATEM_F405 ProjectManager.ProjectName=STM_ATEM_F405
ProjectManager.ProjectStructure= ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack= ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x800 ProjectManager.StackSize=0x1000
ProjectManager.TargetToolchain=STM32CubeIDE ProjectManager.TargetToolchain=STM32CubeIDE
ProjectManager.ToolChainLocation= ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptAfterPath=

View File

@ -290,7 +290,7 @@ int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t bl
// 使用较长的超时时间 (SD NAND 读写较慢) // 使用较长的超时时间 (SD NAND 读写较慢)
uint32_t timeout = 2000; uint32_t timeout = 2000;
if (HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, timeout) != HAL_OK) { if (HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, 0xffff) != HAL_OK) {
return (USBD_FAIL); return (USBD_FAIL);
} }
@ -321,10 +321,10 @@ int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t b
// 修正 3: 增加超时时间,并等待 Busy 结束 // 修正 3: 增加超时时间,并等待 Busy 结束
uint32_t timeout = 5000; // 给 5秒SD NAND 写入由于要擦除/编程,很慢 uint32_t timeout = 5000; // 给 5秒SD NAND 写入由于要擦除/编程,很慢
if (HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, timeout) != HAL_OK) { if (HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, 0xffff) != HAL_OK) {
return (USBD_FAIL); return (USBD_FAIL);
} }
// 【最关键的一步】等待 SD NAND 内部编程结束 // 【最关键的一步】等待 SD NAND 内部编程结束
// 如果没有这一步,文件就会丢失! // 如果没有这一步,文件就会丢失!
uint32_t tickstart = HAL_GetTick(); uint32_t tickstart = HAL_GetTick();

View File

@ -2,6 +2,7 @@
#include "system_monitor.h" #include "system_monitor.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
/** /**
* @brief * @brief
@ -29,9 +30,8 @@ HAL_StatusTypeDef DataStorage_Init(DataStorageHandle_t *handle)
handle->flush_buffer = 1; handle->flush_buffer = 1;
handle->flush_in_progress = 0; handle->flush_in_progress = 0;
// 创建数据存储目录 // 创建新的会话文件夹(每次上电创建新文件夹)
FRESULT res = f_mkdir(DATA_STORAGE_PATH); if (DataStorage_CreateSessionFolder(handle) != HAL_OK) {
if (res != FR_OK && res != FR_EXIST) {
return HAL_ERROR; return HAL_ERROR;
} }
@ -177,10 +177,10 @@ HAL_StatusTypeDef DataStorage_CreateNewFile(DataStorageHandle_t *handle)
return HAL_ERROR; return HAL_ERROR;
} }
// 生成文件名 (基于时间戳) // 生成文件名 (基于时间戳),文件存储在当前会话文件夹中
uint32_t timestamp = HAL_GetTick(); uint32_t timestamp = HAL_GetTick();
snprintf(handle->stats.current_filename, sizeof(handle->stats.current_filename), snprintf(handle->stats.current_filename, sizeof(handle->stats.current_filename),
"%s%s%08lX.dat", DATA_STORAGE_PATH, DATA_STORAGE_FILE_PREFIX, timestamp); "%s%s%08lX.dat", handle->current_session_path, DATA_STORAGE_FILE_PREFIX, timestamp);
// 创建并打开文件 // 创建并打开文件
FRESULT res = f_open(&handle->file, handle->stats.current_filename, FRESULT res = f_open(&handle->file, handle->stats.current_filename,
@ -287,8 +287,7 @@ HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t b
flush_count++; flush_count++;
// 每10次刷新才同步一次或者文件即将达到最大大小时同步 // 每10次刷新才同步一次或者文件即将达到最大大小时同步
// 这样可以显著减少SD卡写入延迟提高吞吐量 if (flush_count % 10 == 0 ||
if (flush_count % 10 == 0 ||
handle->stats.current_file_size + bytes_written >= DATA_STORAGE_FILE_MAX_SIZE) { handle->stats.current_file_size + bytes_written >= DATA_STORAGE_FILE_MAX_SIZE) {
f_sync(&handle->file); f_sync(&handle->file);
} }
@ -368,3 +367,161 @@ HAL_StatusTypeDef DataStorage_SwitchBuffer(DataStorageHandle_t *handle)
return HAL_OK; return HAL_OK;
} }
/**
* @brief
* @param handle:
* @param required_size:
* @retval 1: , 0:
*/
uint8_t DataStorage_IsBufferAvailable(DataStorageHandle_t *handle, uint32_t required_size)
{
if (handle == NULL || !handle->initialized) {
return 0;
}
// 如果未在记录状态,返回不可用
if (handle->stats.state != DATA_STORAGE_RECORDING) {
return 0;
}
DataBuffer_t *active_buf = &handle->buffers[handle->active_buffer];
// 检查当前活动缓冲区是否有足够空间
if (active_buf->index + required_size <= DATA_STORAGE_BUFFER_SIZE) {
return 1; // 当前缓冲区有足够空间
}
// 当前缓冲区空间不足,检查是否可以切换到另一个缓冲区
uint8_t next_buffer = (handle->active_buffer == 0) ? 1 : 0;
DataBuffer_t *next_buf = &handle->buffers[next_buffer];
// 如果另一个缓冲区正在刷新或准备刷新,则不可用
if (next_buf->state == BUFFER_FLUSHING || next_buf->state == BUFFER_READY_TO_FLUSH) {
return 0; // 无法切换,缓冲区不可用
}
// 另一个缓冲区可用
return 1;
}
/**
* @brief
* @param handle:
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_CreateSessionFolder(DataStorageHandle_t *handle)
{
if (handle == NULL) {
return HAL_ERROR;
}
// 从PARAM.TXT加载当前序号
uint32_t session_number = 0;
DataStorage_LoadSessionNumber(&session_number);
// 递增序号
session_number++;
// 生成会话文件夹名(基于序号)
snprintf(handle->current_session_path, sizeof(handle->current_session_path),
"%s/%s%06lu", DATA_STORAGE_BASE_PATH, DATA_STORAGE_FOLDER_PREFIX, session_number);
// 创建基础数据目录(如果不存在)
FRESULT res = f_mkdir(DATA_STORAGE_BASE_PATH);
if (res != FR_OK && res != FR_EXIST) {
return HAL_ERROR;
}
// 创建会话文件夹
res = f_mkdir(handle->current_session_path);
if (res != FR_OK && res != FR_EXIST) {
return HAL_ERROR;
}
// 保存更新后的序号到PARAM.TXT
if (DataStorage_SaveSessionNumber(session_number) != HAL_OK) {
// 即使保存失败,也继续使用该文件夹
// 这不是致命错误
}
return HAL_OK;
}
/**
* @brief
* @param session_number:
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_LoadSessionNumber(uint32_t *session_number)
{
if (session_number == NULL) {
return HAL_ERROR;
}
FIL file;
FRESULT res;
UINT bytes_read;
char buffer[16];
// 打开PARAM.TXT文件
res = f_open(&file, DATA_STORAGE_PARAM_FILE, FA_READ);
if (res != FR_OK) {
// 文件不存在返回初始序号0
*session_number = 0;
return HAL_OK;
}
// 读取序号
res = f_read(&file, buffer, sizeof(buffer) - 1, &bytes_read);
if (res != FR_OK) {
f_close(&file);
*session_number = 0;
return HAL_OK;
}
// 添加字符串结束符
buffer[bytes_read] = '\0';
// 关闭文件
f_close(&file);
// 转换为数字
*session_number = (uint32_t)atoi(buffer);
return HAL_OK;
}
/**
* @brief
* @param session_number:
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef DataStorage_SaveSessionNumber(uint32_t session_number)
{
FIL file;
FRESULT res;
UINT bytes_written;
char buffer[16];
// 创建或覆盖PARAM.TXT文件
res = f_open(&file, DATA_STORAGE_PARAM_FILE, FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK) {
return HAL_ERROR;
}
// 将序号转换为字符串
snprintf(buffer, sizeof(buffer), "%lu", session_number);
// 写入序号
res = f_write(&file, buffer, strlen(buffer), &bytes_written);
if (res != FR_OK || bytes_written != strlen(buffer)) {
f_close(&file);
return HAL_ERROR;
}
// 关闭文件
f_close(&file);
return HAL_OK;
}

View File

@ -11,8 +11,11 @@
// 数据存储配置 // 数据存储配置
#define DATA_STORAGE_BUFFER_SIZE 32768 // 缓冲区大小(字节) #define DATA_STORAGE_BUFFER_SIZE 32768 // 缓冲区大小(字节)
#define DATA_STORAGE_FILE_MAX_SIZE (20*1024*1024) // 单个文件最大20MB #define DATA_STORAGE_FILE_MAX_SIZE (20*1024*1024) // 单个文件最大20MB
#define DATA_STORAGE_PATH "0:/DATA2" // 数据存储路径 #define DATA_STORAGE_BASE_PATH "0:/DATA" // 数据存储基础路径
#define DATA_STORAGE_FILE_PREFIX "/ADC_DATA_" // 文件名前缀 #define DATA_STORAGE_FILE_PREFIX "/ADC_DATA_" // 文件名前缀
#define DATA_STORAGE_FOLDER_PREFIX "SESSION_" // 文件夹名前缀
#define DATA_STORAGE_PARAM_FILE "0:/PARAM.TXT" // 记录会话序号的文件
#define DATA_STORAGE_MAX_PATH_LEN 128 // 最大路径长度
// 缓冲区状态 // 缓冲区状态
typedef enum { typedef enum {
@ -37,7 +40,7 @@ typedef struct {
uint32_t file_count; uint32_t file_count;
uint32_t error_count; uint32_t error_count;
DataStorageState_t state; DataStorageState_t state;
char current_filename[64]; char current_filename[256];
} DataStorageStats_t; } DataStorageStats_t;
// 双缓冲区结构 // 双缓冲区结构
@ -56,6 +59,7 @@ typedef struct {
DataStorageStats_t stats; DataStorageStats_t stats;
uint8_t initialized; uint8_t initialized;
uint8_t flush_in_progress; // 刷新进行中标志 uint8_t flush_in_progress; // 刷新进行中标志
char current_session_path[DATA_STORAGE_MAX_PATH_LEN]; // 当前会话文件夹路径
} DataStorageHandle_t; } DataStorageHandle_t;
// 函数声明 // 函数声明
@ -68,9 +72,19 @@ HAL_StatusTypeDef DataStorage_Flush(DataStorageHandle_t *handle);
void DataStorage_GetStats(DataStorageHandle_t *handle, DataStorageStats_t *stats); void DataStorage_GetStats(DataStorageHandle_t *handle, DataStorageStats_t *stats);
HAL_StatusTypeDef DataStorage_CreateNewFile(DataStorageHandle_t *handle); HAL_StatusTypeDef DataStorage_CreateNewFile(DataStorageHandle_t *handle);
// 文件夹管理函数
HAL_StatusTypeDef DataStorage_CreateSessionFolder(DataStorageHandle_t *handle);
// 序号管理函数
HAL_StatusTypeDef DataStorage_LoadSessionNumber(uint32_t *session_number);
HAL_StatusTypeDef DataStorage_SaveSessionNumber(uint32_t session_number);
// 双缓冲区管理函数 // 双缓冲区管理函数
HAL_StatusTypeDef DataStorage_SwitchBuffer(DataStorageHandle_t *handle); HAL_StatusTypeDef DataStorage_SwitchBuffer(DataStorageHandle_t *handle);
HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t buffer_index); HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t buffer_index);
void DataStorage_ProcessBackgroundTasks(DataStorageHandle_t *handle); void DataStorage_ProcessBackgroundTasks(DataStorageHandle_t *handle);
// 缓冲区可用性检查函数
uint8_t DataStorage_IsBufferAvailable(DataStorageHandle_t *handle, uint32_t required_size);
#endif // DATA_STORAGE_H #endif // DATA_STORAGE_H

View File

@ -19,14 +19,14 @@ HAL_StatusTypeDef RS485_SendData(uint8_t *pData, uint16_t Size)
{ {
HAL_StatusTypeDef ret; HAL_StatusTypeDef ret;
if (g_rs485_tx_busy) // if (g_rs485_tx_busy)
{ // {
return HAL_BUSY; // return HAL_BUSY;
} // }
g_rs485_tx_busy = 1; // g_rs485_tx_busy = 1;
HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_SET); // 设置为发送模式 HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_SET); // 设置为发送模式
ret = HAL_UART_Transmit_IT(g_huart_485, pData, Size); ret = HAL_UART_Transmit(g_huart_485, pData, Size, 0xffff);
// 注意:不能在这里立即切换回接收模式! // 注意:不能在这里立即切换回接收模式!
// DMA传输是非阻塞的需要在传输完成回调中切换 // DMA传输是非阻塞的需要在传输完成回调中切换
@ -34,11 +34,11 @@ HAL_StatusTypeDef RS485_SendData(uint8_t *pData, uint16_t Size)
{ {
// 如果启动DMA失败需要清除忙标志并切换回接收模式 // 如果启动DMA失败需要清除忙标志并切换回接收模式
HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET);
g_rs485_tx_busy = 0; // g_rs485_tx_busy = 0;
} }
// 等待数据传输完成 // 等待数据传输完成
while(g_rs485_tx_busy) // while(g_rs485_tx_busy)
{ {
; ;
} }
@ -52,7 +52,7 @@ void RS485_TxCpltCallback(UART_HandleTypeDef *huart)
if (huart == g_huart_485) if (huart == g_huart_485)
{ {
// DMA传输完成后切换回接收模式 // DMA传输完成后切换回接收模式
HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET); // HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET);
g_rs485_tx_busy = 0; // g_rs485_tx_busy = 0;
} }
} }

View File

@ -1,168 +1,217 @@
/* USER CODE BEGIN Includes */
#include <stdio.h> // 用于 printf 打印调试信息
#include "fatfs.h"
#include "main.h"
#include "dma.h"
#include "fatfs.h"
#include "sdio.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"
#include "main.h"
#include "fatfs.h"
#include "ff.h" #include "ff.h"
#include "data_packet.h" #include "stdio.h"
#include "correction.h" #include "string.h"
#include <stdint.h> #include "main.h" // Ensure huart3 is defined here
/* USER CODE END Includes */ //#define NEED_FORMAT_SD
#ifdef NEED_FORMAT_SD
/* USER CODE BEGIN 4 */ extern UART_HandleTypeDef huart3;
extern SD_HandleTypeDef hsd; // Configuration
//DMA_HandleTypeDef hdma_sdio_rx; #define TEST_FILE_NAME "ST_DATA.BIN"
//DMA_HandleTypeDef hdma_sdio_tx; #define TEST_BUF_SIZE (64 * 1024) // 64KB Buffer (Good for SDIO DMA)
#define TOTAL_TEST_SIZE (16 * 1024 * 1024) // 16MB Total Data
/** // Align buffer to 4 bytes for DMA compatibility
* @brief SD NAND uint8_t g_test_buffer[TEST_BUF_SIZE] __attribute__((aligned(4)));
* @return 0: , -1: char uart_buf[128]; // Buffer for formatting UART messages
*/
int SD_NAND_Init_And_Mount(void) // Helper function to print via UART3
{ void UART3_Print(const char* str) {
HAL_UART_Transmit(&huart3, (uint8_t*)str, strlen(str), 100);
}
void Run_SDNAND_SpeedTest(void) {
FIL file;
FRESULT res; FRESULT res;
BYTE workBuffer[4096]; // f_mkfs 需要的工作缓存 UINT bw, br;
uint32_t startTime, endTime;
float speed;
UART3_Print("\r\n=== SD NAND Speed Test Start ===\r\n");
// Initialize buffer with dummy data
for (uint32_t i = 0; i < TEST_BUF_SIZE; i++) g_test_buffer[i] = (uint8_t)(i % 256);
// 1. 物理层延时SD NAND 内部初始化比普通卡慢 // --- WRITE TEST ---
HAL_Delay(500); res = f_open(&file, TEST_FILE_NAME, FA_CREATE_ALWAYS | FA_WRITE);
// 2. 检查底层 SDIO 是否通了
// 如果这里检测不到,说明硬件接线或 IOC 时钟配置有问题
HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd); // 确认句柄是 hsd1 还是 hsd
if (cardState == HAL_SD_CARD_ERROR) {
printf("Error: SD Card Hardware Not Ready!\r\n");
return -1;
}
// 3. 尝试挂载 (Force Mount = 1)
printf("Attempting to mount SD card...\r\n");
res = f_mount(&SDFatFS, SDPath, 1);
// 4. 分析挂载结果
if (res == FR_OK) {
// 挂载成功,打印容量信息
DWORD free_clusters;
FATFS *fs;
f_getfree(SDPath, &free_clusters, &fs);
uint32_t total_blocks = (fs->n_fatent - 2) * fs->csize;
printf("Mount Success! Total: %lu sectors\r\n", total_blocks);
return 0;
}
// 5. 如果没有文件系统 (新芯片或损坏),执行格式化
else if (res == FR_NO_FILESYSTEM)
{
printf("No Filesystem found. Starting formatting (Legacy Mode)...\r\n");
/* 针对你的 FatFs 版本 (5个参数) 的修正
:
1. path:
2. opt: (FM_FAT32, FM_SFD )
3. au: (Allocation Unit) 4096 SD NAND
4. work:
5. len:
*/
// 确保你的 ff.h 中定义了 FM_FAT32。如果没有尝试用 0x02 代替
BYTE format_opt = FM_FAT32; // 或者 FM_ANY | FM_SFD
// 【关键】针对 SD NAND强制使用 4096 字节的簇大小
DWORD au_size = 512;
// 修正后的函数调用:传入 5 个参数,而不是结构体
res = f_mkfs(SDPath, format_opt, au_size, workBuffer, sizeof(workBuffer));
if (res == FR_OK) {
printf("Format Successful! Remounting...\r\n");
// 格式化后建议取消挂载再重新挂载
f_mount(NULL, SDPath, 0);
res = f_mount(&SDFatFS, SDPath, 1);
if (res == FR_OK) {
printf("Remount Success!\r\n");
return 0;
}
} else {
printf("Format Failed! Error: %d\r\n", res);
}
}
return -1;
}
/* 简单的测试写文件函数 */
void SD_Test_Write(void) {
FIL fil;
UINT bw;
if (f_open(&fil, "SDTest.txt", FA_WRITE | FA_CREATE_ALWAYS) == FR_OK) {
f_write(&fil, "Hello SD NAND!", 14, &bw);
f_close(&fil);
printf("Write Test: OK\r\n");
} else {
printf("Write Test: Failed\r\n");
}
}
/**
* @brief
* SDTest.txt printf
*/
void SD_Test_Read(void)
{
FIL fil; // 文件对象
FRESULT res; // FatFs 返回结果
UINT br; // Bytes Read (实际读取到的字节数)
BYTE readBuf[128]; // 读取缓存 (根据需要调整大小)
printf("\r\n--- Starting Read Test ---\r\n");
// 1. 打开文件 (使用 FA_READ 模式)
// 注意:文件名必须与写入时完全一致
res = f_open(&fil, "SDTest.txt", FA_READ);
if (res != FR_OK) { if (res != FR_OK) {
printf("Read Failed: f_open error code %d\r\n", res); sprintf(uart_buf, "Open Fail (Write). Error: %d\r\n", res);
if (res == FR_NO_FILE) { UART3_Print(uart_buf);
printf("Error: File does not exist. Did Write Test run successfully?\r\n");
}
return; return;
} }
// 2. 读取文件 UART3_Print("Testing Write Speed... Please wait.\r\n");
// 为了安全,读取长度设为 buffer大小 - 1留一个字节给字符串结束符 startTime = HAL_GetTick();
res = f_read(&fil, readBuf, sizeof(readBuf) - 1, &br); for (uint32_t i = 0; i < TOTAL_TEST_SIZE / TEST_BUF_SIZE; i++) {
res = f_write(&file, g_test_buffer, TEST_BUF_SIZE, &bw);
if (res != FR_OK) break;
}
f_sync(&file); // Flush to physical NAND
endTime = HAL_GetTick();
if (res == FR_OK) { speed = ((float)TOTAL_TEST_SIZE / 1024.0 / 1024.0) / ((float)(endTime - startTime) / 1000.0);
// 3. 处理读取到的数据 sprintf(uart_buf, "WRITE: %.2f MB/s (%lu ms)\r\n", speed, endTime - startTime);
readBuf[br] = '\0'; // 手动添加字符串结束符,方便 printf 打印 UART3_Print(uart_buf);
f_close(&file);
printf("Read Success!\r\n"); // --- READ TEST ---
printf("Bytes Read: %d\r\n", br); res = f_open(&file, TEST_FILE_NAME, FA_READ);
if (res != FR_OK) {
if (br > 0) { UART3_Print("Open Fail (Read)\r\n");
printf("File Content: \r\n%s\r\n", readBuf); return;
} else {
printf("Warning: File is empty (0 bytes).\r\n");
}
} else {
printf("Read Failed: f_read error code %d\r\n", res);
} }
// 4. 关闭文件 (读取完成后也必须关闭,释放句柄) UART3_Print("Testing Read Speed... Please wait.\r\n");
f_close(&fil); startTime = HAL_GetTick();
for (uint32_t i = 0; i < TOTAL_TEST_SIZE / TEST_BUF_SIZE; i++) {
res = f_read(&file, g_test_buffer, TEST_BUF_SIZE, &br);
if (res != FR_OK) break;
}
endTime = HAL_GetTick();
printf("--- Read Test Finished ---\r\n"); speed = ((float)TOTAL_TEST_SIZE / 1024.0 / 1024.0) / ((float)(endTime - startTime) / 1000.0);
sprintf(uart_buf, "READ: %.2f MB/s (%lu ms)\r\n", speed, endTime - startTime);
UART3_Print(uart_buf);
f_close(&file);
f_unlink(TEST_FILE_NAME); // Clean up
UART3_Print("=== Test Finished ===\r\n");
} }
/* USER CODE END 4 */
extern SD_HandleTypeDef hsd;
extern DMA_HandleTypeDef hdma_sdio_rx;
extern DMA_HandleTypeDef hdma_sdio_tx;
void Raw_Hardware_Test(void) {
uint32_t start, end;
HAL_StatusTypeDef status;
UART3_Print("\r\n--- Starting Raw Hardware Test (No File System) ---\r\n");
// Test Raw DMA Write
start = HAL_GetTick();
status = HAL_SD_WriteBlocks_DMA(&hsd, g_test_buffer, 1000, TEST_BUF_SIZE / 512);
if (status == HAL_OK) {
// Wait for DMA to finish
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) {}
end = HAL_GetTick();
sprintf(uart_buf, "Raw DMA Write: %lu ms\r\n", end - start);
UART3_Print(uart_buf);
} else {
UART3_Print("Raw Write Failed!\r\n");
}
}
void Run_SDNAND_SpeedTest_V2(void) {
FIL file;
FRESULT res;
UINT bw, br;
uint32_t startTime, endTime, duration;
float speed;
UART3_Print("\r\n=== SD NAND Speed Test V2 ===\r\n");
// 预填充数据
for (uint32_t i = 0; i < TEST_BUF_SIZE; i++) g_test_buffer[i] = (uint8_t)(i % 256);
// --- WRITE TEST ---
res = f_open(&file, TEST_FILE_NAME, FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK) {
sprintf(uart_buf, "Open Fail (Write). Error: %d\r\n", res);
UART3_Print(uart_buf);
return;
}
UART3_Print("Writing 16MB...\r\n");
startTime = HAL_GetTick();
for (uint32_t i = 0; i < TOTAL_TEST_SIZE / TEST_BUF_SIZE; i++) {
res = f_write(&file, g_test_buffer, TEST_BUF_SIZE, &bw);
if (res != FR_OK || bw != TEST_BUF_SIZE) {
sprintf(uart_buf, "Write Fail at block %lu, Res: %d\r\n", i, res);
UART3_Print(uart_buf);
f_close(&file);
return;
}
}
f_close(&file); // 必须先关闭文件,确保 FAT 目录项更新
endTime = HAL_GetTick();
duration = (endTime - startTime > 0) ? (endTime - startTime) : 1; // 防止除以0
speed = ((float)TOTAL_TEST_SIZE / 1024.0 / 1024.0) / ((float)duration / 1000.0);
sprintf(uart_buf, "WRITE Result: %.2f MB/s (%lu ms)\r\n", speed, duration);
UART3_Print(uart_buf);
// --- READ TEST ---
HAL_Delay(100); // 稍微等待文件系统稳定
res = f_open(&file, TEST_FILE_NAME, FA_READ);
if (res != FR_OK) {
sprintf(uart_buf, "Open Fail (Read). Error: %d\r\n", res);
UART3_Print(uart_buf);
return;
}
UART3_Print("Reading 16MB...\r\n");
startTime = HAL_GetTick();
for (uint32_t i = 0; i < TOTAL_TEST_SIZE / TEST_BUF_SIZE; i++) {
res = f_read(&file, g_test_buffer, TEST_BUF_SIZE, &br);
if (res != FR_OK || br != TEST_BUF_SIZE) {
sprintf(uart_buf, "Read Fail at block %lu, Res: %d\r\n", i, res);
UART3_Print(uart_buf);
break;
}
}
endTime = HAL_GetTick();
duration = (endTime - startTime > 0) ? (endTime - startTime) : 1;
speed = ((float)TOTAL_TEST_SIZE / 1024.0 / 1024.0) / ((float)duration / 1000.0);
sprintf(uart_buf, "READ Result: %.2f MB/s (%lu ms)\r\n", speed, duration);
UART3_Print(uart_buf);
f_close(&file);
UART3_Print("=== Test Finished ===\r\n");
}
void SDNAND_ForceFormat_and_Mount(void) {
FATFS fs;
FRESULT res;
BYTE work[_MAX_SS];
char msg[128];
UART3_Print("\r\n--- Initializing SD NAND for Optimization ---\r\n");
// 1. 先尝试挂载 (立即挂载模式)
res = f_mount(&fs, "", 1);
if (res != FR_OK && res != FR_NO_FILESYSTEM) {
sprintf(msg, "Mount failed before format: %d\r\n", res);
UART3_Print(msg);
return;
}
// 2. 执行格式化 (强制 512 簇)
UART3_Print("Formatting... this may take a few seconds.\r\n");
res = f_mkfs("", FM_FAT32, 32768, work, sizeof(work));
if (res != FR_OK) {
sprintf(msg, "Format failed: %d\r\n", res);
UART3_Print(msg);
return;
}
UART3_Print("Format completed successfully.\r\n");
// 3. 卸载以清除旧缓存
f_mount(NULL, "", 0);
// 4. 重新挂载
res = f_mount(&fs, "", 1);
if (res == FR_OK) {
UART3_Print("SD NAND Remounted with 4KB cluster size.\r\n");
} else {
sprintf(msg, "Final mount failed: %d\r\n", res);
UART3_Print(msg);
}
}
#endif

View File

@ -1,5 +1,8 @@
#include "system_monitor.h" #include "system_monitor.h"
#include "fatfs.h"
#include "ff.h"
#include <string.h> #include <string.h>
#include <stdio.h>
// 静态变量 // 静态变量
static SystemMonitorStats_t g_system_stats = {0}; static SystemMonitorStats_t g_system_stats = {0};
@ -86,3 +89,81 @@ void SystemMonitor_ReportSDFileCreated(void)
{ {
g_system_stats.sd_file_count++; g_system_stats.sd_file_count++;
} }
/**
* @brief
* @param None
* @retval None
*/
void SystemMonitor_ReportDataDropped(void)
{
g_system_stats.sd_data_dropped_count++;
}
/**
* @brief
* @param None
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef SystemMonitor_SaveStatus(void)
{
FIL file;
FRESULT res;
UINT bytes_written;
char buffer[512];
// 创建或覆盖MONITOR.TXT文件
res = f_open(&file, MONITOR_STATUS_FILE, FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK) {
return HAL_ERROR;
}
// 格式化监控数据为文本
int len = snprintf(buffer, sizeof(buffer),
"=== System Monitor Status ===\r\n"
"Total Samples: %lu\r\n"
"Data Overflow: %lu\r\n"
"\r\n"
"=== 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"
"SD Data Dropped: %lu\r\n",
g_system_stats.total_samples,
g_system_stats.data_overflow_count,
g_system_stats.sd_write_count,
g_system_stats.sd_write_error_count,
g_system_stats.sd_buffer_full_count,
g_system_stats.sd_total_bytes_written,
g_system_stats.sd_file_count,
g_system_stats.sd_data_dropped_count
);
// 写入监控数据
res = f_write(&file, buffer, len, &bytes_written);
if (res != FR_OK || bytes_written != (UINT)len) {
f_close(&file);
return HAL_ERROR;
}
// 关闭文件
f_close(&file);
return HAL_OK;
}
/**
* @brief
* @param None
* @retval HAL_StatusTypeDef
* @note
*/
HAL_StatusTypeDef SystemMonitor_LoadStatus(void)
{
// 当前实现:不从文件恢复状态
// 每次上电重新开始统计,避免累积错误
// MONITOR.TXT仅用于记录上次运行的状态
return HAL_OK;
}

View File

@ -4,6 +4,9 @@
#include "main.h" #include "main.h"
#include <stdint.h> #include <stdint.h>
// 监控状态文件配置
#define MONITOR_STATUS_FILE "0:/MONITOR.TXT" // 监控状态存储文件
// 简化的系统监控统计信息 // 简化的系统监控统计信息
typedef struct { typedef struct {
uint32_t total_samples; // 总采样样点数 uint32_t total_samples; // 总采样样点数
@ -15,6 +18,7 @@ typedef struct {
uint32_t sd_buffer_full_count; // 缓冲区满次数 uint32_t sd_buffer_full_count; // 缓冲区满次数
uint32_t sd_total_bytes_written; // SD卡总写入字节数 uint32_t sd_total_bytes_written; // SD卡总写入字节数
uint32_t sd_file_count; // 创建的文件数量 uint32_t sd_file_count; // 创建的文件数量
uint32_t sd_data_dropped_count; // 未存储的数据数量(缓冲区满时丢弃)
} SystemMonitorStats_t; } SystemMonitorStats_t;
// 函数声明 // 函数声明
@ -28,5 +32,10 @@ void SystemMonitor_ReportSDWrite(uint32_t bytes_written);
void SystemMonitor_ReportSDWriteError(void); void SystemMonitor_ReportSDWriteError(void);
void SystemMonitor_ReportSDBufferFull(void); void SystemMonitor_ReportSDBufferFull(void);
void SystemMonitor_ReportSDFileCreated(void); void SystemMonitor_ReportSDFileCreated(void);
void SystemMonitor_ReportDataDropped(void);
// 监控状态持久化函数
HAL_StatusTypeDef SystemMonitor_SaveStatus(void);
HAL_StatusTypeDef SystemMonitor_LoadStatus(void);
#endif // SYSTEM_MONITOR_H #endif // SYSTEM_MONITOR_H