電子產(chǎn)業(yè)一站式賦能平臺

PCB聯(lián)盟網(wǎng)

搜索
查看: 166|回復(fù): 0
收起左側(cè)

使用FAL分區(qū)管理與easyflash變量管理

[復(fù)制鏈接]

502

主題

502

帖子

3383

積分

四級會員

Rank: 4

積分
3383
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2024-10-1 11:38:00 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
1.
FAL組件
1.1
什么是FAL
FAL (Flash Abstraction Layer) Flash 抽象層,是對 Flash 及基于 Flash 的分區(qū)進行管理、操作的抽象層,對上層統(tǒng)一了 Flash 及 分區(qū)操作的 API (框架圖如下所示),并具有以下特性:
支持靜態(tài)可配置的分區(qū)表,并可關(guān)聯(lián)多個 Flash 設(shè)備;
分區(qū)表支持 自動裝載 。避免在多固件項目,分區(qū)表被多次定義的問題;
代碼精簡,對操作系統(tǒng) 無依賴 ,可運行于裸機平臺,比如對資源有一定要求的 Bootloader;
統(tǒng)一的操作接口。保證了文件系統(tǒng)、OTA、NVM(例如:EasyFlash https://github.com/armink-rtt-pkgs/EasyFlash) 等對 Flash 有一定依賴的組件,底層 Flash 驅(qū)動的可重用性;
自帶基于 Finsh/MSH 的測試命令,可以通過 Shell 按字節(jié)尋址的方式操作(讀寫擦) Flash 或分區(qū),方便開發(fā)者進行調(diào)試、測試;


通過上圖我們也可以清晰明了了,看到,F(xiàn)AL抽象層向下可以通過Flash硬件進行統(tǒng)一管理,當然也可以使用SFUD框架(串行Flash通用驅(qū)動庫,這部分RT-Thread已完成官方框架的移植同時提供多個應(yīng)用歷程),而對上也可以使用如DFS、NVM提供的Flash硬件統(tǒng)一訪問接口,方便用戶更加直接方便對底層Flash硬件的訪問操作。
注:非易失性存儲器 (NVM):在芯片電源關(guān)閉期間保存存儲在其中的數(shù)據(jù)。因此,它被用于沒有磁盤的便攜式設(shè)備中的內(nèi)存,以及用于可移動存儲卡等用途。主要類型有:非易失性半導(dǎo)體存儲器 (Non-volatile semiconductor memory, NVSM) 將數(shù)據(jù)存儲在浮柵存儲單元中,每個單元都由一個浮柵(floating-gate) MOSFET 組成。
關(guān)于存儲,可以用一張圖來解釋:

來源:ROM、RAM、FLASH、NVM......一文搞定(https://blog.csdn.net/lianyunyouyou/article/details/118277207)
1.2
使用ENV配置FAL
在RT-Thread v4.1.0之前,F(xiàn)AL是作為軟件包形式對用戶開放使用的,而v4.1.0之后,F(xiàn)AL被RT-Thread官方重新定義為RTT組件的一部分,這樣也能更加方便用戶的開發(fā)。
我們下面正式講解FAL組件的使用:
首先打開ENV工具,根據(jù)以下路徑打開FAL使能 RT-Thread Components->
  • FAL: flash abstraction layer,由于我們后面會用到SFUD,所以這里把 FAL uses SFUD drivers 一并使能,并修改FAL設(shè)備名稱為 W25Q128.

    完成上述操作后保存退出,并使用 scons --target=mdk5 重新生成MDK5文件并打開
    1.3
    FAL SFUD 移植
    為了提供示例,我們選用 W25Q128 spi flash 作為測試模塊,并且使用SFUD框架對spi flash設(shè)備進行管理和驅(qū)動。
    由于目前RT-Thread的SFUD已經(jīng)對 W25Q128 完成支持,根據(jù)官方的使用手冊,我們僅需編寫 fal_cfg.h 文件完成對 FAL_FLASH_DEV_TABLE 及 FAL_PART_TABLE 的定義即可。文件存放路徑:.\rt-thread\bsp\lpc55sxx\lpc55s69_nxp_evk\board\ports\fal_cfg.h
  • // fal.cfg.h
    /* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2023-04-21     Wangyuqiang  the first version */#ifndef _FAL_CFG_H_#define _FAL_CFG_H_
    #include #include
    #ifndef FAL_USING_NOR_FLASH_DEV_NAME#define NOR_FLASH_DEV_NAME             "norflash0"#else#define NOR_FLASH_DEV_NAME              FAL_USING_NOR_FLASH_DEV_NAME#endif
    /* Flash device Configuration */
    extern struct fal_flash_dev nor_flash0;
    /* flash device table */
    #define FAL_FLASH_DEV_TABLE                                          \{                                                                    \    &nor_flash0,                                                     \}
    /* Partition Configuration */
    #ifdef FAL_PART_HAS_TABLE_CFG
    /* partition table */
    #define FAL_PART_TABLE                                                                                                  \{                                                                                                                       \    {FAL_PART_MAGIC_WROD,  "easyflash", NOR_FLASH_DEV_NAME,                                    0,       512 * 1024, 0}, \    {FAL_PART_MAGIC_WROD,   "download", NOR_FLASH_DEV_NAME,                           512 * 1024,      1024 * 1024, 0}, \    {FAL_PART_MAGIC_WROD, "wifi_image", NOR_FLASH_DEV_NAME,                  (512 + 1024) * 1024,       512 * 1024, 0}, \    {FAL_PART_MAGIC_WROD,       "font", NOR_FLASH_DEV_NAME,            (512 + 1024 + 512) * 1024,  7 * 1024 * 1024, 0}, \    {FAL_PART_MAGIC_WROD, "filesystem", NOR_FLASH_DEV_NAME, (512 + 1024 + 512 + 7 * 1024) * 1024,  7 * 1024 * 1024, 0}, \}#endif /* FAL_PART_HAS_TABLE_CFG */
    #endif /* _FAL_CFG_H_ */此時編譯的話是找不到該頭文件的,需要我們在Keil中設(shè)置:

    在RTT FAL組件中的SFUD提供的 fal_flash_dev 對象默認的nor_flash0參數(shù)中,flash大小默認為8M,而 W25Q128 最大最16M,我們可以選擇在 .\rt-thread\components\fal\samples\porting\fal_flash_sfud_port.c文件中對struct fal_flash_dev nor_flash0 進行修改:
  • struct fal_flash_dev nor_flash0 ={    .name       = FAL_USING_NOR_FLASH_DEV_NAME,    .addr       = 0,    .len        = 16 * 1024 * 1024,    .blk_size   = 4096,    .ops        = {init, read, write, erase},    .write_gran = 1};當然也可以選擇不進行修改,根據(jù)大佬的原話就是因為在調(diào)用初始化接口函數(shù)init后,會從flash設(shè)備讀取正確的參數(shù)更新到nor_flash0表項中,我們在使用FAL組件前都需要調(diào)用FAL初始化函數(shù)fal_init,其內(nèi)調(diào)用flash設(shè)備初始化函數(shù)fal_flash_init,最后會調(diào)用注冊到fal_flash_dev設(shè)備表項中的初始化函數(shù)device_table->ops.init,所以nor_flash0表項參數(shù)會在FAL初始化時被更新。
    同時我們需要開啟SFUD框架支持,打開ENV工具,由于SFUD的使用需要指定一個spi設(shè)備,這里我選擇使用最近移植好的軟件spi,路徑 Hardware Drivers Config->On-chip Peripheral Drivers->
  • Enable soft SPI BUS->
  • Enable soft SPI1 BUS (software simulation) ,這里我的測試開發(fā)板是恩智浦的LPC55S69-EVK,并且這款bsp的軟件模擬spi由我本人對接,關(guān)于這部分的軟件spi引腳定義可以選用默認即可,當然也可以使用自定義引腳,記住不要與其他引腳產(chǎn)生沖突。

    此時我們回到ENV主界面,進入 RT-Thread Components->Device Drivers->Using Serial Flash Universal Driver ,此時我們才可以看到SFUD選項出現(xiàn)(如果沒有使能spi是沒法看到的),使能后保持默認即可

    到這里,ENV的配置暫時告一段落!
    1.4
    FAL SFUD 測試用例
    為了驗證 W25Q128 及軟件模擬spi在SFUD框架上是否能夠成功運行,我們在 .\rt-thread\bsp\lpc55sxx\lpc55s69_nxp_evk\board\ports\ 下新建一個 soft_spi_flash_init.c 文件,代碼如下
  • /* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2023-04-21     Wangyuqiang  the first version */
    #include #include "spi_flash.h"#include "spi_flash_sfud.h"#include "drv_soft_spi.h"#include "drv_pin.h"#include "rtconfig.h"
    #define cs_pin  GET_PINS(1,9)
    static int rt_soft_spi_flash_init(void){  int result = -1;
        result = rt_hw_softspi_device_attach("sspi1", "sspi10", cs_pin);  rt_kprintf("value is %d
    ",result);    if(result == RT_EOK)  {    rt_kprintf("rt_hw_softspi_device_attach successful!
    ");  }
        if (RT_NULL == rt_sfud_flash_probe("W25Q128", "sspi10"))    {        return -RT_ERROR;    }
        return RT_EOK;}INIT_COMPONENT_EXPORT(rt_soft_spi_flash_init);這里我們需要指定一個片選引腳,我暫時使用了 sspi2 的SCK引腳作為片選,這里注意不要同時打開 sspi1 和 sspi2 ,后續(xù)我會專門上傳一個通用GPIO作為片選引腳,到時候就不會產(chǎn)生問題了。然后軟件spi設(shè)備的掛載使用的是 sspi1 bus 及 sspi10 device ,并且掛載flash設(shè)備到 sspi10 。
    另外我們在 .\rt-thread\bsp\lpc55sxx\lpc55s69_nxp_evk\board\ports\ 下新建 fal_sample.c 文件,并編寫測試代碼:
  • //fal_sample.c
    /* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2023-04-21     Wangyuqiang  the first version */ #include "rtthread.h"#include "rtdevice.h"#include "board.h"#include "fal.h"
    #define BUF_SIZE 1024
    static int fal_test(const char *partiton_name){    int ret;    int i, j, len;    uint8_t buf[BUF_SIZE];    const struct fal_flash_dev *flash_dev = RT_NULL;    const struct fal_partition *partition = RT_NULL;
        if (!partiton_name)    {        rt_kprintf("Input param partition name is null!
    ");        return -1;    }
        partition = fal_partition_find(partiton_name);    if (partition == RT_NULL)    {        rt_kprintf("Find partition (%s) failed!
    ", partiton_name);        ret = -1;        return ret;    }
        flash_dev = fal_flash_device_find(partition->flash_name);    if (flash_dev == RT_NULL)    {        rt_kprintf("Find flash device (%s) failed!
    ", partition->flash_name);        ret = -1;        return ret;    }
        rt_kprintf("Flash device : %s   "               "Flash size : %dK   
    "               "Partition : %s   "               "Partition size: %dK
    ",                 partition->flash_name,                 flash_dev->len/1024,                partition->name,                partition->len/1024);
        /* erase all partition */    ret = fal_partition_erase_all(partition);    if (ret 0)    {        rt_kprintf("Partition (%s) erase failed!
    ", partition->name);        ret = -1;        return ret;    }    rt_kprintf("Erase (%s) partition finish!
    ", partiton_name);
        /* read the specified partition and check data */    for (i = 0; i len;)    {        rt_memset(buf, 0x00, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_read(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) read failed!
    ", partition->name);            ret = -1;            return ret;        }
            for(j = 0; j len; j++)        {            if (buf[j] != 0xFF)            {                rt_kprintf("The erase operation did not really succeed!
    ");                ret = -1;                return ret;            }        }        i += len;    }
        /* write 0x00 to the specified partition */    for (i = 0; i len;)    {        rt_memset(buf, 0x00, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_write(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) write failed!
    ", partition->name);            ret = -1;            return ret;        }
            i += len;    }    rt_kprintf("Write (%s) partition finish! Write size %d(%dK).
    ", partiton_name, i, i/1024);
        /* read the specified partition and check data */    for (i = 0; i len;)    {        rt_memset(buf, 0xFF, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_read(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) read failed!
    ", partition->name);            ret = -1;            return ret;        }
            for(j = 0; j len; j++)        {            if (buf[j] != 0x00)            {                rt_kprintf("The write operation did not really succeed!
    ");                ret = -1;                return ret;            }        }
            i += len;    }
        ret = 0;    return ret;}
    static void fal_sample(void){    /* 1- init */    fal_init();
        if (fal_test("font") == 0)    {        rt_kprintf("Fal partition (%s) test success!
    ", "font");    }    else    {        rt_kprintf("Fal partition (%s) test failed!
    ", "font");    }
        if (fal_test("download") == 0)    {        rt_kprintf("Fal partition (%s) test success!
    ", "download");    }    else    {        rt_kprintf("Fal partition (%s) test failed!
    ", "download");    }}MSH_CMD_EXPORT(fal_sample, fal sample);1.5
    測試結(jié)果
    到這里就可以進行編譯下載了,成功后的截圖如下:

    2.
    DFS文件系統(tǒng)
    2.1
    什么是DFS
    DFS 是 RT-Thread 提供的虛擬文件系統(tǒng)組件,全稱為 Device File System,即設(shè)備虛擬文件系統(tǒng),文件系統(tǒng)的名稱使用類似 UNIX 文件、文件夾的風(fēng)格,目錄結(jié)構(gòu)如下圖所示:

    在 RT-Thread DFS 中,文件系統(tǒng)有統(tǒng)一的根目錄,使用 / 來表示。而在根目錄下的 f1.bin 文件則使用 /f1.bin 來表示,2018 目錄下的 f1.bin 目錄則使用 /data/2018/f1.bin 來表示。即目錄的分割符號是 /,這與 UNIX/Linux 完全相同,與 Windows 則不相同(Windows 操作系統(tǒng)上使用 \ 來作為目錄的分割符)。
    2.2
    DFS架構(gòu)
    RT-Thread DFS 組件的主要功能特點有:
    為應(yīng)用程序提供統(tǒng)一的 POSIX 文件和目錄操作接口:read、write、poll/select 等。
    支持多種類型的文件系統(tǒng),如 FatFS、RomFS、DevFS 等,并提供普通文件、設(shè)備文件、網(wǎng)絡(luò)文件描述符的管理。
    支持多種類型的存儲設(shè)備,如 SD Card、SPI Flash、Nand Flash 等。
    DFS 的層次架構(gòu)如下圖所示,主要分為 POSIX 接口層、虛擬文件系統(tǒng)層和設(shè)備抽象層。

    2.3
    使用ENV配置DFS
    打開ENV,進入路徑 RT-Thread Components → DFS: device virtual file system ,使能
  • DFS: device virtual file system

    由于DFS使用的是POSIX接口,而dfs_posix.h已經(jīng)在新版本中被移除了,如果想要兼容老版本,可以在menuconfig中使能 RT-Thread Components->
  • Support legacy version for compatibility

    由于elmfat文件系統(tǒng)默認最大扇區(qū)大小為512,但我們使用的flash模塊 W25Q128 的Flash扇區(qū)大小為4096,為了將elmfat文件系統(tǒng)掛載到W25Q128上,這里的 Maximum sector size 需要和W25Q128扇區(qū)大小保持一致,修改為4096,路徑:RT-Thread Components → DFS: device virtual file system →
  • Enable elm-chan fatfs / elm-chan's FatFs, Generic FAT Filesystem Module

    保存退出后使用 scons --target=mdk5 生成MDK5工程。
    2.4
    DFS掛載到FAL分區(qū)測試
    這里增加FAL flash抽象層,我們將elmfat文件系統(tǒng)掛載到W25Q128 flash設(shè)備的filesystem分區(qū)上,由于FAL管理的filesystem分區(qū)不是塊設(shè)備,需要先使用FAL分區(qū)轉(zhuǎn)BLK設(shè)備接口函數(shù)將filesystem分區(qū)轉(zhuǎn)換為塊設(shè)備,然后再將DFS elmfat文件系統(tǒng)掛載到filesystem塊設(shè)備上。
    我們接著修改fal_sample.c文件,修改后代碼:
  • /* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2023-04-21     Wangyuqiang  the first version */ #include "rtthread.h"#include "rtdevice.h"#include "board.h"#include "fal.h"
    #include
    #define FS_PARTITION_NAME  "filesystem"
    #define BUF_SIZE 1024
    static int fal_test(const char *partiton_name){    int ret;    int i, j, len;    uint8_t buf[BUF_SIZE];    const struct fal_flash_dev *flash_dev = RT_NULL;    const struct fal_partition *partition = RT_NULL;
        if (!partiton_name)    {        rt_kprintf("Input param partition name is null!
    ");        return -1;    }
        partition = fal_partition_find(partiton_name);    if (partition == RT_NULL)    {        rt_kprintf("Find partition (%s) failed!
    ", partiton_name);        ret = -1;        return ret;    }
        flash_dev = fal_flash_device_find(partition->flash_name);    if (flash_dev == RT_NULL)    {        rt_kprintf("Find flash device (%s) failed!
    ", partition->flash_name);        ret = -1;        return ret;    }
        rt_kprintf("Flash device : %s   "               "Flash size : %dK   
    "               "Partition : %s   "               "Partition size: %dK
    ",                 partition->flash_name,                 flash_dev->len/1024,                partition->name,                partition->len/1024);
        /* erase all partition */    ret = fal_partition_erase_all(partition);    if (ret 0)    {        rt_kprintf("Partition (%s) erase failed!
    ", partition->name);        ret = -1;        return ret;    }    rt_kprintf("Erase (%s) partition finish!
    ", partiton_name);
        /* read the specified partition and check data */    for (i = 0; i len;)    {        rt_memset(buf, 0x00, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_read(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) read failed!
    ", partition->name);            ret = -1;            return ret;        }
            for(j = 0; j         {            if (buf[j] != 0xFF)            {                rt_kprintf("The erase operation did not really succeed!
    ");                ret = -1;                return ret;            }        }        i += len;    }
        /* write 0x00 to the specified partition */    for (i = 0; i len;)    {        rt_memset(buf, 0x00, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_write(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) write failed!
    ", partition->name);            ret = -1;            return ret;        }
            i += len;    }    rt_kprintf("Write (%s) partition finish! Write size %d(%dK).
    ", partiton_name, i, i/1024);
        /* read the specified partition and check data */    for (i = 0; i len;)    {        rt_memset(buf, 0xFF, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_read(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) read failed!
    ", partition->name);            ret = -1;            return ret;        }
            for(j = 0; j         {            if (buf[j] != 0x00)            {                rt_kprintf("The write operation did not really succeed!
    ");                ret = -1;                return ret;            }        }
            i += len;    }
        ret = 0;    return ret;}
    static void fal_sample(void){    /* 1- init */    fal_init();
        if (fal_test("font") == 0)    {        rt_kprintf("Fal partition (%s) test success!
    ", "font");    }    else    {        rt_kprintf("Fal partition (%s) test failed!
    ", "font");    }
        if (fal_test("download") == 0)    {        rt_kprintf("Fal partition (%s) test success!
    ", "download");    }    else    {        rt_kprintf("Fal partition (%s) test failed!
    ", "download");    }}MSH_CMD_EXPORT(fal_sample, fal sample);
    static void fal_elmfat_sample(void){    int fd, size;    struct statfs elm_stat;    struct fal_blk_device *blk_dev;    char str[] = "elmfat mount to W25Q flash.", buf[80];
        /* fal init */    fal_init();
        /* create block device */    blk_dev = (struct fal_blk_device *)fal_blk_device_create(FS_PARTITION_NAME);    if(blk_dev == RT_NULL)        rt_kprintf("Can't create a block device on '%s' partition.
    ", FS_PARTITION_NAME);    else        rt_kprintf("Create a block device on the %s partition of flash successful.
    ", FS_PARTITION_NAME);
        /* make a elmfat format filesystem */    if(dfs_mkfs("elm", FS_PARTITION_NAME) == 0)        rt_kprintf("make elmfat filesystem success.
    ");
        /* mount elmfat file system to FS_PARTITION_NAME */    if(dfs_mount(FS_PARTITION_NAME, "/", "elm", 0, 0) == 0)        rt_kprintf("elmfat filesystem mount success.
    ");
        /* Get elmfat file system statistics */    if(statfs("/", &elm_stat) == 0)        rt_kprintf("elmfat filesystem block size: %d, total blocks: %d, free blocks: %d.
    ",                     elm_stat.f_bsize, elm_stat.f_blocks, elm_stat.f_bfree);
        if(mkdir("/user", 0x777) == 0)        rt_kprintf("make a directory: '/user'.
    ");
        rt_kprintf("Write string '%s' to /user/test.txt.
    ", str);
        /* Open the file in create and read-write mode, create the file if it does not exist*/    fd = open("/user/test.txt", O_WRONLY | O_CREAT);    if (fd >= 0)    {        if(write(fd, str, sizeof(str)) == sizeof(str))            rt_kprintf("Write data done.
    ");
            close(fd);       }
        /* Open file in read-only mode */    fd = open("/user/test.txt", O_RDONLY);    if (fd >= 0)    {        size = read(fd, buf, sizeof(buf));
            close(fd);
            if(size == sizeof(str))            rt_kprintf("Read data from file test.txt(size: %d): %s
    ", size, buf);    }}MSH_CMD_EXPORT_ALIAS(fal_elmfat_sample, fal_elmfat,fal elmfat sample);2.5
    測試結(jié)果
    測試結(jié)果如下:

    3.
    Easyflash移植到FAL分區(qū)
    3.1
    簡述EasyFlash
    關(guān)于EasyFlash的來源我們已經(jīng)講過了,此處不再贅述。EasyFlash(https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2Farmink%2FEasyFlash)是一款開源的輕量級嵌入式Flash存儲器庫,方便開發(fā)者更加輕松的實現(xiàn)基于Flash存儲器的常見應(yīng)用開發(fā)。非常適合智能家居、可穿戴、工控、醫(yī)療、物聯(lián)網(wǎng)等需要斷電存儲功能的產(chǎn)品,資源占用極低,支持各種 MCU 片上存儲器。
    EasyFlash不僅能夠?qū)崿F(xiàn)對產(chǎn)品的 設(shè)定參數(shù)運行日志 等信息的掉電保存功能,還封裝了簡潔的 增加、刪除、修改及查詢 方法, 降低了開發(fā)者對產(chǎn)品參數(shù)的處理難度,也保證了產(chǎn)品在后期升級時擁有更好的擴展性。讓Flash變?yōu)镹oSQL(非關(guān)系型數(shù)據(jù)庫)模型的小型鍵值(Key-Value)存儲數(shù)據(jù)庫。
    3.2
    EasyFlash軟件包使用
    打開ENV進入路徑:RT-Thread online packages → tools packages → EasyFlash: Lightweight embedded flash memory library. ,選擇軟件包版本為最新版。

    配置后退出ENV,同時使用 pkgs --update 下載軟件包,然后再使用 scons --target=mdk5 重新生成MDK5文件
    3.3
    移植easyflash
    下載完easyflash軟件包后,我們復(fù)制 .\rt-thread\bsp\lpc55sxx\lpc55s69_nxp_evk\packages\EasyFlash-latest\ports\ef_fal_port.c 到目錄 .\rt-thread\bsp\lpc55sxx\lpc55s69_nxp_evk\board\ports\easyflash\ef_fal_port.c ,雙擊打開該文件,完成以下修改:
  • // 修改 FAL_EF_PART_NAME 為 easyflash#define FAL_EF_PART_NAME               "easyflash"
  • // 修改環(huán)境變量內(nèi)容為 {"boot_times", "0"},這里我們先只設(shè)置一個開機次數(shù)static const ef_env default_env_set[] = {        {"boot_times", "0"},};3.4
    編寫Easyflash測試用例
  • /* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2023-04-21     Wangyuqiang  the first version */ #include "rtthread.h"#include "rtdevice.h"#include "board.h"#include "fal.h"
    #include
    #include "easyflash.h"#include
    #define FS_PARTITION_NAME  "filesystem"
    #define BUF_SIZE 1024
    static int fal_test(const char *partiton_name){    int ret;    int i, j, len;    uint8_t buf[BUF_SIZE];    const struct fal_flash_dev *flash_dev = RT_NULL;    const struct fal_partition *partition = RT_NULL;
        if (!partiton_name)    {        rt_kprintf("Input param partition name is null!
    ");        return -1;    }
        partition = fal_partition_find(partiton_name);    if (partition == RT_NULL)    {        rt_kprintf("Find partition (%s) failed!
    ", partiton_name);        ret = -1;        return ret;    }
        flash_dev = fal_flash_device_find(partition->flash_name);    if (flash_dev == RT_NULL)    {        rt_kprintf("Find flash device (%s) failed!
    ", partition->flash_name);        ret = -1;        return ret;    }
        rt_kprintf("Flash device : %s   "               "Flash size : %dK   
    "               "Partition : %s   "               "Partition size: %dK
    ",                 partition->flash_name,                 flash_dev->len/1024,                partition->name,                partition->len/1024);
        /* erase all partition */    ret = fal_partition_erase_all(partition);    if (ret 0)    {        rt_kprintf("Partition (%s) erase failed!
    ", partition->name);        ret = -1;        return ret;    }    rt_kprintf("Erase (%s) partition finish!
    ", partiton_name);
        /* read the specified partition and check data */    for (i = 0; i len;)    {        rt_memset(buf, 0x00, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_read(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) read failed!
    ", partition->name);            ret = -1;            return ret;        }
            for(j = 0; j         {            if (buf[j] != 0xFF)            {                rt_kprintf("The erase operation did not really succeed!
    ");                ret = -1;                return ret;            }        }        i += len;    }
        /* write 0x00 to the specified partition */    for (i = 0; i len;)    {        rt_memset(buf, 0x00, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_write(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) write failed!
    ", partition->name);            ret = -1;            return ret;        }
            i += len;    }    rt_kprintf("Write (%s) partition finish! Write size %d(%dK).
    ", partiton_name, i, i/1024);
        /* read the specified partition and check data */    for (i = 0; i len;)    {        rt_memset(buf, 0xFF, BUF_SIZE);
            len = (partition->len - i) > BUF_SIZE ? BUF_SIZE : (partition->len - i);
            ret = fal_partition_read(partition, i, buf, len);        if (ret 0)        {            rt_kprintf("Partition (%s) read failed!
    ", partition->name);            ret = -1;            return ret;        }
            for(j = 0; j         {            if (buf[j] != 0x00)            {                rt_kprintf("The write operation did not really succeed!
    ");                ret = -1;                return ret;            }        }
            i += len;    }
        ret = 0;    return ret;}
    static void fal_sample(void){    /* 1- init */    fal_init();
        if (fal_test("font") == 0)    {        rt_kprintf("Fal partition (%s) test success!
    ", "font");    }    else    {        rt_kprintf("Fal partition (%s) test failed!
    ", "font");    }
        if (fal_test("download") == 0)    {        rt_kprintf("Fal partition (%s) test success!
    ", "download");    }    else    {        rt_kprintf("Fal partition (%s) test failed!
    ", "download");    }}MSH_CMD_EXPORT(fal_sample, fal sample);
    static void fal_elmfat_sample(void){    int fd, size;    struct statfs elm_stat;    struct fal_blk_device *blk_dev;    char str[] = "elmfat mount to W25Q flash.", buf[80];
        /* fal init */    fal_init();
        /* create block device */    blk_dev = (struct fal_blk_device *)fal_blk_device_create(FS_PARTITION_NAME);    if(blk_dev == RT_NULL)        rt_kprintf("Can't create a block device on '%s' partition.
    ", FS_PARTITION_NAME);    else        rt_kprintf("Create a block device on the %s partition of flash successful.
    ", FS_PARTITION_NAME);
        /* make a elmfat format filesystem */    if(dfs_mkfs("elm", FS_PARTITION_NAME) == 0)        rt_kprintf("make elmfat filesystem success.
    ");
        /* mount elmfat file system to FS_PARTITION_NAME */    if(dfs_mount(FS_PARTITION_NAME, "/", "elm", 0, 0) == 0)        rt_kprintf("elmfat filesystem mount success.
    ");
        /* Get elmfat file system statistics */    if(statfs("/", &elm_stat) == 0)        rt_kprintf("elmfat filesystem block size: %d, total blocks: %d, free blocks: %d.
    ",                     elm_stat.f_bsize, elm_stat.f_blocks, elm_stat.f_bfree);
        if(mkdir("/user", 0x777) == 0)        rt_kprintf("make a directory: '/user'.
    ");
        rt_kprintf("Write string '%s' to /user/test.txt.
    ", str);
        /* Open the file in create and read-write mode, create the file if it does not exist*/    fd = open("/user/test.txt", O_WRONLY | O_CREAT);    if (fd >= 0)    {        if(write(fd, str, sizeof(str)) == sizeof(str))            rt_kprintf("Write data done.
    ");
            close(fd);       }
        /* Open file in read-only mode */    fd = open("/user/test.txt", O_RDONLY);    if (fd >= 0)    {        size = read(fd, buf, sizeof(buf));
            close(fd);
            if(size == sizeof(str))            rt_kprintf("Read data from file test.txt(size: %d): %s
    ", size, buf);    }}MSH_CMD_EXPORT_ALIAS(fal_elmfat_sample, fal_elmfat,fal elmfat sample);
    static void easyflash_sample(void){    /* fal init */    fal_init();
        /* easyflash init */    if(easyflash_init() == EF_NO_ERR)    {        uint32_t i_boot_times = NULL;        char *c_old_boot_times, c_new_boot_times[11] = {0};
            /* get the boot count number from Env */        c_old_boot_times = ef_get_env("boot_times");        /* get the boot count number failed */        if (c_old_boot_times == RT_NULL)            c_old_boot_times[0] = '0';
            i_boot_times = atol(c_old_boot_times);        /* boot count +1 */        i_boot_times ++;        rt_kprintf("===============================================
    ");        rt_kprintf("The system now boot %d times
    ", i_boot_times);        rt_kprintf("===============================================
    ");        /* interger to string */        sprintf(c_new_boot_times, "%d", i_boot_times);        /* set and store the boot count number to Env */        ef_set_env("boot_times", c_new_boot_times);        ef_save_env();    }}MSH_CMD_EXPORT(easyflash_sample, easyflash sample);3.5
    測試結(jié)果
    打開串口助手,輸入命令:
  • msh />easyflash_sample第一次命令調(diào)用:

    第二次RESET開發(fā)板后調(diào)用:


    點擊閱讀原文,查看更多分享。
  • 回復(fù)

    使用道具 舉報

    發(fā)表回復(fù)

    您需要登錄后才可以回帖 登錄 | 立即注冊

    本版積分規(guī)則


    聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表