首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >写入EEPROM的算法?

写入EEPROM的算法?
EN

Stack Overflow用户
提问于 2016-11-23 09:34:22
回答 2查看 1K关注 0票数 1

我有一个内存,它是一个4字节行的列。我只能用写成16字节(),用I2C (逐行)读取4字节。

我感兴趣的是如何将数据写入EEPROM:正在写入的数据由几个不同的部分组成,其中两个部分可以是可变长度的。例如,我可以使用XYYZ或XYYYYZZZZZZZ,其中每个字母都是4个字节。

我的问题是,我应该如何解决这个问题,才能使用适合这两个部分的可变性质的16字节写入将消息写入内存的一般方式?

EN

回答 2

Stack Overflow用户

发布于 2016-11-23 11:42:18

与其尝试以4或16字节的单位工作,您可以考虑为eeprom使用一个小的(21字节)静态缓存。让我们假设你

代码语言:javascript
复制
void eeprom_read16(uint32_t page, uint8_t *data);
void eeprom_write16(uint32_t page, const uint8_t *data);

其中page是被16除的地址,并且总是在16字节块上操作。缓存本身及其初始化函数(您可以在电源上调用一次)将是

代码语言:javascript
复制
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;
    }
}

只有当您希望确保某些数据存储在EEPROM中时,才需要eeprom_flush()函数--基本上,在每个事务完成之后。你可以在任何时候安全地呼叫它。

若要访问EEPROM中的任何内存,请使用访问器函数

代码语言:javascript
复制
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;这只是一个优化。上面的static inline告诉C99编译器在可能的情况下内联这些函数。它可能会增加一些您的代码大小,但是它会产生更快的代码(因为当这样的小函数被内联到代码中时,编译器可以进行更好的优化)。

请注意,您不应该在中断处理程序中使用上面的内容,因为正常的代码没有为eeprom页面准备以更改中间操作。

您可以混合读写操作,但这可能导致不必要的磨损EEPROM。当然,如果您确实将读和写混合在一起,则可以将读和写边拆分为单独的缓存。这还允许您安全地从中断上下文中读取EEPROM (尽管I2C访问的延迟/延迟可能会在其他地方造成严重破坏)。

票数 1
EN

Stack Overflow用户

发布于 2016-11-23 10:43:17

不是专门为您的示例量身定做的,完全未经测试,依赖于将“从EEPROM读取4个字节”和“将16个字节写入EEPROM”封装在适当的函数中。

代码语言:javascript
复制
void write_to_eeprom(uint32_t start, size_t len, uint8_t *data) {
  uint32_t eeprom_dst = start & 0xfffffff0;
  uint8_t buffer[16];
  ssize_t data_offset;

  for (data_offset = (start - eeprom_dst); data_offset < len; data_offset += 16, eeprom_dst+= 16) {
    if (data_offset < 0) || ((len - data_offset) < 16) {
      // we need to fill our buffer with EEPROM data
      read_from_eeprom(eeprom_dst, buffer); // read 4 bytes, place at ptr
      read_from_eeprom(eeprom_dst+4, buffer+4);
      read_from_eeprom(eeprom_dst+8, buffer+8);
      read_from_eeprom(eeprom_dst+12, buffer+12);
      for (int buf_ix=0, ssize_t tmp_offset = data_offset; buf_ix < 16; buf_ix++, offset++) {
        if ((offset >= 0) && (buf_ix < 16)) {
          // We want to copy actual data
          buffer[buf_ix] = data[offset];
        }
      }
    } else {
      // We don't need to cater for edge cases and can simply shift
      // 16 bytes into our tmp buffer.
      for (int ix = 0; ix < 16; ix++) {
         buffer[ix] = data[data_offset + ix];
      }
    }
    write_to_eeprom(eeprom_dst, buffer);
  }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40760602

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档