• 闪存中的键值对:无文件系统 minINI


      许多嵌入式系统应用需要以持久的方式存储某种数据:校准值、设置或日志信息。对于较少的数据量,使用外部存储器或文件系统是一种过度大材小用。在许多系统中,我使用minINI以“ini-file”的方式存储键值解析,但它需要使用某种文件系统。minINI很棒,效率很高,使获取和存储数据变得非常容易。但对于简单的情况,单个闪存页面或扇区正是我所需要的。相反,直接管理该页面,为什么不在没有文件系统的情况下使用minINI?

      例如,我使用上面的电路板驱动多达4个不同的步进电机和霍尔传感器。我需要存储校准偏移量和电机信息,并且每个电路板的信息可能不同。这些板通过RS-485总线连接,因此每个板都有一个唯一的地址。对于此应用程序,我需要存储键值对(例如,address=0x10)。为此,我使用minINI将数据存储在内部闪存的一页中,因此不需要文件系统。

    1、概述

      因为 minINI 处理文件,所以它需要某种文件系统。对于较小的系统或较小的数据量,随着代码大小和数据需求的增加,这增加了复杂性。在本文中,我将介绍一种对 minINI 库进行无文件和无文件系统适配的方法,该方法只需要一个小型且可配置的 RAM 缓冲区以及单个 FLASH 页面或扇区。这样,一个非常通用和用户友好的键值存储可用于小型嵌入式系统,而无需文件系统。
      该实现可在 GitHub 上找到。

    2、.ini文件

      .ini文件允许我将数据分组为“部分”和“键值”对。下面是一个示例:

    [motor0]
    name=split-flap 0
    offset=30
    x=0
     
    [motor1]
    offset=32
    

      使用minINI,我可以读/写这样的值。它具有“只读”模式,在这种模式下,我只能读取数据。

    3、minINI接口

      minINI 架构包括一个“粘合”接口。这样,它可以很容易地适应不同的文件系统。以下是 FatFS 的“粘合”实现:

    #define INI_FILETYPE    FIL
    #define ini_openread(filename,file)   (f_open((file), (filename), FA_READ+FA_OPEN_EXISTING) == FR_OK)
    #define ini_openwrite(filename,file)  (f_open((file), (filename), FA_WRITE+FA_CREATE_ALWAYS) == FR_OK)
    #define ini_close(file)               (f_close(file) == FR_OK)
    #define ini_read(buffer,size,file)    f_gets((buffer), (size),(file))
    #define ini_write(buffer,file)        f_puts((buffer), (file))
    #define ini_remove(filename)          (f_unlink(filename) == FR_OK)
     
    #define INI_FILEPOS                   unsigned long//DWORD
    #define ini_tell(file,pos)            (*(pos) = f_tell((file)))
    #define ini_seek(file,pos)            (f_lseek((file), *(pos)) == FR_OK)
    

    4、FLASH接口

      我们的想法是添加一个新的“粘合”,它不需要文件系统。相反,它直接读取和写入闪存,并模仿文件系统。
      这有一个限制:仅支持单个“ini文件”。该限制可以很容易地扩展到支持多个“文件”,但我真的没有看到这种需求,至少在我的应用程序中没有。

    5、配置

      配置是使用配置宏(请参见软件配置的不同方式)。下面是一个示例配置:

      这样就可以配置闪存。数据大小宏用于限制数据大小,以减少用于写入闪存的内存缓冲区的数量。
    需要从可用于链接器的闪存数量中减少/排除已使用的闪存,否则应用程序也可能使用它。以下是如何使用恩智浦MCUXpresso IDE从内存映射中减少内存:

    6、命令行

      该实现包括一个命令行/shell 接口。
      低于只读配置的状态:

      “McuMinINI”显示minINI的“核心”信息,而“ini”组用于闪存实现它。
      使用命令行界面,可以检查或修改数据:

    7、用法

      将键值对与 minINI 结合使用非常简单:我可以查询整数、布尔值、浮点值或字符串值。下面是获取设备存储地址的示例:

    #define NVMC_MININI_FILE_NAME         "settings.ini" /* 'file' name used */
     
    /* RS-485 bus settings */
    #define NVMC_MININI_SECTION_RS485     "rs485"
    #define NVMC_MININI_KEY_RS485_ADDR    "addr" /* long value: RS-485 address */
    ...
    *addr = McuMinINI_ini_getl(NVMC_MININI_SECTION_RS485, NVMC_MININI_KEY_RS485_ADDR, 0x1, NVMC_MININI_FILE_NAME);
    

      我真正喜欢minINI的是我可以提供默认值(在上面的示例中0x1):如果部分/键不存在,它将返回我指定的默认值:这样默认值就不需要配置区域中的任何空间。
    存储值类似于下面的示例:

    McuMinINI_ini_putl(NVMC_MININI_SECTION_RS485, NVMC_MININI_KEY_RS485_ADDR, addr, NVMC_MININI_FILE_NAME);
    

    8、内存要求

      当然,每个功能都会带来一些成本。但在这种情况下,我认为它真的是最小的。
      为了在闪存中存储数据,它至少需要一个扇区或闪存页。其大小取决于所使用的系统,例如1 kByte(LPC845)或2 KByte(Kinetis K22),具体取决于微控制器。大小配置为McuMinINI_CONFIG_FLASH_NVM_BLOCK_SIZE。
      对于写入访问,它需要一个RAM缓冲区来备份和存储来自FLASH的数据。该金额McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE配置。最小值为 64 个字节。根据要存储的数据量,128 或 256 可能更合理。对于只读访问,缓冲区量为零。根据所使用的微控制器和SDK,需要闪存驱动程序的设备句柄:例如,在Kinetis上,这需要额外的100字节。对于像LP845这样的其他产品,不需要手柄,因为ROM例程用于闪存编程。
      在 Kinetis 上,只读配置会增加大约 6 KB 的代码大小(-O0,无优化),而使其读写会增加额外的 3 KB (-O0)。添加shell支持会增加额外的1 KB:因此这意味着最多需要10 KB的闪存,在启用优化后降至约6 KB。到目前为止,还不到完整的文件系统支持,很容易是30-50 KB的闪存。

    9、总结

      有了这个用于minINI的附加粘合端口,可以在没有文件系统的情况下使用它。这使得它适用于较小的嵌入式系统。它支持只读和读写数据存储。它使用直接闪存读/写,只有在读写配置中,它才需要一个可配置的RAM缓冲区来写入或扩展数据。这样,就可以轻松地将“键值”对存储添加到任何嵌入式系统,而闪存的成本不到10 KB。
      您可以在GitHub上的McuLib中找到该实现。

    链接

    英文原文​:Key-Value pairs in FLASH Memory: file-system-less minINI | MCU on Eclipse

    欢迎关注:

  • 相关阅读:
    RHEL简单管理SELINUX
    CentOS配置samba服务
    CentOS中配置NFS服务
    CentOS里route命令详解
    Linux 进程管理之四大名捕
    编辑器之神-VIM
    纠结的链接——ln、ln -s、fs.symlink、require
    History(历史)命令用法 15 例
    备份MySQL数据库
    MySQL 资源大全
  • 原文地址:https://www.cnblogs.com/foxclever/p/16164571.html
Copyright © 2020-2023  润新知