1. 程式人生 > >ESP8266學習筆記(2)——Flash讀寫

ESP8266學習筆記(2)——Flash讀寫

一、儲存晶片W25Q系列

w25q 系列生產的加工的商家很多,但是裡面的分佈和命名規則都是一樣的。比如華邦的w25q64,spi通訊介面,64就是指 64Mbit 也就是 8M 的容量。而我們平時的8266-12f的 32Mbit 就是 4M 容量。

w25q32 為例,裡面的儲存分佈。w25q32把4M容量分為了 64 塊,每一塊又分為 16 個扇區,而每個扇區佔 4K 大小。

由此可計算到,w25q32有 32Mbit / 8 * 1024 / 16 / 4 = 64 塊 ,有 64 * 16 = 1024 個扇區。

注:1B=8 Bit ,1KB=1024B ,1MB=1024KB

二、ESP8266記憶體分佈

程式區:程式碼編譯生成的 bin 檔案,燒錄到 Flash 佔用的區域,請勿改寫

系統引數區: esp_iot_sdk 中底層用於存放系統引數的區域,請勿改寫

使用者引數區:上層應用程式儲存使用者引數的區域。開發者請根據實際使用的 Flash size 設定,可以參考文件“2A-ESP8266__IOT_SDK_User_Manual” 中的 “Flash Map” 文章。

2.1 Non-FOTA

2.2 FOTA

更多圖檢視:

三、Flash讀寫介面

3.1 spi_flash_erase_sector

3.2 spi_flash_write

注意:

    • Flash 請先擦再寫。

    • Flash 讀寫必須 4 位元組對齊。

示例程式碼:

#define N 0x7C

uint32 data[M];

spi_flash_erase_sector (N);

spi_flash_write (N*4*1024, data, M*4);

3.3 spi_flash_read

3.4 system_param_save_with_protect

3.5 system_param_load

四、Flash讀防寫

4.1 Espressif Flash讀防寫示例

4.1.1 實現原理

Espressif Flash 讀防寫示例,使用三個 sector(扇區)實現(每 sector 4KB),提供 4KB 的可 靠儲存空間。 將 sector 1 和 sector 2 作為資料 sector,輪流讀寫,始終分別存放“本次”資料和“前一次”資料, 確保了至少有一份資料儲存安全; sector 3 作為 flag sector,標誌最新的資料儲存 sector。

保護機制如下:

1. 初始上電時,資料儲存在 sector 2 中,從 sector 2 中將資料讀到 RAM。

2. 第一次寫資料時,將資料寫入 sector 1。 此時若突然掉電, sector 1寫入失敗, sector 2 & 3資料未改變;重新上電時,仍是從 sector 2 中 讀取資料,不影響使用。

3. 改寫 sector 3,將標誌置為 0,表示資料存於 sector 1。 此時若突然掉電, sector 3 寫入失敗, sector 1 & 2 均存有一份完整資料;重新上電時,因 sector 3 無有效 flag,預設從 sector 2 中讀取資料,則仍能正常使用,只是未能包含掉電前對 sector 1 寫入的資料。

4. 再一次寫資料時,先從 sector 3 讀取 flag,若 flag 為0,則上次資料存於 sector 1,此次應將資料寫入 sector 2;若 flag 為非 0,則認為上次資料存於 sector 2,此次應將資料寫入 sector 1。 此時若寫資料出錯,請參考步驟 2、 3的說明,同理。

5. 寫入 sector 1(或 sector 2)完成後,才會寫 sector 3,重置 flag。

注意: 只有資料扇區(sector 1或 sector 2)寫完之後,才會寫 flag sector(sector 3),這樣即使 flag sector 寫入出錯,兩個資料扇區都已存有完整資料內容,目前預設會讀取 sector 2。

4.1.2 軟體示例

在 IOT_Demo 中,使用 0x3C000 開始的 4 個 sector(每 sector 4KB),作為使用者引數儲存區。 其中 0x3D000、 0x3E000、 0x3F000 這 3 個 sector 實現了讀防寫的功能,並存儲了應用級引數 esp_platform_saved_param

圖中“有讀防寫的儲存區”, IOT_Demo 中建議呼叫 system_param_loadsystem_param_save_with_protect 進行讀寫。

system_param_load - 讀 Flash 使用者引數區資料

system_param_save_with_protect - 寫 Flash 使用者引數區資料

引數 struct esp_platform_saved_param 定義了目前樂鑫儲存於 Flash 的使用者應用級資料,使用者只需將自己要儲存的資料新增到結構體 struct esp_platform_saved_param 後面,呼叫上述兩個函 數進行 Flash 讀寫即可。

4.2 Flash讀防寫參考一

用法: “輪流寫入”+“首部記數”+“尾部校驗”

佔用空間: 2 個 sector,共計 8KB;提供 4KB 的帶資料保護儲存空間。

原理:

仍然採用兩個資料 sector 輪流寫入來做備份資料保護,只是不再專門設立 flag sector。 記一個 counter,寫入資料 sector 的首部,每次寫入時計數加一,用記數比較來判別下一次應寫入哪個 sector;在資料尾部加入校驗碼(CRC、 checksum 等任一種校驗方式),用以驗證資料的完整性。

(1) 假設初次上電,資料儲存在 sector A, sector A 的記數為初始值 0xFF,從 sector A 將資料讀入 RAM。

(2) 第一次資料寫入 sector B,則在 sector B 首部資訊中記錄 counter 為 1,尾部加入校驗碼。

(3) 再次寫入資料時,先分別讀取 sector A/B 的 counter 值進行比較,此次應當將資料寫入 sector A, sector A 首部記錄 counter 為 2,尾部加入校驗碼。

(4) 若發生突然掉電,當前正在寫入的 sector 資料丟失,重新上電時,先比較 sector A/B 的 counter 值,讀取 counter 值較⼤的完整 sector,根據 sector 尾部的校驗碼進行校驗,當前 sector 資料是否可靠,若校驗通過,則繼續執行;若校驗失敗,則讀取另一個 sector 的資料,校驗,並執行。

4.2 Flash讀防寫參考二

用法: “備份扇區”+“尾部校驗”

佔用空間: 2 個 sector,共計 8KB;提供 4KB 的帶資料保護儲存空間。

原理:

始終往 sector A 讀寫資料,每次寫入時,同樣寫一遍 sector B 作為 sector A 的備份扇區,每個 sector 尾部均加入校驗碼(CRC、 checksum等任一種校驗方式)。

(1) 從 sector A 讀取資料,並進行校驗。

(2) 資料寫入 sector A,尾部為校驗碼。

(3) sector A 寫入完成後,同樣的資料也寫入 sector B 進行備份。

(4) 若發生突然掉電,當前正在寫入的 sector 資料丟失,重新上電時,先從 sector A 讀取資料,根 據尾部的校驗碼進行校驗, sector A 資料是否可靠,若校驗通過,則繼續執行;若校驗失敗,則讀取 sector B 的資料,校驗,並執行。

• 由 Leung 寫於 2018 年 9 月 14 日

• 參考:《ESP8266 Flash 讀寫說明》《ESP8266 Non-OS SDK IoT_Demo 指南》《ESP8266 Non-OS SDK API 參考》