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

一、背景

NRF52832 內部 Flash 的存儲官方提供了兩種方式,一種是 FStorage 方式,另一種是在 FStorage 基礎上的 FDS 方式。

1.1 FStorage方式

FStorage 是一個用於讀取、寫入和擦除持久閃存中數據的模塊。該模塊定義了一個異步接口來訪問閃存,並使用 讀、寫和(page)擦除 操作。通過對註冊事件處理程序的回調,通知應用程序的操作結果。

FStorage 方式是一個低級庫,旨在爲閃存提供一個簡單的、原始的接口。如果需要一個具有 更新、搜索 功能的更高級別 API 來存儲記錄和文件,可以看第二種方式 FDS 數據存儲方式。

1.2 Flash區域

FStorage 方式不保證不同的存儲應用實例在非重疊的閃存區域上運行,因此需要用戶自己確保對該區域的使用不會影響其他功能,也就是說用戶自己保證不將數據內容疊加到同個區域進行存儲。

下圖提供了關於 Flash 中存儲數據的 SDK 模塊使用了芯片上的 Flash 區域情況。

1.3 注意

當程序運行了藍牙協議棧,Flash 操作的成功與協議的時間限制和硬件的特性聯繫在一起。使用過於激進的掃描或廣播間隔,或運行多個連接,會影響 Flash 操作的成功。

在大多數情況下,nrf_storage_sd 將在沒有問題的情況下與無線電協議同時處理 Flash 操作。如果出現超時錯誤,請嘗試減少正在寫入的數據大小(在一個 nrf_storage_write 調用中)。否則,嘗試修改 nrf_storage_max_write_size 和增量 nrf_storage_max 重試。如果問題仍然存在,請參考軟件規範文檔來確定更合適的掃描和廣播間隔。

二、移植文件

注意:以下出現缺失common.h文件錯誤,去除即可。uint8改爲uint8_t或unsigned char或自己宏定義
鏈接:https://pan.baidu.com/s/1rWA9cKgN4XFTb9y6VEpkDQ 提取碼:e7lk
board_flash_fstorage.cboard_flash_fstorage.h 兩個文件加入工程的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讀寫內存初始化
 @param 無
 @return 無
*/
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處理的開始地址和結束地址初始化
	APP_ERROR_CHECK(errCode);
	
	(void)getflashEndAddress();															// 獲取地址,判斷爲可寫地址大小
}

/**
 @brief Fstorage讀寫內存操作
 @param flashAddr -[in] 閃存地址
 @param readWriteFlag -[in] 讀寫操作標誌
 @param pData -[in&out] 指向需要操作的數據
 @param dataLen -[in] 數據長度
 @return 無
*/
void Fstorage_FlashContrl(uint32 flashAddr, uint8 readWriteFlag, uint32 *pData, uint8 dataLen)
{
	ret_code_t errCode;
	
    if(readWriteFlag == FSTORAGE_READ)                       							// 讀取數據
    {
		errCode = nrf_fstorage_read(&s_fstorageHandle, flashAddr, pData, dataLen);
		APP_ERROR_CHECK(errCode);
    }
    else 																				// 寫入數據
    {
		errCode = nrf_fstorage_erase(&s_fstorageHandle, flashAddr, 1, NULL);			// 只能寫入位值1,不能寫入位值0,所以先擦後寫		
        errCode = nrf_fstorage_write(&s_fstorageHandle, flashAddr, pData, dataLen, NULL);
		APP_ERROR_CHECK(errCode);
		
		waitForFlashReady(&s_fstorageHandle);											// 等待寫完
    }
}


/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief Fstorage事件回調函數
 @param pFstorageEvent -[in] Fstorage事件
 @return 無
*/
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上可用於寫入數據的地址
 @param 無
 @return 無
*/
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 等待寫入完成
 @param pFstorageHandle -[in] Fstorage句柄
 @return 無
*/
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調用

需包含頭文件 board_flash_fstorage.h

Fstorage_FlashInit

功能 初始化Flash讀寫模塊
函數定義 void Fstorage_FlashInit(void)
參數
返回

Fstorage_FlashContrl

功能 Flash讀寫操作
函數定義 void Fstorage_FlashContrl(uint32 flashAddr, uint8 readWriteFlag, uint32 *pData, uint8 dataLen)
參數 flashAddr:進行讀寫的地址
readWriteFlag:讀寫標記,0-讀,1-寫
pData:讀寫的數據
dataLen:寫入數據長度
返回

四、使用例子

1)添加頭文件

#include "board_flash_fstorage.h"

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

int main(void)
{
	bool erase_bonds;

    /*-------------------------- 外設驅動初始化 ---------------------------*/
	// Initialize.
    log_init();																	// 日誌驅動初始化																	
    timers_init();																// 定時器驅動初始化(在此加入自定義定時器)
	Fstorage_FlashInit();														// 初始化Flash讀寫模塊	
	
	/*-------------------------- 藍牙協議棧初始化 ---------------------------*/
    power_management_init();
    ble_stack_init();															// 協議棧初始化
    gap_params_init();
    gatt_init();
    advertising_init();															// 廣播初始化
    services_init();															// 服務初始化
    conn_params_init();															// 連接參數初始化
    peer_manager_init();
	
	/*-------------------------- 開啓應用 ---------------------------*/
	// Start execution.
    NRF_LOG_INFO("Template example started."); 
    advertising_start(erase_bonds);												// 開啓廣播	
	application_timers_start();													// 定時器應用開啓(在此開啓自定義定時器)	
	Fstorage_FlashContrl(CUSTOM_FSTORAGE_ADDR, FSTORAGE_READ, (uint32 *) &s_totalConfigData, sizeof(s_totalConfigData));

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

3)在開啓應用部分 讀取數據

/*-------------------------- 開啓應用 ---------------------------*/
// Start execution.
Fstorage_FlashContrl(CUSTOM_FSTORAGE_ADDR, FSTORAGE_READ, (uint32 *) &s_totalConfigData, sizeof(s_totalConfigData));
advertising_start(erase_bonds);												// 開啓廣播	
application_timers_start();													// 定時器應用開啓(在此開啓自定義定時器)

• 由 Leung 寫於 2020 年 2 月 28 日

• 參考:青風電子社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章