国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

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

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

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

Flash訪問模塊FDS用法及常見問題—nRF5 SDK模塊系列一

jf_14701710 ? 來源:jf_14701710 ? 作者:jf_14701710 ? 2025-05-12 15:59 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

FDS,全稱Flash Data Storage,用來訪問芯片內(nèi)部Flash的。當(dāng)你需要把數(shù)據(jù)存儲(chǔ)在Flash中,或者讀取Flash中的用戶數(shù)據(jù),或者更新或者刪除Flash中的數(shù)據(jù),那么FDS模塊是你最好的選擇。FDS采用文件和記錄方式來組織Flash數(shù)據(jù),也就是說,真正的數(shù)據(jù)是放在一條記錄中,而多條記錄組成一個(gè)文件。根據(jù)應(yīng)用的需要,整個(gè)系統(tǒng)可以只有一個(gè)文件,也可以包含多個(gè)文件。文件采用文件ID來標(biāo)示,文件ID為2個(gè)字節(jié)(注:不能取值為0xFFFF)。一個(gè)文件下面可以放一條記錄,也可以放多條記錄,記錄是通過記錄key來標(biāo)示的,記錄key也是2個(gè)字節(jié)長度(注:不能取值為0x0000)。這里需要注意的是,同一個(gè)文件下面的兩條或者多條記錄他們的key可以是一樣的,比如我們可以建立如下文件系統(tǒng):文件1包含2條記錄,文件2包含3條記錄,文件2包含2條key為0x0003的記錄

wKgZPGghql6AIYVWAACbkRdmlVQ170.png

注:如果你可以保證一個(gè)文件下面所有記錄的key都不一樣,那么文件系統(tǒng)會(huì)變得更簡潔一些,尤其在find記錄的時(shí)候,只會(huì)返回一條記錄,可以簡化很多應(yīng)用邏輯。如前所述,這個(gè)不是強(qiáng)制要求:同一個(gè)文件下記錄key可以相同。

FDS用法

一般而言,按照如下步驟使用FDS模塊:

修改FDS的默認(rèn)配置參數(shù),比如總共分配多少Flash空間(默認(rèn)只分配了8kB Flash空間給用戶使用),請到sdk_config.h文件中修改如下默認(rèn)配置項(xiàng):

wKgZO2ghql-AeGMmAAGMYeFyRKk668.png

通過fds_register注冊FDS事件回調(diào)函數(shù)及通過fds_init初始化FDS模塊。FDS模塊的初始化,寫記錄,更新記錄,刪除記錄以及垃圾回收,這些API都是異步的。也就是說調(diào)用這些FDS操作的API,只是把相應(yīng)操作放入隊(duì)列然后立即返回(隊(duì)列大小由上述的FDS_OP_QUEUE_SIZE控制),真正的Flash操作結(jié)果是通過事件回調(diào)函數(shù)通知你的。注:現(xiàn)在的FDS模塊可以進(jìn)行多次初始化。示例代碼如下所示:

// Simple event handler to handle errors during initialization.

static void fds_evt_handler(fds_evt_t const * p_fds_evt)

{

    switch (p_fds_evt->id)

    {

        case FDS_EVT_INIT:

            if (p_fds_evt->result != FDS_SUCCESS)

            {

                // Initialization failed.

            }

            break;

        default:

            break;

    }

}

ret_code_t ret = fds_register(fds_evt_handler);

if (ret != FDS_SUCCESS)

{

    // Registering of the FDS event handler has failed.

}

ret_code_t ret = fds_init();

if (ret != FDS_SUCCESS)

{

    // Handle error.

}

通過fds_record_write創(chuàng)建新的記錄,即寫記錄。 注意寫記錄的時(shí)候,必須保證輸入?yún)?shù)是全局變量或者static的局部變量,推薦使用全局變量! 由于record key可以重復(fù),所以連續(xù)調(diào)用兩次相同的fds_record_write,將生成兩條同樣key的記錄。前面也提及過,fds_record_write是異步的,所以它的返回值為success只是表示操作入隊(duì)成功,真正的flash操作結(jié)果是通過前面注冊的fds_evt_handler來通知的。示例代碼如下所示:

#define FILE_ID         0x0001  /* The ID of the file to write the records into. */

#define RECORD_KEY_1    0x1111  /* A key for the first record. */

#define RECORD_KEY_2    0x2222  /* A key for the second record. */

static uint32_t   const m_deadbeef = 0xDEADBEEF;

static char       const m_hello[]  = "Hello, world!";

fds_record_t        record;

fds_record_desc_t   record_desc;

// Set up record.

record.file_id           = FILE_ID;

record.key               = RECORD_KEY_1;

record.data.p_data       = &m_deadbeef;

record.data.length_words = 1;   /* one word is four bytes. */

ret_code_t rc;

rc = fds_record_write(&record_desc, &record);

if (rc != FDS_SUCCESS)

{

    /* Handle error. */

}

// Set up record.

record.file_id           = FILE_ID;

record.key               = RECORD_KEY_2;

record.data.p_data       = &m_hello;

/* The following calculation takes into account any eventual remainder of the division. */

record.data.length_words = (sizeof(m_hello) + 3) / 4;

rc = fds_record_write(&record_desc, &record);

if (rc != FDS_SUCCESS)

{

    /* Handle error. */

}

通過fds_record_open來讀記錄。讀記錄之前必須先找到這條記錄,這個(gè)是通過fds_record_find來實(shí)現(xiàn)的,由于同一個(gè)文件可以包含多條key相同的記錄,所以通過多次調(diào)用同一個(gè)fds_record_find,可以找到所有相關(guān)記錄。示例代碼如下所示:

#define FILE_ID     0x1111

#define RECORD_KEY  0x2222

fds_flash_record_t  flash_record;

fds_record_desc_t   record_desc;

fds_find_token_t    ftok;

/* It is required to zero the token before first use. */

memset(&ftok, 0x00, sizeof(fds_find_token_t));

/* Loop until all records with the given key and file ID have been found. */

while (fds_record_find(FILE_ID, RECORD_KEY, &record_desc, &ftok) == FDS_SUCCESS)

{

    if (fds_record_open(&record_desc, &flash_record) != FDS_SUCCESS)

    {

        /* Handle error. */

    }

    /* Access the record through the flash_record structure. */

    /* Close the record when done. */

    if (fds_record_close(&record_desc) != FDS_SUCCESS)

    {

        /* Handle error. */

    }

}

操作記錄,比如fds_record_update,fds_record_delete等,update和delete操作,必須先找到相應(yīng)記錄,然后才能去update或者delete。fds_record_delete不是真得把記錄刪除,而是將記錄標(biāo)示為無效。而fds_record_update實(shí)際包含2步:先找到之前的記錄然后將其標(biāo)記為無效(即delete操作),然后write一條新記錄。記住:delete并不會(huì)回收Flash空間,無效記錄仍然占據(jù)著Flash空間,這些無效記錄占據(jù)著的Flash空間只有經(jīng)過垃圾回收(fds_gc)才能再次給新記錄使用。請注意fds_record_find只會(huì)去尋找有效記錄,而不會(huì)將無效記錄返回給用戶的。另外,fds_record_ update和fds_record_delete是異步的,所以它們的返回值為success只是表示操作入隊(duì)成功,真正的flash操作結(jié)果是通過前面注冊的fds_evt_handler來通知的。示例代碼如下所示:

    fds_record_desc_t desc = {0};
    fds_find_token_t  tok  = {0};
    rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
    if (rc == FDS_SUCCESS)
    {

        /* A config file is in flash. Let's update it. */
        fds_flash_record_t config = {0};

        /* Open the record and read its contents. */

        rc = fds_record_open(&desc, &config);
        APP_ERROR_CHECK(rc);

        /* Copy the configuration from flash into m_dummy_cfg. */

        memcpy(&m_dummy_cfg, config.p_data, sizeof(configuration_t));

        NRF_LOG_INFO("Config file found, updating boot count to %d.", m_dummy_cfg.boot_count);

        /* Update boot count. */
        m_dummy_cfg.boot_count++;

        /* Close the record when done reading. */

        rc = fds_record_close(&desc);
        APP_ERROR_CHECK(rc);

        /* Write the updated record to flash. */

        rc = fds_record_update(&desc, &m_dummy_record);
 if (rc == FDS_ERR_NO_SPACE_IN_FLASH) fds_gc();

         else APP_ERROR_CHECK(rc);

    }

ret_code_t ret = fds_record_delete(&desc);

if (ret != FDS_SUCCESS)

{

    /* Error. */

}

當(dāng)Flash不夠用時(shí),即FDS寫記錄或者更新記錄操作返回錯(cuò)誤FDS_ERR_NO_SPACE_IN_FLASH,請調(diào)用垃圾回收函數(shù):fds_gc進(jìn)行垃圾回收。fds_gc是一個(gè)非常耗時(shí)的操作過程(請確保操作過程中不會(huì)掉電,否則Flash行為未知),它會(huì)一個(gè)page一個(gè)page操作,然后將該page中的有效記錄拷貝到swap page,然后擦除該page,并標(biāo)記該page為swap page,而之前的swap page則變?yōu)閐ata page,如此往復(fù),直到把所有page都回收完。只有經(jīng)過fds_gc后,之前無效記錄占據(jù)的Flash空間才會(huì)釋放,這個(gè)時(shí)候才會(huì)有多余的Flash空間給用戶去操作。

建議大家直接參考SDK里面自帶的fds例子來編寫自己的fds應(yīng)用代碼,SDK自帶的fds例子所在目錄為:SDK安裝目錄examplesperipheralflash_fds (注:從SDK14之后才有fds例子)

理解FDS

FDS作為上層模塊,它是通過調(diào)用fstorage API來實(shí)現(xiàn)自己的功能,fstorage又是通過調(diào)用NVMC外設(shè)驅(qū)動(dòng)或者softdevice Flash訪問API來達(dá)到操作Flash的目的,調(diào)用關(guān)系圖如下所示:

wKgZPGghqmCAMjCyAAAiHtJ3fQg784.png

當(dāng)softdevice存在的時(shí)候,建議使用nrf_fstorage_sd后端;沒有softdevice的時(shí)候,請使用nrf_fstorage_nvmc后端。

根據(jù)有無bootloader,F(xiàn)DS將操作不同的Flash空間,如下:

wKgZO2ghqmCAXuESAAB2qcwYdO4300.png

當(dāng)你通過FDS把數(shù)據(jù)寫入Flash中,除了數(shù)據(jù)本身,F(xiàn)DS還會(huì)在這條記錄中加入額外的信息:記錄頭header,一條記錄在Flash中完整的格式如下所示:

wKgZPGghqmGAA6sMAAByStE7zKk646.png

字段 大小 描述
Record key 16 bits Key that can be used to find the record. The value FDS_RECORD_KEY_DIRTY (0x0000) is reserved by the system to flag records that have been invalidated. See Restrictions on keys and IDs for further restrictions.
Data length 16 bits Length of the data that is stored in the record (in 4-byte words).
File ID 16 bits ID of the file that the record is associated with. The value FDS_FILE_ID_INVALID (0xFFFF) is used by the system to identify records that have not been written correctly. See Restrictions on keys and IDs for further restrictions.
CRC value 16 bits CRC value of the whole record (checks can be enabled by setting the FDS_CRC_ENABLED compile flag, see Configuration).
Record ID 32 bits Unique identifier of the record. 注:對用戶不可見

所以,在計(jì)算記錄總共占用多少Flash空間的時(shí)候,記得一定要把每條記錄的header(3個(gè)word)也加上。

FDS使用常見問題

大家在使用FDS模塊時(shí),經(jīng)常碰到的問題有如下幾種:

FDS不支持掉電保護(hù),所以在Flash操作過程中出現(xiàn)了掉電,F(xiàn)DS行為將未知

OTA的時(shí)候,新固件的FDS page數(shù)目一定要等于老固件的FDS page數(shù),否則將出現(xiàn)不可知行為

fds_record_write或者fds_record_update后,強(qiáng)烈建議回讀該記錄,以確保記錄的確write或者update成功

忘了給參數(shù)清0。Nordic提供的API輸入?yún)?shù)很多都是結(jié)構(gòu)體變量,這些變量使用之前,記得一定要通過memset先清0。如果忘了清0,就會(huì)出現(xiàn)一些匪夷所思的現(xiàn)象。

fds_record_desc_t desc;  //= {0};  //錯(cuò)誤,忘了清0
fds_find_token_t  tok;  //= {0}; //錯(cuò)誤,忘了清0

忘了使用全局變量或者靜態(tài)局部變量。因?yàn)閣rite和update操作都是異步的,所以record.data.p_data必須指向全局變量或者靜態(tài)局部變量,以保證Flash操作過程中p_data指向的內(nèi)容不會(huì)更改。

變量起始地址必須字對齊。Flash操作是以word為單位的,所以要求write和update操作的p_data指向的變量的起始地址必須word對齊,大家可以使用偽匯編指令“__ALIGN(sizeof(uint32_t))”來保證該變量起始地址是word對齊的。

Update或者delete之前必須先find。fds_record_update或者fds_record_delete會(huì)用到參數(shù)descriptor,這個(gè)descriptor必須是通過fds_record_find返回的。

忘了使用fds_gc導(dǎo)致Flash fatal error或者其他奇奇怪怪的問題。當(dāng)write或者update報(bào)FDS_ERR_NO_SPACE_IN_FLASH錯(cuò)誤時(shí),記得一定要調(diào)用fds_gc。或者當(dāng)delete record或者update record達(dá)到一定次數(shù)后,主動(dòng)調(diào)用fds_gc。或者通過查看fds_stat得到dirty record數(shù)目達(dá)到某個(gè)值后,主動(dòng)調(diào)用fds_gc。

SDK已知問題。每個(gè)版本SDK都有或多或少的問題,這些問題都可以在Nordic devzone上查到。比如SDK12.2.0 fds_gc在某些情況下,就會(huì)有問題,請參考:https://devzone.nordicsemi.com/question/93241/what-are-sdk-12x0-known-issues/,所以,一般建議大家使用最新版SDK,最新版SDK會(huì)把之前發(fā)現(xiàn)的問題都修復(fù)掉,它的穩(wěn)定性和可靠性都是最高的。

最后再次強(qiáng)調(diào)一遍:FDS不支持掉電保護(hù),所以在FDS操作過程中,尤其是垃圾回收過程中,發(fā)生了掉電,那么Flash內(nèi)容將變得不可靠。所以強(qiáng)烈建議大家:在每一次write或者update之后,都把相應(yīng)記錄讀出來,跟原始內(nèi)容進(jìn)行比對,以確保記錄真的寫成功或者更新成功了

審核編輯 黃宇

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

    關(guān)注

    3

    文章

    1101

    瀏覽量

    51717
  • Nordic
    +關(guān)注

    關(guān)注

    9

    文章

    257

    瀏覽量

    49017
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

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

    針對雙bank和單bank的使用方法建議

    應(yīng)用繼續(xù)工作或重新嘗試 DFU。 有足夠 Flash 空間 需要能在應(yīng)用和應(yīng)用數(shù)據(jù)之間騰出塊足夠大的區(qū)域存放完整新鏡像。[nRF5 dual-bank 空間條件] 需要回退機(jī)制 / 版本切換策略
    發(fā)表于 02-12 10:24

    深度技術(shù)解析nRF Connect SDK裸機(jī)選項(xiàng)方案

    nRF Connect SDK的裸機(jī)選項(xiàng)基于經(jīng)過市場驗(yàn)證的SoftDevice,這是預(yù)構(gòu)建的低功耗藍(lán)牙協(xié)議堆棧,該協(xié)議堆棧為大多數(shù)nRF5 SDK用戶所熟悉,并由nrfx提供獨(dú)立于
    發(fā)表于 10-31 23:11

    使用nRF52840芯片的USB Host 功能參考例程

    Host 示例 Nordic 的 nRF5 SDK(或 nRF Connect SDK,取決于你使用的開發(fā)框架)中包含專門的 USB Host 示例,路徑通常如下:
    發(fā)表于 10-31 12:47

    深度技術(shù)解析低功耗藍(lán)牙廠商nordic的nRF Connect SDK裸機(jī)選項(xiàng)方案

    : 基于nRF54L系列的裸機(jī)選項(xiàng)低功耗藍(lán)牙開發(fā) SoftDevice S115 僅支持外設(shè)角色,最多支持2個(gè)連接 與最新nRF5 SDK SoftDevice (v17)采用相同AP
    發(fā)表于 10-29 21:17

    nRF Connect SDK Basic

    用戶在使用 nRF connect SDK 的時(shí)候經(jīng)常會(huì)操作的外設(shè)有GPIO,I2C,SPI,UART。我們就以 nRF connect SDK 2.7.0 中的例程代碼
    的頭像 發(fā)表于 08-20 10:41 ?819次閱讀
    <b class='flag-5'>nRF</b> Connect <b class='flag-5'>SDK</b> Basic

    Nordic nRF5 SDK和softdevice介紹

    Connect SDK般來說,開發(fā)nRF51/52產(chǎn)品推薦使用nRF5 SDK,開發(fā)nRF
    的頭像 發(fā)表于 08-20 09:54 ?3086次閱讀
    Nordic <b class='flag-5'>nRF5</b> <b class='flag-5'>SDK</b>和softdevice介紹

    ZYNQ UltraScalePlus RFSOC QSPI Flash固化常見問題說明

    璞致 ZYNQ UltraScalePlus RFSOC QSPI Flash 固化常見問題說明
    發(fā)表于 08-08 15:49 ?0次下載

    如何調(diào)試nRF5 SDK

    本文將講述Nordic nRF5 SDK的主要調(diào)試手段,以幫助大家快速定位問題,并解決問題。般來說,你可以通過打log方式,IDE的debug模式,SDK自帶的app_error_c
    的頭像 發(fā)表于 06-24 08:59 ?1006次閱讀
    如何調(diào)試<b class='flag-5'>nRF5</b> <b class='flag-5'>SDK</b>

    nRF5 SDK軟件架構(gòu)及softdevice工作原理

    SDK,建議先看下這篇文章“Nordic nRF5 SDK和softdevice介紹”,以建立Nordic nRF5
    的頭像 發(fā)表于 06-23 11:08 ?694次閱讀
    <b class='flag-5'>nRF5</b> <b class='flag-5'>SDK</b>軟件架構(gòu)及softdevice工作原理

    Nordic nRF51/nRF52開發(fā)流程說明

    51422/nRF51802等芯片,開發(fā)者可以按照如下流程去評估和開發(fā)nRF52/51應(yīng)用解決方案。 如果你英文比較好的話,建議直接閱讀Nordic官方的“nRF5 Getting Started”:https
    的頭像 發(fā)表于 06-17 14:25 ?1489次閱讀
    Nordic <b class='flag-5'>nRF</b>51/<b class='flag-5'>nRF</b>52開發(fā)流程說明

    定時(shí)模塊app_timer用法常見問題nRF5 SDK模塊系列

    app_timer是大家經(jīng)常用到的個(gè)庫,app_timer的功能就是定時(shí),也就是說,你在某時(shí)刻啟動(dòng)個(gè)app timer并設(shè)定超時(shí)時(shí)間,超時(shí)時(shí)間到,app_timer就會(huì)回調(diào)ti
    的頭像 發(fā)表于 05-12 16:13 ?806次閱讀
    定時(shí)<b class='flag-5'>模塊</b>app_timer<b class='flag-5'>用法</b>及<b class='flag-5'>常見問題</b>—<b class='flag-5'>nRF5</b> <b class='flag-5'>SDK</b><b class='flag-5'>模塊</b><b class='flag-5'>系列</b>二

    nRF Connect SDK(NCS)/Zephyr固件升級詳解 – 重點(diǎn)講述MCUboot和藍(lán)牙空中升級

    編碼如何解讀?NCS可不可以進(jìn)行單bank升級?可不可以把個(gè)nRF5 SDK應(yīng)用升級到NCS應(yīng)用?MCUboot拷貝操作中的swap和overwrite有什么區(qū)別?為什么說MCUboot升級永遠(yuǎn)都不
    的頭像 發(fā)表于 05-09 14:14 ?3594次閱讀
    <b class='flag-5'>nRF</b> Connect <b class='flag-5'>SDK</b>(NCS)/Zephyr固件升級詳解 – 重點(diǎn)講述MCUboot和藍(lán)牙空中升級

    如何調(diào)試nRF5 SDK

    本文將講述Nordic nRF5 SDK的主要調(diào)試手段,以幫助大家快速定位問題,并解決問題。般來說,你可以通過打log方式,IDE的debug模式,SDK自帶的app_error_c
    發(fā)表于 04-26 23:13

    關(guān)于功率模塊冷卻的六個(gè)常見問題

    的壽命并使其發(fā)揮最佳性能。本文章將概述在為應(yīng)用設(shè)計(jì)功率模塊時(shí)可能出現(xiàn)的關(guān)于功率模塊冷卻的六個(gè)常見問題。1.器件溫度是否均勻?功率晶體管和二極管等功率元器件會(huì)產(chǎn)生局部熱
    的頭像 發(fā)表于 04-08 11:42 ?756次閱讀
    關(guān)于功率<b class='flag-5'>模塊</b>冷卻的六個(gè)<b class='flag-5'>常見問題</b>

    藍(lán)牙模塊PTR5618性能、開發(fā)與應(yīng)用解析

    J-Link驅(qū)動(dòng)?。 優(yōu)先選擇Nordic官方SDKnRF5 SDK)進(jìn)行底層開發(fā)?。 ?六、互動(dòng)討論? ?話題:你在PTR5618開發(fā)中遇到過哪些挑戰(zhàn)?歡迎分享優(yōu)化方案或替代型號推薦!? ?聲明:? 本文
    發(fā)表于 03-12 14:32