4バイトまたは16バイト単位で作業するのではなく、eepromに小さな(21バイトの)静的キャッシュを使用することを検討できます。 page
は16で割ったアドレスがどこにあるのは、あなたが
void eeprom_read16(uint32_t page, uint8_t *data);
void eeprom_write16(uint32_t page, const uint8_t *data);
を持っていると仮定しましょう、と常に16個のバイトのチャンク上で動作します。基本的には、後に - あなたはEEPROMに保存されているいくつかのデータを確保したい場合は、それ自体とその初期化関数は、(あなたは、電源投入時に一度呼びたい)キャッシュがeeprom_flush()
機能のみが必要とされている
static uint32_t eeprom_page; /* uint16_t suffices for 2 MiB EEPROM */
static uint8_t eeprom_cache[16];
static uint8_t eeprom_dirty;
static void eeprom_init(void)
{
eeprom_page = 0x80000000U; /* "None", at 32 GiB */
eeprom_dirty = 0;
}
static void eeprom_flush(void)
{
if (eeprom_dirty) {
eeprom_write16(eeprom_page, eeprom_cache);
eeprom_dirty = 0;
}
}
だろう各完全なトランザクション。あなたはいつでもそれを安全に呼び出すことができます。
あなたは
static inline uint8_t eeprom_get(const uint32_t address)
{
const uint32_t page = address >> 4;
if (page != eeprom_page) {
if (eeprom_dirty) {
eeprom_write(eeprom_page, eeprom_cache);
eeprom_dirty = 0;
}
eeprom_read(page, eeprom_cache);
eeprom_page = page;
}
return eeprom_cache[address % 0xFU];
}
static inline void eeprom_set(const uint32_t address, const uint8_t value)
{
const uint32_t page = address >> 4;
if (page != eeprom_page) {
if (eeprom_dirty) {
eeprom_write(eeprom_page, eeprom_cache);
eeprom_dirty = 0;
}
eeprom_read(page, eeprom_cache);
eeprom_page = page;
}
eeprom_dirty = 1;
eeprom_cache[address % 0xFU] = value;
}
あなたが好きならinline
を省略気軽にアクセサ関数を使用し、EEPROM内の任意のメモリにアクセスするには、単なる最適化です。上記のstatic inline
は、可能であれば、関数をインライン化するようにC99コンパイラに指示します。あなたのコードサイズを少し増やすかもしれませんが、より小さなコードがコードにインライン展開されたときにコンパイラがより良い最適化を行うことができるので、より速いコードを生成するはずです。
eepromページが途中で変更されるための通常のコードが用意されていないため、上記の割り込みハンドラでは使用しないでください。
読み取り操作と書き込み操作を混在させることはできますが、EEPROMに不必要な摩耗が生じる可能性があります。ミックスの読み書きを行う場合は、もちろん、読み取り側と書き込み側を別々のキャッシュに分割することができます。そうすれば、I2Cアクセスの遅延/レイテンシが他の場所に混乱を招くかもしれないが、割り込みコンテキストからEEPROMの読み込みを安全に行うことができます。