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

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

2.2 fal具體配置

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

2.4 設(shè)備表和分區(qū)表
FAL組件初始化最重要的是維護兩個表:一個是flash設(shè)備表;另一個是FAL分區(qū)表,兩個表的元素分別是前面介紹過的fal_flash_dev結(jié)構(gòu)體地址和fal_partition結(jié)構(gòu)體對象。
fal_flash_dev設(shè)備表主要由底層的Flash驅(qū)動(包括MCU片內(nèi)Flash和SFUD驅(qū)動的片外Flash)提供,也即FAL移植的重點就是在Flash驅(qū)動層向FAL提供fal_flash_dev設(shè)備表,每個flash設(shè)備提供設(shè)備表中的一個元素。
fal_partition分區(qū)表由用戶事先配置在fal_cfg.h頭文件中,F(xiàn)AL向上面的用戶層提供的分區(qū)訪問接口函數(shù)操作的內(nèi)存區(qū)間就是從fal_partition分區(qū)表獲取的,最后對分區(qū)的訪問還是通過Flash驅(qū)動提供的接口函數(shù)(fal_flash_dev.ops)實現(xiàn)的。
設(shè)備表管理不同的flash設(shè)備,可以是片內(nèi)的也可以是片外的。有點像管理不同的硬盤。分區(qū)表就是我們電腦上經(jīng)常說的那個磁盤分區(qū)的意思。
2.5 復(fù)制文件
考慮到packages下面的軟件版本后續(xù)可能會升級覆蓋,我們不在packagesfal-latest目錄下直接進行移植修改,而是在packages目錄外新建一個文件夾ports專門保存軟件包的移植文件信息。
(如果不擔心升級覆蓋問題,跳過2.5和2.6直接看2.9,再回來看2.7和2.8)
新建與packages軟件包同級的移植文件目錄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ū)動外置的flash)
2.6 修改sconscript文件
由于portsfal目錄及下面的文件名有變化,所以需要修改編譯腳本portsfalSConscript,主要是修改文件目錄及文件名,修改后的編譯腳本如下:(直接覆蓋,其實不改這個SConscript文件也沒啥問題,強迫癥建議覆蓋)
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命令,到此直接編譯工程會出現(xiàn)error,需要接下來繼續(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)添加下面語句
config BSP_USING_ON_CHIP_FLASH
bool "Enable On-Chip Flash"
default n
添加完,進入menuconfig選中該項,并保存退出。
2.8 修改drv_flash_f4.c文件
STM32f427片內(nèi)Flash驅(qū)動,RT-Thread已經(jīng)在librariesHAL_Drivers drv_flashdrv_flash_f4.c目錄下提供了,同時還通過條件宏提供了向FAL注冊fal_flash_dev設(shè)備表項的代碼。但還需我們自己添加一部分代碼(個人覺得應(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ū)基地址和大小?
先看下面的圖

因此我們現(xiàn)在這樣是在使用扇區(qū)12到23,又由于STM32F42x的這幾個扇區(qū)有16K,64K,128K大小的。所以使用fal時,必須把他們看成3個不同的flash設(shè)備進行管理,這也是上文所說flash設(shè)備表的作用。
2.9 覆蓋(或新建)fal_cfg.h
新建一個下面代碼塊內(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)建四個分區(qū),分別名為bl,param,app,filesystem(名字都是隨便取的)。后兩個分區(qū)是分別瓜分了onchip_flash_128k設(shè)備內(nèi)存。
2.x FAL使用示例
見博客 1.4 FAL使用示例 或者** **FAL:Flash 抽象層的 3、Finsh/MSH 測試命令
我的部分操作見 4.2 fal指令實驗
到此已經(jīng)移植完fal了
3.搭載 littlefs 文件系統(tǒng)
littlefs 是 ARM 官方推出的,專為嵌入式系統(tǒng)設(shè)計的文件系統(tǒng),相比傳統(tǒng)的文件系統(tǒng),littlefs 具有以下優(yōu)點:
自帶擦寫均衡
支持掉電保護
占用的 RAM/ROM 少
littlefs 自帶的擦寫均衡和掉電保護使開發(fā)者可以放心的將文件系統(tǒng)掛載到 nor flash 上。
3.1 使能DFS框架
打開 env,輸入 menuconfig,在 RT-Thread Components → Device virtual file system 中打開 DFS 框架。

使用默認配置
3.2 配置 littlefs
在 RT-Thread online packages → system packages → Littlefs: A high-integrity embedded file system 中打開 littlefs。

注意lfs enable wear leveling要改成100,這項意思是 lfs啟用損耗均衡
3.2.1 猜測
代碼中對于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 翻譯
//可擦除塊的大小。 這不會影響ram的消耗,并且
//可能大于物理擦除大小。 但是,非內(nèi)聯(lián)文件
//至少占用一個街區(qū)。 必須是讀取的倍數(shù)
//和程序大小。
結(jié)合程序調(diào)試中mtd_nor->block_size值為0x0002 0000。即128KB,又是”filesystem”分區(qū)所在的扇區(qū)的大小。

所以基本確定disk block size應(yīng)該填128*1024,即131072。
其他配置我覺得默認配置問題不大。比如下面這個注釋的描述。
// 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 組件并沒有加入自動初始化的代碼,所以我們需要在 main 函數(shù)中初始化 fal,并使用 fal 提供的 API 來創(chuàng)建一個 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);
}
}
注意這里使用了一個分區(qū)”filesystem”。所以上面創(chuàng)建分區(qū)必須也有名為”filesystem”的分區(qū)。
3.5 使用littlefs 文件系統(tǒng)
3.5.1 參考
文件系統(tǒng)語句都是通用的,都是基于POSIX 標準的
3.5.2 問題
需要注意:我這一直有個問題,就是只能使用mkdir 創(chuàng)建2條路徑,創(chuàng)建第3條就會出錯。如下:

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

文檔里漏了
3.5.4 官方例程

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



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


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

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


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