STM_ATEM/User/SD_Performance_Analysis.md
zhoujie 8a928032dd feat(storage): 新增SD卡性能分析文档并优化写入策略
- 新增SD卡性能分析文档,详细分析写入瓶颈并提供优化建议
- 优化DataStorage_FlushBuffer函数,减少f_sync调用频率以提高写入性能
- 在停止录制时强制同步所有数据到SD卡,确保数据完整性
- 使用静态变量记录刷新次数,每10次刷新或文件即将达到最大大小时才同步

🐛 fix(adc): 修复中断回调中的条件判断逻辑

- 注释掉cnt % 2条件判断,确保中断回调中的处理逻辑能正常执行
- 保持原有的GPIO引脚检测和处理流程不变
2026-02-07 00:02:50 +08:00

6.4 KiB
Raw Blame History

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

// 同步到存储设备
f_sync(&handle->file);

问题:每次写入都调用 f_sync() 会严重降低性能。

优化方案

// 只在特定条件下同步
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

#define DATA_STORAGE_BUFFER_SIZE    32768  // 32KB

优化方案

#define DATA_STORAGE_BUFFER_SIZE    65536  // 64KB

或者更激进:

#define DATA_STORAGE_BUFFER_SIZE    131072  // 128KB

注意需要确保MCU有足够的RAMSTM32F405有128KB SRAM

1.3 优化SDIO时钟分频

当前配置sdio.c:49

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卡

  • 推荐使用 32KB64KB 分配单元
  • 与缓冲区大小对齐可提高性能

推荐的优化步骤

第一步:修改 f_sync() 策略

修改 data_storage.c 中的 DataStorage_FlushBuffer() 函数:

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

// 从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 中添加:

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. 监控写入速度

计算实际写入速度:

// 在统计信息中添加
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卡或降低数据采样率。