Nordic--nrf52832--FDS(一)基本介紹

FDS(Flash Data Storage 模塊是sdk中提供的操作flash的模塊。

前面介紹過fs(Flash Storage)模塊,這個模塊也是sdk中提供的操作flash的模塊。爲什麼要提供兩個呢?

 這需要了解一下關於flash操作的問題。 因爲操作的是片上flash,所以在擦寫flash的時候CPU會暫停,這對於ble來說很可能影響底層的鏈路上的時序。所以對於ble應用來說,不能通過flash相關的寄存器來直接操作flash,因爲你不知道你操作的時機對不對會不會對ble協議的底層交互時序造成影響。所以nordic協議棧封裝了flash操作,對外提供了flash操作的接口,形如sd_flash_write 所以對於ble應用來說,我們能操作的最底層函數api就是sd開頭的flash操作函數,這些sd開頭的flash操作函數是異步的,即調用後不會立刻就操作flash,底層協議棧會在合適的時候,不影響或說不至於影響到ble的正常連接的時候纔會實際去執行flash操作。操作結束後協議棧再拋出底層事件,告訴你flash操作的結果。

 底層函數畢竟需要了解一些nordic協議棧的機制,以及flash操作的方式。所以nordic提供的sdk,在這些sd開頭的底層函數上封裝了一層來方便用戶使用。即fs(Flash Storage)模塊,這個模塊封裝了底層sd開頭的API的調用以及協議棧返回的flash操作完成事件的處理。

 開發者只需要註冊自己的回調函數,調用初始化函數,之後就直接調用可以讀/寫/擦除操作來操作flash了,而不需要注意和底層flash的事件的交互,flash執行真正完成時會自動調用註冊的回調函數。

只是fs封裝後提供的操作接口還是保留了flash操作的特性—flash必須是要先擦除後才能寫。

這就導致了還是有一定的不便性,想更新一些數據的時候,你得先把flash數據讀出來,然後修改,擦除flash最後再寫回flash。

關於fs 模塊這裏不再多介紹,之前的fs幾篇文章已經詳細描述了fs相關原理和操作。

 綜上爲了解決fs的不便性,sdk又在fs的基礎又封裝了一層。形成了FDS,FDS的好處就是不僅屏蔽了和底層協議棧的事件交互(以爲他依賴fs),同時也封裝了更新這樣的操作。Fds幫用戶處理好了flash的更新,而不需要自己再去擦除flash再重寫。 當然fds還提供了其他方便的特性,比如抽象了文件和記錄的概念。這對上層的一些數據的組織提供了方便。比如你要存一個學校的學生記錄,可以將一個班級的學生file ID設置相同,record id來區分不同的學生。

 PS:那爲什麼還需要fs?直接提供一個fds不就可以了? 因爲你不能限定別人的使用方式,FDS的操作方便,那就引入了一定的侷限性。如果操作方式,數據格式等。當然封裝的層次越多,速度上也會稍慢一點。 Fs雖然有一些不便性,但是相對更靈活。當然最靈活的還是協議棧直接開放的api SD開頭的flash操作函數。 即sdk提供了3中大類的flash操作方式,操作約方便操作的方式約受限。所以爲了滿足不同的可能的需求,所以sdk纔將這三種操作flash的方式都提供出來。

我們畫一下FDS,FS以及 協議棧提供的flash操作API的關係,方便後面理解。

在這裏插入圖片描述
在這裏插入圖片描述
下面詳細介紹FDS相關的一些原理和操作。

 FDS將對flash操作抽象成了類似PC上的對文件的操作。抽象出了file ID和record ID這兩個概念。 第一次寫flash時也同時是這個寫數據的創建的時候,所以需要設置file id和record key

Fds組織的數據在flash上以記錄的形式組織,實際存儲結構如下圖:
在這裏插入圖片描述
File IDrecord key 是我們使用FDS時需要使用的。對於開發者來說file id和record用來標識一個記錄。在第一次將這個記錄寫入flash時必須指定。FDS並沒有要求file id和record key的唯一性。也就是你可以創建幾個記錄,他們的file id和record key都指定相同都不會有問題。

record key 不能設置爲0x0000,0x0000表示該record是無效的。File ID不能設置爲0xFFFF,0xFFFF標識無效的file id。

 因爲FDS並沒有限制file id和record key的唯一性,那麼如果使用的場景中的確需要有幾個記錄有同樣的file id和record key,那麼當想刪除這幾個記錄怎麼辦?所以FDS內部維護了record id,該字段就是每個記錄再flash中的唯一標識,由FDS模塊內部維護。不需要開發者操作。當刪除幾個file id和record key都相同的記錄時,需要開發者自己調用函數 枚舉找到這幾個記錄,雖然每次查找時傳入的file id 和record key都一樣,但是fds返回的記錄描述符中的record id是不同的。再依次使用該返回的描述符就可以正確刪除這些同樣file id和record key的記錄了。

 前面介紹了FDS相對於FS來說更方便了開發者的調用,因爲它封裝了更新flash的函數接口,想更新某個記錄的數據可以直接調用fds_record_update 函數即可。FDS的內部實現對於update操作也很快。因爲FDS的更新操作並不是真的更新這個舊的數據塊,以前的舊SDK比如SDK9,更新一個數據會先將數據塊讀取出來保存到交換區,再更新數據,最後將交換區數據寫回。 FDS的實現,不會做這些操作。FDS更新數據時,直接當成一個寫操作,它會找到flash中沒用的空間,然後寫入這個更新的數據內容。最後直接將舊的數據塊的 record key設置成髒數據標記0x0000,標識改記錄無效的。所以FDS的更新操作相對以前舊的SDK很快。

 同理刪除操作的原理也是一樣,並不是真正的擦掉flash中的數據而是直接將數據塊的record key

 需要注意的是工程中並不是可以任意使用file id和record key。除了前面說的record key =0x0000標識該記錄無效,file id=0xffff標識無效外如果工程中存在 Peer Manager.模塊,那麼record key只能使用0x0001 - 0xBFFF.0xC000 to 0xFFFF是PM模塊內部使用的,因爲PM模塊內部也會使用FDS進行flash操作。 File id只能使用0x0000 - 0xBFFF. 0xC000 to 0xFFFE也是PM模塊使用了。

一些宏的介紹

FDS模塊內部又很多宏都是可配置的,開發者可以更具自己實際情況配置。一般這些宏都是在sdk_config.h 配置文件中。

  • FDS_OP_QUEUE_SIZE: 設置flash操作隊列的大小,flash操作都是異步的,所以調用fds提供api時,其內部實際都是放入一個操作隊列然後一個個執行。所以如果應用中可能有一些地方不會等待flash操作返回結果就調用多次fds的flash操作接口,那麼可能需要適當增大該宏的大小。否則可能因爲隊列中緩存了太多flash操作而導致新調用fds的api時返回FDS_ERR_NO_SPACE_IN_QUEUES的錯誤。

  • FDS_CHUNK_QUEUE_SIZE:設置允許緩存的記錄的塊的個數。這裏的緩存並不是緩存內容而是緩存的地址,同樣如果fds經常返回FDS_ERR_NO_SPACE_IN_QUEUES錯誤時,也可嘗試增大該宏大小

  • FDS_VIRTUAL_PAGE_SIZE: FDS模塊層面的虛擬頁的大小。通常就是物理頁大小不需要改。如果應用中的一個記錄大小超過該大小,這裏需要修改增大。

  • FDS_VIRTUAL_PAGES: 定義了虛擬頁的個數,通常也不需要修改。如果存儲的總數據量比較大,則需要適當增大。

  • FDS_MAX_USERS: 回調函數最大可註冊數。可能有不同的模塊都需要存儲自己的Flash數據,所以每個模塊都需要註冊自己的flash回調函數。

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