Flash (索引式儲存空間)

開發應用程式的過程,有時開發者會需要斷電後也能保存資料的非揮發性儲存空間。LinkIt 7697 Arduino BSP 提供了 Arduino 開發者 LFlash 類別,以索引式存取的方式,將 LinkIt SDK 原生的 NVDM (NVDM: Non-Volatile Data Management) 資料儲存功能開放出來。藉由使用 LFlash APIs,可透過以字串為索引的方式將使用者資料儲存在開發板內建的 flash 記憶空間之中。在 Files / Examples / LFlash / ClickCount 裡,提供了利用 LFlash 來記錄 USR 按鈕按壓次數的範例,透過這個例子便可了解 LFlash 類別的使用方式。當執行這個範例時,開啟 Serial Monitor 並按下 USR 按鈕,即可看到 "USR button has been pressed for XXX times." 顯示按鈕被按了幾次的資訊;每當 USR 按鈕被按下時,顯示的按壓次數就會增加。

接下來將說明使用 LFlash 類別的方法:

NVDM 所管理的總空間為 64KB,而這個空間由 LFlash 與 EEPROM 兩個函式庫共同分享使用。也就是說,如果開發者將 EEPROM 的 1KB 空間都使用完畢,那麼 LFlash 就只剩下 64 - 1 = 63KB 可以使用。反之,若開發者完全不使用 EEPROM,那麼 LFlash 就可以使用 NVDM 完整的 64KB 儲存空間。

初始化

在程式的一開始要加入 "LFlash.h" 的 header file。由於 LFlash 類別預設在系統起始時即會產生物件實體,所以開發者可直接呼叫 LFlash.begin() 進行初始化動作。

讀寫操作

透過 LFlash.write()LFlash.read() API 來存取使用者的資料。函式的宣告原型如下:

LFlashStatus write(
  const char *sectionName,
  const char *propertyName,
  LFlashDataType dataType,
  const uint8_t *buffer,
  uint32_t dataSize);
 
LFlashStatus read(
  const char *sectionName, 
  const char *propertyName, 
  uint8_t *buffer, 
  uint32_t *size);

對應的參數說明:

  • [IN] sectionName:存放資料的資料區名稱。

  • [IN] propertyName:資料區裡的屬性名稱。

  • [IN] dataType:資料類型。寫入的資料類型可為字串型別或是 raw 資料格式,這兩者對應到的 enum 名稱分別為 LFLASH_STRING_DATALFLASH_RAW_DATA

  • [IN] buffer:儲存使用者資料的記憶體起始位址。

  • [IN] dataSize:輸入資料量的大小。

  • [IN/OUT] size:此參數一開始為輸入值,表示 buffer 參數所指到的空間大小。函式呼叫返回後,它則為輸出值,表示實際讀回來的資料量。

以一開始提到的 ClickCount 範例來說,要把按鈕按壓次數寫入 flash,需要呼叫 write() 函式如下:

LFlash.write(
  SECTION_NAME,
  PROPERTY_NAME,
  LFLASH_RAW_DATA,
  (const uint8_t *)&_count,
  sizeof(_count));

這個函式呼叫會以 raw 格式把資料以屬性名 PROPERTY_NAME 寫入到資料區 SECTION_NAME。

而在範例的 setup() 函式裡,透過下列方式將按鈕按壓次數讀出來以顯示至 Serial Monitor:

LFlash.read(
  SECTION_NAME, 
  PROPERTY_NAME, 
  (uint8_t *)&_count, 
  &size);

函式中的 size 參數一開始被設定為 _count 這塊記憶體空間的大小,等到讀取完成後,它的值會被更新為在 SECTION_NAME 區裡 PROPERTY_NAME 屬性所存的資料量大小。

範例程式

#include "Arduino.h"
#include "LFlash.h"
#include <string.h>

#define BUFFER_LENGTH (4)

#define SECTION_NAME "MONITOR"
#define PROPERTY_NAME "BTN_CLICK"

#define LED_PIN (7)
#define BUTTON_PIN (6)

static uint32_t _count = 0;

void show_message(uint32_t times)
{
  Serial.print("USR button has been pressed for ");
  Serial.print(times);
  Serial.print(" time");
  
  if (times < 2)
  {
    Serial.println(".");
  }
  else
  {
    Serial.println("s.");
  }
}

void button_press(void)
{
  _count++;
  
  // write the count into the flash
  LFlash.write(
    SECTION_NAME,
    PROPERTY_NAME,
    LFLASH_RAW_DATA,
    (const uint8_t *)&_count,
    sizeof(_count));

  show_message(_count);
}

void setup() {
  uint32_t size = BUFFER_LENGTH;

  Serial.begin(115200);
  
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);

  if (LFlash.begin() != LFLASH_OK)
  {
    Serial.println("Flash init failed.");
    return;
  }

  // flash init done and okay
  digitalWrite(LED_PIN, LOW);

  attachInterrupt(BUTTON_PIN, button_press, RISING);

  // read back the current click count
  LFlash.read(SECTION_NAME, PROPERTY_NAME, (uint8_t *)&_count, &size);

  show_message(_count);
}

void loop() {
  delay(1000);
}

Last updated