✨ 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:
parent
8a928032dd
commit
5419e33397
@ -57,7 +57,7 @@ void MX_DMA_Init(void)
|
||||
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
|
||||
/* 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);
|
||||
/* DMA2_Stream6_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 10, 0);
|
||||
|
||||
108
Core/Src/main.c
108
Core/Src/main.c
@ -46,12 +46,15 @@
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
// 串口输出控制开关
|
||||
#define ENABLE_UART_DEBUG_OUTPUT 1
|
||||
#define DEBUG_OUTPUT_INTERVAL_MS 1000 // 调试输出间隔(毫秒)
|
||||
|
||||
// 监控功能宏开关
|
||||
// 监控功能宏开关(统一控制串口输出和文件存储)
|
||||
#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 */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
@ -87,7 +90,9 @@ static uint32_t g_last_usb_check = 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 */
|
||||
|
||||
@ -147,6 +152,13 @@ static void ProcessAdcData(void)
|
||||
LTC2508_BufferTypeDef *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
|
||||
SystemMonitor_IncrementSampleCount();
|
||||
#endif
|
||||
@ -174,20 +186,26 @@ static void ProcessAdcData(void)
|
||||
|
||||
correction_applied = 1;
|
||||
|
||||
// 发送校正后的数据包
|
||||
// RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t));
|
||||
#if DATA_OUTPUT_MODE_UART
|
||||
// 发送校正后的数据包到串口
|
||||
RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t));
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
// 4b. 校正失败或未启用,使用原始数据
|
||||
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));
|
||||
#endif
|
||||
}
|
||||
|
||||
// 6. 存储数据到SD卡 (如果启用记录)
|
||||
// 6. 存储数据到SD卡 (如果启用记录且缓冲区可用)
|
||||
#if DATA_OUTPUT_MODE_STORAGE
|
||||
if (g_recording_enabled) {
|
||||
if (can_store_data) {
|
||||
if (correction_applied) {
|
||||
// 存储校正后的数据
|
||||
DataStorage_WriteCorrectedData(&g_data_storage, &g_corrected_packet);
|
||||
@ -195,7 +213,14 @@ static void ProcessAdcData(void)
|
||||
// 存储原始数据
|
||||
DataStorage_WriteData(&g_data_storage, &g_data_packet);
|
||||
}
|
||||
} else {
|
||||
// 缓冲区满,数据被丢弃
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
SystemMonitor_ReportDataDropped();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 7. 释放已处理的缓冲区
|
||||
LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer());
|
||||
@ -211,9 +236,9 @@ static void ProcessAdcData(void)
|
||||
static void DebugOutput_Init(void)
|
||||
{
|
||||
// USART3已在MX_USART3_UART_Init()中初始化
|
||||
if (g_debug_output_enabled) {
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
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)
|
||||
{
|
||||
if (!g_debug_output_enabled || str == NULL) {
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
if (str == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
if (!g_debug_output_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[256];
|
||||
SystemMonitorStats_t sys_stats;
|
||||
SystemMonitor_GetStats(&sys_stats);
|
||||
@ -261,12 +284,14 @@ static void DebugOutput_PrintSystemStats(void)
|
||||
"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 File Count: %lu\r\n"
|
||||
"SD Data Dropped: %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);
|
||||
sys_stats.sd_file_count,
|
||||
sys_stats.sd_data_dropped_count);
|
||||
DebugOutput_SendString(buffer);
|
||||
|
||||
// 计算并打印统计指标
|
||||
@ -328,6 +353,12 @@ static void HandleUSBConnectionChange(void)
|
||||
|
||||
// 卸载用于采样的文件系统
|
||||
UnmountFileSystemForSampling();
|
||||
|
||||
while(1)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
} else {
|
||||
// USB断开:重新挂载文件系统,开始数据采集
|
||||
DebugOutput_SendString("USB Disconnected: Starting data acquisition\r\n");
|
||||
@ -461,10 +492,6 @@ int main(void)
|
||||
MX_TIM2_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
// SD_NAND_Init_And_Mount();
|
||||
// SD_Test_Write();
|
||||
// SD_Test_Read();
|
||||
|
||||
// 初始化系统监控
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
SystemMonitor_Init();
|
||||
@ -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数据处理
|
||||
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) {
|
||||
Error_Handler();
|
||||
@ -533,21 +570,34 @@ 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;
|
||||
}
|
||||
|
||||
// 处理数据存储后台任务 (轮询方式)
|
||||
// 优化:连续处理3次,加快缓冲区刷新速度
|
||||
if (g_recording_enabled) {
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
DataStorage_ProcessBackgroundTasks(&g_data_storage);
|
||||
// }
|
||||
}
|
||||
|
||||
// 定期输出调试信息 (每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();
|
||||
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外部中断触发,不在主循环中触发
|
||||
// 可以在这里添加其他低优先级任务
|
||||
@ -617,7 +667,7 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
|
||||
if(LTC2508_IsInited() == 0) return;
|
||||
|
||||
cnt ++;
|
||||
// if(cnt % 2 == 0)
|
||||
// if(cnt % 5 == 0)
|
||||
{
|
||||
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
|
||||
if (GPIO_Pin == ADC_DRY_Pin) {
|
||||
|
||||
@ -131,7 +131,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
|
||||
__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
|
||||
|
||||
/* USART1 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART1_IRQn, 6, 0);
|
||||
HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);
|
||||
HAL_NVIC_EnableIRQ(USART1_IRQn);
|
||||
/* USER CODE BEGIN USART1_MspInit 1 */
|
||||
|
||||
|
||||
@ -175,7 +175,7 @@
|
||||
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
|
||||
/ function will be available. */
|
||||
#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,
|
||||
/ 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
|
||||
|
||||
@ -89,7 +89,7 @@ Dma.USART1_TX.5.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphData
|
||||
FATFS.BSP.number=1
|
||||
FATFS.IPParameters=_USE_LFN,USE_DMA_CODE_SD,_MAX_SS,_MIN_SS
|
||||
FATFS.USE_DMA_CODE_SD=1
|
||||
FATFS._MAX_SS=512
|
||||
FATFS._MAX_SS=4096
|
||||
FATFS._MIN_SS=512
|
||||
FATFS._USE_LFN=2
|
||||
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.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_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_Stream7_IRQn=true\:12\:0\:true\:false\:true\:false\:true\:true
|
||||
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.SysTick_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:false
|
||||
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
|
||||
PA1.GPIOParameters=GPIO_Label
|
||||
PA1.GPIO_Label=ADC_DRY
|
||||
@ -291,7 +291,7 @@ ProjectManager.ProjectFileName=STM_ATEM_F405.ioc
|
||||
ProjectManager.ProjectName=STM_ATEM_F405
|
||||
ProjectManager.ProjectStructure=
|
||||
ProjectManager.RegisterCallBack=
|
||||
ProjectManager.StackSize=0x800
|
||||
ProjectManager.StackSize=0x1000
|
||||
ProjectManager.TargetToolchain=STM32CubeIDE
|
||||
ProjectManager.ToolChainLocation=
|
||||
ProjectManager.UAScriptAfterPath=
|
||||
|
||||
@ -290,7 +290,7 @@ int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t bl
|
||||
// 使用较长的超时时间 (SD NAND 读写较慢)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -321,7 +321,7 @@ int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t b
|
||||
// 修正 3: 增加超时时间,并等待 Busy 结束
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "system_monitor.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* @brief 初始化数据存储模块
|
||||
@ -29,9 +30,8 @@ HAL_StatusTypeDef DataStorage_Init(DataStorageHandle_t *handle)
|
||||
handle->flush_buffer = 1;
|
||||
handle->flush_in_progress = 0;
|
||||
|
||||
// 创建数据存储目录
|
||||
FRESULT res = f_mkdir(DATA_STORAGE_PATH);
|
||||
if (res != FR_OK && res != FR_EXIST) {
|
||||
// 创建新的会话文件夹(每次上电创建新文件夹)
|
||||
if (DataStorage_CreateSessionFolder(handle) != HAL_OK) {
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
@ -177,10 +177,10 @@ HAL_StatusTypeDef DataStorage_CreateNewFile(DataStorageHandle_t *handle)
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 生成文件名 (基于时间戳)
|
||||
// 生成文件名 (基于时间戳),文件存储在当前会话文件夹中
|
||||
uint32_t timestamp = HAL_GetTick();
|
||||
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,
|
||||
@ -287,7 +287,6 @@ HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t b
|
||||
flush_count++;
|
||||
|
||||
// 每10次刷新才同步一次,或者文件即将达到最大大小时同步
|
||||
// 这样可以显著减少SD卡写入延迟,提高吞吐量
|
||||
if (flush_count % 10 == 0 ||
|
||||
handle->stats.current_file_size + bytes_written >= DATA_STORAGE_FILE_MAX_SIZE) {
|
||||
f_sync(&handle->file);
|
||||
@ -368,3 +367,161 @@ HAL_StatusTypeDef DataStorage_SwitchBuffer(DataStorageHandle_t *handle)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -11,8 +11,11 @@
|
||||
// 数据存储配置
|
||||
#define DATA_STORAGE_BUFFER_SIZE 32768 // 缓冲区大小(字节)
|
||||
#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_FOLDER_PREFIX "SESSION_" // 文件夹名前缀
|
||||
#define DATA_STORAGE_PARAM_FILE "0:/PARAM.TXT" // 记录会话序号的文件
|
||||
#define DATA_STORAGE_MAX_PATH_LEN 128 // 最大路径长度
|
||||
|
||||
// 缓冲区状态
|
||||
typedef enum {
|
||||
@ -37,7 +40,7 @@ typedef struct {
|
||||
uint32_t file_count;
|
||||
uint32_t error_count;
|
||||
DataStorageState_t state;
|
||||
char current_filename[64];
|
||||
char current_filename[256];
|
||||
} DataStorageStats_t;
|
||||
|
||||
// 双缓冲区结构
|
||||
@ -56,6 +59,7 @@ typedef struct {
|
||||
DataStorageStats_t stats;
|
||||
uint8_t initialized;
|
||||
uint8_t flush_in_progress; // 刷新进行中标志
|
||||
char current_session_path[DATA_STORAGE_MAX_PATH_LEN]; // 当前会话文件夹路径
|
||||
} DataStorageHandle_t;
|
||||
|
||||
// 函数声明
|
||||
@ -68,9 +72,19 @@ HAL_StatusTypeDef DataStorage_Flush(DataStorageHandle_t *handle);
|
||||
void DataStorage_GetStats(DataStorageHandle_t *handle, DataStorageStats_t *stats);
|
||||
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_FlushBuffer(DataStorageHandle_t *handle, uint8_t buffer_index);
|
||||
void DataStorage_ProcessBackgroundTasks(DataStorageHandle_t *handle);
|
||||
|
||||
// 缓冲区可用性检查函数
|
||||
uint8_t DataStorage_IsBufferAvailable(DataStorageHandle_t *handle, uint32_t required_size);
|
||||
|
||||
#endif // DATA_STORAGE_H
|
||||
|
||||
@ -19,14 +19,14 @@ HAL_StatusTypeDef RS485_SendData(uint8_t *pData, uint16_t Size)
|
||||
{
|
||||
HAL_StatusTypeDef ret;
|
||||
|
||||
if (g_rs485_tx_busy)
|
||||
{
|
||||
return HAL_BUSY;
|
||||
}
|
||||
// if (g_rs485_tx_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); // 设置为发送模式
|
||||
ret = HAL_UART_Transmit_IT(g_huart_485, pData, Size);
|
||||
ret = HAL_UART_Transmit(g_huart_485, pData, Size, 0xffff);
|
||||
|
||||
// 注意:不能在这里立即切换回接收模式!
|
||||
// DMA传输是非阻塞的,需要在传输完成回调中切换
|
||||
@ -34,11 +34,11 @@ HAL_StatusTypeDef RS485_SendData(uint8_t *pData, uint16_t Size)
|
||||
{
|
||||
// 如果启动DMA失败,需要清除忙标志并切换回接收模式
|
||||
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)
|
||||
{
|
||||
// DMA传输完成后切换回接收模式
|
||||
HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET);
|
||||
g_rs485_tx_busy = 0;
|
||||
// HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET);
|
||||
// g_rs485_tx_busy = 0;
|
||||
}
|
||||
}
|
||||
|
||||
347
User/sd_test.c
347
User/sd_test.c
@ -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 "data_packet.h"
|
||||
#include "correction.h"
|
||||
#include <stdint.h>
|
||||
#include "stdio.h"
|
||||
#include "string.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;
|
||||
//DMA_HandleTypeDef hdma_sdio_rx;
|
||||
//DMA_HandleTypeDef hdma_sdio_tx;
|
||||
// Configuration
|
||||
#define TEST_FILE_NAME "ST_DATA.BIN"
|
||||
#define TEST_BUF_SIZE (64 * 1024) // 64KB Buffer (Good for SDIO DMA)
|
||||
#define TOTAL_TEST_SIZE (16 * 1024 * 1024) // 16MB Total Data
|
||||
|
||||
/**
|
||||
* @brief 针对 SD NAND 的专用初始化与格式化函数
|
||||
* @return 0: 成功, -1: 失败
|
||||
*/
|
||||
int SD_NAND_Init_And_Mount(void)
|
||||
{
|
||||
// Align buffer to 4 bytes for DMA compatibility
|
||||
uint8_t g_test_buffer[TEST_BUF_SIZE] __attribute__((aligned(4)));
|
||||
char uart_buf[128]; // Buffer for formatting UART messages
|
||||
|
||||
// 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;
|
||||
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");
|
||||
|
||||
// 1. 物理层延时:SD NAND 内部初始化比普通卡慢
|
||||
HAL_Delay(500);
|
||||
|
||||
// 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);
|
||||
// Initialize buffer with dummy data
|
||||
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) {
|
||||
printf("Read Failed: f_open error code %d\r\n", res);
|
||||
if (res == FR_NO_FILE) {
|
||||
printf("Error: File does not exist. Did Write Test run successfully?\r\n");
|
||||
}
|
||||
sprintf(uart_buf, "Open Fail (Write). Error: %d\r\n", res);
|
||||
UART3_Print(uart_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 读取文件
|
||||
// 为了安全,读取长度设为 buffer大小 - 1,留一个字节给字符串结束符
|
||||
res = f_read(&fil, readBuf, sizeof(readBuf) - 1, &br);
|
||||
UART3_Print("Testing Write Speed... Please wait.\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) break;
|
||||
}
|
||||
f_sync(&file); // Flush to physical NAND
|
||||
endTime = HAL_GetTick();
|
||||
|
||||
speed = ((float)TOTAL_TEST_SIZE / 1024.0 / 1024.0) / ((float)(endTime - startTime) / 1000.0);
|
||||
sprintf(uart_buf, "WRITE: %.2f MB/s (%lu ms)\r\n", speed, endTime - startTime);
|
||||
UART3_Print(uart_buf);
|
||||
f_close(&file);
|
||||
|
||||
// --- READ TEST ---
|
||||
res = f_open(&file, TEST_FILE_NAME, FA_READ);
|
||||
if (res != FR_OK) {
|
||||
UART3_Print("Open Fail (Read)\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
UART3_Print("Testing Read Speed... Please wait.\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) break;
|
||||
}
|
||||
endTime = HAL_GetTick();
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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) {
|
||||
// 3. 处理读取到的数据
|
||||
readBuf[br] = '\0'; // 手动添加字符串结束符,方便 printf 打印
|
||||
|
||||
printf("Read Success!\r\n");
|
||||
printf("Bytes Read: %d\r\n", br);
|
||||
|
||||
if (br > 0) {
|
||||
printf("File Content: \r\n%s\r\n", readBuf);
|
||||
UART3_Print("SD NAND Remounted with 4KB cluster size.\r\n");
|
||||
} else {
|
||||
printf("Warning: File is empty (0 bytes).\r\n");
|
||||
sprintf(msg, "Final mount failed: %d\r\n", res);
|
||||
UART3_Print(msg);
|
||||
}
|
||||
} else {
|
||||
printf("Read Failed: f_read error code %d\r\n", res);
|
||||
}
|
||||
|
||||
// 4. 关闭文件 (读取完成后也必须关闭,释放句柄)
|
||||
f_close(&fil);
|
||||
|
||||
printf("--- Read Test Finished ---\r\n");
|
||||
}
|
||||
/* USER CODE END 4 */
|
||||
#endif
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#include "system_monitor.h"
|
||||
#include "fatfs.h"
|
||||
#include "ff.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// 静态变量
|
||||
static SystemMonitorStats_t g_system_stats = {0};
|
||||
@ -86,3 +89,81 @@ void SystemMonitor_ReportSDFileCreated(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
#include "main.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// 监控状态文件配置
|
||||
#define MONITOR_STATUS_FILE "0:/MONITOR.TXT" // 监控状态存储文件
|
||||
|
||||
// 简化的系统监控统计信息
|
||||
typedef struct {
|
||||
uint32_t total_samples; // 总采样样点数
|
||||
@ -15,6 +18,7 @@ typedef struct {
|
||||
uint32_t sd_buffer_full_count; // 缓冲区满次数
|
||||
uint32_t sd_total_bytes_written; // SD卡总写入字节数
|
||||
uint32_t sd_file_count; // 创建的文件数量
|
||||
uint32_t sd_data_dropped_count; // 未存储的数据数量(缓冲区满时丢弃)
|
||||
} SystemMonitorStats_t;
|
||||
|
||||
// 函数声明
|
||||
@ -28,5 +32,10 @@ void SystemMonitor_ReportSDWrite(uint32_t bytes_written);
|
||||
void SystemMonitor_ReportSDWriteError(void);
|
||||
void SystemMonitor_ReportSDBufferFull(void);
|
||||
void SystemMonitor_ReportSDFileCreated(void);
|
||||
void SystemMonitor_ReportDataDropped(void);
|
||||
|
||||
// 监控状态持久化函数
|
||||
HAL_StatusTypeDef SystemMonitor_SaveStatus(void);
|
||||
HAL_StatusTypeDef SystemMonitor_LoadStatus(void);
|
||||
|
||||
#endif // SYSTEM_MONITOR_H
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user