AVR内蔵のEEPROMを操作するための関数群が <avr/eeprom.h> に用意されています。
AVR Libc 1.6.7 で提供されている関数に基づきます。(1.7.1まで確認済み)
目次
詳細なEEPROMの扱いは、データシートを読んでください。AVR Memory の中にEEPROMの扱いが載っています。
EEPROMのアクセスは、必ず使用できる状態かを確認してから読み書きをする。
確認方法は2種類ある。
その他の方法として、割込 (EE_READY_vect / EE_RDY_vect / EEPROM_READY_vect ) を使用する方法もある。
EEPROMがアクセス可能かを判定する。(並行処理する場合のポーリングに用いる。)
返値
EEPROMがアクセス可能になるまでループして待つ。
EEPROMのアクセスは、0x0000~E2END (avr/io.hで定義) のアドレスとなります。 各AVR毎に搭載されているEEPROMのサイズが違うため、使う場合はデータシートを確認してください。
EEPROMのアドレス管理方法は、次の2つがあります。
各自でアドレスとサイズを把握しておかなければ、予想外に上書きなどをする場合があるため、しっかりと管理しなければならず煩雑となる。
#include <stdint.h> #include <avr/io.h> #include <avr/eeprom.h> #define EEPROM_V1 0x0000 /* EEPROM uint16_t 0x0000-0x0001 2Byte */ #define EEPROM_V2 0x0002 /* EEPROM uint8_t 0x0002 1Byte */ #define EEPROM_V3 0x0003 /* EEPROM int16_t 0x0003-0x0004 2Byte */ int main( void ) { uint16_t value; /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ value = eeprom_read_word((uint16_t *)EEPROM_V1); /* EEPROM_V1の読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_word((uint16_t *)EEPROM_V1, 0xCCAA); /* EEPROM_V1へ2byte書き込み */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_byte((uint8_t *)EEPROM_V2, 0xAA); /* EEPROM_V2へ1byte書き込み */ }
ソースコード上で、EEPROM用の変数として宣言する方法。管理が楽であるが、コードを書き換える(宣言の順番を入れ替える)と、EEPROMのアドレスが変り、昔の情報を読み出せなくなったりするので注意。
宣言方法は次の2種類がありどちらも同じです。初期値の設定も出来きます。
#include <stdint.h> #include <avr/io.h> #include <avr/eeprom.h> static uint16_t EEMEM EEPROM_V1; /* EEPROM_V1を宣言 */ static uint8_t EEPROM_V2 __attribute__((section(".eeprom"))); /* EEPROM_V2を宣言 */ static uint16_t EEMEM EEPROM_V3 = 5; /* EEPROM_V3を宣言と初期値 5 */ int main( void ) { uint16_t value; /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ value = eeprom_read_word(&EEPROM_V1); /* EEPROM_V1の読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_word(&EEPROM_V1, 0xCCAA); /* EEPROM_V1へ2byte書き込み */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_byte(&EEPROM_V2, 0xAA); /* EEPROM_V2へ1byte書き込み */ }
AVR libCでは、EEPROMへのアクセスする関数として読出し・書き込み・更新の3種類が提供されている。
読出し(eeprom_read_xxx())・書き込み関数(eeprom_write_xxx())は、指定されたアドレスに対して読み書きを行う関数です。
更新(eeprom_update_xxx())は、一度読出しを行い、書き込み指定値と違うときのみ書き込みを行う関数です。これを用いることで、EEPROMを頻繁に書き換えをすることを防げます。ただし、一度読出しを行うため、動作は単純な書き込みより少し(CPU 6サイクル分)遅くなります。
EEPROMの読出し・書き込み・更新の目安時間 (ATmega88の場合)
関数 | 時間 | |
---|---|---|
eeprom_read_byte(0x0000) | 4 CPUサイクル (20MHz時 200ns) | データシート p23 EEREの記述より |
eeprom_write_byte(0x0000, 0x00) | 3.4ms | データシート p22 Table6-1より |
eeprom_update_byte(0x0000, 0x00) | 4 CPUサイクル + 3.4ms(書き換え) |
関数プロトタイプ | 説明 |
---|---|
uint8_t eeprom_read_byte (const uint8_t *__p) __ATTR_PURE__ | EEPROM 1Byte(8bit)読出し |
uint16_t eeprom_read_word (const uint16_t *__p) __ATTR_PURE__ | EEPROM 2Byte(16bit)読出し |
uint32_t eeprom_read_dword (const uint32_t *__p) __ATTR_PURE__ | EEPROM 4Byte(32bit)読出し |
float eeprom_read_float (const float *__p) __ATTR_PURE__ | EEPROM float読出し |
void eeprom_read_block (void *__dst, const void *__src, size_t __n) | EEPROM ブロック読出し |
関数プロトタイプ | 説明 |
---|---|
void eeprom_write_byte (uint8_t *__p, uint8_t __value) | EEPROM 1Byte(8bit)書き込み |
void eeprom_write_word (uint16_t *__p, uint16_t __value) | EEPROM 2Byte(16bit)書き込み |
void eeprom_write_dword (uint32_t *__p, uint32_t __value) | EEPROM 4Byte(32bit)書き込み |
void eeprom_write_float (float *__p, float __value) | EEPROM float書き込み |
void eeprom_write_block (const void *__src, void *__dst, size_t __n) | EEPROM ブロック書き込み |
関数プロトタイプ | 説明 |
---|---|
void eeprom_update_byte (uint8_t *__p, uint8_t __value) | EEPROM 1Byte(8bit)更新 |
void eeprom_update_word (uint16_t *__p, uint16_t __value) | EEPROM 2Byte(16bit)更新 |
void eeprom_update_dword (uint32_t *__p, uint32_t __value) | EEPROM 4Byte(32bit)更新 |
void eeprom_update_float (float *__p, float __value) | EEPROM float更新 |
void eeprom_update_block (const void *__src, void *__dst, size_t __n) | EEPROM ブロック更新 |
1ByteのEEPROMアクセスのサンプルコードです。
符号ビットを含めるかの違いのため、int8_t型を入れることも可能
#include <stdint.h> #include <avr/io.h> #include <avr/eeprom.h> static uint8_t EEMEM EEPROM_V1 = 5; /* EEPROM_V1 を宣言 */ static uint8_t EEMEM EEPROM_V2; /* EEPROM_V2 を宣言 */ int main( void ) { uint8_t value; /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ value = eeprom_read_byte(&EEPROM_V1); /* EEPROM_V1の読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_byte(&EEPROM_V1, 0xAA); /* EEPROM_V1へ書き込み */ /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_byte(&EEPROM_V2, value); /* EEPROM_V2を更新 */ }
2Byte(WORD)のEEPROMアクセスのサンプルコードです。
符号ビットを含めるかの違いのため、int16_t型(int型)を入れることも可能
#include <stdint.h> #include <avr/io.h> #include <avr/eeprom.h> static uint16_t EEMEM EEPROM_V1 = 5; /* EEPROM_V1 を宣言 */ static uint16_t EEMEM EEPROM_V2; /* EEPROM_V2 を宣言 */ int main( void ) { uint16_t value; /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ value = eeprom_read_word(&EEPROM_V1); /* EEPROM_V1の読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_word(&EEPROM_V1, 0xCCAA); /* EEPROM_V1へ書き込み */ /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_word(&EEPROM_V2, value); /* EEPROM_V2を更新 */ }
4Byte(DWORD)のEEPROMアクセスのサンプルコードです。
符号ビットを含めるかの違いのため、int32_t型(long int型)を入れることも可能
#include <stdint.h> #include <avr/io.h> #include <avr/eeprom.h> static uint32_t EEMEM EEPROM_V1 = 5; /* EEPROM_V1 を宣言 */ static uint32_t EEMEM EEPROM_V2; /* EEPROM_V2 を宣言 */ int main( void ) { uint32_t value; /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ value = eeprom_read_dword(&EEPROM_V1); /* EEPROM_V1の読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_dword(&EEPROM_V1, 0x55DDCCAA); /* EEPROM_V1へ書き込み */ /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_dword(&EEPROM_V2, value); /* EEPROM_V2を更新 */ }
float型のEEPROMアクセスのサンプルコードです。浮動小数点の変数を取り扱えます。
#include <stdint.h> #include <avr/io.h> #include <avr/eeprom.h> static float EEMEM EEPROM_V1 = 10.1; /* EEPROM_V1 を宣言 */ static float EEMEM EEPROM_V2; /* EEPROM_V2 を宣言 */ int main( void ) { float value; /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ value = eeprom_read_float(&EEPROM_V1); /* EEPROM_V1の読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_float(&EEPROM_V1, 20.2); /* EEPROM_V1へ書き込み */ /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_float(&EEPROM_V2, value); /* EEPROM_V2を更新 */ }
EEPROM上に配列を宣言して取り扱うことも可能です。
1バイト単位の制御
ブロック単位(配列全体)の制御
#include <stdint.h> #include <avr/io.h> #include <avr/eeprom.h> static uint8_t EEMEM EEPROM_V1[10]; /* EEPROM_V1[10] を宣言 */ static uint8_t EEMEM EEPROM_V2[] = { 10, 3, 20, 4}; /* EEPROM_V2[] を宣言・初期値 */ int main( void ) { uint8_t value; uint8_t vars[10]; /* EEPROM 読出し */ /* 1Byte単位のアクセス */ eeprom_busy_wait(); /* 読み書き可能までwait */ value = eeprom_read_byte(&EEPROM_V1[0]); /* EEPROM_V1[0]の読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_byte(&EEPROM_V1[1], 0xAA); /* EEPROM_V1[1]へ書き込み */ /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_byte(&EEPROM_V1[2], value); /* EEPROM_V1[2]を更新 */ /* 配列単位(ブロック)のアクセス */ /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_read_block(vars, EEPROM_V1, sizeof(vars)); /* EEPROM_V1[]をvars[10]のサイズまとめて読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_block(vars, EEPROM_V1, sizeof(vars)); /* EEPROM_V1[]へvars[10]をまとめて書き込み */ /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_block(vars, EEPROM_V1, sizeof(vars)); /* EEPROM_V1[]をvars[10]でまとめて更新 */ /* 配列単位(ブロック)のアクセス その2 10Byteを指定する場合で上と同じ動作 */ /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_read_block(&vars[0], &EEPROM_V1[0], 10); /* EEPROM_V1[0]からvars[0]へ10Byteまとめて読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_block(vars, &EEPROM_V1[0], 10); /* EEPROM_V1[]へvars[10]をまとめて書き込み */ /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_block(&vars[0], EEPROM_V1, 10); /* EEPROM_V1[]をvars[10]でまとめて更新 */ }
EEPROM上に配列を宣言して取り扱うことも可能です。
ブロック単位(配列・文字列全体)の制御
#include <stdint.h> #include <stdio.h> #include <avr/io.h> #include <avr/eeprom.h> static uint8_t EEMEM EEPROM_V1[12] = "Hello World"; /* EEPROM_V1[12] を宣言 */ int main( void ) { char str[12]; /* 配列単位(ブロック)のアクセス */ /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_read_block(str, EEPROM_V1, sizeof(str)); /* EEPROM_V1[]をstr[]へまとめて読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_block(str, EEPROM_V1, sizeof(str)); /* EEPROM_V1[]へstr[]をまとめて書き込み */ printf("%s", str); sprintf(str,"hello2"); /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_block(str, EEPROM_V1, sizeof(str)); /* EEPROM_V1[]をstr[]でまとめて更新 */ }
EEPROM上に構造体を宣言して取り扱うことも可能です。
ブロック単位(構造体)の制御
#include <stdint.h> #include <avr/io.h> #include <avr/eeprom.h> typedef struct { uint8_t x,y; uint16_t z; } st_t; static st_t EEMEM EEPROM_st = { 1, 3, 579 }; /* 構造体 EEPROM_st を宣言 */ int main( void ) { st_t st; uint8_t val; /* 構造体(ブロック)のアクセス */ /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_read_block(&st, &EEPROM_st, sizeof(st_t)); /* EEPROM_stをstへ読出し */ /* EEPROM 書込み */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_write_block(&st, &EEPROM_st, sizeof(st_t)); /* EEPROM_stへstを書き込み */ /* EEPROM 更新 */ eeprom_busy_wait(); /* 読み書き可能までwait */ eeprom_update_block(&st, &EEPROM_st, sizeof(st_t)); /* EEPROM_stをstで更新 */ /* 構造体のメンバへアクセス */ /* EEPROM 読出し */ eeprom_busy_wait(); /* 読み書き可能までwait */ val = eeprom_read_byte(&EEPROM_st.x); /* EEPROM_st.xをvalへ1byte読出し */ }