NRF52832學(xué)習(xí)筆記(14)——Flash接口使用(FStorage方式)

一、背景

NRF52832 內(nèi)部 Flash 的存儲(chǔ)官方提供了兩種方式钮蛛,一種是 FStorage 方式洒忧,另一種是在 FStorage 基礎(chǔ)上的 FDS 方式。

1.1 FStorage方式

FStorage 是一個(gè)用于讀取咏尝、寫(xiě)入和擦除持久閃存中數(shù)據(jù)的模塊。該模塊定義了一個(gè)異步接口來(lái)訪(fǎng)問(wèn)閃存啸罢,并使用 讀编检、寫(xiě)和(page)擦除 操作。通過(guò)對(duì)注冊(cè)事件處理程序的回調(diào)扰才,通知應(yīng)用程序的操作結(jié)果允懂。

FStorage 方式是一個(gè)低級(jí)庫(kù),旨在為閃存提供一個(gè)簡(jiǎn)單的衩匣、原始的接口蕾总。如果需要一個(gè)具有 更新粥航、搜索 功能的更高級(jí)別 API 來(lái)存儲(chǔ)記錄和文件,可以看第二種方式 FDS 數(shù)據(jù)存儲(chǔ)方式生百。

1.2 Flash區(qū)域

FStorage 方式不保證不同的存儲(chǔ)應(yīng)用實(shí)例在非重疊的閃存區(qū)域上運(yùn)行递雀,因此需要用戶(hù)自己確保對(duì)該區(qū)域的使用不會(huì)影響其他功能,也就是說(shuō)用戶(hù)自己保證不將數(shù)據(jù)內(nèi)容疊加到同個(gè)區(qū)域進(jìn)行存儲(chǔ)置侍。

下圖提供了關(guān)于 Flash 中存儲(chǔ)數(shù)據(jù)的 SDK 模塊使用了芯片上的 Flash 區(qū)域情況映之。


1.3 注意

當(dāng)程序運(yùn)行了藍(lán)牙協(xié)議棧拦焚,F(xiàn)lash 操作的成功與協(xié)議的時(shí)間限制和硬件的特性聯(lián)系在一起蜡坊。使用過(guò)于激進(jìn)的掃描或廣播間隔,或運(yùn)行多個(gè)連接赎败,會(huì)影響 Flash 操作的成功秕衙。

在大多數(shù)情況下,nrf_storage_sd 將在沒(méi)有問(wèn)題的情況下與無(wú)線(xiàn)電協(xié)議同時(shí)處理 Flash 操作僵刮。如果出現(xiàn)超時(shí)錯(cuò)誤据忘,請(qǐng)嘗試減少正在寫(xiě)入的數(shù)據(jù)大小(在一個(gè) nrf_storage_write 調(diào)用中)搞糕。否則勇吊,嘗試修改 nrf_storage_max_write_size 和增量 nrf_storage_max 重試。如果問(wèn)題仍然存在窍仰,請(qǐng)參考軟件規(guī)范文檔來(lái)確定更合適的掃描和廣播間隔汉规。

二、移植文件

注意:以下出現(xiàn)缺失common.h文件錯(cuò)誤驹吮,去除即可针史。uint8改為uint8_t或unsigned char或自己宏定義
鏈接:https://pan.baidu.com/s/1rWA9cKgN4XFTb9y6VEpkDQ 提取碼:e7lk
board_flash_fstorage.cboard_flash_fstorage.h 兩個(gè)文件加入工程的Application文件夾下


2.1 board_flash_fstorage.c

/*********************************************************************
 * INCLUDES
 */
#include "nrf_fstorage.h"
#include "nrf_fstorage_sd.h"
#include "nrf_soc.h"
#include "nrf_log.h"
#include "app_error.h"

#include "board_flash.h"

static void fstorageCallbackFunc(nrf_fstorage_evt_t *pFstorageEvent);
static uint32 getflashEndAddress(void);
static void waitForFlashReady(nrf_fstorage_t const *pFstorageHandle);

/*********************************************************************
 * LOCAL VARIABLES
 */
NRF_FSTORAGE_DEF(nrf_fstorage_t s_fstorageHandle) =
{
    /* Set a handler for fstorage events. */
    .evt_handler = fstorageCallbackFunc,

    /* These below are the boundaries of the flash space assigned to this instance of fstorage.
     * You must set these manually, even at runtime, before nrf_fstorage_init() is called.
     * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
     * last page of flash available to write data. */
    .start_addr = 0x3e000,
    .end_addr   = 0x3ffff,
};

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief Fstorage讀寫(xiě)內(nèi)存初始化
 @param 無(wú)
 @return 無(wú)
*/
void Fstorage_FlashInit(void)
{
    ret_code_t errCode;

    nrf_fstorage_api_t *pFstorageApi;
    pFstorageApi = &nrf_fstorage_sd;
    
    errCode = nrf_fstorage_init(&s_fstorageHandle, pFstorageApi, NULL);                 // Flash處理的開(kāi)始地址和結(jié)束地址初始化
    APP_ERROR_CHECK(errCode);
    
    (void)getflashEndAddress();                                                         // 獲取地址,判斷為可寫(xiě)地址大小
}

/**
 @brief Fstorage讀寫(xiě)內(nèi)存操作
 @param flashAddr -[in] 閃存地址
 @param readWriteFlag -[in] 讀寫(xiě)操作標(biāo)志
 @param pData -[in&out] 指向需要操作的數(shù)據(jù)
 @param dataLen -[in] 數(shù)據(jù)長(zhǎng)度
 @return 無(wú)
*/
void Fstorage_FlashContrl(uint32 flashAddr, uint8 readWriteFlag, uint32 *pData, uint8 dataLen)
{
    ret_code_t errCode;
    
    if(readWriteFlag == FSTORAGE_READ)                                                  // 讀取數(shù)據(jù)
    {
        errCode = nrf_fstorage_read(&s_fstorageHandle, flashAddr, pData, dataLen);
        APP_ERROR_CHECK(errCode);
    }
    else                                                                                // 寫(xiě)入數(shù)據(jù)
    {
        errCode = nrf_fstorage_erase(&s_fstorageHandle, flashAddr, 1, NULL);            // 只能寫(xiě)入位值1碟狞,不能寫(xiě)入位值0啄枕,所以先擦后寫(xiě)       
        errCode = nrf_fstorage_write(&s_fstorageHandle, flashAddr, pData, dataLen, NULL);
        APP_ERROR_CHECK(errCode);
        
        waitForFlashReady(&s_fstorageHandle);                                           // 等待寫(xiě)完
    }
}


/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief Fstorage事件回調(diào)函數(shù)
 @param pFstorageEvent -[in] Fstorage事件
 @return 無(wú)
*/
static void fstorageCallbackFunc(nrf_fstorage_evt_t *pFstorageEvent)
{
    if(pFstorageEvent->result != NRF_SUCCESS)
    {
        NRF_LOG_INFO("--> Event received: ERROR while executing an fstorage operation.");
        return ;
    }

    switch(pFstorageEvent->id)
    {
    case NRF_FSTORAGE_EVT_WRITE_RESULT:
        NRF_LOG_INFO("--> Event received: wrote %d bytes at address 0x%x.", pFstorageEvent->len, pFstorageEvent->addr);
        break;

    case NRF_FSTORAGE_EVT_ERASE_RESULT:
        NRF_LOG_INFO("--> Event received: erased %d page from address 0x%x.", pFstorageEvent->len, pFstorageEvent->addr);
        break;

    default:
        break;
    }
}

/**
 @brief 檢索Flash上可用于寫(xiě)入數(shù)據(jù)的地址
 @param 無(wú)
 @return 無(wú)
*/
static uint32 getflashEndAddress(void)
{
    uint32 const bootloaderAddr = NRF_UICR->NRFFW[0];
    uint32 const pageSz         = NRF_FICR->CODEPAGESIZE;
    uint32 const codeSz         = NRF_FICR->CODESIZE;

    return (bootloaderAddr != 0xFFFFFFFF ? bootloaderAddr : (codeSz * pageSz));
}

/**
 @brief 等待寫(xiě)入完成
 @param pFstorageHandle -[in] Fstorage句柄
 @return 無(wú)
*/
static void waitForFlashReady(nrf_fstorage_t const *pFstorageHandle)
{
    while(nrf_fstorage_is_busy(pFstorageHandle))                                        // While fstorage is busy, sleep and wait for an event.
    {
       sd_app_evt_wait();
    }
}

/****************************************************END OF FILE****************************************************/

2.2 board_flash_fstorage.h

#ifndef _BOARD_FLASH_H_
#define _BOARD_FLASH_H_

/*********************************************************************
 * INCLUDES
 */
#include "common.h"

/*********************************************************************
 * DEFINITIONS
 */
#define FSTORAGE_READ               0x00
#define FSTORAGE_WRITE              0x01

#define CUSTOM_FSTORAGE_ADDR        0x3e000

/*********************************************************************
 * API FUNCTIONS
 */
void Fstorage_FlashInit(void);
void Fstorage_FlashContrl(uint32 flashAddr, uint8 readWriteFlag, uint32 *pData, uint8 dataLen);

#endif /* _BOARD_FLASH_H_ */

三、API調(diào)用

需包含頭文件 board_flash_fstorage.h

Fstorage_FlashInit

功能 初始化Flash讀寫(xiě)模塊
函數(shù)定義 void Fstorage_FlashInit(void)
參數(shù) 無(wú)
返回 無(wú)

Fstorage_FlashContrl

功能 Flash讀寫(xiě)操作
函數(shù)定義 void Fstorage_FlashContrl(uint32 flashAddr, uint8 readWriteFlag, uint32 *pData, uint8 dataLen)
參數(shù) flashAddr:進(jìn)行讀寫(xiě)的地址
readWriteFlag:讀寫(xiě)標(biāo)記族沃,0-讀频祝,1-寫(xiě)
pData:讀寫(xiě)的數(shù)據(jù)
dataLen:寫(xiě)入數(shù)據(jù)長(zhǎng)度
返回 無(wú)

四、使用例子

1)添加頭文件

#include "board_flash_fstorage.h"

2)添加初始化代碼(SDK15.3 中 ble_peripheral 的 ble_app_template 工程 main() 函數(shù)中)
加入 Fstorage_FlashInit()

int main(void)
{
    bool erase_bonds;

    /*-------------------------- 外設(shè)驅(qū)動(dòng)初始化 ---------------------------*/
    // Initialize.
    log_init();                                                                 // 日志驅(qū)動(dòng)初始化                                                                  
    timers_init();                                                              // 定時(shí)器驅(qū)動(dòng)初始化(在此加入自定義定時(shí)器)
    Fstorage_FlashInit();                                                       // 初始化Flash讀寫(xiě)模塊 
    
    /*-------------------------- 藍(lán)牙協(xié)議棧初始化 ---------------------------*/
    power_management_init();
    ble_stack_init();                                                           // 協(xié)議棧初始化
    gap_params_init();
    gatt_init();
    advertising_init();                                                         // 廣播初始化
    services_init();                                                            // 服務(wù)初始化
    conn_params_init();                                                         // 連接參數(shù)初始化
    peer_manager_init();
    
    /*-------------------------- 開(kāi)啟應(yīng)用 ---------------------------*/
    // Start execution.
    NRF_LOG_INFO("Template example started."); 
    advertising_start(erase_bonds);                                             // 開(kāi)啟廣播 
    application_timers_start();                                                 // 定時(shí)器應(yīng)用開(kāi)啟(在此開(kāi)啟自定義定時(shí)器)  
    Fstorage_FlashContrl(CUSTOM_FSTORAGE_ADDR, FSTORAGE_READ, (uint32 *) &s_totalConfigData, sizeof(s_totalConfigData));

    // Enter main loop.
    for(;;)
    {
        idle_state_handle();
    }
}

3)在開(kāi)啟應(yīng)用部分 讀取數(shù)據(jù)

/*-------------------------- 開(kāi)啟應(yīng)用 ---------------------------*/
// Start execution.
Fstorage_FlashContrl(CUSTOM_FSTORAGE_ADDR, FSTORAGE_READ, (uint32 *) &s_totalConfigData, sizeof(s_totalConfigData));
advertising_start(erase_bonds);                                             // 開(kāi)啟廣播 
application_timers_start();                                                 // 定時(shí)器應(yīng)用開(kāi)啟(在此開(kāi)啟自定義定時(shí)器)

? 由 Leung 寫(xiě)于 2020 年 2 月 28 日

? 參考:青風(fēng)電子社區(qū)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脆淹,一起剝皮案震驚了整個(gè)濱河市智润,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌未辆,老刑警劉巖窟绷,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異咐柜,居然都是意外死亡兼蜈,警方通過(guò)查閱死者的電腦和手機(jī)攘残,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)为狸,“玉大人歼郭,你說(shuō)我怎么就攤上這事》簦” “怎么了病曾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)漾根。 經(jīng)常有香客問(wèn)我泰涂,道長(zhǎng),這世上最難降的妖魔是什么辐怕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任逼蒙,我火速辦了婚禮,結(jié)果婚禮上寄疏,老公的妹妹穿的比我還像新娘是牢。我一直安慰自己,他們只是感情好陕截,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布驳棱。 她就那樣靜靜地躺著,像睡著了一般农曲。 火紅的嫁衣襯著肌膚如雪社搅。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天朋蔫,我揣著相機(jī)與錄音罚渐,去河邊找鬼。 笑死驯妄,一個(gè)胖子當(dāng)著我的面吹牛荷并,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播青扔,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼源织,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了微猖?” 一聲冷哼從身側(cè)響起谈息,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凛剥,沒(méi)想到半個(gè)月后侠仇,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年逻炊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了互亮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡余素,死狀恐怖豹休,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桨吊,我是刑警寧澤威根,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站视乐,受9級(jí)特大地震影響洛搀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜炊林,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一姥卢、第九天 我趴在偏房一處隱蔽的房頂上張望卷要。 院中可真熱鬧渣聚,春花似錦、人聲如沸僧叉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瓶堕。三九已至隘道,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郎笆,已是汗流浹背谭梗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宛蚓,地道東北人激捏。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像凄吏,于是被迫代替她去往敵國(guó)和親远舅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容