【Zephyr開發實踐系列】08_NVS文件系統調試記錄

文章目錄

  • 前言
  • 一、NVS原理介紹:
  • 二、BUG-NO1:將NVS運用在NAND-Flash類大容量存儲設備
    • 2.1 情況描述:
    • 2.2 BUG復現:
      • 文件系統設備樹構建
      • 測試應用編寫(導致錯誤部分):
      • 問題呈現:
    • 2.3 問題簡述:
      • 問題定位:
      • 強制實現:
    • 2.3 最后解決:
  • 三、BUG-NO2:nvs_partition地址范圍超出內存范圍
    • 3.1 情況描述:
    • 3.2 BUG復現:
      • 文件系統設備樹構建:
      • 測試代碼編寫(無錯代碼):
      • 問題定位:
    • 3.3 最后解決:
  • 總結


前言

在嵌入式系統開發中,穩定可靠的非易失性存儲方案是系統健壯性的關鍵保障。近期在項目芯片驅動開發中,先后實現了內部Flash和外部NAND Flash的基礎驅動驗證。隨即需要著手構建文件系統層->NVS與LittleFS對Flash進行統一文件管理。
選NVS,如果

  • 只需要存儲少量配置參數(如Wi-Fi SSID、設備序列號)。
  • 數據需要頻繁更新(如計數器、狀態標志)。
  • 對RAM/Flash占用極其敏感。

選LittleFS,如果:

  • 需要存儲日志、圖片、固件等較大文件。
  • 需要目錄管理(如/config/device.cfg)。
  • 設備可能頻繁斷電,需強數據一致性。

但一般可以互相搭配使用

  • NVS 存儲關鍵配置(如藍牙MAC、校準參數)。
  • LittleFS 管理日志、固件包等大文件。

本文記錄使用內部Flash與外部NAND-Flash進行NVS文件系統操作時出現的BUG與調試情況。

一、NVS原理介紹:

請參考:NVS文件系統原理及應用

二、BUG-NO1:將NVS運用在NAND-Flash類大容量存儲設備

2.1 情況描述:

想在外部NAND-Flash上構建類似EEPROM專門存儲小數據的掉電記憶系統,于是碰見了NVS。

2.2 BUG復現:

文件系統設備樹構建

boot_partition: partition@0 {label = "mcuboot";reg = <0x00000000 DT_SIZE_M(1)>;};lfs1_partition: partition@100000 {reg = <0x00100000 DT_SIZE_M(510)>;};slot0_partition: partition@1FF00000 {label = "image-0";reg = <0x1FF00000 DT_SIZE_K(128)>;};slot1_partition: partition@1FF20000 {label = "image-1";reg = <0x1FF20000 DT_SIZE_K(128)>;};nvs_partition: partition@1FF40000 {label = "nvs";reg = <0x1FF40000 DT_SIZE_K(256)>;};

說明將512M NAND-Flash劃分為四個分區:

  • boot_partition:存放mcu-boot
  • lfs1_partition:LittleFS文件系統管理處
  • slot0_partition:迭代版本程序0
  • slot1_partition:迭代版本程序1
  • nvs_partition:NVS文件系統管理處
    1M+510M+128K+128K+256K<512M,使用該分配是合理的。

測試應用編寫(導致錯誤部分):

/* 最小擦除單位是128KB*/
#define NVS_SECTOR_SIZE  128*1024
#define NVS_SECTOR_COUNT (DT_SIZE_K(256K) / NVS_SECTOR_SIZE)  // 256KB / 128KB = 2 static struct nvs_fs fs = {.sector_size = NVS_SECTOR_SIZE, //最小擦除單位*n.sector_count = NVS_SECTOR_COUNT, //大于等于2.offset = NVS_PARTITION_OFFSET, //起始地址,必須是可擦除區域的邊界:1FF40000/128K無余數
};

說明:

  • sector_size:最小擦除單位,針對NOR-Flash叫扇區,一般是1-2K。而NAND-Flash,無扇區概念,額定最小擦除單位(塊):128K
  • sector_count:扇區個數。sector_size*sector_count小于等于nvs_partition大小即可。
  • offset:可擦除邊界地址

問題呈現:

編譯后報錯:NVS_SECTOR_SIZE Over sector_size(0~65536)

2.3 問題簡述:

問題定位:

sector_size的數據格式是uint16(0~65535)=64K,若輸入范圍大于uint16將會返回錯誤。
定義文件路徑:settings_env.c

	if (nvs_sector_size > UINT16_MAX) {return -EDOM;}

我們NAND-Flash最小擦除范圍是128K,大于uint16。

強制實現:

嘗試強制將NAND-Flash改為sector_size的范圍(64K),同時增加sector_count數。
經嘗試編譯通過:但毫無疑問出現邊界未對齊問題,芯片直接跑飛:

[19:57:48.802][00:00:01.387,000] <err> os: ***** USAGE FAULT *****
[19:57:48.804][00:00:01.387,000] <err> os:   Unaligned memory access
[19:57:48.805][00:00:01.387,000] <err> os: r0/a1:  0x00000073  r1/a2:  0x39c00000  r2/a3:  0x00000073
[19:57:48.806][00:00:01.387,000] <err> os: r3/a4:  0x39c00000 r12/ip:  0x0000019b r14/lr:  0x0c0cf2fb
[19:57:48.807][00:00:01.387,000] <err> os:  xpsr:  0x01100000
[19:57:48.808][00:00:01.387,000] <err> os: s[ 0]:  0x00000000  s[ 1]:  0x00000000  s[ 2]:  0x00000000  s[ 3]:  0x00000000
[19:57:48.810][00:00:01.387,000] <err> os: s[ 4]:  0x616c7f25  s[ 5]:  0x3fe55555  s[ 6]:  0xf8198216  s[ 7]:  0x3f326636
[19:57:48.811][00:00:01.387,000] <err> os: s[ 8]:  0x5f00cb5a  s[ 9]:  0xbf912862  s[10]:  0x35793c76  s[11]:  0x3dea39ef
[19:57:48.812][00:00:01.387,000] <err> os: s[12]:  0x40400000  s[13]:  0x40600000  s[14]:  0x3bb54000  s[15]:  0x44160000
[19:57:48.814][00:00:01.387,000] <err> os: fpscr:  0x20040010

2.3 最后解決:

經詢問,原因是NVS不支持需要大塊擦除的存儲設備,特別是NAND-Flash還需要ECC和壞塊檢測的存儲設備,NAND-Flash只能使用LittleFS。
github
具體問題路徑:NVS service sector_size limited range is (0~65535)

三、BUG-NO2:nvs_partition地址范圍超出內存范圍

3.1 情況描述:

幸虧Zephyr頻繁在支持與更新,問題一很快得到了官方項目貢獻者的回答。
得知NVS無法運用在NAND-Flash于是將NVS運用在內部NOR-Flash上,但由于nvs_partition地址范圍超出內存范圍,出現讀取錯誤。

3.2 BUG復現:

文件系統設備樹構建:

&flash0 {partitions {compatible = "fixed-partitions";#address-cells = <1>;#size-cells = <1>;/* Bootloader保留區 (16KB) */boot_partition: partition@0 {label = "bootloader";reg = <0x00000000 DT_SIZE_K(16)>;read-only;};/* 主應用程序區 (432KB) */app_partition: partition@4000 {label = "app";reg = <0x00004000 DT_SIZE_K(432)>;};/* NVS存儲區 (48KB) - 嚴格對齊2KB邊界 */storage_partition: partition@70000 {label = "storage";reg = <0x0007C000 DT_SIZE_K(48)>; };};
};

內部Flash大小是512K,16K+532KB+48KB<512K

測試代碼編寫(無錯代碼):

/* 最小擦除單位是2KB*/
#define NVS_SECTOR_SIZE  2*1024
#define NVS_SECTOR_COUNT (DT_SIZE_K(256K) / NVS_SECTOR_SIZE)  // 64KB / 2KB = 32 static struct nvs_fs fs = {.sector_size = NVS_SECTOR_SIZE, //最小擦除單位*n.sector_count = NVS_SECTOR_COUNT, //大于等于2.offset = NVS_PARTITION_OFFSET, //起始地址,必須是可擦除區域的邊界
};

編譯通過,但讀取過程報錯:

*** Booting Zephyr OS build v4.1.0-5510-g8d2010e1e179 ***[2025-07-18 12:48:39.376]
[00:00:00.005,000] [1;31m<err> flash_stm32: Read range invalid. Offset: 526328, len: 8[0m[2025-07-18 12:48:39.385]
[00:00:00.013,000] [1;31m<err> flash_stm32: Read range invalid. Offset: 528376, len: 8[0m[2025-07-18 12:48:39.392]
[00:00:00.021,000] [1;31m<err> flash_stm32: Read range invalid. Offset: 528376, len: 8[0m[2025-07-18 12:48:39.405]
[00:00:00.029,000] [1;31m<err> flash_stm32: Read range invalid. Offset: 530424, len: 8[0m[2025-07-18 12:48:39.412]
[00:00:00.037,000] [1;31m<err> flash_stm32: Read range invalid. Offset: 530424, len: 8[0m[2025-07-18 12:48:39.420]
[00:00:00.045,000] [1;31m<err> flash_stm32: Read range invalid. Offset: 532472, len: 8[0m[2025-07-18 12:48:39.428]

問題定位:

看似合理,但是512KB = 0x00000000 ~ 0x0007FFFF
地址計算錯誤:
storage_partition分區的起始地址 0x7C000 + 大小 0xC000 = 0x88000>512K,但實際Flash結束于 0x7FFFF。

根據NVS算法原理:NVS在存儲時會向ate(記錄分配表)里寫入一組數據,ate在扇區中從后向前增長。所以說明部分ID數據的ATE表會保存在最后一塊扇區的最后幾位即0x88000附近>512K。這就是導致問題的直接原因。

3.3 最后解決:

&flash0 {partitions {compatible = "fixed-partitions";#address-cells = <1>;#size-cells = <1>;/* Bootloader保留區 (16KB) */boot_partition: partition@0 {label = "bootloader";reg = <0x00000000 DT_SIZE_K(16)>;read-only;};/* 主應用程序區 (432KB) */app_partition: partition@4000 {label = "app";reg = <0x00004000 DT_SIZE_K(432)>;};/* NVS存儲區 (48KB) - 嚴格對齊2KB邊界 */storage_partition: partition@70000 {label = "storage";reg = <0x00070000 DT_SIZE_K(48)>; };};
};

0x00070000 +48K<512K,符合要求,測試順利!!!!

總結

在 Zephyr 上配置 NVS 時,需要綜合考慮:

  • 設備樹分區布局
  • Flash 物理特性
  • 內存對齊要求

通過系統性的問題分析和逐步調試,最終成功解決了所有編譯和運行時錯誤。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89385.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89385.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89385.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡安全第二次作業

靶場闖關1~8 1. 在url后的name后輸入payload ?name<script>alert(1)</script> 2. 嘗試在框中輸入上一關的payload,發現并沒有通過&#xff0c;此時我們可以點開頁面的源代碼看看我們輸入的值被送到什么地方去了 從圖中可以看到&#xff0c;我們輸入的值被送到i…

LangChain 源碼剖析(七)RunnableBindingBase 深度剖析:給 Runnable“穿衣服“ 的裝飾器架構

每一篇文章都短小精悍&#xff0c;不啰嗦。一、功能定位&#xff1a;Runnable 的 "增強包裝器"RunnableBindingBase 是 LangChain 中實現裝飾器模式的核心組件。它就像給原有 Runnable 套上一件 "功能外套"—— 不改變原有 Runnable 的核心邏輯&#xff0c…

為 Git branch 命令添加描述功能

寫在最前面的使用方式 查看 所有分支的備注 git branch.notes創建分支并為分支添加備注 git co -b feat/oauth -m 第三方用戶登錄對分支描述的添加與清除 添加 git branch.note --add 清除 git branch.note --clear &#x1f4dd; 為 Git branch 命令添加描述功能 &#x…

LeetCode|Day18|20. 有效的括號|Python刷題筆記

LeetCode&#xff5c;Day18&#xff5c;20. 有效的括號&#xff5c;Python刷題筆記 &#x1f5d3;? 本文屬于【LeetCode 簡單題百日計劃】系列 &#x1f449; 點擊查看系列總目錄 >> &#x1f4cc; 題目簡介 題號&#xff1a;20. 有效的括號 難度&#xff1a;簡單 題目…

使?Pytorch構建?個神經?絡

關于torch.nn:使?Pytorch來構建神經?絡, 主要的?具都在torch.nn包中.nn依賴于autograd來定義模型, 并對其?動求導.構建神經?絡的典型流程:定義?個擁有可學習參數的神經?絡遍歷訓練數據集處理輸?數據使其流經神經?絡計算損失值將?絡參數的梯度進?反向傳播以?定的規則…

網絡爬蟲的詳細知識點

基本介紹 什么是網絡爬蟲 網絡爬蟲&#xff08;Web Crawler&#xff09;是一種自動化程序&#xff0c;用于從互聯網上抓取、解析和存儲網頁數據。其核心功能是模擬人類瀏覽行為&#xff0c;通過HTTP/HTTPS協議訪問目標網站&#xff0c;提取文本、鏈接、圖片或其他結構化信息&…

AndroidX中ComponentActivity與原生 Activity 的區別

一、AndroidX 與原生 Activity 的區別 1. 概念與背景 原生 Activity&#xff1a;指 Android 早期&#xff08;API 1 起&#xff09;就存在于 android.app 包下的 Activity 類&#xff08;如 android.app.Activity&#xff09;&#xff0c;是 Android 最初的 Activity 實現&…

Spring AI 使用 Elasticsearch 作為向量數據庫

前言 嗨&#xff0c;大家好&#xff0c;我是雪荷&#xff0c;最近在公司開發 AI 知識庫&#xff0c;同時學到了一些 AI 開發相關的技術&#xff0c;這期先與大家分享一下如何用 ES 當做向量數據庫。 安裝ES 第一步我們先安裝 Elasticsearch&#xff0c;這里建議 Elasticsear…

TypeScript 配置全解析:tsconfig.json、tsconfig.app.json 與 tsconfig.node.json 的深度指南

前言在現代前端和后端開發中&#xff0c;TypeScript 已經成為許多開發者的首選語言。然而&#xff0c;TypeScript 的配置文件&#xff08;特別是多個配置文件協同工作時&#xff09;常常讓開發者感到困惑。本文將深入探討 tsconfig.json、tsconfig.app.json 和 tsconfig.node.j…

讀書筆記(學會說話)

1、一個人只有會說話&#xff0c;才會有好人緣&#xff0c;做事才會順利。會說話的人容易成功。善于說話的人易成功&#xff0c;而不善說話的人往往寸步難行。我們要把話說得好聽&#xff0c;同時更要把事做得漂亮。或許一句話&#xff0c;一件事&#xff0c;就可能使人生的旅途…

私有服務器AI智能體搭建-大模型選擇優缺點、擴展性、可開發

以下是主流 AI 框架與模型的對比分析&#xff0c;涵蓋其優缺點、擴展性、可開發性等方面。 文章目錄一、AI 框架對比二、主流大模型對比三、擴展性對比總結四、可開發性對比總結五、選擇建議&#xff08;按場景&#xff09;六、未來趨勢一、AI 框架對比 框架優點缺點擴展性可開…

OpenCV直線段檢測算法類cv::line_descriptor::LSDDetector

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 該類用于實現 LSD (Line Segment Detector) 直線段檢測算法。LSD 是一種快速、準確的直線檢測方法&#xff0c;能夠在不依賴邊緣檢測的前提下直接從…

Go語言流程控制(if / for)

分支結構package mainimport ("fmt""strconv" )/* 1.順序結構 2.分支結構 3.循環結構 *//* if 條件1 {// 條件1為真時執行的代碼 } else if 條件2 {// 條件1為假但條件2為真時執行的代碼 } else {// 所有條件均為假時執行的代碼 }一種特殊的條件分支結構if…

wx小程序設置沉浸式導航文字高度問題

第一步&#xff1a;在app.json中設置"navigationStyle": "custom"第二步驟&#xff1a;文件的home.js中// pages/test/test.js Page({/*** 頁面的初始數據*/data: {statusBarHeight: 0,navBarHeight: 44 // 自定義導航內容區高度(單位px)},/*** 生命周期函…

C++算法競賽篇:DevC++ 如何進行debug調試

C算法競賽篇&#xff1a;DevC 如何進行debug調試前言一、準備工作&#xff1a;編譯生成可執行程序二、核心步驟&#xff1a;設置斷點與啟動調試1. 設置斷點2. 啟動調試模式三、調試操作&#xff1a;逐步執行與變量監控1. 逐步執行代碼2. 監控變量值變化四、調試結束前言 在算法…

語音大模型速覽(三)- cosyvoice2

CosyVoice 2: Scalable Streaming Speech Synthesis with Large Language Models 論文鏈接&#xff1a;https://arxiv.org/pdf/2412.10117代碼鏈接&#xff1a;https://github.com/FunAudioLLM/CosyVoice 一句話總結 CosyVoice 2 是一款改進的流式語音合成模型&#xff0c;其…

-lstdc++與-static-libstdc++的用法和差異

CMakeLists.txt 里寫了&#xff1a; target_link_libraries(${PROJECT_NAME} PRIVATEgccstdc ) target_link_options(${PROJECT_NAME} PRIVATE -static-libstdc)看起來像是“鏈接了兩次 C 標準庫”&#xff0c;其實它們的作用完全不同&#xff1a;1. target_link_libraries(...…

Redis學習其二(事務,SpringBoot整合,持久化RDB和AOF)

文章目錄5,事務5.1Redis 事務不保證原子性的原因5.2事務操作過程5.3監控6,SpringBoot整合Redis6.1Redis客戶端6.1.1Jedis簡單使用6.1.2Lettuce&Jedis6.2配置相關6.3使用6.3.1使用RedisTemplate6.3.2Redis工具類7,持久化RDB7.1RDB持久化原理7.2觸發機制save命令flushall命令…

springboot項目部署到K8S

java后臺 創建harbor鏡像拉取Secret&#xff1a;kubectl create secret docker-registry harbor-regcred \--docker-server \ #harbor倉庫地址--docker-username \ #harbor 賬號--docker-password \ #harbor密碼-n productionDockerfile FROM *harbor地址*/library/custom-jdk…

【FPGA開發】一文輕松入門Modelsim的基本操作

Modelsim仿真的步驟 &#xff08;1&#xff09;創建新的工程。 &#xff08;2&#xff09;在彈出的窗口中&#xff0c;確定項目名和工作路徑&#xff0c;庫保持為work不變(如有需要可以根據需求進行更改)。 &#xff08;3&#xff09;添加已經存在的文件&#xff08;rtl代碼和t…