由于之前需要使用片上的flash多余的部分來(lái)搭建文件系統(tǒng),但是沒(méi)有找到使用片上的教程,都是利用片外的flash教程。后來(lái)發(fā)現(xiàn)能直接使用fal軟件包作為flash設(shè)備抽象層,向上可以提供文件系統(tǒng)的接口,向下可以驅(qū)動(dòng)片內(nèi)的flash。這里放上之前使用的筆記。
1.簡(jiǎn)介
littlefs 在 RT-Thread 上運(yùn)行的層級(jí)關(guān)系圖如下所示:

開(kāi)發(fā)者使用的是 DFS 框架提供的統(tǒng)一的 POSIX API,DFS 框架會(huì)調(diào)用 littlefs 的 API,littlefs 會(huì)使用 MTD 設(shè)備的讀寫(xiě)接口,開(kāi)發(fā)者可以使用 RT-Thread 提供的 fal 組件和 SFUD 組件來(lái)完成對(duì) FLASH 的讀寫(xiě)任務(wù),也可以自己實(shí)現(xiàn) MTD 設(shè)備的驅(qū)動(dòng)程序,使 littlefs 可以掛載到更多的存儲(chǔ)介質(zhì)上。
2.FAL MCU Flash移植
2.1 FAL軟件包源碼獲取
打開(kāi)bsp工程的ENV環(huán)境,運(yùn)行menuconfig命令。

2.2 fal具體配置

FAL uses SFUD drivers:是用來(lái)驅(qū)動(dòng)外置的flash設(shè)備,由于我們只使用內(nèi)部flash,所以不需要選上。
每個(gè)功能的配置說(shuō)明如下:
開(kāi)啟調(diào)試日志輸出(默認(rèn)開(kāi)啟);
 分區(qū)表是否在fal_cfg.h中定義(默認(rèn)開(kāi)啟)。如果關(guān)閉此選項(xiàng),fal 將會(huì)自動(dòng)去指定 Flash 的指定位置去檢索并裝載分區(qū)表,具體配置詳見(jiàn)下面兩個(gè)選項(xiàng);
 存放分區(qū)表的 Flash 設(shè)備;
 分區(qū)表的 結(jié)束地址 位于 Flash 設(shè)備上的偏移。fal 將從此地址開(kāi)始往回進(jìn)行檢索分區(qū)表,直接讀取到 Flash 頂部。如果不確定分區(qū)表具體位置,這里也可以配置為 Flash 的結(jié)束地址,fal 將會(huì)檢索整個(gè) Flash,檢索時(shí)間可能會(huì)增加。
 啟用 FAL 針對(duì) SFUD 的移植文件(默認(rèn)關(guān)閉);
 應(yīng)輸入調(diào)用 rt_sfud_flash_probe 函數(shù)時(shí)傳入的 FLASH 設(shè)備名稱(也可以通過(guò) list_device 命令查看 Block Device 的名字獲?。?。該名稱與分區(qū)表中的 Flash 名稱對(duì)應(yīng),只有正確設(shè)置設(shè)備名字,才能完成對(duì) FLASH 的讀寫(xiě)操作。
 關(guān)于分區(qū)表,下文還會(huì)提及并解釋。
2.3 pkgs —update
保存配置退出后,在env環(huán)境執(zhí)行pkgs —update命令,會(huì)自動(dòng)從FAL的github倉(cāng)庫(kù)獲取FAL軟件包源碼到本地工程目錄,如下圖所示:

2.4 設(shè)備表和分區(qū)表
 FAL組件初始化最重要的是維護(hù)兩個(gè)表:一個(gè)是flash設(shè)備表;另一個(gè)是FAL分區(qū)表,兩個(gè)表的元素分別是前面介紹過(guò)的fal_flash_dev結(jié)構(gòu)體地址和fal_partition結(jié)構(gòu)體對(duì)象。
fal_flash_dev設(shè)備表主要由底層的Flash驅(qū)動(dòng)(包括MCU片內(nèi)Flash和SFUD驅(qū)動(dòng)的片外Flash)提供,也即FAL移植的重點(diǎn)就是在Flash驅(qū)動(dòng)層向FAL提供fal_flash_dev設(shè)備表,每個(gè)flash設(shè)備提供設(shè)備表中的一個(gè)元素。
fal_partition分區(qū)表由用戶事先配置在fal_cfg.h頭文件中,F(xiàn)AL向上面的用戶層提供的分區(qū)訪問(wèn)接口函數(shù)操作的內(nèi)存區(qū)間就是從fal_partition分區(qū)表獲取的,最后對(duì)分區(qū)的訪問(wèn)還是通過(guò)Flash驅(qū)動(dòng)提供的接口函數(shù)(fal_flash_dev.ops)實(shí)現(xiàn)的。
設(shè)備表管理不同的flash設(shè)備,可以是片內(nèi)的也可以是片外的。有點(diǎn)像管理不同的硬盤。分區(qū)表就是我們電腦上經(jīng)常說(shuō)的那個(gè)磁盤分區(qū)的意思。
2.5 復(fù)制文件
考慮到packages下面的軟件版本后續(xù)可能會(huì)升級(jí)覆蓋,我們不在packagesfal-latest目錄下直接進(jìn)行移植修改,而是在packages目錄外新建一個(gè)文件夾ports專門保存軟件包的移植文件信息。
(如果不擔(dān)心升級(jí)覆蓋問(wèn)題,跳過(guò)2.5和2.6直接看2.9,再回來(lái)看2.7和2.8)
 新建與packages軟件包同級(jí)的移植文件目錄ports,將packagesfal-latestsamplesporting目錄下的fal_cfg.h文件復(fù)制一份到portsfal目錄下,將packagesfal-latestSConscript復(fù)制一份到portsfal目錄下,將packagesSConscript復(fù)制一份到ports目錄下,復(fù)制文件后的目錄結(jié)構(gòu)如下圖所示:

(注:圖片里多了fal_flash_sfud_port.c文件,是原博客圖片,但是我們不需要驅(qū)動(dòng)外置的flash)
2.6 修改sconscript文件
由于portsfal目錄及下面的文件名有變化,所以需要修改編譯腳本portsfalSConscript,主要是修改文件目錄及文件名,修改后的編譯腳本如下:(直接覆蓋,其實(shí)不改這個(gè)SConscript文件也沒(méi)啥問(wèn)題,強(qiáng)迫癥建議覆蓋)
from building import *
 import rtconfig
 cwd = GetCurrentDir()
 src = []
 CPPPATH = [cwd]
 LOCAL_CCFLAGS = ''
 if rtconfig.CROSS_TOOL == 'gcc':
 LOCAL_CCFLAGS += ' -std=c99'
 elif rtconfig.CROSS_TOOL == 'keil':
 LOCAL_CCFLAGS += ' --c99'
 group = DefineGroup('fal', src, depend = ['PKG_USING_FAL'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS)
 Return('group')
別忘了執(zhí)行scons —target=mdk5命令,到此直接編譯工程會(huì)出現(xiàn)error,需要接下來(lái)繼續(xù)更改文件。
.buildkeilObjrt-thread.axf: Error: L6218E: Undefined symbol nor_flash0 (referred from fal_flash.o).
 .buildkeilObjrt-thread.axf: Error: L6218E: Undefined symbol stm32f2_onchip_flash (referred from fal_flash.o).
2.7 修改Kconfig
在原bsp目錄的board/Kconfig中的menu “On-chip Peripheral Drivers”內(nèi)添加下面語(yǔ)句
config BSP_USING_ON_CHIP_FLASH
 bool "Enable On-Chip Flash"
 default n
添加完,進(jìn)入menuconfig選中該項(xiàng),并保存退出。
2.8 修改drv_flash_f4.c文件
STM32f427片內(nèi)Flash驅(qū)動(dòng),RT-Thread已經(jīng)在librariesHAL_Drivers drv_flashdrv_flash_f4.c目錄下提供了,同時(shí)還通過(guò)條件宏提供了向FAL注冊(cè)fal_flash_dev設(shè)備表項(xiàng)的代碼。但還需我們自己添加一部分代碼(個(gè)人覺(jué)得應(yīng)該是rtt 官方留白,讓我們自定義分區(qū)基地址和大小),如下圖:

#define STM32_FLASH_START_ADRESS_16K ((uint32_t)0x08100000)
 #define STM32_FLASH_START_ADRESS_64K ((uint32_t)0x08110000)
 #define STM32_FLASH_START_ADRESS_128K ((uint32_t)0x08120000)
 #define FLASH_SIZE_GRANULARITY_16K (641024 )
 #define FLASH_SIZE_GRANULARITY_64K (641024 )
 #define FLASH_SIZE_GRANULARITY_128K (896*1024)
為什么這樣添加分區(qū)基地址和大?。?/p>
先看下面的圖

因此我們現(xiàn)在這樣是在使用扇區(qū)12到23,又由于STM32F42x的這幾個(gè)扇區(qū)有16K,64K,128K大小的。所以使用fal時(shí),必須把他們看成3個(gè)不同的flash設(shè)備進(jìn)行管理,這也是上文所說(shuō)flash設(shè)備表的作用。
2.9 覆蓋(或新建)fal_cfg.h
新建一個(gè)下面代碼塊內(nèi)容的fal_cfg.h文件在packagesfal-latestinc 內(nèi)
/*
- Copyright (c) 2006-2018, RT-Thread Development Team
 - SPDX-License-Identifier: Apache-2.0
 - Change Logs:
 - Date Author Notes
 - 2018-05-17 armink the first version
/
#ifndef FAL_CFG_H
#define FAL_CFG_H
#include
#include
/ ===================== Flash device Configuration ========================= /
extern const struct fal_flash_dev stm32_onchip_flash_16k ;
extern const struct fal_flash_dev stm32_onchip_flash_64k ;
extern const struct fal_flash_dev stm32_onchip_flash_128k;
/ flash device table /
#define FAL_FLASH_DEV_TABLE
{
&stm32_onchip_flash_16k,
&stm32_onchip_flash_64k,
&stm32_onchip_flash_128k,
}
/ ====================== Partition Configuration ========================== /
#ifdef FAL_PART_HAS_TABLE_CFG
/ partition table /
#define FAL_PART_TABLE
{
{FAL_PART_MAGIC_WORD, "bl", "onchip_flash_16k" , 0, 64 * 1024, 0},
{FAL_PART_MAGIC_WORD, "param", "onchip_flash_64k" , 0, 64 * 1024, 0},
{FAL_PART_MAGIC_WORD, "app", "onchip_flash_128k", 0, 128 1024, 0},
{FAL_PART_MAGIC_WORD, "filesystem", "onchip_flash_128k", 128 * 1024, 768* 1024, 0},
}
#endif /* FAL_PART_HAS_TABLE_CFG /
#endif /FAL_CFG_H */
這段代碼的意思是使用flash設(shè)備stm32_onchip_flash_16k,stm32_onchip_flash_64k,stm32_onchip_flash_128k
創(chuàng)建四個(gè)分區(qū),分別名為bl,param,app,filesystem(名字都是隨便取的)。后兩個(gè)分區(qū)是分別瓜分了onchip_flash_128k設(shè)備內(nèi)存。 
2.x FAL使用示例
見(jiàn)博客 1.4 FAL使用示例 或者** **FAL:Flash 抽象層的 3、Finsh/MSH 測(cè)試命令
 我的部分操作見(jiàn) 4.2 fal指令實(shí)驗(yàn)
 到此已經(jīng)移植完fal了
3.搭載 littlefs 文件系統(tǒng)
littlefs 是 ARM 官方推出的,專為嵌入式系統(tǒng)設(shè)計(jì)的文件系統(tǒng),相比傳統(tǒng)的文件系統(tǒng),littlefs 具有以下優(yōu)點(diǎn):
自帶擦寫(xiě)均衡
 支持掉電保護(hù)
 占用的 RAM/ROM 少
 littlefs 自帶的擦寫(xiě)均衡和掉電保護(hù)使開(kāi)發(fā)者可以放心的將文件系統(tǒng)掛載到 nor flash 上。
3.1 使能DFS框架
打開(kāi) env,輸入 menuconfig,在 RT-Thread Components → Device virtual file system 中打開(kāi) DFS 框架。

使用默認(rèn)配置
3.2 配置 littlefs
在 RT-Thread online packages → system packages → Littlefs: A high-integrity embedded file system 中打開(kāi) littlefs。

注意lfs enable wear leveling要改成100,這項(xiàng)意思是 lfs啟用損耗均衡
3.2.1 猜測(cè)
代碼中對(duì)于disk block size的注釋
// Size of an erasable block. This does not impact ram consumption and
// may be larger than the physical erase size. However, non-inlined files
// take up at minimum one block. Must be a multiple of the read
// and program sizes.
Google 翻譯
//可擦除塊的大小。 這不會(huì)影響ram的消耗,并且
//可能大于物理擦除大小。 但是,非內(nèi)聯(lián)文件
//至少占用一個(gè)街區(qū)。 必須是讀取的倍數(shù)
//和程序大小。
結(jié)合程序調(diào)試中mtd_nor->block_size值為0x0002 0000。即128KB,又是”filesystem”分區(qū)所在的扇區(qū)的大小。

所以基本確定disk block size應(yīng)該填128*1024,即131072。
其他配置我覺(jué)得默認(rèn)配置問(wèn)題不大。比如下面這個(gè)注釋的描述。
// Minimum size of a block read. All read operations will be a
// multiple of this value.
lfs_size_t read_size;
3.3 使能 MTD 設(shè)備
在 RT-Thread Components → Device Drivers 中使能 MTD 設(shè)備。

使用pkgs —update更新軟件包和scons —target=mdk5
3.4 創(chuàng)建 MTD 設(shè)備并掛載文件系統(tǒng)
fal 組件并沒(méi)有加入自動(dòng)初始化的代碼,所以我們需要在 main 函數(shù)中初始化 fal,并使用 fal 提供的 API 來(lái)創(chuàng)建一個(gè) MTD 設(shè)備。創(chuàng)建 MTD 設(shè)備后,就可以將 littlefs 掛載到剛剛生成的 MTD 設(shè)備上了。
 在 main.c 文件中添加(覆蓋)的代碼如下所示:
/* 添加 fal 頭文件 /
 #include
 / 添加文件系統(tǒng)頭文件 /
 #include
 / 添加 DEBUG 頭文件 /
 #define DBG_SECTION_NAME "main"
 #define DBG_LEVEL DBG_INFO
 #include
 / 定義要使用的分區(qū)名字 */
 #define FS_PARTITION_NAME "filesystem"
 int main(void)
 {
 struct rt_device mtd_dev = RT_NULL;
 / 初始化 fal /
 fal_init();
 / 生成 mtd 設(shè)備 /
 mtd_dev = fal_mtd_nor_device_create(FS_PARTITION_NAME);
 if (!mtd_dev)
 {
 LOG_E("Can't create a mtd device on '%s' partition.", FS_PARTITION_NAME);
 }
 else
 {
 / 掛載 littlefs /
 if (dfs_mount(FS_PARTITION_NAME, "/", "lfs", 0, 0) == 0)
 {
 LOG_I("Filesystem initialized!");
 }
 else
 {
 / 格式化文件系統(tǒng) /
 dfs_mkfs("lfs", FS_PARTITION_NAME);
 / 掛載 littlefs */
 if (dfs_mount("filesystem", "/", "lfs", 0, 0) == 0)
 {
 LOG_I("Filesystem initialized!");
 }
 else
 {
 LOG_E("Failed to initialize filesystem!");
 }
 }
 }
 while (1)
 {
 rt_thread_mdelay(100);
 }
 }
 注意這里使用了一個(gè)分區(qū)”filesystem”。所以上面創(chuàng)建分區(qū)必須也有名為”filesystem”的分區(qū)。
3.5 使用littlefs 文件系統(tǒng)
3.5.1 參考
文件系統(tǒng)語(yǔ)句都是通用的,都是基于POSIX 標(biāo)準(zhǔn)的
3.5.2 問(wèn)題
需要注意:我這一直有個(gè)問(wèn)題,就是只能使用mkdir 創(chuàng)建2條路徑,創(chuàng)建第3條就會(huì)出錯(cuò)。如下:

暫未解決,因?yàn)閯?chuàng)建二三十個(gè).txt .c也沒(méi)出錯(cuò),就先這樣吧。
3.5.3 格式化
文檔里講的不清楚。
 littlefs的格式化語(yǔ)句
 :
 1.程序里面寫(xiě)的
/* 定義要使用的分區(qū)名字 /
 #define FS_PARTITION_NAME "filesystem"
 / 格式化文件系統(tǒng) */
 dfs_mkfs("lfs", FS_PARTITION_NAME);
2.Finsh組件
 mkfs -t lfs filesystem

文檔里漏了
3.5.4 官方例程

4.實(shí)驗(yàn)
4.1 分區(qū)實(shí)驗(yàn)
看從0x0800 0000開(kāi)始是否影響原程序
 (是影響的,所以建議從扇區(qū)12開(kāi)始。當(dāng)然也可以看.map文件來(lái)知道程序所占ROM內(nèi)存大小,來(lái)算從第幾個(gè)扇區(qū)開(kāi)始是安全的,不過(guò)這樣就需要自己不按照我上文講的那樣配置設(shè)備表和分區(qū)表)



再步進(jìn)一次,擦除所有扇區(qū),即原來(lái)的程序也被擦除,導(dǎo)致hard_fault。匿名上位機(jī)保持上一張圖片的狀態(tài)


4.2 fal指令實(shí)驗(yàn)
FAL為便于用戶調(diào)試,也提供了finsh命令fal,包括fal probe / read / write / erase / bench等命令

通過(guò)使用隨機(jī)的人為數(shù)據(jù)給“寫(xiě)入函數(shù)”,讀取出“讀取函數(shù)”的值,來(lái)驗(yàn)證是否復(fù)位后還保存著數(shù)據(jù)
 (是能繼續(xù)存儲(chǔ)的,所以fal確實(shí)是操作著掉電不丟失數(shù)據(jù)的東西)


- 
                                驅(qū)動(dòng)器
                                +關(guān)注
關(guān)注
54文章
8980瀏覽量
152733 - 
                                片上系統(tǒng)
                                +關(guān)注
關(guān)注
0文章
197瀏覽量
27545 - 
                                RT-Thread
                                +關(guān)注
關(guān)注
32文章
1514瀏覽量
43986 - 
                                Flash存儲(chǔ)
                                +關(guān)注
關(guān)注
0文章
40瀏覽量
8526 - 
                                DFS
                                +關(guān)注
關(guān)注
0文章
26瀏覽量
9518 
發(fā)布評(píng)論請(qǐng)先 登錄
VxWorks文件系統(tǒng)、Flash的TFFS設(shè)計(jì)與實(shí)現(xiàn)
    
如何去實(shí)現(xiàn)RT-Thread的片上flash掛載littlefs文件系統(tǒng)呢
嵌入式系統(tǒng)中的Flash文件系統(tǒng)
車載MP3中Flash文件系統(tǒng)的設(shè)計(jì)與應(yīng)用
車載MP3中Flash文件系統(tǒng)的設(shè)計(jì)與應(yīng)用
基于CC CCS 的Flash 文件系統(tǒng)設(shè)計(jì)
基于VxWorks的文件系統(tǒng)的研究與實(shí)現(xiàn)
Flash文件系統(tǒng)剖析
    
SPI—外部FLASH文件系統(tǒng)
    
SPI FLASH LittleFS文件系統(tǒng)例程資料免費(fèi)下載
    
線性文件系統(tǒng)的設(shè)計(jì)方案在嵌入式應(yīng)用管理Flash空間中的應(yīng)用
    
Nand Flash文件系統(tǒng)解決方案
    
手把手教你在flash上移植fatfs文件系統(tǒng)(含實(shí)時(shí)操作系統(tǒng))
    
          
        
        
片上flash使用文件系統(tǒng)筆記
                
 
           
            
            
                
            
評(píng)論