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_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);

View File

@ -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) {

View File

@ -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 */

View File

@ -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

View File

@ -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=

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 读写较慢)
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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
}

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 "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);
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);
} else {
printf("Warning: File is empty (0 bytes).\r\n");
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;
}
} else {
printf("Read Failed: f_read error code %d\r\n", res);
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;
}
// 4. 关闭文件 (读取完成后也必须关闭,释放句柄)
f_close(&fil);
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();
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 "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;
}

View File

@ -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