在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【S32K146 RT-thread】基于內(nèi)部PFLASH的littlefs適配

RT-Thread官方賬號 ? 2025-01-14 18:32 ? 次閱讀

LittleFS是一個應(yīng)用于單片機內(nèi)部flash和外掛NOR flash的文件系統(tǒng)。由于它相比傳統(tǒng)的FAT文件系統(tǒng)更適合于小型嵌入式系統(tǒng),具有以下特點:

掉電恢復能力: 設(shè)計用于處理隨機電源故障。所有文件操作都有很強的寫時拷貝保證,如果斷電,文件系統(tǒng)將恢復到上一次已知的良好狀態(tài)。

動態(tài)磨損均衡: 設(shè)計考慮到閃存,并提供動態(tài)塊磨損均衡。此外,littlefs可以檢測壞塊并在它們周圍工作。

有限RAM/ROM: 被設(shè)計為使用少量內(nèi)存。RAM的使用是嚴格限制的,這意味著RAM的使用不會隨著文件系統(tǒng)的增長而改變。文件系統(tǒng)不包含無界遞歸,動態(tài)內(nèi)存僅限于可靜態(tài)提供的可配置緩沖區(qū)。

官方的詳細介紹參照此鏈接(https://github.com/littlefs-project/littlefs/
S32K146 內(nèi)部的Pflash 資源大小為1M,這個大小對普通的嵌入式開發(fā)資源是有很大的空閑的,本次試驗基于內(nèi)部的pflash 將后512K資源劃分為文件系統(tǒng)分區(qū),使用littlefs 進行管理,我們修改鏈接腳本把后512K資源保留出來給文件系統(tǒng)使用,本次試驗使用的IAR環(huán)境,link file 修改如下:

d3fc9456-d262-11ef-9434-92fbcf53809c.jpgd407e130-d262-11ef-9434-92fbcf53809c.jpg

littlefs 移植適配依賴物理層的配置結(jié)構(gòu)體如下:

// Configuration provided during initialization of the littlefsstruct lfs_config { // Opaque user provided context that can be used to pass // information to the block device operations void *context;
// Read a region in a block. Negative error codes are propagated // to the user. int (*read)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size);
// Program a region in a block. The block must have previously // been erased. Negative error codes are propagated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. int (*prog)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block. A block must be erased before being programmed. // The state of an erased block is undefined. Negative error codes // are propagated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. int (*erase)(const struct lfs_config *c, lfs_block_t block);
// Sync the state of the underlying block device. Negative error codes // are propagated to the user. int (*sync)(const struct lfs_config *c);
#ifdef LFS_THREADSAFE // Lock the underlying block device. Negative error codes // are propagated to the user. int (*lock)(const struct lfs_config *c);
// Unlock the underlying block device. Negative error codes // are propagated to the user. int (*unlock)(const struct lfs_config *c);#endif
// Minimum size of a block read in bytes. All read operations will be a // multiple of this value. lfs_size_t read_size;
// Minimum size of a block program in bytes. All program operations will be // a multiple of this value. lfs_size_t prog_size;
// Size of an erasable block in bytes. 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. lfs_size_t block_size;
// Number of erasable blocks on the device. lfs_size_t block_count;
// Number of erase cycles before littlefs evicts metadata logs and moves // the metadata to another block. Suggested values are in the // range 100-1000, with large values having better performance at the cost // of less consistent wear distribution. // // Set to -1 to disable block-level wear-leveling. int32_t block_cycles;
// Size of block caches in bytes. Each cache buffers a portion of a block in // RAM. The littlefs needs a read cache, a program cache, and one additional // cache per file. Larger caches can improve performance by storing more // data and reducing the number of disk accesses. Must be a multiple of the // read and program sizes, and a factor of the block size. lfs_size_t cache_size;
// Size of the lookahead buffer in bytes. A larger lookahead buffer // increases the number of blocks found during an allocation pass. The // lookahead buffer is stored as a compact bitmap, so each byte of RAM // can track 8 blocks. Must be a multiple of 8. lfs_size_t lookahead_size;
// Optional statically allocated read buffer. Must be cache_size. // By default lfs_malloc is used to allocate this buffer. void *read_buffer;
// Optional statically allocated program buffer. Must be cache_size. // By default lfs_malloc is used to allocate this buffer. void *prog_buffer;
// Optional statically allocated lookahead buffer. Must be lookahead_size // and aligned to a 32-bit boundary. By default lfs_malloc is used to // allocate this buffer. void *lookahead_buffer;
// Optional upper limit on length of file names in bytes. No downside for // larger names except the size of the info struct which is controlled by // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in // superblock and must be respected by other littlefs drivers. lfs_size_t name_max;
// Optional upper limit on files in bytes. No downside for larger files // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored // in superblock and must be respected by other littlefs drivers. lfs_size_t file_max;
// Optional upper limit on custom attributes in bytes. No downside for // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to // LFS_ATTR_MAX when zero. lfs_size_t attr_max;
// Optional upper limit on total space given to metadata pairs in bytes. On // devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB) // can help bound the metadata compaction time. Must be <= block_size. // Defaults to block_size when zero. lfs_size_t metadata_max;};

主要包含物理層設(shè)備的讀寫/擦除,及FLASH最小編程塊屬性配置,查看S32K146 的features 可以知道,最小擦除的sector 為4096字節(jié),最小寫操作size 為8字節(jié),我們按照littlefs 依賴的配置結(jié)構(gòu)實現(xiàn)對應(yīng)的函數(shù)。

read 接口實現(xiàn):



int lfs_mflash_read(const struct lfs_config *lfsc, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size){ struct lfs_mflash_ctx *ctx; uint32_t flash_addr;
assert(lfsc); ctx = (struct lfs_mflash_ctx *)lfsc->context; assert(ctx);
flash_addr = ctx->start_addr + block * lfsc->block_size + off; for(lfs_size_t i=0; i < size; i++) { ((int8_t *)buffer)[i] = *((__IO int8_t*)flash_addr); flash_addr++; }
return LFS_ERR_OK;}

prog接口實現(xiàn):


int32_t mflash_drv_program(uint32_t addr,uint32_t size,uint8_t * pdata){ status_t ret;
ret = FLASH_DRV_Program(&pSSDConfig,addr,size,pdata);
return ret == STATUS_SUCCESS ? 0 : -1;}
int lfs_mflash_prog( const struct lfs_config *lfsc, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size){ struct lfs_mflash_ctx *ctx; uint32_t flash_addr; int32_t ret;
ctx = (struct lfs_mflash_ctx *)lfsc->context;
flash_addr = ctx->start_addr + block * lfsc->block_size + off; ret = mflash_drv_program(flash_addr,size,(uint8_t *)buffer); return (ret == 0) ? LFS_ERR_OK : LFS_ERR_IO;}

erase 接口實現(xiàn);

int32_t mflash_drv_erase(uint32_t dest,uint32_t size)

對應(yīng)的配置結(jié)構(gòu)如下:

d41dda12-d262-11ef-9434-92fbcf53809c.jpg

適配接口已經(jīng)對應(yīng)完成,littlefs 會依賴動態(tài)malloc/free 內(nèi)存接口,本次是基于RT-thread 系統(tǒng)lfs_util.h需做如下修改:

d42e7282-d262-11ef-9434-92fbcf53809c.jpg

至此Littfs 依賴的適配接口已經(jīng)完成,我們追加shell 測試命令來驗證littlefs的基本創(chuàng)建刪除文件及文件夾及讀寫刪除試驗,對應(yīng)的shell 測試命令代碼如下:

#include "drv_mflash.h"#include #include #include #include #include
#define SHELL_Printf rt_kprintf#define PRINTF rt_kprintf
/******************************************************************************* * Variables ******************************************************************************/
lfs_t lfs;struct lfs_config cfg;int lfs_mounted;

static void format(int argc, char **argv){ int res;
if (lfs_mounted) { SHELL_Printf("LFS is mounted, please unmount it first.\r\n"); return; }
if (argc != 2 || strcmp(argv[1], "yes")) { SHELL_Printf("Are you sure? Please issue command "format yes" to proceed.\r\n"); return; }
res = lfs_format(&lfs, &cfg); if (res) { PRINTF("\rError formatting LFS: %d\r\n", res); }
return;}
MSH_CMD_EXPORT(format,"lfs format api");
static void mount(int argc, char **argv){ int res;
if (lfs_mounted) { SHELL_Printf("LFS already mounted\r\n"); return; }
res = lfs_mount(&lfs, &cfg); if (res) { PRINTF("\rError mounting LFS\r\n"); } else { lfs_mounted = 1; }
return;}MSH_CMD_EXPORT(mount,lfs mount api);
static void unmount(int argc, char **argv){ int res;
if (!lfs_mounted) { SHELL_Printf("LFS not mounted\r\n"); return; }
res = lfs_unmount(&lfs); if (res) { PRINTF("\rError unmounting LFS: %i\r\n", res); }
lfs_mounted = 0; return;}MSH_CMD_EXPORT(unmount,lfs unmount api);
static void cd(int argc, char **argv){ SHELL_Printf( "There is no concept of current directory in this example.\r\nPlease always specify the full path.\r\n"); return;}MSH_CMD_EXPORT(cd,lfs cd api);

static void lls(int argc, char **argv){ int res; char *path; lfs_dir_t dir; struct lfs_info info; int files; int dirs;
if (!lfs_mounted) { SHELL_Printf("LFS not mounted\r\n"); return; }
if (argc > 2) { SHELL_Printf("Invalid number of parameters\r\n"); return; }
if (argc < 2) { path = "/"; } else { path = argv[1]; }
/* open the directory */ res = lfs_dir_open(&lfs, &dir, path); if (res) { PRINTF("\rError opening directory: %i\r\n", res); return; }
PRINTF(" Directory of %s\r\n", path); files = 0; dirs = 0;
/* iterate until end of directory */ while ((res = lfs_dir_read(&lfs, &dir, &info)) != 0) { if (res < 0) { /* break the loop in case of an error */ PRINTF("\rError reading directory: %i\r\n", res); break; }
if (info.type == LFS_TYPE_REG) { SHELL_Printf("%8d %s\r\n", info.size, info.name); files++; } else if (info.type == LFS_TYPE_DIR) { SHELL_Printf("% DIR %s\r\n", info.name); dirs++; } else { SHELL_Printf("%???\r\n"); } }
res = lfs_dir_close(&lfs, &dir); if (res) { PRINTF("\rError closing directory: %i\r\n", res); return; }
PRINTF(" %d File(s), %d Dir(s)\r\n", files, dirs);
return;}MSH_CMD_EXPORT(lls,lfs ls api);

static void rm(int argc, char **argv){ int res;
if (!lfs_mounted) { SHELL_Printf("LFS not mounted\r\n"); return; }
res = lfs_remove(&lfs, argv[1]);
if (res) { PRINTF("\rError while removing: %i\r\n", res); }
return;}MSH_CMD_EXPORT(rm,lfs rm api);

static void lmkdir(int argc, char **argv){ int res;
if (!lfs_mounted) { SHELL_Printf("LFS not mounted\r\n"); return; }
res = lfs_mkdir(&lfs, argv[1]);
if (res) { PRINTF("\rError creating directory: %i\r\n", res); }
return;}MSH_CMD_EXPORT(lmkdir,lfs mkdir api);
static void write(int argc, char **argv){ int res; lfs_file_t file;
if (!lfs_mounted) { SHELL_Printf("LFS not mounted\r\n"); return; }
res = lfs_file_open(&lfs, &file, argv[1], LFS_O_WRONLY | LFS_O_APPEND | LFS_O_CREAT); if (res) { PRINTF("\rError opening file: %i\r\n", res); return; }
res = lfs_file_write(&lfs, &file, argv[2], strlen(argv[2])); if (res > 0) res = lfs_file_write(&lfs, &file, "\r\n", 2);
if (res < 0) { PRINTF("\rError writing file: %i\r\n", res); }
res = lfs_file_close(&lfs, &file); if (res) { PRINTF("\rError closing file: %i\r\n", res); }
return;}MSH_CMD_EXPORT(write,lfs write api);

static void cat(int argc, char **argv){ int res; lfs_file_t file; uint8_t buf[16];
if (!lfs_mounted) { SHELL_Printf("LFS not mounted\r\n"); return; }
res = lfs_file_open(&lfs, &file, argv[1], LFS_O_RDONLY); if (res) { PRINTF("\rError opening file: %i\r\n", res); return; }
do { res = lfs_file_read(&lfs, &file, buf, sizeof(buf)); if (res < 0) { PRINTF("\rError reading file: %i\r\n", res); break; } if(res > 0) { buf[res] = '\0'; PRINTF("%s",(char *)buf); } } while (res);
res = lfs_file_close(&lfs, &file); if (res) { PRINTF("\rError closing file: %i\r\n", res); }
return;}MSH_CMD_EXPORT(cat,lfs cat api);
static void lfsinit(int argc, char **argv){ mflash_drv_init(); lfs_get_default_config(&cfg); return;}MSH_CMD_EXPORT(lfsinit,lfs init api);
static void df(int argc, char **argv){ printf("used block %d total %d\r\n",lfs_fs_size(&lfs),cfg.block_count); return;}MSH_CMD_EXPORT(df,lfs init api);

至此準備工作已經(jīng)完成,我們通過shell 來驗證文件系統(tǒng)的功能,shell 命令驗證文件系統(tǒng)已經(jīng)可以通過操作文件文件夾。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 單片機
    +關(guān)注

    關(guān)注

    6066

    文章

    44946

    瀏覽量

    648305
  • 嵌入式
    +關(guān)注

    關(guān)注

    5144

    文章

    19575

    瀏覽量

    315832
  • RT-Thread
    +關(guān)注

    關(guān)注

    32

    文章

    1377

    瀏覽量

    41619
收藏 人收藏

    評論

    相關(guān)推薦
    熱點推薦

    RT-Thread的C語言編碼規(guī)范

    的編程風格。同時對于使用 RT-Thread 的用戶,也可通過這份文檔了解 RT-Thread代碼內(nèi)部一些約定從而比較容易的把握到 RT-Thread 的實現(xiàn)方式。
    的頭像 發(fā)表于 02-21 16:50 ?2769次閱讀

    S32K146的hard fault問題解決方案

    最近有個客戶使用S32K146的產(chǎn)品在量產(chǎn)之后出現(xiàn)了三個售后件,ABBA測試之后的結(jié)果表明失效現(xiàn)象跟著S32K146走;同時客戶反饋說試著將其中一個售后件重新燒錄程序,S32K146又正常工作了。結(jié)合這兩種情況,
    的頭像 發(fā)表于 11-22 11:35 ?3806次閱讀
    <b class='flag-5'>S32K146</b>的hard fault問題解決方案

    S32K146如何用中斷喚醒VLPS模式?

    S32K146的模式設(shè)置為VLPS后,觸發(fā)外部中斷后CLOCK_SYS_GetFreq獲取的頻率沒有變化,如何使用中斷將電源模式從VLPS恢復為RUN?
    發(fā)表于 06-01 08:13

    RT-Thread編程指南

    RT-Thread編程指南——RT-Thread開發(fā)組(2015-03-31)。RT-Thread做為國內(nèi)有較大影響力的開源實時操作系統(tǒng),本文是RT-Thread實時操作系統(tǒng)的編程指南
    發(fā)表于 11-26 16:06 ?0次下載

    RT-Thread用戶手冊

    RT-Thread用戶手冊——本書是RT-Thread的編程手冊,用于指導在RT-Thread實時操作系統(tǒng)環(huán)境下如何進行編 程。
    發(fā)表于 11-26 16:16 ?0次下載

    RT-Thread全球技術(shù)大會:螢石研發(fā)團隊使用RT-Thread的技術(shù)挑戰(zhàn)

    RT-Thread全球技術(shù)大會:研發(fā)團隊使用RT-Thread的技術(shù)挑戰(zhàn) ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 11:36 ?1515次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會:螢石研發(fā)團隊使用<b class='flag-5'>RT-Thread</b>的技術(shù)挑戰(zhàn)

    RT-Thread全球技術(shù)大會:Kconfig在RT-Thread中的工作機制

    RT-Thread全球技術(shù)大會:Kconfig在RT-Thread中的工作機制 ? ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 14:49 ?1794次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會:Kconfig在<b class='flag-5'>RT-Thread</b>中的工作機制

    RT-Thread全球技術(shù)大會:RT-Thread測試用例集合案例

    RT-Thread全球技術(shù)大會:RT-Thread測試用例集合案例 ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:34 ?2343次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會:<b class='flag-5'>RT-Thread</b>測試用例集合案例

    RT-Thread學習筆記 RT-Thread的架構(gòu)概述

    RT-Thread 簡介 作為一名 RTOS 的初學者,也許你對 RT-Thread 還比較陌生。然而,隨著你的深入接觸,你會逐漸發(fā)現(xiàn) RT-Thread 的魅力和它相較于其他同類型 RTOS
    的頭像 發(fā)表于 07-09 11:27 ?4940次閱讀
    <b class='flag-5'>RT-Thread</b>學習筆記 <b class='flag-5'>RT-Thread</b>的架構(gòu)概述

    RT-Thread文檔_RT-Thread 簡介

    RT-Thread文檔_RT-Thread 簡介
    發(fā)表于 02-22 18:22 ?5次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 簡介

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南
    發(fā)表于 02-22 18:23 ?10次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread SMP 介紹與移植

    RT-Thread文檔_RT-Thread SMP 介紹與移植
    發(fā)表于 02-22 18:31 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> SMP 介紹與移植

    基于RT-Thread Studio學習

    前期準備:從官網(wǎng)下載 RT-Thread Studio,弄個賬號登陸,開啟rt-thread學習之旅。
    的頭像 發(fā)表于 05-15 11:00 ?5105次閱讀
    基于<b class='flag-5'>RT-Thread</b> Studio學習

    S32K146 RT-thread】之 SPI驅(qū)動適配

    概述RT-Thread對SPI總線的驅(qū)動,抽象出了spibus的設(shè)備驅(qū)動,我們基于S32K146的硬件學習spibus設(shè)備驅(qū)動。
    的頭像 發(fā)表于 11-01 08:11 ?1224次閱讀
    【<b class='flag-5'>S32K146</b> <b class='flag-5'>RT-thread</b>】之 SPI驅(qū)動<b class='flag-5'>適配</b>

    S32K146 RT-Thread】之 使用SFUD組件驅(qū)動spi flash

    S32K146 RT-Thread】之 使用SFUD組件驅(qū)動spi flash
    的頭像 發(fā)表于 11-21 01:05 ?1032次閱讀
    【<b class='flag-5'>S32K146</b> <b class='flag-5'>RT-Thread</b>】之 使用SFUD組件驅(qū)動spi flash
    主站蜘蛛池模板: 色婷婷影视 | 天堂色| 日韩毛片网 | 黄视频网站免费观看 | 毛片又大又粗又长又硬 | 成人黄色三级 | 久久精品免看国产 | 亚洲高清国产拍精品影院 | 一级特黄国产高清毛片97看片 | 五月激情六月 | 男人的天堂在线精品视频 | 最近2018年中文字幕免费图片 | 91婷婷色涩涩 | 日本免费色视频 | 免费的男女拍拍拍的视频 | 天天干狠狠干 | 68日本xxxxxxxxx777 | 在线天堂中文有限公司 | 毛色毛片免费观看 | 免费看h视频 | 九九美剧 | 免费v片网站 | 人人插人人插 | 中国china体内裑精亚洲毛片 | 国产亚洲高清在线精品不卡 | 国产一区二区三区四卡 | 色偷偷男人天堂 | 国产成人高清 | 成年片色大黄全免费 | 狠狠色96视频 | 视频在线观看高清免费大全 | 久久综合五月婷婷 | 一区二区精品 | 日本加勒比在线视频 | 色视频网站色视频播放 | 丁香六月色婷婷 | 久久综合狠狠综合狠狠 | 天天综合在线视频 | 亚洲男人的天堂久久无 | 中国性猛交xxxx乱大交 | 边摸边吃奶边做视频叫床韩剧 |