由于之前需要使用片上的flash多余的部分來搭建文件系統,但是沒有找到使用片上的教程,都是利用片外的flash教程。后來發現能直接使用fal軟件包作為flash設備抽象層,向上可以提供文件系統的接口,向下可以驅動片內的flash。這里放上之前使用的筆記。
1.簡介
littlefs 在 RT-Thread 上運行的層級關系圖如下所示:
開發者使用的是 DFS 框架提供的統一的 POSIX API,DFS 框架會調用 littlefs 的 API,littlefs 會使用 MTD 設備的讀寫接口,開發者可以使用 RT-Thread 提供的 fal 組件和 SFUD 組件來完成對 FLASH 的讀寫任務,也可以自己實現 MTD 設備的驅動程序,使 littlefs 可以掛載到更多的存儲介質上。
2.FAL MCU Flash移植
2.1 FAL軟件包源碼獲取
打開bsp工程的ENV環境,運行menuconfig命令。
2.2 fal具體配置
FAL uses SFUD drivers:是用來驅動外置的flash設備,由于我們只使用內部flash,所以不需要選上。
每個功能的配置說明如下:
開啟調試日志輸出(默認開啟);
分區表是否在fal_cfg.h中定義(默認開啟)。如果關閉此選項,fal 將會自動去指定 Flash 的指定位置去檢索并裝載分區表,具體配置詳見下面兩個選項;
存放分區表的 Flash 設備;
分區表的 結束地址 位于 Flash 設備上的偏移。fal 將從此地址開始往回進行檢索分區表,直接讀取到 Flash 頂部。如果不確定分區表具體位置,這里也可以配置為 Flash 的結束地址,fal 將會檢索整個 Flash,檢索時間可能會增加。
啟用 FAL 針對 SFUD 的移植文件(默認關閉);
應輸入調用 rt_sfud_flash_probe 函數時傳入的 FLASH 設備名稱(也可以通過 list_device 命令查看 Block Device 的名字獲取)。該名稱與分區表中的 Flash 名稱對應,只有正確設置設備名字,才能完成對 FLASH 的讀寫操作。
關于分區表,下文還會提及并解釋。
2.3 pkgs —update
保存配置退出后,在env環境執行pkgs —update命令,會自動從FAL的github倉庫獲取FAL軟件包源碼到本地工程目錄,如下圖所示:
2.4 設備表和分區表
FAL組件初始化最重要的是維護兩個表:一個是flash設備表;另一個是FAL分區表,兩個表的元素分別是前面介紹過的fal_flash_dev結構體地址和fal_partition結構體對象。
fal_flash_dev設備表主要由底層的Flash驅動(包括MCU片內Flash和SFUD驅動的片外Flash)提供,也即FAL移植的重點就是在Flash驅動層向FAL提供fal_flash_dev設備表,每個flash設備提供設備表中的一個元素。
fal_partition分區表由用戶事先配置在fal_cfg.h頭文件中,FAL向上面的用戶層提供的分區訪問接口函數操作的內存區間就是從fal_partition分區表獲取的,最后對分區的訪問還是通過Flash驅動提供的接口函數(fal_flash_dev.ops)實現的。
設備表管理不同的flash設備,可以是片內的也可以是片外的。有點像管理不同的硬盤。分區表就是我們電腦上經常說的那個磁盤分區的意思。
2.5 復制文件
考慮到packages下面的軟件版本后續可能會升級覆蓋,我們不在packagesfal-latest目錄下直接進行移植修改,而是在packages目錄外新建一個文件夾ports專門保存軟件包的移植文件信息。
(如果不擔心升級覆蓋問題,跳過2.5和2.6直接看2.9,再回來看2.7和2.8)
新建與packages軟件包同級的移植文件目錄ports,將packagesfal-latestsamplesporting目錄下的fal_cfg.h文件復制一份到portsfal目錄下,將packagesfal-latestSConscript復制一份到portsfal目錄下,將packagesSConscript復制一份到ports目錄下,復制文件后的目錄結構如下圖所示:
(注:圖片里多了fal_flash_sfud_port.c文件,是原博客圖片,但是我們不需要驅動外置的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')
別忘了執行scons —target=mdk5命令,到此直接編譯工程會出現error,需要接下來繼續更改文件。
.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”內添加下面語句
config BSP_USING_ON_CHIP_FLASH
bool "Enable On-Chip Flash"
default n
添加完,進入menuconfig選中該項,并保存退出。
2.8 修改drv_flash_f4.c文件
STM32f427片內Flash驅動,RT-Thread已經在librariesHAL_Drivers drv_flashdrv_flash_f4.c目錄下提供了,同時還通過條件宏提供了向FAL注冊fal_flash_dev設備表項的代碼。但還需我們自己添加一部分代碼(個人覺得應該是rtt 官方留白,讓我們自定義分區基地址和大小),如下圖:
#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)
為什么這樣添加分區基地址和大小?
先看下面的圖
因此我們現在這樣是在使用扇區12到23,又由于STM32F42x的這幾個扇區有16K,64K,128K大小的。所以使用fal時,必須把他們看成3個不同的flash設備進行管理,這也是上文所說flash設備表的作用。
2.9 覆蓋(或新建)fal_cfg.h
新建一個下面代碼塊內容的fal_cfg.h文件在packagesfal-latestinc 內
/*
- 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設備stm32_onchip_flash_16k,stm32_onchip_flash_64k,stm32_onchip_flash_128k
創建四個分區,分別名為bl,param,app,filesystem(名字都是隨便取的)。后兩個分區是分別瓜分了onchip_flash_128k設備內存。
2.x FAL使用示例
見博客 1.4 FAL使用示例 或者** **FAL:Flash 抽象層的 3、Finsh/MSH 測試命令
我的部分操作見 4.2 fal指令實驗
到此已經移植完fal了
3.搭載 littlefs 文件系統
littlefs 是 ARM 官方推出的,專為嵌入式系統設計的文件系統,相比傳統的文件系統,littlefs 具有以下優點:
自帶擦寫均衡
支持掉電保護
占用的 RAM/ROM 少
littlefs 自帶的擦寫均衡和掉電保護使開發者可以放心的將文件系統掛載到 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的消耗,并且
//可能大于物理擦除大小。 但是,非內聯文件
//至少占用一個街區。 必須是讀取的倍數
//和程序大小。
結合程序調試中mtd_nor->block_size值為0x0002 0000。即128KB,又是”filesystem”分區所在的扇區的大小。
所以基本確定disk block size應該填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 設備
在 RT-Thread Components → Device Drivers 中使能 MTD 設備。
使用pkgs —update更新軟件包和scons —target=mdk5
3.4 創建 MTD 設備并掛載文件系統
fal 組件并沒有加入自動初始化的代碼,所以我們需要在 main 函數中初始化 fal,并使用 fal 提供的 API 來創建一個 MTD 設備。創建 MTD 設備后,就可以將 littlefs 掛載到剛剛生成的 MTD 設備上了。
在 main.c 文件中添加(覆蓋)的代碼如下所示:
/* 添加 fal 頭文件 /
#include
/ 添加文件系統頭文件 /
#include
/ 添加 DEBUG 頭文件 /
#define DBG_SECTION_NAME "main"
#define DBG_LEVEL DBG_INFO
#include
/ 定義要使用的分區名字 */
#define FS_PARTITION_NAME "filesystem"
int main(void)
{
struct rt_device mtd_dev = RT_NULL;
/ 初始化 fal /
fal_init();
/ 生成 mtd 設備 /
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
{
/ 格式化文件系統 /
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);
}
}
注意這里使用了一個分區”filesystem”。所以上面創建分區必須也有名為”filesystem”的分區。
3.5 使用littlefs 文件系統
3.5.1 參考
文件系統語句都是通用的,都是基于POSIX 標準的
3.5.2 問題
需要注意:我這一直有個問題,就是只能使用mkdir 創建2條路徑,創建第3條就會出錯。如下:
暫未解決,因為創建二三十個.txt .c也沒出錯,就先這樣吧。
3.5.3 格式化
文檔里講的不清楚。
littlefs的格式化語句
:
1.程序里面寫的
/* 定義要使用的分區名字 /
#define FS_PARTITION_NAME "filesystem"
/ 格式化文件系統 */
dfs_mkfs("lfs", FS_PARTITION_NAME);
2.Finsh組件
mkfs -t lfs filesystem
文檔里漏了
3.5.4 官方例程
4.實驗
4.1 分區實驗
看從0x0800 0000開始是否影響原程序
(是影響的,所以建議從扇區12開始。當然也可以看.map文件來知道程序所占ROM內存大小,來算從第幾個扇區開始是安全的,不過這樣就需要自己不按照我上文講的那樣配置設備表和分區表)
再步進一次,擦除所有扇區,即原來的程序也被擦除,導致hard_fault。匿名上位機保持上一張圖片的狀態
4.2 fal指令實驗
FAL為便于用戶調試,也提供了finsh命令fal,包括fal probe / read / write / erase / bench等命令
通過使用隨機的人為數據給“寫入函數”,讀取出“讀取函數”的值,來驗證是否復位后還保存著數據
(是能繼續存儲的,所以fal確實是操作著掉電不丟失數據的東西)
-
驅動器
+關注
關注
53文章
8271瀏覽量
147067 -
片上系統
+關注
關注
0文章
186瀏覽量
26883 -
RT-Thread
+關注
關注
31文章
1305瀏覽量
40386 -
Flash存儲
+關注
關注
0文章
38瀏覽量
8334 -
DFS
+關注
關注
0文章
26瀏覽量
9191
發布評論請先 登錄
相關推薦
評論