ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SD卡数据记录仅几分钟就停止?从供电到文件系统的完整排查指南

SD卡数据记录仅几分钟就停止?从供电到文件系统的完整排查指南 做数据记录最烦的事情不是没数据而是数据记录器跑着跑着就停了。SD卡明明在卡槽里插着前面几分钟数据也正常之后却再也写不进去必须断电重启或者把卡拔出来重插才能再坚持一小会儿。这个现象在环境监测、车载日志、便携式采集这些场景里非常普遍很多人第一反应是卡坏了于是换卡、换卡槽、换读卡器折腾一圈问题照样复现。这篇文章从 SD Card 数据记录这个具体场景出发把“SD卡只工作短时间就停止记录”这类问题拆开揉碎从供电、文件系统、写入策略、硬件时序到软件隐患一层层讲清楚排查方向并给出可以直接上手的验证方法。无论你是用 STM32 跑 FatFs还是用 Arduino/ESP32 写日志这套思路都能用得上。1. 问题定位先判断“只记录短时间”到底是哪一层的问题1.1 现象分类卡掉线、写失败、还是系统死机很多人遇到问题就直接怀疑SD卡坏了其实最先要做的是把事情定义清楚。同样表现为“只记录短时间”背后可能是至少三种完全不同的情况。第一种系统整体死机或者复位。如果记录器本身不再运行LED不再闪烁串口界面卡死那问题多半不在SD卡而在主控程序。第二种系统还在跑但写入函数返回错误码比如 FatFs 的 FR_DISK_ERR、FR_NOT_READY或者你用的是更上层的文件库报“file open failed”之类的错误。第三种主控侧完全正常写入也返回成功但当你把SD卡插到电脑上看发现文件大小不增长或者断电后文件丢失。这三种情况对应的排查路径差得很远所以别急着拆硬件。正确的做法是给系统加足够的调试输出把每一步的写卡状态都打出来。比如每次写入后打印返回值、累计写入字节数、文件指针位置、系统运行时间这样至少能判断出“停止”是发生在哪个环节。我见过很多项目串口上连一条日志都没有就一个LED在那边闪出问题时根本没法判断是逻辑层没调用写函数还是写函数内部卡死。这个习惯一定要改过来一个小小的调试打印能给后面节省大量时间。1.2 错误码和日志是定位故障的第一手线索如果你是直接操作底层驱动比如用 SPI 接口通过 FatFs 写文件那么 FatFs 返回的错误码很值得研究。FR_OK正常。FR_DISK_ERR底层磁盘 I/O 错误表示驱动无法读写扇区通常是硬件层面的问题。FR_INT_ERR内部断言错误常见于 FatFs 代码被中断破坏或缓冲区溢出。FR_NOT_READY磁盘未初始化常见于卡在某个时间点重新上电或休眠后被移除。FR_NO_FILE / FR_NO_FILESYSTEM文件不存在或文件系统不存在通常是 FAT 表被破坏或者卡没有正常挂载。如果你用的是 Arduino 的 SD 库写失败时 SD.write 返回 false如果用 Python 在单板电脑上直接写文件则会看到 errno。不管是哪一层都要在代码里把错误信息落到串口或运行日志上而不是让它静默。这里有个容易忽略的细节很多开发板的 SD 库在初始化时返回成功但实际写操作的错误被吞掉了导致你只看到“文件大小不变”却找不到报错点。所以判断问题前先把 SD 库的 error 函数比如 SD.errorCode()或底层错误码读出来否则后面全是盲猜。1.3 先做10分钟复现测试记录“掉链子”的时间在动手改代码之前建议先做一个基础测试把SD卡格式化成 FAT32插进电脑用 h2testw 或 F3 这类工具跑一遍全卡写读测试确认卡的硬件本身不是坏块满天飞。之后空卡插回记录器让它写一个纯文本文件每隔一秒写一行时间戳看它什么时候停。如果停的时间点很固定比如每次都是开机后大概2分钟那优先怀疑和温度、电压、文件大小到达某个阈值有关。如果时间点完全不固定时好时坏那更可能是接触不良、电压跌落或者随机的中断冲突。这一步测试要记录三个信息停止时的系统运行时间、停止时的文件大小、停止前最后几条日志。这三个数据能把问题范围缩小很多。比如“运行2分17秒文件约128KB时停止”和“运行13分钟时停止文件1.3MB”是两个完全不同的排查方向。2. 供电所有间歇性写卡故障的第一怀疑对象2.1 不是只给3.3V供电就够了很多人觉得SD卡数字电路只有几十毫安一颗 LDO 就够其实不是这样。SD卡在擦写动作时会有明显的电流尖峰尤其是质量一般的普通卡瞬时电流可能从几十毫安跳到200毫安以上而且是在微秒级内发生的。如果你的主控、SD卡槽、电机、无线模块共用同一颗电源无线模块一发射或者蜂鸣器一响电源电压就可能跌落。SD卡对电压跌落的表现很隐蔽不是立即报错而是写入不稳定偶尔出现 CRC 错误再往后就是重新初始化失败表现为“还能读但写不了”。很多设备和“只记录短时间”对应不上的原因就在这里因为你可能只测了静态电压没看瞬态。所以排查供电问题时不要用手持万用表看平均电压因为万用表采样率太低测不出瞬态跌落。正确工具是数字示波器并且要把探头直接点在主控供电引脚和SD卡槽 VCC 上抓取“写卡瞬间”的波形。2.2 用示波器看写卡瞬间的电压跌落我常用的做法是这样的把示波器设成单次触发触发电平设到3.0V下降沿触发然后让记录器执行一次格式化或者密集写入测试。重点观察写卡动作时 VCC 波形有没有掉到2.7V以下。如果你的系统是5V供电板载 LDO 转3.3V那更得看电源电容的位置。许多廉价开发板的3.3V引脚只有一颗10uF电解电容高频特性不好瞬间抽流时根本顶不住。可以试着在SD卡槽附近就近放一颗100nF陶瓷电容再并一颗10uF以上的钽电容或 MLCC效果通常立竿见影。还有一个很多人不常提的点SD卡座的引脚接触电阻也会导致电压跌落。如果你用的是弹簧触点式卡座时间长了锈蚀或弹片疲劳接触电阻可能从几十毫欧涨到几百毫欧大电流时压降明显。拧开卡座、清理触点、或直接换新卡座往往能解决很多“换了卡也没用”的怪问题。2.3 供电方案的工程化建议如果你的设备是电池供电尤其是锂电池直接经过 LDO 给SD卡供电那建议在SD卡供电上单独加一组 LC 滤波或至少一颗大容量储能电容。更稳妥的方案是给SD卡用独立 LDO避免主控无线模块的暂态直接串到卡上。判断供电是否够用的一个简单经验用示波器看启动瞬间卡上电初始化有没有低于2.7V再看密集写入时有没有周期性对应写操作的跌落。如果跌落的深度超过300mV即使没有立刻报错也建议先把电源加固再往软件层面排查。我之前修过一台工业采集器症状就是每隔几小时停一次最后发现是电源线太长、负载一高就掉到2.5VSD卡直接就“失踪”了和“运行几分钟后停止”是一个原理只是时间轴拉长了。3. 格式化与文件系统很多“只能写一会儿”其实卡在文件系统3.1 为什么卡会被“写满”而不是物理满这个现象非常典型一张32GB的卡日志文件可能只写了几个MB但系统却报“磁盘已满”或者写操作失败。很多人为此反复低格、换卡最后也找不到原因。问题往往出在 FAT 表或根目录结构上。比如你在 Windows 上做的是快速格式化没有重建分区和 FAT 表或者卡上有隐藏分区、残留的引导记录、系统保留区导致记录器挂载到的分区很小看起来已经满。另一个常见问题是 FAT32 的单个文件最大4GB限制。如果你写入的是一个持续增长的日志文件跨过4GB边界就会失败。FAT32 本身处理大文件的能力就不强在嵌入式设备上更是如此。解决方法有两个要么在文件尺寸接近阈值前主动按日期或序号分文件比如每小时生成一个 log 文件要么换用 exFAT但很多嵌入式文件系统库对 exFAT 支持不全切换起来反而踩坑。所以对大多数记录设备按时间分文件是最稳妥的路线。3.2 用官方 SD Card Formatter 重新格式化而不是 Windows 快速格式化这里就要提一下很多 SD 卡异常问题的标准解法用 SD 协会官方的 SD Card Formatter 工具重新格式化。网上大量“sd card formatter”“sd memory card formatter”的搜索词其实指的就是这个工具。它和 Windows 自带的格式化有很大区别不只是写一遍文件系统还会做低层级的全卡擦除、重建分区表、对非标准的行业格式做覆盖能把卡恢复到比较接近出厂的状态。具体操作很简单把卡插到电脑上下载并运行 SD Card Formatter选择 Overwrite format完整覆盖格式化而不是 Quick format等它跑完再拿回记录器试一次。这个操作能解决一部分“只能写短时间”的问题因为清理掉的可能是 FAT 表混乱、删除不干净的分区或者隐藏分区。但也要说实话SD Card Formatter 不是万能药。如果卡本身有物理坏块或者主控老化格式化也无济于事。所以格式化之前最好先用 h2testw 这类工具做全卡写入和回读测试确认坏块比例。如果测试结果里出现大量错误那直接换卡别在格式化上浪费时间。3.3 簇大小、文件碎片和格式化背后的原理格式化时还有一个容易被忽略的参数簇大小allocation unit size。如果簇太小比如4KB写入大量小日志时 FAT 表会频繁更新效率低如果簇太大比如64KB小文件会浪费空间。对于数据记录场景我一般推荐 FAT32 配合32KB或64KB簇具体看单次写入的块大小。FatFs 挂载时会对格式化参数有一定要求如果簇大小和库的配置不匹配也可能出现挂载异常。文件碎片是另一个罪魁祸首。日志系统反复删除旧文件、追加新文件的话卡上的文件会越来越碎片化。碎片多了每次写入需要更新 FAT 表多个条目写入速度和稳定性都会下降。FatFs 这类库对碎片处理并不好所以定期用 SD Card Formatter 做一次完整格式化本质上就是整理碎片、重建干净的 FAT 表。这也是为什么很多人最后发现格式化之后记录器就正常了。这里再提一个冷门知识部分工业级 SD 卡和普通卡的区别在于固件和损耗均衡策略。普通卡在持续长时间频繁写入时主控内部可能会因为垃圾回收跟不上而出现写入停顿甚至假死表现为记录器过一段时间就写失败。这类问题光靠格式化无法根治需要靠降低写入速度、批量写、或者换工业卡来缓解。4. 写入策略把日志写得慢一点、稳一点4.1 高频小数据写入是怎么把卡“拖死”的“只记录短时间”这个标题让我联想到很多新手项目的通病每循环一次就打开文件、写入一行、关闭文件。这样每次写入都要执行打开、定位、写、关闭四个动作SD 卡的主控要频繁处理文件系统更新和 FAT 表更新效率极低。更致命的是很多嵌入式 SD 库在写入小数据后不会立刻把缓存刷到物理介质而是先放到卡内部缓存。如果你在缓存累积到一定程度前突然断电那这段数据就丢了。如果写入频率太高有些 SD 卡主控的垃圾回收会触发长暂停导致单次写入时间突然拉长几十毫秒甚至几百毫秒。主控如果没有等待机制就会判断超时返回失败然后卡就再也不响应了。所以对于数据记录设备第一条原则就是不要频繁打开和关闭文件也不要逐字节写。正确做法是维护一块内存缓冲区攒够一定大小再一次性写。4.2 缓冲区加定时落盘的实现思路这里给一个简化的实现思路配合 FatFs 使用。首先是初始化时打开一个日志文件并记录文件句柄FIL logFile; FATFS fs; f_mount(fs, , 1); f_open(logFile, 0:/log.txt, FA_OPEN_ALWAYS | FA_WRITE);注意如果你的板子用 SPI 模式挂载 SD 卡FatFs 的底层驱动要遵循 TF 卡的初始化流程尤其是 CMD0、CMD8、ACMD41 那套顺序不能乱。然后每次采集数据时先把数据放到内存缓冲区#define LOG_BUF_SIZE 512 uint8_t logBuf[LOG_BUF_SIZE]; uint16_t logLen 0; void appendLog(const char *line) { size_t len strlen(line); if (logLen len LOG_BUF_SIZE) { memcpy(logBuf logLen, line, len); logLen len; } else { flushLog(); appendLog(line); } } void flushLog(void) { if (logLen 0) { UINT written; f_write(logFile, logBuf, logLen, written); f_sync(logFile); logLen 0; } }只有缓冲区满或者定时时间到才调用一次 f_write 把整块数据写进去并调用 f_sync 确保数据落到卡上。这种批量写入方式能大幅降低 SD 卡主控的负担避免出现“写一会儿就罢工”的现象。另外日志文件如果不断增长建议在每次写入后检查文件大小超过设定阈值就关闭当前文件并新建一个新文件避免 FAT32 文件大小限制导致写失败。文件命名可以用日期时间或递增序号比如log_0001.txt、log_0002.txt。4.3 掉电保护与异常断电恢复写卡最怕断电。即使你有缓冲区如果系统在缓存还没落盘时断电数据也会丢。更麻烦的是如果断电发生在 FAT 表更新的过程中可能造成整个文件系统损坏卡上已有的日志全部打不开。工业上常用的方案是“双文件交替写入”或者“每次写满一条数据块就 f_sync”。f_sync 的代价是会增加写次数所以平衡点是关键。我一般保守一点每512字节落盘一次同时采用一个固定的 magic 数据头结构每次开机后扫描所有日志文件如果发现不完整块就加上损坏标记这样至少不会让整个分区崩溃。还有一个容易被忽略的点如果你的设备用锂电池供电断电时电压不是瞬间掉到0而是缓慢下降这时候主控可能一直在低压下“挣扎”SD 卡写失败却不复位。建议加一个电压检测在电压低于阈值时立即停止写卡、关闭文件并进入低功耗模式而不是继续硬写。这一招能显著降低文件系统损坏概率。5. 硬件与初始化SPI/SDIO时序和卡识别的坑5.1 SPI 模式下的速率和上拉电阻如果你的记录器用的是 SPI 模式速度和稳定性受很多硬件因素影响。第一个坑是 SPI 时钟频率过高。很多 SD 卡在 SDIO 模式下能跑几十MHz但转成 SPI 模式后并不支持那么高。保守起见8到10MHz是常见安全值。如果你用的是长杜邦线可能4MHz都跑到极限。所以遇到“只能写短时间”时先尝试把 SPI 时钟降下来比如从20MHz降到5MHz。如果问题消失说明是时序裕量不足。另一个容易被忽视的是上拉电阻。SD 卡的 MISO、MOSI、SCK、CS 信号线尤其是 MISO需要上拉到 VCC。很多开发板 SD 卡槽上已经有上拉但如果你是一块手工飞线板子不加上拉电阻初始化偶尔成功、写几秒钟后失败非常符合这个故障现象。用示波器抓一下 SPI 信号线的波形如果看到整条边像是斜坡而不是陡峭的方波那多半是线上电容太大或驱动能力太弱这时候降速或者加缓冲器比改代码更有效。5.2 初始化顺序与重试逻辑SD 卡初始化失败也是导致“只写一段时间”的一类原因。很多设备的软件只有在开机时初始化一次 SD 卡如果初始化途中被瞬间断电、电源毛刺打断之后就再也不重试。等到正常运行中电源稳定后其实卡还在线但软件已经认为卡不行了。正确的做法是在每次写失败后不要把错误直接返回而是先执行一段“重新初始化”流程。把卡的电源引脚拉低等10ms再上电然后重新发送 CMD0、CMD8、ACMD41、CMD17/CMD24 等初始化序列。如果连续重试3次还不行才报告“SD 卡错误”。同时初始化时要设置正确的超时时间。ACMD41 有时会长期忙尤其冷启动时有些卡要几百毫秒才准备好。很多库默认超时太短导致卡没真正就绪就认为失败。我的代码里一般会给 ACMD41 设置1秒的超时并循环100次每次间隔10ms确保慢启动的卡也能正常识别。5.3 插槽质量与静电防护插槽的机械接触问题前面供电部分提过接触电阻这里再说一个扩展层面。SD 卡插槽的卡扣松了或者机器振动大卡座内部接触片发生微小位移会导致数据线时通时断。记录器在车上、无人机、工业设备上使用时这个问题特别突出。有一种验证方法用胶带把 SD 卡和卡座粘牢让它无法位移再跑一下长时间记录测试。如果问题消失说明是接触不良换一个带锁紧结构的卡座是最直接的解决方案。静电也是个隐患尤其在干燥环境下频繁插拔 SD 卡后静电可能击穿 SD 卡供电引脚附近的小电阻或者主控 GPIO造成间歇性故障。正规一点的设备应该在卡座的数据线和电源线上加 ESD 防护器件比如 TVS 管。虽然这些防护器件正常情况下看着没用但在现场环境里能省掉大量售后排查时间。6. 软件侧隐患中断、看门狗、缓存这些“隐形杀手”6.1 中断打断写卡操作的后果很多开发者没有意识到SD 卡操作的底层时序对中断非常敏感尤其是 SPI 模式。如果在 f_write 过程中一个中断服务函数占用 CPU 时间过长或者中断优先级太高导致 SPI 传输被延迟几个字节那 SD 卡接收到的数据就错了。SD 卡侧会报 CRC 错误主控侧可能返回 FR_DISK_ERR。你可以查一下自己的代码里有没有在日志写入期间关闭了全局中断很多人的做法是干脆在写卡期间用__disable_irq()保护但这样写卡时间太长又会丢失实时采集。更好的做法是把 SD 卡操作放在优先级较低的主循环或者任务中采集数据用定时器中断放进环形队列互不干扰。如果你用的是 FreeRTOS 之类要给 SD 卡操作的任务一个独占信号量避免另一个任务同时读写文件。一个文件系统库同时被两个任务调用是极其经典的“跑一会就挂”的原因。6.2 看门狗把系统复位后SD 卡状态丢失看门狗是嵌入式系统的标配但它也会造成隐蔽的“只记录短时间”问题。如果系统中有个任务卡在一个死循环里看门狗就会在几秒后复位。复位后主控重新初始化、重新挂载 SD 卡看起来日志文件还在但只要这个死循环反复发生系统就会反复重启表现为记录器工作几秒到几分钟就“重启一次”SD 卡日志中断。排查方法是把系统运行时间写到日志里开机时打印启动原因。看门狗复位后有些芯片的复位状态寄存器会标记“看门狗复位”把这一信息输出来就能立刻判断是不是看门狗在搞鬼。如果是就别怪 SD 卡去查死循环或阻塞任务。另外有些主控内部看门狗在掉电时也会复位导致 SD 卡写入中断。如果你发现自己明明加了缓存还是掉数据检查一下 MCU 供电引脚上的掉电检测是否过于灵敏在电源毛刺瞬间触发了复位。6.3 文件句柄没关闭、缓存没刷新这个问题特别容易出现在“写一会儿就停”的 log 场景里。程序一开始打开文件之后一直在 f_write但从不调用 f_sync 或 f_close。文件系统库内部会有一个缓冲比如512字节只有缓冲满了才真正写到卡上。如果你写数据的速度很慢每次只写几十字节缓冲可能要几十秒甚至几分钟才满看起来日志文件在增长但一旦断电最后一段时间的数据就全丢了。更常见的是缓冲区满了要写回时失败但库没有妥善处理导致后续写入全部失败。为了避免这种情况建议采用定时 f_sync 策略每攒够一段时间比如1秒或一定数据量就刷新一次。文件句柄长期不关闭还会导致文件分配表被频繁修改损坏概率上升。如果系统需要长时间每个小时生成一个新文件记得先 f_close 旧文件再打开新文件不能让旧句柄一直悬空。7. 一套能落地的排查流程照着做就行7.1 从硬件到软件的分步排查清单这里我整理一个可以打印出来对照做的检查单适用于绝大多数“数据记录只短时间”的问题先做卡的健康测试把卡插到电脑用 h2testw 或 F3 写满再读回有错误就直接换卡。用 SD Card Formatter 完整格式化一次不要用 Windows 快速格式化。用示波器盯着 SD 卡 VCC跑一次密集写入测试看写卡瞬间电压跌落是否超过300mV。检查 SPI 时钟频率降到5MHz试跑同时确认 MISO 有上拉电阻。在代码里把每次写卡的错误码打印出来确认是否报 FR_DISK_ERR、FR_NOT_READY。检查是否在写卡期间有高频中断或看门狗复位把运行时间和复位原因录下来。改成缓冲批量写入并增加 f_sync 策略。如果是长时间运行强制每个小时或每达到一定大小就切换日志文件避免单个文件过大或 FAT 表频繁更新。检查卡座是否松动必要时换带锁紧的卡座。每一步都要能在复现后明确“问题有没有变化”。不要同时改两个变量否则你无法知道是哪个改动起了作用。7.2 用逻辑分析仪抓初始化时序如果你有条件逻辑分析仪是排查 SD 卡时序的利器。不需要太高端的型号采样率20MHz以上、支持 SPI 解码就能用。把探头接在主控的 CS、SCK、MOSI、MISO 上在记录器启动时抓一段初始化数据。重点看几个地方CMD0 是否被正确发送卡是否回复 R1CMD8 之后是否收到 0x01 和 0x000001AAACMD41 的 0x00 字节是否在重试后变成 0x01卡忙结束。如果卡一直回复 0x01 或 0x00 不变化说明初始化没完成问题多半在电源或卡兼容性上。还有一个技巧连续多次冷启动抓波形看每次的时序是否一致。如果偶尔一次初始化成功偶尔失败那就是噪声或电压波动影响而不是逻辑错误。7.3 区分“卡本身有问题”和“设备有问题”的快速方法如果你不想一开始就做全卡测试有个更快的区分方法拿两张不同品牌、不同容量的 SD 卡插到同一个记录器上分别测试。如果两张卡都只能写几分钟那问题八成在设备侧如果一张正常一张不正常那重点查卡。再多说一句网上很多“sd card formatter”的搜索场景是因为卡出厂格式是 exFAT 或私有格式嵌入式库只认 FAT32格式化后就能正常挂载。另一个常见现象是买到扩容卡标称32GB实际只有4GB写了一小会儿就报错。这种情况下无论你如何优化设备都没用只能换正规渠道的卡。我个人在实际项目里更倾向选择工业级或者至少是“高耐久”SD 卡来做长期数据记录这类卡针对连续写入做了优化垃圾回收策略更激进价格虽然贵一些但对无人值守的数据采集设备来说一次损坏造成的数据丢失成本更高。普通卡不是不能用但一定要配合前面说的缓冲写入和定期格式化维护才能稳定跑长周期。如果你照着上面的流程走下来大多数“只记录短时间”的问题都能定位到供电、格式化、写入策略或者硬件时序中的某一个环节。我自己修过不下十台类似的设备最后发现真正需要换卡的反而是少数绝大部分是电源或文件系统设置的问题。当然每个项目都有自己的特殊性如果你能在排查时把错误码、电压波形、初始化时序这些数据留下来哪怕自己暂时解决不了拿这些信息去问别人也能大大提高沟通效率。这种习惯比任何单一技巧都值钱。
返回列表