littlefs介紹


1、littlefs主要用在微控制器和flash上,是一種嵌入式文件系統。主要有3個特點:

1)、掉電恢復

在寫入時即使復位或者掉電也可以恢復到上一個正確的狀態。

2)、擦寫均衡

有效延長flash的使用壽命

3)、有限的RAM/ROM

節省ROM和RAM空間

 

2、已有的文件系統

1)非掉電恢復,基於block的文件系統,常見的有FAT和EXT2。這兩個文件系統在寫入文件時是原地更新的,不具備非掉電恢復的特性。

2) 日志式的文件系統,比如JFFS,YAFFS等,具備掉電恢復的特性。但是這幾個系統消耗了太多的RAM,且性能較低。

3) EXT4和COW類型的btrfs具有良好的恢復性和讀寫性能,但是需要的資源過多,不適合小型的嵌入式系統。

 

    littlefs綜合了日志式文件系統和COW文件系統的優點。從sub-block的角度來看,littlefs是基於日志的文件系統,提供了metadata的原子更新;從super-block的角度,littlefs是基於block的COW樹。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

移植LittleFs

MT2503的板子外掛8Mbit的SPI Flash,本打算移植Fatfs,但Fatfs並不支持Wear leveling,后發現LittleFs,一個專門為單片機設計的文件系統,並且支持fail-safe。

詳細介紹:https://os.mbed.com/blog/entry/littlefs-high-integrity-embedded-fs/
LittleFs Github https://github.com/ARMmbed/littlefs

LittleFs的移植很簡單,只需實現Flash的讀、寫和擦除基本操作即可,官方例子如下:

  1.  
    #include "lfs.h"
  2.  
     
  3.  
    // variables used by the filesystem
  4.  
    lfs_t lfs;
  5.  
    lfs_file_t file;
  6.  
     
  7.  
    // configuration of the filesystem is provided by this struct
  8.  
    const struct lfs_config cfg = {
  9.  
    // block device operations
  10.  
    .read = user_provided_block_device_read,
  11.  
    .prog = user_provided_block_device_prog,
  12.  
    .erase = user_provided_block_device_erase,
  13.  
    .sync = user_provided_block_device_sync,
  14.  
     
  15.  
    // block device configuration
  16.  
    .read_size = 16,
  17.  
    .prog_size = 16,
  18.  
    .block_size = 4096,
  19.  
    .block_count = 128,
  20.  
    .lookahead = 128,
  21.  
    };
  22.  
     
  23.  
    // entry point
  24.  
    int main(void) {
  25.  
    // mount the filesystem
  26.  
    int err = lfs_mount( &lfs, &cfg);
  27.  
     
  28.  
    // reformat if we can't mount the filesystem
  29.  
    // this should only happen on the first boot
  30.  
    if (err) {
  31.  
    lfs_format( &lfs, &cfg);
  32.  
    lfs_mount( &lfs, &cfg);
  33.  
    }
  34.  
     
  35.  
    // read current count
  36.  
    uint32_t boot_count = 0;
  37.  
    lfs_file_open( &lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
  38.  
    lfs_file_read( &lfs, &file, &boot_count, sizeof(boot_count));
  39.  
     
  40.  
    // update boot count
  41.  
    boot_count += 1;
  42.  
    lfs_file_rewind( &lfs, &file);
  43.  
    lfs_file_write( &lfs, &file, &boot_count, sizeof(boot_count));
  44.  
     
  45.  
    // remember the storage is not updated until the file is closed successfully
  46.  
    lfs_file_close( &lfs, &file);
  47.  
     
  48.  
    // release any resources we were using
  49.  
    lfs_unmount( &lfs);
  50.  
     
  51.  
    // print the boot count
  52.  
    printf("boot_count: %d\n", boot_count);
  53.  
    }
已經實現的Flash驅動聲明:
  1.  
    void flash_read_block(kal_uint32 addr, kal_uint8 *buff, kal_uint32 len);
  2.  
    void flash_write_block(kal_uint32 addr, kal_uint8 *buff, kal_uint32 len);
  3.  
    void flash_erase_block(kal_uint32 addr);
操作接口配置:
  1.  
    static int _block_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
  2.  
    {
  3.  
    flash_read_block(block * c->block_size + off, (kal_uint8 *)buffer, (kal_uint32)size);
  4.  
    return 0;
  5.  
    }
  6.  
    static int _block_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
  7.  
    {
  8.  
    flash_write_block(block * c->block_size + off, (kal_uint8 *)buffer, (kal_uint32)size);
  9.  
    return 0;
  10.  
    }
  11.  
    static int _block_erase(const struct lfs_config *c, lfs_block_t block)
  12.  
    {
  13.  
    flash_erase_block(block * c->block_size);
  14.  
    return 0;
  15.  
    }
  16.  
    static int _block_sync(const struct lfs_config *c)
  17.  
    {
  18.  
    return 0;
  19.  
    }
  20.  
     
  21.  
    const struct lfs_config cfg = {
  22.  
    // block device operations
  23.  
    .read = _block_read,
  24.  
    .prog = _block_prog,
  25.  
    .erase = _block_erase,
  26.  
    .sync = _block_sync,
  27.  
     
  28.  
    // block device configuration
  29.  
    .read_size = 16,
  30.  
    .prog_size = 16,
  31.  
    .block_size = 4096,
  32.  
    .block_count = 256,
  33.  
    .lookahead = 256,
  34.  
    };

編譯時出現大量Error,經過折騰最終搞定。

總結了一下:
1. armcc默認不支持對結構體指定成員名稱進行初始化、不支持可執行代碼之后聲明變量,CFLAG添加 –gnu 可以解決問題,添加方法請參考《MTK功能機MMI,添加GNU特性》
2. LittleFs需要提供系統的malloc, free函數接口。

 

原文地址:http://www.noblock.cn/?p=183

-------------------------------------------------------------------------------------------------------------------------------------------------------------

littlefs 重要的數據結構

1、文件類型

  1. // File types

  2. enum lfs_type {

  3. // file types

  4. LFS_TYPE_REG = 0x001,

  5. LFS_TYPE_DIR = 0x002,

  6.  
  7. // internally used types

  8. LFS_TYPE_SPLICE = 0x400,

  9. LFS_TYPE_NAME = 0x000,

  10. LFS_TYPE_STRUCT = 0x200,

  11. LFS_TYPE_USERATTR = 0x300,

  12. LFS_TYPE_FROM = 0x100,

  13. LFS_TYPE_TAIL = 0x600,

  14. LFS_TYPE_GLOBALS = 0x700,

  15. LFS_TYPE_CRC = 0x500,

  16.  
  17. // internally used type specializations

  18. LFS_TYPE_CREATE = 0x401,

  19. LFS_TYPE_DELETE = 0x4ff,

  20. LFS_TYPE_SUPERBLOCK = 0x0ff,

  21. LFS_TYPE_DIRSTRUCT = 0x200,

  22. LFS_TYPE_CTZSTRUCT = 0x202,

  23. LFS_TYPE_INLINESTRUCT = 0x201,

  24. LFS_TYPE_SOFTTAIL = 0x600,

  25. LFS_TYPE_HARDTAIL = 0x601,

  26. LFS_TYPE_MOVESTATE = 0x7ff,

  27.  
  28. // internal chip sources

  29. LFS_FROM_NOOP = 0x000,

  30. LFS_FROM_MOVE = 0x101,

  31. LFS_FROM_USERATTRS = 0x102,

  32. };

2、文件打開時的標志

  1. // File open flags

  2. enum lfs_open_flags {

  3. // open flags

  4. LFS_O_RDONLY = 1, // Open a file as read only

  5. LFS_O_WRONLY = 2, // Open a file as write only

  6. LFS_O_RDWR = 3, // Open a file as read and write

  7. LFS_O_CREAT = 0x0100, // Create a file if it does not exist

  8. LFS_O_EXCL = 0x0200, // Fail if a file already exists

  9. LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size

  10. LFS_O_APPEND = 0x0800, // Move to end of file on every write

  11.  
  12. // internally used flags

  13. LFS_F_DIRTY = 0x010000, // File does not match storage

  14. LFS_F_WRITING = 0x020000, // File has been written since last flush

  15. LFS_F_READING = 0x040000, // File has been read since last flush

  16. LFS_F_ERRED = 0x080000, // An error occured during write

  17. LFS_F_INLINE = 0x100000, // Currently inlined in directory entry

  18. LFS_F_OPENED = 0x200000, // File has been opened

  19. };

3、文件seek時的標志

  1. // File seek flags

  2. enum lfs_whence_flags {

  3. LFS_SEEK_SET = 0, // Seek relative to an absolute position

  4. LFS_SEEK_CUR = 1, // Seek relative to the current file position

  5. LFS_SEEK_END = 2, // Seek relative to the end of the file

  6. };

4、lfs的配置參數

  1. // Configuration provided during initialization of the littlefs

  2. struct lfs_config {

  3. // Opaque user provided context that can be used to pass

  4. // information to the block device operations

  5. /* 這個參數主要是傳遞給block驅動代碼 */

  6. void *context;

  7.  
  8. /* 從設備讀數據 */

  9. int (*read)(const struct lfs_config *c, lfs_block_t block,

  10. lfs_off_t off, void *buffer, lfs_size_t size);

  11.  
  12. /* 向設備寫入數據,block設備在寫入前必須已經erase了 */

  13. int (*prog)(const struct lfs_config *c, lfs_block_t block,

  14. lfs_off_t off, const void *buffer, lfs_size_t size);

  15.  
  16. /* 擦除block */

  17. int (*erase)(const struct lfs_config *c, lfs_block_t block);

  18.  
  19. /* sync塊設備的狀態 */

  20. int (*sync)(const struct lfs_config *c);

  21.  
  22. /* 最小的讀取單元大小 */

  23. lfs_size_t read_size;

  24.  
  25. /* 最小的寫入數據單元大小,也是數據metadata pair中tag的對齊尺寸 */

  26. lfs_size_t prog_size;

  27.  
  28. /* 最小的擦除單元大小。可以比flash的實際block尺寸大。但是對於ctz類型的文件,block size是最小的分配單元。同時block size必須是

  29. read size和program size的倍數,block size會存儲在superblock中 */

  30. lfs_size_t block_size;

  31.  
  32. /* 屬於文件系統的block數量,block count會存儲在superblock中 */

  33. lfs_size_t block_count;

  34.  
  35. /* 文件系統進行垃圾回收時的block的擦除次數,推薦取值100-1000.值越大垃圾回收的次數越少,性能越好 */

  36. int32_t block_cycles;

  37.  
  38. /* littlefs需要一個read cache,一個program cache,每個文件也需要一個cache。cache越大性能越好,會減少會flash的訪問次數,

  39. cache必須是block的read size和program size的倍數,同時是block size的因數 */

  40. lfs_size_t cache_size;

  41.  
  42. /* lookahead buffer的尺寸。lookahead buffer主要是block alloctor在分配塊的時候用到。lookahead size必須是8的倍數,

  43. 因為它是采用bitmap的形式存儲的 */

  44. lfs_size_t lookahead_size;

  45.  
  46. /* cache size大小的read buffer,可以靜態分配也可以動態分配 */

  47. void *read_buffer;

  48.  
  49. /* cache size大小的program buffer,可以靜態分配也可以動態分配 */

  50. void *prog_buffer;

  51.  
  52. /* lookahead_size大小的lookahead buffer,且是32-bit對齊的,即可以靜態分配也可以動態分配 */

  53. void *lookahead_buffer;

  54.  
  55. /* 文件名的最大長度,這個值會存儲在superblock中 */

  56. lfs_size_t name_max;

  57.  
  58. /* 文件的最大長度,存儲在superblock中 */

  59. lfs_size_t file_max;

  60.  
  61. /* 用戶屬性的最大長度 */

  62. lfs_size_t attr_max;

  63. };

5、文件信息

  1. // File info structure

  2. struct lfs_info {

  3. // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR 普通文件或者目錄

  4. uint8_t type;

  5.  
  6. // Size of the file, only valid for REG files. Limited to 32-bits. 對於普通文件才有意義

  7. lfs_size_t size;

  8.  
  9. // Name of the file stored as a null-terminated string. Limited to

  10. // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to

  11. // reduce RAM. LFS_NAME_MAX is stored in superblock and must be

  12. // respected by other littlefs drivers.

  13. /* 字符串形式的文件名 */

  14. char name[LFS_NAME_MAX+1];

  15. };

6、用戶屬性

  1. struct lfs_attr {

  2. /* 屬性類型 */

  3. uint8_t type;

  4.  
  5. /* 存儲屬性的buffer */

  6. void *buffer;

  7.  
  8. /* 屬性的長度,最大值為LFS_ATTR_MAX */

  9. lfs_size_t size;

  10. };

7、文件open時的配置

  1. struct lfs_file_config {

  2. /* cache size長度的buffer,可以靜態分配也可以動態分配 */

  3. void *buffer;

  4.  
  5. /* 用戶屬性,讀文件時,attr存儲從flash上讀取的文件用戶屬性,寫入文件時,attr存放用戶指定的文件屬性並會寫入到flash中 */

  6. struct lfs_attr *attrs;

  7.  
  8. /* 用戶屬性的長度 */

  9. lfs_size_t attr_count;

  10. };

8、lfs_cache結構

  1. typedef struct lfs_cache {

  2. lfs_block_t block; // cache中的數據屬於的block

  3. lfs_off_t off; // cache中的數據在block上的偏移地址

  4. lfs_size_t size; // cache的大小

  5. uint8_t *buffer; // cache數據的存放地址

  6. } lfs_cache_t;

9、lfs_mdir結構,代表metadata pair,dir本身所在的block

  1. typedef struct lfs_mdir {

  2. lfs_block_t pair[2]; // dir的metadata pair所在的block

  3. uint32_t rev; // metadata pair的revision

  4. lfs_off_t off; // tag的偏移地址

  5. uint32_t etag;

  6. uint16_t count;

  7. bool erased;

  8. bool split; // metadata pair是否是鏈表

  9. lfs_block_t tail[2]; // 用於metadata pair鏈表

  10. } lfs_mdir_t;

10、lfs目錄結構

  1. // littlefs directory type

  2. typedef struct lfs_dir {

  3. struct lfs_dir *next; // 指向子目錄

  4. uint16_t id;

  5. uint8_t type; // LFS_TYPE_DIR

  6. lfs_mdir_t m; // 代表dir的metadata pair

  7. lfs_off_t pos; // 在目錄中的當前位置,主要用在seek,tell和rewind操作中

  8. lfs_block_t head[2];

  9. } lfs_dir_t;

11、lfs文件類型

  1. // littlefs file type

  2. typedef struct lfs_file {

  3. struct lfs_file *next;

  4. uint16_t id; // metadata tag中的id,在文件open時獲取

  5. uint8_t type; // LFS_TYPE_REG 或者 LFS_TYPE_DIR

  6. lfs_mdir_t m; // 文件所在的目錄的metadata pair

  7.  
  8. struct lfs_ctz {

  9. lfs_block_t head;

  10. lfs_size_t size;

  11. } ctz; // 指向大文件的CTZ skip-list。對於小文件則直接inline了,無需CTZ skip-list

  12.  
  13. uint32_t flags; // lfs_open_flags中的值

  14. lfs_off_t pos; // 文件訪問時的偏移

  15. lfs_block_t block; // file當前的block

  16. lfs_off_t off; // 在block內的offset

  17. lfs_cache_t cache; // 文件訪問時的cache

  18.  
  19. const struct lfs_file_config *cfg; // 文件open時的配置參數,包含一個buffer以及用戶屬性

  20. } lfs_file_t;

12、lfs superblock結構

  1. typedef struct lfs_superblock {

  2. uint32_t version; // 文件系統的版本號

  3. lfs_size_t block_size; // 文件系統的block size,和flash的block size不一定相同

  4. lfs_size_t block_count; // 文件系統包含的block數量,每個block的大小等於上面的block size

  5. lfs_size_t name_max; // 文件名的最大長度

  6. lfs_size_t file_max; // 文件的最大長度

  7. lfs_size_t attr_max; // 用戶屬性的最大長度

  8. } lfs_superblock_t;

13、lfs文件系統類型結構

  1. // The littlefs filesystem type

  2. typedef struct lfs {

  3. lfs_cache_t rcache; // read cache

  4. lfs_cache_t pcache; // program cache

  5. lfs_block_t root[2]; // 根目錄所在的block

  6. struct lfs_mlist {

  7. struct lfs_mlist *next; // 指向下一個節點

  8. uint16_t id; // metadata pair的id

  9. uint8_t type; // metadata pair的類型

  10. lfs_mdir_t m; // metadata pair

  11. } *mlist; // metadata pair list

  12. uint32_t seed; // block alloctor的隨機數生成的seed

  13.  
  14. struct lfs_gstate {

  15. uint32_t tag;

  16. lfs_block_t pair[2];

  17. } gstate, gpending, gdelta; // 用於目錄操作sync的global state,

  18.  
  19. struct lfs_free {

  20. lfs_block_t off; // 記錄lookahead buffer中起始block的偏移

  21. lfs_block_t size; // lookahead buffer中block的數量,注意lookahead采用的是bitmap的形式,因此size=8*lookahead_size

  22. lfs_block_t i; // lookahead buffer內部的偏移地址

  23. lfs_block_t ack; // 剩余block的數量,初始值為block count,如果該值為0,表示已經沒有free block了

  24. uint32_t *buffer; // buffer的長度為lookahead size

  25. } free; // lookahead buffer,用於分配free block

  26.  
  27. const struct lfs_config *cfg; // 文件系統的配置參數

  28. lfs_size_t name_max; // 文件名的最大長度,和superblock中的name_max值相同

  29. lfs_size_t file_max; // 文件的最大長度,和superblock中的file_max值相同

  30. lfs_size_t attr_max; // 用戶屬性的最大長度,和superblock中的attr_max值相同

  31. } lfs_t;

----------------------------------------------------------------------------------------------------------------------------------------------------------------

小型文件系統FatFS和LittleFS對比和區別

對於許多物聯網設備而言,擁有一個小型且具有彈性的文件系統至關重要。

在MCU上運行的文件系統不多,絕大部分人應該知道FatFS這個文件系統,今天就給大家講講FatFS和LittleFS的內容,以及他們之間的一些差異。

一、文件系統FatFS

FatFs是一個通用的文件系統(FAT/exFAT)模塊,用於在小型嵌入式系統中實現FAT文件系統。

網址:

http://elm-chan.org/fsw/ff/00index_e.html

 

FatFs組件的編寫遵循ANSI C(C89),完全分離於磁盤 I/O 層,因此不依賴於硬件平台。它可以嵌入到資源有限的微控制器中,如 8051, PIC, AVR, ARM, Z80, RX等等,不需要做任何修改。

---來自百度百科

特征

a.DOS/ Windows兼容的FAT/exFAT文件系統。

b.平台無關,容易移植。

c.程序代碼和工作區的占用空間非常小。

d.支持以下各種配置選項:

  • ANSI / OEM或Unicode中的長文件名。

  • exFAT文件系統,64位LBA和GPT可存儲大量數據。

  • RTOS的線程安全。

  • 多個卷(物理驅動器和分區)。

  • 可變扇區大小。

  • 多個代碼頁,包括DBCS。

  • 只讀,可選API,I / O緩沖區等...

如果你會使用STM32CubeMX,想要使用FatFS非常容易,輕松幾步就能將STM32“變成”一個U盤。

二、文件系統Littlefs

知道Littlefs文件系統的人相對比較少,但是如果使用過Mbed OS系統的人絕大部分都應該知道。

Mbed OS是Arm公司針對Cortex-M系列處理器,面向IoT開發的一套免費、開源開源嵌入式操作系統,專門為物聯網中的“things”而設計。

而Littlefs只是Mbed其中的一部分內容,如下框圖:

源碼地址:

https://github.com/armmbed/mbed-littlefs

Littlefs特點:

  • 占用資源小:物聯網設備受到ROM和RAM的限制。

  • 斷電恢復能力:要求文件系統保持一致,並將數據刷新到底層存儲。

  • 平均磨損:通常情況下,存儲支持每塊數量有限的擦除,因此使用整個存儲設備對於可靠性非常重要。

用法也挺簡單,參看官方例程:

  1.  
    #include "LittleFileSystem2.h"
  2.  
    #include "SPIFBlockDevice.h"
  3.  
     
  4.  
     
  5.  
    // Physical block device, can be any device that supports the BlockDevice API
  6.  
    SPIFBlockDevice bd(PTE2, PTE4, PTE1, PTE5);
  7.  
     
  8.  
     
  9.  
    // Storage for the littlefs
  10.  
    LittleFileSystem2 fs("fs");
  11.  
     
  12.  
     
  13.  
    // Entry point
  14.  
    int main() {
  15.  
    // Mount the filesystem
  16.  
    int err = fs.mount(&bd);
  17.  
    if (err) {
  18.  
    // Reformat if we can't mount the filesystem,
  19.  
    // this should only happen on the first boot
  20.  
    LittleFileSystem2::format(&bd);
  21.  
    fs.mount(&bd);
  22.  
    }
  23.  
     
  24.  
     
  25.  
    // Read the boot count
  26.  
    uint32_t boot_count = 0;
  27.  
    FILE *f = fopen( "/fs/boot_count", "r+");
  28.  
    if (!f) {
  29.  
    // Create the file if it doesn't exist
  30.  
    f = fopen( "/fs/boot_count", "w+");
  31.  
    }
  32.  
    fread(&boot_count, sizeof(boot_count), 1, f);
  33.  
     
  34.  
     
  35.  
    // Update the boot count
  36.  
    boot_count += 1;
  37.  
    rewind(f);
  38.  
    fwrite(&boot_count, sizeof(boot_count), 1, f);
  39.  
     
  40.  
     
  41.  
    // Remember that storage may not be updated until the file
  42.  
    // is closed successfully
  43.  
    fclose(f);
  44.  
     
  45.  
     
  46.  
    // Release any resources we were using
  47.  
    fs.unmount();
  48.  
     
  49.  
     
  50.  
    // Print the boot count
  51.  
    printf("boot_count: %ld\n", boot_count);
  52.  
    }

三、文件系統對比

每一種產物都有它存在的價值,文件系統也同樣如此,各有各的優缺點,下面簡單羅列幾點它們的區別。

1.資源RAM / ROM大小

Littlefs是Mbed OS中的高完整性嵌入式文件系統,經過優化可與RAM和ROM有限的MCU一起使用。

Littlefs高度集成的嵌入式文件系統使用比FAT少的13K ROM和少於4K的RAM。

2.失電恢復能力

littlefs具有強大的copy-on-write保證,並且磁盤上的存儲總是保持有效狀態,可能有隨機電源故障的系統適合該文件系統。

3.磨損均衡

嵌入式設備使用的大多數存儲芯片都支持每個扇區有限的擦除集,如果沒有均衡,則嵌入式設備的壽命可能會受到影響。

參考來源:

https://os.mbed.com/blog/entry/littlefs-high-integrity-embedded-fs/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM