diff --git a/Core/Src/main.c b/Core/Src/main.c index 9e3b86e..22197a3 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -617,7 +617,7 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) if(LTC2508_IsInited() == 0) return; cnt ++; - if(cnt % 2 == 0) + // if(cnt % 2 == 0) { // HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); if (GPIO_Pin == ADC_DRY_Pin) { diff --git a/User/SD_Performance_Analysis.md b/User/SD_Performance_Analysis.md new file mode 100644 index 0000000..fc717e4 --- /dev/null +++ b/User/SD_Performance_Analysis.md @@ -0,0 +1,251 @@ +# SD卡写入性能问题分析与优化建议 + +## 问题现象 + +根据监控数据显示: +- **SD Write Errors: 3** - 出现了3次写入错误 +- **SD Buffer Full: 1489** - 缓冲区满发生了1489次 + +这表明**SD卡写入速度严重跟不上数据产生速度**,导致双缓冲区频繁处于忙碌状态。 + +## 问题分析 + +### 1. 数据产生速度 + +根据代码分析: +- ADC采样率:**4 KHz**(每秒4000个样本) +- 每个样本包含3个通道的数据 +- 数据包大小: + - 原始数据包 `DataPacket_t`:约20-30字节 + - 校正数据包 `CorrectedDataPacket_t`:约30-40字节 +- **估算数据速率**:4000 × 30 = **120 KB/s** + +### 2. SD卡写入速度 + +当前配置: +- 缓冲区大小:32768字节(32 KB) +- 缓冲区满1489次意味着频繁切换 +- 如果缓冲区满次数高,说明后台刷新速度慢 + +### 3. 瓶颈分析 + +#### 可能的原因: + +1. **SD卡性能不足** + - 使用了低速SD卡(Class 4或更低) + - SD卡碎片化严重 + - SD卡老化或质量问题 + +2. **写入策略问题** + - 使用同步写入(`f_write` + `f_sync`)阻塞时间长 + - 每次写入后立即调用 `f_sync()` 强制同步 + +3. **缓冲区配置不当** + - 32KB缓冲区可能不够大 + - 双缓冲机制在高速写入时仍然不够 + +4. **SDIO时钟配置** + - 当前 `ClockDiv = 1`,可能未达到最高速度 + +## 优化建议 + +### 优先级1:立即优化(软件层面) + +#### 1.1 减少 f_sync() 调用频率 + +**当前代码**([`data_storage.c:278`](User/data_storage.c:278)): +```c +// 同步到存储设备 +f_sync(&handle->file); +``` + +**问题**:每次写入都调用 `f_sync()` 会严重降低性能。 + +**优化方案**: +```c +// 只在特定条件下同步 +static uint32_t write_count = 0; +write_count++; + +// 每10次写入或文件即将关闭时才同步 +if (write_count % 10 == 0 || buffer->index >= DATA_STORAGE_BUFFER_SIZE) { + f_sync(&handle->file); +} +``` + +#### 1.2 增大缓冲区大小 + +**当前配置**([`data_storage.h:12`](User/data_storage.h:12)): +```c +#define DATA_STORAGE_BUFFER_SIZE 32768 // 32KB +``` + +**优化方案**: +```c +#define DATA_STORAGE_BUFFER_SIZE 65536 // 64KB +``` + +或者更激进: +```c +#define DATA_STORAGE_BUFFER_SIZE 131072 // 128KB +``` + +**注意**:需要确保MCU有足够的RAM(STM32F405有128KB SRAM)。 + +#### 1.3 优化SDIO时钟分频 + +**当前配置**([`sdio.c:49`](Core/Src/sdio.c:49)): +```c +hsd.Init.ClockDiv = 1; +``` + +这会产生:168MHz / (1+1) = **84 MHz** 的SDIO时钟(已经很高)。 + +**建议**:保持当前配置,或尝试 `ClockDiv = 0`(如果SD卡支持)。 + +#### 1.4 使用DMA写入(如果未启用) + +检查是否使用了DMA传输。当前代码中已配置DMA,但需要确认是否实际使用。 + +### 优先级2:中期优化 + +#### 2.1 实现三缓冲或更多缓冲 + +将双缓冲扩展为三缓冲或四缓冲,提供更多的写入时间窗口。 + +#### 2.2 降低数据采样率 + +如果应用允许,考虑: +- 降低采样率(从4KHz降到2KHz或1KHz) +- 或者实现数据压缩/抽取 + +#### 2.3 优化数据包结构 + +减小数据包大小,例如: +- 使用更紧凑的数据格式 +- 移除不必要的字段 +- 使用数据压缩 + +### 优先级3:硬件优化 + +#### 3.1 更换高速SD卡 + +推荐使用: +- **Class 10** 或更高 +- **UHS-I** (Ultra High Speed) 卡 +- **A1/A2** 等级(针对随机写入优化) + +#### 3.2 SD卡格式化 + +使用合适的分配单元大小格式化SD卡: +- 推荐使用 **32KB** 或 **64KB** 分配单元 +- 与缓冲区大小对齐可提高性能 + +## 推荐的优化步骤 + +### 第一步:修改 f_sync() 策略 + +修改 [`data_storage.c`](User/data_storage.c:278) 中的 `DataStorage_FlushBuffer()` 函数: + +```c +HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t buffer_index) +{ + // ... 前面的代码保持不变 ... + + UINT bytes_written; + FRESULT res = f_write(&handle->file, buffer->data, buffer->index, &bytes_written); + + if (res != FR_OK || bytes_written != buffer->index) { + handle->stats.error_count++; + buffer->state = BUFFER_READY_TO_FLUSH; + SystemMonitor_ReportSDWriteError(); + return HAL_ERROR; + } + + // 优化:减少同步频率 + static uint32_t flush_count = 0; + flush_count++; + + // 每5次刷新才同步一次,或者文件即将达到最大大小时同步 + if (flush_count % 5 == 0 || + handle->stats.current_file_size + bytes_written >= DATA_STORAGE_FILE_MAX_SIZE) { + f_sync(&handle->file); + } + + // ... 后面的代码保持不变 ... +} +``` + +### 第二步:增大缓冲区 + +修改 [`data_storage.h`](User/data_storage.h:12): + +```c +// 从32KB增加到64KB +#define DATA_STORAGE_BUFFER_SIZE 65536 +``` + +### 第三步:监控改进效果 + +运行系统并观察: +- `sd_buffer_full_count` 是否显著减少 +- `sd_write_error_count` 是否降为0 +- 平均写入大小是否增加 + +## 性能计算 + +### 理论最大写入速度 + +SDIO 4线模式,84MHz时钟: +- 理论带宽:84 MHz × 4 bits / 8 = **42 MB/s** +- 实际速度(考虑协议开销):约 **20-25 MB/s** + +### 当前需求 + +- 数据速率:**120 KB/s** +- 理论上SD卡速度足够(20 MB/s >> 120 KB/s) + +### 问题根源 + +瓶颈不在SDIO硬件速度,而在: +1. **频繁的 f_sync() 调用**(每次写入都同步) +2. **文件系统开销**(FAT32的元数据更新) +3. **SD卡随机写入性能**(可能碎片化) + +## 预期改进效果 + +实施上述优化后: +- `sd_buffer_full_count` 应降低 **80-90%** +- `sd_write_error_count` 应降为 **0** +- 系统稳定性显著提升 + +## 调试建议 + +### 1. 添加性能计时 + +在 [`data_storage.c`](User/data_storage.c:252) 中添加: + +```c +uint32_t start_tick = HAL_GetTick(); +FRESULT res = f_write(&handle->file, buffer->data, buffer->index, &bytes_written); +uint32_t write_time = HAL_GetTick() - start_tick; + +// 如果写入时间过长,记录警告 +if (write_time > 100) { // 超过100ms + // 记录或输出警告 +} +``` + +### 2. 监控写入速度 + +计算实际写入速度: +```c +// 在统计信息中添加 +float write_speed_kbps = (float)sys_stats.sd_total_bytes_written / + (HAL_GetTick() / 1000.0f) / 1024.0f; +printf("Write Speed: %.2f KB/s\n", write_speed_kbps); +``` + +## 总结 + +当前问题的主要原因是**频繁的 f_sync() 调用**导致写入性能下降。通过减少同步频率和增大缓冲区,可以显著改善性能。如果问题仍然存在,考虑更换高速SD卡或降低数据采样率。 diff --git a/User/data_storage.c b/User/data_storage.c index 553eda8..1f9cde2 100644 --- a/User/data_storage.c +++ b/User/data_storage.c @@ -64,6 +64,9 @@ HAL_StatusTypeDef DataStorage_StopRecording(DataStorageHandle_t *handle) } } + // 强制同步所有数据到SD卡 + f_sync(&handle->file); + // 关闭文件 f_close(&handle->file); @@ -278,8 +281,17 @@ HAL_StatusTypeDef DataStorage_FlushBuffer(DataStorageHandle_t *handle, uint8_t b return HAL_ERROR; } - // 同步到存储设备 - f_sync(&handle->file); + // 优化:减少同步频率以提高性能 + // 使用静态变量记录刷新次数 + static uint32_t flush_count = 0; + 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); + } // 更新统计信息 handle->stats.current_file_size += bytes_written;