# Flash (索引式儲存空間)

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

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

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

### 初始化 <a href="#flashkeypairstorage-chu-shi-hua" id="flashkeypairstorage-chu-shi-hua"></a>

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

### 讀寫操作 <a href="#flashkeypairstorage-du-xie-cao-zuo" id="flashkeypairstorage-du-xie-cao-zuo"></a>

透過 *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\_DATA* 與 *LFLASH\_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 屬性所存的資料量大小。

### 範例程式 <a href="#flashkeypairstorage-fan-li-cheng-shi" id="flashkeypairstorage-fan-li-cheng-shi"></a>

```
#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);
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cavedu.gitbook.io/linkit-7697/linkit-7697-arduinoide/kai-fa-zhi-nan/flash-suo-yin-shi-chu-cun-kong-jian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
