如何避免因大写而损坏SD卡?

时间:2014-07-24 10:41:57

标签: c embedded sd-card fat

好的,首先有一点背景可以帮助我解决问题:

我正在研究一种从传感器收集某些数据并使用GSM调制解调器将它们发布到服务器的设备。由于GSM连接不是100%可靠,它将包含一个记录机制,可以将未发送的数据写入SD卡。

我们正在使用Chan's FatFs模块为我们提供文件系统,因为我们希望在PC上可以读取日志。

现在我一直在测试FAT系统的边界条件,即尝试完全填满卡片。

在第一次运行中,我打开文件并设置代码以继续写入字符串,直到驱动器已满。每次写入后程序都会同步。

我让代码在一夜之间运行。

第二天,我检查了SD卡。我发现该文件的大小只有150 MB。写了大约120万行。该卡仍然可以从中读取,但不能写入或格式化。

下次我尝试了相同类型的测试,但这次我使用f_lseek()函数将文件预分配到1GB。然后它将写入该文件,直到达到该限制。这次数据将在50次写入后同步。然后它将关闭该文件并打开另一个文件来执行相同操作。

正如你可以猜到的那样,另一张勇敢的小卡片当天就失去了它。

所以这些是我想要帮助的:

  1. 如何在写入大量数据时防止卡损坏?
  2. 长时间打开文件会产生任何负面影响吗?
  3. 由于完整代码可能太长,这里是写作发生的主要部分

    for(file_count=3;file_count>=0;--file_count){
    
        ax_log_msg(E_LOG_INFO,"===================================");
    
        ax_log_msg(E_LOG_INFO,file_names[file_count]);
    
    
        f_open(&file_ptr,file_names[file_count],FA_WRITE|FA_OPEN_ALWAYS);
    
        if(result!=FR_OK){
    
            ax_log_msg(E_LOG_INFO,"\n\rf_open Failed\n\rResult code");
            ax_log_msg(E_LOG_INFO,FRESULT_S[result]);
    
            continue;
    
        }
    
        ax_log_msg(E_LOG_INFO,"\n\rf_open Sucessfull");
    
        result=f_lseek(&file_ptr,FILE_SIZE_LIMIT_1GB);
    
        if(result!=FR_OK){
    
            ax_log_msg(E_LOG_INFO,"\n\rf_lseek Failed for preallocation\n\rResult code");
            ax_log_msg(E_LOG_INFO,FRESULT_S[result]);
    
            f_close(&file_ptr);
    
            continue;
    
        }
    
        ax_log_msg(E_LOG_INFO,"\n\rf_lseek Sucessfull for preallocation");
    
        f_lseek(&file_ptr,0);
    
        bytes_to_write=sizeof(messages[file_count]);
    
        write_count=0;
    
        while( (f_tell(&file_ptr) < FILE_SIZE_LIMIT_1GB )){
    
            result=f_write(&file_ptr,messages[file_count],bytes_to_write,&bytes_written);
    
            if(result==FR_OK){
                ++write_count;
    
                if(write_count%50==0){
    
                    f_sync(&file_ptr);
                }
    
            }else{
    
                ax_log_msg(E_LOG_INFO,"\n\rWrite failed\n\rFRESULT=");
                ax_log_msg(E_LOG_INFO,FRESULT_S[result]);
    
                break;
    
            }
    
        }
    
        f_close(&file_ptr);
    
    
    }
    

    注意:

    1. ax_log_msg()是要在控制台上打印的设备固件的一部分。
    2. FRESULT_S [result]用于将枚举结果代码转换为字符串。
    3. 如果缺少任何数据,请提及。

      谢谢

2 个答案:

答案 0 :(得分:3)

您可能需要缓冲整个数据块(可能是4 KB),以避免每次刷新时闪烁整个块。但是,文件系统或驱动程序应该为您执行此操作,只要您不明确地调用fflush,这是真正的教训。

为什么你需要这么频繁地同步?也许计时器比每个记录数的间隔更好?

答案 1 :(得分:-1)

由于每个扇区限制100,000个写周期,因此延长闪存寿命是一项非常具有挑战性的任务。在我对它进行编写测试后,我的一张卡片死了一个晚上。然后我计算了时间段,并且在一夜之间确实很容易执行100,000次写入(在同一扇区中)(不考虑经验中的计算)。

那时我被告知在一些文件系统中有一个智能监视器,他们计算并保持每个扇区的写入数量,以便每个扇区的写入数量相同,我猜。我既不接受也不考试。

我现在发现了一些非常受欢迎/高度评价的Raspberrypi答案/建议,我现在在这里引用它:

这些方法应通过以各种方式最小化读/写次数来延长SD卡的使用寿命:

禁用交换

交换是将部分SD卡用作易失性存储器的过程。这将增加可用的RAM量,但会导致大量的读/写。它不太可能显着提高性能。

使用swapoff命令禁用交换:

sudo swapoff --all

您还必须阻止它在重新启动后返回:

  • 对于使用dphys-swapfile管理交换文件的Raspbian(而不是&#34;普通&#34;交换分区),您只需sudo apt-get remove dphys-swapfile即可永久删除它。最好删除,因为将CONF_SWAPSIZE设置为0,如this answer中所述,似乎无法正常工作,并且在重新启动后仍会创建一个100MB的交换文件。
  • 对于使用交换分区而不是交换文件的其他发行版,请从/etc/fstab
  • 中删除相应的行

在文件系统上禁用日记功能

使用日记文件系统(例如ext3ext4没有日志)是减少读/写的选项。使用禁用日记功能的文件系统的明显缺点是由于非正常卸载(即电源故障,内核锁定等)导致的数据丢失。

您可以通过将ext3

挂载在ext2上来停用日记功能

您可以在未安装的驱动器上禁用ext4上的日记功能,如下所示:

tune4fs -O ^has_journal /dev/sdaX
e4fsck –f /dev/sdaX
sudo reboot

noatime Mount Flag

将noatime挂载标志分配给驻留在SD卡上的分区,方法是将其添加到/etc/fstab中分区的选项部分。

  

读取对文件系统的访问将不再导致与文件关联的atime信息的更新。 noatime设置的重要性在于它消除了系统对文件系统进行简单读取文件的需要。由于写入可能有点昂贵,如上一节所述,这可以带来可衡量的性能提升。请注意,只要在启用此选项的情况下写入文件,就会继续更新文件的写入时间信息。

RAM中的目录

/var/tmp//var/log等高度使用的目录可以像/etc/fstab一样重新定位到RAM中:

tmpfs /var/tmp tmpfs nodev,nosuid,size=50M 0 0

这将允许/var/tmp使用50MB的RAM作为磁盘空间。这样做的唯一问题是安装在RAM中的任何驱动器都不会在重新启动后持续存在。因此,如果您挂载/var/log并且系统遇到导致其重新启动的错误,您将无法找到原因。

外部硬盘中的目录

您还可以在持久性USB硬盘上安装某些目录。有关详细信息,请参阅this question

Raspberry Pi还可以从外部驱动器启动它的根分区。这可以通过USB或以太网进行,这意味着SD卡仅用于在引导期间委派给不同的设备。这需要一些内核黑客来完成,因为我不认为默认内核支持USB存储。您可以在this question或此external blog post找到更多信息。


以下是另一位回答者的另一个有趣的考虑因素:

关于flash filesystems的优秀文章。

谈论闪存文件系统时的重要问题如下:什么是磨损均衡? Wikipedia article。基本上,在闪存盘上,您可以写入有限的次数,直到块变坏。之后,文件系统(如果硬件上没有内置的耗损均衡管理,就像通常有SSD那样)必须将该块标记为无效,并且不再使用它。

典型的文件系统(例如reiserfs,ntfs,ext3等)是专为硬盘设计的,没有这些限制。

JFFS2

包括压缩和优雅的磨损均衡保护。

YAFFS2

  • 唯一能与众不同的东西:成功卸载后的安装时间短。
  • 实现一次写入属性:一旦将数据写入一个块,就不需要重写它。这对于防止磨损均衡很重要。

LogFS

  • 不是很成熟,但已经包含在Linux内核树中。
  • 支持比JFFS2 / YAFFS2更大的文件系统而不会出现问题。

UBIFS

  • 比LogFS更成熟
  • 编写缓存支持
  • 关于可扩展性:article。在大型磁盘上,性能优于JFFS2

EXT4

如果没有驱动程序或卡(例如SSD驱动器确实有内部磨损平衡,至少通常是手柄磨损均衡),则ext4不是最好的主意,因为它不适用于原始闪存使用。

什么是最好的?

当然,这取决于使用和支持。根据我从互联网上读到的内容,我推荐使用UBIFS。对大型文件系统的良好支持,成熟的开发阶段,充分的性能以及没有巨大的缺点。

感谢回答者:

How can I extend the life of my SD card?

Choice of filesystem for GNU/Linux on an SD card