> For the complete documentation index, see [llms.txt](https://cavedu.gitbook.io/linkit-7697/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cavedu.gitbook.io/linkit-7697/linkit-7697-arduinoide/kai-fa-zhi-nan/eeprom.md).

# EEPROM

和 RAM 不同，EEPROM 提供在系統斷電後仍能儲存資料的空間 (就像顆小硬碟)。透過使用 Arduino 的 [EEPROM 函式庫](https://www.arduino.cc/en/Reference/EEPROM)開發者可以讀寫 LinkIt 7697 上虛擬 (\*) 的 EEPROM，且此 EEPROM 總容量大小為 **1KB**。

(\*) LinkIt 7697 的非揮發性儲存媒介只有 serial flash、並沒有 EEPROM。但為了相容於 Arduino 開發環境，透過使用 LinkIt SDK 裡的 [NVDM](http://labs.mediatek.com/api/mt7697/group___n_v_d_m.html) (**N**on-**V**olatile **D**ata **M**anagement) 模組模擬出一顆具有 1KB 大小的 EEPROM。

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

### 使用方法 <a href="#eeprom-shi-yong-fang-fa" id="eeprom-shi-yong-fang-fa"></a>

在使用 EEPROM APIs 前，須先加入相關的 header file：

```
#include <EEPROM.h>
```

存取 EEPROM 會使用到下列六個 APIs：

* length()
* read()
* write()
* update()
* get()
* put()

#### 基本操作 <a href="#eeprom-ji-ben-cao-zuo" id="eeprom-ji-ben-cao-zuo"></a>

若要查詢 EEPROM 的總空間大小，可呼叫 *EEPROM.length()*，在 LinkIt 7697 上它的回傳值會是 1024 (也就是 1KB)。

若要進行單一位元組的存取，可以使用 *EEPROM.read()*、*EEPROM.write()* 和 *EEPROM.update()* 等 API。這些函式的原型宣告如下：

```
uint8_t read(int idx);
void write(int idx, uint8_t val);
void update(int idx, uint8_t val);
```

API 參數定義為：

* **idx**：要讀寫的位元組的位置。有效的位置範圍為 0 \~ EEPROM.length() - 1。
* **val**：要寫入 EEPROM 的資料。

由於 flash 記憶體有最大寫入次數的物理限制，因此不建議對 flash 空間進行頻繁的寫入操作造成使用壽命下降。為了改善這個狀況，可以使用 *.update()* API 取代 *.write()* API 進行寫入。因為 *.update()* 會在每次寫入前，會先檢查該位置的資料是否與欲寫入的資料相同，若不相同才會真的觸發 flash 寫入。反之，若該位置的資料已經與欲寫入的資料相同，則 *.update()* 就不會觸發 flash 寫入。

相對的，若使用 *.write()* 進行寫入，則不會檢查欲寫入位置的資料為何，一律都會觸發 flash 寫入操作。

#### 使用 \[] 運算子進行存取 <a href="#eeprom-shi-yong-yun-suan-zi-jin-hang-cun-qu" id="eeprom-shi-yong-yun-suan-zi-jin-hang-cun-qu"></a>

除了呼叫 API 之外，也可以使用 \[] 運算子存取 EEPROM 如以下範例：

```
// read the byte from address 88 and store it to the 'data' variable
uint8_t data = EEPROM[88];
// write a byte (the value is 97) to address 76
EEPROM[76] = 97;
// increase the value in address 2 by 1
EEPROM[2]++;
```

#### 多位元組存取 <a href="#eeprom-duo-wei-yuan-zu-cun-qu" id="eeprom-duo-wei-yuan-zu-cun-qu"></a>

讀寫 EEPROM 時除了一次讀寫一個位元組，EEPROM 函式庫亦提供了 *.get()* 與 *.put()* 這兩個讓開發者可以同時存取多位元組的 API：

```
template<typename T> T &get(int idx, T &t);
template<typename T> const T &put(int idx, const T &t);
```

API 參數定義如下：

* **idx**：要讀寫資料的起始位置。
* **t**：用來儲存要讀出或寫入 EEPROM 的位元組的資料結構。 &#x20;

以下是使用 *.get()* 與 *.put()* 的操作範例：

```
// define the data type
typedef struct
{
  int id;
  float value;
  char ch;
} data_t;
 
data_t input, output;
int address = 76;
 
// init the values for input
input.id = 10;
input.value = 123.456f;
input.ch = 'c';
 
// store the input data to the EEPROM
put(address, &input);
// after the input is stored, we can read it back from the same address
get(address, &output);
```

在這個範例裡，透過呼叫 *.put()* 將一多位元組的資料結構 (*data\_t*) 寫入 EEPROM。寫入後，可再透過 *.get()* 讀出來。讀出來的結果應該和寫入的內容是一致的。

若要參考更多範例，請點選 Arduino IDE 裡的 **Files / Examples / EEPROM** 選單，裡面提供了更多不同的 EEPROM 應用範例。
